You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@cxf.apache.org by se...@apache.org on 2009/12/18 13:23:54 UTC

svn commit: r892237 - 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/ rt/frontend/jaxrs/src/main/java/org/apache/cxf/jaxrs/ext/logging/atom/converte...

Author: sergeyb
Date: Fri Dec 18 12:23:54 2009
New Revision: 892237

URL: http://svn.apache.org/viewvc?rev=892237&view=rev
Log:
JAXRS : some Atom push logging updates

Added:
    cxf/trunk/rt/frontend/jaxrs/src/main/java/org/apache/cxf/jaxrs/ext/logging/LogRecords.java   (with props)
Removed:
    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/deliverer/FireAndForgetDeliverer.java
Modified:
    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/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/AtomPushEngineConfigurator.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/converter/StandardConverter.java
    cxf/trunk/rt/frontend/jaxrs/src/main/java/org/apache/cxf/jaxrs/ext/logging/atom/deliverer/Deliverer.java
    cxf/trunk/rt/frontend/jaxrs/src/main/java/org/apache/cxf/jaxrs/ext/logging/atom/deliverer/RetryingDeliverer.java
    cxf/trunk/rt/frontend/jaxrs/src/main/java/org/apache/cxf/jaxrs/ext/logging/atom/deliverer/WebClientDeliverer.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/JAXRSLoggingAtomPushSpringTest.java
    cxf/trunk/systests/jaxrs/src/test/java/org/apache/cxf/systest/jaxrs/JAXRSLoggingAtomPushTest.java
    cxf/trunk/systests/jaxrs/src/test/resources/jaxrs_logging_atompush/WEB-INF/beans.xml

Modified: 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=892237&r1=892236&r2=892237&view=diff
==============================================================================
--- cxf/trunk/rt/frontend/jaxrs/src/main/java/org/apache/cxf/jaxrs/ext/logging/LogRecord.java (original)
+++ cxf/trunk/rt/frontend/jaxrs/src/main/java/org/apache/cxf/jaxrs/ext/logging/LogRecord.java Fri Dec 18 12:23:54 2009
@@ -39,7 +39,7 @@
  * 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(namespace = "http://cxf.apache.org/jaxrs/log")
+@XmlRootElement(namespace = "http://cxf.apache.org/log")
 public class LogRecord {
 
     private Date eventTimestamp = new Date();
@@ -77,7 +77,7 @@
         return record;
     }
 
-    @XmlElement(namespace = "http://cxf.apache.org/jaxrs/log")
+    @XmlElement(namespace = "http://cxf.apache.org/log")
     public Date getEventTimestamp() {
         return eventTimestamp;
     }
@@ -87,7 +87,7 @@
         this.eventTimestamp = eventTimestamp;
     }
 
-    @XmlElement(namespace = "http://cxf.apache.org/jaxrs/log")
+    @XmlElement(namespace = "http://cxf.apache.org/log")
     public LogLevel getLevel() {
         return level;
     }
@@ -100,7 +100,7 @@
     /**
      * Formatted message with parameters filled in.
      */
-    @XmlElement(namespace = "http://cxf.apache.org/jaxrs/log")
+    @XmlElement(namespace = "http://cxf.apache.org/log")
     public String getMessage() {
         return message;
     }
@@ -110,7 +110,7 @@
         this.message = renderedMessage;
     }
 
-    @XmlElement(namespace = "http://cxf.apache.org/jaxrs/log")
+    @XmlElement(namespace = "http://cxf.apache.org/log")
     public String getLoggerName() {
         return loggerName;
     }
@@ -120,7 +120,7 @@
         this.loggerName = loggerName;
     }
 
-    @XmlElement(namespace = "http://cxf.apache.org/jaxrs/log")
+    @XmlElement(namespace = "http://cxf.apache.org/log")
     public String getThreadName() {
         return threadName;
     }
@@ -133,7 +133,7 @@
     /**
      * Full stack trace of {@link Throwable} associated with log record.
      */
-    @XmlElement(namespace = "http://cxf.apache.org/jaxrs/log")
+    @XmlElement(namespace = "http://cxf.apache.org/log")
     public String getThrowable() {
         return throwable;
     }

Added: cxf/trunk/rt/frontend/jaxrs/src/main/java/org/apache/cxf/jaxrs/ext/logging/LogRecords.java
URL: http://svn.apache.org/viewvc/cxf/trunk/rt/frontend/jaxrs/src/main/java/org/apache/cxf/jaxrs/ext/logging/LogRecords.java?rev=892237&view=auto
==============================================================================
--- cxf/trunk/rt/frontend/jaxrs/src/main/java/org/apache/cxf/jaxrs/ext/logging/LogRecords.java (added)
+++ cxf/trunk/rt/frontend/jaxrs/src/main/java/org/apache/cxf/jaxrs/ext/logging/LogRecords.java Fri Dec 18 12:23:54 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 = "http://cxf.apache.org/log")
+public class LogRecords {
+
+    private List<LogRecord> logRecords = new ArrayList<LogRecord>();
+
+    @XmlElement(name = "logRecord", namespace = "http://cxf.apache.org/log")
+    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);
+    }
+}

Propchange: cxf/trunk/rt/frontend/jaxrs/src/main/java/org/apache/cxf/jaxrs/ext/logging/LogRecords.java
------------------------------------------------------------------------------
    svn:eol-style = native

Propchange: cxf/trunk/rt/frontend/jaxrs/src/main/java/org/apache/cxf/jaxrs/ext/logging/LogRecords.java
------------------------------------------------------------------------------
    svn:keywords = Rev Date

Modified: 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=892237&r1=892236&r2=892237&view=diff
==============================================================================
--- cxf/trunk/rt/frontend/jaxrs/src/main/java/org/apache/cxf/jaxrs/ext/logging/atom/AtomPushBean.java (original)
+++ cxf/trunk/rt/frontend/jaxrs/src/main/java/org/apache/cxf/jaxrs/ext/logging/atom/AtomPushBean.java Fri Dec 18 12:23:54 2009
@@ -189,6 +189,15 @@
         Validate.notNull(batchSize, "batchSize is null");
         conf.setBatchSize(batchSize);
     }
+    
+    /**
+     * Batch cleanup time in minutes
+     */
+    public void setBatchCleanupTime(String batchCleanupTime) {
+        checkInit();
+        Validate.notNull(batchCleanupTime, "batchCleanup is null");
+        conf.setBatchCleanupTime(batchCleanupTime);
+    }
 
     /**
      * Retry pause calculation strategy, either "linear" or "exponential".

Modified: 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=892237&r1=892236&r2=892237&view=diff
==============================================================================
--- cxf/trunk/rt/frontend/jaxrs/src/main/java/org/apache/cxf/jaxrs/ext/logging/atom/AtomPushEngine.java (original)
+++ cxf/trunk/rt/frontend/jaxrs/src/main/java/org/apache/cxf/jaxrs/ext/logging/atom/AtomPushEngine.java Fri Dec 18 12:23:54 2009
@@ -19,7 +19,10 @@
 package org.apache.cxf.jaxrs.ext.logging.atom;
 
 import java.util.ArrayList;
+import java.util.Collections;
 import java.util.List;
+import java.util.Timer;
+import java.util.TimerTask;
 import java.util.concurrent.ExecutorService;
 import java.util.concurrent.Executors;
 
@@ -51,9 +54,11 @@
     private List<LogRecord> queue = new ArrayList<LogRecord>();
     private ExecutorService executor = Executors.newSingleThreadExecutor();
     private int batchSize = 1;
+    private int batchTime;
     private Converter converter;
     private Deliverer deliverer;
-
+    private Timer timer;
+    
     /**
      * 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
@@ -64,19 +69,33 @@
     public synchronized void publish(LogRecord record) {
         Validate.notNull(record, "record is null");
         if (isValid()) {
+            if (batchSize > 1 && batchTime > 0 && timer == null) {
+                createTimerTask(batchTime * 60 * 1000);
+            }
             queue.add(record);
             if (queue.size() >= batchSize) {
-                publishBatch(queue);
-                queue = new ArrayList<LogRecord>();
+                publishAndReset();
             }
+        } else {
+            handleUndeliveredRecords(Collections.singletonList(record), 
+                                     deliverer == null ? "" : deliverer.getEndpointAddress());
         }
     }
+    
+    protected synchronized void publishAndReset() {
+        publishBatch(queue, deliverer, converter);
+        queue = new ArrayList<LogRecord>();
+    }
 
     /**
      * Shuts engine down.
      */
     public synchronized void shutdown() {
-        executor.shutdownNow();
+        cancelTimerTask();
+        if (isValid() && queue.size() > 0) {
+            publishAndReset();
+        }
+        executor.shutdown();
     }
 
     private boolean isValid() {
@@ -96,25 +115,36 @@
         return true;
     }
 
