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/10/30 10:44:04 UTC

svn commit: r590006 - in /mina/trunk: core/src/main/java/org/apache/mina/common/ core/src/main/java/org/apache/mina/filter/codec/demux/ core/src/main/java/org/apache/mina/handler/demux/ example/src/main/java/org/apache/mina/example/httpserver/codec/ ex...

Author: trustin
Date: Tue Oct 30 02:44:02 2007
New Revision: 590006

URL: http://svn.apache.org/viewvc?rev=590006&view=rev
Log:
Resolved issue: DIRMINA-439 (DemuxingProtocolEncoder and DemuxingProtocolDecoder by refactoring DemuxingProtocolCodecFactory)
* Added DemuxingProtocolEncoder
* Added DemuxingProtocolDecoder
* Rewrote DemuxingProtocolCodecFactory by using DemuxingProtocolEncoder and Decoder
* Updated JavaDoc
* Moved UnknownMessageTypeException to org.apache.mina.common


Added:
    mina/trunk/core/src/main/java/org/apache/mina/common/UnknownMessageTypeException.java
      - copied, changed from r589979, mina/trunk/core/src/main/java/org/apache/mina/handler/demux/UnknownMessageTypeException.java
    mina/trunk/core/src/main/java/org/apache/mina/filter/codec/demux/DemuxingProtocolDecoder.java   (with props)
    mina/trunk/core/src/main/java/org/apache/mina/filter/codec/demux/DemuxingProtocolEncoder.java   (with props)
Removed:
    mina/trunk/core/src/main/java/org/apache/mina/handler/demux/UnknownMessageTypeException.java
Modified:
    mina/trunk/core/src/main/java/org/apache/mina/filter/codec/demux/DemuxingProtocolCodecFactory.java
    mina/trunk/core/src/main/java/org/apache/mina/filter/codec/demux/MessageDecoder.java
    mina/trunk/core/src/main/java/org/apache/mina/filter/codec/demux/MessageDecoderFactory.java
    mina/trunk/core/src/main/java/org/apache/mina/filter/codec/demux/MessageEncoder.java
    mina/trunk/core/src/main/java/org/apache/mina/filter/codec/demux/MessageEncoderFactory.java
    mina/trunk/core/src/main/java/org/apache/mina/handler/demux/DemuxingIoHandler.java
    mina/trunk/example/src/main/java/org/apache/mina/example/httpserver/codec/HttpResponseEncoder.java
    mina/trunk/example/src/main/java/org/apache/mina/example/httpserver/codec/HttpServerProtocolCodecFactory.java
    mina/trunk/example/src/main/java/org/apache/mina/example/sumup/codec/AbstractMessageEncoder.java
    mina/trunk/example/src/main/java/org/apache/mina/example/sumup/codec/AddMessageEncoder.java
    mina/trunk/example/src/main/java/org/apache/mina/example/sumup/codec/ResultMessageEncoder.java
    mina/trunk/example/src/main/java/org/apache/mina/example/sumup/codec/SumUpProtocolCodecFactory.java

Copied: mina/trunk/core/src/main/java/org/apache/mina/common/UnknownMessageTypeException.java (from r589979, mina/trunk/core/src/main/java/org/apache/mina/handler/demux/UnknownMessageTypeException.java)
URL: http://svn.apache.org/viewvc/mina/trunk/core/src/main/java/org/apache/mina/common/UnknownMessageTypeException.java?p2=mina/trunk/core/src/main/java/org/apache/mina/common/UnknownMessageTypeException.java&p1=mina/trunk/core/src/main/java/org/apache/mina/handler/demux/UnknownMessageTypeException.java&r1=589979&r2=590006&rev=590006&view=diff
==============================================================================
--- mina/trunk/core/src/main/java/org/apache/mina/handler/demux/UnknownMessageTypeException.java (original)
+++ mina/trunk/core/src/main/java/org/apache/mina/common/UnknownMessageTypeException.java Tue Oct 30 02:44:02 2007
@@ -17,14 +17,11 @@
  *  under the License.
  *
  */
-package org.apache.mina.handler.demux;
+package org.apache.mina.common;
+
 
 /**
- * An exception that is thrown when {@link DemuxingIoHandler}
- * cannot find any {@link MessageHandler}s associated with the specific
- * message type.  You have to use
- * {@link DemuxingIoHandler#addMessageHandler(Class, MessageHandler)}
- * to associate a message type and a message handler.
+ * An exception that is thrown when the type of the message cannot be determined.
  *
  * @author The Apache MINA Project (dev@mina.apache.org)
  * @version $Rev$, $Date$

Modified: mina/trunk/core/src/main/java/org/apache/mina/filter/codec/demux/DemuxingProtocolCodecFactory.java
URL: http://svn.apache.org/viewvc/mina/trunk/core/src/main/java/org/apache/mina/filter/codec/demux/DemuxingProtocolCodecFactory.java?rev=590006&r1=590005&r2=590006&view=diff
==============================================================================
--- mina/trunk/core/src/main/java/org/apache/mina/filter/codec/demux/DemuxingProtocolCodecFactory.java (original)
+++ mina/trunk/core/src/main/java/org/apache/mina/filter/codec/demux/DemuxingProtocolCodecFactory.java Tue Oct 30 02:44:02 2007
@@ -19,390 +19,59 @@
  */
 package org.apache.mina.filter.codec.demux;
 
-import java.util.IdentityHashMap;
-import java.util.Iterator;
-import java.util.Map;
-import java.util.Set;
-
-import org.apache.mina.common.IoBuffer;
-import org.apache.mina.common.IoSession;
-import org.apache.mina.filter.codec.CumulativeProtocolDecoder;
 import org.apache.mina.filter.codec.ProtocolCodecFactory;
 import org.apache.mina.filter.codec.ProtocolDecoder;
-import org.apache.mina.filter.codec.ProtocolDecoderException;
-import org.apache.mina.filter.codec.ProtocolDecoderOutput;
 import org.apache.mina.filter.codec.ProtocolEncoder;
