You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@mina.apache.org by ma...@apache.org on 2007/09/16 22:33:50 UTC

svn commit: r576168 - in /mina/trunk: core/src/main/java/org/apache/mina/filter/logging/ core/src/main/java/org/apache/mina/filter/util/ core/src/test/java/org/apache/mina/filter/logging/ core/src/test/java/org/apache/mina/filter/util/ example/ example...

Author: maarten
Date: Sun Sep 16 13:33:48 2007
New Revision: 576168

URL: http://svn.apache.org/viewvc?rev=576168&view=rev
Log:
Resolved issue: DIRMINA-422 : an IoFilter that leverages SLF4J's MDC feature

Added:
    mina/trunk/core/src/main/java/org/apache/mina/filter/logging/MDCInjectionFilter.java
      - copied, changed from r573022, mina/trunk/core/src/main/java/org/apache/mina/filter/logging/MdcLoggingFilter.java
    mina/trunk/core/src/test/java/org/apache/mina/filter/logging/
    mina/trunk/core/src/test/java/org/apache/mina/filter/logging/MDCInjectionFilterTest.java
Removed:
    mina/trunk/core/src/main/java/org/apache/mina/filter/logging/MdcLoggingFilter.java
Modified:
    mina/trunk/core/src/main/java/org/apache/mina/filter/util/WrappingFilter.java
    mina/trunk/core/src/test/java/org/apache/mina/filter/util/WrappingFilterTest.java
    mina/trunk/example/pom.xml
    mina/trunk/example/src/main/java/org/apache/mina/example/chat/ChatProtocolHandler.java
    mina/trunk/example/src/main/java/org/apache/mina/example/chat/Main.java
    mina/trunk/example/src/main/resources/log4j.properties
    mina/trunk/example/src/main/resources/org/apache/mina/example/chat/serverContext.xml

Copied: mina/trunk/core/src/main/java/org/apache/mina/filter/logging/MDCInjectionFilter.java (from r573022, mina/trunk/core/src/main/java/org/apache/mina/filter/logging/MdcLoggingFilter.java)
URL: http://svn.apache.org/viewvc/mina/trunk/core/src/main/java/org/apache/mina/filter/logging/MDCInjectionFilter.java?p2=mina/trunk/core/src/main/java/org/apache/mina/filter/logging/MDCInjectionFilter.java&p1=mina/trunk/core/src/main/java/org/apache/mina/filter/logging/MdcLoggingFilter.java&r1=573022&r2=576168&rev=576168&view=diff
==============================================================================
--- mina/trunk/core/src/main/java/org/apache/mina/filter/logging/MdcLoggingFilter.java (original)
+++ mina/trunk/core/src/main/java/org/apache/mina/filter/logging/MDCInjectionFilter.java Sun Sep 16 13:33:48 2007
@@ -8,39 +8,81 @@
 import java.util.*;
 
 /**
+ * This filter will inject some key IoSession properties into the Mapped Diagnostic Context (MDC)
+ * <p/>
+ * These properties will be set in the MDC for all logging events that are generated
+ * down the call stack, even in code that is not aware of MINA.
+ *
+ * The following properties will be set for all transports:
+ * <ul>
+ *  <li>"IoHandlerClass"</li>
+ *  <li>"remoteAddress"</li>
+ *  <li>"localAddress"</li>
+ * </ul>
+ *
+ * When <code>session.getTransportMetadata().getAddressType() == InetSocketAddress.class</code>
+ * the following properties will also be set:
+ * <ul>
+ * <li>"remoteIp"</li>
+ * <li>"remotePort"</li>
+ * <li>"localIp"</li>
+ * <li>"localPort"</li>
+ * </ul>
+ *
+ * User code can also add properties to the context, via
+ *
+ * If you only want the MDC to be set for the IoHandler code, it's enough to add
+ * one MDCInjectionFilter at the end of the filter chain.
+ *
+ * If you want the MDC to be set for ALL code, you should
+ *   add an MDCInjectionFilter to the start of the chain
+ *   and add one after EVERY ExecutorFilter in the chain
  *
  * @author The Apache MINA Project (dev@mina.apache.org)
  * @version $Rev: 566952 $, $Date: 2007-08-17 09:25:04 +0200 (vr, 17 aug 2007) $
  */
 