-    private void publishBatch(final List<LogRecord> batch) {
+    private void publishBatch(final List<LogRecord> batch,
+                              final Deliverer d,
+                              final Converter c) {
         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());
-                        List<? extends Element> elements = converter.convert(batch);
-                        for (Element element : elements) {
-                            if (!deliverer.deliver(element)) {
-                                System.err.println("Delivery failed, shutting engine down");
-                                executor.shutdownNow();
-                                break;
+                    List<? extends Element> elements = c.convert(batch);
+                    for (int i = 0; i < elements.size(); i++) {
+                        Element element = elements.get(i);
+                        if (!d.deliver(element)) {
+                            System.err.println("Delivery to " + d.getEndpointAddress() 
+                                + " failed, shutting engine down");
+                            List<LogRecord> undelivered = null;
+                            if (i == 0) {
+                                undelivered = batch;
+                            } else {
+                                int index = (batch.size() / elements.size()) * i;
+                                // should not happen but just in case :-)
+                                if (index < batch.size()) {
+                                    undelivered = batch.subList(index, batch.size());
+                                }
                             }
+                            handleUndeliveredRecords(undelivered, d.getEndpointAddress());
+                            shutdown();
+                            break;
                         }
                     }
                 } catch (InterruptedException e) {
-                    // no action on executor.shutdownNow();
+                    // no action
                 } finally {
                     LoggingThread.markSilent(false);
                 }
@@ -122,6 +152,14 @@
         });
     }
 
+    protected void handleUndeliveredRecords(List<LogRecord> records, String address) {
+        // TODO : save them to some transient storage perhaps ?
+        System.err.println("The following records have been undelivered to " + address + " : ");
+        for (LogRecord r : records) {
+            System.err.println(r.toString());
+        }
+    }
+    
     public int getBatchSize() {
         return batchSize;
     }
@@ -130,8 +168,36 @@
         Validate.isTrue(batchSize > 0, "batch size is not greater than zero");
         this.batchSize = batchSize;
     }
+    
+    public void setBatchTime(int batchTime) {
+        this.batchTime = batchTime;
+    }
 
-    public Converter getConverter() {
+    /**
+     * Creates a timer task which will periodically flush the batch queue
+     * thus ensuring log records won't become too 'stale'. 
+     * Ex, if we have a batch size 10 and only WARN records need to be delivered
+     * then without the periodic cleanup the consumers may not get prompt notifications
+     *  
+     * @param timeout
+     */
+    protected void createTimerTask(long timeout) {
+        timer = new Timer();
+        timer.schedule(new TimerTask() {
+            public void run() {
+                publishAndReset();
+            }
+        }, timeout);
+    }
+    
+    protected void cancelTimerTask() {
+        if (timer != null) {
+            timer.cancel();
+            timer = null;
+        }
+    }
+    
+    public synchronized Converter getConverter() {
         return converter;
     }
 
@@ -140,7 +206,7 @@
         this.converter = converter;
     }
 
-    public Deliverer getDeliverer() {
+    public synchronized Deliverer getDeliverer() {
         return deliverer;
     }
 

Modified: cxf/trunk/rt/frontend/jaxrs/src/main/java/org/apache/cxf/jaxrs/ext/logging/atom/AtomPushEngineConfigurator.java
URL: http://svn.apache.org/viewvc/cxf/trunk/rt/frontend/jaxrs/src/main/java/org/apache/cxf/jaxrs/ext/logging/atom/AtomPushEngineConfigurator.java?rev=892237&r1=892236&r2=892237&view=diff
==============================================================================
--- cxf/trunk/rt/frontend/jaxrs/src/main/java/org/apache/cxf/jaxrs/ext/logging/atom/AtomPushEngineConfigurator.java (original)
+++ cxf/trunk/rt/frontend/jaxrs/src/main/java/org/apache/cxf/jaxrs/ext/logging/atom/AtomPushEngineConfigurator.java Fri Dec 18 12:23:54 2009
@@ -41,6 +41,7 @@
     private String delivererClass;
     private String converterClass;
     private String batchSize;
+    private String batchCleanupTime;
     private String delivererUrl;
     private String retryTimeout;
     private String retryPause;
@@ -65,6 +66,10 @@
         this.retryPauseTime = retryPauseTime;
     }
 
+    public void setBatchCleanupTime(String cleanupTime) {
+        this.batchCleanupTime = cleanupTime;
+    }
+    
     public void setBatchSize(String batchSize) {
         this.batchSize = batchSize;
     }
@@ -101,6 +106,7 @@
         Deliverer d = deliverer;
         Converter c = converter;
         int batch = parseInt(batchSize, 1, 1);
