Author: jvermillard
Date: Wed Feb 15 15:22:50 2012
New Revision: 1244531

URL: http://svn.apache.org/viewvc?rev=1244531&view=rev
Log:
DIRMINA-850 idle checker (WIP)

Added:
    mina/trunk/core/src/main/java/org/apache/mina/service/idlechecker/
    
mina/trunk/core/src/main/java/org/apache/mina/service/idlechecker/IdleChecker.java
   (with props)
    
mina/trunk/core/src/main/java/org/apache/mina/service/idlechecker/IndexedIdleChecker.java
   (with props)
Modified:
    mina/trunk/core/src/main/java/org/apache/mina/api/IdleStatus.java
    mina/trunk/core/src/main/java/org/apache/mina/api/IoSession.java
    mina/trunk/core/src/main/java/org/apache/mina/api/IoSessionConfig.java
    mina/trunk/core/src/main/java/org/apache/mina/session/AbstractIoSession.java
    
mina/trunk/core/src/main/java/org/apache/mina/transport/tcp/DefaultSocketSessionConfig.java
    
mina/trunk/core/src/main/java/org/apache/mina/transport/tcp/NioSelectorProcessor.java
    
mina/trunk/core/src/main/java/org/apache/mina/transport/tcp/ProxySocketSessionConfig.java
    
mina/trunk/core/src/main/java/org/apache/mina/transport/tcp/nio/NioTcpServer.java
    
mina/trunk/core/src/test/java/org/apache/mina/session/AbstractIoSessionTest.java
    
mina/trunk/core/src/test/java/org/apache/mina/transport/tcp/ProxySocketSessionConfigTest.java

