You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@logging.apache.org by ni...@apache.org on 2013/07/07 21:17:09 UTC

svn commit: r1500509 - in /logging/log4j/log4j2/trunk: core/src/main/java/org/apache/logging/log4j/core/web/ core/src/test/java/org/apache/logging/log4j/core/web/ src/site/xdoc/manual/

Author: nickwilliams
Date: Sun Jul  7 19:17:09 2013
New Revision: 1500509

URL: http://svn.apache.org/r1500509
Log:
[LOG4J2-270], [LOG4J2-293] Removing the separate log4j-web artifact/submodule and integrating it into core. Adding support for web-fragment/auto-initialization in Servlet 3.0 and newer. (Unit tests)

Added:
    logging/log4j/log4j2/trunk/core/src/test/java/org/apache/logging/log4j/core/web/
    logging/log4j/log4j2/trunk/core/src/test/java/org/apache/logging/log4j/core/web/Log4jServletContainerInitializerTest.java
    logging/log4j/log4j2/trunk/core/src/test/java/org/apache/logging/log4j/core/web/Log4jServletContextListenerTest.java
    logging/log4j/log4j2/trunk/core/src/test/java/org/apache/logging/log4j/core/web/Log4jServletFilterTest.java
    logging/log4j/log4j2/trunk/core/src/test/java/org/apache/logging/log4j/core/web/Log4jWebInitializerImplTest.java
Modified:
    logging/log4j/log4j2/trunk/core/src/main/java/org/apache/logging/log4j/core/web/Log4jServletContainerInitializer.java
    logging/log4j/log4j2/trunk/core/src/main/java/org/apache/logging/log4j/core/web/Log4jServletContextListener.java
    logging/log4j/log4j2/trunk/core/src/main/java/org/apache/logging/log4j/core/web/Log4jServletFilter.java
    logging/log4j/log4j2/trunk/core/src/main/java/org/apache/logging/log4j/core/web/Log4jWebInitializer.java
    logging/log4j/log4j2/trunk/core/src/main/java/org/apache/logging/log4j/core/web/Log4jWebInitializerImpl.java
    logging/log4j/log4j2/trunk/src/site/xdoc/manual/webapp.xml

Modified: logging/log4j/log4j2/trunk/core/src/main/java/org/apache/logging/log4j/core/web/Log4jServletContainerInitializer.java
URL: http://svn.apache.org/viewvc/logging/log4j/log4j2/trunk/core/src/main/java/org/apache/logging/log4j/core/web/Log4jServletContainerInitializer.java?rev=1500509&r1=1500508&r2=1500509&view=diff
==============================================================================
--- logging/log4j/log4j2/trunk/core/src/main/java/org/apache/logging/log4j/core/web/Log4jServletContainerInitializer.java (original)
+++ logging/log4j/log4j2/trunk/core/src/main/java/org/apache/logging/log4j/core/web/Log4jServletContainerInitializer.java Sun Jul  7 19:17:09 2013
@@ -36,10 +36,11 @@ public class Log4jServletContainerInitia
 
         Log4jWebInitializer initializer = Log4jWebInitializerImpl.getLog4jWebInitializer(servletContext);
         initializer.initialize();
+        initializer.setLoggerContext(); // the application is just now starting to start up
 
         servletContext.addListener(new Log4jServletContextListener());
 
-        FilterRegistration.Dynamic filter = servletContext.addFilter("Log4jServletFilter", new Log4jServletFilter());
+        FilterRegistration.Dynamic filter = servletContext.addFilter("log4jServletFilter", new Log4jServletFilter());
         filter.addMappingForUrlPatterns(EnumSet.allOf(DispatcherType.class), false, "/*");
     }
 }

Modified: logging/log4j/log4j2/trunk/core/src/main/java/org/apache/logging/log4j/core/web/Log4jServletContextListener.java
URL: http://svn.apache.org/viewvc/logging/log4j/log4j2/trunk/core/src/main/java/org/apache/logging/log4j/core/web/Log4jServletContextListener.java?rev=1500509&r1=1500508&r2=1500509&view=diff
==============================================================================
--- logging/log4j/log4j2/trunk/core/src/main/java/org/apache/logging/log4j/core/web/Log4jServletContextListener.java (original)
+++ logging/log4j/log4j2/trunk/core/src/main/java/org/apache/logging/log4j/core/web/Log4jServletContextListener.java Sun Jul  7 19:17:09 2013
@@ -39,6 +39,7 @@ public class Log4jServletContextListener
         this.initializer = Log4jWebInitializerImpl.getLog4jWebInitializer(this.servletContext);
         try {
             this.initializer.initialize();
+            this.initializer.setLoggerContext(); // the application is just now starting to start up
         } catch (UnavailableException e) {
             throw new RuntimeException("Failed to initialize Log4j properly.", e);
         }
@@ -51,6 +52,7 @@ public class Log4jServletContextListener
         }
         this.servletContext.log("Log4jServletContextListener ensuring that Log4j shuts down properly.");
 
+        this.initializer.clearLoggerContext(); // the application is finished shutting down now
         this.initializer.deinitialize();
     }
 }