+        int batchTime = parseInt(batchCleanupTime, 0);
         if (d == null) {
             if (delivererUrl != null) {
                 if (delivererClass != null) {
@@ -118,9 +124,15 @@
                 c = createConverter(converterClass);
             } else {
                 Output out = parseEnum(output, Output.FEED);
-                Multiplicity mul = parseEnum(multiplicity, Multiplicity.ONE);
+                Multiplicity defaultMul = out == Output.FEED ? Multiplicity.MANY
+                    : batch > 1 ? Multiplicity.MANY : Multiplicity.ONE; 
+                Multiplicity mul = parseEnum(multiplicity, defaultMul);
                 Format form = parseEnum(format, Format.CONTENT);
-                c = new StandardConverter(out, mul, form);
+                if (out == Output.FEED) {
+                    c = new StandardConverter(out, mul, form);
+                } else {
+                    c = new StandardConverter(out, mul, form);
+                }
                 if (retryPause != null) {
                     int timeout = parseInt(retryTimeout, 0, 0);
                     int pause = parseInt(retryPauseTime, 1, 30);
@@ -133,6 +145,7 @@
         engine.setDeliverer(d);
         engine.setConverter(c);
         engine.setBatchSize(batch);
+        engine.setBatchTime(batchTime);
         return engine;
     }
 
@@ -145,6 +158,7 @@
         }
     }
 
+    @SuppressWarnings("unchecked")
     private Converter createConverter(String clazz) {
         try {
             Constructor<Converter> ctor = loadClass(clazz, Converter.class).getConstructor();

Modified: 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=892237&r1=892236&r2=892237&view=diff
==============================================================================
--- cxf/trunk/rt/frontend/jaxrs/src/main/java/org/apache/cxf/jaxrs/ext/logging/atom/AtomPushHandler.java (original)
+++ cxf/trunk/rt/frontend/jaxrs/src/main/java/org/apache/cxf/jaxrs/ext/logging/atom/AtomPushHandler.java Fri Dec 18 12:23:54 2009
@@ -173,6 +173,7 @@
         conf.setDelivererClass(manager.getProperty(cname + ".deliverer"));
         conf.setConverterClass(manager.getProperty(cname + ".converter"));
         conf.setBatchSize(manager.getProperty(cname + ".batchSize"));
+        conf.setBatchCleanupTime(manager.getProperty(cname + ".batchCleanupTime"));
         conf.setRetryPause(manager.getProperty(cname + ".retry.pause"));
         conf.setRetryPauseTime(manager.getProperty(cname + ".retry.pause.time"));
         conf.setRetryTimeout(manager.getProperty(cname + ".retry.timeout"));

Modified: cxf/trunk/rt/frontend/jaxrs/src/main/java/org/apache/cxf/jaxrs/ext/logging/atom/converter/StandardConverter.java
URL: http://svn.apache.org/viewvc/cxf/trunk/rt/frontend/jaxrs/src/main/java/org/apache/cxf/jaxrs/ext/logging/atom/converter/StandardConverter.java?rev=892237&r1=892236&r2=892237&view=diff
==============================================================================
--- cxf/trunk/rt/frontend/jaxrs/src/main/java/org/apache/cxf/jaxrs/ext/logging/atom/converter/StandardConverter.java (original)
+++ cxf/trunk/rt/frontend/jaxrs/src/main/java/org/apache/cxf/jaxrs/ext/logging/atom/converter/StandardConverter.java Fri Dec 18 12:23:54 2009
@@ -31,7 +31,6 @@
 
 import javax.xml.bind.JAXBContext;
 import javax.xml.bind.JAXBException;
-import javax.xml.bind.Marshaller;
 import javax.xml.namespace.QName;
 
 import org.apache.abdera.Abdera;
@@ -45,7 +44,7 @@
 import org.apache.cxf.jaxrs.ext.atom.AbstractEntryBuilder;
 import org.apache.cxf.jaxrs.ext.atom.AbstractFeedBuilder;
 import org.apache.cxf.jaxrs.ext.logging.LogRecord;
-import org.apache.cxf.jaxrs.ext.logging.LogRecordsList;
+import org.apache.cxf.jaxrs.ext.logging.LogRecords;
 
 /**
  * Converter producing ATOM Feeds on standalone Entries with LogRecords or LogRecordsLists embedded as content
@@ -72,10 +71,11 @@
     }
 
     private Factory factory;
-    private Marshaller marsh;
+    private JAXBContext context;
     private DateFormat df;
     private Converter worker;
-    private Postprocessor postprocessor;
+    private AbstractFeedBuilder<List<LogRecord>> feedBuilder;
+    private AbstractEntryBuilder<List<LogRecord>> entryBuilder;
 
     /**
      * Creates configured converter with default post-processing of feeds/entries mandatory properties.
@@ -95,7 +95,7 @@
      * @param format log records embedded as entry content or extension.
      */
     public StandardConverter(Output output, Multiplicity multiplicity, Format format) {
-        this(output, multiplicity, format, new DefaultPostprocessor());
+        this(output, multiplicity, format, null, null);
     }
 
     /**
@@ -105,21 +105,17 @@
     public StandardConverter(Output output, Multiplicity multiplicity, Format format,
                              AbstractFeedBuilder<List<LogRecord>> feedBuilder,
                              AbstractEntryBuilder<List<LogRecord>> entryBuilder) {
-        this(output, multiplicity, format, new BuilderPostprocessor(feedBuilder, entryBuilder));
-    }
-
-    private StandardConverter(Output output, Multiplicity multiplicity, Format format,
-                              Postprocessor postprocessor) {
         Validate.notNull(output, "output is null");
         Validate.notNull(multiplicity, "multiplicity is null");
         Validate.notNull(format, "format is null");
-        Validate.notNull(postprocessor, "interceptor is null");
+        this.feedBuilder = feedBuilder;
+        this.entryBuilder = entryBuilder;
+        
         configure(output, multiplicity, format);
-        this.postprocessor = postprocessor;
         df = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss.SSSZ");
         factory = Abdera.getNewFactory();
         try {
-            marsh = JAXBContext.newInstance(LogRecordsList.class).createMarshaller();
+            context = JAXBContext.newInstance(LogRecords.class, LogRecord.class);
         } catch (JAXBException e) {
             throw new RuntimeException(e);
         }
@@ -132,73 +128,32 @@
     private void configure(final Output output, final Multiplicity multiplicity, final Format format) {
         if (output == Output.ENTRY && multiplicity == Multiplicity.ONE) {
             worker = new Converter() {
-                public List<? extends Element> convert(List<LogRecord> records) {
-                    // produces many entries, each entry with one log record
-                    List<Element> ret = new ArrayList<Element>();
-                    for (LogRecord record : records) {
-                        Entry e;
-                        if (format == Format.CONTENT) {
-                            e = createEntry(createContent(record));
-                        } else {
-                            e = createEntry(createExtension(record));
-                        }
-                        ret.add(e);
-                        postprocessor.afterEntry(e, Collections.singletonList(record));
-                    }
-                    return ret;
+                public List<Entry> convert(List<LogRecord> records) {
+                    return createEntries(format, records);
                 }
             };
         }
         if (output == Output.ENTRY && multiplicity == Multiplicity.MANY) {
             worker = new Converter() {
-                public List<? extends Element> convert(List<LogRecord> records) {
+                public List<Entry> convert(List<LogRecord> records) {
                     // produces one entry with list of all log records
-                    Entry e;
-                    if (format == Format.CONTENT) {
-                        e = createEntry(createContent(records));
-                    } else {
-                        e = createEntry(createExtension(records));
-                    }
-                    postprocessor.afterEntry(e, records);
-                    return Arrays.asList(e);
+                    return Arrays.asList(createEntryFromList(format, records));
                 }
             };
         }
         if (output == Output.FEED && multiplicity == Multiplicity.ONE) {
             worker = new Converter() {
-                public List<? extends Element> convert(List<LogRecord> records) {
+                public List<Feed> convert(List<LogRecord> records) {
                     // produces one feed with one entry with list of all log records
-                    Entry e;
-                    if (format == Format.CONTENT) {
-                        e = createEntry(createContent(records));
-                    } else {
-                        e = createEntry(createExtension(records));
-                    }
-                    postprocessor.afterEntry(e, records);
-                    Feed f = createFeed(e);
-                    postprocessor.afterFeed(f, records);
-                    return Arrays.asList(f);
+                    return Arrays.asList(createFeedWithSingleEntry(format, records));
                 }
             };
         }
         if (output == Output.FEED && multiplicity == Multiplicity.MANY) {
             worker = new Converter() {
-                public List<? extends Element> convert(List<LogRecord> records) {
+                public List<Feed> convert(List<LogRecord> records) {
                     // produces one feed with many entries, each entry with one log record
-                    List<Entry> entries = new ArrayList<Entry>();
-                    for (LogRecord record : records) {
-                        Entry e;
-                        if (format == Format.CONTENT) {
-                            e = createEntry(createContent(record));
-                        } else {
-                            e = createEntry(createExtension(record));
-                        }
-                        entries.add(e);
-                        postprocessor.afterEntry(e, Collections.singletonList(record));
-                    }
-                    Feed f = createFeed(entries);
-                    postprocessor.afterFeed(f, records);
-                    return Arrays.asList(f);
+                    return Arrays.asList(createFeed(format, records));
                 }
             };
         }
@@ -207,10 +162,38 @@
         }
     }
 
+    private List<Entry> createEntries(Format format, List<LogRecord> records) {
+        List<Entry> entries = new ArrayList<Entry>();
+        for (LogRecord record : records) {
+            entries.add(createEntryFromRecord(format, record));
+        }
+        return entries;
+    }
+    
+    private Entry createEntryFromList(Format format, List<LogRecord> records) {
+        Entry e = createEntry(records);
+        if (format == Format.CONTENT) {
+            setEntryContent(e, createContent(records));
+        } else {
+            setEntryContent(e, createExtension(records));
+        }
+        return e;
+    }
+    
+    private Entry createEntryFromRecord(Format format, LogRecord record) {
+        Entry e = createEntry(Collections.singletonList(record));
+        if (format == Format.CONTENT) {
+            setEntryContent(e, createContent(record));
+        } else {
+            setEntryContent(e, createExtension(record));
+        }
+        return e;
+    }
+    
     private String createContent(LogRecord record) {
         StringWriter writer = new StringWriter();
         try {
-            marsh.marshal(record, writer);
+            context.createMarshaller().marshal(record, writer);
         } catch (JAXBException e) {
             throw new RuntimeException(e);
         }
@@ -219,10 +202,10 @@
 
     private String createContent(List<LogRecord> records) {
         StringWriter writer = new StringWriter();
-        LogRecordsList list = new LogRecordsList();
+        LogRecords list = new LogRecords();
         list.setLogRecords(records);
         try {
-            marsh.marshal(list, writer);
+            context.createMarshaller().marshal(list, writer);
         } catch (JAXBException e) {
             throw new RuntimeException(e);
         }
@@ -254,86 +237,80 @@
     }
 
     private QName qn(String name) {
-        return new QName("http://cxf.apache.org/jaxrs/log", name, "log");
+        return new QName("http://cxf.apache.org/log", name, "log");
     }
 
     private ExtensibleElement createExtension(List<LogRecord> records) {
-        ExtensibleElement list = factory.newExtensionElement(qn("logRecordsList"));
+        ExtensibleElement list = factory.newExtensionElement(qn("logRecords"));
         for (LogRecord rec : records) {
             list.addExtension(createExtension(rec));
         }
         return list;
     }
 
-    private Entry createEntry(String content) {
+    private Entry createEntry(List<LogRecord> records) {
         Entry entry = factory.newEntry();
-        entry.setContent(content, Content.Type.XML);
+        setDefaultEntryProperties(entry, records);
+        
         return entry;
     }
+    
+    private void setEntryContent(Entry e, String content) {
+        e.setContent(content, Content.Type.XML);
+    }
 
-    private Entry createEntry(ExtensibleElement ext) {
-        Entry entry = factory.newEntry();
-        entry.addExtension(ext);
-        return entry;
+    private void setEntryContent(Entry e, ExtensibleElement ext) {
+        e.addExtension(ext);
     }
 
-    private Feed createFeed(Entry entry) {
+    private Feed createFeedWithSingleEntry(Format format, List<LogRecord> records) {
+        
         Feed feed = factory.newFeed();
-        feed.addEntry(entry);
+        feed.addEntry(createEntryFromList(format, records));
+        setDefaultFeedProperties(feed, records);
         return feed;
     }
-
-    private Feed createFeed(List<Entry> entries) {
+    
+    private Feed createFeed(Format format, List<LogRecord> records) {
+        
         Feed feed = factory.newFeed();
+        List<Entry> entries = createEntries(format, records);
         for (Entry entry : entries) {
             feed.addEntry(entry);
         }
+        setDefaultFeedProperties(feed, records);
         return feed;
     }
 
-    /**
-     * Post-processing for feeds/entries properties customization eg setup of dates, titles, author etc.
-     */
-    private interface Postprocessor {
-
-        /** Called after entry creation for given log records. */
-        void afterEntry(Entry entry, List<LogRecord> records);
-
-        /** Called after feed creation; at this stage feed has associated entries. */
-        void afterFeed(Feed feed, List<LogRecord> records);
-    }
-
-    private static class DefaultPostprocessor implements Postprocessor {
-        public void afterEntry(Entry entry, List<LogRecord> records) {
-            // required fields (see RFC 4287)
-            entry.setId("uuid:" + UUID.randomUUID().toString());
-            entry.addAuthor("CXF");
-            entry.setTitle(String.format("Entry with %d log record(s)", records.size()));
-            entry.setUpdated(new Date());
-        }
-
-        public void afterFeed(Feed feed, List<LogRecord> records) {
-            // required fields (see RFC 4287)
+    protected void setDefaultFeedProperties(Feed feed, List<LogRecord> records) {
+        if (feedBuilder != null) {
+            feed.setId(feedBuilder.getId(records));
+            feed.addAuthor(feedBuilder.getAuthor(records));
+            feed.setTitle(feedBuilder.getTitle(records));
+            feed.setUpdated(feedBuilder.getUpdated(records));
+            feed.setBaseUri(feedBuilder.getBaseUri(records));
+            List<String> categories = feedBuilder.getCategories(records);
+            if (categories != null) {
+                for (String category : categories) {
+                    feed.addCategory(category);
+                }
+            }
+            Map<String, String> links = feedBuilder.getLinks(records);
+            if (links != null) {
+                for (java.util.Map.Entry<String, String> mapEntry : links.entrySet()) {
+                    feed.addLink(mapEntry.getKey(), mapEntry.getValue());
+                }
+            }            
+        } else {
             feed.setId("uuid:" + UUID.randomUUID().toString());
             feed.addAuthor("CXF");
             feed.setTitle(String.format("Feed with %d entry(ies)", feed.getEntries().size()));
             feed.setUpdated(new Date());
         }
     }
-
-    private static class BuilderPostprocessor implements Postprocessor {
-        private AbstractFeedBuilder<List<LogRecord>> feedBuilder;
-        private AbstractEntryBuilder<List<LogRecord>> entryBuilder;
-
-        public BuilderPostprocessor(AbstractFeedBuilder<List<LogRecord>> feedBuilder,
-                                    AbstractEntryBuilder<List<LogRecord>> entryBuilder) {
-            Validate.notNull(feedBuilder, "feedBuilder is null");
-            Validate.notNull(entryBuilder, "entryBuilder is null");
-            this.feedBuilder = feedBuilder;
-            this.entryBuilder = entryBuilder;
-        }
-
-        public void afterEntry(Entry entry, List<LogRecord> records) {
+    
+    protected void setDefaultEntryProperties(Entry entry, List<LogRecord> records) {
+        if (entryBuilder != null) {
             entry.setId(entryBuilder.getId(records));
             entry.addAuthor(entryBuilder.getAuthor(records));
             entry.setTitle(entryBuilder.getTitle(records));
@@ -353,26 +330,13 @@
             }
             entry.setPublished(entryBuilder.getPublished(records));
             entry.setSummary(entryBuilder.getSummary(records));
-        }
-
-        public void afterFeed(Feed feed, List<LogRecord> records) {
-            feed.setId(feedBuilder.getId(records));
-            feed.addAuthor(feedBuilder.getAuthor(records));
-            feed.setTitle(feedBuilder.getTitle(records));
-            feed.setUpdated(feedBuilder.getUpdated(records));
-            feed.setBaseUri(feedBuilder.getBaseUri(records));
-            List<String> categories = feedBuilder.getCategories(records);
-            if (categories != null) {
-                for (String category : categories) {
-                    feed.addCategory(category);
-                }
-            }
-            Map<String, String> links = feedBuilder.getLinks(records);
-            if (links != null) {
-                for (java.util.Map.Entry<String, String> mapEntry : links.entrySet()) {
-                    feed.addLink(mapEntry.getKey(), mapEntry.getValue());
-                }
-            }
+        } else {    
+            entry.setId("uuid:" + UUID.randomUUID().toString());
+            entry.addAuthor("CXF");
+            entry.setTitle(String.format("Entry with %d log record(s)", 
+                                         records.size()));
+            entry.setUpdated(new Date());
         }
     }
+    
 }

Modified: cxf/trunk/rt/frontend/jaxrs/src/main/java/org/apache/cxf/jaxrs/ext/logging/atom/deliverer/Deliverer.java
URL: http://svn.apache.org/viewvc/cxf/trunk/rt/frontend/jaxrs/src/main/java/org/apache/cxf/jaxrs/ext/logging/atom/deliverer/Deliverer.java?rev=892237&r1=892236&r2=892237&view=diff
==============================================================================
--- cxf/trunk/rt/frontend/jaxrs/src/main/java/org/apache/cxf/jaxrs/ext/logging/atom/deliverer/Deliverer.java (original)
+++ cxf/trunk/rt/frontend/jaxrs/src/main/java/org/apache/cxf/jaxrs/ext/logging/atom/deliverer/Deliverer.java Fri Dec 18 12:23:54 2009
@@ -33,4 +33,10 @@
      * @return true if delivery successful, false otherwise.
      */
     boolean deliver(Element element) throws InterruptedException;
+    
+    /**
+     * Returns the address of the remote endpoint this deliverer send elements to
+     * @return
+     */
+    String getEndpointAddress();
 }

Modified: cxf/trunk/rt/frontend/jaxrs/src/main/java/org/apache/cxf/jaxrs/ext/logging/atom/deliverer/RetryingDeliverer.java
URL: http://svn.apache.org/viewvc/cxf/trunk/rt/frontend/jaxrs/src/main/java/org/apache/cxf/jaxrs/ext/logging/atom/deliverer/RetryingDeliverer.java?rev=892237&r1=892236&r2=892237&view=diff
==============================================================================
--- cxf/trunk/rt/frontend/jaxrs/src/main/java/org/apache/cxf/jaxrs/ext/logging/atom/deliverer/RetryingDeliverer.java (original)
+++ cxf/trunk/rt/frontend/jaxrs/src/main/java/org/apache/cxf/jaxrs/ext/logging/atom/deliverer/RetryingDeliverer.java Fri Dec 18 12:23:54 2009
@@ -136,4 +136,8 @@
         }
     }
 
+    public String getEndpointAddress() {
+        return deliverer.getEndpointAddress();
+    }
+
 }

Modified: cxf/trunk/rt/frontend/jaxrs/src/main/java/org/apache/cxf/jaxrs/ext/logging/atom/deliverer/WebClientDeliverer.java
URL: http://svn.apache.org/viewvc/cxf/trunk/rt/frontend/jaxrs/src/main/java/org/apache/cxf/jaxrs/ext/logging/atom/deliverer/WebClientDeliverer.java?rev=892237&r1=892236&r2=892237&view=diff
==============================================================================
--- cxf/trunk/rt/frontend/jaxrs/src/main/java/org/apache/cxf/jaxrs/ext/logging/atom/deliverer/WebClientDeliverer.java (original)
+++ cxf/trunk/rt/frontend/jaxrs/src/main/java/org/apache/cxf/jaxrs/ext/logging/atom/deliverer/WebClientDeliverer.java Fri Dec 18 12:23:54 2009
@@ -24,6 +24,7 @@
 import javax.ws.rs.core.Response;
 
 import org.apache.abdera.model.Element;
+import org.apache.abdera.model.Feed;
 import org.apache.commons.lang.Validate;
 import org.apache.cxf.jaxrs.client.WebClient;
 import org.apache.cxf.jaxrs.provider.AtomEntryProvider;
@@ -40,7 +41,6 @@
         Validate.notEmpty(deliveryAddress, "deliveryAddress is empty or null");
         List<?> providers = Arrays.asList(new AtomFeedProvider(), new AtomEntryProvider());
         wc = WebClient.create(deliveryAddress, providers);
-        wc.type("application/atom+xml");
     }
 
     public WebClientDeliverer(WebClient wc) {
@@ -49,8 +49,14 @@
     }
 
     public boolean deliver(Element element) {
+        String type = element instanceof Feed ? "application/atom+xml" : "application/atom+xml;type=entry";
+        wc.type(type);
         Response res = wc.post(element);
         int status = res.getStatus();
         return status >= 200 && status <= 299;
     }