-public class MdcLoggingFilter extends WrappingFilter {
+public class MDCInjectionFilter extends WrappingFilter {
 
     /** key used for storing the context map in the IoSession */
-    public static final String CONTEXT_KEY = MdcLoggingFilter.class + ".CONTEXT_KEY";
+    private static final String CONTEXT_KEY = MDCInjectionFilter.class + ".CONTEXT_KEY";
+
+    private ThreadLocal<Integer> callDepth = new ThreadLocal<Integer>() {
+        protected Integer initialValue() {
+            return 0;
+        }
+    };
 
-    protected void wrapFilterAction(IoEventType eventType, IoSession session, WrappingFilter.FilterAction action) {
-        //noinspection unchecked
-        Map<String,String> context = getContext(session);
+    @Override
+    protected void wrap(IoEventType eventType, IoSession session, Runnable action) {
+        // since this method can potentially call into itself
+        // we need to check the call depth before clearing the MDC
+        callDepth.set (callDepth.get() + 1);
+        Context context = getContext(session);
         /* copy context to the MDC */
-        for (Map.Entry<String, String> e : context.entrySet()) {
+        for (Map.Entry<String,String> e : context.entrySet()) {
             MDC.put(e.getKey(), e.getValue());
         }
         try {
             /* propagate event down the filter chain */
-            action.execute();
+            action.run();
         } finally {
-            /* remove context from the MDC */
-            for (String key : context.keySet()) {
-                MDC.remove(key);
+            callDepth.set ( callDepth.get() - 1);
+            if (callDepth.get() == 0) {
+                /* remove context from the MDC */
+                for (Object key : context.keySet()) {
+                    MDC.remove(key.toString());
+                }
+                MDC.remove("name");
             }
         }
-    }    
+    }
+
 
-    public Map<String,String> getContext(final IoSession session) {
-        //noinspection unchecked
-        Map<String,String> context = (Map<String,String>) session.getAttribute(CONTEXT_KEY);
+    public static Context getContext(final IoSession session) {
+        Context context = (Context) session.getAttribute(CONTEXT_KEY);
         if (context == null) {
-            context = new HashMap<String, String>();
+            context = new Context();
             fillContext(session, context);
             session.setAttribute(CONTEXT_KEY, context);
         }
@@ -53,8 +95,8 @@
      * @param session the session to map
      * @param context key properties will be added to this map
      */
-    protected void fillContext(final IoSession session, final Map<String,String> context) {
-        context.put("IoHandlerClass", session.getHandler().getClass().toString());
+    protected static void fillContext(final IoSession session, final Context context) {
+        context.put("IoHandlerClass", session.getHandler().getClass().getName());
         context.put("remoteAddress", session.getRemoteAddress().toString());
         context.put("localAddress", session.getLocalAddress().toString());
         if (session.getTransportMetadata().getAddressType() == InetSocketAddress.class) {
@@ -67,4 +109,19 @@
         }
     }
 
+    /**
+     * Add a property to the context for the given session
+     * This property will be added to the MDC for all subsequent events
+     * @param session The session for which you want to set a property
+     * @param key  The name of the property
+     * @param value The value of the property
+     */
+    public static void setProperty (IoSession session, String key, String value) {
+        Context context = getContext(session);  
+        context.put(key, value);        
+    }
+
+    private static class Context extends HashMap<String,String> {
+    }
+    
 }

Modified: mina/trunk/core/src/main/java/org/apache/mina/filter/util/WrappingFilter.java
URL: http://svn.apache.org/viewvc/mina/trunk/core/src/main/java/org/apache/mina/filter/util/WrappingFilter.java?rev=576168&r1=576167&r2=576168&view=diff
==============================================================================
--- mina/trunk/core/src/main/java/org/apache/mina/filter/util/WrappingFilter.java (original)
+++ mina/trunk/core/src/main/java/org/apache/mina/filter/util/WrappingFilter.java Sun Sep 16 13:33:48 2007
@@ -1,10 +1,6 @@
 package org.apache.mina.filter.util;
 
-import org.apache.mina.common.IdleStatus;
-import org.apache.mina.common.IoEventType;
-import org.apache.mina.common.IoFilterAdapter;
-import org.apache.mina.common.IoSession;
-import org.apache.mina.common.WriteRequest;
+import org.apache.mina.common.*;
 
 /**
  * Extend this class when you want to create a filter that
@@ -12,79 +8,86 @@
  */
 public abstract class WrappingFilter extends IoFilterAdapter {
 
-    protected interface FilterAction {
-        void execute();
+    public WrappingFilter() {
     }
 
-    abstract protected void wrapFilterAction(IoEventType eventType, IoSession session, FilterAction action);
+    protected abstract void wrap(IoEventType eventType, IoSession session, Runnable action);
 
-    public void sessionCreated(final NextFilter nextFilter, final IoSession session) throws Exception {
-        wrapFilterAction(IoEventType.SESSION_CREATED, session, new FilterAction() {
-            public void execute() {
+    final public void sessionCreated(final NextFilter nextFilter, final IoSession session) throws Exception {
+        wrap(IoEventType.SESSION_CREATED, session, new Runnable() {
+            public void run() {
                 nextFilter.sessionCreated(session);
             }
         });
     }
 
-    public void sessionOpened(final NextFilter nextFilter, final IoSession session) throws Exception {
-        wrapFilterAction(IoEventType.SESSION_OPENED, session, new FilterAction() {
-            public void execute() {
+    @Override
+    final public void sessionOpened(final NextFilter nextFilter, final IoSession session) throws Exception {
+        wrap(IoEventType.SESSION_OPENED, session, new Runnable() {
+            public void run() {
                 nextFilter.sessionOpened(session);
             }
         });
     }
 
-    public void sessionClosed(final NextFilter nextFilter, final IoSession session) throws Exception {
-        wrapFilterAction(IoEventType.SESSION_CLOSED, session, new FilterAction() {
-            public void execute() {
+    @Override
+    final public void sessionClosed(final NextFilter nextFilter, final IoSession session) throws Exception {
+        wrap(IoEventType.SESSION_CLOSED, session, new Runnable() {
+            public void run() {
                 nextFilter.sessionClosed(session);
             }
         });
     }
 
-    public void sessionIdle(final NextFilter nextFilter, final IoSession session, final IdleStatus status) throws Exception {
-        wrapFilterAction(IoEventType.SESSION_IDLE, session, new FilterAction() {
-            public void execute() {
+    @Override
+    final public void sessionIdle(final NextFilter nextFilter, final IoSession session, final IdleStatus status) throws Exception {
+        wrap(IoEventType.SESSION_IDLE, session, new Runnable() {
+            public void run() {
                 nextFilter.sessionIdle(session, status);
             }
         });
     }
 
-    public void exceptionCaught(final NextFilter nextFilter, final IoSession session, final Throwable cause) throws Exception {
-        wrapFilterAction(IoEventType.EXCEPTION_CAUGHT, session, new FilterAction() {
-            public void execute() {
+    @Override
+    final public void exceptionCaught(final NextFilter nextFilter, final IoSession session, final Throwable cause) throws Exception {
+        wrap(IoEventType.EXCEPTION_CAUGHT, session, new Runnable() {
+            public void run() {
                 nextFilter.exceptionCaught(session, cause);
             }
         });
     }
 
-    public void messageReceived(final NextFilter nextFilter, final IoSession session, final Object message) throws Exception {
-        wrapFilterAction(IoEventType.MESSAGE_RECEIVED, session, new FilterAction() {
-            public void execute() {
+    @Override
+    final public void messageReceived(final NextFilter nextFilter, final IoSession session, final Object message) throws Exception {
+        wrap(IoEventType.MESSAGE_RECEIVED, session, new Runnable() {
+            public void run() {
                 nextFilter.messageReceived(session, message);
             }
         });
     }
 
-    public void messageSent(final NextFilter nextFilter, final IoSession session, final WriteRequest writeRequest) throws Exception {
-        wrapFilterAction(IoEventType.MESSAGE_SENT, session, new FilterAction() {
-            public void execute() {
+    @Override
+    final public void messageSent(final NextFilter nextFilter, final IoSession session, final WriteRequest writeRequest) throws Exception {
+        wrap(IoEventType.MESSAGE_SENT, session, new Runnable() {
+            public void run() {
                 nextFilter.messageSent(session, writeRequest);
             }
         });
     }
 
-    public void filterWrite(final NextFilter nextFilter, final IoSession session, final WriteRequest writeRequest) throws Exception {
-        wrapFilterAction(IoEventType.WRITE, session, new FilterAction() {
-            public void execute() {
+    @Override
+    final public void filterWrite(final NextFilter nextFilter, final IoSession session, final WriteRequest writeRequest) throws Exception {
+        wrap(IoEventType.WRITE, session, new Runnable() {
+            public void run() {
                 nextFilter.filterWrite(session, writeRequest);
             }
         });
     }
 
-    public void filterClose(final NextFilter nextFilter, final IoSession session) throws Exception {
-        wrapFilterAction(IoEventType.CLOSE, session, new FilterAction() {
-            public void execute() {
+    @Override
+    final public void filterClose(final NextFilter nextFilter, final IoSession session) throws Exception {
+        wrap(IoEventType.CLOSE, session, new Runnable() {
+            public void run() {
                 nextFilter.filterClose(session);
             }
         });

Added: mina/trunk/core/src/test/java/org/apache/mina/filter/logging/MDCInjectionFilterTest.java
URL: http://svn.apache.org/viewvc/mina/trunk/core/src/test/java/org/apache/mina/filter/logging/MDCInjectionFilterTest.java?rev=576168&view=auto
==============================================================================
--- mina/trunk/core/src/test/java/org/apache/mina/filter/logging/MDCInjectionFilterTest.java (added)
+++ mina/trunk/core/src/test/java/org/apache/mina/filter/logging/MDCInjectionFilterTest.java Sun Sep 16 13:33:48 2007
@@ -0,0 +1,289 @@
+package org.apache.mina.filter.logging;
+
+import junit.framework.TestCase;
+import org.apache.mina.filter.codec.*;
+import org.apache.mina.filter.executor.ExecutorFilter;
+import org.apache.mina.filter.statistic.ProfilerTimerFilter;
+import org.apache.mina.common.*;
+import org.apache.mina.transport.socket.nio.SocketAcceptor;
+import org.apache.mina.transport.socket.nio.SocketConnector;
+import org.apache.log4j.AppenderSkeleton;
+import org.apache.log4j.Level;
+import org.apache.log4j.spi.LoggingEvent;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import java.io.IOException;
+import java.net.InetSocketAddress;
+import java.net.SocketAddress;
+import java.util.*;
+import java.util.concurrent.CountDownLatch;
+
+/**
+ */
+public class MDCInjectionFilterTest extends TestCase {
+
+    private static Logger logger = LoggerFactory.getLogger("MDCInjectionFilterTest");
+    private static final int PORT = 7475;
+    private static final int TIMEOUT = 5000;
+
+    private MyAppender appender = new MyAppender();
+    private SocketAcceptor acceptor;
+
+    protected void setUp() throws Exception {
+        super.setUp();
+        // uncomment next line if you want to see normal logging
+        org.apache.log4j.Logger.getRootLogger().removeAllAppenders();
+        org.apache.log4j.Logger.getRootLogger().setLevel(Level.DEBUG);
+        org.apache.log4j.Logger.getRootLogger().addAppender(appender);
+        acceptor = new SocketAcceptor();
+    }
+
+
+    protected void tearDown() throws Exception {
+        acceptor.unbind();
+        super.tearDown();
+    }
+
+    public void testSimpleChain() throws IOException, InterruptedException {
+        DefaultIoFilterChainBuilder chain = new DefaultIoFilterChainBuilder();
+        chain.addFirst("mdc-injector", new MDCInjectionFilter());
+        chain.addLast("dummy", new DummyIoFilter());
+        chain.addLast("protocol", new ProtocolCodecFilter(new DummyProtocolCodecFactory()));
+        test(chain);
+    }
+
+    public void testExecutorFilterAtTheEnd() throws IOException, InterruptedException {
+        DefaultIoFilterChainBuilder chain = new DefaultIoFilterChainBuilder();
+        MDCInjectionFilter mdcInjectionFilter = new MDCInjectionFilter();
+        chain.addFirst("mdc-injector1", mdcInjectionFilter);
+        chain.addLast("dummy", new DummyIoFilter());
+        chain.addLast("protocol", new ProtocolCodecFilter(new DummyProtocolCodecFactory()));
+        chain.addLast("executor" , new ExecutorFilter());
+        chain.addLast("mdc-injector2", mdcInjectionFilter);
+        test(chain);
+    }
+
+    public void testExecutorFilterAtBeginning() throws IOException, InterruptedException {
+        DefaultIoFilterChainBuilder chain = new DefaultIoFilterChainBuilder();
+        MDCInjectionFilter mdcInjectionFilter = new MDCInjectionFilter();
+        chain.addLast("executor" , new ExecutorFilter());
+        chain.addLast("mdc-injector", mdcInjectionFilter);
+        chain.addLast("dummy", new DummyIoFilter());
+        chain.addLast("protocol", new ProtocolCodecFilter(new DummyProtocolCodecFactory()));
+        test(chain);
+    }
+
+    public void testExecutorFilterBeforeProtocol() throws IOException, InterruptedException {
+        DefaultIoFilterChainBuilder chain = new DefaultIoFilterChainBuilder();
+        MDCInjectionFilter mdcInjectionFilter = new MDCInjectionFilter();
+        chain.addLast("executor" , new ExecutorFilter());
+        chain.addLast("mdc-injector", mdcInjectionFilter);
+        chain.addLast("dummy", new DummyIoFilter());
+        chain.addLast("protocol", new ProtocolCodecFilter(new DummyProtocolCodecFactory()));
+        test(chain);
+    }
+
+    public void testMultipleFilters() throws IOException, InterruptedException {
+        DefaultIoFilterChainBuilder chain = new DefaultIoFilterChainBuilder();
+        MDCInjectionFilter mdcInjectionFilter = new MDCInjectionFilter();
+        chain.addLast("executor" , new ExecutorFilter());
+        chain.addLast("mdc-injector", mdcInjectionFilter);
+        chain.addLast("profiler", new ProfilerTimerFilter());
+        chain.addLast("dummy", new DummyIoFilter());
+        chain.addLast("logger", new LoggingFilter());
+        chain.addLast("protocol", new ProtocolCodecFilter(new DummyProtocolCodecFactory()));
+        test(chain);
+    }
+
+
+    public void testTwoExecutorFilters() throws IOException, InterruptedException {
+        DefaultIoFilterChainBuilder chain = new DefaultIoFilterChainBuilder();
+        MDCInjectionFilter mdcInjectionFilter = new MDCInjectionFilter();
+        chain.addLast("executor1" , new ExecutorFilter());
+        chain.addLast("mdc-injector1", mdcInjectionFilter);
+        chain.addLast("protocol", new ProtocolCodecFilter(new DummyProtocolCodecFactory()));
+        chain.addLast("dummy", new DummyIoFilter());
+        chain.addLast("executor2" , new ExecutorFilter());
+        chain.addLast("mdc-injector2", mdcInjectionFilter);
+        test(chain);
+    }
+
+    private void test(DefaultIoFilterChainBuilder chain) throws IOException, InterruptedException {
+        // configure the server
+        SimpleIoHandler simpleIoHandler = new SimpleIoHandler();
+        acceptor.setHandler(simpleIoHandler);
+        acceptor.setLocalAddress(new InetSocketAddress(PORT));
+        acceptor.bind();
+        acceptor.setFilterChainBuilder(chain);
+        // create some clients
+        SocketConnector connector = new SocketConnector();
+        connector.setHandler(new IoHandlerAdapter());
+        SocketAddress remoteAddressClients[] = new SocketAddress[2];
+        remoteAddressClients[0] = connectAndWrite(connector,0);
+        remoteAddressClients[1] = connectAndWrite(connector,1);
+        // wait until Iohandler has received all events
+        simpleIoHandler.messageSentLatch.await();
+        simpleIoHandler.sessionIdleLatch.await();
+        simpleIoHandler.sessionClosedLatch.await();
+
+        // verify that all logging events have correct MDC
+        for (LoggingEvent event : new ArrayList<LoggingEvent>(appender.events)) {
+            if (!ExecutorFilter.class.getName().equals(event.getLoggerName())) {
+                Object remoteAddress = event.getMDC("remoteAddress");
+                assertNotNull(
+                    "MDC[remoteAddress] not set for [" + event.getMessage() + "]",
+                    remoteAddress);
+                assertNotNull(
+                    "MDC[remotePort] not set for [" + event.getMessage() + "]",
+                    event.getMDC("remotePort"));
+                assertEquals(
+                    "every event should have MDC[IoHandlerClass]",
+                    SimpleIoHandler.class.getName(),
+                    event.getMDC("IoHandlerClass") );
+            }
+        }
+        // asert we have received all expected logging events for each client
+        for (int i = 0; i < remoteAddressClients.length; i++) {
+            SocketAddress remoteAddressClient = remoteAddressClients[i];
+            assertEventExists(appender.events, "sessionCreated", remoteAddressClient, null);
+            assertEventExists(appender.events, "sessionOpened", remoteAddressClient, null);
+            assertEventExists(appender.events, "decode", remoteAddressClient, null);
+            assertEventExists(appender.events, "messageReceived", remoteAddressClient, null);
+            assertEventExists(appender.events, "encode", remoteAddressClient, null);
+            assertEventExists(appender.events, "exceptionCaught", remoteAddressClient, "user-" + i);
+            assertEventExists(appender.events, "messageSent", remoteAddressClient, "user-" + i);
+            assertEventExists(appender.events, "sessionIdle", remoteAddressClient, "user-" + i);
+            assertEventExists(appender.events, "sessionClosed", remoteAddressClient, "user-" + i);
+            assertEventExists(appender.events, "sessionClosed", remoteAddressClient, "user-" + i);
+            assertEventExists(appender.events, "DummyIoFilter.sessionOpened", remoteAddressClient, "user-" + i);
+        }
+    }
+
+    private SocketAddress connectAndWrite(SocketConnector connector, int clientNr) {
+        ConnectFuture connectFuture = connector.connect(new InetSocketAddress("localhost",PORT));
+        connectFuture.awaitUninterruptibly(TIMEOUT);
+        ByteBuffer message = ByteBuffer.allocate(4).putInt(clientNr).flip();
+        IoSession session = connectFuture.getSession();
+        session.write(message).awaitUninterruptibly(TIMEOUT);
+        return session.getLocalAddress();
+    }
+
+    private void assertEventExists(List<LoggingEvent> events,
+                                   String message,
+                                   SocketAddress address,
+                                   String user) {
+        InetSocketAddress remoteAddress = (InetSocketAddress) address;
+        for (LoggingEvent event : events) {
+            if (event.getMessage().equals(message) &&
+                event.getMDC("remoteAddress").equals(remoteAddress.toString()) &&
+                event.getMDC("remoteIp").equals(remoteAddress.getAddress().getHostAddress()) &&
+                event.getMDC("remotePort").equals(remoteAddress.getPort()+"") ) {
+                if (user == null && event.getMDC("user") == null) {
+                    return;
+                }
+                if (user != null && user.equals(event.getMDC("user"))) {
+                    return;
+                }                
+                return;
+            }
+        }
+        fail("No LoggingEvent found from [" + remoteAddress +"] with message [" + message + "]");
+    }
+
+    private static class SimpleIoHandler extends IoHandlerAdapter {
+
+        CountDownLatch sessionIdleLatch = new CountDownLatch(2);
+        CountDownLatch sessionClosedLatch = new CountDownLatch(2);
+        CountDownLatch messageSentLatch = new CountDownLatch(2);
+
+        public void sessionCreated(IoSession session) throws Exception {
+            logger.info("sessionCreated");
+            session.getConfig().setIdleTime(IdleStatus.BOTH_IDLE, 1);
+        }
+
+        public void sessionOpened(IoSession session) throws Exception {
+            logger.info("sessionOpened");
+        }
+
+        public void sessionClosed(IoSession session) throws Exception {
+            logger.info("sessionClosed");
+            sessionClosedLatch.countDown();
+        }
+
+        public void sessionIdle(IoSession session, IdleStatus status) throws Exception {
+            logger.info("sessionIdle");
+            sessionIdleLatch.countDown();
+            session.close();            
+        }
+
+        public void exceptionCaught(IoSession session, Throwable cause) throws Exception {
+            logger.info("exceptionCaught", cause);
+        }
+
+        public void messageReceived(IoSession session, Object message) throws Exception {
+            logger.info("messageReceived");
+            // adding a custom property to the context
+            String user = "user-" + message;
+            MDCInjectionFilter.setProperty(session, "user", user);
+            logger.info("logged-in: " + user);
+            session.write(message);
+            throw new RuntimeException("just a test, forcing exceptionCaught");
+        }
+
+        public void messageSent(IoSession session, Object message) throws Exception {
+            logger.info("messageSent");
+            messageSentLatch.countDown();
+        }
+    }
+
+    private static class DummyProtocolCodecFactory implements ProtocolCodecFactory {
+
+        public ProtocolEncoder getEncoder() throws Exception {
+            return new ProtocolEncoderAdapter() {
+                public void encode(IoSession session, Object message, ProtocolEncoderOutput out) throws Exception {
+                    logger.info("encode");
+                    ByteBuffer buffer = ByteBuffer.allocate(4).putInt(123).flip();
+                    out.write(buffer);
+                }
+            };
+        }
+
+        public ProtocolDecoder getDecoder() throws Exception {
+            return new ProtocolDecoderAdapter() {
+                public void decode(IoSession session, ByteBuffer in, ProtocolDecoderOutput out) throws Exception {
+                    if (in.remaining() >= 4) {
+                        int value = in.getInt();
+                        logger.info("decode");
+                        out.write(value);                        
+                    }
+                }
+            };
+        }
+    }
+
+    private static class MyAppender extends AppenderSkeleton {
+
+        List<LoggingEvent> events = Collections.synchronizedList(new ArrayList<LoggingEvent>());
+
+        protected void append(final LoggingEvent loggingEvent) {
+            loggingEvent.getMDCCopy();
+            events.add(loggingEvent);
+        }
+
+        public boolean requiresLayout() {
+            return false;
+        }
+
+        public void close() {
+        }
+    }
+
+    private static class DummyIoFilter extends IoFilterAdapter {
+        public void sessionOpened(NextFilter nextFilter, IoSession session) throws Exception {
+            logger.info("DummyIoFilter.sessionOpened");
+            nextFilter.sessionOpened(session);
+        }
+    }
+
+}

Modified: mina/trunk/core/src/test/java/org/apache/mina/filter/util/WrappingFilterTest.java
URL: http://svn.apache.org/viewvc/mina/trunk/core/src/test/java/org/apache/mina/filter/util/WrappingFilterTest.java?rev=576168&r1=576167&r2=576168&view=diff
==============================================================================
--- mina/trunk/core/src/test/java/org/apache/mina/filter/util/WrappingFilterTest.java (original)
+++ mina/trunk/core/src/test/java/org/apache/mina/filter/util/WrappingFilterTest.java Sun Sep 16 13:33:48 2007
@@ -102,9 +102,9 @@
 
         private List<IoEventType> eventsAfter = new ArrayList<IoEventType>();
 
-        protected void wrapFilterAction(IoEventType eventType, IoSession session, WrappingFilter.FilterAction action) {
+        protected void wrap(IoEventType eventType, IoSession session, Runnable action) {
             eventsBefore.add(eventType);
-            action.execute();
+            action.run();
             eventsAfter.add(eventType);
         }
     }

Modified: mina/trunk/example/pom.xml
URL: http://svn.apache.org/viewvc/mina/trunk/example/pom.xml?rev=576168&r1=576167&r2=576168&view=diff
==============================================================================
--- mina/trunk/example/pom.xml (original)
+++ mina/trunk/example/pom.xml Sun Sep 16 13:33:48 2007
@@ -41,7 +41,7 @@
       <groupId>log4j</groupId>
       <artifactId>log4j</artifactId>
       <version>1.2.14</version>
-      <scope>runtime</scope>
+      <scope>compile</scope>
     </dependency>
 
     <dependency>

Modified: mina/trunk/example/src/main/java/org/apache/mina/example/chat/ChatProtocolHandler.java
URL: http://svn.apache.org/viewvc/mina/trunk/example/src/main/java/org/apache/mina/example/chat/ChatProtocolHandler.java?rev=576168&r1=576167&r2=576168&view=diff
==============================================================================
--- mina/trunk/example/src/main/java/org/apache/mina/example/chat/ChatProtocolHandler.java (original)
+++ mina/trunk/example/src/main/java/org/apache/mina/example/chat/ChatProtocolHandler.java Sun Sep 16 13:33:48 2007
@@ -22,13 +22,12 @@
 import java.util.Collections;
 import java.util.HashSet;
 import java.util.Set;
-import java.util.Map;
 
 import org.apache.mina.common.IoHandler;
 import org.apache.mina.common.IoHandlerAdapter;
 import org.apache.mina.common.IoSession;
 import org.apache.mina.common.IoSessionLogger;
-import org.apache.mina.filter.logging.MdcLoggingFilter;
+import org.apache.mina.filter.logging.MDCInjectionFilter;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
@@ -95,8 +94,7 @@
 
                 sessions.add(session);
                 session.setAttribute("user", user);
-                Map<String,String> context = (Map<String,String>) session.getAttribute(MdcLoggingFilter.CONTEXT_KEY);
-                context.put("user", user);
+                MDCInjectionFilter.setProperty(session, "user", user);
 
                 // Allow all users
                 users.add(user);

Modified: mina/trunk/example/src/main/java/org/apache/mina/example/chat/Main.java
URL: http://svn.apache.org/viewvc/mina/trunk/example/src/main/java/org/apache/mina/example/chat/Main.java?rev=576168&r1=576167&r2=576168&view=diff
==============================================================================
--- mina/trunk/example/src/main/java/org/apache/mina/example/chat/Main.java (original)
+++ mina/trunk/example/src/main/java/org/apache/mina/example/chat/Main.java Sun Sep 16 13:33:48 2007
@@ -19,17 +19,17 @@
  */
 package org.apache.mina.example.chat;
 
-import java.net.InetSocketAddress;
-
 import org.apache.mina.common.DefaultIoFilterChainBuilder;
 import org.apache.mina.example.echoserver.ssl.BogusSSLContextFactory;
 import org.apache.mina.filter.codec.ProtocolCodecFilter;
 import org.apache.mina.filter.codec.textline.TextLineCodecFactory;
 import org.apache.mina.filter.logging.LoggingFilter;
-import org.apache.mina.filter.logging.MdcLoggingFilter;
+import org.apache.mina.filter.logging.MDCInjectionFilter;
 import org.apache.mina.filter.ssl.SSLFilter;
 import org.apache.mina.transport.socket.nio.SocketAcceptor;
 
+import java.net.InetSocketAddress;
+
 /**
  * (<b>Entry point</b>) Chat server
  * 
@@ -47,6 +47,9 @@
         SocketAcceptor acceptor = new SocketAcceptor();
         DefaultIoFilterChainBuilder chain = acceptor.getFilterChain();
 
+        MDCInjectionFilter mdcInjectionFilter = new MDCInjectionFilter();
+        chain.addLast("mdc", mdcInjectionFilter);
+
         // Add SSL filter if SSL is enabled.
         if (USE_SSL) {
             addSSLSupport(chain);
@@ -75,7 +78,6 @@
 
     private static void addLogger(DefaultIoFilterChainBuilder chain)
             throws Exception {
-        chain.addLast("mdc-logger", new MdcLoggingFilter());
         chain.addLast("logger", new LoggingFilter());        
         System.out.println("Logging ON");
     }

Modified: mina/trunk/example/src/main/resources/log4j.properties
URL: http://svn.apache.org/viewvc/mina/trunk/example/src/main/resources/log4j.properties?rev=576168&r1=576167&r2=576168&view=diff
==============================================================================
--- mina/trunk/example/src/main/resources/log4j.properties (original)
+++ mina/trunk/example/src/main/resources/log4j.properties Sun Sep 16 13:33:48 2007
@@ -4,7 +4,7 @@
 
 log4j.appender.stdout=org.apache.log4j.ConsoleAppender
 log4j.appender.stdout.layout=org.apache.log4j.PatternLayout
-log4j.appender.stdout.layout.ConversionPattern=[%d{HH:mm:ss}] %p [%X{user}] %X{remoteIp}:%X{remotePort} [%c] - %m%n
+log4j.appender.stdout.layout.ConversionPattern=[%d{HH:mm:ss}] %p [%c] - %m%n
 
 # you could use this pattern to test the MDC with the Chat server
-#log4j.appender.stdout.layout.ConversionPattern=[%d{HH:mm:ss}] %p [%X{user}] [%X{remoteIp}:%X{remotePort}] [%c] - %m%n
\ No newline at end of file
+#log4j.appender.stdout.layout.ConversionPattern=[%d{HH:mm:ss}] %t %p %X{name} [%X{user}] [%X{remoteIp}:%X{remotePort}] [%c] - %m%n
\ No newline at end of file

Modified: mina/trunk/example/src/main/resources/org/apache/mina/example/chat/serverContext.xml
URL: http://svn.apache.org/viewvc/mina/trunk/example/src/main/resources/org/apache/mina/example/chat/serverContext.xml?rev=576168&r1=576167&r2=576168&view=diff
==============================================================================
--- mina/trunk/example/src/main/resources/org/apache/mina/example/chat/serverContext.xml (original)
+++ mina/trunk/example/src/main/resources/org/apache/mina/example/chat/serverContext.xml Sun Sep 16 13:33:48 2007
@@ -40,6 +40,7 @@
     <property name="filters">
       <list>
         <bean class="org.apache.mina.filter.executor.ExecutorFilter"/>
+        <bean class="org.apache.mina.filter.logging.MDCInjectionFilter"/>
         <bean class="org.apache.mina.filter.codec.ProtocolCodecFilter">
           <constructor-arg>
             <bean class="org.apache.mina.filter.codec.textline.TextLineCodecFactory" />
@@ -55,6 +56,7 @@
     <property name="filters">
       <list>
         <bean class="org.apache.mina.filter.executor.ExecutorFilter"/>
+        <bean class="org.apache.mina.filter.logging.MDCInjectionFilter"/>
         <bean class="org.apache.mina.filter.ssl.SSLFilter">
           <constructor-arg ref="sslContext"/>
         </bean>