-import org.apache.mina.filter.codec.ProtocolEncoderException;
-import org.apache.mina.filter.codec.ProtocolEncoderOutput;
-import org.apache.mina.util.IdentityHashSet;
 
 /**
- * A composite {@link ProtocolCodecFactory} that consists of multiple
- * {@link MessageEncoder}s and {@link MessageDecoder}s.
- * {@link ProtocolEncoder} and {@link ProtocolDecoder} this factory
- * returns demultiplex incoming messages and buffers to
- * appropriate {@link MessageEncoder}s and {@link MessageDecoder}s.
- *
- * <h2>Disposing resources acquired by {@link MessageEncoder} and {@link MessageDecoder}</h2>
+ * A convenience {@link ProtocolCodecFactory} that provides {@link DemuxingProtocolEncoder}
+ * and {@link DemuxingProtocolDecoder} as a pair.
  * <p>
- * Make your {@link MessageEncoder} and {@link MessageDecoder} to put all
- * resources that need to be released as a session attribute.  {@link #disposeCodecResources(IoSession)}
- * method will be invoked when a session is closed.  Override {@link #disposeCodecResources(IoSession)}
- * to release the resources you've put as an attribute.
- * <p>
- * We didn't provide any <tt>dispose</tt> method for {@link MessageEncoder} and {@link MessageDecoder}
- * because they can give you a big performance penalty in case you have a lot of
- * message types to handle.
+ * {@link DemuxingProtocolEncoder} and {@link DemuxingProtocolDecoder} demultiplex
+ * incoming messages and buffers to appropriate {@link MessageEncoder}s and 
+ * {@link MessageDecoder}s.
  *
  * @author The Apache MINA Project (dev@mina.apache.org)
  * @version $Rev$, $Date$
- *
- * @see MessageEncoder
- * @see MessageDecoder
  */
 public class DemuxingProtocolCodecFactory implements ProtocolCodecFactory {
-    private MessageDecoderFactory[] decoderFactories = new MessageDecoderFactory[0];
 
-    private MessageEncoderFactory<?>[] encoderFactories = new MessageEncoderFactory[0];
-
-    private static final Class<?>[] EMPTY_PARAMS = new Class[0];
+    private final DemuxingProtocolEncoder encoder = new DemuxingProtocolEncoder();
+    private final DemuxingProtocolDecoder decoder = new DemuxingProtocolDecoder();
 
     public DemuxingProtocolCodecFactory() {
     }
 
-    public void register(Class<?> encoderOrDecoderClass) {
-        if (encoderOrDecoderClass == null) {
-            throw new NullPointerException("encoderOrDecoderClass");
-        }
-
-        try {
-            encoderOrDecoderClass.getConstructor(EMPTY_PARAMS);
-        } catch (NoSuchMethodException e) {
-            throw new IllegalArgumentException(
-                    "The specifiec class doesn't have a public default constructor.");
-        }
-
-        boolean registered = false;
-        if (MessageEncoder.class.isAssignableFrom(encoderOrDecoderClass)) {
-            register(new DefaultConstructorMessageEncoderFactory(encoderOrDecoderClass));
-            registered = true;
-        }
-
-        if (MessageDecoder.class.isAssignableFrom(encoderOrDecoderClass)) {
-            register(new DefaultConstructorMessageDecoderFactory(
-                    encoderOrDecoderClass));
-            registered = true;
-        }
-
-        if (!registered) {
-            throw new IllegalArgumentException("Unregisterable type: "
-                    + encoderOrDecoderClass);
-        }
-    }
-
-    public <T> void register(MessageEncoder<T> encoder) {
-        register(new SingletonMessageEncoderFactory<T>(encoder));
-    }
-
-    public void register(MessageEncoderFactory<?> factory) {
-        if (factory == null) {
-            throw new NullPointerException("factory");
-        }
-        MessageEncoderFactory<?>[] encoderFactories = this.encoderFactories;
-        MessageEncoderFactory<?>[] newEncoderFactories = new MessageEncoderFactory[encoderFactories.length + 1];
-        System.arraycopy(encoderFactories, 0, newEncoderFactories, 0,
-                encoderFactories.length);
-        newEncoderFactories[encoderFactories.length] = factory;
-        this.encoderFactories = newEncoderFactories;
-    }
-
-    public void register(MessageDecoder decoder) {
-        register(new SingletonMessageDecoderFactory(decoder));
-    }
-
-    public void register(MessageDecoderFactory factory) {
-        if (factory == null) {
-            throw new NullPointerException("factory");
-        }
-        MessageDecoderFactory[] decoderFactories = this.decoderFactories;
-        MessageDecoderFactory[] newDecoderFactories = new MessageDecoderFactory[decoderFactories.length + 1];
-        System.arraycopy(decoderFactories, 0, newDecoderFactories, 0,
-                decoderFactories.length);
-        newDecoderFactories[decoderFactories.length] = factory;
-        this.decoderFactories = newDecoderFactories;
-    }
-
     public ProtocolEncoder getEncoder() throws Exception {
-        return new ProtocolEncoderImpl();
+        return encoder;
     }
 
     public ProtocolDecoder getDecoder() throws Exception {
-        return new ProtocolDecoderImpl();
-    }
-
-    /**
-     * Implement this method to release all resources acquired to perform
-     * encoding and decoding messages for the specified <tt>session</tt>.
-     * By default, this method does nothing.
-     *
-     * @param session the session that requires resource deallocation now
-     */
-    protected void disposeCodecResources(IoSession session) {
-        // Do nothing by default; let users implement it as they want.
-
-        // This statement is just to avoid compiler warning.  Please ignore.
-        session.getService();
+        return decoder;
     }
-
+    
     @SuppressWarnings("unchecked")
-    private class ProtocolEncoderImpl implements ProtocolEncoder {
-        private final Map<Class<?>, MessageEncoder> encoders =
-            new IdentityHashMap<Class<?>, MessageEncoder>();
-
-        private ProtocolEncoderImpl() throws Exception {
-            MessageEncoderFactory[] encoderFactories =
-                DemuxingProtocolCodecFactory.this.encoderFactories;
-            for (int i = encoderFactories.length - 1; i >= 0; i--) {
-                MessageEncoder encoder = encoderFactories[i].getEncoder();
-                Set<Class<?>> messageTypes = encoder.getMessageTypes();
-                if (messageTypes == null) {
-                    throw new IllegalStateException(encoder.getClass()
-                            .getName()
-                            + "#getMessageTypes() may not return null.");
-                }
-
-                Iterator<Class<?>> it = messageTypes.iterator();
-                while (it.hasNext()) {
-                    Class<?> type = it.next();
-                    encoders.put(type, encoder);
-                }
-            }
-        }
-
-        public void encode(IoSession session, Object message,
-                ProtocolEncoderOutput out) throws Exception {
-            Class<?> type = message.getClass();
-            MessageEncoder encoder = findEncoder(type);
-            if (encoder == null) {
-                throw new ProtocolEncoderException("Unexpected message type: "
-                        + type);
-            }
-
-            encoder.encode(session, message, out);
-        }
-
-        private MessageEncoder findEncoder(Class<?> type) {
-            MessageEncoder encoder = encoders.get(type);
-            if (encoder == null) {
-                encoder = findEncoder(type, new IdentityHashSet<Class<?>>());
-            }
-
-            return encoder;
-        }
-
-        private MessageEncoder findEncoder(Class<?> type,
-                Set<Class<?>> triedClasses) {
-            MessageEncoder encoder;
-
-            if (triedClasses.contains(type)) {
-                return null;
-            }
-            triedClasses.add(type);
-
-            encoder = encoders.get(type);
-            if (encoder == null) {
-                encoder = findEncoder(type, triedClasses);
-                if (encoder != null) {
-                    return encoder;
-                }
-
-                Class<?>[] interfaces = type.getInterfaces();
-                for (Class<?> element : interfaces) {
-                    encoder = findEncoder(element, triedClasses);
-                    if (encoder != null) {
-                        return encoder;
-                    }
-                }
-
-                return null;
-            } else {
-                return encoder;
-            }
-        }
-
-        public void dispose(IoSession session) throws Exception {
-            DemuxingProtocolCodecFactory.this.disposeCodecResources(session);
-        }
+    public void addMessageEncoder(Class<?> messageType, Class<? extends MessageEncoder> encoderClass) {
+        this.encoder.addMessageEncoder(messageType, encoderClass);
     }
 
-    private class ProtocolDecoderImpl extends CumulativeProtocolDecoder {
-        private final MessageDecoder[] decoders;
-
-        private MessageDecoder currentDecoder;
-
-        protected ProtocolDecoderImpl() throws Exception {
-            MessageDecoderFactory[] decoderFactories = DemuxingProtocolCodecFactory.this.decoderFactories;
-            decoders = new MessageDecoder[decoderFactories.length];
-            for (int i = decoderFactories.length - 1; i >= 0; i--) {
-                decoders[i] = decoderFactories[i].getDecoder();
-            }
-        }
-
-        @Override
-        protected boolean doDecode(IoSession session, IoBuffer in,
-                ProtocolDecoderOutput out) throws Exception {
-            if (currentDecoder == null) {
-                MessageDecoder[] decoders = this.decoders;
-                int undecodables = 0;
-                for (int i = decoders.length - 1; i >= 0; i--) {
-                    MessageDecoder decoder = decoders[i];
-                    int limit = in.limit();
-                    int pos = in.position();
-
-                    MessageDecoderResult result;
-                    try {
-                        result = decoder.decodable(session, in);
-                    } finally {
-                        in.position(pos);
-                        in.limit(limit);
-                    }
-
-                    if (result == MessageDecoder.OK) {
-                        currentDecoder = decoder;
-                        break;
-                    } else if (result == MessageDecoder.NOT_OK) {
-                        undecodables++;
-                    } else if (result != MessageDecoder.NEED_DATA) {
-                        throw new IllegalStateException(
-                                "Unexpected decode result (see your decodable()): "
-                                        + result);
-                    }
-                }
-
-                if (undecodables == decoders.length) {
-                    // Throw an exception if all decoders cannot decode data.
-                    String dump = in.getHexDump();
-                    in.position(in.limit()); // Skip data
-                    throw new ProtocolDecoderException(
-                            "No appropriate message decoder: " + dump);
-                }
-
-                if (currentDecoder == null) {
-                    // Decoder is not determined yet (i.e. we need more data)
-                    return false;
-                }
-            }
-
-            MessageDecoderResult result = currentDecoder.decode(session, in,
-                    out);
-            if (result == MessageDecoder.OK) {
-                currentDecoder = null;
-                return true;
-            } else if (result == MessageDecoder.NEED_DATA) {
-                return false;
-            } else if (result == MessageDecoder.NOT_OK) {
-                currentDecoder = null;
-                throw new ProtocolDecoderException(
-                        "Message decoder returned NOT_OK.");
-            } else {
-                currentDecoder = null;
-                throw new IllegalStateException(
-                        "Unexpected decode result (see your decode()): "
-                                + result);
-            }
-        }
-
-        @Override
-        public void finishDecode(IoSession session, ProtocolDecoderOutput out)
-                throws Exception {
-            if (currentDecoder == null) {
-                return;
-            }
-
-            currentDecoder.finishDecode(session, out);
-        }
-
-        @Override
-        public void dispose(IoSession session) throws Exception {
-            super.dispose(session);
-
-            // ProtocolEncoder.dispose() already called disposeCodec(),
-            // so there's nothing more we need to do.
-        }
+    public <T> void addMessageEncoder(Class<T> messageType, MessageEncoder<? super T> encoder) {
+        this.encoder.addMessageEncoder(messageType, encoder);
     }
 
-    private static class SingletonMessageEncoderFactory<T> implements
-            MessageEncoderFactory<T> {
-        private final MessageEncoder<T> encoder;
-
-        private SingletonMessageEncoderFactory(MessageEncoder<T> encoder) {
-            if (encoder == null) {
-                throw new NullPointerException("encoder");
-            }
-            this.encoder = encoder;
-        }
-
-        public MessageEncoder<T> getEncoder() {
-            return encoder;
-        }
+    public <T> void addMessageEncoder(Class<T> messageType, MessageEncoderFactory<? super T> factory) {
+        this.encoder.addMessageEncoder(messageType, factory);
     }
 
-    private static class SingletonMessageDecoderFactory implements
-            MessageDecoderFactory {
-        private final MessageDecoder decoder;
-
-        private SingletonMessageDecoderFactory(MessageDecoder decoder) {
-            if (decoder == null) {
-                throw new NullPointerException("decoder");
-            }
-            this.decoder = decoder;
-        }
-
-        public MessageDecoder getDecoder() {
-            return decoder;
-        }
+    public void addMessageDecoder(Class<? extends MessageDecoder> decoderClass) {
+        this.decoder.addMessageDecoder(decoderClass);
     }
 
-    @SuppressWarnings("unchecked")
-    private static class DefaultConstructorMessageEncoderFactory implements
-            MessageEncoderFactory {
-        private final Class encoderClass;
-
-        private DefaultConstructorMessageEncoderFactory(Class encoderClass) {
-            if (encoderClass == null) {
-                throw new NullPointerException("encoderClass");
-            }
-
-            if (!MessageEncoder.class.isAssignableFrom(encoderClass)) {
-                throw new IllegalArgumentException(
-                        "encoderClass is not assignable to MessageEncoder");
-            }
-            this.encoderClass = encoderClass;
-        }
-
-        public MessageEncoder getEncoder() throws Exception {
-            return (MessageEncoder) encoderClass.newInstance();
-        }
+    public void addMessageDecoder(MessageDecoder decoder) {
+        this.decoder.addMessageDecoder(decoder);
     }
 
-    private static class DefaultConstructorMessageDecoderFactory implements
-            MessageDecoderFactory {
-        private final Class<?> decoderClass;
-
-        private DefaultConstructorMessageDecoderFactory(Class<?> decoderClass) {
-            if (decoderClass == null) {
-                throw new NullPointerException("decoderClass");
-            }
-
-            if (!MessageDecoder.class.isAssignableFrom(decoderClass)) {
-                throw new IllegalArgumentException(
-                        "decoderClass is not assignable to MessageDecoder");
-            }
-            this.decoderClass = decoderClass;
-        }
-
-        public MessageDecoder getDecoder() throws Exception {
-            return (MessageDecoder) decoderClass.newInstance();
-        }
+    public void addMessageDecoder(MessageDecoderFactory factory) {
+        this.decoder.addMessageDecoder(factory);
     }
 }

Added: mina/trunk/core/src/main/java/org/apache/mina/filter/codec/demux/DemuxingProtocolDecoder.java
URL: http://svn.apache.org/viewvc/mina/trunk/core/src/main/java/org/apache/mina/filter/codec/demux/DemuxingProtocolDecoder.java?rev=590006&view=auto
==============================================================================
--- mina/trunk/core/src/main/java/org/apache/mina/filter/codec/demux/DemuxingProtocolDecoder.java (added)
+++ mina/trunk/core/src/main/java/org/apache/mina/filter/codec/demux/DemuxingProtocolDecoder.java Tue Oct 30 02:44:02 2007
@@ -0,0 +1,268 @@
+/*
+ *  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.filter.codec.demux;
+
+import org.apache.mina.common.AttributeKey;
+import org.apache.mina.common.IoBuffer;
+import org.apache.mina.common.IoSession;
+import org.apache.mina.filter.codec.CumulativeProtocolDecoder;
+import org.apache.mina.filter.codec.ProtocolDecoderException;
+import org.apache.mina.filter.codec.ProtocolDecoderOutput;
+
+/**
+ * A composite {@link ProtocoDecoder} that demultiplexes incoming {@link IoBuffer}
+ * decoding requests into an appropriate {@link MessageDecoder}.
+ * 
+ * <h2>Internal mechanism of {@link MessageDecoder} selection</h2>
+ * <p>
+ * <ol>
+ * <li>{@link DemuxingProtocolDecoder} iterates the list of candidate
+ * {@link MessageDecoder}s and calls {@link MessageDecoder#decodable(IoSession, IoBuffer)}.
+ * Initially, all registered {@link MessageDecoder}s are candidates.</li>
+ * <li>If {@link MessageDecoderResult#NOT_OK} is returned, it is removed from the candidate
+ *     list.</li>
+ * <li>If {@link MessageDecoderResult#NEED_DATA} is returned, it is retained in the candidate
+ *     list, and its {@link MessageDecoder#decodable(IoSession, IoBuffer)} will be invoked
+ *     again when more data is received.</li>
+ * <li>If {@link MessageDecoderResult#OK} is returned, {@link DemuxingProtocolDecoder}
+ *     found the right {@link MessageDecoder}.</li>
+ * <li>If there's no candidate left, an exception is raised.  Otherwise, 
+ *     {@link DemuxingProtocolDecoder} will keep iterating the candidate list.
+ * </ol>
+ * 
+ * Please note that any change of position and limit of the specified {@link IoBuffer}
+ * in {@link MessageDecoder#decodable(IoSession, IoBuffer)} will be reverted back to its
+ * original value.
+ * <p>
+ * Once a {@link MessageDecoder} is selected, {@link DemuxingProtocolDecoder} calls
+ * {@link MessageDecoder#decode(IoSession, IoBuffer, ProtocolDecoderOutput)} continuously
+ * reading its return value:
+ * <ul>
+ * <li>{@link MessageDecoderResult#NOT_OK} - protocol violation; {@link ProtocolDecoderException}
+ *                                           is raised automatically.</li>
+ * <li>{@link MessageDecoderResult#NEED_DATA} - needs more data to read the whole message;
+ *                                              {@link MessageDecoder#decode(IoSession, IoBuffer, ProtocolDecoderOutput)}
+ *                                              will be invoked again when more data is received.</li>
+ * <li>{@link MessageDecoderResult#OK} - successfully decoded a message; the candidate list will
+ *                                       be reset and the selection process will start over.</li>
+ * </ul>
+ *
+ * @author The Apache MINA Project (dev@mina.apache.org)
+ * @version $Rev$, $Date$
+ *
+ * @see MessageDecoderFactory
+ * @see MessageDecoder
+ */
+public class DemuxingProtocolDecoder extends CumulativeProtocolDecoder {
+
+    private final AttributeKey STATE = new AttributeKey(getClass(), "state");
+    
+    private MessageDecoderFactory[] decoderFactories = new MessageDecoderFactory[0];
+    private static final Class<?>[] EMPTY_PARAMS = new Class[0];
+
+    public DemuxingProtocolDecoder() {
+    }
+
+    public void addMessageDecoder(Class<? extends MessageDecoder> decoderClass) {
+        if (decoderClass == null) {
+            throw new NullPointerException("decoderClass");
+        }
+
+        try {
+            decoderClass.getConstructor(EMPTY_PARAMS);
+        } catch (NoSuchMethodException e) {
+            throw new IllegalArgumentException(
+                    "The specified class doesn't have a public default constructor.");
+        }
+
+        boolean registered = false;
+        if (MessageDecoder.class.isAssignableFrom(decoderClass)) {
+            addMessageDecoder(new DefaultConstructorMessageDecoderFactory(decoderClass));
+            registered = true;
+        }
+
+        if (!registered) {
+            throw new IllegalArgumentException(
+                    "Unregisterable type: " + decoderClass);
+        }
+    }
+
+    public void addMessageDecoder(MessageDecoder decoder) {
+        addMessageDecoder(new SingletonMessageDecoderFactory(decoder));
+    }
+
+    public void addMessageDecoder(MessageDecoderFactory factory) {
+        if (factory == null) {
+            throw new NullPointerException("factory");
+        }
+        MessageDecoderFactory[] decoderFactories = this.decoderFactories;
+        MessageDecoderFactory[] newDecoderFactories = new MessageDecoderFactory[decoderFactories.length + 1];
+        System.arraycopy(decoderFactories, 0, newDecoderFactories, 0,
+                decoderFactories.length);
+        newDecoderFactories[decoderFactories.length] = factory;
+        this.decoderFactories = newDecoderFactories;
+    }
+    
+    @Override
+    protected boolean doDecode(IoSession session, IoBuffer in,
+            ProtocolDecoderOutput out) throws Exception {
+        State state = getState(session);
+        if (state.currentDecoder == null) {
+            MessageDecoder[] decoders = state.decoders;
+            int undecodables = 0;
+            for (int i = decoders.length - 1; i >= 0; i--) {
+                MessageDecoder decoder = decoders[i];
+                int limit = in.limit();
+                int pos = in.position();
+
+                MessageDecoderResult result;
+                try {
+                    result = decoder.decodable(session, in);
+                } finally {
+                    in.position(pos);
+                    in.limit(limit);
+                }
+
+                if (result == MessageDecoder.OK) {
+                    state.currentDecoder = decoder;
+                    break;
+                } else if (result == MessageDecoder.NOT_OK) {
+                    undecodables++;
+                } else if (result != MessageDecoder.NEED_DATA) {
+                    throw new IllegalStateException(
+                            "Unexpected decode result (see your decodable()): "
+                                    + result);
+                }
+            }
+
+            if (undecodables == decoders.length) {
+                // Throw an exception if all decoders cannot decode data.
+                String dump = in.getHexDump();
+                in.position(in.limit()); // Skip data
+                throw new ProtocolDecoderException(
+                        "No appropriate message decoder: " + dump);
+            }
+
+            if (state.currentDecoder == null) {
+                // Decoder is not determined yet (i.e. we need more data)
+                return false;
+            }
+        }
+
+        MessageDecoderResult result = state.currentDecoder.decode(session, in,
+                out);
+        if (result == MessageDecoder.OK) {
+            state.currentDecoder = null;
+            return true;
+        } else if (result == MessageDecoder.NEED_DATA) {
+            return false;
+        } else if (result == MessageDecoder.NOT_OK) {
+            state.currentDecoder = null;
+            throw new ProtocolDecoderException(
+                    "Message decoder returned NOT_OK.");
+        } else {
+            state.currentDecoder = null;
+            throw new IllegalStateException(
+                    "Unexpected decode result (see your decode()): "
+                            + result);
+        }
+    }
+
+    @Override
+    public void finishDecode(IoSession session, ProtocolDecoderOutput out)
+            throws Exception {
+        super.finishDecode(session, out);
+        State state = getState(session);
+        MessageDecoder currentDecoder = state.currentDecoder;
+        if (currentDecoder == null) {
+            return;
+        }
+
+        currentDecoder.finishDecode(session, out);
+    }
+
+    @Override
+    public void dispose(IoSession session) throws Exception {
+        super.dispose(session);
+        session.removeAttribute(STATE);
+    }
+    
+    private State getState(IoSession session) throws Exception {
+        State state = (State) session.getAttribute(STATE);
+        if (state == null) {
+            state = new State();
+            State oldState = (State) session.setAttributeIfAbsent(STATE, state);
+            if (oldState != null) {
+                state = oldState;
+            }
+        }
+        return state;
+    }
+    
+    private class State {
+        private final MessageDecoder[] decoders;
+        private MessageDecoder currentDecoder;
+        
+        private State() throws Exception {
+            MessageDecoderFactory[] decoderFactories = DemuxingProtocolDecoder.this.decoderFactories;
+            decoders = new MessageDecoder[decoderFactories.length];
+            for (int i = decoderFactories.length - 1; i >= 0; i--) {
+                decoders[i] = decoderFactories[i].getDecoder();
+            }
+        }
+    }
+
+    private static class SingletonMessageDecoderFactory implements
+            MessageDecoderFactory {
+        private final MessageDecoder decoder;
+
+        private SingletonMessageDecoderFactory(MessageDecoder decoder) {
+            if (decoder == null) {
+                throw new NullPointerException("decoder");
+            }
+            this.decoder = decoder;
+        }
+
+        public MessageDecoder getDecoder() {
+            return decoder;
+        }
+    }
+
+    private static class DefaultConstructorMessageDecoderFactory implements
+            MessageDecoderFactory {
+        private final Class<?> decoderClass;
+
+        private DefaultConstructorMessageDecoderFactory(Class<?> decoderClass) {
+            if (decoderClass == null) {
+                throw new NullPointerException("decoderClass");
+            }
+
+            if (!MessageDecoder.class.isAssignableFrom(decoderClass)) {
+                throw new IllegalArgumentException(
+                        "decoderClass is not assignable to MessageDecoder");
+            }
+            this.decoderClass = decoderClass;
+        }
+
+        public MessageDecoder getDecoder() throws Exception {
+            return (MessageDecoder) decoderClass.newInstance();
+        }
+    }
+}

Propchange: mina/trunk/core/src/main/java/org/apache/mina/filter/codec/demux/DemuxingProtocolDecoder.java
------------------------------------------------------------------------------
    svn:eol-style = native

Propchange: mina/trunk/core/src/main/java/org/apache/mina/filter/codec/demux/DemuxingProtocolDecoder.java
------------------------------------------------------------------------------
    svn:keywords = Rev Date

Added: mina/trunk/core/src/main/java/org/apache/mina/filter/codec/demux/DemuxingProtocolEncoder.java
URL: http://svn.apache.org/viewvc/mina/trunk/core/src/main/java/org/apache/mina/filter/codec/demux/DemuxingProtocolEncoder.java?rev=590006&view=auto
==============================================================================
--- mina/trunk/core/src/main/java/org/apache/mina/filter/codec/demux/DemuxingProtocolEncoder.java (added)
+++ mina/trunk/core/src/main/java/org/apache/mina/filter/codec/demux/DemuxingProtocolEncoder.java Tue Oct 30 02:44:02 2007
@@ -0,0 +1,254 @@
+/*
+ *  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.filter.codec.demux;
+
+import java.util.Map;
+import java.util.Set;
+import java.util.concurrent.ConcurrentHashMap;
+import java.util.concurrent.ConcurrentMap;
+
+import org.apache.mina.common.AttributeKey;
+import org.apache.mina.common.IoSession;
+import org.apache.mina.common.UnknownMessageTypeException;
+import org.apache.mina.filter.codec.ProtocolEncoder;
+import org.apache.mina.filter.codec.ProtocolEncoderOutput;
+import org.apache.mina.util.IdentityHashSet;
+
+/**
+ * A composite {@link ProtocolEncoder} that demultiplexes incoming message
+ * encoding requests into an appropriate {@link MessageEncoder}.
+ *
+ * <h2>Disposing resources acquired by {@link MessageEncoder}</h2>
+ * <p>
+ * Override {@link #dispose(IoSession)} method. Please don't forget to call
+ * <tt>super.dispose()</tt>.
+ *
+ * @author The Apache MINA Project (dev@mina.apache.org)
+ * @version $Rev$, $Date$
+ *
+ * @see MessageEncoderFactory
+ * @see MessageEncoder
+ */
+public class DemuxingProtocolEncoder implements ProtocolEncoder {
+    
+    private final AttributeKey STATE = new AttributeKey(getClass(), "state");
+
+    @SuppressWarnings("unchecked")
+    private final ConcurrentMap<Class<?>, MessageEncoderFactory> type2encoderFactory = new ConcurrentHashMap<Class<?>, MessageEncoderFactory>();
+
+    private static final Class<?>[] EMPTY_PARAMS = new Class[0];
+
+    public DemuxingProtocolEncoder() {
+    }
+
+    @SuppressWarnings("unchecked")
+    public void addMessageEncoder(Class<?> messageType, Class<? extends MessageEncoder> encoderClass) {
+        if (encoderClass == null) {
+            throw new NullPointerException("encoderClass");
+        }
+
+        try {
+            encoderClass.getConstructor(EMPTY_PARAMS);
+        } catch (NoSuchMethodException e) {
+            throw new IllegalArgumentException(
+                    "The specified class doesn't have a public default constructor.");
+        }
+
+        boolean registered = false;
+        if (MessageEncoder.class.isAssignableFrom(encoderClass)) {
+            addMessageEncoder(messageType, new DefaultConstructorMessageEncoderFactory(encoderClass));
+            registered = true;
+        }
+
+        if (!registered) {
+            throw new IllegalArgumentException(
+                    "Unregisterable type: " + encoderClass);
+        }
+    }
+
+    @SuppressWarnings("unchecked")
+    public <T> void addMessageEncoder(Class<T> messageType, MessageEncoder<? super T> encoder) {
+        addMessageEncoder(messageType, new SingletonMessageEncoderFactory(encoder));
+    }
+
+    public <T> void addMessageEncoder(Class<T> messageType, MessageEncoderFactory<? super T> factory) {
+        if (messageType == null) {
+            throw new NullPointerException("messageType");
+        }
+        
+        if (factory == null) {
+            throw new NullPointerException("factory");
+        }
+        
+        if (type2encoderFactory.putIfAbsent(messageType, factory) != null) {
+            throw new IllegalStateException(
+                    "The specified message type (" + messageType.getName() + ") is registered already.");
+        }
+    }
+
+    public void encode(IoSession session, Object message,
+            ProtocolEncoderOutput out) throws Exception {
+        State state = getState(session);
+        MessageEncoder<Object> encoder = findEncoder(state, message.getClass());
+        if (encoder != null) {
+            encoder.encode(session, message, out);
+        } else {
+            throw new UnknownMessageTypeException(
+                    "No message encoder found for message: " + message);
+        }
+    }
+
+    protected MessageEncoder<Object> findEncoder(State state, Class<?> type) {
+        return findEncoder(state, type, null);
+    }
+
+    @SuppressWarnings("unchecked")
+    private MessageEncoder<Object> findEncoder(
+            State state, Class type, Set<Class> triedClasses) {
+        MessageEncoder encoder = null;
+
+        if (triedClasses != null && triedClasses.contains(type)) {
+            return null;
+        }
+
+        /*
+         * Try the cache first.
+         */
+        encoder = state.findEncoderCache.get(type);
+        if (encoder != null) {
+            return encoder;
+        }
+
+        /*
+         * Try the registered encoders for an immediate match.
+         */
+        encoder = state.type2encoder.get(type);
+
+        if (encoder == null) {
+            /*
+             * No immediate match could be found. Search the type's interfaces.
+             */
+
+            if (triedClasses == null) {
+                triedClasses = new IdentityHashSet<Class>();
+            }
+            triedClasses.add(type);
+
+            Class[] interfaces = type.getInterfaces();
+            for (Class element : interfaces) {
+                encoder = findEncoder(state, element, triedClasses);
+                if (encoder != null) {
+                    break;
+                }
+            }
+        }
+
+        if (encoder == null) {
+            /*
+             * No match in type's interfaces could be found. Search the
+             * superclass.
+             */
+
+            Class superclass = type.getSuperclass();
+            if (superclass != null) {
+                encoder = findEncoder(state, superclass);
+            }
+        }
+
+        /*
+         * Make sure the encoder is added to the cache. By updating the cache
+         * here all the types (superclasses and interfaces) in the path which
+         * led to a match will be cached along with the immediate message type.
+         */
+        if (encoder != null) {
+            state.findEncoderCache.put(type, encoder);
+        }
+
+        return encoder;
+    }
+
+    public void dispose(IoSession session) throws Exception {
+        session.removeAttribute(STATE);
+    }
+    
+    private State getState(IoSession session) throws Exception {
+        State state = (State) session.getAttribute(STATE);
+        if (state == null) {
+            state = new State();
+            State oldState = (State) session.setAttributeIfAbsent(STATE, state);
+            if (oldState != null) {
+                state = oldState;
+            }
+        }
+        return state;
+    }
+    
+    private class State {
+        @SuppressWarnings("unchecked")
+        private final Map<Class<?>, MessageEncoder> findEncoderCache = new ConcurrentHashMap<Class<?>, MessageEncoder>();
+
+        @SuppressWarnings("unchecked")
+        private final Map<Class<?>, MessageEncoder> type2encoder = new ConcurrentHashMap<Class<?>, MessageEncoder>();
+        
+        @SuppressWarnings("unchecked")
+        private State() throws Exception {
+            for (Map.Entry<Class<?>, MessageEncoderFactory> e: type2encoderFactory.entrySet()) {
+                type2encoder.put(e.getKey(), e.getValue().getEncoder());
+            }
+        }
+    }
+
+    private static class SingletonMessageEncoderFactory<T> implements
+            MessageEncoderFactory<T> {
+        private final MessageEncoder<T> encoder;
+
+        private SingletonMessageEncoderFactory(MessageEncoder<T> encoder) {
+            if (encoder == null) {
+                throw new NullPointerException("encoder");
+            }
+            this.encoder = encoder;
+        }
+
+        public MessageEncoder<T> getEncoder() {
+            return encoder;
+        }
+    }
+
+    private static class DefaultConstructorMessageEncoderFactory<T> implements
+            MessageEncoderFactory<T> {
+        private final Class<MessageEncoder<T>> encoderClass;
+
+        private DefaultConstructorMessageEncoderFactory(Class<MessageEncoder<T>> encoderClass) {
+            if (encoderClass == null) {
+                throw new NullPointerException("encoderClass");
+            }
+
+            if (!MessageEncoder.class.isAssignableFrom(encoderClass)) {
+                throw new IllegalArgumentException(
+                        "encoderClass is not assignable to MessageEncoder");
+            }
+            this.encoderClass = encoderClass;
+        }
+
+        public MessageEncoder<T> getEncoder() throws Exception {
+            return encoderClass.newInstance();
+        }
+    }
+}

Propchange: mina/trunk/core/src/main/java/org/apache/mina/filter/codec/demux/DemuxingProtocolEncoder.java
------------------------------------------------------------------------------
    svn:eol-style = native

Propchange: mina/trunk/core/src/main/java/org/apache/mina/filter/codec/demux/DemuxingProtocolEncoder.java
------------------------------------------------------------------------------
    svn:keywords = Rev Date

Modified: mina/trunk/core/src/main/java/org/apache/mina/filter/codec/demux/MessageDecoder.java
URL: http://svn.apache.org/viewvc/mina/trunk/core/src/main/java/org/apache/mina/filter/codec/demux/MessageDecoder.java?rev=590006&r1=590005&r2=590006&view=diff
==============================================================================
--- mina/trunk/core/src/main/java/org/apache/mina/filter/codec/demux/MessageDecoder.java (original)
+++ mina/trunk/core/src/main/java/org/apache/mina/filter/codec/demux/MessageDecoder.java Tue Oct 30 02:44:02 2007
@@ -24,12 +24,16 @@
 import org.apache.mina.filter.codec.ProtocolDecoderOutput;
 
 /**
- * Decodes specific messages.
+ * Decodes a certain type of messages.
+ * <p>
+ * We didn't provide any <tt>dispose</tt> method for {@link MessageDecoder}
+ * because it can give you  performance penalty in case you have a lot of
+ * message types to handle.
  *
  * @author The Apache MINA Project (dev@mina.apache.org)
  * @version $Rev$, $Date$
  *
- * @see DemuxingProtocolCodecFactory
+ * @see DemuxingProtocolDecoder
  * @see MessageDecoderFactory
  */
 public interface MessageDecoder {

Modified: mina/trunk/core/src/main/java/org/apache/mina/filter/codec/demux/MessageDecoderFactory.java
URL: http://svn.apache.org/viewvc/mina/trunk/core/src/main/java/org/apache/mina/filter/codec/demux/MessageDecoderFactory.java?rev=590006&r1=590005&r2=590006&view=diff
==============================================================================
--- mina/trunk/core/src/main/java/org/apache/mina/filter/codec/demux/MessageDecoderFactory.java (original)
+++ mina/trunk/core/src/main/java/org/apache/mina/filter/codec/demux/MessageDecoderFactory.java Tue Oct 30 02:44:02 2007
@@ -25,7 +25,7 @@
  * @author The Apache MINA Project (dev@mina.apache.org)
  * @version $Rev$, $Date$
  *
- * @see DemuxingProtocolCodecFactory
+ * @see DemuxingProtocolDecoder
  */
 public interface MessageDecoderFactory {
     /**

Modified: mina/trunk/core/src/main/java/org/apache/mina/filter/codec/demux/MessageEncoder.java
URL: http://svn.apache.org/viewvc/mina/trunk/core/src/main/java/org/apache/mina/filter/codec/demux/MessageEncoder.java?rev=590006&r1=590005&r2=590006&view=diff
==============================================================================
--- mina/trunk/core/src/main/java/org/apache/mina/filter/codec/demux/MessageEncoder.java (original)
+++ mina/trunk/core/src/main/java/org/apache/mina/filter/codec/demux/MessageEncoder.java Tue Oct 30 02:44:02 2007
@@ -19,27 +19,24 @@
  */
 package org.apache.mina.filter.codec.demux;
 
-import java.util.Set;
-
 import org.apache.mina.common.IoBuffer;
 import org.apache.mina.common.IoSession;
 import org.apache.mina.filter.codec.ProtocolEncoderOutput;
 
 /**
- * Encodes messages of specific types specified by {@link #getMessageTypes()}.
- *
+ * Encodes a certain type of messages.
+ * <p>
+ * We didn't provide any <tt>dispose</tt> method for {@link MessageEncoder}
+ * because it can give you  performance penalty in case you have a lot of
+ * message types to handle.
+ * 
  * @author The Apache MINA Project (dev@mina.apache.org)
  * @version $Rev$, $Date$
  *
- * @see DemuxingProtocolCodecFactory
+ * @see DemuxingProtocolEncoder
  * @see MessageEncoderFactory
  */
 public interface MessageEncoder<T> {
-    /**
-     * Returns the set of message classes this encoder can encode.
-     */
-    Set<Class<? extends T>> getMessageTypes();
-
     /**
      * Encodes higher-level message objects into binary or protocol-specific data.
      * MINA invokes {@link #encode(IoSession, Object, ProtocolEncoderOutput)}

Modified: mina/trunk/core/src/main/java/org/apache/mina/filter/codec/demux/MessageEncoderFactory.java
URL: http://svn.apache.org/viewvc/mina/trunk/core/src/main/java/org/apache/mina/filter/codec/demux/MessageEncoderFactory.java?rev=590006&r1=590005&r2=590006&view=diff
==============================================================================
--- mina/trunk/core/src/main/java/org/apache/mina/filter/codec/demux/MessageEncoderFactory.java (original)
+++ mina/trunk/core/src/main/java/org/apache/mina/filter/codec/demux/MessageEncoderFactory.java Tue Oct 30 02:44:02 2007
@@ -25,7 +25,7 @@
  * @author The Apache MINA Project (dev@mina.apache.org)
  * @version $Rev$, $Date$
  *
- * @see DemuxingProtocolCodecFactory
+ * @see DemuxingProtocolEncoder
  */
 public interface MessageEncoderFactory<T> {
     /**

Modified: mina/trunk/core/src/main/java/org/apache/mina/handler/demux/DemuxingIoHandler.java
URL: http://svn.apache.org/viewvc/mina/trunk/core/src/main/java/org/apache/mina/handler/demux/DemuxingIoHandler.java?rev=590006&r1=590005&r2=590006&view=diff
==============================================================================
--- mina/trunk/core/src/main/java/org/apache/mina/handler/demux/DemuxingIoHandler.java (original)
+++ mina/trunk/core/src/main/java/org/apache/mina/handler/demux/DemuxingIoHandler.java Tue Oct 30 02:44:02 2007
@@ -27,6 +27,7 @@
 import org.apache.mina.common.IoHandler;
 import org.apache.mina.common.IoHandlerAdapter;
 import org.apache.mina.common.IoSession;
+import org.apache.mina.common.UnknownMessageTypeException;
 import org.apache.mina.util.IdentityHashSet;
 
 /**

Modified: mina/trunk/example/src/main/java/org/apache/mina/example/httpserver/codec/HttpResponseEncoder.java
URL: http://svn.apache.org/viewvc/mina/trunk/example/src/main/java/org/apache/mina/example/httpserver/codec/HttpResponseEncoder.java?rev=590006&r1=590005&r2=590006&view=diff
==============================================================================
--- mina/trunk/example/src/main/java/org/apache/mina/example/httpserver/codec/HttpResponseEncoder.java (original)
+++ mina/trunk/example/src/main/java/org/apache/mina/example/httpserver/codec/HttpResponseEncoder.java Tue Oct 30 02:44:02 2007
@@ -22,9 +22,6 @@
 import java.nio.charset.CharacterCodingException;
 import java.nio.charset.Charset;
 import java.nio.charset.CharsetEncoder;
-import java.util.Collections;
-import java.util.HashSet;
-import java.util.Set;
 import java.util.Map.Entry;
 
 import org.apache.mina.common.IoBuffer;
@@ -38,23 +35,15 @@
  * @author The Apache MINA Project (dev@mina.apache.org)
  * @version $Rev$, $Date$
  */
-public class HttpResponseEncoder implements MessageEncoder {
-    private static final Set<Class<?>> TYPES;
-
-    static {
-        Set<Class<?>> types = new HashSet<Class<?>>();
-        types.add(HttpResponseMessage.class);
-        TYPES = Collections.unmodifiableSet(types);
-    }
+public class HttpResponseEncoder implements MessageEncoder<HttpResponseMessage> {
 
     private static final byte[] CRLF = new byte[] { 0x0D, 0x0A };
 
     public HttpResponseEncoder() {
     }
 
-    public void encode(IoSession session, Object message,
+    public void encode(IoSession session, HttpResponseMessage message,
             ProtocolEncoderOutput out) throws Exception {
-        HttpResponseMessage msg = (HttpResponseMessage) message;
         IoBuffer buf = IoBuffer.allocate(256);
         // Enable auto-expand for easier encoding
         buf.setAutoExpand(true);
@@ -63,8 +52,8 @@
             // output all headers except the content length
             CharsetEncoder encoder = Charset.defaultCharset().newEncoder();
             buf.putString("HTTP/1.1 ", encoder);
-            buf.putString(String.valueOf(msg.getResponseCode()), encoder);
-            switch (msg.getResponseCode()) {
+            buf.putString(String.valueOf(message.getResponseCode()), encoder);
+            switch (message.getResponseCode()) {
             case HttpResponseMessage.HTTP_STATUS_SUCCESS:
                 buf.putString(" OK", encoder);
                 break;
@@ -73,7 +62,7 @@
                 break;
             }
             buf.put(CRLF);
-            for (Entry<String, String> entry: msg.getHeaders().entrySet()) {
+            for (Entry<String, String> entry: message.getHeaders().entrySet()) {
                 buf.putString(entry.getKey(), encoder);
                 buf.putString(": ", encoder);
                 buf.putString(entry.getValue(), encoder);
@@ -81,11 +70,11 @@
             }
             // now the content length is the body length
             buf.putString("Content-Length: ", encoder);
-            buf.putString(String.valueOf(msg.getBodyLength()), encoder);
+            buf.putString(String.valueOf(message.getBodyLength()), encoder);
             buf.put(CRLF);
             buf.put(CRLF);
             // add body
-            buf.put(msg.getBody());
+            buf.put(message.getBody());
             //System.out.println("\n+++++++");
             //for (int i=0; i<buf.position();i++)System.out.print(new String(new byte[]{buf.get(i)}));
             //System.out.println("\n+++++++");
@@ -95,9 +84,5 @@
 
         buf.flip();
         out.write(buf);
-    }
-
-    public Set<Class<?>> getMessageTypes() {
-        return TYPES;
     }
 }

Modified: mina/trunk/example/src/main/java/org/apache/mina/example/httpserver/codec/HttpServerProtocolCodecFactory.java
URL: http://svn.apache.org/viewvc/mina/trunk/example/src/main/java/org/apache/mina/example/httpserver/codec/HttpServerProtocolCodecFactory.java?rev=590006&r1=590005&r2=590006&view=diff
==============================================================================
--- mina/trunk/example/src/main/java/org/apache/mina/example/httpserver/codec/HttpServerProtocolCodecFactory.java (original)
+++ mina/trunk/example/src/main/java/org/apache/mina/example/httpserver/codec/HttpServerProtocolCodecFactory.java Tue Oct 30 02:44:02 2007
@@ -30,7 +30,7 @@
 public class HttpServerProtocolCodecFactory extends
         DemuxingProtocolCodecFactory {
     public HttpServerProtocolCodecFactory() {
-        super.register(HttpRequestDecoder.class);
-        super.register(HttpResponseEncoder.class);
+        super.addMessageDecoder(HttpRequestDecoder.class);
+        super.addMessageEncoder(HttpResponseMessage.class, HttpResponseEncoder.class);
     }
 }

Modified: mina/trunk/example/src/main/java/org/apache/mina/example/sumup/codec/AbstractMessageEncoder.java
URL: http://svn.apache.org/viewvc/mina/trunk/example/src/main/java/org/apache/mina/example/sumup/codec/AbstractMessageEncoder.java?rev=590006&r1=590005&r2=590006&view=diff
==============================================================================
--- mina/trunk/example/src/main/java/org/apache/mina/example/sumup/codec/AbstractMessageEncoder.java (original)
+++ mina/trunk/example/src/main/java/org/apache/mina/example/sumup/codec/AbstractMessageEncoder.java Tue Oct 30 02:44:02 2007
@@ -32,29 +32,26 @@
  * @author The Apache MINA Project (dev@mina.apache.org)
  * @version $Rev$, $Date$
  */
-public abstract class AbstractMessageEncoder implements MessageEncoder {
+public abstract class AbstractMessageEncoder<T extends AbstractMessage> implements MessageEncoder<T> {
     private final int type;
 
     protected AbstractMessageEncoder(int type) {
         this.type = type;
     }
 
-    public void encode(IoSession session, Object message,
-            ProtocolEncoderOutput out) throws Exception {
-        AbstractMessage m = (AbstractMessage) message;
+    public void encode(IoSession session, T message, ProtocolEncoderOutput out) throws Exception {
         IoBuffer buf = IoBuffer.allocate(16);
         buf.setAutoExpand(true); // Enable auto-expand for easier encoding
 
         // Encode a header
         buf.putShort((short) type);
-        buf.putInt(m.getSequence());
+        buf.putInt(message.getSequence());
 
         // Encode a body
-        encodeBody(session, m, buf);
+        encodeBody(session, message, buf);
         buf.flip();
         out.write(buf);
     }
 
-    protected abstract void encodeBody(IoSession session,
-            AbstractMessage message, IoBuffer out);
+    protected abstract void encodeBody(IoSession session, T message, IoBuffer out);
 }

Modified: mina/trunk/example/src/main/java/org/apache/mina/example/sumup/codec/AddMessageEncoder.java
URL: http://svn.apache.org/viewvc/mina/trunk/example/src/main/java/org/apache/mina/example/sumup/codec/AddMessageEncoder.java?rev=590006&r1=590005&r2=590006&view=diff
==============================================================================
--- mina/trunk/example/src/main/java/org/apache/mina/example/sumup/codec/AddMessageEncoder.java (original)
+++ mina/trunk/example/src/main/java/org/apache/mina/example/sumup/codec/AddMessageEncoder.java Tue Oct 30 02:44:02 2007
@@ -19,13 +19,8 @@
  */
 package org.apache.mina.example.sumup.codec;
 
-import java.util.Collections;
-import java.util.HashSet;
-import java.util.Set;
-
 import org.apache.mina.common.IoBuffer;
 import org.apache.mina.common.IoSession;
-import org.apache.mina.example.sumup.message.AbstractMessage;
 import org.apache.mina.example.sumup.message.AddMessage;
 import org.apache.mina.filter.codec.demux.MessageEncoder;
 
@@ -35,28 +30,14 @@
  * @author The Apache MINA Project (dev@mina.apache.org)
  * @version $Rev$, $Date$
  */
-public class AddMessageEncoder extends AbstractMessageEncoder {
-    private static final Set<Class<?>> TYPES;
-
-    static {
-        Set<Class<?>> types = new HashSet<Class<?>>();
-        types.add(AddMessage.class);
-        TYPES = Collections.unmodifiableSet(types);
-    }
-
+public class AddMessageEncoder<T extends AddMessage> extends AbstractMessageEncoder<T> {
     public AddMessageEncoder() {
         super(Constants.ADD);
     }
 
     @Override
-    protected void encodeBody(IoSession session, AbstractMessage message,
-            IoBuffer out) {
-        AddMessage m = (AddMessage) message;
-        out.putInt(m.getValue());
-    }
-
-    public Set<Class<?>> getMessageTypes() {
-        return TYPES;
+    protected void encodeBody(IoSession session, T message, IoBuffer out) {
+        out.putInt(message.getValue());
     }
 
     public void dispose() throws Exception {

Modified: mina/trunk/example/src/main/java/org/apache/mina/example/sumup/codec/ResultMessageEncoder.java
URL: http://svn.apache.org/viewvc/mina/trunk/example/src/main/java/org/apache/mina/example/sumup/codec/ResultMessageEncoder.java?rev=590006&r1=590005&r2=590006&view=diff
==============================================================================
--- mina/trunk/example/src/main/java/org/apache/mina/example/sumup/codec/ResultMessageEncoder.java (original)
+++ mina/trunk/example/src/main/java/org/apache/mina/example/sumup/codec/ResultMessageEncoder.java Tue Oct 30 02:44:02 2007
@@ -19,13 +19,8 @@
  */
 package org.apache.mina.example.sumup.codec;
 
-import java.util.Collections;
-import java.util.HashSet;
-import java.util.Set;
-
 import org.apache.mina.common.IoBuffer;
 import org.apache.mina.common.IoSession;
-import org.apache.mina.example.sumup.message.AbstractMessage;
 import org.apache.mina.example.sumup.message.ResultMessage;
 import org.apache.mina.filter.codec.demux.MessageEncoder;
 
@@ -35,36 +30,21 @@
  * @author The Apache MINA Project (dev@mina.apache.org)
  * @version $Rev$, $Date$
  */
-public class ResultMessageEncoder extends AbstractMessageEncoder {
-    private static final Set<Class<?>> TYPES;
-
-    static {
-        Set<Class<?>> types = new HashSet<Class<?>>();
-        types.add(ResultMessage.class);
-        TYPES = Collections.unmodifiableSet(types);
-    }
-
+public class ResultMessageEncoder<T extends ResultMessage> extends AbstractMessageEncoder<T> {
     public ResultMessageEncoder() {
         super(Constants.RESULT);
     }
 
     @Override
-    protected void encodeBody(IoSession session, AbstractMessage message,
-            IoBuffer out) {
-        ResultMessage m = (ResultMessage) message;
-        if (m.isOk()) {
+    protected void encodeBody(IoSession session, T message, IoBuffer out) {
+        if (message.isOk()) {
             out.putShort((short) Constants.RESULT_OK);
-            out.putInt(m.getValue());
+            out.putInt(message.getValue());
         } else {
             out.putShort((short) Constants.RESULT_ERROR);
         }
     }
 
-    public Set<Class<?>> getMessageTypes() {
-        return TYPES;
-    }
-
     public void dispose() throws Exception {
     }
-
 }

Modified: mina/trunk/example/src/main/java/org/apache/mina/example/sumup/codec/SumUpProtocolCodecFactory.java
URL: http://svn.apache.org/viewvc/mina/trunk/example/src/main/java/org/apache/mina/example/sumup/codec/SumUpProtocolCodecFactory.java?rev=590006&r1=590005&r2=590006&view=diff
==============================================================================
--- mina/trunk/example/src/main/java/org/apache/mina/example/sumup/codec/SumUpProtocolCodecFactory.java (original)
+++ mina/trunk/example/src/main/java/org/apache/mina/example/sumup/codec/SumUpProtocolCodecFactory.java Tue Oct 30 02:44:02 2007
@@ -19,6 +19,8 @@
  */
 package org.apache.mina.example.sumup.codec;
 
+import org.apache.mina.example.sumup.message.AddMessage;
+import org.apache.mina.example.sumup.message.ResultMessage;
 import org.apache.mina.filter.codec.ProtocolCodecFactory;
 import org.apache.mina.filter.codec.demux.DemuxingProtocolCodecFactory;
 
@@ -33,12 +35,12 @@
 
     public SumUpProtocolCodecFactory(boolean server) {
         if (server) {
-            super.register(AddMessageDecoder.class);
-            super.register(ResultMessageEncoder.class);
+            super.addMessageDecoder(AddMessageDecoder.class);
+            super.addMessageEncoder(ResultMessage.class, ResultMessageEncoder.class);
         } else // Client
         {
-            super.register(AddMessageEncoder.class);
-            super.register(ResultMessageDecoder.class);
+            super.addMessageEncoder(AddMessage.class, AddMessageEncoder.class);
+            super.addMessageDecoder(ResultMessageDecoder.class);
         }
     }
 }