+    
+    public String getEndpointAddress() {
+        return wc.getBaseURI().toString();
+    }
 }

Modified: 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=892237&r1=892236&r2=892237&view=diff
==============================================================================
--- cxf/trunk/rt/frontend/jaxrs/src/main/java/org/apache/cxf/jaxrs/ext/logging/package-info.java (original)
+++ cxf/trunk/rt/frontend/jaxrs/src/main/java/org/apache/cxf/jaxrs/ext/logging/package-info.java Fri Dec 18 12:23:54 2009
@@ -18,14 +18,14 @@
  */
 
 /**
- * JAX-RS specific logging support. Based on <tt>java.util.logging</tt> (JUL)
+ * CXF 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.
  */
 @javax.xml.bind.annotation.XmlSchema(xmlns = {
-        @javax.xml.bind.annotation.XmlNs(namespaceURI = "http://cxf.apache.org/jaxrs/log", prefix = "log")
+        @javax.xml.bind.annotation.XmlNs(namespaceURI = "http://cxf.apache.org/log", prefix = "log")
             })
 package org.apache.cxf.jaxrs.ext.logging;
 

Modified: cxf/trunk/systests/jaxrs/src/test/java/org/apache/cxf/systest/jaxrs/JAXRSLoggingAtomPushSpringTest.java
URL: http://svn.apache.org/viewvc/cxf/trunk/systests/jaxrs/src/test/java/org/apache/cxf/systest/jaxrs/JAXRSLoggingAtomPushSpringTest.java?rev=892237&r1=892236&r2=892237&view=diff
==============================================================================
--- cxf/trunk/systests/jaxrs/src/test/java/org/apache/cxf/systest/jaxrs/JAXRSLoggingAtomPushSpringTest.java (original)
+++ cxf/trunk/systests/jaxrs/src/test/java/org/apache/cxf/systest/jaxrs/JAXRSLoggingAtomPushSpringTest.java Fri Dec 18 12:23:54 2009
@@ -18,6 +18,7 @@
  */
 package org.apache.cxf.systest.jaxrs;
 
