You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@cxf.apache.org by am...@apache.org on 2009/11/17 23:50:00 UTC
svn commit: r881592 - in /cxf/trunk:
rt/frontend/jaxrs/src/main/java/org/apache/cxf/jaxrs/ext/logging/
rt/frontend/jaxrs/src/main/java/org/apache/cxf/jaxrs/ext/logging/atom/
systests/jaxrs/src/test/java/org/apache/cxf/systest/jaxrs/
systests/jaxrs/src/...
Author: amichalec
Date: Tue Nov 17 22:49:55 2009
New Revision: 881592
URL: http://svn.apache.org/viewvc?rev=881592&view=rev
Log:
Initial version of ATOM push-style logger
Added:
cxf/trunk/rt/frontend/jaxrs/src/main/java/org/apache/cxf/jaxrs/ext/logging/
cxf/trunk/rt/frontend/jaxrs/src/main/java/org/apache/cxf/jaxrs/ext/logging/LogLevel.java
cxf/trunk/rt/frontend/jaxrs/src/main/java/org/apache/cxf/jaxrs/ext/logging/LogRecord.java
cxf/trunk/rt/frontend/jaxrs/src/main/java/org/apache/cxf/jaxrs/ext/logging/LogRecordsList.java
cxf/trunk/rt/frontend/jaxrs/src/main/java/org/apache/cxf/jaxrs/ext/logging/atom/
cxf/trunk/rt/frontend/jaxrs/src/main/java/org/apache/cxf/jaxrs/ext/logging/atom/AtomPushBean.java
cxf/trunk/rt/frontend/jaxrs/src/main/java/org/apache/cxf/jaxrs/ext/logging/atom/AtomPushEngine.java
cxf/trunk/rt/frontend/jaxrs/src/main/java/org/apache/cxf/jaxrs/ext/logging/atom/AtomPushHandler.java
cxf/trunk/rt/frontend/jaxrs/src/main/java/org/apache/cxf/jaxrs/ext/logging/atom/ContentSingleEntryConverter.java
cxf/trunk/rt/frontend/jaxrs/src/main/java/org/apache/cxf/jaxrs/ext/logging/atom/Converter.java
cxf/trunk/rt/frontend/jaxrs/src/main/java/org/apache/cxf/jaxrs/ext/logging/atom/Deliverer.java
cxf/trunk/rt/frontend/jaxrs/src/main/java/org/apache/cxf/jaxrs/ext/logging/atom/LoggingThread.java
cxf/trunk/rt/frontend/jaxrs/src/main/java/org/apache/cxf/jaxrs/ext/logging/atom/RetryingDeliverer.java
cxf/trunk/rt/frontend/jaxrs/src/main/java/org/apache/cxf/jaxrs/ext/logging/atom/WebClientDeliverer.java
cxf/trunk/rt/frontend/jaxrs/src/main/java/org/apache/cxf/jaxrs/ext/logging/atom/package-info.java
cxf/trunk/rt/frontend/jaxrs/src/main/java/org/apache/cxf/jaxrs/ext/logging/package-info.java
cxf/trunk/systests/jaxrs/src/test/java/org/apache/cxf/systest/jaxrs/JAXRSLoggingAtomPushTest.java
cxf/trunk/systests/jaxrs/src/test/java/org/apache/cxf/systest/jaxrs/resources/logging_atompush.properties
cxf/trunk/systests/jaxrs/src/test/java/org/apache/cxf/systest/jaxrs/resources/logging_atompush_batch.properties
cxf/trunk/systests/jaxrs/src/test/java/org/apache/cxf/systest/jaxrs/resources/logging_atompush_disabled.properties
Added: cxf/trunk/rt/frontend/jaxrs/src/main/java/org/apache/cxf/jaxrs/ext/logging/LogLevel.java
URL: http://svn.apache.org/viewvc/cxf/trunk/rt/frontend/jaxrs/src/main/java/org/apache/cxf/jaxrs/ext/logging/LogLevel.java?rev=881592&view=auto
==============================================================================
--- cxf/trunk/rt/frontend/jaxrs/src/main/java/org/apache/cxf/jaxrs/ext/logging/LogLevel.java (added)
+++ cxf/trunk/rt/frontend/jaxrs/src/main/java/org/apache/cxf/jaxrs/ext/logging/LogLevel.java Tue Nov 17 22:49:55 2009
@@ -0,0 +1,66 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.cxf.jaxrs.ext.logging;
+
+import java.util.HashMap;
+import java.util.Map;
+import java.util.logging.Level;
+
+import javax.xml.bind.annotation.XmlEnum;
+import javax.xml.bind.annotation.XmlTransient;
+
+/**
+ * Log level of {@link LogRecord}. Based on SLF4J being popular facade for loggers like JUL, Log4J, JCL and so
+ * on. Severities order is: FATAL > ERROR > WARN > INFO > DEBUG > TRACE.
+ * <p>
+ * Mapping of levels:
+ * <ol>
+ * <li>JUL - same as <a href="http://www.slf4j.org/apidocs/org/slf4j/bridge/SLF4JBridgeHandler.html">SLF4J
+ * approach</a>.</li>
+ * <li>Log4J - levels are identical</li>
+ * </ol>
+ */
+@XmlEnum
+public enum LogLevel {
+ FATAL,
+ ERROR,
+ WARN,
+ INFO,
+ DEBUG,
+ TRACE;
+
+ @XmlTransient
+ private static Map<Level, LogLevel> julLogLevels = new HashMap<Level, LogLevel>();
+
+ static {
+ julLogLevels.put(Level.SEVERE, LogLevel.ERROR);
+ julLogLevels.put(Level.WARNING, LogLevel.WARN);
+ julLogLevels.put(Level.INFO, LogLevel.INFO);
+ julLogLevels.put(Level.FINE, LogLevel.DEBUG);
+ julLogLevels.put(Level.FINER, LogLevel.DEBUG);
+ julLogLevels.put(Level.FINEST, LogLevel.TRACE);
+ }
+
+ /**
+ * Creates this enum from JUL {@link Level}.
+ */
+ public static LogLevel fromJUL(Level level) {
+ return julLogLevels.get(level);
+ }
+}
Added: cxf/trunk/rt/frontend/jaxrs/src/main/java/org/apache/cxf/jaxrs/ext/logging/LogRecord.java
URL: http://svn.apache.org/viewvc/cxf/trunk/rt/frontend/jaxrs/src/main/java/org/apache/cxf/jaxrs/ext/logging/LogRecord.java?rev=881592&view=auto
==============================================================================
--- cxf/trunk/rt/frontend/jaxrs/src/main/java/org/apache/cxf/jaxrs/ext/logging/LogRecord.java (added)
+++ cxf/trunk/rt/frontend/jaxrs/src/main/java/org/apache/cxf/jaxrs/ext/logging/LogRecord.java Tue Nov 17 22:49:55 2009
@@ -0,0 +1,167 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.cxf.jaxrs.ext.logging;
+
+import java.io.PrintWriter;
+import java.io.StringWriter;
+import java.text.MessageFormat;
+import java.util.Date;
+
+import javax.xml.bind.annotation.XmlElement;
+import javax.xml.bind.annotation.XmlRootElement;
+
+import org.apache.commons.lang.Validate;
+import org.apache.commons.lang.builder.EqualsBuilder;
+import org.apache.commons.lang.builder.HashCodeBuilder;
+import org.apache.commons.lang.builder.ToStringBuilder;
+import org.apache.commons.lang.builder.ToStringStyle;
+
+/**
+ * Log entry serializable to XML. Based on common set of {@link java.util.logging.LogRecord} and
+ * {@link org.apache.log4j.spi.LoggingEvent} attributes.
+ * <p>
+ * LogRecord are never null; if some attributes are not set (e.g. logger name, or rendered cause taken from
+ * Throwable) empty strings are returned.
+ */
+@XmlRootElement
+public class LogRecord {
+
+ private Date eventTimestamp = new Date();
+ private LogLevel level = LogLevel.INFO;
+ private String message = "";
+ private String loggerName = "";
+ private String threadName = "";
+ private String throwable = "";
+
+ /**
+ * Creates this object from JUL LogRecord. Most attributes are copied, others are converted as follows:
+ * raw {@link java.util.logging.LogRecord#getMessage() message} is formatted with
+ * {@link java.util.logging.LogRecord#getParameters() parameters} using {@link MessageFormat}, attached
+ * {@link java.util.logging.LogRecord#getThrown() throwable} has full stack trace dumped, and log levels
+ * are mapped as specified in {@link LogRecord}.
+ *
+ * @param julRecord log record to convert.
+ * @return conversion result.
+ */
+ public static LogRecord fromJUL(java.util.logging.LogRecord julRecord) {
+ Validate.notNull(julRecord, "julRecord is null");
+ LogRecord record = new LogRecord();
+ record.setEventTimestamp(new Date(julRecord.getMillis()));
+ record.setLevel(LogLevel.fromJUL(julRecord.getLevel()));
+ record.setLoggerName(julRecord.getLoggerName());
+ if (julRecord.getThrown() != null) {
+ record.setThrowable(julRecord.getThrown());
+ }
+ if (julRecord.getParameters() != null) {
+ record.setMessage(MessageFormat.format(julRecord.getMessage(), julRecord.getParameters()));
+ } else {
+ record.setMessage(julRecord.getMessage());
+ }
+ record.setThreadName(Integer.toString(julRecord.getThreadID()));
+ return record;
+ }
+
+ @XmlElement
+ public Date getEventTimestamp() {
+ return eventTimestamp;
+ }
+
+ public void setEventTimestamp(Date eventTimestamp) {
+ Validate.notNull(eventTimestamp, "eventTimestamp is null");
+ this.eventTimestamp = eventTimestamp;
+ }
+
+ @XmlElement
+ public LogLevel getLevel() {
+ return level;
+ }
+
+ public void setLevel(LogLevel level) {
+ Validate.notNull(level, "level is null");
+ this.level = level;
+ }
+
+ /**
+ * Formatted message with parameters filled in.
+ */
+ @XmlElement
+ public String getMessage() {
+ return message;
+ }
+
+ public void setMessage(String renderedMessage) {
+ Validate.notNull(level, "message is null");
+ this.message = renderedMessage;
+ }
+
+ @XmlElement
+ public String getLoggerName() {
+ return loggerName;
+ }
+
+ public void setLoggerName(String loggerName) {
+ Validate.notNull(level, "loggerName is null");
+ this.loggerName = loggerName;
+ }
+
+ @XmlElement
+ public String getThreadName() {
+ return threadName;
+ }
+
+ public void setThreadName(String threadName) {
+ Validate.notNull(level, "threadName is null");
+ this.threadName = threadName;
+ }
+
+ /**
+ * Full stack trace of {@link Throwable} associated with log record.
+ */
+ @XmlElement
+ public String getThrowable() {
+ return throwable;
+ }
+
+ public void setThrowable(String throwable) {
+ Validate.notNull(throwable, "throwable is null");
+ this.throwable = throwable;
+ }
+
+ public void setThrowable(Throwable thr) {
+ Validate.notNull(thr, "throwable is null");
+ StringWriter sw = new StringWriter();
+ thr.printStackTrace(new PrintWriter(sw));
+ this.throwable = sw.getBuffer().toString();
+ }
+
+ @Override
+ public boolean equals(Object obj) {
+ return EqualsBuilder.reflectionEquals(obj, this);
+ }
+
+ @Override
+ public int hashCode() {
+ return HashCodeBuilder.reflectionHashCode(this);
+ }
+
+ @Override
+ public String toString() {
+ return ToStringBuilder.reflectionToString(this, ToStringStyle.SHORT_PREFIX_STYLE);
+ }
+}
Added: cxf/trunk/rt/frontend/jaxrs/src/main/java/org/apache/cxf/jaxrs/ext/logging/LogRecordsList.java
URL: http://svn.apache.org/viewvc/cxf/trunk/rt/frontend/jaxrs/src/main/java/org/apache/cxf/jaxrs/ext/logging/LogRecordsList.java?rev=881592&view=auto
==============================================================================
--- cxf/trunk/rt/frontend/jaxrs/src/main/java/org/apache/cxf/jaxrs/ext/logging/LogRecordsList.java (added)
+++ cxf/trunk/rt/frontend/jaxrs/src/main/java/org/apache/cxf/jaxrs/ext/logging/LogRecordsList.java Tue Nov 17 22:49:55 2009
@@ -0,0 +1,65 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.cxf.jaxrs.ext.logging;
+
+import java.util.ArrayList;
+import java.util.List;
+
+import javax.xml.bind.annotation.XmlElement;
+import javax.xml.bind.annotation.XmlRootElement;
+
+import org.apache.commons.lang.Validate;
+import org.apache.commons.lang.builder.EqualsBuilder;
+import org.apache.commons.lang.builder.HashCodeBuilder;
+import org.apache.commons.lang.builder.ToStringBuilder;
+import org.apache.commons.lang.builder.ToStringStyle;
+
+/**
+ * List of {@link LogRecord}s. Necessary wrapper for {@link List} used in JAXB context.
+ */
+@XmlRootElement(namespace = "zzz")
+public class LogRecordsList {
+
+ private List<LogRecord> logRecords = new ArrayList<LogRecord>();
+
+ @XmlElement(name = "logRecord", namespace = "zzz")
+ public List<LogRecord> getLogRecords() {
+ return logRecords;
+ }
+
+ public void setLogRecords(List<LogRecord> logRecords) {
+ Validate.notNull(logRecords, "logRecords is null");
+ this.logRecords = logRecords;
+ }
+
+ @Override
+ public boolean equals(Object obj) {
+ return EqualsBuilder.reflectionEquals(obj, this);
+ }
+
+ @Override
+ public int hashCode() {
+ return HashCodeBuilder.reflectionHashCode(this);
+ }
+
+ @Override
+ public String toString() {
+ return ToStringBuilder.reflectionToString(this, ToStringStyle.SHORT_PREFIX_STYLE);
+ }
+}
Added: cxf/trunk/rt/frontend/jaxrs/src/main/java/org/apache/cxf/jaxrs/ext/logging/atom/AtomPushBean.java
URL: http://svn.apache.org/viewvc/cxf/trunk/rt/frontend/jaxrs/src/main/java/org/apache/cxf/jaxrs/ext/logging/atom/AtomPushBean.java?rev=881592&view=auto
==============================================================================
--- cxf/trunk/rt/frontend/jaxrs/src/main/java/org/apache/cxf/jaxrs/ext/logging/atom/AtomPushBean.java (added)
+++ cxf/trunk/rt/frontend/jaxrs/src/main/java/org/apache/cxf/jaxrs/ext/logging/atom/AtomPushBean.java Tue Nov 17 22:49:55 2009
@@ -0,0 +1,23 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.cxf.jaxrs.ext.logging.atom;
+
+public class AtomPushBean {
+
+}
Added: cxf/trunk/rt/frontend/jaxrs/src/main/java/org/apache/cxf/jaxrs/ext/logging/atom/AtomPushEngine.java
URL: http://svn.apache.org/viewvc/cxf/trunk/rt/frontend/jaxrs/src/main/java/org/apache/cxf/jaxrs/ext/logging/atom/AtomPushEngine.java?rev=881592&view=auto
==============================================================================
--- cxf/trunk/rt/frontend/jaxrs/src/main/java/org/apache/cxf/jaxrs/ext/logging/atom/AtomPushEngine.java (added)
+++ cxf/trunk/rt/frontend/jaxrs/src/main/java/org/apache/cxf/jaxrs/ext/logging/atom/AtomPushEngine.java Tue Nov 17 22:49:55 2009
@@ -0,0 +1,145 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.cxf.jaxrs.ext.logging.atom;
+
+import java.util.ArrayList;
+import java.util.List;
+import java.util.concurrent.ExecutorService;
+import java.util.concurrent.Executors;
+
+import org.apache.abdera.model.Element;
+import org.apache.commons.lang.Validate;
+import org.apache.cxf.jaxrs.ext.logging.LogRecord;
+
+/**
+ * ATOM push-style realization class. Engine enqueues log records as they are {@link #publish(LogRecord)
+ * published}. After queue size exceeds {@link #getBatchSize() batch size} processing of collection of these
+ * records (in size of batch size) is triggered.
+ * <p>
+ * Processing is done in separate thread not to block publishing interface. Processing is two step: first list
+ * of log records is transformed by {@link Converter converter} to ATOM {@link Element element} and then it is
+ * pushed out by {@link Deliverer deliverer} to client. Next to transport deliverer is indirectly responsible
+ * for marshaling ATOM element to XML.
+ * <p>
+ * Processing is done by single threaded {@link java.util.concurrent.Executor executor}; next batch of records
+ * is taken from queue only when currently processed batch finishes and queue has enough elements to proceed.
+ * <p>
+ * First failure of any delivery shuts engine down. To avoid this situation engine must have registered
+ * reliable deliverer or use wrapping {@link RetryingDeliverer}.
+ */
+// TODO add internal diagnostics - log messages somewhere except for logger :D
+public class AtomPushEngine {
+ private List<LogRecord> queue = new ArrayList<LogRecord>();
+ private ExecutorService executor = Executors.newSingleThreadExecutor();
+ private int batchSize = 1;
+ private Converter converter;
+ private Deliverer deliverer;
+
+ /**
+ * Put record to publishing queue. Engine accepts published records only if is in proper state - is
+ * properly configured (has deliverer and converter registered) and is not shot down; otherwise calls to
+ * publish are ignored.
+ *
+ * @param record record to be published.
+ */
+ public synchronized void publish(LogRecord record) {
+ Validate.notNull(record, "record is null");
+ if (isValid()) {
+ queue.add(record);
+ if (queue.size() >= batchSize) {
+ publishBatch(queue);
+ queue = new ArrayList<LogRecord>();
+ }
+ }
+ }
+
+ /**
+ * Shuts engine down.
+ */
+ public synchronized void shutdown() {
+ executor.shutdownNow();
+ }
+
+ private boolean isValid() {
+ if (deliverer == null) {
+ // TODO report cause
+ System.err.println("deliverer is not set");
+ return false;
+ }
+ if (converter == null) {
+ System.err.println("converter is not set");
+ return false;
+ }
+ if (executor.isShutdown()) {
+ System.err.println("engine shutdown");
+ return false;
+ }
+ return true;
+ }
+
+ private void publishBatch(final List<LogRecord> batch) {
+ executor.execute(new Runnable() {
+ public void run() {
+ try {
+ LoggingThread.markSilent(true);
+ // syncing for safe converter/deliverer on the fly replacement
+ synchronized (this) {
+ // TODO diagnostic output here: System.out.println(element.toString());
+ Element element = converter.convert(batch);
+ if (!deliverer.deliver(element)) {
+ System.err.println("Delivery failed, shutting engine down");
+ executor.shutdownNow();
+ }
+ }
+ } catch (InterruptedException e) {
+ // no action on executor.shutdownNow();
+ } finally {
+ LoggingThread.markSilent(false);
+ }
+ }
+ });
+ }
+
+ public int getBatchSize() {
+ return batchSize;
+ }
+
+ public void setBatchSize(int batchSize) {
+ Validate.isTrue(batchSize > 0, "batch size is not greater than zero");
+ this.batchSize = batchSize;
+ }
+
+ public Converter getConverter() {
+ return converter;
+ }
+
+ public synchronized void setConverter(Converter converter) {
+ Validate.notNull(converter, "converter is null");
+ this.converter = converter;
+ }
+
+ public Deliverer getDeliverer() {
+ return deliverer;
+ }
+
+ public synchronized void setDeliverer(Deliverer deliverer) {
+ Validate.notNull(deliverer, "deliverer is null");
+ this.deliverer = deliverer;
+ }
+}
Added: cxf/trunk/rt/frontend/jaxrs/src/main/java/org/apache/cxf/jaxrs/ext/logging/atom/AtomPushHandler.java
URL: http://svn.apache.org/viewvc/cxf/trunk/rt/frontend/jaxrs/src/main/java/org/apache/cxf/jaxrs/ext/logging/atom/AtomPushHandler.java?rev=881592&view=auto
==============================================================================
--- cxf/trunk/rt/frontend/jaxrs/src/main/java/org/apache/cxf/jaxrs/ext/logging/atom/AtomPushHandler.java (added)
+++ cxf/trunk/rt/frontend/jaxrs/src/main/java/org/apache/cxf/jaxrs/ext/logging/atom/AtomPushHandler.java Tue Nov 17 22:49:55 2009
@@ -0,0 +1,215 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.cxf.jaxrs.ext.logging.atom;
+
+import java.lang.reflect.Constructor;
+import java.util.logging.Handler;
+import java.util.logging.LogManager;
+
+import org.apache.cxf.jaxrs.ext.logging.LogRecord;
+
+/**
+ * Handler pushing log records in batches as Atom Feeds to registered client. Handler responsibility is to
+ * adapt to JUL framework while most of job is delegated to {@link AtomPushEngine}.
+ * <p>
+ * For simple configuration using properties file (one global root-level handler of this class) following
+ * properties prefixed with full class name can be used:
+ * <ul>
+ * <li><b>url</b> - URL where feeds will be pushed (mandatory parameter)</li>
+ * <li><b>converter</b> - name of class implementing {@link Converter} class. For classes from this package
+ * only class name can be given e.g. instead of
+ * "org.apache.cxf.jaxrs.ext.logging.atom.ContentSingleEntryConverter" one can specify
+ * "ContentSingleEntryConverter". If parameter is not set {@link ContentSingleEntryConverter} is used.</li>
+ * <li><b>deliverer</b> - name of class implementing {@link Deliverer} class. For classes from this package
+ * only class name can be given e.g. instead of "org.apache.cxf.jaxrs.ext.logging.atom.WebClientDeliverer" one
+ * can specify "WebClientDeliverer". If parameter is not set {@link WebClientDeliverer} is used.</li>
+ * <li><b>batchSize</b> - integer number specifying minimal number of published log records that trigger
+ * processing and pushing ATOM document. If parameter is not set, is not greater than zero or is not a number,
+ * batch size is set to 1.</li>
+ * </ul>
+ * Family of <tt>retry</tt> parameters below; availability of any of this parameters enables delivery retrying
+ * (e.g. for default non-reliable deliverers) with {@link RetryingDeliverer} that can be combined with
+ * provided non-reliable deliverers. Detailed explanation of these parameter, see {@link RetryingDeliverer}
+ * class description.
+ * <ul>
+ * <li><b>retry.pause</b> - pausing strategy of delivery retries, either <b>linear</b> or <b>exponential</b>
+ * value (mandatory parameter). If mispelled linear is used.</li>
+ * <li><b>retry.pause.time</b> - pause time (in seconds) between retries. If parameter is not set, pause is
+ * set to 30 seconds.</li>
+ * <li><b>retry.timeout</b> - maximum time (in seconds) retrying will be continued. If not set timeout is not
+ * set (infinite loop of retries).</li>
+ * </ul>
+ * Example:
+ *
+ * <pre>
+ * handlers = org.apache.cxf.jaxrs.ext.logging.atom.AtomPushHandler, java.util.logging.ConsoleHandler
+ * .level = INFO
+ * ...
+ * org.apache.cxf.jaxrs.ext.logging.atom.AtomPushHandler.url = http://localhost:9080
+ * org.apache.cxf.jaxrs.ext.logging.atom.AtomPushHandler.batchSize = 10
+ * org.apache.cxf.jaxrs.ext.logging.atom.AtomPushHandler.deliverer = WebClientDeliverer
+ * org.apache.cxf.jaxrs.ext.logging.atom.AtomPushHandler.converter = foo.bar.MyConverter
+ * org.apache.cxf.jaxrs.ext.logging.atom.AtomPushHandler.retry.pause = linear
+ * org.apache.cxf.jaxrs.ext.logging.atom.AtomPushHandler.retry.pause.time = 10
+ * org.apache.cxf.jaxrs.ext.logging.atom.AtomPushHandler.retry.timeout = 360
+ * ...
+ * </pre>
+ */
+public final class AtomPushHandler extends Handler {
+
+ private AtomPushEngine engine = new AtomPushEngine();
+ private boolean lazyConfig;
+
+ /**
+ * Creates handler with configuration taken from properties file.
+ */
+ public AtomPushHandler() {
+ // deferred configuration: configure() called from here would use utilities that attempt to log
+ // and create this handler instance in recursion; configure() will be called on first publish()
+ lazyConfig = true;
+ }
+
+ /**
+ * Creates handler with custom parameters.
+ *
+ * @param batchSize batch size, see {@link AtomPushEngine#getBatchSize()}
+ * @param converter converter transforming logs into ATOM elements
+ * @param deliverer deliverer pushing ATOM elements to client
+ */
+ public AtomPushHandler(int batchSize, Converter converter, Deliverer deliverer) {
+ engine.setBatchSize(batchSize);
+ engine.setConverter(converter);
+ engine.setDeliverer(deliverer);
+ }
+
+ @Override
+ public synchronized void publish(java.util.logging.LogRecord record) {
+ if (LoggingThread.isSilent()) {
+ return;
+ }
+ LoggingThread.markSilent(true);
+ try {
+ if (lazyConfig) {
+ lazyConfig = false;
+ configure();
+ }
+ LogRecord rec = LogRecord.fromJUL(record);
+ engine.publish(rec);
+ } finally {
+ LoggingThread.markSilent(false);
+ }
+ }
+
+ @Override
+ public synchronized void close() throws SecurityException {
+ engine.shutdown();
+ }
+
+ @Override
+ public synchronized void flush() {
+ // no-op
+ }
+
+ /**
+ * Configuration from properties. Aligned to JUL strategy - properties file is only for simple
+ * configuration: it allows configure one root handler with its parameters. What is even more dummy, JUL
+ * does not allow to iterate over configuration properties to make interpretation automated (e.g. using
+ * commons-beanutils)
+ */
+ private void configure() {
+ LogManager manager = LogManager.getLogManager();
+ String cname = getClass().getName();
+ String url = manager.getProperty(cname + ".url");
+ if (url == null) {
+ // cannot proceed
+ return;
+ }
+ String deliverer = manager.getProperty(cname + ".deliverer");
+ if (deliverer != null) {
+ engine.setDeliverer(createDeliverer(deliverer, url));
+ } else {
+ // default
+ engine.setDeliverer(new WebClientDeliverer(url));
+ }
+ String converter = manager.getProperty(cname + ".converter");
+ if (converter != null) {
+ engine.setConverter(createConverter(converter));
+ } else {
+ // default
+ engine.setConverter(new ContentSingleEntryConverter());
+ }
+ engine.setBatchSize(toInt(manager.getProperty(cname + ".batchSize"), 1, 1));
+ String retryType = manager.getProperty(cname + ".retry.pause");
+ if (retryType != null) {
+ int timeout = toInt(manager.getProperty(cname + ".retry.timeout"), 0, 0);
+ int pause = toInt(manager.getProperty(cname + ".retry.pause.time"), 1, 30);
+ boolean linear = !retryType.equalsIgnoreCase("exponential");
+ Deliverer wrapped = new RetryingDeliverer(engine.getDeliverer(), timeout, pause, linear);
+ engine.setDeliverer(wrapped);
+ }
+ }
+
+ private int toInt(String property, int defaultValue) {
+ try {
+ return Integer.parseInt(property);
+ } catch (NumberFormatException e) {
+ return defaultValue;
+ }
+ }
+
+ private int toInt(String property, int lessThan, int defaultValue) {
+ int ret = toInt(property, defaultValue);
+ if (ret < lessThan) {
+ ret = defaultValue;
+ }
+ return ret;
+ }
+
+ private Deliverer createDeliverer(String clazz, String url) {
+ try {
+ Constructor<?> ctor = loadClass(clazz).getConstructor(String.class);
+ return (Deliverer)ctor.newInstance(url);
+ } catch (Exception e) {
+ throw new IllegalArgumentException(e);
+ }
+ }
+
+ private Converter createConverter(String clazz) {
+ try {
+ Constructor<?> ctor = loadClass(clazz).getConstructor();
+ return (Converter)ctor.newInstance();
+ } catch (Exception e) {
+ throw new IllegalArgumentException(e);
+ }
+ }
+
+ private Class<?> loadClass(String clazz) throws ClassNotFoundException {
+ try {
+ return getClass().getClassLoader().loadClass(clazz);
+ } catch (ClassNotFoundException e) {
+ try {
+ // clazz could be shorted (stripped package name) retry
+ String clazz2 = getClass().getPackage().getName() + "." + clazz;
+ return getClass().getClassLoader().loadClass(clazz2);
+ } catch (Exception e1) {
+ throw new ClassNotFoundException(e.getMessage() + " or " + e1.getMessage());
+ }
+ }
+ }
+}
Added: cxf/trunk/rt/frontend/jaxrs/src/main/java/org/apache/cxf/jaxrs/ext/logging/atom/ContentSingleEntryConverter.java
URL: http://svn.apache.org/viewvc/cxf/trunk/rt/frontend/jaxrs/src/main/java/org/apache/cxf/jaxrs/ext/logging/atom/ContentSingleEntryConverter.java?rev=881592&view=auto
==============================================================================
--- cxf/trunk/rt/frontend/jaxrs/src/main/java/org/apache/cxf/jaxrs/ext/logging/atom/ContentSingleEntryConverter.java (added)
+++ cxf/trunk/rt/frontend/jaxrs/src/main/java/org/apache/cxf/jaxrs/ext/logging/atom/ContentSingleEntryConverter.java Tue Nov 17 22:49:55 2009
@@ -0,0 +1,73 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.cxf.jaxrs.ext.logging.atom;
+
+import java.io.StringWriter;
+import java.util.List;
+
+import javax.xml.bind.JAXBContext;
+import javax.xml.bind.JAXBException;
+import javax.xml.bind.Marshaller;
+
+import org.apache.abdera.Abdera;
+import org.apache.abdera.factory.Factory;
+import org.apache.abdera.model.Content;
+import org.apache.abdera.model.Element;
+import org.apache.abdera.model.Entry;
+import org.apache.abdera.model.Feed;
+import org.apache.cxf.jaxrs.ext.logging.LogRecord;
+import org.apache.cxf.jaxrs.ext.logging.LogRecordsList;
+
+/**
+ * Single entry in feed with content set to list of log records.
+ */
+public class ContentSingleEntryConverter implements Converter {
+
+ private Factory factory;
+ private Marshaller marsh;
+
+ public ContentSingleEntryConverter() {
+ factory = Abdera.getNewFactory();
+ try {
+ marsh = JAXBContext.newInstance(LogRecordsList.class).createMarshaller();
+ } catch (JAXBException e) {
+ throw new RuntimeException(e);
+ }
+ }
+
+ public Element convert(List<LogRecord> records) {
+ Feed feed = factory.newFeed();
+ Entry entry = factory.newEntry();
+ feed.addEntry(entry);
+ Content content = factory.newContent();
+ content.setContentType(Content.Type.XML);
+ entry.setContent(content);
+ StringWriter writer = new StringWriter();
+ LogRecordsList list = new LogRecordsList();
+ list.setLogRecords(records);
+ try {
+ marsh.marshal(list, writer);
+ } catch (JAXBException e) {
+ throw new RuntimeException(e);
+ }
+ content.setValue(writer.toString());
+ return feed;
+ }
+
+}
Added: cxf/trunk/rt/frontend/jaxrs/src/main/java/org/apache/cxf/jaxrs/ext/logging/atom/Converter.java
URL: http://svn.apache.org/viewvc/cxf/trunk/rt/frontend/jaxrs/src/main/java/org/apache/cxf/jaxrs/ext/logging/atom/Converter.java?rev=881592&view=auto
==============================================================================
--- cxf/trunk/rt/frontend/jaxrs/src/main/java/org/apache/cxf/jaxrs/ext/logging/atom/Converter.java (added)
+++ cxf/trunk/rt/frontend/jaxrs/src/main/java/org/apache/cxf/jaxrs/ext/logging/atom/Converter.java Tue Nov 17 22:49:55 2009
@@ -0,0 +1,39 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.cxf.jaxrs.ext.logging.atom;
+
+import java.util.List;
+
+import org.apache.abdera.model.Element;
+import org.apache.cxf.jaxrs.ext.logging.LogRecord;
+
+/**
+ * Converts batch of log records into ATOM element to deliver. Represents strategies of conversion e.g. as
+ * ATOM format extensions, as Entry content etc.
+ */
+public interface Converter {
+
+ /**
+ * Converts collection of log records into ATOM element.
+ *
+ * @param records not-null collection of records
+ * @return ATOM document representing records
+ */
+ Element convert(List<LogRecord> records);
+}
Added: cxf/trunk/rt/frontend/jaxrs/src/main/java/org/apache/cxf/jaxrs/ext/logging/atom/Deliverer.java
URL: http://svn.apache.org/viewvc/cxf/trunk/rt/frontend/jaxrs/src/main/java/org/apache/cxf/jaxrs/ext/logging/atom/Deliverer.java?rev=881592&view=auto
==============================================================================
--- cxf/trunk/rt/frontend/jaxrs/src/main/java/org/apache/cxf/jaxrs/ext/logging/atom/Deliverer.java (added)
+++ cxf/trunk/rt/frontend/jaxrs/src/main/java/org/apache/cxf/jaxrs/ext/logging/atom/Deliverer.java Tue Nov 17 22:49:55 2009
@@ -0,0 +1,36 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.cxf.jaxrs.ext.logging.atom;
+
+import org.apache.abdera.model.Element;
+
+/**
+ * ATOM element deliverer. Represents transport strategy e.g. using
+ * {@link org.apache.cxf.jaxrs.client.WebClient}, SOAP reliable messaging etc.
+ */
+public interface Deliverer {
+
+ /**
+ * Delivers ATOM element.
+ *
+ * @param element element to deliver.
+ * @return true if delivery successful, false otherwise.
+ */
+ boolean deliver(Element element) throws InterruptedException;
+}
Added: cxf/trunk/rt/frontend/jaxrs/src/main/java/org/apache/cxf/jaxrs/ext/logging/atom/LoggingThread.java
URL: http://svn.apache.org/viewvc/cxf/trunk/rt/frontend/jaxrs/src/main/java/org/apache/cxf/jaxrs/ext/logging/atom/LoggingThread.java?rev=881592&view=auto
==============================================================================
--- cxf/trunk/rt/frontend/jaxrs/src/main/java/org/apache/cxf/jaxrs/ext/logging/atom/LoggingThread.java (added)
+++ cxf/trunk/rt/frontend/jaxrs/src/main/java/org/apache/cxf/jaxrs/ext/logging/atom/LoggingThread.java Tue Nov 17 22:49:55 2009
@@ -0,0 +1,51 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.cxf.jaxrs.ext.logging.atom;
+
+/**
+ * Helps disable logging from calls of the same thread. Motivation: log handlers in this package causes other
+ * threads (from executor) to start logging (by using JAXB that itself uses JUL) which in turn can be caught
+ * by the same handler leading to infinite loop.
+ * <p>
+ * Other approach than using thread local storage would be scanning of stack trace of current thread to see if
+ * root of call comes from same package as package of handler - it's less effective so TLS is using here.
+ */
+public final class LoggingThread {
+
+ private static ThreadLocal<LoggingThread> threadLocal = new ThreadLocal<LoggingThread>() {
+ @Override
+ protected LoggingThread initialValue() {
+ return new LoggingThread();
+ }
+ };
+
+ private boolean isSilent;
+
+ private LoggingThread() {
+ }
+
+ public static void markSilent(boolean silent) {
+ LoggingThread lt = threadLocal.get();
+ lt.isSilent = silent;
+ }
+
+ public static boolean isSilent() {
+ return threadLocal.get().isSilent;
+ }
+}
Added: cxf/trunk/rt/frontend/jaxrs/src/main/java/org/apache/cxf/jaxrs/ext/logging/atom/RetryingDeliverer.java
URL: http://svn.apache.org/viewvc/cxf/trunk/rt/frontend/jaxrs/src/main/java/org/apache/cxf/jaxrs/ext/logging/atom/RetryingDeliverer.java?rev=881592&view=auto
==============================================================================
--- cxf/trunk/rt/frontend/jaxrs/src/main/java/org/apache/cxf/jaxrs/ext/logging/atom/RetryingDeliverer.java (added)
+++ cxf/trunk/rt/frontend/jaxrs/src/main/java/org/apache/cxf/jaxrs/ext/logging/atom/RetryingDeliverer.java Tue Nov 17 22:49:55 2009
@@ -0,0 +1,124 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.cxf.jaxrs.ext.logging.atom;
+
+import java.util.Calendar;
+import java.util.Date;
+
+import org.apache.abdera.model.Element;
+import org.apache.commons.lang.Validate;
+
+/**
+ * Wrapper on other deliverer retrying delivery in case of failure. Delivery attempts repeat in loop with some
+ * pause time between retries until successful delivery or exceeding time limit. Time delay between delivery
+ * is configurable strategy. Two predefined strategies are given: each time pause same amount of time (linear)
+ * and each next time pause time doubles (exponential).
+ */
+public class RetryingDeliverer implements Deliverer {
+
+ private Deliverer deliverer;
+ private PauseCalculator pauser;
+ private int timeout;
+
+ /**
+ * Creates retrying deliverer with predefined retry strategy.
+ *
+ * @param worker real deliverer used to push data out.
+ * @param timeout maximum time range (in seconds) that retrial is continued; time spent on delivery call
+ * is included. No timeout (infinite loop) if set to zero.
+ * @param pause time of pause (in seconds) greater than zero.
+ * @param linear if true linear strategy (each time pause same amount of time), exponential otherwise
+ * (each next time pause time doubles).
+ */
+ public RetryingDeliverer(Deliverer worker, int timeout, int pause, boolean linear) {
+ Validate.notNull(worker, "worker is null");
+ Validate.isTrue(timeout >= 0, "timeout is negative");
+ Validate.isTrue(pause > 0, "pause is not greater than zero");
+ deliverer = worker;
+ this.timeout = timeout;
+ this.pauser = linear ? new ConstantPause(pause) : new ExponentialPause(pause);
+ }
+
+ /**
+ * Creates retrying deliverer with custom retry strategy.
+ *
+ * @param worker real deliverer used to push data out.
+ * @param timeout maximum time range (in seconds) that retrial is continued; time spent on delivery call
+ * is included. No timeout (infinite loop) if set to zero.
+ * @param strategy custom retry pausing strategy.
+ */
+ public RetryingDeliverer(Deliverer worker, int timeout, PauseCalculator strategy) {
+ Validate.notNull(worker, "worker is null");
+ Validate.notNull(strategy, "strategy is null");
+ Validate.isTrue(timeout >= 0, "timeout is negative");
+ deliverer = worker;
+ pauser = strategy;
+ this.timeout = timeout;
+ }
+
+ public boolean deliver(Element element) throws InterruptedException {
+ Calendar cal = Calendar.getInstance();
+ cal.add(Calendar.SECOND, timeout);
+ Date timeoutDate = cal.getTime();
+ while (!deliverer.deliver(element)) {
+ int sleep = pauser.nextPause();
+ cal = Calendar.getInstance();
+ cal.add(Calendar.SECOND, sleep);
+ if (timeout == 0 || timeoutDate.after(cal.getTime())) {
+ Thread.sleep(sleep * 1000);
+ } else {
+ return false;
+ }
+ }
+ return true;
+ }
+
+ /** Calculates time of subsequent pauses between delivery attempts. */
+ public interface PauseCalculator {
+ /** Time of next pause (in seconds). */
+ int nextPause();
+ }
+
+ private static class ConstantPause implements PauseCalculator {
+ private int pause;
+
+ public ConstantPause(int pause) {
+ this.pause = pause;
+ }
+
+ public int nextPause() {
+ return pause;
+ }
+ }
+
+ private static class ExponentialPause implements PauseCalculator {
+ private int pause;
+
+ public ExponentialPause(int pause) {
+ this.pause = pause;
+ }
+
+ public int nextPause() {
+ int curr = pause;
+ pause *= 2;
+ return curr;
+ }
+ }
+
+}
Added: cxf/trunk/rt/frontend/jaxrs/src/main/java/org/apache/cxf/jaxrs/ext/logging/atom/WebClientDeliverer.java
URL: http://svn.apache.org/viewvc/cxf/trunk/rt/frontend/jaxrs/src/main/java/org/apache/cxf/jaxrs/ext/logging/atom/WebClientDeliverer.java?rev=881592&view=auto
==============================================================================
--- cxf/trunk/rt/frontend/jaxrs/src/main/java/org/apache/cxf/jaxrs/ext/logging/atom/WebClientDeliverer.java (added)
+++ cxf/trunk/rt/frontend/jaxrs/src/main/java/org/apache/cxf/jaxrs/ext/logging/atom/WebClientDeliverer.java Tue Nov 17 22:49:55 2009
@@ -0,0 +1,58 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.cxf.jaxrs.ext.logging.atom;
+
+import java.util.Arrays;
+import java.util.List;
+
+import javax.ws.rs.core.Response;
+
+import org.apache.abdera.model.Element;
+import org.apache.commons.lang.Validate;
+import org.apache.cxf.jaxrs.client.WebClient;
+import org.apache.cxf.jaxrs.provider.AtomEntryProvider;
+import org.apache.cxf.jaxrs.provider.AtomFeedProvider;
+
+public class WebClientDeliverer implements Deliverer {
+ private WebClient wc;
+
+ public WebClientDeliverer(String deliveryAddress) {
+ this.wc = create(deliveryAddress);
+ }
+
+ public WebClientDeliverer(WebClient wc) {
+ Validate.notNull(wc, "wc is null");
+ this.wc = wc;
+ }
+
+ public boolean deliver(Element element) {
+ Response res = wc.post(element);
+ int status = res.getStatus();
+ return status >= 200 && status <= 299;
+ }
+
+ @SuppressWarnings("unchecked")
+ public static WebClient create(String baseAddress) {
+ Validate.notEmpty(baseAddress, "baseAddress is empty or null");
+ List<?> providers = Arrays.asList(new AtomFeedProvider(), new AtomEntryProvider());
+ WebClient wc = WebClient.create(baseAddress, providers);
+ wc.type("application/atom+xml");
+ return wc;
+ }
+}
Added: cxf/trunk/rt/frontend/jaxrs/src/main/java/org/apache/cxf/jaxrs/ext/logging/atom/package-info.java
URL: http://svn.apache.org/viewvc/cxf/trunk/rt/frontend/jaxrs/src/main/java/org/apache/cxf/jaxrs/ext/logging/atom/package-info.java?rev=881592&view=auto
==============================================================================
--- cxf/trunk/rt/frontend/jaxrs/src/main/java/org/apache/cxf/jaxrs/ext/logging/atom/package-info.java (added)
+++ cxf/trunk/rt/frontend/jaxrs/src/main/java/org/apache/cxf/jaxrs/ext/logging/atom/package-info.java Tue Nov 17 22:49:55 2009
@@ -0,0 +1,27 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+/**
+ * Support for producing logs in
+ * <a href="http://tools.ietf.org/html/rfc4287">ATOM Syndication Format</a>.
+ * Allows to configure <tt>java.util.logging</tt> (JUL) loggers to use
+ * handlers producing ATOM feeds that are either pushed to or pulled by client.
+ */
+package org.apache.cxf.jaxrs.ext.logging.atom;
+
Added: cxf/trunk/rt/frontend/jaxrs/src/main/java/org/apache/cxf/jaxrs/ext/logging/package-info.java
URL: http://svn.apache.org/viewvc/cxf/trunk/rt/frontend/jaxrs/src/main/java/org/apache/cxf/jaxrs/ext/logging/package-info.java?rev=881592&view=auto
==============================================================================
--- cxf/trunk/rt/frontend/jaxrs/src/main/java/org/apache/cxf/jaxrs/ext/logging/package-info.java (added)
+++ cxf/trunk/rt/frontend/jaxrs/src/main/java/org/apache/cxf/jaxrs/ext/logging/package-info.java Tue Nov 17 22:49:55 2009
@@ -0,0 +1,28 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+/**
+ * JAX-RS specific logging support. Based on <tt>java.util.logging</tt> (JUL)
+ * with use of different logging frameworks factored out; assumes that client
+ * with source code logging to other systems, like Log4J, can bridge
+ * to this implementation applying <a href="www.slf4j.org">SLF4J</a>
+ * that JAXRS already depends on.
+ */
+package org.apache.cxf.jaxrs.ext.logging;
+
Added: cxf/trunk/systests/jaxrs/src/test/java/org/apache/cxf/systest/jaxrs/JAXRSLoggingAtomPushTest.java
URL: http://svn.apache.org/viewvc/cxf/trunk/systests/jaxrs/src/test/java/org/apache/cxf/systest/jaxrs/JAXRSLoggingAtomPushTest.java?rev=881592&view=auto
==============================================================================
--- cxf/trunk/systests/jaxrs/src/test/java/org/apache/cxf/systest/jaxrs/JAXRSLoggingAtomPushTest.java (added)
+++ cxf/trunk/systests/jaxrs/src/test/java/org/apache/cxf/systest/jaxrs/JAXRSLoggingAtomPushTest.java Tue Nov 17 22:49:55 2009
@@ -0,0 +1,157 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.cxf.systest.jaxrs;
+
+import java.io.InputStream;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.List;
+import java.util.logging.Handler;
+import java.util.logging.Level;
+import java.util.logging.LogManager;
+import java.util.logging.LogRecord;
+import java.util.logging.Logger;
+
+import javax.ws.rs.POST;
+import javax.ws.rs.Path;
+
+import org.apache.abdera.model.Element;
+import org.apache.abdera.model.Feed;
+import org.apache.cxf.common.logging.LogUtils;
+import org.apache.cxf.endpoint.Server;
+import org.apache.cxf.jaxrs.JAXRSServerFactoryBean;
+import org.apache.cxf.jaxrs.ext.logging.atom.AtomPushHandler;
+import org.apache.cxf.jaxrs.ext.logging.atom.ContentSingleEntryConverter;
+import org.apache.cxf.jaxrs.ext.logging.atom.WebClientDeliverer;
+import org.apache.cxf.jaxrs.provider.AtomEntryProvider;
+import org.apache.cxf.jaxrs.provider.AtomFeedProvider;
+
+import org.junit.AfterClass;
+import org.junit.Before;
+import org.junit.BeforeClass;
+import org.junit.Ignore;
+import org.junit.Test;
+
+import static org.junit.Assert.assertEquals;
+
+public class JAXRSLoggingAtomPushTest {
+ private static final Logger LOG = LogUtils.getL7dLogger(JAXRSLoggingAtomPushTest.class);
+ private static Server server;
+ private static List<Element> received;
+
+ @Ignore
+ @Path("/")
+ public static class Resource {
+ @POST
+ public void consume(Feed feed) {
+ System.out.println(feed);
+ received.add(feed);
+ }
+ }
+
+ @SuppressWarnings("unchecked")
+ @BeforeClass
+ public static void beforeClass() throws Exception {
+ // disable logging for server startup
+ configureLogging("resources/logging_atompush_disabled.properties");
+
+ JAXRSServerFactoryBean sf = new JAXRSServerFactoryBean();
+ sf.setResourceClasses(JAXRSLoggingAtomPushTest.Resource.class);
+ sf.setAddress("http://localhost:9080/");
+ sf.setProviders(Arrays.asList(new AtomFeedProvider(), new AtomEntryProvider()));
+ server = sf.create();
+ server.start();
+ }
+
+ /** Configures global logging */
+ private static void configureLogging(String propFile) throws Exception {
+ LogManager lm = LogManager.getLogManager();
+ InputStream ins = JAXRSLoggingAtomPushTest.class.getResourceAsStream(propFile);
+ lm.readConfiguration(ins);
+ }
+
+ private static void logSixEvents(Logger log) {
+ log.severe("severe message");
+ log.warning("warning message");
+ log.info("info message");
+ LogRecord r = new LogRecord(Level.FINE, "fine message");
+ r.setThrown(new IllegalArgumentException("tadaam"));
+ log.log(r);
+ r = new LogRecord(Level.FINER, "finer message with {0} and {1}");
+ r.setParameters(new Object[] {
+ "param1", "param2"
+ });
+ r.setLoggerName("faky-logger");
+ log.log(r);
+ log.finest("finest message");
+ }
+
+ @AfterClass
+ public static void afterClass() throws Exception {
+ if (server != null) {
+ server.stop();
+ }
+ LogManager lm = LogManager.getLogManager();
+ try {
+ // restoring original configuration to not use tested logging handlers
+ lm.readConfiguration();
+ } catch (Exception e) {
+ // ignore missing config file
+ }
+ }
+
+ @Before
+ public void before() throws Exception {
+ received = new ArrayList<Element>();
+ }
+
+ @Test
+ public void testOneElementBatch() throws Exception {
+ configureLogging("resources/logging_atompush.properties");
+ logSixEvents(LOG);
+ // need to wait: multithreaded and client-server journey
+ Thread.sleep(1000);
+ assertEquals("Different logged events count;", 6, received.size());
+ }
+
+ @Test
+ public void testMultiElementBatch() throws Exception {
+ configureLogging("resources/logging_atompush_batch.properties");
+ logSixEvents(LOG);
+ // need to wait: multithreaded and client-server journey
+ Thread.sleep(1000);
+ // 6 events / 3 element batch = 2 feeds expected
+ assertEquals("Different logged events count;", 2, received.size());
+ }
+
+ @Test
+ public void testPrivateLogger() throws Exception {
+ configureLogging("resources/logging_atompush_disabled.properties");
+ Logger log = LogUtils.getL7dLogger(JAXRSLoggingAtomPushTest.class, null, "private-log");
+ Handler h = new AtomPushHandler(2, new ContentSingleEntryConverter(),
+ new WebClientDeliverer("http://localhost:9080"));
+ log.addHandler(h);
+ log.setLevel(Level.ALL);
+ logSixEvents(log);
+ // need to wait: multithreaded and client-server journey
+ Thread.sleep(1000);
+ // 6 events / 2 element batch = 3 feeds expected
+ assertEquals("Different logged events count;", 3, received.size());
+ }
+}
Added: cxf/trunk/systests/jaxrs/src/test/java/org/apache/cxf/systest/jaxrs/resources/logging_atompush.properties
URL: http://svn.apache.org/viewvc/cxf/trunk/systests/jaxrs/src/test/java/org/apache/cxf/systest/jaxrs/resources/logging_atompush.properties?rev=881592&view=auto
==============================================================================
--- cxf/trunk/systests/jaxrs/src/test/java/org/apache/cxf/systest/jaxrs/resources/logging_atompush.properties (added)
+++ cxf/trunk/systests/jaxrs/src/test/java/org/apache/cxf/systest/jaxrs/resources/logging_atompush.properties Tue Nov 17 22:49:55 2009
@@ -0,0 +1,33 @@
+# Atom logger plus echo on console
+handlers = org.apache.cxf.jaxrs.ext.logging.atom.AtomPushHandler, java.util.logging.ConsoleHandler
+
+# Set the default logging level for the root logger
+.level = ALL
+
+# Set logging levels for the package-named loggers
+org.apache.cxf.systest.jaxrs.level = ALL
+
+# Need to turn off logging from surrounding environment to properly count log entries in tests
+# (specified sub-entries since root level overrides sub-levels... yes, JUL is dumb :)
+org.apache.cxf.jaxrs.level = OFF
+org.apache.cxf.phase.level = OFF
+org.apache.cxf.service.level = OFF
+org.apache.cxf.interceptor.level = OFF
+org.apache.cxf.transport.level = OFF
+org.apache.cxf.bus.level = OFF
+org.apache.cxf.configuration.level = OFF
+org.apache.cxf.endpoint.level = OFF
+org.apache.cxf.resource.level = OFF
+org.springframework.level = OFF
+org.mortbay.level = OFF
+org.apache.axiom.level = OFF
+
+# Atom handler specific settings
+org.apache.cxf.jaxrs.ext.logging.atom.AtomPushHandler.url = http://localhost:9080
+org.apache.cxf.jaxrs.ext.logging.atom.AtomPushHandler.batchSize = 1
+#org.apache.cxf.jaxrs.ext.logging.atom.AtomPushHandler.converter = ContentSingleEntryConverter
+#org.apache.cxf.jaxrs.ext.logging.atom.AtomPushHandler.deliverer = WebClientDeliverer
+
+#org.apache.cxf.jaxrs.ext.logging.atom.AtomPushHandler.retry.pause = linear
+#org.apache.cxf.jaxrs.ext.logging.atom.AtomPushHandler.retry.pause.time = 5
+#org.apache.cxf.jaxrs.ext.logging.atom.AtomPushHandler.retry.timeout = 10
Added: cxf/trunk/systests/jaxrs/src/test/java/org/apache/cxf/systest/jaxrs/resources/logging_atompush_batch.properties
URL: http://svn.apache.org/viewvc/cxf/trunk/systests/jaxrs/src/test/java/org/apache/cxf/systest/jaxrs/resources/logging_atompush_batch.properties?rev=881592&view=auto
==============================================================================
--- cxf/trunk/systests/jaxrs/src/test/java/org/apache/cxf/systest/jaxrs/resources/logging_atompush_batch.properties (added)
+++ cxf/trunk/systests/jaxrs/src/test/java/org/apache/cxf/systest/jaxrs/resources/logging_atompush_batch.properties Tue Nov 17 22:49:55 2009
@@ -0,0 +1,33 @@
+# Atom logger plus echo on console
+handlers = org.apache.cxf.jaxrs.ext.logging.atom.AtomPushHandler, java.util.logging.ConsoleHandler
+
+# Set the default logging level for the root logger
+.level = ALL
+
+# Set logging levels for the package-named loggers
+org.apache.cxf.systest.jaxrs.level = ALL
+
+# Need to turn off logging from surrounding environment to properly count log entries in tests
+# (specified sub-entries since root level overrides sub-levels... yes, JUL is dumb :)
+org.apache.cxf.jaxrs.level = OFF
+org.apache.cxf.phase.level = OFF
+org.apache.cxf.service.level = OFF
+org.apache.cxf.interceptor.level = OFF
+org.apache.cxf.transport.level = OFF
+org.apache.cxf.bus.level = OFF
+org.apache.cxf.configuration.level = OFF
+org.apache.cxf.endpoint.level = OFF
+org.apache.cxf.resource.level = OFF
+org.springframework.level = OFF
+org.mortbay.level = OFF
+org.apache.axiom.level = OFF
+
+# Atom handler specific settings
+org.apache.cxf.jaxrs.ext.logging.atom.AtomPushHandler.url = http://localhost:9080
+org.apache.cxf.jaxrs.ext.logging.atom.AtomPushHandler.batchSize = 3
+#org.apache.cxf.jaxrs.ext.logging.atom.AtomPushHandler.converter = ContentSingleEntryConverter
+#org.apache.cxf.jaxrs.ext.logging.atom.AtomPushHandler.deliverer = WebClientDeliverer
+
+#org.apache.cxf.jaxrs.ext.logging.atom.AtomPushHandler.retry.pause = linear
+#org.apache.cxf.jaxrs.ext.logging.atom.AtomPushHandler.retry.pause.time = 5
+#org.apache.cxf.jaxrs.ext.logging.atom.AtomPushHandler.retry.timeout = 10
Added: cxf/trunk/systests/jaxrs/src/test/java/org/apache/cxf/systest/jaxrs/resources/logging_atompush_disabled.properties
URL: http://svn.apache.org/viewvc/cxf/trunk/systests/jaxrs/src/test/java/org/apache/cxf/systest/jaxrs/resources/logging_atompush_disabled.properties?rev=881592&view=auto
==============================================================================
--- cxf/trunk/systests/jaxrs/src/test/java/org/apache/cxf/systest/jaxrs/resources/logging_atompush_disabled.properties (added)
+++ cxf/trunk/systests/jaxrs/src/test/java/org/apache/cxf/systest/jaxrs/resources/logging_atompush_disabled.properties Tue Nov 17 22:49:55 2009
@@ -0,0 +1,15 @@
+handlers = java.util.logging.ConsoleHandler
+.level = OFF
+org.apache.cxf.jaxrs.level = OFF
+org.apache.cxf.phase.level = OFF
+org.apache.cxf.service.level = OFF
+org.apache.cxf.interceptor.level = OFF
+org.apache.cxf.transport.level = OFF
+org.apache.cxf.bus.level = OFF
+org.apache.cxf.configuration.level = OFF
+org.apache.cxf.endpoint.level = OFF
+org.apache.cxf.resource.level = OFF
+org.springframework.level = OFF
+org.mortbay.level = OFF
+org.apache.axiom.level = OFF
+