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 05:04:51 UTC

svn commit: r589954 - in /mina/trunk: core/src/main/java/org/apache/mina/common/ core/src/main/java/org/apache/mina/transport/socket/nio/ core/src/main/java/org/apache/mina/transport/vmpipe/ core/src/test/java/org/apache/mina/common/ transport-apr/src/...

Author: trustin
Date: Mon Oct 29 21:04:50 2007
New Revision: 589954

URL: http://svn.apache.org/viewvc?rev=589954&view=rev
Log:
Resolved issue: DIRMINA-393 (Allow users to choose a Map implementation for storing session attributes.)
* Added IoSessionAttributeMap
* Added IoSessionAttributeMapFactory
* Added AbstractIoService.finishSessionInitialization() to initialize session attribute map
* Fixed some compiler warnings and typo...


Added:
    mina/trunk/core/src/main/java/org/apache/mina/common/DefaultIoSessionAttributeMapFactory.java   (with props)
    mina/trunk/core/src/main/java/org/apache/mina/common/IoSessionAttributeMap.java   (with props)
    mina/trunk/core/src/main/java/org/apache/mina/common/IoSessionAttributeMapFactory.java   (with props)
    mina/trunk/core/src/main/java/org/apache/mina/common/IoSessionInitializationException.java   (with props)
Modified:
    mina/trunk/core/src/main/java/org/apache/mina/common/AbstractIoConnector.java
    mina/trunk/core/src/main/java/org/apache/mina/common/AbstractIoService.java
    mina/trunk/core/src/main/java/org/apache/mina/common/AbstractIoSession.java
    mina/trunk/core/src/main/java/org/apache/mina/common/DefaultIoFilterChain.java
    mina/trunk/core/src/main/java/org/apache/mina/common/DummySession.java
    mina/trunk/core/src/main/java/org/apache/mina/common/IoService.java
    mina/trunk/core/src/main/java/org/apache/mina/common/IoSession.java
    mina/trunk/core/src/main/java/org/apache/mina/transport/socket/nio/NioDatagramAcceptor.java
    mina/trunk/core/src/main/java/org/apache/mina/transport/socket/nio/NioSocketAcceptor.java
    mina/trunk/core/src/main/java/org/apache/mina/transport/vmpipe/VmPipeAcceptor.java
    mina/trunk/core/src/main/java/org/apache/mina/transport/vmpipe/VmPipeConnector.java
    mina/trunk/core/src/test/java/org/apache/mina/common/IoServiceListenerSupportTest.java
    mina/trunk/transport-apr/src/main/java/org/apache/mina/transport/socket/apr/AprConnector.java
    mina/trunk/transport-apr/src/main/java/org/apache/mina/transport/socket/apr/AprIoProcessor.java
    mina/trunk/transport-serial/src/main/java/org/apache/mina/transport/serial/SerialConnector.java

Modified: mina/trunk/core/src/main/java/org/apache/mina/common/AbstractIoConnector.java
URL: http://svn.apache.org/viewvc/mina/trunk/core/src/main/java/org/apache/mina/common/AbstractIoConnector.java?rev=589954&r1=589953&r2=589954&view=diff
==============================================================================
--- mina/trunk/core/src/main/java/org/apache/mina/common/AbstractIoConnector.java (original)
+++ mina/trunk/core/src/main/java/org/apache/mina/common/AbstractIoConnector.java Mon Oct 29 21:04:50 2007
@@ -97,10 +97,9 @@
      * related with event notifications to the specified {@code session}
      * and {@code future}.
      */