+import java.io.StringReader;
 import java.util.ArrayList;
 import java.util.List;
 import java.util.logging.Level;
@@ -27,11 +28,16 @@
 import javax.ws.rs.GET;
 import javax.ws.rs.POST;
 import javax.ws.rs.Path;
+import javax.xml.bind.JAXBContext;
+import javax.xml.namespace.QName;
 
 import org.apache.abdera.model.Element;
+import org.apache.abdera.model.Entry;
+import org.apache.abdera.model.ExtensibleElement;
 import org.apache.abdera.model.Feed;
 import org.apache.cxf.common.logging.LogUtils;
 import org.apache.cxf.jaxrs.client.WebClient;
+import org.apache.cxf.jaxrs.ext.logging.LogRecords;
 import org.apache.cxf.testutil.common.AbstractClientServerTestBase;
 
 import org.junit.Before;
@@ -41,8 +47,12 @@
 
 public class JAXRSLoggingAtomPushSpringTest extends AbstractClientServerTestBase {
 
-    private static List<Element> retrieved = new ArrayList<Element>();
-
+    private JAXBContext context; 
+    private int fakyLogger;
+    private int namedLogger;
+    private int resourceLogger;
+    private int throwables;
+    
     @BeforeClass
     public static void beforeClass() throws Exception {
         // must be 'in-process' to communicate with inner class in single JVM
@@ -58,53 +68,367 @@
     }
 
     @Before
-    public void before() {
-        retrieved.clear();
+    public void before() throws Exception {
+        Resource.clear();
+        Resource2.clear();
+        Resource3.clear();
+        Resource4.clear();
+        Resource5.clear();
+        context = JAXBContext.newInstance(LogRecords.class, 
+            org.apache.cxf.jaxrs.ext.logging.LogRecord.class);
     }
 
+    @Test
+    public void testFeedsWithLogRecordsOneEntry() throws Exception {
+        WebClient wc = WebClient.create("http://localhost:9080/root");
+        wc.path("/log").get();
+        Thread.sleep(3000);
+        List<Feed> elements = Resource.getElements();
+        assertEquals(8, elements.size());
+
+        resetCounters();
+        for (Feed feed : elements) {
+            List<Entry> entries = feed.getEntries();
+            assertEquals(1, entries.size());
+            Entry e = entries.get(0);
+            LogRecords records = readLogRecords(e.getContent());
+            List<org.apache.cxf.jaxrs.ext.logging.LogRecord> list = records.getLogRecords();
+            assertNotNull(list);
+            assertEquals(1, list.size());
+            updateCounters(list.get(0), "Resource");
+        }
+        
+        verifyCounters();
+    }
+    
+    @Test
+    public void testFeedsWithBatchLogRecordsOneEntry() throws Exception {
+        WebClient wc = WebClient.create("http://localhost:9080/batch");
+        wc.path("/log").get();
+        Thread.sleep(3000);
+        List<Feed> elements = Resource2.getElements();
+        assertEquals(2, elements.size());
+        
+        resetCounters();
+        for (Feed feed : elements) {
+            List<Entry> entries = feed.getEntries();
+            assertEquals(4, entries.size());
+            
+            for (Entry e : entries) {
+                updateCounters(readLogRecord(e.getContent()), "Resource2");
+            }
+        }
+        
+        verifyCounters();
+        
+    }
+    
+    @Test
+    public void testEntriesWithLogRecordsOneEntry() throws Exception {
+        WebClient wc = WebClient.create("http://localhost:9080/entries");
+        wc.path("/log").get();
+        Thread.sleep(3000);
+        List<Entry> elements = Resource3.getElements();
+        assertEquals(8, elements.size());
+        
+        resetCounters();
+        
+        for (Entry e : elements) {
+            updateCounters(readLogRecord(e.getContent()), "Resource3");
+        }
+        
+        verifyCounters();
+        
+    }
+    
+    @Test
+    public void testManyEntries() throws Exception {
+        WebClient wc = WebClient.create("http://localhost:9080/entriesMany");
+        wc.path("/log").get();
+        Thread.sleep(3000);
+        List<Entry> elements = Resource4.getElements();
+        assertEquals(4, elements.size());
+        
+        resetCounters();
+        
+        for (Entry e : elements) {
+            LogRecords records = readLogRecords(e.getContent());
+            List<org.apache.cxf.jaxrs.ext.logging.LogRecord> list = records.getLogRecords();
+            assertNotNull(list);
+            assertEquals(2, list.size());
+            for (org.apache.cxf.jaxrs.ext.logging.LogRecord record : list) {
+                updateCounters(record, "Resource4");
+            }
+            
+        }
+        verifyCounters();
+    }
+    
+    @Test
+    public void testFeedsWithLogRecordsExtension() throws Exception {
+        WebClient wc = WebClient.create("http://localhost:9080/extensions");
+        wc.path("/log").get();
+        Thread.sleep(3000);
+        List<Feed> elements = Resource5.getElements();
+        assertEquals(8, elements.size());
+
+        resetCounters();
+        for (Feed feed : elements) {
+            List<Entry> entries = feed.getEntries();
+            assertEquals(1, entries.size());
+            Entry e = entries.get(0);
+            LogRecords records = readLogRecordsExtension(e);
+            List<org.apache.cxf.jaxrs.ext.logging.LogRecord> list = records.getLogRecords();
+            assertNotNull(list);
+            assertEquals(1, list.size());
+            updateCounters(list.get(0), "Resource5");
+        }
+        
+        verifyCounters();
+    }
+    
     @Ignore
-    @Path("/")
+    @Path("/root")
     public static class Resource {
         private static final Logger LOG1 = LogUtils.getL7dLogger(Resource.class);
         private static final Logger LOG2 = LogUtils.getL7dLogger(Resource.class, null, "namedLogger");
+        
+        private static List<Feed> feeds = new ArrayList<Feed>();
+        
+        @GET
+        @Path("/log")
+        public void doLogging() {
+            doLog(LOG1, LOG2);
+        }
 
+        @POST
+        @Path("/feeds")
+        public void consume(Feed feed) {
+            feed.toString();
+            synchronized (Resource.class) {
+                feeds.add(feed);
+            }
+        }
+        
+        public static void clear() {
+            feeds.clear();
+        }
+        
+        public static synchronized List<Feed> getElements() {
+            return new ArrayList<Feed>(feeds);
+        }
+    }
+    
+    @Ignore
+    @Path("/batch")
+    public static class Resource2 {
+        private static final Logger LOG1 = LogUtils.getL7dLogger(Resource2.class);
+        private static final Logger LOG2 = LogUtils.getL7dLogger(Resource2.class, null, "namedLogger");
+        
+        private static List<Feed> feeds = new ArrayList<Feed>();
+        
         @GET
         @Path("/log")
         public void doLogging() {
-            LOG1.severe("severe message");
-            LOG1.warning("warning message");
-            LOG1.info("info message");
-            LogRecord r = new LogRecord(Level.FINE, "fine message");
-            r.setThrown(new IllegalArgumentException("tadaam"));
-            LOG1.log(r);
-            r = new LogRecord(Level.FINER, "finer message with {0} and {1}");
-            r.setParameters(new Object[] {
-                "param1", "param2"
-            });
-            r.setLoggerName("faky-logger");
-            LOG1.log(r);
-            LOG1.finest("finest message");
-
-            // for LOG2 only 'warning' and above messages should be logged
-            LOG2.severe("severe message");
-            LOG2.info("info message - should not pass!");
-            LOG2.finer("finer message - should not pass!");
+            doLog(LOG1, LOG2);
         }
 
-        // 2. ATOM push handler should populate logs here
         @POST
-        @Path("/feed")
+        @Path("/feeds")
         public void consume(Feed feed) {
-            // System.out.println(feed);
-            retrieved.add(feed);
+            feed.toString();
+            synchronized (Resource2.class) {
+                feeds.add(feed);
+            }
+        }
+        
+        public static void clear() {
+            feeds.clear();
+        }
+        
+        public static synchronized List<Feed> getElements() {
+            return new ArrayList<Feed>(feeds);
         }
     }
+    
+    @Ignore
+    @Path("/entries")
+    public static class Resource3 {
+        private static final Logger LOG1 = LogUtils.getL7dLogger(Resource3.class);
+        private static final Logger LOG2 = LogUtils.getL7dLogger(Resource3.class, null, "namedLogger");
+        
+        private static List<Entry> entries = new ArrayList<Entry>();
+        
+        @GET
+        @Path("/log")
+        public void doLogging() {
+            doLog(LOG1, LOG2);
+        }
 
-    @Test
-    public void testLogEvents() throws Exception {
-        WebClient wc = WebClient.create("http://localhost:9080");
-        wc.path("/log").get();
-        Thread.sleep(1000);
-        assertEquals(7, retrieved.size());
+        @POST
+        @Path("/entries")
+        public void consume(Entry entry) {
+            entry.toString();
+            synchronized (Resource3.class) {
+                entries.add(entry);
+            }
+        }
+        
+        public static void clear() {
+            entries.clear();
+        }
+        
+        public static synchronized List<Entry> getElements() {
+            return new ArrayList<Entry>(entries);
+        }
+    }
+    
+    @Ignore
+    @Path("/entriesMany")
+    public static class Resource4 {
+        private static final Logger LOG1 = LogUtils.getL7dLogger(Resource4.class);
+        private static final Logger LOG2 = LogUtils.getL7dLogger(Resource4.class, null, "namedLogger");
+        
+        private static List<Entry> entries = new ArrayList<Entry>();
+        
+        @GET
+        @Path("/log")
+        public void doLogging() {
+            doLog(LOG1, LOG2);
+        }
+
+        @POST
+        @Path("/entries")
+        public void consume(Entry entry) {
+            entry.toString();
+            synchronized (Resource4.class) {
+                entries.add(entry);
+            }
+        }
+        
+        public static void clear() {
+            entries.clear();
+        }
+        
+        public static synchronized List<Entry> getElements() {
+            return new ArrayList<Entry>(entries);
+        }
+    }
+    
+    @Ignore
+    @Path("/extensions")
+    public static class Resource5 {
+        private static final Logger LOG1 = LogUtils.getL7dLogger(Resource5.class);
+        private static final Logger LOG2 = LogUtils.getL7dLogger(Resource5.class, null, "namedLogger");
+        
+        private static List<Feed> feeds = new ArrayList<Feed>();
+        
+        @GET
+        @Path("/log")
+        public void doLogging() {
+            doLog(LOG1, LOG2);
+        }
+
+        @POST
+        @Path("/feeds")
+        public void consume(Feed feed) {
+            feed.toString();
+            synchronized (Resource5.class) {
+                feeds.add(feed);
+            }
+        }
+        
+        public static void clear() {
+            feeds.clear();
+        }
+        
+        public static List<Feed> getElements() {
+            return new ArrayList<Feed>(feeds);
+        }
+    }
+    
+    private static void doLog(Logger l1, Logger l2) {
+        l1.severe("severe message");
+        l1.warning("warning message");
+        l1.info("info message");
+        LogRecord r = new LogRecord(Level.FINE, "fine message");
+        r.setThrown(new IllegalArgumentException("tadaam"));
+        l1.log(r);
+        r = new LogRecord(Level.FINER, "finer message with {0} and {1}");
+        r.setParameters(new Object[] {
+            "param1", "param2"
+        });
+        r.setLoggerName("faky-logger");
+        l1.log(r);
+        l1.finest("finest message");
+
+        // for LOG2 only 'warning' and above messages should be logged
+        l2.severe("severe message");
+        l2.severe("severe message2");
+        l2.info("info message - should not pass!");
+        l2.finer("finer message - should not pass!");
+    }
+    
+    private LogRecords readLogRecords(String value) throws Exception {
+        return (LogRecords)context.createUnmarshaller().unmarshal(new StringReader(value));
+    }
+    
+    private org.apache.cxf.jaxrs.ext.logging.LogRecord readLogRecord(String value) throws Exception {
+        return (org.apache.cxf.jaxrs.ext.logging.LogRecord)
+            context.createUnmarshaller().unmarshal(new StringReader(value));
+    }
+    
+    private LogRecords readLogRecordsExtension(Entry e) throws Exception {
+        ExtensibleElement el = e.getExtension(new QName("http://cxf.apache.org/log", "logRecords", "log"));
+        LogRecords records = new LogRecords();
+        List<org.apache.cxf.jaxrs.ext.logging.LogRecord> list = 
+            new ArrayList<org.apache.cxf.jaxrs.ext.logging.LogRecord>();
+        for (Element element : el.getElements()) {
+            org.apache.cxf.jaxrs.ext.logging.LogRecord record = 
+                new org.apache.cxf.jaxrs.ext.logging.LogRecord();
+            Element loggerName = element.getFirstChild(
+                                     new QName("http://cxf.apache.org/log", "loggerName", "log"));
+            if (loggerName != null) {
+                record.setLoggerName(loggerName.getText());
+            }
+            Element throwable = element.getFirstChild(
+                                     new QName("http://cxf.apache.org/log", "throwable", "log")); 
+            if (throwable != null) {
+                record.setThrowable(throwable.getText());
+            }
+            list.add(record);
+        }
+        records.setLogRecords(list);
+        return records;
+    }
+    
+    private void updateCounters(org.apache.cxf.jaxrs.ext.logging.LogRecord record, String clsName) {
+        String name = record.getLoggerName();
+        if (name != null && name.length() > 0) {
+            if (("org.apache.cxf.systest.jaxrs.JAXRSLoggingAtomPushSpringTest$" + clsName).equals(name)) {
+                resourceLogger++;      
+            } else if ("namedLogger".equals(name)) {
+                namedLogger++;      
+            } else if ("faky-logger".equals(name)) {
+                fakyLogger++;      
+            }
+        } else {
+            assertNotNull(record.getThrowable());
+            throwables++;
+        }
+    }
+    
+    private void resetCounters() {
+        fakyLogger = 0;
+        namedLogger = 0;
+        resourceLogger = 0;
+        throwables = 0;
+    }
+    
+    private void verifyCounters() {
+        assertEquals(1, throwables);
+        assertEquals(4, resourceLogger);
+        assertEquals(2, namedLogger);
+        assertEquals(1, fakyLogger);
     }
 }

Modified: 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=892237&r1=892236&r2=892237&view=diff
==============================================================================
--- cxf/trunk/systests/jaxrs/src/test/java/org/apache/cxf/systest/jaxrs/JAXRSLoggingAtomPushTest.java (original)
+++ cxf/trunk/systests/jaxrs/src/test/java/org/apache/cxf/systest/jaxrs/JAXRSLoggingAtomPushTest.java Fri Dec 18 12:23:54 2009
@@ -19,9 +19,10 @@
 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.Queue;
+import java.util.concurrent.ConcurrentLinkedQueue;
 import java.util.logging.Handler;
 import java.util.logging.Level;
 import java.util.logging.LogManager;
@@ -60,12 +61,14 @@
 public class JAXRSLoggingAtomPushTest {
     private static final Logger LOG = LogUtils.getL7dLogger(JAXRSLoggingAtomPushTest.class);
     private static Server server;
-    private static List<Feed> feeds = new ArrayList<Feed>();
-    private static List<Entry> entries = new ArrayList<Entry>();
-
+    
     @Ignore
     @Path("/")
     public static class Resource {
+        
+        private static Queue<Feed> feeds = new ConcurrentLinkedQueue<Feed>();
+        private static Queue<Entry> entries = new ConcurrentLinkedQueue<Entry>();
+        
         @POST
         public void consume(Feed feed) {
             feeds.add(feed);
@@ -76,6 +79,11 @@
         public void consume(Entry entry) {
             entries.add(entry);
         }
+        
+        public static void clear() {
+            feeds.clear();
+            entries.clear();
+        }
     }
 
     @SuppressWarnings("unchecked")
@@ -131,8 +139,7 @@
 
     @Before
     public void before() throws Exception {
-        feeds.clear();
-        entries.clear();
+        Resource.clear();
     }
 
     @Test
@@ -140,8 +147,8 @@
         configureLogging("resources/logging_atompush.properties");
         logSixEvents(LOG);
         // need to wait: multithreaded and client-server journey
-        Thread.sleep(1000);
-        assertEquals("Different logged events count;", 6, feeds.size());
+        Thread.sleep(3000);
+        assertEquals("Different logged events count;", 6, Resource.feeds.size());
     }
 
     @Test
@@ -149,9 +156,9 @@
         configureLogging("resources/logging_atompush_batch.properties");
         logSixEvents(LOG);
         // need to wait: multithreaded and client-server journey
-        Thread.sleep(1000);
+        Thread.sleep(3000);
         // 6 events / 3 element batch = 2 feeds expected
-        assertEquals("Different logged events count;", 2, feeds.size());
+        assertEquals("Different logged events count;", 2, Resource.feeds.size());
     }
 
     @Test
@@ -165,9 +172,9 @@
         log.setLevel(Level.ALL);
         logSixEvents(log);
         // need to wait: multithreaded and client-server journey
-        Thread.sleep(1000);
+        Thread.sleep(3000);
         // 6 events / 2 element batch = 3 feeds expected
-        assertEquals("Different logged events count;", 3, feeds.size());
+        assertEquals("Different logged events count;", 3, Resource.feeds.size());
     }
 
     @Test
@@ -195,9 +202,9 @@
         log.setLevel(Level.ALL);
         logSixEvents(log);
         // need to wait: multithreaded and client-server journey
-        Thread.sleep(1000);
+        Thread.sleep(3000);
         // 6 events / 2 element batch = 3 feeds expected
-        assertEquals("Different logged events count;", 3, feeds.size());
+        assertEquals("Different logged events count;", 3, Resource.feeds.size());
     }
 
     @Test
