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

svn commit: r580762 - in /mina/trunk: core/src/main/java/org/apache/mina/common/ core/src/main/java/org/apache/mina/filter/codec/ core/src/main/java/org/apache/mina/filter/codec/textline/ core/src/main/java/org/apache/mina/filter/executor/ core/src/mai...

Author: trustin
Date: Sun Sep 30 11:33:00 2007
New Revision: 580762

URL: http://svn.apache.org/viewvc?rev=580762&view=rev
Log:
Resolved issue: DIRMINA-447 (Allow adding more than one IoFilters of the same type)
* Added AttributeKey for fast attribute matching
* Certain filters can be added more than once now, but not the same instance twice


Added:
    mina/trunk/core/src/main/java/org/apache/mina/common/AttributeKey.java   (with props)
Modified:
    mina/trunk/core/src/main/java/org/apache/mina/common/DefaultIoFilterChain.java
    mina/trunk/core/src/main/java/org/apache/mina/common/IoSessionLogger.java
    mina/trunk/core/src/main/java/org/apache/mina/filter/codec/CumulativeProtocolDecoder.java
    mina/trunk/core/src/main/java/org/apache/mina/filter/codec/ProtocolCodecFilter.java
    mina/trunk/core/src/main/java/org/apache/mina/filter/codec/textline/TextLineDecoder.java
    mina/trunk/core/src/main/java/org/apache/mina/filter/codec/textline/TextLineEncoder.java
    mina/trunk/core/src/main/java/org/apache/mina/filter/executor/ExecutorFilter.java
    mina/trunk/core/src/main/java/org/apache/mina/filter/logging/MdcInjectionFilter.java
    mina/trunk/core/src/main/java/org/apache/mina/filter/reqres/RequestResponseFilter.java
    mina/trunk/core/src/main/java/org/apache/mina/filter/ssl/SslFilter.java
    mina/trunk/core/src/main/java/org/apache/mina/filter/stream/StreamWriteFilter.java
    mina/trunk/core/src/main/java/org/apache/mina/handler/multiton/SingleSessionIoHandlerDelegate.java
    mina/trunk/core/src/main/java/org/apache/mina/handler/stream/StreamIoHandler.java
    mina/trunk/core/src/main/java/org/apache/mina/management/StatCollector.java
    mina/trunk/filter-codec-http/src/main/java/org/apache/mina/filter/codec/http/HttpResponseDecoder.java
    mina/trunk/filter-compression/src/main/java/org/apache/mina/filter/compression/CompressionFilter.java
    mina/trunk/protocol-http-client/src/main/java/org/apache/mina/protocol/http/client/HttpIoHandler.java

Added: mina/trunk/core/src/main/java/org/apache/mina/common/AttributeKey.java
URL: http://svn.apache.org/viewvc/mina/trunk/core/src/main/java/org/apache/mina/common/AttributeKey.java?rev=580762&view=auto
==============================================================================
--- mina/trunk/core/src/main/java/org/apache/mina/common/AttributeKey.java (added)
+++ mina/trunk/core/src/main/java/org/apache/mina/common/AttributeKey.java Sun Sep 30 11:33:00 2007
@@ -0,0 +1,44 @@
+/*
+ *  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.mina.common;
+
+/**
+ * A key that makes its parent {@link Map} or session attribute to search
+ * fast while being debug-friendly by providing the spring representation.
+ *
+ * @author The Apache Directory Project (mina-dev@directory.apache.org)
+ * @version $Rev$, $Date$
+ */
+public final class AttributeKey {
+    private final String name;
+    
+    /**
+     * Creates a new instance.
+     */
+    public AttributeKey(Class<?> source, String name) {
+        this.name = source.getName() + '.' + String.valueOf(name) + '@' +
+                Integer.toHexString(System.identityHashCode(this));
+    }
+    
+    @Override
+    public String toString() {
+        return name;
+    }
+}

Propchange: mina/trunk/core/src/main/java/org/apache/mina/common/AttributeKey.java
------------------------------------------------------------------------------
    svn:eol-style = native

Propchange: mina/trunk/core/src/main/java/org/apache/mina/common/AttributeKey.java
------------------------------------------------------------------------------
    svn:keywords = Rev Date

