You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@logging.apache.org by rg...@apache.org on 2012/12/01 19:49:51 UTC

svn commit: r1416041 - in /logging/log4j/log4j2/trunk: core/src/main/java/org/apache/logging/log4j/core/ core/src/main/java/org/apache/logging/log4j/core/appender/rewrite/ core/src/main/java/org/apache/logging/log4j/core/net/ core/src/test/java/org/apa...

Author: rgoers
Date: Sat Dec  1 18:49:48 2012
New Revision: 1416041

URL: http://svn.apache.org/viewvc?rev=1416041&view=rev
Log:
LOG4J2-126 - Allow JMS appenders to recover if the queue or topic is unavailable.

Added:
    logging/log4j/log4j2/trunk/core/src/test/java/org/apache/logging/log4j/core/net/JMSQueueFailoverTest.java
      - copied, changed from r1411553, logging/log4j/log4j2/trunk/core/src/test/java/org/apache/logging/log4j/core/net/JMSQueueAppenderTest.java
    logging/log4j/log4j2/trunk/core/src/test/java/org/apache/logging/log4j/core/net/JMSTopicFailoverTest.java
    logging/log4j/log4j2/trunk/core/src/test/resources/log4j-jmsqueue-failover.xml
      - copied, changed from r1411345, logging/log4j/log4j2/trunk/core/src/test/resources/log4j-failover.xml
    logging/log4j/log4j2/trunk/core/src/test/resources/log4j-jmstopic-failover.xml
Modified:
    logging/log4j/log4j2/trunk/core/src/main/java/org/apache/logging/log4j/core/AbstractServer.java
    logging/log4j/log4j2/trunk/core/src/main/java/org/apache/logging/log4j/core/appender/rewrite/PropertiesRewritePolicy.java
    logging/log4j/log4j2/trunk/core/src/main/java/org/apache/logging/log4j/core/net/AbstractJMSManager.java
    logging/log4j/log4j2/trunk/core/src/main/java/org/apache/logging/log4j/core/net/JMSQueueManager.java
    logging/log4j/log4j2/trunk/core/src/main/java/org/apache/logging/log4j/core/net/JMSTopicManager.java
    logging/log4j/log4j2/trunk/core/src/test/java/org/apache/logging/log4j/core/net/SocketServerTest.java
    logging/log4j/log4j2/trunk/flume-ng/src/main/java/org/apache/logging/log4j/flume/appender/FlumeEvent.java
    logging/log4j/log4j2/trunk/src/changes/changes.xml