@@ -205,9 +212,9 @@
         configureLogging("resources/logging_atompush_atompub.properties");
         logSixEvents(LOG);
         // need to wait: multithreaded and client-server journey
-        Thread.sleep(1000);
+        Thread.sleep(3000);
         // 6 events logged as entries
-        assertEquals("Different logged events count;", 6, entries.size());
+        assertEquals("Different logged events count;", 6, Resource.entries.size());
     }
 
 }

Modified: cxf/trunk/systests/jaxrs/src/test/resources/jaxrs_logging_atompush/WEB-INF/beans.xml
URL: http://svn.apache.org/viewvc/cxf/trunk/systests/jaxrs/src/test/resources/jaxrs_logging_atompush/WEB-INF/beans.xml?rev=892237&r1=892236&r2=892237&view=diff
==============================================================================
--- cxf/trunk/systests/jaxrs/src/test/resources/jaxrs_logging_atompush/WEB-INF/beans.xml (original)
+++ cxf/trunk/systests/jaxrs/src/test/resources/jaxrs_logging_atompush/WEB-INF/beans.xml Fri Dec 18 12:23:54 2009
@@ -25,12 +25,14 @@
 	-->
 <beans xmlns="http://www.springframework.org/schema/beans"
 	xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:jaxrs="http://cxf.apache.org/jaxrs"