Modified: logging/log4j/log4j2/trunk/core/src/main/java/org/apache/logging/log4j/core/web/Log4jServletFilter.java
URL: http://svn.apache.org/viewvc/logging/log4j/log4j2/trunk/core/src/main/java/org/apache/logging/log4j/core/web/Log4jServletFilter.java?rev=1500509&r1=1500508&r2=1500509&view=diff
==============================================================================
--- logging/log4j/log4j2/trunk/core/src/main/java/org/apache/logging/log4j/core/web/Log4jServletFilter.java (original)
+++ logging/log4j/log4j2/trunk/core/src/main/java/org/apache/logging/log4j/core/web/Log4jServletFilter.java Sun Jul  7 19:17:09 2013
@@ -38,7 +38,7 @@ import javax.servlet.ServletResponse;
  */
 public class Log4jServletFilter implements Filter {
 
-    private static final String ALREADY_FILTERED_ATTRIBUTE = Log4jServletFilter.class.getName() + ".FILTERED";
+    static final String ALREADY_FILTERED_ATTRIBUTE = Log4jServletFilter.class.getName() + ".FILTERED";
 
     private ServletContext servletContext;
     private Log4jWebInitializer initializer;

Modified: logging/log4j/log4j2/trunk/core/src/main/java/org/apache/logging/log4j/core/web/Log4jWebInitializer.java
URL: http://svn.apache.org/viewvc/logging/log4j/log4j2/trunk/core/src/main/java/org/apache/logging/log4j/core/web/Log4jWebInitializer.java?rev=1500509&r1=1500508&r2=1500509&view=diff
==============================================================================
--- logging/log4j/log4j2/trunk/core/src/main/java/org/apache/logging/log4j/core/web/Log4jWebInitializer.java (original)
+++ logging/log4j/log4j2/trunk/core/src/main/java/org/apache/logging/log4j/core/web/Log4jWebInitializer.java Sun Jul  7 19:17:09 2013
@@ -24,25 +24,26 @@ import javax.servlet.UnavailableExceptio
  */
 interface Log4jWebInitializer {
     /**
-     * The {@link javax.servlet.ServletContext} context-param name for the name of the {@link org.apache.logging.log4j.core.LoggerContext}.
+     * The {@link javax.servlet.ServletContext} context-param name for the name of the
+     * {@link org.apache.logging.log4j.core.LoggerContext}.
      */
-    public static final String LOG4J_CONTEXT_NAME = "log4jContextName";
+    final String LOG4J_CONTEXT_NAME = "log4jContextName";
 
     /**
      * The {@link javax.servlet.ServletContext} context-param name for the location of the configuration.
      */
-    public static final String LOG4J_CONFIG_LOCATION = "log4jConfiguration";
+    final String LOG4J_CONFIG_LOCATION = "log4jConfiguration";
 
     /**
      * The {@link javax.servlet.ServletContext} context-param name for the JNDI flag.
      */
-    public static final String LOG4J_CONFIG_IS_JNDI = "isLog4jContextSelectorNamed";
+    final String IS_LOG4J_CONTEXT_SELECTOR_NAMED = "isLog4jContextSelectorNamed";
 
     /**
      * The attribute key for the {@link javax.servlet.ServletContext} attribute that the singleton initializer instance
      * is stored in.
      */
-    static final String INITIALIZER_ATTRIBUTE = Log4jWebInitializer.class.getName() + ".INSTANCE";
+    final String INITIALIZER_ATTRIBUTE = Log4jWebInitializer.class.getName() + ".INSTANCE";
 
     /**
      * Starts up Log4j in the web application. Calls {@link #setLoggerContext()} after initialization is complete.

Modified: logging/log4j/log4j2/trunk/core/src/main/java/org/apache/logging/log4j/core/web/Log4jWebInitializerImpl.java
URL: http://svn.apache.org/viewvc/logging/log4j/log4j2/trunk/core/src/main/java/org/apache/logging/log4j/core/web/Log4jWebInitializerImpl.java?rev=1500509&r1=1500508&r2=1500509&view=diff
==============================================================================
--- logging/log4j/log4j2/trunk/core/src/main/java/org/apache/logging/log4j/core/web/Log4jWebInitializerImpl.java (original)
+++ logging/log4j/log4j2/trunk/core/src/main/java/org/apache/logging/log4j/core/web/Log4jWebInitializerImpl.java Sun Jul  7 19:17:09 2013
@@ -34,9 +34,20 @@ import org.apache.logging.log4j.spi.Logg
 /**
  * This class initializes and deinitializes Log4j no matter how the initialization occurs.
  */
-class Log4jWebInitializerImpl implements Log4jWebInitializer {
+final class Log4jWebInitializerImpl implements Log4jWebInitializer {
     private static final Object MUTEX = new Object();
 
+    static {
+        try {
+            Class.forName("org.apache.logging.log4j.core.web.JNDIContextFilter");
+            throw new IllegalStateException("You are using Log4j 2 in a web application with the old, extinct " +
+                    "log4j-web artifact. This is not supported and could cause serious runtime problems. Please" +
+                    "remove the log4j-web JAR file from your application.");
+        } catch (ClassNotFoundException ignore) {
+            /* Good. They don't have the old log4j-web artifact loaded. */
+        }
+    }
+
     private final StrSubstitutor substitutor = new StrSubstitutor(new Interpolator());
     private final ServletContext servletContext;
 
@@ -63,15 +74,13 @@ class Log4jWebInitializerImpl implements
 
             this.name = this.substitutor.replace(this.servletContext.getInitParameter(LOG4J_CONTEXT_NAME));
             String location = this.substitutor.replace(this.servletContext.getInitParameter(LOG4J_CONFIG_LOCATION));
-            boolean isJndi = "true".equals(this.servletContext.getInitParameter(LOG4J_CONFIG_IS_JNDI));
+            boolean isJndi = "true".equals(this.servletContext.getInitParameter(IS_LOG4J_CONTEXT_SELECTOR_NAMED));
 
             if (isJndi) {
                 this.initializeJndi(location);
             } else {
                 this.initializeNonJndi(location);
             }
-
-            this.setLoggerContext(); // the application is just now starting to start up
         }
     }
 
@@ -119,7 +128,7 @@ class Log4jWebInitializerImpl implements
             return;
         }
 
-        this.loggerContext = Configurator.initialize(this.name, getClassLoader(), location);
+        this.loggerContext = Configurator.initialize(this.name, this.getClassLoader(), location);
     }
 
     @Override