Modified: logging/log4j/log4j2/trunk/core/src/main/java/org/apache/logging/log4j/core/AbstractServer.java
URL: http://svn.apache.org/viewvc/logging/log4j/log4j2/trunk/core/src/main/java/org/apache/logging/log4j/core/AbstractServer.java?rev=1416041&r1=1416040&r2=1416041&view=diff
==============================================================================
--- logging/log4j/log4j2/trunk/core/src/main/java/org/apache/logging/log4j/core/AbstractServer.java (original)
+++ logging/log4j/log4j2/trunk/core/src/main/java/org/apache/logging/log4j/core/AbstractServer.java Sat Dec  1 18:49:48 2012
@@ -26,7 +26,7 @@ public class AbstractServer {
     private final LoggerContext context;
 
     protected AbstractServer() {
-        context = (LoggerContext) LogManager.getContext();
+        context = (LoggerContext) LogManager.getContext(false);
     }
 
     protected void log(LogEvent event) {

Modified: logging/log4j/log4j2/trunk/core/src/main/java/org/apache/logging/log4j/core/appender/rewrite/PropertiesRewritePolicy.java
URL: http://svn.apache.org/viewvc/logging/log4j/log4j2/trunk/core/src/main/java/org/apache/logging/log4j/core/appender/rewrite/PropertiesRewritePolicy.java?rev=1416041&r1=1416040&r2=1416041&view=diff
==============================================================================
--- logging/log4j/log4j2/trunk/core/src/main/java/org/apache/logging/log4j/core/appender/rewrite/PropertiesRewritePolicy.java (original)
+++ logging/log4j/log4j2/trunk/core/src/main/java/org/apache/logging/log4j/core/appender/rewrite/PropertiesRewritePolicy.java Sat Dec  1 18:49:48 2012
@@ -65,10 +65,8 @@ public final class PropertiesRewritePoli
         Map<String, String> props = new HashMap<String, String>(source.getContextMap());
         for (Map.Entry<Property, Boolean> entry : properties.entrySet()) {
             Property prop = entry.getKey();
-            if (!props.containsKey(prop.getName())) {
-                props.put(prop.getName(), entry.getValue() ?
-                    config.getSubst().replace(prop.getValue()) : prop.getValue());
-            }
+            props.put(prop.getName(), entry.getValue() ?
+                config.getSubst().replace(prop.getValue()) : prop.getValue());
         }
 
         return new Log4jLogEvent(source.getLoggerName(), source.getMarker(), source.getFQCN(), source.getLevel(),

Modified: logging/log4j/log4j2/trunk/core/src/main/java/org/apache/logging/log4j/core/net/AbstractJMSManager.java
URL: http://svn.apache.org/viewvc/logging/log4j/log4j2/trunk/core/src/main/java/org/apache/logging/log4j/core/net/AbstractJMSManager.java?rev=1416041&r1=1416040&r2=1416041&view=diff
==============================================================================
--- logging/log4j/log4j2/trunk/core/src/main/java/org/apache/logging/log4j/core/net/AbstractJMSManager.java (original)
+++ logging/log4j/log4j2/trunk/core/src/main/java/org/apache/logging/log4j/core/net/AbstractJMSManager.java Sat Dec  1 18:49:48 2012
@@ -75,7 +75,7 @@ public abstract class AbstractJMSManager
         try {
             return ctx.lookup(name);
         } catch (NameNotFoundException e) {
-            LOGGER.error("Could not find name [" + name + "].");
+            LOGGER.warn("Could not find name [" + name + "].");
             throw e;
         }
     }

Modified: logging/log4j/log4j2/trunk/core/src/main/java/org/apache/logging/log4j/core/net/JMSQueueManager.java
URL: http://svn.apache.org/viewvc/logging/log4j/log4j2/trunk/core/src/main/java/org/apache/logging/log4j/core/net/JMSQueueManager.java?rev=1416041&r1=1416040&r2=1416041&view=diff
==============================================================================
--- logging/log4j/log4j2/trunk/core/src/main/java/org/apache/logging/log4j/core/net/JMSQueueManager.java (original)
+++ logging/log4j/log4j2/trunk/core/src/main/java/org/apache/logging/log4j/core/net/JMSQueueManager.java Sat Dec  1 18:49:48 2012
@@ -36,22 +36,32 @@ public class JMSQueueManager extends Abs
 
     private static final JMSQueueManagerFactory factory = new JMSQueueManagerFactory();
 
-    private final QueueConnection queueConnection;
-    private final QueueSession queueSession;
-    private final QueueSender queueSender;
+    private QueueInfo info;
+    private final String factoryBindingName;
+    private final String queueBindingName;
+    private final String userName;
+    private final String password;
+    private final Context context;
 
     /**
      * The Constructor.
      * @param name The unique name of the connection.
-     * @param conn The QueueConnection.
-     * @param sess The QueueSession.
-     * @param sender The QueueSender.
+     * @param context The context.
+     * @param factoryBindingName The factory binding name.
+     * @param queueBindingName The queue binding name.
+     * @param userName The user name.
+     * @param password The credentials for the user.
+     * @param info The Queue connection info.
      */
-    protected JMSQueueManager(String name, QueueConnection conn, QueueSession sess, QueueSender sender) {
+    protected JMSQueueManager(String name, Context context, String factoryBindingName, String queueBindingName,
+                              String userName, String password, QueueInfo info) {
         super(name);
-        this.queueConnection = conn;
-        this.queueSession = sess;
-        this.queueSender = sender;
+        this.context = context;
+        this.factoryBindingName = factoryBindingName;
+        this.queueBindingName = queueBindingName;
+        this.userName = userName;
+        this.password = password;
+        this.info = info;
     }
 
     /**
@@ -88,21 +98,24 @@ public class JMSQueueManager extends Abs
     }
 
     @Override
-    public void send(Serializable object) throws Exception {
-        super.send(object, queueSession, queueSender);
+    public synchronized void send(Serializable object) throws Exception {
+        if (info == null) {
+            info = connect(context, factoryBindingName, queueBindingName, userName, password, false);
+        }
+        super.send(object, info.session, info.sender);
     }
 
     @Override
     public void releaseSub() {
         try {
-            if (queueSession != null) {
-                queueSession.close();
-            }
-            if (queueConnection != null) {
-                queueConnection.close();
+            if (info != null) {
+                info.session.close();
+                info.conn.close();
             }
         } catch (JMSException ex) {
             LOGGER.error("Error closing " + getName(), ex);
+        } finally {
+            info = null;
         }
     }
 
@@ -135,6 +148,47 @@ public class JMSQueueManager extends Abs
         }
     }
 
+    private static QueueInfo connect(Context context, String factoryBindingName, String queueBindingName,
+                                     String userName, String password, boolean suppress) throws Exception {
+        try {
+            QueueConnectionFactory factory = (QueueConnectionFactory) lookup(context, factoryBindingName);
+            QueueConnection conn;
+            if (userName != null) {
+                conn = factory.createQueueConnection(userName, password);
+            } else {
+                conn = factory.createQueueConnection();
+            }
+            QueueSession sess = conn.createQueueSession(false, Session.AUTO_ACKNOWLEDGE);
+            Queue queue = (Queue) lookup(context, queueBindingName);
+            QueueSender sender = sess.createSender(queue);
+            conn.start();
+            return new QueueInfo(conn, sess, sender);
+        } catch (NamingException ex) {
+            LOGGER.warn("Unable to locate connection factory " + factoryBindingName, ex);
+            if (!suppress) {
+                throw ex;
+            }
+        } catch (JMSException ex) {
+            LOGGER.warn("Unable to create connection to queue " + queueBindingName, ex);
+            if (!suppress) {
+                throw ex;
+            }
+        }
+        return null;
+    }
+
+    private static class QueueInfo {
+        private final QueueConnection conn;
+        private final QueueSession session;
+        private final QueueSender sender;
+
+        public QueueInfo(QueueConnection conn, QueueSession session, QueueSender sender) {
+            this.conn = conn;
+            this.session = session;
+            this.sender = sender;
+        }
+    }
+
     /**
      * Factory to create the JMSQueueManager.
      */
@@ -144,23 +198,14 @@ public class JMSQueueManager extends Abs
             try {
                 Context ctx = createContext(data.factoryName, data.providerURL, data.urlPkgPrefixes,
                                             data.securityPrincipalName, data.securityCredentials);
-                QueueConnectionFactory factory = (QueueConnectionFactory) lookup(ctx, data.factoryBindingName);
-                QueueConnection conn;
-                if (data.userName != null) {
-                    conn = factory.createQueueConnection(data.userName, data.password);
-                } else {
-                    conn = factory.createQueueConnection();
-                }
-                QueueSession sess = conn.createQueueSession(false, Session.AUTO_ACKNOWLEDGE);
-                Queue queue = (Queue) lookup(ctx, data.queueBindingName);
-                QueueSender sender = sess.createSender(queue);
-                conn.start();
-                return new JMSQueueManager(name, conn, sess, sender);
-
+                QueueInfo info = connect(ctx, data.factoryBindingName, data.queueBindingName, data.userName,
+                    data.password, true);
+                return new JMSQueueManager(name, ctx, data.factoryBindingName, data.queueBindingName,
+                    data.userName, data.password, info);
             } catch (NamingException ex) {
                 LOGGER.error("Unable to locate resource", ex);
-            } catch (JMSException jmsex) {
-                LOGGER.error("Unable to establish connection", jmsex);
+            } catch (Exception ex) {
+                LOGGER.error("Unable to connect", ex);
             }
 
             return null;

Modified: logging/log4j/log4j2/trunk/core/src/main/java/org/apache/logging/log4j/core/net/JMSTopicManager.java
URL: http://svn.apache.org/viewvc/logging/log4j/log4j2/trunk/core/src/main/java/org/apache/logging/log4j/core/net/JMSTopicManager.java?rev=1416041&r1=1416040&r2=1416041&view=diff
==============================================================================
--- logging/log4j/log4j2/trunk/core/src/main/java/org/apache/logging/log4j/core/net/JMSTopicManager.java (original)
+++ logging/log4j/log4j2/trunk/core/src/main/java/org/apache/logging/log4j/core/net/JMSTopicManager.java Sat Dec  1 18:49:48 2012
@@ -36,22 +36,31 @@ public class JMSTopicManager extends Abs
 
     private static final JMSTopicManagerFactory factory = new JMSTopicManagerFactory();
 
-    private final TopicConnection topicConnection;
-    private final TopicSession topicSession;
-    private final TopicPublisher topicPublisher;
-
+    private TopicInfo info;
+    private final String factoryBindingName;
+    private final String topicBindingName;
+    private final String userName;
+    private final String password;
+    private final Context context;
     /**
      * Constructor.
      * @param name The unique name of the connection.
-     * @param conn The TopicConnection.
-     * @param sess The TopicSession.
-     * @param pub The TopicPublisher.
+     * @param context The context.
+     * @param factoryBindingName The factory binding name.
+     * @param topicBindingName The queue binding name.
+     * @param userName The user name.
+     * @param password The credentials for the user.
+     * @param info The Queue connection info.
      */
-    public JMSTopicManager(String name, TopicConnection conn, TopicSession sess, TopicPublisher pub) {
+    protected JMSTopicManager(String name, Context context, String factoryBindingName, String topicBindingName,
+                              String userName, String password, TopicInfo info) {
         super(name);
-        this.topicConnection = conn;
-        this.topicSession = sess;
-        this.topicPublisher = pub;
+        this.context = context;
+        this.factoryBindingName = factoryBindingName;
+        this.topicBindingName = topicBindingName;
+        this.userName = userName;
+        this.password = password;
+        this.info = info;
     }
 
     /**
@@ -90,17 +99,18 @@ public class JMSTopicManager extends Abs
 
     @Override
     public void send(Serializable object) throws Exception {
-        super.send(object, topicSession, topicPublisher);
+        if (info == null) {
+            info = connect(context, factoryBindingName, topicBindingName, userName, password, false);
+        }
+        super.send(object, info.session, info.publisher);
     }
 
     @Override
     public void releaseSub() {
         try {
-            if (topicSession != null) {
-                topicSession.close();
-            }
-            if (topicConnection != null) {
-                topicConnection.close();
+            if (info != null) {
+                info.session.close();
+                info.conn.close();
             }
         } catch (JMSException ex) {
             LOGGER.error("Error closing " + getName(), ex);
@@ -136,31 +146,64 @@ public class JMSTopicManager extends Abs
         }
     }
 
+    private static TopicInfo connect(Context context, String factoryBindingName, String queueBindingName,
+                                     String userName, String password, boolean suppress) throws Exception {
+        try {
+            TopicConnectionFactory factory = (TopicConnectionFactory) lookup(context, factoryBindingName);
+            TopicConnection conn;
+            if (userName != null) {
+                conn = factory.createTopicConnection(userName, password);
+            } else {
+                conn = factory.createTopicConnection();
+            }
+            TopicSession sess = conn.createTopicSession(false, Session.AUTO_ACKNOWLEDGE);
+            Topic topic = (Topic) lookup(context, queueBindingName);
+            TopicPublisher publisher = sess.createPublisher(topic);
+            conn.start();
+            return new TopicInfo(conn, sess, publisher);
+        } catch (NamingException ex) {
+            LOGGER.warn("Unable to locate connection factory " + factoryBindingName, ex);
+            if (!suppress) {
+                throw ex;
+            }
+        } catch (JMSException ex) {
+            LOGGER.warn("Unable to create connection to queue " + queueBindingName, ex);
+            if (!suppress) {
+                throw ex;
+            }
+        }
+        return null;
+    }
+
+    private static class TopicInfo {
+        private final TopicConnection conn;
+        private final TopicSession session;
+        private final TopicPublisher publisher;
+
+        public TopicInfo(TopicConnection conn, TopicSession session, TopicPublisher publisher) {
+            this.conn = conn;
+            this.session = session;
+            this.publisher = publisher;
+        }
+    }
+
     /**
-     * Factory to create a JMSTopicManager.
+     * Factory to create the JMSQueueManager.
      */
     private static class JMSTopicManagerFactory implements ManagerFactory<JMSTopicManager, FactoryData> {
 
         public JMSTopicManager createManager(String name, FactoryData data) {
             try {
                 Context ctx = createContext(data.factoryName, data.providerURL, data.urlPkgPrefixes,
-                                            data.securityPrincipalName, data.securityCredentials);
-                TopicConnectionFactory factory = (TopicConnectionFactory) lookup(ctx, data.factoryBindingName);
-                TopicConnection conn;
-                if (data.userName != null) {
-                    conn = factory.createTopicConnection(data.userName, data.password);
-                } else {
-                    conn = factory.createTopicConnection();
-                }
-                TopicSession sess = conn.createTopicSession(false, Session.AUTO_ACKNOWLEDGE);
-                Topic topic = (Topic) lookup(ctx, data.topicBindingName);
-                TopicPublisher pub = sess.createPublisher(topic);
-                conn.start();
-                return new JMSTopicManager(name, conn, sess, pub);
+                    data.securityPrincipalName, data.securityCredentials);
+                TopicInfo info = connect(ctx, data.factoryBindingName, data.topicBindingName, data.userName,
+                    data.password, true);
+                return new JMSTopicManager(name, ctx, data.factoryBindingName, data.topicBindingName,
+                    data.userName, data.password, info);
             } catch (NamingException ex) {
-                LOGGER.error("Bad Name " + data.topicBindingName, ex);
-            } catch (JMSException jmsex) {
-                LOGGER.error("Unable to create publisher ", jmsex);
+                LOGGER.error("Unable to locate resource", ex);
+            } catch (Exception ex) {
+                LOGGER.error("Unable to connect", ex);
             }
 
             return null;

Copied: logging/log4j/log4j2/trunk/core/src/test/java/org/apache/logging/log4j/core/net/JMSQueueFailoverTest.java (from r1411553, logging/log4j/log4j2/trunk/core/src/test/java/org/apache/logging/log4j/core/net/JMSQueueAppenderTest.java)
URL: http://svn.apache.org/viewvc/logging/log4j/log4j2/trunk/core/src/test/java/org/apache/logging/log4j/core/net/JMSQueueFailoverTest.java?p2=logging/log4j/log4j2/trunk/core/src/test/java/org/apache/logging/log4j/core/net/JMSQueueFailoverTest.java&p1=logging/log4j/log4j2/trunk/core/src/test/java/org/apache/logging/log4j/core/net/JMSQueueAppenderTest.java&r1=1411553&r2=1416041&rev=1416041&view=diff
==============================================================================
--- logging/log4j/log4j2/trunk/core/src/test/java/org/apache/logging/log4j/core/net/JMSQueueAppenderTest.java (original)
+++ logging/log4j/log4j2/trunk/core/src/test/java/org/apache/logging/log4j/core/net/JMSQueueFailoverTest.java Sat Dec  1 18:49:48 2012
@@ -18,28 +18,20 @@ package org.apache.logging.log4j.core.ne
 
 import org.apache.logging.log4j.Level;
 import org.apache.logging.log4j.LogManager;
+import org.apache.logging.log4j.Logger;
+import org.apache.logging.log4j.ThreadContext;
 import org.apache.logging.log4j.core.Appender;
-import org.apache.logging.log4j.core.Filter;
 import org.apache.logging.log4j.core.LogEvent;
-import org.apache.logging.log4j.core.Logger;
 import org.apache.logging.log4j.core.LoggerContext;
-import org.apache.logging.log4j.core.appender.ConsoleAppender;
-import org.apache.logging.log4j.core.appender.JMSQueueAppender;
 import org.apache.logging.log4j.core.config.Configuration;
-import org.apache.logging.log4j.core.config.Configurator;
 import org.apache.logging.log4j.core.config.XMLConfigurationFactory;
-import org.apache.logging.log4j.test.appender.ListAppender;
-import org.apache.logging.log4j.core.filter.CompositeFilter;
-import org.apache.logging.log4j.core.filter.AbstractFilter;
-import org.apache.logging.log4j.core.layout.PatternLayout;
 import org.apache.logging.log4j.status.StatusConsoleListener;
 import org.apache.logging.log4j.status.StatusLogger;
-
-import org.junit.After;
+import org.apache.logging.log4j.test.appender.ListAppender;
 import org.junit.AfterClass;
+import org.junit.Before;
 import org.junit.BeforeClass;
 import org.junit.Test;
-
 import org.mockejb.jms.MockQueue;
 import org.mockejb.jms.QueueConnectionFactoryImpl;
 import org.mockejb.jndi.MockContextFactory;
@@ -55,42 +47,81 @@ import static org.junit.Assert.assertTru
 /**
  *
  */
-public class JMSQueueAppenderTest {
+public class JMSQueueFailoverTest {
 
-    private static final String FACTORY_NAME = "TestQueueConnectionFactory";
-    private static final String QUEUE_NAME = "TestQueue";
+    private static final String FACTORY_NAME = "QueueConnectionFactory";
+    private static final String QUEUE_NAME = "Log4j2Queue";
 
     private static Context context;
     private static AbstractJMSReceiver receiver;
 
-    private static final String CONFIG = "log4j-jmsqueue.xml";
+    private static final String CONFIG = "log4j-jmsqueue-failover.xml";
 
-    LoggerContext ctx = (LoggerContext) LogManager.getContext();
-    Logger root = ctx.getLogger("JMSQueueTest");
+    private static Configuration config;
+    private static ListAppender app;
+    private static LoggerContext ctx;
 
     @BeforeClass
     public static void setupClass() throws Exception {
+        setupQueue();
+        System.setProperty(XMLConfigurationFactory.CONFIGURATION_FILE_PROPERTY, CONFIG);
+        ctx = (LoggerContext) LogManager.getContext(false);
+    }
+
+    @AfterClass
+    public static void cleanupClass() {
+        System.clearProperty(XMLConfigurationFactory.CONFIGURATION_FILE_PROPERTY);
+        ctx.reconfigure();
+        StatusLogger.getLogger().reset();
+    }
+
+    @Before
+    public void before() {
+        config = ctx.getConfiguration();
+        for (Map.Entry<String, Appender> entry : config.getAppenders().entrySet()) {
+            if (entry.getKey().equals("List")) {
+                app = (ListAppender) entry.getValue();
+                break;
+            }
+        }
+        assertNotNull("No Appender", app);
+        app.clear();
+        ThreadContext.clear();
+    }
+
+    private static void setupQueue() throws Exception {
         // MockContextFactory becomes the primary JNDI provider
         StatusConsoleListener l = new StatusConsoleListener(Level.ERROR);
         StatusLogger.getLogger().registerListener(l);
         MockContextFactory.setAsInitial();
         context = new InitialContext();
         context.rebind(FACTORY_NAME, new QueueConnectionFactoryImpl() );
-        context.rebind(QUEUE_NAME, new MockQueue(QUEUE_NAME));
-        System.setProperty(XMLConfigurationFactory.CONFIGURATION_FILE_PROPERTY, CONFIG);
-        receiver = new JMSQueueReceiver(FACTORY_NAME, QUEUE_NAME, null, null);
+        //context.rebind(QUEUE_NAME, new MockQueue(QUEUE_NAME));
+        //System.setProperty(XMLConfigurationFactory.CONFIGURATION_FILE_PROPERTY, CONFIG);
+        //receiver = new JMSQueueReceiver(FACTORY_NAME, QUEUE_NAME, null, null);
     }
 
-    @AfterClass
-    public static void cleanupClass() {
-        StatusLogger.getLogger().reset();
+    @Test
+    public void testFailover() throws Exception {
+        ThreadContext.put("appender", "Failover");
+        Logger logger = LogManager.getLogger(JMSQueueFailoverTest.class);
+        logger.debug("Test Message");
+        List<LogEvent> events = app.getEvents();
+        assertNotNull("No events returned", events);
+        assertTrue("No events returned", events.size() > 0);
+        assertTrue("Incorrect event", "Test Message".equals(events.get(0).getMessage().getFormattedMessage()));
     }
 
     @Test
-    public void testConfiguration() throws Exception {
-        LoggerContext ctx = (LoggerContext) LogManager.getContext();
-        Configuration config = ctx.getConfiguration();
-        Map<String, Appender> appenders = config.getAppenders();
-        assertTrue(appenders.containsKey("JMSQueue"));
+    public void testReconnect() throws Exception {
+        context.rebind(QUEUE_NAME, new MockQueue(QUEUE_NAME));
+        receiver = new JMSQueueReceiver(FACTORY_NAME, QUEUE_NAME, null, null);
+        ThreadContext.put("appender", "Failover");
+        Logger logger = LogManager.getLogger(JMSQueueFailoverTest.class);
+        logger.debug("Test Message");
+        List<LogEvent> events = app.getEvents();
+        assertNotNull("No events returned", events);
+        assertTrue("No events returned", events.size() > 0);
+        assertTrue("Incorrect event", "Test Message".equals(events.get(0).getMessage().getFormattedMessage()));
     }
 }

Added: logging/log4j/log4j2/trunk/core/src/test/java/org/apache/logging/log4j/core/net/JMSTopicFailoverTest.java
URL: http://svn.apache.org/viewvc/logging/log4j/log4j2/trunk/core/src/test/java/org/apache/logging/log4j/core/net/JMSTopicFailoverTest.java?rev=1416041&view=auto
==============================================================================
--- logging/log4j/log4j2/trunk/core/src/test/java/org/apache/logging/log4j/core/net/JMSTopicFailoverTest.java (added)
+++ logging/log4j/log4j2/trunk/core/src/test/java/org/apache/logging/log4j/core/net/JMSTopicFailoverTest.java Sat Dec  1 18:49:48 2012
@@ -0,0 +1,126 @@
+/*
+ * 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.logging.log4j.core.net;
+
+import org.apache.logging.log4j.Level;
+import org.apache.logging.log4j.LogManager;
+import org.apache.logging.log4j.Logger;
+import org.apache.logging.log4j.ThreadContext;
+import org.apache.logging.log4j.core.Appender;
+import org.apache.logging.log4j.core.LogEvent;
+import org.apache.logging.log4j.core.LoggerContext;
+import org.apache.logging.log4j.core.config.Configuration;
+import org.apache.logging.log4j.core.config.XMLConfigurationFactory;
+import org.apache.logging.log4j.status.StatusConsoleListener;
+import org.apache.logging.log4j.status.StatusLogger;
+import org.apache.logging.log4j.test.appender.ListAppender;
+import org.junit.AfterClass;
+import org.junit.Before;
+import org.junit.BeforeClass;
+import org.junit.Test;
+import org.mockejb.jms.MockTopic;
+import org.mockejb.jms.TopicConnectionFactoryImpl;
+import org.mockejb.jndi.MockContextFactory;
+
+import javax.naming.Context;
+import javax.naming.InitialContext;
+import java.util.List;
+import java.util.Map;
+
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertTrue;
+
+/**
+ *
+ */
+public class JMSTopicFailoverTest {
+
+    private static final String FACTORY_NAME = "TopicConnectionFactory";
+    private static final String TOPIC_NAME = "Log4j2Topic";
+
+    private static Context context;
+
+    private static final String CONFIG = "log4j-jmstopic-failover.xml";
+
+    private static Configuration config;
+    private static ListAppender app;
+    private static LoggerContext ctx;
+
+    @BeforeClass
+    public static void setupClass() throws Exception {
+        setupQueue();
+        System.setProperty(XMLConfigurationFactory.CONFIGURATION_FILE_PROPERTY, CONFIG);
+        ctx = (LoggerContext) LogManager.getContext(false);
+    }
+
+    @AfterClass
+    public static void cleanupClass() {
+        System.clearProperty(XMLConfigurationFactory.CONFIGURATION_FILE_PROPERTY);
+        ctx.reconfigure();
+        StatusLogger.getLogger().reset();
+    }
+
+    @Before
+    public void before() {
+        config = ctx.getConfiguration();
+        for (Map.Entry<String, Appender> entry : config.getAppenders().entrySet()) {
+            if (entry.getKey().equals("List")) {
+                app = (ListAppender) entry.getValue();
+                break;
+            }
+        }
+        assertNotNull("No Appender", app);
+        app.clear();
+        ThreadContext.clear();
+    }
+
+    private static void setupQueue() throws Exception {
+        // MockContextFactory becomes the primary JNDI provider
+        StatusConsoleListener l = new StatusConsoleListener(Level.ERROR);
+        StatusLogger.getLogger().registerListener(l);
+        MockContextFactory.setAsInitial();
+        context = new InitialContext();
+        context.rebind(FACTORY_NAME, new TopicConnectionFactoryImpl() );
+        //context.rebind(QUEUE_NAME, new MockQueue(QUEUE_NAME));
+        //System.setProperty(XMLConfigurationFactory.CONFIGURATION_FILE_PROPERTY, CONFIG);
+        //receiver = new JMSQueueReceiver(FACTORY_NAME, QUEUE_NAME, null, null);
+    }
+
+    @Test
+    public void testFailover() throws Exception {
+        ThreadContext.put("appender", "Failover");
+        Logger logger = LogManager.getLogger(JMSTopicFailoverTest.class);
+        logger.debug("Test Message");
+        List<LogEvent> events = app.getEvents();
+        assertNotNull("No events returned", events);
+        assertTrue("No events returned", events.size() > 0);
+        assertTrue("Incorrect event", "Test Message".equals(events.get(0).getMessage().getFormattedMessage()));
+    }
+
+    @Test
+    public void testReconnect() throws Exception {
+        context.rebind(TOPIC_NAME, new MockTopic(TOPIC_NAME));
+        AbstractJMSReceiver receiver = new JMSTopicReceiver(FACTORY_NAME, TOPIC_NAME, null, null);
+        ThreadContext.put("appender", "Failover");
+        Logger logger = LogManager.getLogger(JMSTopicFailoverTest.class);
+        logger.debug("Test Message");
+        List<LogEvent> events = app.getEvents();
+        assertNotNull("No events returned", events);
+        assertTrue("No events returned", events.size() > 0);
+        assertTrue("Incorrect event", "Test Message".equals(events.get(0).getMessage().getFormattedMessage()));
+    }
+}

Modified: logging/log4j/log4j2/trunk/core/src/test/java/org/apache/logging/log4j/core/net/SocketServerTest.java
URL: http://svn.apache.org/viewvc/logging/log4j/log4j2/trunk/core/src/test/java/org/apache/logging/log4j/core/net/SocketServerTest.java?rev=1416041&r1=1416040&r2=1416041&view=diff
==============================================================================
--- logging/log4j/log4j2/trunk/core/src/test/java/org/apache/logging/log4j/core/net/SocketServerTest.java (original)
+++ logging/log4j/log4j2/trunk/core/src/test/java/org/apache/logging/log4j/core/net/SocketServerTest.java Sat Dec  1 18:49:48 2012
@@ -55,12 +55,12 @@ public class SocketServerTest {
     private static SocketServer tcp;
     private static Thread thread;
 
-    LoggerContext ctx = (LoggerContext) LogManager.getContext();
+    LoggerContext ctx = (LoggerContext) LogManager.getContext(false);
     Logger root = ctx.getLogger("SocketServerTest");
 
     @BeforeClass
     public static void setupClass() throws Exception {
-        ((LoggerContext) LogManager.getContext()).reconfigure();
+        ((LoggerContext) LogManager.getContext(false)).reconfigure();
         tcp = new SocketServer(PORTNUM);
         thread = new Thread(tcp);
         thread.start();

Copied: logging/log4j/log4j2/trunk/core/src/test/resources/log4j-jmsqueue-failover.xml (from r1411345, logging/log4j/log4j2/trunk/core/src/test/resources/log4j-failover.xml)
URL: http://svn.apache.org/viewvc/logging/log4j/log4j2/trunk/core/src/test/resources/log4j-jmsqueue-failover.xml?p2=logging/log4j/log4j2/trunk/core/src/test/resources/log4j-jmsqueue-failover.xml&p1=logging/log4j/log4j2/trunk/core/src/test/resources/log4j-failover.xml&r1=1411345&r2=1416041&rev=1416041&view=diff
==============================================================================
--- logging/log4j/log4j2/trunk/core/src/test/resources/log4j-failover.xml (original)
+++ logging/log4j/log4j2/trunk/core/src/test/resources/log4j-jmsqueue-failover.xml Sat Dec  1 18:49:48 2012
@@ -18,9 +18,16 @@
 -->
 <configuration status="error" name="FailoverTest" packages="org.apache.logging.log4j.test">
   <Appenders>
-    <AlwaysFail name="Fail" />
-    <List name="List" />
-    <Failover name="Failover" primary="Fail" suppressExceptions="false">
+    <List name="List"/>
+    <JMSQueue name="Log4j2Queue" queueBindingName="Log4j2Queue" factoryBindingName="QueueConnectionFactory"
+        suppressExceptions="false"/>
+    <Rewrite name="Rewrite" suppressExceptions="false">
+      <PropertiesRewritePolicy>
+        <Property name="appender">List</Property>
+      </PropertiesRewritePolicy>
+      <appender-ref ref="Log4j2Queue"/>
+    </Rewrite>
+    <Failover name="Failover" primary="Rewrite" suppressExceptions="false">
       <Failovers>
         <appender-ref ref="List"/>
       </Failovers>
@@ -28,8 +35,17 @@
   </Appenders>
 
   <loggers>
-    <root level="error">
-      <appender-ref ref="Failover"/>
+    <root level="debug">
+      <appender-ref ref="Failover">
+        <ThreadContextMapFilter onMatch="ACCEPT" onMismatch="DENY">
+          <KeyValuePair key="appender" value="Failover"/>
+        </ThreadContextMapFilter>
+      </appender-ref>
+      <appender-ref ref="List">
+        <ThreadContextMapFilter onMatch="ACCEPT" onMismatch="DENY">
+          <KeyValuePair key="appender" value="List"/>
+        </ThreadContextMapFilter>
+      </appender-ref>
     </root>
   </loggers>
 

Added: logging/log4j/log4j2/trunk/core/src/test/resources/log4j-jmstopic-failover.xml
URL: http://svn.apache.org/viewvc/logging/log4j/log4j2/trunk/core/src/test/resources/log4j-jmstopic-failover.xml?rev=1416041&view=auto
==============================================================================
--- logging/log4j/log4j2/trunk/core/src/test/resources/log4j-jmstopic-failover.xml (added)
+++ logging/log4j/log4j2/trunk/core/src/test/resources/log4j-jmstopic-failover.xml Sat Dec  1 18:49:48 2012
@@ -0,0 +1,52 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ 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.
+
+-->
+<configuration status="error" name="FailoverTest" packages="org.apache.logging.log4j.test">
+  <Appenders>
+    <List name="List"/>
+    <JMSTopic name="Log4j2Topic" topicBindingName="Log4j2Topic" factoryBindingName="TopicConnectionFactory"
+        suppressExceptions="false"/>
+    <Rewrite name="Rewrite" suppressExceptions="false">
+      <PropertiesRewritePolicy>
+        <Property name="appender">List</Property>
+      </PropertiesRewritePolicy>
+      <appender-ref ref="Log4j2Topic"/>
+    </Rewrite>
+    <Failover name="Failover" primary="Rewrite" suppressExceptions="false">
+      <Failovers>
+        <appender-ref ref="List"/>
+      </Failovers>
+    </Failover>
+  </Appenders>
+
+  <loggers>
+    <root level="debug">
+      <appender-ref ref="Failover">
+        <ThreadContextMapFilter onMatch="ACCEPT" onMismatch="DENY">
+          <KeyValuePair key="appender" value="Failover"/>
+        </ThreadContextMapFilter>
+      </appender-ref>
+      <appender-ref ref="List">
+        <ThreadContextMapFilter onMatch="ACCEPT" onMismatch="DENY">
+          <KeyValuePair key="appender" value="List"/>
+        </ThreadContextMapFilter>
+      </appender-ref>
+    </root>
+  </loggers>
+
+</configuration>
\ No newline at end of file

Modified: logging/log4j/log4j2/trunk/flume-ng/src/main/java/org/apache/logging/log4j/flume/appender/FlumeEvent.java
URL: http://svn.apache.org/viewvc/logging/log4j/log4j2/trunk/flume-ng/src/main/java/org/apache/logging/log4j/flume/appender/FlumeEvent.java?rev=1416041&r1=1416040&r2=1416041&view=diff
==============================================================================
--- logging/log4j/log4j2/trunk/flume-ng/src/main/java/org/apache/logging/log4j/flume/appender/FlumeEvent.java (original)
+++ logging/log4j/log4j2/trunk/flume-ng/src/main/java/org/apache/logging/log4j/flume/appender/FlumeEvent.java Sat Dec  1 18:49:48 2012
@@ -30,6 +30,7 @@ import org.apache.logging.log4j.message.
 
 import java.io.ByteArrayOutputStream;
 import java.io.IOException;
+import java.util.ArrayList;
 import java.util.Arrays;
 import java.util.HashMap;
 import java.util.List;
@@ -86,6 +87,7 @@ public class FlumeEvent extends SimpleEv
             String[] array = includes.split(",");
             if (array.length > 0) {
                 for (String str : array) {
+                    str = str.trim();
                     if (mdc.containsKey(str)) {
                         ctx.put(str, mdc.get(str));
                     }
@@ -94,7 +96,10 @@ public class FlumeEvent extends SimpleEv
         } else if (excludes != null) {
             String[] array = excludes.split(",");
             if (array.length > 0) {
-                List<String> list = Arrays.asList(array);
+                List<String> list = new ArrayList<String>(array.length);
+                for (String value : array) {
+                    list.add(value.trim());
+                }
                 for (Map.Entry<String, String> entry : mdc.entrySet()) {
                     if (!list.contains(entry.getKey())) {
                         ctx.put(entry.getKey(), entry.getValue());
@@ -109,6 +114,7 @@ public class FlumeEvent extends SimpleEv
             String[] array = required.split(",");
             if (array.length > 0) {
                 for (String str : array) {
+                    str = str.trim();
                     if (!mdc.containsKey(str)) {
                         throw new LoggingException("Required key " + str + " is missing from the MDC");
                     }

Modified: logging/log4j/log4j2/trunk/src/changes/changes.xml
URL: http://svn.apache.org/viewvc/logging/log4j/log4j2/trunk/src/changes/changes.xml?rev=1416041&r1=1416040&r2=1416041&view=diff
==============================================================================
--- logging/log4j/log4j2/trunk/src/changes/changes.xml (original)
+++ logging/log4j/log4j2/trunk/src/changes/changes.xml Sat Dec  1 18:49:48 2012
@@ -23,6 +23,9 @@
 
   <body>
     <release version="2.0-beta4" date="TBD" description="Bug fixes and enhancements">
+      <action issue="LOG4J2-126" dev="rgoers" type="fix">
+        Allow JMS appenders to recover if the queue or topic is unavailable.
+      </action>
       <action issue="LOG4J2-128" dev="rgoers" type="update">
         Add follow attribute to Console Appender.
       </action>