Modified: mina/trunk/core/src/main/java/org/apache/mina/common/DefaultIoFilterChain.java
URL: http://svn.apache.org/viewvc/mina/trunk/core/src/main/java/org/apache/mina/common/DefaultIoFilterChain.java?rev=580762&r1=580761&r2=580762&view=diff
==============================================================================
--- mina/trunk/core/src/main/java/org/apache/mina/common/DefaultIoFilterChain.java (original)
+++ mina/trunk/core/src/main/java/org/apache/mina/common/DefaultIoFilterChain.java Sun Sep 30 11:33:00 2007
@@ -42,9 +42,7 @@
      * attribute and notifies the future when {@link #fireSessionOpened()}
      * or {@link #fireExceptionCaught(Throwable)} is invoked
      */
-    public static final String CONNECT_FUTURE = DefaultIoFilterChain.class
-            .getName()
-            + ".connectFuture";
+    public static final AttributeKey CONNECT_FUTURE = new AttributeKey(DefaultIoFilterChain.class, "connectFuture");
 
     private final AbstractIoSession session;
 

Modified: mina/trunk/core/src/main/java/org/apache/mina/common/IoSessionLogger.java
URL: http://svn.apache.org/viewvc/mina/trunk/core/src/main/java/org/apache/mina/common/IoSessionLogger.java?rev=580762&r1=580761&r2=580762&view=diff
==============================================================================
--- mina/trunk/core/src/main/java/org/apache/mina/common/IoSessionLogger.java (original)
+++ mina/trunk/core/src/main/java/org/apache/mina/common/IoSessionLogger.java Sun Sep 30 11:33:00 2007
@@ -38,12 +38,12 @@
     /**
      * Session attribute key: prefix string
      */
-    public static final String PREFIX = IoSessionLogger.class.getName() + ".prefix";
+    public static final AttributeKey PREFIX = new AttributeKey(IoSessionLogger.class, "prefix");
 
     /**
      * Session attribute key: {@link Logger}
      */
-    public static final String LOGGER = IoSessionLogger.class.getName() + ".logger";
+    public static final AttributeKey LOGGER = new AttributeKey(IoSessionLogger.class, "logger");
 
     private static Class<? extends IoHandler> getClass(IoSession session) {
         return session.getHandler().getClass();

Modified: mina/trunk/core/src/main/java/org/apache/mina/filter/codec/CumulativeProtocolDecoder.java
URL: http://svn.apache.org/viewvc/mina/trunk/core/src/main/java/org/apache/mina/filter/codec/CumulativeProtocolDecoder.java?rev=580762&r1=580761&r2=580762&view=diff
==============================================================================
--- mina/trunk/core/src/main/java/org/apache/mina/filter/codec/CumulativeProtocolDecoder.java (original)
+++ mina/trunk/core/src/main/java/org/apache/mina/filter/codec/CumulativeProtocolDecoder.java Sun Sep 30 11:33:00 2007
@@ -20,6 +20,7 @@
 package org.apache.mina.filter.codec;
 
 import org.apache.mina.common.ByteBuffer;
+import org.apache.mina.common.AttributeKey;
 import org.apache.mina.common.IoSession;
 
 /**
@@ -95,9 +96,7 @@
  */
 public abstract class CumulativeProtocolDecoder extends ProtocolDecoderAdapter {
 
-    private static final String BUFFER = CumulativeProtocolDecoder.class
-            .getName()
-            + ".Buffer";
+    private final AttributeKey BUFFER = new AttributeKey(getClass(), "buffer");
 
     /**
      * Creates a new instance.

Modified: mina/trunk/core/src/main/java/org/apache/mina/filter/codec/ProtocolCodecFilter.java
URL: http://svn.apache.org/viewvc/mina/trunk/core/src/main/java/org/apache/mina/filter/codec/ProtocolCodecFilter.java?rev=580762&r1=580761&r2=580762&view=diff
==============================================================================
--- mina/trunk/core/src/main/java/org/apache/mina/filter/codec/ProtocolCodecFilter.java (original)
+++ mina/trunk/core/src/main/java/org/apache/mina/filter/codec/ProtocolCodecFilter.java Sun Sep 30 11:33:00 2007
@@ -25,6 +25,7 @@
 import org.apache.mina.common.ByteBuffer;
 import org.apache.mina.common.DefaultWriteFuture;
 import org.apache.mina.common.DefaultWriteRequest;
+import org.apache.mina.common.AttributeKey;
 import org.apache.mina.common.IoFilter;
 import org.apache.mina.common.IoFilterAdapter;
 import org.apache.mina.common.IoFilterChain;
@@ -43,19 +44,13 @@
  * @version $Rev$, $Date$
  */
 public class ProtocolCodecFilter extends IoFilterAdapter {
-    public static final String ENCODER = ProtocolCodecFilter.class.getName()
-            + ".encoder";
-
-    public static final String DECODER = ProtocolCodecFilter.class.getName()
-            + ".decoder";
-
-    private static final String DECODER_OUT = ProtocolCodecFilter.class.getName()
-            + ".decoderOut";
 
     private static final Class<?>[] EMPTY_PARAMS = new Class[0];
-
     private static final ByteBuffer EMPTY_BUFFER = ByteBuffer.wrap(new byte[0]);
 
+    private final AttributeKey ENCODER = new AttributeKey(getClass(), "encoder");
+    private final AttributeKey DECODER = new AttributeKey(getClass(), "decoder");
+    private final AttributeKey DECODER_OUT = new AttributeKey(getClass(), "decoderOut");
     private final ProtocolCodecFactory factory;
 
     public ProtocolCodecFilter(ProtocolCodecFactory factory) {
@@ -125,14 +120,13 @@
             }
         };
     }
-
-    @Override
-    public void onPreAdd(IoFilterChain parent, String name,
-            NextFilter nextFilter) throws Exception {
-        if (parent.contains(ProtocolCodecFilter.class)) {
-            throw new IllegalStateException(
-                    "A filter chain cannot contain more than one ProtocolCodecFilter.");
-        }
+    
+    public ProtocolEncoder getEncoder(IoSession session) {
+        return (ProtocolEncoder) session.getAttribute(ENCODER);
+    }
+    
+    public ProtocolDecoder getDecoder(IoSession session) {
+        return (ProtocolDecoder) session.getAttribute(DECODER);
     }
 
     @Override
@@ -152,7 +146,7 @@
         }
 
         ByteBuffer in = (ByteBuffer) message;
-        ProtocolDecoder decoder = getDecoder(session);
+        ProtocolDecoder decoder = getDecoder0(session);
         ProtocolDecoderOutput decoderOut = getDecoderOut(session, nextFilter);
 
         try {
@@ -198,7 +192,7 @@
             return;
         }
 
-        ProtocolEncoder encoder = getEncoder(session);
+        ProtocolEncoder encoder = getEncoder0(session);
         ProtocolEncoderOutputImpl encoderOut = getEncoderOut(session,
                 nextFilter, writeRequest);
 
@@ -222,7 +216,7 @@
     public void sessionClosed(NextFilter nextFilter, IoSession session)
             throws Exception {
         // Call finishDecode() first when a connection is closed.
-        ProtocolDecoder decoder = getDecoder(session);
+        ProtocolDecoder decoder = getDecoder0(session);
         ProtocolDecoderOutput decoderOut = getDecoderOut(session, nextFilter);
         try {
             decoder.finishDecode(session, decoderOut);
@@ -245,7 +239,7 @@
         nextFilter.sessionClosed(session);
     }
 
-    private ProtocolEncoder getEncoder(IoSession session) throws Exception {
+    private ProtocolEncoder getEncoder0(IoSession session) throws Exception {
         ProtocolEncoder encoder = (ProtocolEncoder) session
                 .getAttribute(ENCODER);
         if (encoder == null) {
@@ -260,7 +254,7 @@
         return new ProtocolEncoderOutputImpl(session, nextFilter, writeRequest);
     }
 
-    private ProtocolDecoder getDecoder(IoSession session) throws Exception {
+    private ProtocolDecoder getDecoder0(IoSession session) throws Exception {
         ProtocolDecoder decoder = (ProtocolDecoder) session
                 .getAttribute(DECODER);
         if (decoder == null) {

Modified: mina/trunk/core/src/main/java/org/apache/mina/filter/codec/textline/TextLineDecoder.java
URL: http://svn.apache.org/viewvc/mina/trunk/core/src/main/java/org/apache/mina/filter/codec/textline/TextLineDecoder.java?rev=580762&r1=580761&r2=580762&view=diff
==============================================================================
--- mina/trunk/core/src/main/java/org/apache/mina/filter/codec/textline/TextLineDecoder.java (original)
+++ mina/trunk/core/src/main/java/org/apache/mina/filter/codec/textline/TextLineDecoder.java Sun Sep 30 11:33:00 2007
@@ -25,6 +25,7 @@
 
 import org.apache.mina.common.BufferDataException;
 import org.apache.mina.common.ByteBuffer;
+import org.apache.mina.common.AttributeKey;
 import org.apache.mina.common.IoSession;
 import org.apache.mina.filter.codec.ProtocolDecoder;
 import org.apache.mina.filter.codec.ProtocolDecoderOutput;
@@ -36,8 +37,7 @@
  * @version $Rev$, $Date$,
  */
 public class TextLineDecoder implements ProtocolDecoder {
-    private static final String CONTEXT = TextLineDecoder.class.getName()
-            + ".context";
+    private final AttributeKey CONTEXT = new AttributeKey(getClass(), "context");
 
     private final Charset charset;
 

Modified: mina/trunk/core/src/main/java/org/apache/mina/filter/codec/textline/TextLineEncoder.java
URL: http://svn.apache.org/viewvc/mina/trunk/core/src/main/java/org/apache/mina/filter/codec/textline/TextLineEncoder.java?rev=580762&r1=580761&r2=580762&view=diff
==============================================================================
--- mina/trunk/core/src/main/java/org/apache/mina/filter/codec/textline/TextLineEncoder.java (original)
+++ mina/trunk/core/src/main/java/org/apache/mina/filter/codec/textline/TextLineEncoder.java Sun Sep 30 11:33:00 2007
@@ -23,6 +23,7 @@
 import java.nio.charset.CharsetEncoder;
 
 import org.apache.mina.common.ByteBuffer;
+import org.apache.mina.common.AttributeKey;
 import org.apache.mina.common.IoSession;
 import org.apache.mina.filter.codec.ProtocolEncoder;
 import org.apache.mina.filter.codec.ProtocolEncoderAdapter;
@@ -36,8 +37,7 @@
  * @version $Rev$, $Date$,
  */
 public class TextLineEncoder extends ProtocolEncoderAdapter {
-    private static final String ENCODER = TextLineEncoder.class.getName()
-            + ".encoder";
+    private final AttributeKey ENCODER = new AttributeKey(getClass(), "encoder");
 
     private final Charset charset;
 

Modified: mina/trunk/core/src/main/java/org/apache/mina/filter/executor/ExecutorFilter.java
URL: http://svn.apache.org/viewvc/mina/trunk/core/src/main/java/org/apache/mina/filter/executor/ExecutorFilter.java?rev=580762&r1=580761&r2=580762&view=diff
==============================================================================
--- mina/trunk/core/src/main/java/org/apache/mina/filter/executor/ExecutorFilter.java (original)
+++ mina/trunk/core/src/main/java/org/apache/mina/filter/executor/ExecutorFilter.java Sun Sep 30 11:33:00 2007
@@ -23,6 +23,7 @@
 import java.util.Queue;
 import java.util.concurrent.Executor;
 
+import org.apache.mina.common.AttributeKey;
 import org.apache.mina.common.IoEventType;
 import org.apache.mina.common.IoFilterChain;
 import org.apache.mina.common.IoFilterEvent;
@@ -54,6 +55,7 @@
  * @version $Rev: 350169 $, $Date: 2005-12-01 00:17:41 -0500 (Thu, 01 Dec 2005) $
  */
 public class ExecutorFilter extends AbstractExecutorFilter {
+    private final AttributeKey BUFFER = new AttributeKey(getClass(), "buffer");
     private final Logger logger = LoggerFactory.getLogger(getClass());
 
     // added a default constructor for IoC containers that need one
@@ -84,7 +86,7 @@
     @Override
     protected void fireEvent(IoFilterEvent event) {
         IoSession session = event.getSession();
-        SessionBuffer buf = SessionBuffer.getSessionBuffer(session);
+        SessionBuffer buf = getSessionBuffer(session);
 
         boolean execute;
         synchronized (buf.eventQueue) {
@@ -106,22 +108,19 @@
             getExecutor().execute(new ProcessEventsRunnable(buf));
         }
     }
-
-    private static class SessionBuffer {
-        private static final String KEY = SessionBuffer.class.getName()
-                + ".KEY";
-
-        private static SessionBuffer getSessionBuffer(IoSession session) {
-            synchronized (session) {
-                SessionBuffer buf = (SessionBuffer) session.getAttribute(KEY);
-                if (buf == null) {
-                    buf = new SessionBuffer(session);
-                    session.setAttribute(KEY, buf);
-                }
-                return buf;
+    
+    private SessionBuffer getSessionBuffer(IoSession session) {
+        synchronized (session) {
+            SessionBuffer buf = (SessionBuffer) session.getAttribute(BUFFER);
+            if (buf == null) {
+                buf = new SessionBuffer(session);
+                session.setAttribute(BUFFER, buf);
             }
+            return buf;
         }
+    }
 
+    private static class SessionBuffer {
         private final IoSession session;
 
         private final Queue<IoFilterEvent> eventQueue = new LinkedList<IoFilterEvent>();

Modified: mina/trunk/core/src/main/java/org/apache/mina/filter/logging/MdcInjectionFilter.java
URL: http://svn.apache.org/viewvc/mina/trunk/core/src/main/java/org/apache/mina/filter/logging/MdcInjectionFilter.java?rev=580762&r1=580761&r2=580762&view=diff
==============================================================================
--- mina/trunk/core/src/main/java/org/apache/mina/filter/logging/MdcInjectionFilter.java (original)
+++ mina/trunk/core/src/main/java/org/apache/mina/filter/logging/MdcInjectionFilter.java Sun Sep 30 11:33:00 2007
@@ -4,6 +4,7 @@
 import java.util.HashMap;
 import java.util.Map;
 
+import org.apache.mina.common.AttributeKey;
 import org.apache.mina.common.IoFilterEvent;
 import org.apache.mina.common.IoSession;
 import org.apache.mina.filter.util.WrappingFilter;
@@ -47,7 +48,7 @@
 public class MdcInjectionFilter extends WrappingFilter {
 
     /** key used for storing the context map in the IoSession */
-    private static final String CONTEXT_KEY = MdcInjectionFilter.class + ".CONTEXT_KEY";
+    private static final AttributeKey CONTEXT_KEY = new AttributeKey(MdcInjectionFilter.class, "context");
 
     private ThreadLocal<Integer> callDepth = new ThreadLocal<Integer>() {
         @Override

Modified: mina/trunk/core/src/main/java/org/apache/mina/filter/reqres/RequestResponseFilter.java
URL: http://svn.apache.org/viewvc/mina/trunk/core/src/main/java/org/apache/mina/filter/reqres/RequestResponseFilter.java?rev=580762&r1=580761&r2=580762&view=diff
==============================================================================
--- mina/trunk/core/src/main/java/org/apache/mina/filter/reqres/RequestResponseFilter.java (original)
+++ mina/trunk/core/src/main/java/org/apache/mina/filter/reqres/RequestResponseFilter.java Sun Sep 30 11:33:00 2007
@@ -31,6 +31,7 @@
 import java.util.concurrent.ScheduledFuture;
 import java.util.concurrent.TimeUnit;
 
+import org.apache.mina.common.AttributeKey;
 import org.apache.mina.common.IoFilterChain;
 import org.apache.mina.common.IoSession;
 import org.apache.mina.common.IoSessionLogger;
@@ -44,20 +45,11 @@
  */
 public class RequestResponseFilter extends WriteRequestFilter {
 
-    private static final String RESPONSE_INSPECTOR = RequestResponseFilter.class
-            .getName()
-            + ".responseInspector";
-
-    private static final String REQUEST_STORE = RequestResponseFilter.class
-            .getName()
-            + ".requestStore";
-
-    private static final String UNRESPONDED_REQUEST_STORE = RequestResponseFilter.class
-            .getName()
-            + ".unrespondedRequestStore";
+    private final AttributeKey RESPONSE_INSPECTOR = new AttributeKey(getClass(), "responseInspector");
+    private final AttributeKey REQUEST_STORE = new AttributeKey(getClass(), "requestStore");
+    private final AttributeKey UNRESPONDED_REQUEST_STORE = new AttributeKey(getClass(), "unrespondedRequestStore");
 
     private final ResponseInspectorFactory responseInspectorFactory;
-
     private final ScheduledExecutorService timeoutScheduler;
 
     public RequestResponseFilter(final ResponseInspector responseInspector,

Modified: mina/trunk/core/src/main/java/org/apache/mina/filter/ssl/SslFilter.java
URL: http://svn.apache.org/viewvc/mina/trunk/core/src/main/java/org/apache/mina/filter/ssl/SslFilter.java?rev=580762&r1=580761&r2=580762&view=diff
==============================================================================
--- mina/trunk/core/src/main/java/org/apache/mina/filter/ssl/SslFilter.java (original)
+++ mina/trunk/core/src/main/java/org/apache/mina/filter/ssl/SslFilter.java Sun Sep 30 11:33:00 2007
@@ -29,6 +29,7 @@
 
 import org.apache.mina.common.ByteBuffer;
 import org.apache.mina.common.DefaultWriteFuture;
+import org.apache.mina.common.AttributeKey;
 import org.apache.mina.common.IoFilterAdapter;
 import org.apache.mina.common.IoFilterChain;
 import org.apache.mina.common.IoFuture;
@@ -86,8 +87,7 @@
      * A session attribute key that stores underlying {@link SSLSession}
      * for each session.
      */
-    public static final String SSL_SESSION = SslFilter.class.getName()
-            + ".SSLSession";
+    public static final AttributeKey SSL_SESSION = new AttributeKey(SslFilter.class, "session");
 
     /**
      * A session attribute key that makes next one write request bypass
@@ -99,9 +99,7 @@
      * bypass this filter.  This is especially useful when you implement
      * StartTLS.
      */
-    public static final String DISABLE_ENCRYPTION_ONCE = SslFilter.class
-            .getName()
-            + ".DisableEncryptionOnce";
+    public static final AttributeKey DISABLE_ENCRYPTION_ONCE = new AttributeKey(SslFilter.class, "disableOnce");
 
     /**
      * A session attribute key that makes this filter to emit a
@@ -111,8 +109,7 @@
      * value. ({@link Boolean#TRUE} is preferred.)  By default, this filter
      * doesn't emit any events related with SSL session flow control.
      */
-    public static final String USE_NOTIFICATION = SslFilter.class.getName()
-            + ".UseNotification";
+    public static final AttributeKey USE_NOTIFICATION = new AttributeKey(SslFilter.class, "useNotification");
 
     /**
      * A session attribute key that should be set to an {@link InetSocketAddress}.
@@ -127,8 +124,7 @@
      *
      * @see SSLContext#createSSLEngine(String, int)
      */
-    public static final String PEER_ADDRESS = SslFilter.class.getName()
-            + ".PeerAddress";
+    public static final AttributeKey PEER_ADDRESS = new AttributeKey(SslFilter.class, "peerAddress");
 
     /**
      * A special message object which is emitted with a {@link IoHandler#messageReceived(IoSession, Object)}
@@ -146,11 +142,8 @@
     public static final SslFilterMessage SESSION_UNSECURED = new SslFilterMessage(
             "SESSION_UNSECURED");
 
-    private static final String NEXT_FILTER = SslFilter.class.getName()
-            + ".NextFilter";
-
-    private static final String SSL_HANDLER = SslFilter.class.getName()
-            + ".SSLHandler";
+    private static final AttributeKey NEXT_FILTER = new AttributeKey(SslFilter.class, "nextFilter");
+    private static final AttributeKey SSL_HANDLER = new AttributeKey(SslFilter.class, "handler");
 
     // SSL Context
     private final SSLContext sslContext;
@@ -353,7 +346,7 @@
             NextFilter nextFilter) throws SSLException {
         if (parent.contains(SslFilter.class)) {
             throw new IllegalStateException(
-                    "A filter chain cannot contain more than one SSLFilter.");
+                    "Only one " + SslFilter.class.getName() + " is permitted.");
         }
 
         IoSession session = parent.getSession();

Modified: mina/trunk/core/src/main/java/org/apache/mina/filter/stream/StreamWriteFilter.java
URL: http://svn.apache.org/viewvc/mina/trunk/core/src/main/java/org/apache/mina/filter/stream/StreamWriteFilter.java?rev=580762&r1=580761&r2=580762&view=diff
==============================================================================
--- mina/trunk/core/src/main/java/org/apache/mina/filter/stream/StreamWriteFilter.java (original)
+++ mina/trunk/core/src/main/java/org/apache/mina/filter/stream/StreamWriteFilter.java Sun Sep 30 11:33:00 2007
@@ -26,7 +26,9 @@
 
 import org.apache.mina.common.ByteBuffer;
 import org.apache.mina.common.DefaultWriteRequest;
+import org.apache.mina.common.AttributeKey;
 import org.apache.mina.common.IoFilterAdapter;
+import org.apache.mina.common.IoFilterChain;
 import org.apache.mina.common.IoSession;
 import org.apache.mina.common.WriteRequest;
 
@@ -64,19 +66,21 @@
     /**
      * The attribute name used when binding the {@link InputStream} to the session.
      */
-    public static final String CURRENT_STREAM = StreamWriteFilter.class
-            .getName()
-            + ".stream";
+    public static final AttributeKey CURRENT_STREAM = new AttributeKey(StreamWriteFilter.class, "stream");
 
-    protected static final String WRITE_REQUEST_QUEUE = StreamWriteFilter.class
-            .getName()
-            + ".queue";
-
-    protected static final String CURRENT_WRITE_REQUEST = StreamWriteFilter.class
-            .getName()
-            + ".writeRequest";
+    static final AttributeKey WRITE_REQUEST_QUEUE = new AttributeKey(StreamWriteFilter.class, "queue");
+    static final AttributeKey CURRENT_WRITE_REQUEST = new AttributeKey(StreamWriteFilter.class, "writeRequest");
 
     private int writeBufferSize = DEFAULT_STREAM_BUFFER_SIZE;
+
+    @Override
+    public void onPreAdd(IoFilterChain parent, String name,
+            NextFilter nextFilter) throws Exception {
+        if (parent.contains(StreamWriteFilter.class)) {
+            throw new IllegalStateException(
+                    "Only one " + StreamWriteFilter.class.getName() + " is permitted.");
+        }
+    }
 
     @Override
     public void filterWrite(NextFilter nextFilter, IoSession session,

Modified: mina/trunk/core/src/main/java/org/apache/mina/handler/multiton/SingleSessionIoHandlerDelegate.java
URL: http://svn.apache.org/viewvc/mina/trunk/core/src/main/java/org/apache/mina/handler/multiton/SingleSessionIoHandlerDelegate.java?rev=580762&r1=580761&r2=580762&view=diff
==============================================================================
--- mina/trunk/core/src/main/java/org/apache/mina/handler/multiton/SingleSessionIoHandlerDelegate.java (original)
+++ mina/trunk/core/src/main/java/org/apache/mina/handler/multiton/SingleSessionIoHandlerDelegate.java Sun Sep 30 11:33:00 2007
@@ -19,6 +19,7 @@
  */
 package org.apache.mina.handler.multiton;
 
+import org.apache.mina.common.AttributeKey;
 import org.apache.mina.common.IdleStatus;
 import org.apache.mina.common.IoHandler;
 import org.apache.mina.common.IoSession;
@@ -37,9 +38,7 @@
      * The key used to store the {@link SingleSessionIoHandler} as a session
      * attribute.
      */
-    public static final String HANDLER = SingleSessionIoHandlerDelegate.class
-            .getName()
-            + ".handler";
+    public static final AttributeKey HANDLER = new AttributeKey(SingleSessionIoHandlerDelegate.class, "handler");
 
     /**
      * The {@link SingleSessionIoHandlerFactory} used to create new

Modified: mina/trunk/core/src/main/java/org/apache/mina/handler/stream/StreamIoHandler.java
URL: http://svn.apache.org/viewvc/mina/trunk/core/src/main/java/org/apache/mina/handler/stream/StreamIoHandler.java?rev=580762&r1=580761&r2=580762&view=diff
==============================================================================
--- mina/trunk/core/src/main/java/org/apache/mina/handler/stream/StreamIoHandler.java (original)
+++ mina/trunk/core/src/main/java/org/apache/mina/handler/stream/StreamIoHandler.java Sun Sep 30 11:33:00 2007
@@ -25,6 +25,7 @@
 import java.net.SocketTimeoutException;
 
 import org.apache.mina.common.ByteBuffer;
+import org.apache.mina.common.AttributeKey;
 import org.apache.mina.common.IdleStatus;
 import org.apache.mina.common.IoHandler;
 import org.apache.mina.common.IoHandlerAdapter;
@@ -43,11 +44,8 @@
  * @version $Rev$, $Date$
  */
 public abstract class StreamIoHandler extends IoHandlerAdapter {
-    private static final String KEY_IN = StreamIoHandler.class.getName()
-            + ".in";
-
-    private static final String KEY_OUT = StreamIoHandler.class.getName()
-            + ".out";
+    private static final AttributeKey KEY_IN = new AttributeKey(StreamIoHandler.class, "in");
+    private static final AttributeKey KEY_OUT = new AttributeKey(StreamIoHandler.class, "out");
 
     private int readTimeout;
 

Modified: mina/trunk/core/src/main/java/org/apache/mina/management/StatCollector.java
URL: http://svn.apache.org/viewvc/mina/trunk/core/src/main/java/org/apache/mina/management/StatCollector.java?rev=580762&r1=580761&r2=580762&view=diff
==============================================================================
--- mina/trunk/core/src/main/java/org/apache/mina/management/StatCollector.java (original)
+++ mina/trunk/core/src/main/java/org/apache/mina/management/StatCollector.java Sun Sep 30 11:33:00 2007
@@ -23,6 +23,7 @@
 import java.util.concurrent.ConcurrentLinkedQueue;
 import java.util.concurrent.atomic.AtomicLong;
 
+import org.apache.mina.common.AttributeKey;
 import org.apache.mina.common.IoService;
 import org.apache.mina.common.IoServiceListener;
 import org.apache.mina.common.IoSession;
@@ -49,7 +50,7 @@
     /**
      * The session attribute key for {@link IoSessionStat}.
      */
-    public static final String KEY = StatCollector.class.getName() + ".stat";
+    public static final AttributeKey KEY = new AttributeKey(StatCollector.class, "stat");
 
     /**
      * @noinspection StaticNonFinalField

Modified: mina/trunk/filter-codec-http/src/main/java/org/apache/mina/filter/codec/http/HttpResponseDecoder.java
URL: http://svn.apache.org/viewvc/mina/trunk/filter-codec-http/src/main/java/org/apache/mina/filter/codec/http/HttpResponseDecoder.java?rev=580762&r1=580761&r2=580762&view=diff
==============================================================================
--- mina/trunk/filter-codec-http/src/main/java/org/apache/mina/filter/codec/http/HttpResponseDecoder.java (original)
+++ mina/trunk/filter-codec-http/src/main/java/org/apache/mina/filter/codec/http/HttpResponseDecoder.java Sun Sep 30 11:33:00 2007
@@ -20,6 +20,7 @@
 package org.apache.mina.filter.codec.http;
 
 import org.apache.mina.common.ByteBuffer;
+import org.apache.mina.common.AttributeKey;
 import org.apache.mina.common.IoSession;
 import org.apache.mina.filter.codec.CumulativeProtocolDecoder;
 import org.apache.mina.filter.codec.ProtocolDecoderOutput;
@@ -32,84 +33,88 @@
  */
 public class HttpResponseDecoder extends CumulativeProtocolDecoder {
 
-    public final static String CURRENT_RESPONSE = "CURRENT_RESPONSE";
+    private final AttributeKey CURRENT_RESPONSE =
+        new AttributeKey(getClass(), "currentResponse");
 
     private HttpDecoder httpDecoder = new HttpDecoder();
-
+    
     protected boolean doDecode(IoSession ioSession, ByteBuffer in,
             ProtocolDecoderOutput out) throws Exception {
 
-        HttpResponseMessage response = (HttpResponseMessage) ioSession
-                .getAttribute(CURRENT_RESPONSE);
+        HttpResponseMessage response = (HttpResponseMessage) ioSession.getAttribute(CURRENT_RESPONSE);
         if (response == null) {
             response = new HttpResponseMessage();
             ioSession.setAttribute(CURRENT_RESPONSE, response);
         }
 
-        //Test if we need the response...
-        if (response.getState() == HttpResponseMessage.STATE_START) {
-
-            if (!processStatus(response, in)) {
-                return false;
-            }
-
-            //Handle HTTP/1.1 100 Continue
-            if (response.getStatusCode() == 100) {
-                response.setState(HttpResponseMessage.STATE_STATUS_CONTINUE);
-            } else {
-                response.setState(HttpResponseMessage.STATE_STATUS_READ);
-            }
-        }
-
-        //If we are in a 100 Continue, read until we get the real header
-        if (response.getState() == HttpResponseMessage.STATE_STATUS_CONTINUE) {
-            //Continue reading until we get a blank line
-            while (true) {
-                String line = httpDecoder.decodeLine(in);
-
-                //Check if the entire response has been read
-                if (line == null)
+        try {
+            // Test if we need the response...
+            if (response.getState() == HttpResponseMessage.STATE_START) {
+    
+                if (!processStatus(response, in)) {
                     return false;
-
-                //Check if the entire response headers have been read
-                if (line.length() == 0) {
+                }
+    
+                //Handle HTTP/1.1 100 Continue
+                if (response.getStatusCode() == 100) {
+                    response.setState(HttpResponseMessage.STATE_STATUS_CONTINUE);
+                } else {
                     response.setState(HttpResponseMessage.STATE_STATUS_READ);
-
-                    //The next line should be a header
-                    if (!processStatus(response, in)) {
+                }
+            }
+    
+            //If we are in a 100 Continue, read until we get the real header
+            if (response.getState() == HttpResponseMessage.STATE_STATUS_CONTINUE) {
+                //Continue reading until we get a blank line
+                while (true) {
+                    String line = httpDecoder.decodeLine(in);
+    
+                    //Check if the entire response has been read
+                    if (line == null)
                         return false;
+    
+                    //Check if the entire response headers have been read
+                    if (line.length() == 0) {
+                        response.setState(HttpResponseMessage.STATE_STATUS_READ);
+    
+                        //The next line should be a header
+                        if (!processStatus(response, in)) {
+                            return false;
+                        }
+                        break;
                     }
-                    break;
                 }
             }
+    
+            //Are we reading headers?
+            if (response.getState() == HttpResponseMessage.STATE_STATUS_READ) {
+                if (processHeaders(response, in) == false)
+                    return false;
+            }
+    
+            //Are we reading content?
+            if (response.getState() == HttpResponseMessage.STATE_HEADERS_READ) {
+                if (processContent(response, in) == false)
+                    return false;
+            }
+    
+            //If we are chunked and we have read all the content, then read the footers if there are any
+            if (response.isChunked()
+                    && response.getState() == HttpResponseMessage.STATE_CONTENT_READ) {
+                if (processFooters(response, in) == false)
+                    return false;
+            }
+    
+            response.setState(HttpResponseMessage.STATE_FINISHED);
+    
+            out.write(response);
+    
+            ioSession.removeAttribute(CURRENT_RESPONSE);
+            return true;
+        } catch (Exception e) {
+            ioSession.removeAttribute(CURRENT_RESPONSE);
+            throw e;
         }
-
-        //Are we reading headers?
-        if (response.getState() == HttpResponseMessage.STATE_STATUS_READ) {
-            if (processHeaders(response, in) == false)
-                return false;
-        }
-
-        //Are we reading content?
-        if (response.getState() == HttpResponseMessage.STATE_HEADERS_READ) {
-            if (processContent(response, in) == false)
-                return false;
-        }
-
-        //If we are chunked and we have read all the content, then read the footers if there are any
-        if (response.isChunked()
-                && response.getState() == HttpResponseMessage.STATE_CONTENT_READ) {
-            if (processFooters(response, in) == false)
-                return false;
-        }
-
-        response.setState(HttpResponseMessage.STATE_FINISHED);
-
-        out.write(response);
-
-        ioSession.removeAttribute(CURRENT_RESPONSE);
-
-        return true;
     }
 
     private boolean processHeaders(HttpResponseMessage response, ByteBuffer in)
@@ -198,6 +203,12 @@
         response.setState(HttpResponseMessage.STATE_CONTENT_READ);
 
         return true;
+    }
+
+    @Override
+    public void finishDecode(IoSession session, ProtocolDecoderOutput out)
+            throws Exception {
+        session.removeAttribute(CURRENT_RESPONSE);
     }
 
     private boolean processStatus(HttpResponseMessage response, ByteBuffer in)

Modified: mina/trunk/filter-compression/src/main/java/org/apache/mina/filter/compression/CompressionFilter.java
URL: http://svn.apache.org/viewvc/mina/trunk/filter-compression/src/main/java/org/apache/mina/filter/compression/CompressionFilter.java?rev=580762&r1=580761&r2=580762&view=diff
==============================================================================
--- mina/trunk/filter-compression/src/main/java/org/apache/mina/filter/compression/CompressionFilter.java (original)
+++ mina/trunk/filter-compression/src/main/java/org/apache/mina/filter/compression/CompressionFilter.java Sun Sep 30 11:33:00 2007
@@ -22,6 +22,7 @@
 import java.io.IOException;
 
 import org.apache.mina.common.ByteBuffer;
+import org.apache.mina.common.AttributeKey;
 import org.apache.mina.common.IoFilter;
 import org.apache.mina.common.IoFilterChain;
 import org.apache.mina.common.IoSession;
@@ -81,21 +82,17 @@
     /**
      * A session attribute that stores the {@link Zlib} object used for compression.
      */
-    private static final String DEFLATER = CompressionFilter.class.getName()
-            + ".Deflater";
+    private final AttributeKey DEFLATER = new AttributeKey(getClass(), "deflater");
 
     /**
      * A session attribute that stores the {@link Zlib} object used for decompression.
      */
-    private static final String INFLATER = CompressionFilter.class.getName()
-            + ".Inflater";
+    private final AttributeKey INFLATER = new AttributeKey(getClass(), "inflater");
 
     /**
      * A flag that allows you to disable compression once.
      */
-    public static final String DISABLE_COMPRESSION_ONCE = CompressionFilter.class
-            .getName()
-            + ".DisableCompressionOnce";
+    public static final AttributeKey DISABLE_COMPRESSION_ONCE = new AttributeKey(CompressionFilter.class, "disableOnce"); 
 
     private boolean compressInbound = true;
 
@@ -197,8 +194,7 @@
             NextFilter nextFilter) throws Exception {
         if (parent.contains(CompressionFilter.class)) {
             throw new IllegalStateException(
-                    "A filter chain cannot contain more than"
-                            + " one Stream Compression filter.");
+                    "Only one " + CompressionFilter.class + " is permitted.");
         }
 
         Zlib deflater = new Zlib(compressionLevel, Zlib.MODE_DEFLATER);

Modified: mina/trunk/protocol-http-client/src/main/java/org/apache/mina/protocol/http/client/HttpIoHandler.java
URL: http://svn.apache.org/viewvc/mina/trunk/protocol-http-client/src/main/java/org/apache/mina/protocol/http/client/HttpIoHandler.java?rev=580762&r1=580761&r2=580762&view=diff
==============================================================================
--- mina/trunk/protocol-http-client/src/main/java/org/apache/mina/protocol/http/client/HttpIoHandler.java (original)
+++ mina/trunk/protocol-http-client/src/main/java/org/apache/mina/protocol/http/client/HttpIoHandler.java Sun Sep 30 11:33:00 2007
@@ -21,6 +21,7 @@
 
 import org.apache.mina.common.IoHandlerAdapter;
 import org.apache.mina.common.IoSession;
+import org.apache.mina.filter.codec.ProtocolCodecFilter;
 import org.apache.mina.filter.codec.http.HttpResponseDecoder;
 import org.apache.mina.filter.codec.http.HttpResponseMessage;
 
@@ -46,15 +47,19 @@
     @Override
     public void exceptionCaught(IoSession ioSession, Throwable throwable)
             throws Exception {
-        //Clean up if any in-proccess decoding was occurring
-        ioSession.removeAttribute(HttpResponseDecoder.CURRENT_RESPONSE);
+        cleanup(ioSession);
         callback.onException(throwable);
     }
 
     @Override
     public void sessionClosed(IoSession ioSession) throws Exception {
-        //Clean up if any in-proccess decoding was occurring
-        ioSession.removeAttribute(HttpResponseDecoder.CURRENT_RESPONSE);
+        cleanup(ioSession);
         callback.onClosed();
+    }
+
+    private void cleanup(IoSession ioSession) throws Exception {
+        // Clean up if any in-proccess decoding was occurring
+        ProtocolCodecFilter codecFilter = (ProtocolCodecFilter) ioSession.getFilterChain().get("protocolFilter");
+        ((HttpResponseDecoder) codecFilter.getDecoder(ioSession)).finishDecode(ioSession, null);
     }
 }