@@ -132,14 +141,13 @@ class Log4jWebInitializerImpl implements
         if (!this.deinitialized) {
             this.deinitialized = true;
 
-            this.clearLoggerContext(); // the application is finished shutting down now
-
             if (this.loggerContext != null) {
                 this.servletContext.log("Removing LoggerContext for [" + this.name + "].");
                 if (this.selector != null) {
                     this.selector.removeContext(this.name);
                 }
                 this.loggerContext.stop();
+                this.loggerContext = null;
             }
         }
     }
@@ -159,13 +167,22 @@ class Log4jWebInitializerImpl implements
     private ClassLoader getClassLoader() {
         try {
             // if container is Servlet 3.0, use its getClassLoader method
-            return (ClassLoader) this.servletContext.getClass().getMethod("getClassLoader").invoke(this.servletContext);
-        } catch (Exception ignore) {
+            // this may look odd, but the call below will throw NoSuchMethodError if user is on Servlet 2.5
+            // we compile against 3.0 to support Log4jServletContainerInitializer, but we don't require 3.0
+            return this.servletContext.getClassLoader();
+        } catch (Throwable ignore) {
             // otherwise, use this class's class loader
             return Log4jWebInitializerImpl.class.getClassLoader();
         }
     }
 
+    /**
+     * Get the current initializer from the {@link ServletContext}. If the initializer does not exist, create a new one
+     * and add it to the {@link ServletContext}, then return that.
+     *
+     * @param servletContext The {@link ServletContext} for this web application
+     * @return the initializer.
+     */
     static Log4jWebInitializer getLog4jWebInitializer(final ServletContext servletContext) {
         synchronized (MUTEX) {
             Log4jWebInitializer initializer = (Log4jWebInitializer) servletContext.getAttribute(INITIALIZER_ATTRIBUTE);

Added: logging/log4j/log4j2/trunk/core/src/test/java/org/apache/logging/log4j/core/web/Log4jServletContainerInitializerTest.java
URL: http://svn.apache.org/viewvc/logging/log4j/log4j2/trunk/core/src/test/java/org/apache/logging/log4j/core/web/Log4jServletContainerInitializerTest.java?rev=1500509&view=auto
==============================================================================
--- logging/log4j/log4j2/trunk/core/src/test/java/org/apache/logging/log4j/core/web/Log4jServletContainerInitializerTest.java (added)
+++ logging/log4j/log4j2/trunk/core/src/test/java/org/apache/logging/log4j/core/web/Log4jServletContainerInitializerTest.java Sun Jul  7 19:17:09 2013
@@ -0,0 +1,101 @@
+/*
+ * 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.web;
+
+import java.util.EnumSet;
+import java.util.EventListener;
+import javax.servlet.DispatcherType;
+import javax.servlet.Filter;
+import javax.servlet.FilterRegistration;
+import javax.servlet.ServletContext;
+import javax.servlet.UnavailableException;
+
+import org.easymock.Capture;
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Test;
+
+import static org.easymock.EasyMock.*;
+import static org.junit.Assert.assertSame;
+import static org.junit.Assert.fail;
+
+public class Log4jServletContainerInitializerTest {
+    private ServletContext servletContext;
+    private Log4jWebInitializer initializer;
+
+    private Log4jServletContainerInitializer containerInitializer;
+
+    @Before
+    public void setUp() {
+        this.servletContext = createStrictMock(ServletContext.class);
+        this.initializer = createStrictMock(Log4jWebInitializer.class);
+
+        this.containerInitializer = new Log4jServletContainerInitializer();
+    }
+
+    @After
+    public void tearDown() {
+        verify(this.servletContext, this.initializer);
+    }
+
+    @Test
+    public void testOnStartup() throws Exception {
+        FilterRegistration.Dynamic registration = createStrictMock(FilterRegistration.Dynamic.class);
+
+        Capture<EventListener> listenerCapture = new Capture<EventListener>();
+        Capture<Filter> filterCapture = new Capture<Filter>();
+
+        this.servletContext.log(anyObject(String.class));
+        expectLastCall();
+        expect(this.servletContext.getAttribute(Log4jWebInitializer.INITIALIZER_ATTRIBUTE)).andReturn(this.initializer);
+        this.initializer.initialize();
+        expectLastCall();
+        this.initializer.setLoggerContext();
+        expectLastCall();
+        this.servletContext.addListener(capture(listenerCapture));
+        expectLastCall();
+        expect(this.servletContext.addFilter(eq("log4jServletFilter"), capture(filterCapture))).andReturn(registration);
+        registration.addMappingForUrlPatterns(eq(EnumSet.allOf(DispatcherType.class)), eq(false), eq("/*"));
+        expectLastCall();
+
+        replay(this.servletContext, this.initializer, registration);
+
+        this.containerInitializer.onStartup(null, this.servletContext);
+
+        verify(registration);
+    }
+
+    @Test
+    public void testOnStartupFailed() throws Exception {
+        UnavailableException exception = new UnavailableException("");
+
+        this.servletContext.log(anyObject(String.class));
+        expectLastCall();
+        expect(this.servletContext.getAttribute(Log4jWebInitializer.INITIALIZER_ATTRIBUTE)).andReturn(this.initializer);
+        this.initializer.initialize();
+        expectLastCall().andThrow(exception);
+
+        replay(this.servletContext, this.initializer);
+
+        try {
+            this.containerInitializer.onStartup(null, this.servletContext);
+            fail("");
+        } catch (UnavailableException e) {
+            assertSame("The exception is not correct.", exception, e);
+        }
+    }
+}

Added: logging/log4j/log4j2/trunk/core/src/test/java/org/apache/logging/log4j/core/web/Log4jServletContextListenerTest.java
URL: http://svn.apache.org/viewvc/logging/log4j/log4j2/trunk/core/src/test/java/org/apache/logging/log4j/core/web/Log4jServletContextListenerTest.java?rev=1500509&view=auto
==============================================================================
--- logging/log4j/log4j2/trunk/core/src/test/java/org/apache/logging/log4j/core/web/Log4jServletContextListenerTest.java (added)
+++ logging/log4j/log4j2/trunk/core/src/test/java/org/apache/logging/log4j/core/web/Log4jServletContextListenerTest.java Sun Jul  7 19:17:09 2013
@@ -0,0 +1,112 @@
+/*
+ * 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.web;
+
+import javax.servlet.ServletContext;
+import javax.servlet.ServletContextEvent;
+import javax.servlet.UnavailableException;
+
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Test;
+
+import static org.easymock.EasyMock.*;
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.fail;
+
+public class Log4jServletContextListenerTest {
+    private ServletContextEvent event;
+    private ServletContext servletContext;
+    private Log4jWebInitializer initializer;
+
+    private Log4jServletContextListener listener;
+
+    @Before
+    public void setUp() {
+        this.event = createStrictMock(ServletContextEvent.class);
+        this.servletContext = createStrictMock(ServletContext.class);
+        this.initializer = createStrictMock(Log4jWebInitializer.class);
+
+        this.listener = new Log4jServletContextListener();
+    }
+
+    @After
+    public void tearDown() {
+        verify(this.event, this.servletContext, this.initializer);
+    }
+
+    @Test
+    public void testInitAndDestroy() throws Exception {
+        expect(this.event.getServletContext()).andReturn(this.servletContext);
+        this.servletContext.log(anyObject(String.class));
+        expectLastCall();
+        expect(this.servletContext.getAttribute(Log4jWebInitializer.INITIALIZER_ATTRIBUTE)).andReturn(this.initializer);
+        this.initializer.initialize();
+        expectLastCall();
+        this.initializer.setLoggerContext();
+        expectLastCall();
+
+        replay(this.event, this.servletContext, this.initializer);
+
+        this.listener.contextInitialized(this.event);
+
+        verify(this.event, this.servletContext, this.initializer);
+        reset(this.event, this.servletContext, this.initializer);
+
+        this.servletContext.log(anyObject(String.class));
+        expectLastCall();
+        this.initializer.clearLoggerContext();
+        expectLastCall();
+        this.initializer.deinitialize();
+        expectLastCall();
+
+        replay(this.event, this.servletContext, this.initializer);
+
+        this.listener.contextDestroyed(this.event);
+    }
+
+    @Test
+    public void testInitFailure() throws Exception {
+        expect(this.event.getServletContext()).andReturn(this.servletContext);
+        this.servletContext.log(anyObject(String.class));
+        expectLastCall();
+        expect(this.servletContext.getAttribute(Log4jWebInitializer.INITIALIZER_ATTRIBUTE)).andReturn(this.initializer);
+        this.initializer.initialize();
+        expectLastCall().andThrow(new UnavailableException(""));
+
+        replay(this.event, this.servletContext, this.initializer);
+
+        try {
+            this.listener.contextInitialized(this.event);
+            fail("Expected a RuntimeException.");
+        } catch (RuntimeException e) {
+            assertEquals("The message is not correct.", "Failed to initialize Log4j properly.", e.getMessage());
+        }
+    }
+
+    @Test
+    public void testDestroy() {
+        replay(this.event, this.servletContext, this.initializer);
+
+        try {
+            this.listener.contextDestroyed(this.event);
+            fail("Expected an IllegalStateException.");
+        } catch (IllegalStateException ignore) {
+
+        }
+    }
+}

Added: logging/log4j/log4j2/trunk/core/src/test/java/org/apache/logging/log4j/core/web/Log4jServletFilterTest.java
URL: http://svn.apache.org/viewvc/logging/log4j/log4j2/trunk/core/src/test/java/org/apache/logging/log4j/core/web/Log4jServletFilterTest.java?rev=1500509&view=auto
==============================================================================
--- logging/log4j/log4j2/trunk/core/src/test/java/org/apache/logging/log4j/core/web/Log4jServletFilterTest.java (added)
+++ logging/log4j/log4j2/trunk/core/src/test/java/org/apache/logging/log4j/core/web/Log4jServletFilterTest.java Sun Jul  7 19:17:09 2013
@@ -0,0 +1,153 @@
+/*
+ * 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.web;
+
+import javax.servlet.FilterChain;
+import javax.servlet.FilterConfig;
+import javax.servlet.ServletContext;
+import javax.servlet.ServletRequest;
+import javax.servlet.ServletResponse;
+
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Test;
+
+import static org.easymock.EasyMock.*;
+
+public class Log4jServletFilterTest {
+    private FilterConfig filterConfig;
+    private ServletContext servletContext;
+    private Log4jWebInitializer initializer;
+
+    private Log4jServletFilter filter;
+
+    @Before
+    public void setUp() {
+        this.filterConfig = createStrictMock(FilterConfig.class);
+        this.servletContext = createStrictMock(ServletContext.class);
+        this.initializer = createStrictMock(Log4jWebInitializer.class);
+
+        this.filter = new Log4jServletFilter();
+    }
+
+    @After
+    public void tearDown() {
+        verify(this.filterConfig, this.servletContext, this.initializer);
+    }
+
+    @Test
+    public void testInitAndDestroy() throws Exception {
+        expect(this.filterConfig.getServletContext()).andReturn(this.servletContext);
+        this.servletContext.log(anyObject(String.class));
+        expectLastCall();
+        expect(this.servletContext.getAttribute(Log4jWebInitializer.INITIALIZER_ATTRIBUTE)).andReturn(this.initializer);
+        this.initializer.clearLoggerContext();
+        expectLastCall();
+
+        replay(this.filterConfig, this.servletContext, this.initializer);
+
+        this.filter.init(this.filterConfig);
+
+        verify(this.filterConfig, this.servletContext, this.initializer);
+        reset(this.filterConfig, this.servletContext, this.initializer);
+
+        this.servletContext.log(anyObject(String.class));
+        expectLastCall();
+        this.initializer.setLoggerContext();
+        expectLastCall();
+
+        replay(this.filterConfig, this.servletContext, this.initializer);
+
+        this.filter.destroy();
+    }
+
+    @Test(expected = IllegalStateException.class)
+    public void testDestroy() {
+        replay(this.filterConfig, this.servletContext, this.initializer);
+
+        this.filter.destroy();
+    }
+
+    @Test
+    public void testDoFilterFirstTime() throws Exception {
+        expect(this.filterConfig.getServletContext()).andReturn(this.servletContext);
+        this.servletContext.log(anyObject(String.class));
+        expectLastCall();
+        expect(this.servletContext.getAttribute(Log4jWebInitializer.INITIALIZER_ATTRIBUTE)).andReturn(this.initializer);
+        this.initializer.clearLoggerContext();
+        expectLastCall();
+
+        replay(this.filterConfig, this.servletContext, this.initializer);
+
+        this.filter.init(this.filterConfig);
+
+        verify(this.filterConfig, this.servletContext, this.initializer);
+        reset(this.filterConfig, this.servletContext, this.initializer);
+
+        ServletRequest request = createStrictMock(ServletRequest.class);
+        ServletResponse response = createStrictMock(ServletResponse.class);
+        FilterChain chain = createStrictMock(FilterChain.class);
+
+        expect(request.getAttribute(Log4jServletFilter.ALREADY_FILTERED_ATTRIBUTE)).andReturn(null);
+        request.setAttribute(eq(Log4jServletFilter.ALREADY_FILTERED_ATTRIBUTE), eq(Boolean.TRUE));
+        expectLastCall();
+        this.initializer.setLoggerContext();
+        expectLastCall();
+        chain.doFilter(same(request), same(response));
+        expectLastCall();
+        this.initializer.clearLoggerContext();
+        expectLastCall();
+
+        replay(this.filterConfig, this.servletContext, this.initializer, request, response, chain);
+
+        this.filter.doFilter(request, response, chain);
+
+        verify(request, response, chain);
+    }
+
+    @Test
+    public void testDoFilterSecondTime() throws Exception {
+        expect(this.filterConfig.getServletContext()).andReturn(this.servletContext);
+        this.servletContext.log(anyObject(String.class));
+        expectLastCall();
+        expect(this.servletContext.getAttribute(Log4jWebInitializer.INITIALIZER_ATTRIBUTE)).andReturn(this.initializer);
+        this.initializer.clearLoggerContext();
+        expectLastCall();
+
+        replay(this.filterConfig, this.servletContext, this.initializer);
+
+        this.filter.init(this.filterConfig);
+
+        verify(this.filterConfig, this.servletContext, this.initializer);
+        reset(this.filterConfig, this.servletContext, this.initializer);
+
+        ServletRequest request = createStrictMock(ServletRequest.class);
+        ServletResponse response = createStrictMock(ServletResponse.class);
+        FilterChain chain = createStrictMock(FilterChain.class);
+
+        expect(request.getAttribute(Log4jServletFilter.ALREADY_FILTERED_ATTRIBUTE)).andReturn(true);
+        expectLastCall();
+        chain.doFilter(same(request), same(response));
+        expectLastCall();
+
+        replay(this.filterConfig, this.servletContext, this.initializer, request, response, chain);
+
+        this.filter.doFilter(request, response, chain);
+
+        verify(request, response, chain);
+    }
+}

Added: logging/log4j/log4j2/trunk/core/src/test/java/org/apache/logging/log4j/core/web/Log4jWebInitializerImplTest.java
URL: http://svn.apache.org/viewvc/logging/log4j/log4j2/trunk/core/src/test/java/org/apache/logging/log4j/core/web/Log4jWebInitializerImplTest.java?rev=1500509&view=auto
==============================================================================
--- logging/log4j/log4j2/trunk/core/src/test/java/org/apache/logging/log4j/core/web/Log4jWebInitializerImplTest.java (added)
+++ logging/log4j/log4j2/trunk/core/src/test/java/org/apache/logging/log4j/core/web/Log4jWebInitializerImplTest.java Sun Jul  7 19:17:09 2013
@@ -0,0 +1,358 @@
+/*
+ * 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.web;
+
+import javax.servlet.ServletContext;
+import javax.servlet.UnavailableException;
+
+import org.apache.logging.log4j.core.LoggerContext;
+import org.apache.logging.log4j.core.impl.ContextAnchor;
+import org.easymock.Capture;
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Test;
+
+import static org.easymock.EasyMock.*;
+import static org.junit.Assert.*;
+
+public class Log4jWebInitializerImplTest {
+    private ServletContext servletContext;
+
+    private Log4jWebInitializerImpl initializer;
+
+    @Before
+    public void setUp() {
+        Capture<Log4jWebInitializer> initializerCapture = new Capture<Log4jWebInitializer>();
+
+        this.servletContext = createStrictMock(ServletContext.class);
+        expect(this.servletContext.getAttribute(Log4jWebInitializer.INITIALIZER_ATTRIBUTE)).andReturn(null);
+        this.servletContext.setAttribute(eq(Log4jWebInitializer.INITIALIZER_ATTRIBUTE), capture(initializerCapture));
+        expectLastCall();
+
+        replay(this.servletContext);
+
+        Log4jWebInitializer initializer = Log4jWebInitializerImpl.getLog4jWebInitializer(this.servletContext);
+
+        assertNotNull("The initializer should not be null.", initializer);
+        assertSame("The capture is not correct.", initializer, initializerCapture.getValue());
+        assertTrue("The initializer is not correct.", initializer instanceof Log4jWebInitializerImpl);
+        verify(this.servletContext);
+        reset(this.servletContext);
+
+        this.initializer = (Log4jWebInitializerImpl)initializer;
+    }
+
+    @After
+    public void tearDown() {
+        verify(this.servletContext);
+    }
+
+    @Test
+    public void testDeinitializeBeforeInitialize() {
+        replay(this.servletContext);
+
+        try {
+            this.initializer.deinitialize();
+            fail("Expected an IllegalStateException.");
+        } catch (IllegalStateException ignore) {
+
+        }
+    }
+
+    @Test
+    public void testSetLoggerContextBeforeInitialize() {
+        replay(this.servletContext);
+
+        assertNull("The context should be null.", ContextAnchor.THREAD_CONTEXT.get());
+
+        this.initializer.setLoggerContext();
+
+        assertNull("The context should still be null.", ContextAnchor.THREAD_CONTEXT.get());
+    }
+
+    @Test
+    public void testClearLoggerContextBeforeInitialize() {
+        replay(this.servletContext);
+
+        assertNull("The context should be null.", ContextAnchor.THREAD_CONTEXT.get());
+
+        this.initializer.clearLoggerContext();
+
+        assertNull("The context should still be null.", ContextAnchor.THREAD_CONTEXT.get());
+    }
+
+    @Test
+    public void testInitializeWithNoParametersThenSetLoggerContextThenDeinitialize() throws Exception {
+        expect(this.servletContext.getInitParameter(Log4jWebInitializer.LOG4J_CONTEXT_NAME)).andReturn(null);
+        expect(this.servletContext.getInitParameter(Log4jWebInitializer.LOG4J_CONFIG_LOCATION)).andReturn(null);
+        expect(this.servletContext.getInitParameter(Log4jWebInitializer.IS_LOG4J_CONTEXT_SELECTOR_NAMED))
+                .andReturn(null);
+        expect(this.servletContext.getServletContextName()).andReturn("helloWorld01");
+
+        replay(this.servletContext);
+
+        assertNull("The context should be null.", ContextAnchor.THREAD_CONTEXT.get());
+
+        this.initializer.initialize();
+
+        verify(this.servletContext);
+        reset(this.servletContext);
+        replay(this.servletContext);
+
+        assertNull("The context should still be null.", ContextAnchor.THREAD_CONTEXT.get());
+
+        this.initializer.setLoggerContext();
+
+        LoggerContext context = ContextAnchor.THREAD_CONTEXT.get();
+        assertNotNull("The context should not be null.", context);
+
+        this.initializer.clearLoggerContext();
+
+        assertNull("The context should be null again.", ContextAnchor.THREAD_CONTEXT.get());
+
+        verify(this.servletContext);
+        reset(this.servletContext);
+
+        this.servletContext.log(anyObject(String.class));
+        expectLastCall();
+
+        replay(this.servletContext);
+
+        this.initializer.deinitialize();
+
+        verify(this.servletContext);
+        reset(this.servletContext);
+        replay(this.servletContext);
+
+        assertNull("The context should again still be null.", ContextAnchor.THREAD_CONTEXT.get());
+
+        this.initializer.setLoggerContext();
+
+        assertNull("The context should finally still be null.", ContextAnchor.THREAD_CONTEXT.get());
+    }
+
+    @Test
+    public void testInitializeWithClassLoaderNoParametersThenSetLoggerContextThenDeinitialize() throws Exception {
+        expect(this.servletContext.getInitParameter(Log4jWebInitializer.LOG4J_CONTEXT_NAME)).andReturn(null);
+        expect(this.servletContext.getInitParameter(Log4jWebInitializer.LOG4J_CONFIG_LOCATION)).andReturn(null);
+        expect(this.servletContext.getInitParameter(Log4jWebInitializer.IS_LOG4J_CONTEXT_SELECTOR_NAMED))
+                .andReturn("false");
+        expect(this.servletContext.getServletContextName()).andReturn("helloWorld02");
+        expect(this.servletContext.getClassLoader()).andReturn(this.getClass().getClassLoader());
+
+        replay(this.servletContext);
+
+        assertNull("The context should be null.", ContextAnchor.THREAD_CONTEXT.get());
+
+        this.initializer.initialize();
+
+        verify(this.servletContext);
+        reset(this.servletContext);
+        replay(this.servletContext);
+
+        assertNull("The context should still be null.", ContextAnchor.THREAD_CONTEXT.get());
+
+        this.initializer.setLoggerContext();
+
+        LoggerContext context = ContextAnchor.THREAD_CONTEXT.get();
+        assertNotNull("The context should not be null.", context);
+
+        this.initializer.clearLoggerContext();
+
+        assertNull("The context should be null again.", ContextAnchor.THREAD_CONTEXT.get());
+
+        verify(this.servletContext);
+        reset(this.servletContext);
+
+        this.servletContext.log(anyObject(String.class));
+        expectLastCall();
+
+        replay(this.servletContext);
+
+        this.initializer.deinitialize();
+
+        verify(this.servletContext);
+        reset(this.servletContext);
+        replay(this.servletContext);
+
+        assertNull("The context should again still be null.", ContextAnchor.THREAD_CONTEXT.get());
+
+        this.initializer.setLoggerContext();
+
+        assertNull("The context should finally still be null.", ContextAnchor.THREAD_CONTEXT.get());
+    }
+
+    @Test
+    public void testInitializeIsIdempotent() throws Exception {
+        expect(this.servletContext.getInitParameter(Log4jWebInitializer.LOG4J_CONTEXT_NAME)).andReturn(null);
+        expect(this.servletContext.getInitParameter(Log4jWebInitializer.LOG4J_CONFIG_LOCATION)).andReturn(null);
+        expect(this.servletContext.getInitParameter(Log4jWebInitializer.IS_LOG4J_CONTEXT_SELECTOR_NAMED))
+                .andReturn("nothing");
+        expect(this.servletContext.getServletContextName()).andReturn("helloWorld03");
+        expect(this.servletContext.getClassLoader()).andReturn(this.getClass().getClassLoader());
+
+        replay(this.servletContext);
+
+        assertNull("The context should be null.", ContextAnchor.THREAD_CONTEXT.get());
+
+        this.initializer.initialize();
+
+        verify(this.servletContext);
+        reset(this.servletContext);
+        replay(this.servletContext);
+
+        this.initializer.initialize();
+        this.initializer.initialize();
+        this.initializer.initialize();
+
+        verify(this.servletContext);
+        reset(this.servletContext);
+
+        this.servletContext.log(anyObject(String.class));
+        expectLastCall();
+
+        replay(this.servletContext);
+
+        this.initializer.deinitialize();
+    }
+
+    @Test
+    public void testInitializeFailsAfterDeinitialize() throws Exception {
+        expect(this.servletContext.getInitParameter(Log4jWebInitializer.LOG4J_CONTEXT_NAME)).andReturn(null);
+        expect(this.servletContext.getInitParameter(Log4jWebInitializer.LOG4J_CONFIG_LOCATION)).andReturn(null);
+        expect(this.servletContext.getInitParameter(Log4jWebInitializer.IS_LOG4J_CONTEXT_SELECTOR_NAMED))
+                .andReturn(null);
+        expect(this.servletContext.getServletContextName()).andReturn("helloWorld04");
+        expect(this.servletContext.getClassLoader()).andReturn(this.getClass().getClassLoader());
+
+        replay(this.servletContext);
+
+        assertNull("The context should be null.", ContextAnchor.THREAD_CONTEXT.get());
+
+        this.initializer.initialize();
+
+        verify(this.servletContext);
+        reset(this.servletContext);
+
+        this.servletContext.log(anyObject(String.class));
+        expectLastCall();
+
+        replay(this.servletContext);
+
+        this.initializer.deinitialize();
+
+        try {
+            this.initializer.initialize();
+            fail("Expected an IllegalStateException.");
+        } catch (IllegalStateException ignore) {
+
+        }
+    }
+
+    @Test
+    public void testDeinitializeIsIdempotent() throws Exception {
+        expect(this.servletContext.getInitParameter(Log4jWebInitializer.LOG4J_CONTEXT_NAME)).andReturn(null);
+        expect(this.servletContext.getInitParameter(Log4jWebInitializer.LOG4J_CONFIG_LOCATION)).andReturn(null);
+        expect(this.servletContext.getInitParameter(Log4jWebInitializer.IS_LOG4J_CONTEXT_SELECTOR_NAMED))
+                .andReturn(null);
+        expect(this.servletContext.getServletContextName()).andReturn("helloWorld05");
+        expect(this.servletContext.getClassLoader()).andReturn(this.getClass().getClassLoader());
+
+        replay(this.servletContext);
+
+        assertNull("The context should be null.", ContextAnchor.THREAD_CONTEXT.get());
+
+        this.initializer.initialize();
+
+        verify(this.servletContext);
+        reset(this.servletContext);
+
+        this.servletContext.log(anyObject(String.class));
+        expectLastCall();
+
+        replay(this.servletContext);
+
+        this.initializer.deinitialize();
+        this.initializer.deinitialize();
+        this.initializer.deinitialize();
+    }
+
+    @Test
+    public void testInitializeUsingJndiSelectorFails() throws Exception {
+        expect(this.servletContext.getInitParameter(Log4jWebInitializer.LOG4J_CONTEXT_NAME)).andReturn(null);
+        expect(this.servletContext.getInitParameter(Log4jWebInitializer.LOG4J_CONFIG_LOCATION)).andReturn(null);
+        expect(this.servletContext.getInitParameter(Log4jWebInitializer.IS_LOG4J_CONTEXT_SELECTOR_NAMED))
+                .andReturn("true");
+
+        replay(this.servletContext);
+
+        assertNull("The context should be null.", ContextAnchor.THREAD_CONTEXT.get());
+
+        try {
+            this.initializer.initialize();
+            fail("Expected an UnavailableException.");
+        } catch (UnavailableException ignore) {
+
+        }
+    }
+
+    @Test
+    public void testInitializeUsingJndiSelector() throws Exception {
+        expect(this.servletContext.getInitParameter(Log4jWebInitializer.LOG4J_CONTEXT_NAME)).andReturn("helloWorld6");
+        expect(this.servletContext.getInitParameter(Log4jWebInitializer.LOG4J_CONFIG_LOCATION)).andReturn(null);
+        expect(this.servletContext.getInitParameter(Log4jWebInitializer.IS_LOG4J_CONTEXT_SELECTOR_NAMED))
+                .andReturn("true");
+        this.servletContext.log(anyObject(String.class));
+        expectLastCall();
+
+        replay(this.servletContext);
+
+        assertNull("The context should be null.", ContextAnchor.THREAD_CONTEXT.get());
+
+        this.initializer.initialize();
+
+        verify(this.servletContext);
+        reset(this.servletContext);
+        replay(this.servletContext);
+
+        assertNull("The context should still be null.", ContextAnchor.THREAD_CONTEXT.get());
+
+        this.initializer.setLoggerContext();
+
+        assertNull("The context should still be null because no named selector.", ContextAnchor.THREAD_CONTEXT.get());
+
+        this.initializer.clearLoggerContext();
+
+        assertNull("The context should be null again.", ContextAnchor.THREAD_CONTEXT.get());
+
+        verify(this.servletContext);
+        reset(this.servletContext);
+        replay(this.servletContext);
+
+        this.initializer.deinitialize();
+
+        verify(this.servletContext);
+        reset(this.servletContext);
+        replay(this.servletContext);
+
+        assertNull("The context should again still be null.", ContextAnchor.THREAD_CONTEXT.get());
+
+        this.initializer.setLoggerContext();
+
+        assertNull("The context should finally still be null.", ContextAnchor.THREAD_CONTEXT.get());
+    }
+}

Modified: logging/log4j/log4j2/trunk/src/site/xdoc/manual/webapp.xml
URL: http://svn.apache.org/viewvc/logging/log4j/log4j2/trunk/src/site/xdoc/manual/webapp.xml?rev=1500509&r1=1500508&r2=1500509&view=diff
==============================================================================
--- logging/log4j/log4j2/trunk/src/site/xdoc/manual/webapp.xml (original)
+++ logging/log4j/log4j2/trunk/src/site/xdoc/manual/webapp.xml Sun Jul  7 19:17:09 2013
@@ -47,6 +47,13 @@
           the application deploys and shutting down when the application undeploys.
         </p>
         <p>
+          <b><em>Important Note!</em></b> For performance reasons, containers often ignore certain JARs and do not scan
+          them for web-fragments and <code>ServletContainerInitializer</code>s. For example, Tomcat 7 &lt;7.0.42 ignores
+          all JAR files named log4j*.jar, which prevents this feature from working. This has been fixed in
+          Tomcat 7.0.43, Tomcat 8, and later. In Tomcat 7 &lt;7.0.42 you will need to change catalina.properties and
+          remove "log4j*.jar" from the jarsToSkip property.
+        </p>
+        <p>
           <b>The Long Story</b><br />
           The Log4j 2 Core JAR file is a web-fragment configured to order before any other web fragments in your
           application. It contains a <code>ServletContainerInitializer</code>
@@ -141,10 +148,10 @@
     </context-param>]]></pre>
         </p>
         <p>
-          <b>Set the Configuration Path/File/URI to "/etc/myApp/log4j.xml"</b>
+          <b>Set the Configuration Path/File/URI to "/etc/myApp/myLogging.xml"</b>
           <pre class="prettyprint linenums"><![CDATA[    <context-param>
         <param-name>log4jConfiguration</param-name>
-        <param-value>file:///etc/myApp/log4j.xml</param-value>
+        <param-value>file:///etc/myApp/myLogging.xml</param-value>
     </context-param>]]></pre>
         </p>
         <p>
@@ -159,7 +166,7 @@
     </context-param>
     <context-param>
         <param-name>log4jConfiguration</param-name>
-        <param-value>file://D:\conf\log4j.xml</param-value>
+        <param-value>file://D:\conf\myLogging.xml</param-value>
     </context-param>]]></pre>
           Note that in this case you must also set the "Log4jContextSelector" system property to
           "org.apache.logging.log4j.core.selector.JNDIContextSelector."