Modified: mina/trunk/core/src/main/java/org/apache/mina/api/IdleStatus.java
URL: 
http://svn.apache.org/viewvc/mina/trunk/core/src/main/java/org/apache/mina/api/IdleStatus.java?rev=1244531&r1=1244530&r2=1244531&view=diff
==============================================================================
--- mina/trunk/core/src/main/java/org/apache/mina/api/IdleStatus.java (original)
+++ mina/trunk/core/src/main/java/org/apache/mina/api/IdleStatus.java Wed Feb 
15 15:22:50 2012
@@ -25,13 +25,12 @@ package org.apache.mina.api;
  * <ul>
  * <li>{@link #READ_IDLE} - No data is coming from the remote peer.</li>
  * <li>{@link #WRITE_IDLE} - Session is not writing any data.</li>
- * <li>{@link #READ_WRITE_IDLE} - Both {@link #READ_IDLE} and {@link 
#WRITE_IDLE}.</li>
  * </ul>
  *
  * @author <a href="http://mina.apache.org";>Apache MINA Project</a>
  */
 public enum IdleStatus {
-    READ_IDLE("read idle"), WRITE_IDLE("write idle"), READ_WRITE_IDLE("both 
idle");
+    READ_IDLE("read idle"), WRITE_IDLE("write idle");
 
     private final String description;
 

Modified: mina/trunk/core/src/main/java/org/apache/mina/api/IoSession.java
URL: 
http://svn.apache.org/viewvc/mina/trunk/core/src/main/java/org/apache/mina/api/IoSession.java?rev=1244531&r1=1244530&r2=1244531&view=diff
==============================================================================
--- mina/trunk/core/src/main/java/org/apache/mina/api/IoSession.java (original)
+++ mina/trunk/core/src/main/java/org/apache/mina/api/IoSession.java Wed Feb 15 
15:22:50 2012
@@ -266,6 +266,7 @@ public interface IoSession {
     long getLastWriteTime();
 
     /* Session context management */
+
     /**
      * Returns the value of the user-defined attribute for the given
      * <code>key</code>.If the there is no attribute with the specified key 
the <tt>defaultValue</tt> will be returned.
@@ -280,6 +281,19 @@ public interface IoSession {
     <T> T getAttribute(AttributeKey<T> key, T defaultValue);
 
     /**
+     * Returns the value of the user-defined attribute for the given
+     * <code>key</code>.If the there is no attribute with the specified key 
<code>null</code> will be returned.
+     * 
+     * @param key
+     *            the attribute's key, must not be <code>null</code>
+     * @return <code>null</code> if there is no attribute with the specified 
key
+     * @exception IllegalArgumentException
+     *                if <code>key==null</code>
+     * @see #setAttribute(AttributeKey, Object)
+     */
+    <T> T getAttribute(AttributeKey<T> key);
+
+    /**
      * Sets a user-defined attribute. If the <code>value</code> is
      * <code>null</code> the attribute will be removed from this
      * {@link IoSession}.

Modified: mina/trunk/core/src/main/java/org/apache/mina/api/IoSessionConfig.java
URL: 
http://svn.apache.org/viewvc/mina/trunk/core/src/main/java/org/apache/mina/api/IoSessionConfig.java?rev=1244531&r1=1244530&r2=1244531&view=diff
==============================================================================
--- mina/trunk/core/src/main/java/org/apache/mina/api/IoSessionConfig.java 
(original)
+++ mina/trunk/core/src/main/java/org/apache/mina/api/IoSessionConfig.java Wed 
Feb 15 15:22:50 2012
@@ -28,8 +28,8 @@ public interface IoSessionConfig {
 
     /**
      * Returns idle time for the specified type of idleness in milli-seconds.
-     *
      * @see IdleStatus
+     * @return the idle time in ms or <code>-1</code> if no idle time 
configured for this status
      */
     long getIdleTimeInMillis(IdleStatus status);
 
@@ -38,7 +38,7 @@ public interface IoSessionConfig {
      * operation type (read/write/both) @see IdleStatus
      *
      * @param status          the type of idle (read/write/both) timeout to set
-     * @param ildeTimeInMilli the timeout in milliseconds
+     * @param ildeTimeInMilli the timeout in milliseconds (<code>-1</code> for 
no idle detection on this status)
      */
     void setIdleTimeInMillis(IdleStatus status, long ildeTimeInMilli);
 

Added: 
mina/trunk/core/src/main/java/org/apache/mina/service/idlechecker/IdleChecker.java
URL: 
http://svn.apache.org/viewvc/mina/trunk/core/src/main/java/org/apache/mina/service/idlechecker/IdleChecker.java?rev=1244531&view=auto
==============================================================================
--- 
mina/trunk/core/src/main/java/org/apache/mina/service/idlechecker/IdleChecker.java
 (added)
+++ 
mina/trunk/core/src/main/java/org/apache/mina/service/idlechecker/IdleChecker.java
 Wed Feb 15 15:22:50 2012
@@ -0,0 +1,31 @@
+/**
+ * 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.service.idlechecker;
+
+import org.apache.mina.session.AbstractIoSession;
+
+public interface IdleChecker {
+
+    void sessionWritten(AbstractIoSession session, long time);
+
+    void sessionRead(AbstractIoSession session, long time);
+
+    int processIdleSession(long time);
+
+}

Propchange: 
mina/trunk/core/src/main/java/org/apache/mina/service/idlechecker/IdleChecker.java
------------------------------------------------------------------------------
    svn:mime-type = text/plain

Added: 
mina/trunk/core/src/main/java/org/apache/mina/service/idlechecker/IndexedIdleChecker.java
URL: 
http://svn.apache.org/viewvc/mina/trunk/core/src/main/java/org/apache/mina/service/idlechecker/IndexedIdleChecker.java?rev=1244531&view=auto
==============================================================================
--- 
mina/trunk/core/src/main/java/org/apache/mina/service/idlechecker/IndexedIdleChecker.java
 (added)
+++ 
mina/trunk/core/src/main/java/org/apache/mina/service/idlechecker/IndexedIdleChecker.java
 Wed Feb 15 15:22:50 2012
@@ -0,0 +1,165 @@
+/**
+ * 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.service.idlechecker;
+
+import java.util.HashSet;
+import java.util.Set;
+
+import org.apache.mina.api.IdleStatus;
+import org.apache.mina.session.AbstractIoSession;
+import org.apache.mina.session.AttributeKey;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+public class IndexedIdleChecker implements IdleChecker {
+
+    private static int MAX_IDLE_TIME_IN_SEC = 60 * 60; // 1 hour max idle
+
+    private static long MAX_IDLE_TIME_IN_MS = MAX_IDLE_TIME_IN_SEC * 1000L; // 
1 hour max idle
+
+    private static final Logger LOG = 
LoggerFactory.getLogger(IndexedIdleChecker.class);
+
+    private static final AttributeKey<Integer> READ_IDLE_INDEX = 
AttributeKey.createKey(Integer.class,
+            "idle.read.index");
+
+    private static final AttributeKey<Integer> WRITE_IDLE_INDEX = 
AttributeKey.createKey(Integer.class,
+            "idle.write.index");
+
+    private long lastCheckTime = 0L;
+
+    @SuppressWarnings("unchecked")
+    private Set<AbstractIoSession>[] readIdleSessionIndex = new 
Set[MAX_IDLE_TIME_IN_SEC];
+
+    @SuppressWarnings("unchecked")
+    private Set<AbstractIoSession>[] writeIdleSessionIndex = new 
Set[MAX_IDLE_TIME_IN_SEC];
+
+    /**
+     * {@inheritDoc}
+     */
+    @Override
+    public void sessionRead(AbstractIoSession session, long timeInMs) {
+        LOG.debug("session read event, compute idle index of session {}", 
session);
+
+        // remove from the old index position
+        Integer oldIndex = session.getAttribute(READ_IDLE_INDEX);
+        if (oldIndex != null && readIdleSessionIndex[oldIndex] != null) {
+            LOG.debug("remove for old index {}", oldIndex);
+            readIdleSessionIndex[oldIndex].remove(session);
+        }
+
+        long idleTimeInMs = 
session.getConfig().getIdleTimeInMillis(IdleStatus.READ_IDLE);
+        // is idle enabled ?
+        if (idleTimeInMs <= 0L) {
+            LOG.debug("no read idle configuration");
+        } else {
+            int nextIdleTimeInSeconds = (int) ((timeInMs + idleTimeInMs) / 
1000L);
+            int index = nextIdleTimeInSeconds % MAX_IDLE_TIME_IN_SEC;
+            if (readIdleSessionIndex[index] == null) {
+                readIdleSessionIndex[index] = new HashSet<AbstractIoSession>();
+            }
+
+            readIdleSessionIndex[index].add(session);
+            session.setAttribute(READ_IDLE_INDEX, index);
+        }
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    @Override
+    public void sessionWritten(AbstractIoSession session, long timeInMs) {
+        LOG.debug("session write event, compute idle index of session {}", 
session);
+
+        // remove from the old index position
+        Integer oldIndex = session.getAttribute(WRITE_IDLE_INDEX);
+        if (oldIndex != null && writeIdleSessionIndex[oldIndex] != null) {
+            LOG.debug("remove for old index {}", oldIndex);
+            writeIdleSessionIndex[oldIndex].remove(session);
+        }
+
+        long idleTimeInMs = 
session.getConfig().getIdleTimeInMillis(IdleStatus.WRITE_IDLE);
+        // is idle enabled ?
+        if (idleTimeInMs <= 0L) {
+            LOG.debug("no write idle configuration");
+        } else {
+            int nextIdleTimeInSeconds = (int) ((timeInMs + idleTimeInMs) / 
1000L);
+            int index = nextIdleTimeInSeconds % MAX_IDLE_TIME_IN_SEC;
+            if (writeIdleSessionIndex[index] == null) {
+                writeIdleSessionIndex[index] = new 
HashSet<AbstractIoSession>();
+            }
+
+            writeIdleSessionIndex[index].add(session);
+            session.setAttribute(WRITE_IDLE_INDEX, index);
+        }
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    @Override
+    public int processIdleSession(long time) {
+        int counter = 0;
+        long delta = time - lastCheckTime;
+
+        if (LOG.isDebugEnabled()) {
+            LOG.debug("checking idle time, last = {}, now = {}, delta = {}",
+                    new Object[] { lastCheckTime, time, delta });
+        }
+
+        if (delta < 1000) {
+            LOG.debug("not a second between the last checks, abort");
+            return 0;
+        }
+
+        int startIdx = ((int) (Math.max(lastCheckTime, time - 
MAX_IDLE_TIME_IN_MS) / 1000L)) % MAX_IDLE_TIME_IN_SEC;
+        int endIdx = ((int) (time / 1000L)) % MAX_IDLE_TIME_IN_SEC;
+
+        for (int index = startIdx; index != endIdx; index = (index + 1) % 
MAX_IDLE_TIME_IN_SEC) {
+            // look at the read idle index
+            counter += processIndex(readIdleSessionIndex, index, 
IdleStatus.READ_IDLE);
+            counter += processIndex(writeIdleSessionIndex, index, 
IdleStatus.WRITE_IDLE);
+
+        }
+        // save last check time for next call
+        lastCheckTime = time;
+        LOG.debug("detected {} idleing sessions", counter);
+        return counter;
+    }
+
+    private int processIndex(Set<AbstractIoSession>[] indexByTime, int 
position, IdleStatus status) {
+        Set<AbstractIoSession> sessions = indexByTime[position];
+        if (sessions == null) {
+            return 0;
+        }
+
+        int counter = 0;
+
+        for (AbstractIoSession idleSession : sessions) {
+            idleSession.setAttribute(status == IdleStatus.READ_IDLE ? 
READ_IDLE_INDEX : WRITE_IDLE_INDEX, null);
+            // check if idle detection wasn't disabled since the index update
+            if (idleSession.getConfig().getIdleTimeInMillis(status) > 0) {
+                idleSession.processSessionIdle(status);
+            }
+            counter++;
+        }
+        // clear the processed index entry 
+        indexByTime[position] = null;
+        return counter;
+    }
+}

Propchange: 
mina/trunk/core/src/main/java/org/apache/mina/service/idlechecker/IndexedIdleChecker.java
------------------------------------------------------------------------------
    svn:mime-type = text/plain

Modified: 
mina/trunk/core/src/main/java/org/apache/mina/session/AbstractIoSession.java
URL: 
http://svn.apache.org/viewvc/mina/trunk/core/src/main/java/org/apache/mina/session/AbstractIoSession.java?rev=1244531&r1=1244530&r2=1244531&view=diff
==============================================================================
--- 
mina/trunk/core/src/main/java/org/apache/mina/session/AbstractIoSession.java 
(original)
+++ 
mina/trunk/core/src/main/java/org/apache/mina/session/AbstractIoSession.java 
Wed Feb 15 15:22:50 2012
@@ -24,7 +24,7 @@ import java.util.Collections;
 import java.util.Queue;
 import java.util.Set;
 import java.util.concurrent.atomic.AtomicBoolean;
-import java.util.concurrent.atomic.AtomicLong;
+import java.util.concurrent.atomic.AtomicInteger;
 import java.util.concurrent.locks.Lock;
 import java.util.concurrent.locks.ReadWriteLock;
 import java.util.concurrent.locks.ReentrantReadWriteLock;
@@ -32,6 +32,7 @@ import java.util.concurrent.locks.Reentr
 import javax.net.ssl.SSLContext;
 import javax.net.ssl.SSLException;
 
+import org.apache.mina.api.IdleStatus;
 import org.apache.mina.api.IoFilter;
 import org.apache.mina.api.IoFuture;
 import org.apache.mina.api.IoService;
@@ -52,7 +53,7 @@ public abstract class AbstractIoSession 
     private static final Logger LOG = 
LoggerFactory.getLogger(AbstractIoSession.class);
 
     /** unique identifier generator */
-    private static final AtomicLong NEXT_ID = new AtomicLong(0);
+    private static final AtomicInteger NEXT_ID = new AtomicInteger(0);
 
     /** The session's unique identifier */
     private final long id;
@@ -378,6 +379,14 @@ public abstract class AbstractIoSession 
     }
 
     /**
+     * To be called by the internal plumber when some bytes are written on the 
socket
+     * @param bytesCount number of extra bytes written
+     */
+    public void incrementWrittenBytes(int bytesCount) {
+        writtenBytes += bytesCount;
+    }
+
+    /**
      * {@inheritDoc}
      */
     @Override
@@ -431,6 +440,17 @@ public abstract class AbstractIoSession 
     /**
      * {@inheritDoc}
      * 
+     * @exception IllegalArgumentException if <code>key==null</code>
+     * @see #setAttribute(AttributeKey, Object)
+     */
+    @Override
+    public final <T> T getAttribute(AttributeKey<T> key) {
+        return attributes.getAttribute(key);
+    }
+
+    /**
+     * {@inheritDoc}
+     * 
      * @exception IllegalArgumentException
      * <ul>
      *   <li>
@@ -598,6 +618,17 @@ public abstract class AbstractIoSession 
     }
 
     /**
+     * process session idle event using the filter chain. To be called by the 
session {@link SelectorProcessor} .
+     */
+    public void processSessionIdle(IdleStatus status) {
+        LOG.debug("processing session idle {} event for session {}", status, 
this);
+
+        for (IoFilter filter : chain) {
+            filter.sessionIdle(this, status);
+        }
+    }
+
+    /**
      * process session message received event using the filter chain. To be 
called by the session {@link SelectorProcessor} .
      * @param message the received message 
      */

Modified: 
mina/trunk/core/src/main/java/org/apache/mina/transport/tcp/DefaultSocketSessionConfig.java
URL: 
http://svn.apache.org/viewvc/mina/trunk/core/src/main/java/org/apache/mina/transport/tcp/DefaultSocketSessionConfig.java?rev=1244531&r1=1244530&r2=1244531&view=diff
==============================================================================
--- 
mina/trunk/core/src/main/java/org/apache/mina/transport/tcp/DefaultSocketSessionConfig.java
 (original)
+++ 
mina/trunk/core/src/main/java/org/apache/mina/transport/tcp/DefaultSocketSessionConfig.java
 Wed Feb 15 15:22:50 2012
@@ -37,8 +37,9 @@ public class DefaultSocketSessionConfig 
 
     private long idleTimeWrite = -1;
 
-    private long idleTimeReadWrite = -1;
-
+    /**
+     * {@inheritDoc}
+     */
     @Override
     public long getIdleTimeInMillis(IdleStatus status) {
         switch (status) {
@@ -46,13 +47,14 @@ public class DefaultSocketSessionConfig 
             return idleTimeRead;
         case WRITE_IDLE:
             return idleTimeWrite;
-        case READ_WRITE_IDLE:
-            return idleTimeReadWrite;
         default:
             throw new RuntimeException("unexpected excetion, unknown idle 
status : " + status);
         }
     }
 
+    /**
+     * {@inheritDoc}
+     */
     @Override
     public void setIdleTimeInMillis(IdleStatus status, long ildeTimeInMilli) {
         switch (status) {
@@ -62,9 +64,6 @@ public class DefaultSocketSessionConfig 
         case WRITE_IDLE:
             this.idleTimeWrite = ildeTimeInMilli;
             break;
-        case READ_WRITE_IDLE:
-            this.idleTimeReadWrite = ildeTimeInMilli;
-            break;
         default:
             throw new RuntimeException("unexpected excetion, unknown idle 
status : " + status);
         }
@@ -76,11 +75,17 @@ public class DefaultSocketSessionConfig 
 
     private Integer receiveBufferSize = null;
 
+    /**
+     * {@inheritDoc}
+     */
     @Override
     public Integer getReceiveBufferSize() {
         return receiveBufferSize;
     }
 
+    /**
+     * {@inheritDoc}
+     */
     @Override
     public void setReceiveBufferSize(int receiveBufferSize) {
         this.receiveBufferSize = receiveBufferSize;
@@ -88,11 +93,17 @@ public class DefaultSocketSessionConfig 
 
     private Integer sendBufferSize = null;
 
+    /**
+     * {@inheritDoc}
+     */
     @Override
     public Integer getSendBufferSize() {
         return sendBufferSize;
     }
 
+    /**
+     * {@inheritDoc}
+     */
     @Override
     public void setSendBufferSize(int sendBufferSize) {
         this.sendBufferSize = sendBufferSize;
@@ -104,11 +115,17 @@ public class DefaultSocketSessionConfig 
 
     private Boolean tcpNoDelay = null;
 
+    /**
+     * {@inheritDoc}
+     */
     @Override
     public Boolean isTcpNoDelay() {
         return tcpNoDelay;
     }
 
+    /**
+     * {@inheritDoc}
+     */
     @Override
     public void setTcpNoDelay(boolean tcpNoDelay) {
         this.tcpNoDelay = tcpNoDelay;
@@ -116,11 +133,17 @@ public class DefaultSocketSessionConfig 
 
     private Boolean reuseAddress = null;
 
+    /**
+     * {@inheritDoc}
+     */
     @Override
     public Boolean isReuseAddress() {
         return reuseAddress;
     }
 
+    /**
+     * {@inheritDoc}
+     */
     @Override
     public void setReuseAddress(boolean reuseAddress) {
         this.reuseAddress = reuseAddress;
@@ -128,11 +151,17 @@ public class DefaultSocketSessionConfig 
 
     private Integer trafficClass;
 
+    /**
+     * {@inheritDoc}
+     */
     @Override
     public Integer getTrafficClass() {
         return trafficClass;
     }
 
+    /**
+     * {@inheritDoc}
+     */
     @Override
     public void setTrafficClass(int trafficClass) {
         this.trafficClass = trafficClass;
@@ -140,11 +169,17 @@ public class DefaultSocketSessionConfig 
 
     private Boolean keepAlive = null;
 
+    /**
+     * {@inheritDoc}
+     */
     @Override
     public Boolean isKeepAlive() {
         return keepAlive;
     }
 
+    /**
+     * {@inheritDoc}
+     */
     @Override
     public void setKeepAlive(boolean keepAlive) {
         this.keepAlive = keepAlive;
@@ -152,11 +187,17 @@ public class DefaultSocketSessionConfig 
 
     private Boolean oobInline = null;
 
+    /**
+     * {@inheritDoc}
+     */
     @Override
     public Boolean isOobInline() {
         return oobInline;
     }
 
+    /**
+     * {@inheritDoc}
+     */
     @Override
     public void setOobInline(boolean oobInline) {
         this.oobInline = oobInline;
@@ -165,11 +206,17 @@ public class DefaultSocketSessionConfig 
 
     private Integer soLinger;
 
+    /**
+     * {@inheritDoc}
+     */
     @Override
     public Integer getSoLinger() {
         return soLinger;
     }
 
+    /**
+     * {@inheritDoc}
+     */
     @Override
     public void setSoLinger(int soLinger) {
         this.soLinger = soLinger;

Modified: 
mina/trunk/core/src/main/java/org/apache/mina/transport/tcp/NioSelectorProcessor.java
URL: 
http://svn.apache.org/viewvc/mina/trunk/core/src/main/java/org/apache/mina/transport/tcp/NioSelectorProcessor.java?rev=1244531&r1=1244530&r2=1244531&view=diff
==============================================================================
--- 
mina/trunk/core/src/main/java/org/apache/mina/transport/tcp/NioSelectorProcessor.java
 (original)
+++ 
mina/trunk/core/src/main/java/org/apache/mina/transport/tcp/NioSelectorProcessor.java
 Wed Feb 15 15:22:50 2012
@@ -40,6 +40,7 @@ import java.util.concurrent.locks.Reentr
 
 import javax.net.ssl.SSLException;
 
+import org.apache.mina.api.IdleStatus;
 import org.apache.mina.api.IoServer;
 import org.apache.mina.api.IoService;
 import org.apache.mina.api.IoSession;
@@ -47,6 +48,8 @@ import org.apache.mina.api.RuntimeIoExce
 import org.apache.mina.service.AbstractIoService;
 import org.apache.mina.service.SelectorProcessor;
 import org.apache.mina.service.SelectorStrategy;
+import org.apache.mina.service.idlechecker.IdleChecker;
+import org.apache.mina.service.idlechecker.IndexedIdleChecker;
 import org.apache.mina.session.AbstractIoSession;
 import org.apache.mina.session.DefaultWriteFuture;
 import org.apache.mina.session.SslHelper;
@@ -80,6 +83,9 @@ public class NioSelectorProcessor implem
     /** the thread polling and processing the I/O events */
     private SelectorWorker worker = null;
 
+    /** helper for detecting idleing sessions */
+    private IdleChecker idleChecker = new IndexedIdleChecker();
+
     /** A queue containing the servers to bind to this selector */
     private final Queue<Object[]> serversToAdd = new 
ConcurrentLinkedQueue<Object[]>();
 
@@ -185,6 +191,11 @@ public class NioSelectorProcessor implem
             LOGGER.error("Unexpected exception, while configuring socket as 
non blocking", e);
             throw new RuntimeIoException("cannot configure socket as 
non-blocking", e);
         }
+        // apply idle configuration
+        session.getConfig().setIdleTimeInMillis(IdleStatus.READ_IDLE,
+                defaultConfig.getIdleTimeInMillis(IdleStatus.READ_IDLE));
+        session.getConfig().setIdleTimeInMillis(IdleStatus.WRITE_IDLE,
+                defaultConfig.getIdleTimeInMillis(IdleStatus.WRITE_IDLE));
 
         // apply the default service socket configuration
         Boolean keepAlive = defaultConfig.isKeepAlive();
@@ -360,6 +371,9 @@ public class NioSelectorProcessor implem
                     } finally {
                         workerLock.unlock();
                     }
+
+                    // check for idle events
+                    idleChecker.processIdleSession(System.currentTimeMillis());
                 }
             } catch (Exception e) {
                 LOGGER.error("Unexpected exception : ", e);
@@ -414,6 +428,9 @@ public class NioSelectorProcessor implem
                     // fire the event
                     ((AbstractIoService) 
session.getService()).fireSessionCreated(session);
                     session.processSessionOpened();
+                    long time = System.currentTimeMillis();
+                    idleChecker.sessionRead(session, time);
+                    idleChecker.sessionWritten(session, time);
                 }
             }
         }
@@ -485,6 +502,8 @@ public class NioSelectorProcessor implem
                     // Plain message, not encrypted : go directly to the chain
                     session.processMessageReceived(readBuffer);
                 }
+
+                idleChecker.sessionRead(session, System.currentTimeMillis());
             }
         }
 
@@ -517,10 +536,10 @@ public class NioSelectorProcessor implem
                     // Note that if the connection is secured, the buffer 
already
                     // contains encrypted data.
                     int wrote = session.getSocketChannel().write(buf);
+                    session.incrementWrittenBytes(wrote);
+                    LOGGER.debug("wrote {} bytes to {}", wrote, session);
 
-                    if (LOGGER.isDebugEnabled()) {
-                        LOGGER.debug("wrote {} bytes to {}", wrote, session);
-                    }
+                    idleChecker.sessionWritten(session, 
System.currentTimeMillis());
 
                     if (buf.remaining() == 0) {
                         // completed write request, let's remove it

Modified: 
mina/trunk/core/src/main/java/org/apache/mina/transport/tcp/ProxySocketSessionConfig.java
URL: 
http://svn.apache.org/viewvc/mina/trunk/core/src/main/java/org/apache/mina/transport/tcp/ProxySocketSessionConfig.java?rev=1244531&r1=1244530&r2=1244531&view=diff
==============================================================================
--- 
mina/trunk/core/src/main/java/org/apache/mina/transport/tcp/ProxySocketSessionConfig.java
 (original)
+++ 
mina/trunk/core/src/main/java/org/apache/mina/transport/tcp/ProxySocketSessionConfig.java
 Wed Feb 15 15:22:50 2012
@@ -45,23 +45,24 @@ public class ProxySocketSessionConfig im
 
     private long idleTimeWrite = -1;
 
-    private long idleTimeReadWrite = -1;
-
+    /**
+     * {@inheritDoc}
+     */
     @Override
     public long getIdleTimeInMillis(IdleStatus status) {
         switch (status) {
         case READ_IDLE:
             return idleTimeRead;
-
         case WRITE_IDLE:
             return idleTimeWrite;
-        case READ_WRITE_IDLE:
-            return idleTimeReadWrite;
         default:
             throw new RuntimeException("unexpected excetion, unknown idle 
status : " + status);
         }
     }
 
+    /**
+     * {@inheritDoc}
+     */
     @Override
     public void setIdleTimeInMillis(IdleStatus status, long ildeTimeInMilli) {
         switch (status) {
@@ -71,14 +72,14 @@ public class ProxySocketSessionConfig im
         case WRITE_IDLE:
             this.idleTimeWrite = ildeTimeInMilli;
             break;
-        case READ_WRITE_IDLE:
-            this.idleTimeReadWrite = ildeTimeInMilli;
-            break;
         default:
             throw new RuntimeException("unexpected excetion, unknown idle 
status : " + status);
         }
     }
 
+    /**
+     * {@inheritDoc}
+     */
     @Override
     public Boolean isTcpNoDelay() {
         try {
@@ -88,6 +89,9 @@ public class ProxySocketSessionConfig im
         }
     }
 
+    /**
+     * {@inheritDoc}
+     */
     @Override
     public void setTcpNoDelay(boolean tcpNoDelay) {
         LOG.debug("set TCP no delay '{}' for session '{}'", tcpNoDelay, this);
@@ -98,6 +102,9 @@ public class ProxySocketSessionConfig im
         }
     }
 
+    /**
+     * {@inheritDoc}
+     */
     @Override
     public Boolean isReuseAddress() {
         try {
@@ -107,6 +114,9 @@ public class ProxySocketSessionConfig im
         }
     }
 
+    /**
+     * {@inheritDoc}
+     */
     @Override
     public void setReuseAddress(boolean reuseAddress) {
         LOG.debug("set reuse address '{}' for session '{}'", reuseAddress, 
this);
@@ -117,6 +127,9 @@ public class ProxySocketSessionConfig im
         }
     }
 
+    /**
+     * {@inheritDoc}
+     */
     @Override
     public Integer getReceiveBufferSize() {
         try {
@@ -126,6 +139,9 @@ public class ProxySocketSessionConfig im
         }
     }
 
+    /**
+     * {@inheritDoc}
+     */
     @Override
     public void setReceiveBufferSize(int receiveBufferSize) {
         LOG.debug("set receive buffer size '{}' for session '{}'", 
receiveBufferSize, this);
@@ -136,6 +152,9 @@ public class ProxySocketSessionConfig im
         }
     }
 
+    /**
+     * {@inheritDoc}
+     */
     @Override
     public Integer getSendBufferSize() {
         try {
@@ -145,6 +164,9 @@ public class ProxySocketSessionConfig im
         }
     }
 
+    /**
+     * {@inheritDoc}
+     */
     @Override
     public void setSendBufferSize(int sendBufferSize) {
         LOG.debug("set send buffer size '{}' for session '{}'", 
sendBufferSize, this);
@@ -155,6 +177,9 @@ public class ProxySocketSessionConfig im
         }
     }
 
+    /**
+     * {@inheritDoc}
+     */
     @Override
     public Integer getTrafficClass() {
         try {
@@ -164,6 +189,9 @@ public class ProxySocketSessionConfig im
         }
     }
 
+    /**
+     * {@inheritDoc}
+     */
     @Override
     public void setTrafficClass(int trafficClass) {
         LOG.debug("set traffic class '{}' for session '{}'", trafficClass, 
this);
@@ -174,6 +202,9 @@ public class ProxySocketSessionConfig im
         }
     }
 
+    /**
+     * {@inheritDoc}
+     */
     @Override
     public Boolean isKeepAlive() {
         try {
@@ -183,6 +214,9 @@ public class ProxySocketSessionConfig im
         }
     }
 
+    /**
+     * {@inheritDoc}
+     */
     @Override
     public void setKeepAlive(boolean keepAlive) {
         LOG.debug("set keep alive '{}' for session '{}'", keepAlive, this);
@@ -193,6 +227,9 @@ public class ProxySocketSessionConfig im
         }
     }
 
+    /**
+     * {@inheritDoc}
+     */
     @Override
     public Boolean isOobInline() {
         try {
@@ -202,6 +239,9 @@ public class ProxySocketSessionConfig im
         }
     }
 
+    /**
+     * {@inheritDoc}
+     */
     @Override
     public void setOobInline(boolean oobInline) {
         LOG.debug("set oob inline '{}' for session '{}'", oobInline, this);
@@ -212,6 +252,9 @@ public class ProxySocketSessionConfig im
         }
     }
 
+    /**
+     * {@inheritDoc}
+     */
     @Override
     public Integer getSoLinger() {
         try {
@@ -221,6 +264,9 @@ public class ProxySocketSessionConfig im
         }
     }
 
+    /**
+     * {@inheritDoc}
+     */
     @Override
     public void setSoLinger(int soLinger) {
         LOG.debug("set so linger '{}' for session '{}'", soLinger, this);

Modified: 
mina/trunk/core/src/main/java/org/apache/mina/transport/tcp/nio/NioTcpServer.java
URL: 
http://svn.apache.org/viewvc/mina/trunk/core/src/main/java/org/apache/mina/transport/tcp/nio/NioTcpServer.java?rev=1244531&r1=1244530&r2=1244531&view=diff
==============================================================================
--- 
mina/trunk/core/src/main/java/org/apache/mina/transport/tcp/nio/NioTcpServer.java
 (original)
+++ 
mina/trunk/core/src/main/java/org/apache/mina/transport/tcp/nio/NioTcpServer.java
 Wed Feb 15 15:22:50 2012
@@ -26,6 +26,8 @@ import java.util.HashSet;
 import java.util.Set;
 
 import org.apache.mina.service.SelectorStrategy;
+import org.apache.mina.service.idlechecker.IdleChecker;
+import org.apache.mina.service.idlechecker.IndexedIdleChecker;
 import org.apache.mina.transport.tcp.AbstractTcpServer;
 import org.apache.mina.transport.tcp.DefaultSocketSessionConfig;
 import org.apache.mina.transport.tcp.NioSelectorProcessor;
@@ -41,6 +43,9 @@ import org.slf4j.LoggerFactory;
 public class NioTcpServer extends AbstractTcpServer {
     static final Logger LOG = LoggerFactory.getLogger(NioTcpServer.class);
 
+    // the idle checker is used for detecting read or write idle session 
+    private IdleChecker idleChecker = new IndexedIdleChecker();
+
     // list of bound addresses
     private Set<SocketAddress> addresses = Collections.synchronizedSet(new 
HashSet<SocketAddress>());
 

Modified: 
mina/trunk/core/src/test/java/org/apache/mina/session/AbstractIoSessionTest.java
URL: 
http://svn.apache.org/viewvc/mina/trunk/core/src/test/java/org/apache/mina/session/AbstractIoSessionTest.java?rev=1244531&r1=1244530&r2=1244531&view=diff
==============================================================================
--- 
mina/trunk/core/src/test/java/org/apache/mina/session/AbstractIoSessionTest.java
 (original)
+++ 
mina/trunk/core/src/test/java/org/apache/mina/session/AbstractIoSessionTest.java
 Wed Feb 15 15:22:50 2012
@@ -223,6 +223,14 @@ public class AbstractIoSessionTest {
         verify(filter3).sessionClosed(eq(session));
     }
 
+    @Test
+    public void increment_written_bytes() {
+        DummySession session = new DummySession(service);
+        assertEquals(0, session.getWrittenBytes());
+        session.incrementWrittenBytes(1024);
+        assertEquals(1024, session.getWrittenBytes());
+    }
+
     private class PassthruFilter extends DefaultIoFilter {
 
     }

Modified: 
mina/trunk/core/src/test/java/org/apache/mina/transport/tcp/ProxySocketSessionConfigTest.java
URL: 
http://svn.apache.org/viewvc/mina/trunk/core/src/test/java/org/apache/mina/transport/tcp/ProxySocketSessionConfigTest.java?rev=1244531&r1=1244530&r2=1244531&view=diff
==============================================================================
--- 
mina/trunk/core/src/test/java/org/apache/mina/transport/tcp/ProxySocketSessionConfigTest.java
 (original)
+++ 
mina/trunk/core/src/test/java/org/apache/mina/transport/tcp/ProxySocketSessionConfigTest.java
 Wed Feb 15 15:22:50 2012
@@ -51,22 +51,17 @@ public class ProxySocketSessionConfigTes
     @Test
     public void idle() {
         assertEquals(-1, config.getIdleTimeInMillis(IdleStatus.READ_IDLE));
-        assertEquals(-1, 
config.getIdleTimeInMillis(IdleStatus.READ_WRITE_IDLE));
         assertEquals(-1, config.getIdleTimeInMillis(IdleStatus.WRITE_IDLE));
 
         config.setIdleTimeInMillis(IdleStatus.READ_IDLE, 1);
         assertEquals(1, config.getIdleTimeInMillis(IdleStatus.READ_IDLE));
-        assertEquals(-1, 
config.getIdleTimeInMillis(IdleStatus.READ_WRITE_IDLE));
         assertEquals(-1, config.getIdleTimeInMillis(IdleStatus.WRITE_IDLE));
 
-        config.setIdleTimeInMillis(IdleStatus.READ_WRITE_IDLE, 2);
         assertEquals(1, config.getIdleTimeInMillis(IdleStatus.READ_IDLE));
-        assertEquals(2, 
config.getIdleTimeInMillis(IdleStatus.READ_WRITE_IDLE));
         assertEquals(-1, config.getIdleTimeInMillis(IdleStatus.WRITE_IDLE));
 
         config.setIdleTimeInMillis(IdleStatus.WRITE_IDLE, 3);
         assertEquals(1, config.getIdleTimeInMillis(IdleStatus.READ_IDLE));
-        assertEquals(2, 
config.getIdleTimeInMillis(IdleStatus.READ_WRITE_IDLE));
         assertEquals(3, config.getIdleTimeInMillis(IdleStatus.WRITE_IDLE));
     }
 


Reply via email to