-	xmlns:aop="http://www.springframework.org/schema/aop"
+	xmlns:util="http://www.springframework.org/schema/util"
 	xsi:schemaLocation="
 http://www.springframework.org/schema/beans 
 http://www.springframework.org/schema/beans/spring-beans.xsd
-http://cxf.apache.org/jaxrs
-http://cxf.apache.org/schemas/jaxrs.xsd">
+http://cxf.apache.org/jaxrs 
+http://cxf.apache.org/schemas/jaxrs.xsd
+http://www.springframework.org/schema/util 
+http://www.springframework.org/schema/util/spring-util-2.0.xsd">
 
 	<import resource="classpath:META-INF/cxf/cxf.xml" />
 	<import resource="classpath:META-INF/cxf/cxf-extension-jaxrs-binding.xml" />
@@ -38,14 +40,110 @@
 
 	<bean class="org.apache.cxf.jaxrs.ext.logging.atom.AtomPushBean"
 		init-method="init">
-		<property name="url" value="http://localhost:9080/feed" />
-		<!-- Mind the '$' instead of '.' for inner classes! -->
+		<property name="multiplicity" value="one"/>
 		<property name="loggers"
 			value="
 			org.apache.cxf.systest.jaxrs.JAXRSLoggingAtomPushSpringTest$Resource:ALL,
 			namedLogger:WARN" />