-    protected static void finishSessionInitialization(
-            final IoSession session, ConnectFuture future) {
-        // DefaultIoFilterChain will notify the connect future.
-        session.setAttribute(DefaultIoFilterChain.CONNECT_FUTURE, future);
+    protected void finishSessionInitialization(
+            final IoSession session, IoFuture future) {
+        super.finishSessionInitialization(session, future);
 
         // In case that ConnectFuture.cancel() is invoked before
         // setSession() is invoked, add a listener that closes the

Modified: mina/trunk/core/src/main/java/org/apache/mina/common/AbstractIoService.java
URL: http://svn.apache.org/viewvc/mina/trunk/core/src/main/java/org/apache/mina/common/AbstractIoService.java?rev=589954&r1=589953&r2=589954&view=diff
==============================================================================
--- mina/trunk/core/src/main/java/org/apache/mina/common/AbstractIoService.java (original)
+++ mina/trunk/core/src/main/java/org/apache/mina/common/AbstractIoService.java Mon Oct 29 21:04:50 2007
@@ -42,6 +42,9 @@
      * Current handler.
      */
     private IoHandler handler;
+    
+    private IoSessionAttributeMapFactory sessionAttributeMapFactory =
+        new DefaultIoSessionAttributeMapFactory();
 
     /**
      * Maintains the {@link IoServiceListener}s of this service.
@@ -137,6 +140,23 @@
         return sessionConfig;
     }
 
+    public IoSessionAttributeMapFactory getSessionAttributeMapFactory() {
+        return sessionAttributeMapFactory;
+    }
+
+    public void setSessionAttributeMapFactory(IoSessionAttributeMapFactory sessionAttributeMapFactory) {
+        if (sessionAttributeMapFactory == null) {
+            throw new NullPointerException("sessionAttributeMapFactory");
+        }
+
+        if (isActive()) {
+            throw new IllegalStateException(
+                    "sessionAttributeMapFactory cannot be set while the service is active.");
+        }
+
+        this.sessionAttributeMapFactory = sessionAttributeMapFactory;
+    }
+
     public long getReadBytes() {
         return readBytes.get();
     }
@@ -212,6 +232,27 @@
                 return futures.size();
             }
         };
+    }
+    
+    protected void finishSessionInitialization(IoSession session, IoFuture future) {
+        // Every property but attributeMap should be set now.
+        // Now initialize the attributeMap.  The reason why we initialize
+        // the attributeMap at last is to make sure all session properties
+        // such as remoteAddress are provided to IoSessionAttributeMapFactory.
+        try {
+            ((AbstractIoSession) session).setAttributeMap(
+                    session.getService().getSessionAttributeMapFactory().getAttributeMap(session));
+        } catch (IoSessionInitializationException e) {
+            throw e;
+        } catch (Exception e) {
+            throw new IoSessionInitializationException(
+                    "Failed to initialize sessionAttributeMap.", e);
+        }
+
+        if (future != null && future instanceof ConnectFuture) {
+            // DefaultIoFilterChain will notify the future. (We support ConnectFuture only for now).
+            session.setAttribute(DefaultIoFilterChain.SESSION_OPENED_FUTURE, future);
+        }
     }
 
     protected static class ServiceOperationFuture extends DefaultIoFuture {

Modified: mina/trunk/core/src/main/java/org/apache/mina/common/AbstractIoSession.java
URL: http://svn.apache.org/viewvc/mina/trunk/core/src/main/java/org/apache/mina/common/AbstractIoSession.java?rev=589954&r1=589953&r2=589954&view=diff
==============================================================================
--- mina/trunk/core/src/main/java/org/apache/mina/common/AbstractIoSession.java (original)
+++ mina/trunk/core/src/main/java/org/apache/mina/common/AbstractIoSession.java Mon Oct 29 21:04:50 2007
@@ -24,10 +24,6 @@
 import java.io.IOException;
 import java.net.SocketAddress;
 import java.nio.channels.FileChannel;
-import java.util.Collections;
-import java.util.HashMap;
-import java.util.HashSet;
-import java.util.Map;
 import java.util.Queue;
 import java.util.Set;
 import java.util.concurrent.ConcurrentLinkedQueue;
@@ -62,8 +58,7 @@
 
     private final Object lock = new Object();
 
-    private final Map<Object, Object> attributes = Collections
-            .synchronizedMap(new HashMap<Object, Object>(4));
+    private IoSessionAttributeMap attributes;
 
     private final Queue<WriteRequest> writeRequestQueue =
         new ConcurrentLinkedQueue<WriteRequest>() {
@@ -268,115 +263,47 @@
     }
 
     public Object getAttribute(Object key) {
-        if (key == null) {
-            throw new NullPointerException("key");
-        }
-
-        return attributes.get(key);
+        return attributes.getAttribute(this, key);
     }
 
     public Object getAttribute(Object key, Object defaultValue) {
-        if (key == null) {
-            throw new NullPointerException("key");
-        }
-        if (defaultValue == null) {
-            return attributes.get(key);
-        }
-
-        Object answer = attributes.get(key);
-        if (answer == null) {
-            return defaultValue;
-        } else {
-            return answer;
-        }
+        return attributes.getAttribute(this, key, defaultValue);
     }
 
     public Object setAttribute(Object key, Object value) {
-        if (key == null) {
-            throw new NullPointerException("key");
-        }
-
-        if (value == null) {
-            return attributes.remove(key);
-        } else {
-            return attributes.put(key, value);
-        }
+        return attributes.setAttribute(this, key, value);
     }
 
     public Object setAttribute(Object key) {
-        return setAttribute(key, Boolean.TRUE);
+        return attributes.setAttribute(this, key);
     }
 
     public Object setAttributeIfAbsent(Object key, Object value) {
-        if (key == null) {
-            throw new NullPointerException("key");
-        }
-
-        if (value == null) {
-            return null;
-        }
-
-        Object oldValue;
-        synchronized (attributes) {
-            oldValue = attributes.get(key);
-            if (oldValue == null) {
-                attributes.put(key, value);
-            }
-        }
-        return oldValue;
+        return attributes.setAttributeIfAbsent(this, key, value);
     }
 
     public Object removeAttribute(Object key) {
-        if (key == null) {
-            throw new NullPointerException("key");
-        }
-
-        return attributes.remove(key);
+        return attributes.removeAttribute(this, key);
     }
 
     public boolean removeAttribute(Object key, Object value) {
-        if (key == null) {
-            throw new NullPointerException("key");
-        }
-
-        if (value == null) {
-            return false;
-        }
-
-        synchronized (attributes) {
-            if (value.equals(attributes.get(key))) {
-                attributes.remove(key);
-                return true;
-            }
-        }
-
-        return false;
+        return attributes.removeAttribute(this, key, value);
     }
 
     public boolean replaceAttribute(Object key, Object oldValue, Object newValue) {
-        synchronized (attributes) {
-            Object actualOldValue = attributes.get(key);
-            if (actualOldValue == null) {
-                return false;
-            }
-
-            if (actualOldValue.equals(oldValue)) {
-                attributes.put(key, newValue);
-                return true;
-            } else {
-                return false;
-            }
-        }
+        return attributes.replaceAttribute(this, key, oldValue, newValue);
     }
 
     public boolean containsAttribute(Object key) {
-        return attributes.containsKey(key);
+        return attributes.containsAttribute(this, key);
     }
 
     public Set<Object> getAttributeKeys() {
-        synchronized (attributes) {
-            return new HashSet<Object>(attributes.keySet());
-        }
+        return attributes.getAttributeKeys(this);
+    }
+    
+    protected void setAttributeMap(IoSessionAttributeMap attributes) {
+        this.attributes = attributes;
     }
 
     public TrafficMask getTrafficMask() {

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=589954&r1=589953&r2=589954&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 Mon Oct 29 21:04:50 2007
@@ -37,12 +37,12 @@
  */
 public class DefaultIoFilterChain implements IoFilterChain {
     /**
-     * A session attribute that stores a {@link ConnectFuture} related with
+     * A session attribute that stores an {@link IoFuture} related with
      * the {@link IoSession}.  {@link DefaultIoFilterChain} clears this
      * attribute and notifies the future when {@link #fireSessionOpened()}
-     * or {@link #fireExceptionCaught(Throwable)} is invoked
+     * or {@link #fireExceptionCaught(Throwable)} is invoked.
      */
-    public static final AttributeKey CONNECT_FUTURE = new AttributeKey(DefaultIoFilterChain.class, "connectFuture");
+    static final AttributeKey SESSION_OPENED_FUTURE = new AttributeKey(DefaultIoFilterChain.class, "connectFuture");
 
     private final AbstractIoSession session;
 
@@ -434,10 +434,8 @@
     }
 
     public void fireExceptionCaught(Throwable cause) {
-        // Notify the related ConnectFuture
-        // if the session is created from SocketConnector.
-        ConnectFuture future = (ConnectFuture) session
-                .removeAttribute(CONNECT_FUTURE);
+        // Notify the related future.
+        ConnectFuture future = (ConnectFuture) session.removeAttribute(SESSION_OPENED_FUTURE);
         if (future == null) {
             Entry head = this.head;
             callNextExceptionCaught(head, session, cause);
@@ -655,10 +653,8 @@
             try {
                 session.getHandler().sessionOpened(session);
             } finally {
-                // Notify the related ConnectFuture
-                // if the session is created from SocketConnector.
-                ConnectFuture future = (ConnectFuture) session
-                        .removeAttribute(CONNECT_FUTURE);
+                // Notify the related future.
+                ConnectFuture future = (ConnectFuture) session.removeAttribute(SESSION_OPENED_FUTURE);
                 if (future != null) {
                     future.setSession(session);
                 }

Added: mina/trunk/core/src/main/java/org/apache/mina/common/DefaultIoSessionAttributeMapFactory.java
URL: http://svn.apache.org/viewvc/mina/trunk/core/src/main/java/org/apache/mina/common/DefaultIoSessionAttributeMapFactory.java?rev=589954&view=auto
==============================================================================
--- mina/trunk/core/src/main/java/org/apache/mina/common/DefaultIoSessionAttributeMapFactory.java (added)
+++ mina/trunk/core/src/main/java/org/apache/mina/common/DefaultIoSessionAttributeMapFactory.java Mon Oct 29 21:04:50 2007
@@ -0,0 +1,164 @@
+/*
+ *  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;
+
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.Map;
+import java.util.Set;
+
+/**
+ * The default {@link IoSessionAttributeMapFactory} implementation
+ * that creates a new {@link HashMap}-based {@link IoSessionAttributeMap}
+ * instance per {@link IoSession}.
+ * 
+ * @author The Apache MINA Project (dev@mina.apache.org)
+ * @version $Rev$, $Date$
+ */
+public class DefaultIoSessionAttributeMapFactory implements
+        IoSessionAttributeMapFactory {
+
+    public IoSessionAttributeMap getAttributeMap(IoSession session)
+            throws Exception {
+        return new DefaultIoSessionAttributeMap();
+    }
+    
+    private static class DefaultIoSessionAttributeMap implements IoSessionAttributeMap {
+
+        private final Map<Object, Object> attributes =
+            Collections.synchronizedMap(new HashMap<Object, Object>(4));
+
+        public Object getAttribute(IoSession session, Object key) {
+            if (key == null) {
+                throw new NullPointerException("key");
+            }
+
+            return attributes.get(key);
+        }
+
+        public Object getAttribute(IoSession session, Object key, Object defaultValue) {
+            if (key == null) {
+                throw new NullPointerException("key");
+            }
+            if (defaultValue == null) {
+                return attributes.get(key);
+            }
+
+            Object answer = attributes.get(key);
+            if (answer == null) {
+                return defaultValue;
+            } else {
+                return answer;
+            }
+        }
+
+        public Object setAttribute(IoSession session, Object key, Object value) {
+            if (key == null) {
+                throw new NullPointerException("key");
+            }
+
+            if (value == null) {
+                return attributes.remove(key);
+            } else {
+                return attributes.put(key, value);
+            }
+        }
+
+        public Object setAttribute(IoSession session, Object key) {
+            return setAttribute(session, key, Boolean.TRUE);
+        }
+
+        public Object setAttributeIfAbsent(IoSession session, Object key, Object value) {
+            if (key == null) {
+                throw new NullPointerException("key");
+            }
+
+            if (value == null) {
+                return null;
+            }
+
+            Object oldValue;
+            synchronized (attributes) {
+                oldValue = attributes.get(key);
+                if (oldValue == null) {
+                    attributes.put(key, value);
+                }
+            }
+            return oldValue;
+        }
+
+        public Object removeAttribute(IoSession session, Object key) {
+            if (key == null) {
+                throw new NullPointerException("key");
+            }
+
+            return attributes.remove(key);
+        }
+
+        public boolean removeAttribute(IoSession session, Object key, Object value) {
+            if (key == null) {
+                throw new NullPointerException("key");
+            }
+
+            if (value == null) {
+                return false;
+            }
+
+            synchronized (attributes) {
+                if (value.equals(attributes.get(key))) {
+                    attributes.remove(key);
+                    return true;
+                }
+            }
+
+            return false;
+        }
+
+        public boolean replaceAttribute(IoSession session, Object key, Object oldValue, Object newValue) {
+            synchronized (attributes) {
+                Object actualOldValue = attributes.get(key);
+                if (actualOldValue == null) {
+                    return false;
+                }
+
+                if (actualOldValue.equals(oldValue)) {
+                    attributes.put(key, newValue);
+                    return true;
+                } else {
+                    return false;
+                }
+            }
+        }
+
+        public boolean containsAttribute(IoSession session, Object key) {
+            return attributes.containsKey(key);
+        }
+
+        public Set<Object> getAttributeKeys(IoSession session) {
+            synchronized (attributes) {
+                return new HashSet<Object>(attributes.keySet());
+            }
+        }
+
+        public void dispose(IoSession session) throws Exception {
+        }
+    }
+}

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

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

Modified: mina/trunk/core/src/main/java/org/apache/mina/common/DummySession.java
URL: http://svn.apache.org/viewvc/mina/trunk/core/src/main/java/org/apache/mina/common/DummySession.java?rev=589954&r1=589953&r2=589954&view=diff
==============================================================================
--- mina/trunk/core/src/main/java/org/apache/mina/common/DummySession.java (original)
+++ mina/trunk/core/src/main/java/org/apache/mina/common/DummySession.java Mon Oct 29 21:04:50 2007
@@ -114,6 +114,12 @@
             public void updateTrafficMask(IoSession session) {
             }
         };
+
+        try {
+            setAttributeMap(new DefaultIoSessionAttributeMapFactory().getAttributeMap(this));
+        } catch (Exception e) {
+            throw new InternalError();
+        }
     }
 
     public IoSessionConfig getConfig() {

Modified: mina/trunk/core/src/main/java/org/apache/mina/common/IoService.java
URL: http://svn.apache.org/viewvc/mina/trunk/core/src/main/java/org/apache/mina/common/IoService.java?rev=589954&r1=589953&r2=589954&view=diff
==============================================================================
--- mina/trunk/core/src/main/java/org/apache/mina/common/IoService.java (original)
+++ mina/trunk/core/src/main/java/org/apache/mina/common/IoService.java Mon Oct 29 21:04:50 2007
@@ -173,4 +173,16 @@
      * {@link IoSessions#broadcast(Object, java.util.Collection)}.
      */
     Set<WriteFuture> broadcast(Object message);
+    
+    /**
+     * Returns the {@link IoSessionAttributeMapFactory} that provides an
+     * {@link IoSessionAttributeMap} for a new session created by this service.
+     */
+    IoSessionAttributeMapFactory getSessionAttributeMapFactory();
+    
+    /**
+     * Sets the {@link IoSessionAttributeMapFactory} that provides an
+     * {@link IoSessionAttributeMap} for a new session created by this service.
+     */
+    void setSessionAttributeMapFactory(IoSessionAttributeMapFactory sessionAttributeMapFactory);
 }

Modified: mina/trunk/core/src/main/java/org/apache/mina/common/IoSession.java
URL: http://svn.apache.org/viewvc/mina/trunk/core/src/main/java/org/apache/mina/common/IoSession.java?rev=589954&r1=589953&r2=589954&view=diff
==============================================================================
--- mina/trunk/core/src/main/java/org/apache/mina/common/IoSession.java (original)
+++ mina/trunk/core/src/main/java/org/apache/mina/common/IoSession.java Mon Oct 29 21:04:50 2007
@@ -139,19 +139,22 @@
     /**
      * Returns an attachment of this session.
      * This method is identical with <tt>getAttribute( "" )</tt>.
+     * 
+     * @deprecated Use {@link #getAttribute(Object)} instead.
      */
-    Object getAttachment();
+    @Deprecated Object getAttachment();
 
     /**
      * Sets an attachment of this session.
      * This method is identical with <tt>setAttribute( "", attachment )</tt>.
      *
      * @return Old attachment.  <tt>null</tt> if it is new.
+     * @deprecated Use {@link #setAttribute(Object, Object)} instead.
      */
-    Object setAttachment(Object attachment);
+    @Deprecated Object setAttachment(Object attachment);
 
     /**
-     * Returns the value of user-defined attribute of this session.
+     * Returns the value of the user-defined attribute of this session.
      *
      * @param key the key of the attribute
      * @return <tt>null</tt> if there is no attribute with the specified key
@@ -160,7 +163,7 @@
 
     /**
      * Returns the value of user defined attribute associated with the
-     * specified key.  If there's no such attribute, the specified defalut
+     * specified key.  If there's no such attribute, the specified default
      * value is associated with the specified key, and the default value is
      * returned.  This method is same with the following code except that the
      * operation is performed atomically.

Added: mina/trunk/core/src/main/java/org/apache/mina/common/IoSessionAttributeMap.java
URL: http://svn.apache.org/viewvc/mina/trunk/core/src/main/java/org/apache/mina/common/IoSessionAttributeMap.java?rev=589954&view=auto
==============================================================================
--- mina/trunk/core/src/main/java/org/apache/mina/common/IoSessionAttributeMap.java (added)
+++ mina/trunk/core/src/main/java/org/apache/mina/common/IoSessionAttributeMap.java Mon Oct 29 21:04:50 2007
@@ -0,0 +1,147 @@
+/*
+ *  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;
+
+import java.util.Set;
+
+/**
+ * Stores the user-defined attributes which is provided per {@link IoSession}.
+ * All user-defined attribute accesses in {@link IoSession} are forwarded to
+ * the instance of {@link IoSessionAttributeMap}. 
+ * 
+ * @author The Apache MINA Project (dev@mina.apache.org)
+ * @version $Rev$, $Date$
+ */
+public interface IoSessionAttributeMap {
+
+    /**
+     * Returns the value of the user-defined attribute.
+     * @param key the key of the attribute
+     *
+     * @return <tt>null</tt> if there is no attribute with the specified key
+     */
+    Object getAttribute(IoSession session, Object key);
+
+    /**
+     * Returns the value of user defined attribute associated with the
+     * specified key.  If there's no such attribute, the specified default
+     * value is associated with the specified key, and the default value is
+     * returned.  This method is same with the following code except that the
+     * operation is performed atomically.
+     * <pre>
+     * if (containsAttribute(key)) {
+     *     return getAttribute(key);
+     * } else {
+     *     setAttribute(key, defaultValue);
+     *     return defaultValue;
+     * }
+     * </pre>
+     */
+    Object getAttribute(IoSession session, Object key, Object defaultValue);
+
+    /**
+     * Sets a user-defined attribute.
+     *
+     * @param key   the key of the attribute
+     * @param value the value of the attribute
+     * @return The old value of the attribute.  <tt>null</tt> if it is new.
+     */
+    Object setAttribute(IoSession session, Object key, Object value);
+
+    /**
+     * Sets a user defined attribute without a value.  This is useful when
+     * you just want to put a 'mark' attribute.  Its value is set to
+     * {@link Boolean#TRUE}.
+     *
+     * @param key the key of the attribute
+     * @return The old value of the attribute.  <tt>null</tt> if it is new.
+     */
+    Object setAttribute(IoSession session, Object key);
+
+    /**
+     * Sets a user defined attribute if the attribute with the specified key
+     * is not set yet.  This method is same with the following code except
+     * that the operation is performed atomically.
+     * <pre>
+     * if (containsAttribute(key)) {
+     *     return getAttribute(key);
+     * } else {
+     *     return setAttribute(key, value);
+     * }
+     * </pre>
+     */
+    Object setAttributeIfAbsent(IoSession session, Object key, Object value);
+
+    /**
+     * Removes a user-defined attribute with the specified key.
+     *
+     * @return The old value of the attribute.  <tt>null</tt> if not found.
+     */
+    Object removeAttribute(IoSession session, Object key);
+
+    /**
+     * Removes a user defined attribute with the specified key if the current
+     * attribute value is equal to the specified value.  This method is same
+     * with the following code except that the operation is performed
+     * atomically.
+     * <pre>
+     * if (containsAttribute(key) && getAttribute(key).equals(value)) {
+     *     removeAttribute(key);
+     *     return true;
+     * } else {
+     *     return false;
+     * }
+     * </pre>
+     */
+    boolean removeAttribute(IoSession session, Object key, Object value);
+
+    /**
+     * Replaces a user defined attribute with the specified key if the
+     * value of the attribute is equals to the specified old value.
+     * This method is same with the following code except that the operation
+     * is performed atomically.
+     * <pre>
+     * if (containsAttribute(key) && getAttribute(key).equals(oldValue)) {
+     *     setAttribute(key, newValue);
+     *     return true;
+     * } else {
+     *     return false;
+     * }
+     * </pre>
+     */
+    boolean replaceAttribute(IoSession session, Object key, Object oldValue, Object newValue);
+
+    /**
+     * Returns <tt>true</tt> if this session contains the attribute with
+     * the specified <tt>key</tt>.
+     */
+    boolean containsAttribute(IoSession session, Object key);
+
+    /**
+     * Returns the set of keys of all user-defined attributes.
+     */
+    Set<Object> getAttributeKeys(IoSession session);
+    
+    /**
+     * Disposes any releases associated with the specified session.
+     * This method is invoked on disconnection.
+     */
+    void dispose(IoSession session) throws Exception;
+}

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

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

Added: mina/trunk/core/src/main/java/org/apache/mina/common/IoSessionAttributeMapFactory.java
URL: http://svn.apache.org/viewvc/mina/trunk/core/src/main/java/org/apache/mina/common/IoSessionAttributeMapFactory.java?rev=589954&view=auto
==============================================================================
--- mina/trunk/core/src/main/java/org/apache/mina/common/IoSessionAttributeMapFactory.java (added)
+++ mina/trunk/core/src/main/java/org/apache/mina/common/IoSessionAttributeMapFactory.java Mon Oct 29 21:04:50 2007
@@ -0,0 +1,24 @@
+/*
+ *  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;
+
+public interface IoSessionAttributeMapFactory {
+    IoSessionAttributeMap getAttributeMap(IoSession session) throws Exception;
+}

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

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

Added: mina/trunk/core/src/main/java/org/apache/mina/common/IoSessionInitializationException.java
URL: http://svn.apache.org/viewvc/mina/trunk/core/src/main/java/org/apache/mina/common/IoSessionInitializationException.java?rev=589954&view=auto
==============================================================================
--- mina/trunk/core/src/main/java/org/apache/mina/common/IoSessionInitializationException.java (added)
+++ mina/trunk/core/src/main/java/org/apache/mina/common/IoSessionInitializationException.java Mon Oct 29 21:04:50 2007
@@ -0,0 +1,47 @@
+/*
+ *  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 {@link RuntimeException} that is thrown when the initialization of
+ * an {@link IoSession} fails.
+ * 
+ * @author The Apache MINA Project (dev@mina.apache.org)
+ * @version $Rev$, $Date$
+ */
+public class IoSessionInitializationException extends RuntimeException {
+    private static final long serialVersionUID = -1205810145763696189L;
+
+    public IoSessionInitializationException() {
+        super();
+    }
+
+    public IoSessionInitializationException(String message, Throwable cause) {
+        super(message, cause);
+    }
+
+    public IoSessionInitializationException(String message) {
+        super(message);
+    }
+
+    public IoSessionInitializationException(Throwable cause) {
+        super(cause);
+    }
+}

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

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

Modified: mina/trunk/core/src/main/java/org/apache/mina/transport/socket/nio/NioDatagramAcceptor.java
URL: http://svn.apache.org/viewvc/mina/trunk/core/src/main/java/org/apache/mina/transport/socket/nio/NioDatagramAcceptor.java?rev=589954&r1=589953&r2=589954&view=diff
==============================================================================
--- mina/trunk/core/src/main/java/org/apache/mina/transport/socket/nio/NioDatagramAcceptor.java (original)
+++ mina/trunk/core/src/main/java/org/apache/mina/transport/socket/nio/NioDatagramAcceptor.java Mon Oct 29 21:04:50 2007
@@ -194,6 +194,8 @@
             session = datagramSession;
         }
 
+        finishSessionInitialization(session, null);
+
         try {
             this.getFilterChainBuilder().buildFilterChain(session.getFilterChain());
             getListeners().fireSessionCreated(session);

Modified: mina/trunk/core/src/main/java/org/apache/mina/transport/socket/nio/NioSocketAcceptor.java
URL: http://svn.apache.org/viewvc/mina/trunk/core/src/main/java/org/apache/mina/transport/socket/nio/NioSocketAcceptor.java?rev=589954&r1=589953&r2=589954&view=diff
==============================================================================
--- mina/trunk/core/src/main/java/org/apache/mina/transport/socket/nio/NioSocketAcceptor.java (original)
+++ mina/trunk/core/src/main/java/org/apache/mina/transport/socket/nio/NioSocketAcceptor.java Mon Oct 29 21:04:50 2007
@@ -358,6 +358,8 @@
                     // BaseIoSession and is custom for socket-based sessions.
                     NioSocketSession session = new NioSocketSession(
                             NioSocketAcceptor.this, nextProcessor(), ch);
+                    
+                    finishSessionInitialization(session, null);
 
                     // add the session to the SocketIoProcessor
                     session.getProcessor().add(session);

Modified: mina/trunk/core/src/main/java/org/apache/mina/transport/vmpipe/VmPipeAcceptor.java
URL: http://svn.apache.org/viewvc/mina/trunk/core/src/main/java/org/apache/mina/transport/vmpipe/VmPipeAcceptor.java?rev=589954&r1=589953&r2=589954&view=diff
==============================================================================
--- mina/trunk/core/src/main/java/org/apache/mina/transport/vmpipe/VmPipeAcceptor.java (original)
+++ mina/trunk/core/src/main/java/org/apache/mina/transport/vmpipe/VmPipeAcceptor.java Mon Oct 29 21:04:50 2007
@@ -25,6 +25,7 @@
 import java.util.Map;
 
 import org.apache.mina.common.AbstractIoAcceptor;
+import org.apache.mina.common.IoFuture;
 import org.apache.mina.common.IoHandler;
 import org.apache.mina.common.IoSession;
 import org.apache.mina.common.TransportMetadata;
@@ -110,5 +111,11 @@
 
     public IoSession newSession(SocketAddress remoteAddress) {
         throw new UnsupportedOperationException();
+    }
+
+    @Override
+    protected void finishSessionInitialization(IoSession session,
+            IoFuture future) {
+        super.finishSessionInitialization(session, future);
     }
 }

Modified: mina/trunk/core/src/main/java/org/apache/mina/transport/vmpipe/VmPipeConnector.java
URL: http://svn.apache.org/viewvc/mina/trunk/core/src/main/java/org/apache/mina/transport/vmpipe/VmPipeConnector.java?rev=589954&r1=589953&r2=589954&view=diff
==============================================================================
--- mina/trunk/core/src/main/java/org/apache/mina/transport/vmpipe/VmPipeConnector.java (original)
+++ mina/trunk/core/src/main/java/org/apache/mina/transport/vmpipe/VmPipeConnector.java Mon Oct 29 21:04:50 2007
@@ -102,6 +102,7 @@
 
         // initialize acceptor session
         VmPipeSessionImpl remoteSession = localSession.getRemoteSession();
+        ((VmPipeAcceptor) remoteSession.getService()).finishSessionInitialization(remoteSession, null);
         try {
             IoFilterChain filterChain = remoteSession.getFilterChain();
             entry.getAcceptor().getFilterChainBuilder().buildFilterChain(

Modified: mina/trunk/core/src/test/java/org/apache/mina/common/IoServiceListenerSupportTest.java
URL: http://svn.apache.org/viewvc/mina/trunk/core/src/test/java/org/apache/mina/common/IoServiceListenerSupportTest.java?rev=589954&r1=589953&r2=589954&view=diff
==============================================================================
--- mina/trunk/core/src/test/java/org/apache/mina/common/IoServiceListenerSupportTest.java (original)
+++ mina/trunk/core/src/test/java/org/apache/mina/common/IoServiceListenerSupportTest.java Mon Oct 29 21:04:50 2007
@@ -146,7 +146,7 @@
         IoFilterChain chain = (IoFilterChain) chainControl.getMock();
         session.setFilterChain(chain);
 
-        MockControl listenerControl = MockControl
+        final MockControl listenerControl = MockControl
                 .createStrictControl(IoServiceListener.class);
         IoServiceListener listener = (IoServiceListener) listenerControl
                 .getMock();
@@ -190,12 +190,19 @@
                 } catch (InterruptedException e) {
                     e.printStackTrace();
                 }
-                support.fireSessionDestroyed(session);
+                // This synchronization block is a workaround for
+                // the visibility problem of simultaneous EasyMock
+                // state update. (not sure if it fixes the failing test yet.)
+                synchronized (listenerControl) {
+                    support.fireSessionDestroyed(session);
+                }
             }
         }.start();
         support.fireServiceDeactivated();
 
-        listenerControl.verify();
+        synchronized (listenerControl) {
+            listenerControl.verify();
+        }
         acceptorControl.verify();
         chainControl.verify();
 

Modified: mina/trunk/transport-apr/src/main/java/org/apache/mina/transport/socket/apr/AprConnector.java
URL: http://svn.apache.org/viewvc/mina/trunk/transport-apr/src/main/java/org/apache/mina/transport/socket/apr/AprConnector.java?rev=589954&r1=589953&r2=589954&view=diff
==============================================================================
--- mina/trunk/transport-apr/src/main/java/org/apache/mina/transport/socket/apr/AprConnector.java (original)
+++ mina/trunk/transport-apr/src/main/java/org/apache/mina/transport/socket/apr/AprConnector.java Mon Oct 29 21:04:50 2007
@@ -27,7 +27,6 @@
 import org.apache.mina.common.AbstractIoConnector;
 import org.apache.mina.common.ConnectFuture;
 import org.apache.mina.common.DefaultConnectFuture;
-import org.apache.mina.common.DefaultIoFilterChain;
 import org.apache.mina.common.IoConnector;
 import org.apache.mina.common.IoServiceListenerSupport;
 import org.apache.mina.common.TransportMetadata;
@@ -147,6 +146,8 @@
             System.err.println("proc : "+proc);
             AprSessionImpl session = new AprSessionImpl(this,proc ,
                     clientSock, sockAddr, (InetSocketAddress) localAddress);
+            
+            finishSessionInitialization(session, future);
 
             try {
                 getFilterChainBuilder().buildFilterChain(
@@ -156,12 +157,8 @@
                         "Failed to create a session.").initCause(e);
             }
 
-            // Set the ConnectFuture of the specified session, which will be
-            // removed and notified by AbstractIoFilterChain eventually.
-            session.setAttribute(DefaultIoFilterChain.CONNECT_FUTURE, future);
-
             // Forward the remaining process to the APRIoProcessor.
-            // it's will validate the COnnectFuture when the session is in the poll set
+            // it's will validate the ConnectFuture when the session is in the poll set
             session.getIoProcessor().add(session);
             return future;
         } catch (Exception e) {

Modified: mina/trunk/transport-apr/src/main/java/org/apache/mina/transport/socket/apr/AprIoProcessor.java
URL: http://svn.apache.org/viewvc/mina/trunk/transport-apr/src/main/java/org/apache/mina/transport/socket/apr/AprIoProcessor.java?rev=589954&r1=589953&r2=589954&view=diff
==============================================================================
--- mina/trunk/transport-apr/src/main/java/org/apache/mina/transport/socket/apr/AprIoProcessor.java (original)
+++ mina/trunk/transport-apr/src/main/java/org/apache/mina/transport/socket/apr/AprIoProcessor.java Mon Oct 29 21:04:50 2007
@@ -27,8 +27,8 @@
 
 import org.apache.mina.common.AbstractIoProcessor;
 import org.apache.mina.common.AbstractIoSession;
-import org.apache.mina.common.IoBuffer;
 import org.apache.mina.common.FileRegion;
+import org.apache.mina.common.IoBuffer;
 import org.apache.mina.common.IoSession;
 import org.apache.tomcat.jni.Error;
 import org.apache.tomcat.jni.Poll;
@@ -58,7 +58,7 @@
 
         public AbstractIoSession next() {
             AprSessionImpl sess = i.next();
-            return (AbstractIoSession) sess;
+            return sess;
         }
 
         public void remove() {

Modified: mina/trunk/transport-serial/src/main/java/org/apache/mina/transport/serial/SerialConnector.java
URL: http://svn.apache.org/viewvc/mina/trunk/transport-serial/src/main/java/org/apache/mina/transport/serial/SerialConnector.java?rev=589954&r1=589953&r2=589954&view=diff
==============================================================================
--- mina/trunk/transport-serial/src/main/java/org/apache/mina/transport/serial/SerialConnector.java (original)
+++ mina/trunk/transport-serial/src/main/java/org/apache/mina/transport/serial/SerialConnector.java Mon Oct 29 21:04:50 2007
@@ -91,8 +91,8 @@
                         ConnectFuture future = new DefaultConnectFuture();
                         SerialSessionImpl session = new SerialSessionImpl(
                                 this, portAddress, serialPort);
+                        finishSessionInitialization(session, future);
                         session.start();
-                        future.setSession(session);
                         return future;
                     } catch (PortInUseException e) {
                         if (log.isDebugEnabled()) {