+		<property name="deliverer">
+			<ref bean="webDeliverer" />
+		</property>	
+	</bean>
+
+    <bean id="webDeliverer" class="org.apache.cxf.jaxrs.ext.logging.atom.deliverer.WebClientDeliverer">
+        <constructor-arg ref="webClient"/>
+    </bean>
+
+    <bean id="webClient" class="org.apache.cxf.jaxrs.client.WebClient"
+factory-method="create">
+        <constructor-arg type="java.lang.String" value="http://localhost:9080/root/feeds" />
+        <constructor-arg ref="feedProvider" />
+    </bean> 
+
+    <bean class="org.apache.cxf.jaxrs.ext.logging.atom.AtomPushBean"
+		init-method="init">
+		<property name="batchSize" value="4"/>
+		<property name="loggers"
+			value="
+			org.apache.cxf.systest.jaxrs.JAXRSLoggingAtomPushSpringTest$Resource2:ALL,
+			namedLogger:WARN" />
+		<property name="url" value="http://localhost:9080/batch/feeds"/>	
+	</bean>
+
+    <bean class="org.apache.cxf.jaxrs.ext.logging.atom.AtomPushBean"
+		init-method="init">
+		<property name="output" value="entry"/>
+		<property name="loggers"
+			value="
+			org.apache.cxf.systest.jaxrs.JAXRSLoggingAtomPushSpringTest$Resource3:ALL,
+			namedLogger:WARN" />
+		<property name="deliverer">
+			<ref bean="webDeliverer3" />
+		</property>	
 	</bean>
 
+    <bean id="webDeliverer3" class="org.apache.cxf.jaxrs.ext.logging.atom.deliverer.WebClientDeliverer">
+        <constructor-arg ref="webClient3"/>
+    </bean>
+
+    <bean id="webClient3" class="org.apache.cxf.jaxrs.client.WebClient"
+factory-method="create">
+        <constructor-arg type="java.lang.String" value="http://localhost:9080/entries/entries" />
+        <constructor-arg ref="entryProvider" />
+    </bean> 
+
+    <bean class="org.apache.cxf.jaxrs.ext.logging.atom.AtomPushBean"
+		init-method="init">
+		<property name="output" value="entry"/>
+		<property name="multiplicity" value="many"/>
+		<property name="batchSize" value="2"/>
+		<property name="loggers"
+			value="
+			org.apache.cxf.systest.jaxrs.JAXRSLoggingAtomPushSpringTest$Resource4:ALL,
+			namedLogger:WARN" />
+		<property name="url" value="http://localhost:9080/entriesMany/entries"/>
+	</bean>
+
+    <bean class="org.apache.cxf.jaxrs.ext.logging.atom.AtomPushBean"
+		init-method="init">
+		<property name="multiplicity" value="one"/>
+		<property name="format" value="extension"/>
+		<property name="loggers"
+			value="
+			org.apache.cxf.systest.jaxrs.JAXRSLoggingAtomPushSpringTest$Resource5:ALL,
+			namedLogger:WARN" />
+		<property name="url" value="http://localhost:9080/extensions/feeds"/>
+	</bean>
+
+    <util:list id="feedProvider">
+      <ref bean="feed"/>
+    </util:list>
+    
+    <util:list id="entryProvider">
+      <ref bean="entry"/>
+    </util:list>        
+
+	<bean id="feed" class="org.apache.cxf.jaxrs.provider.AtomFeedProvider">
+	    <property name="formattedOutput" value="true"/>
+	</bean>
+	<bean id="entry" class="org.apache.cxf.jaxrs.provider.AtomEntryProvider"> 
+	    <property name="formattedOutput" value="true"/>
+	</bean>
+
+	<jaxrs:server id="atomserver" address="/">
+		<jaxrs:serviceBeans>
+			<bean class="org.apache.cxf.systest.jaxrs.JAXRSLoggingAtomPushSpringTest$Resource"/>
+			<bean class="org.apache.cxf.systest.jaxrs.JAXRSLoggingAtomPushSpringTest$Resource2"/>
+			<bean class="org.apache.cxf.systest.jaxrs.JAXRSLoggingAtomPushSpringTest$Resource3"/>
+			<bean class="org.apache.cxf.systest.jaxrs.JAXRSLoggingAtomPushSpringTest$Resource4"/>
+			<bean class="org.apache.cxf.systest.jaxrs.JAXRSLoggingAtomPushSpringTest$Resource5"/>
+		</jaxrs:serviceBeans>
+		<jaxrs:providers>
+			<ref bean="feed" />
+			<ref bean="entry" />
+		</jaxrs:providers>
+	</jaxrs:server>
+
 	<!--  
 	Other config samples:
 	
@@ -69,23 +167,7 @@
 			  org.apache.cxf.bus:WARNING" />
 		<property name="batchSize" value="10" />
 	</bean>
- 	-->
- 	
-	<jaxrs:server id="atomserver" address="/">
-		<jaxrs:serviceBeans>
-			<ref bean="atombean" />
-		</jaxrs:serviceBeans>
-		<jaxrs:providers>
-			<ref bean="feed" />
-			<ref bean="entry" />
-		</jaxrs:providers>
-	</jaxrs:server>
-
-	<!-- Mind the '$' instead of '.' for inner classes! -->
-	<bean id="atombean"
-		class="org.apache.cxf.systest.jaxrs.JAXRSLoggingAtomPushSpringTest$Resource" />
-	<bean id="feed" class="org.apache.cxf.jaxrs.provider.AtomFeedProvider" />
-	<bean id="entry" class="org.apache.cxf.jaxrs.provider.AtomEntryProvider" />
+ 	--> 
 
 </beans>
 	<!-- END SNIPPET: beans -->