You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@mina.apache.org by jv...@apache.org on 2012/11/07 13:02:09 UTC
svn commit: r1406579 - in /mina/mina/trunk/core/src:
main/java/org/apache/mina/service/idlechecker/
main/java/org/apache/mina/transport/nio/ test/java/org/apache/mina/
test/java/org/apache/mina/transport/tcp/
Author: jvermillard
Date: Wed Nov 7 12:02:09 2012
New Revision: 1406579
URL: http://svn.apache.org/viewvc?rev=1406579&view=rev
Log:
now idle checker use its own thread
Added:
mina/mina/trunk/core/src/test/java/org/apache/mina/transport/tcp/IdleTcpServerTest.java
Removed:
mina/mina/trunk/core/src/test/java/org/apache/mina/AllTests.java
Modified:
mina/mina/trunk/core/src/main/java/org/apache/mina/service/idlechecker/IdleChecker.java
mina/mina/trunk/core/src/main/java/org/apache/mina/service/idlechecker/IndexedIdleChecker.java
mina/mina/trunk/core/src/main/java/org/apache/mina/transport/nio/FixedSelectorLoopPool.java
mina/mina/trunk/core/src/main/java/org/apache/mina/transport/nio/NioSelectorLoop.java
mina/mina/trunk/core/src/main/java/org/apache/mina/transport/nio/NioTcpServer.java
Modified: mina/mina/trunk/core/src/main/java/org/apache/mina/service/idlechecker/IdleChecker.java
URL: http://svn.apache.org/viewvc/mina/mina/trunk/core/src/main/java/org/apache/mina/service/idlechecker/IdleChecker.java?rev=1406579&r1=1406578&r2=1406579&view=diff
==============================================================================
--- mina/mina/trunk/core/src/main/java/org/apache/mina/service/idlechecker/IdleChecker.java (original)
+++ mina/mina/trunk/core/src/main/java/org/apache/mina/service/idlechecker/IdleChecker.java Wed Nov 7 12:02:09 2012
@@ -21,7 +21,7 @@ package org.apache.mina.service.idlechec
import org.apache.mina.session.AbstractIoSession;
/**
- * Utility for checking detecting idle sessions.
+ * Utility for checking detecting idle sessions.
*
* @author <a href="http://mina.apache.org">Apache MINA Project</a>
*/
@@ -29,6 +29,7 @@ public interface IdleChecker {
/**
* Inform the IdleCheker a session have a write event
+ *
* @param session the session with the write event
* @param time the data in ms (unix time) of the event
*/
@@ -36,6 +37,7 @@ public interface IdleChecker {
/**
* Inform the IdleCheker a session have a read event
+ *
* @param session the session with the read event
* @param time the data in ms (unix time) of the event
*/
@@ -49,4 +51,13 @@ public interface IdleChecker {
*/
int processIdleSession(long time);
+ /**
+ * Start the idle checker inner threads
+ */
+ void start();
+
+ /**
+ * Stop the idle checker.
+ */
+ void destroy();
}
Modified: mina/mina/trunk/core/src/main/java/org/apache/mina/service/idlechecker/IndexedIdleChecker.java
URL: http://svn.apache.org/viewvc/mina/mina/trunk/core/src/main/java/org/apache/mina/service/idlechecker/IndexedIdleChecker.java?rev=1406579&r1=1406578&r2=1406579&view=diff
==============================================================================
--- mina/mina/trunk/core/src/main/java/org/apache/mina/service/idlechecker/IndexedIdleChecker.java (original)
+++ mina/mina/trunk/core/src/main/java/org/apache/mina/service/idlechecker/IndexedIdleChecker.java Wed Nov 7 12:02:09 2012
@@ -18,8 +18,9 @@
*/
package org.apache.mina.service.idlechecker;
-import java.util.HashSet;
+import java.util.Collections;
import java.util.Set;
+import java.util.concurrent.ConcurrentHashMap;
import org.apache.mina.api.IdleStatus;
import org.apache.mina.session.AbstractIoSession;
@@ -36,6 +37,7 @@ import org.slf4j.LoggerFactory;
* <li>we round it at the next second</li>
* <li>we store a reference to this session in a circular buffer like :</li>
* </ul>
+ *
* <pre>
*
* +--- Current time
@@ -48,9 +50,9 @@ import org.slf4j.LoggerFactory;
* | +--> { S2, S7, S12...} (sessions that will TO in one second)
* +------> { S5, S6, S8...} (sessions that are idle for the maximum delay of 1 hour )
* </pre>
- *
- *The maximum idle itme is one hour.
- *
+ *
+ * The maximum idle itme is one hour.
+ *
* @author <a href="http://mina.apache.org">Apache MINA Project</a>
*/
public class IndexedIdleChecker implements IdleChecker {
@@ -67,37 +69,68 @@ public class IndexedIdleChecker implemen
private static final AttributeKey<Integer> WRITE_IDLE_INDEX = AttributeKey.createKey(Integer.class,
"idle.write.index");
- private long lastCheckTime = 0L;
+ private long lastCheckTimeMs = 0L;
@SuppressWarnings("unchecked")
- private Set<AbstractIoSession>[] readIdleSessionIndex = new Set[MAX_IDLE_TIME_IN_SEC];
+ private final Set<AbstractIoSession>[] readIdleSessionIndex = new Set[MAX_IDLE_TIME_IN_SEC];
@SuppressWarnings("unchecked")
- private Set<AbstractIoSession>[] writeIdleSessionIndex = new Set[MAX_IDLE_TIME_IN_SEC];
+ private final Set<AbstractIoSession>[] writeIdleSessionIndex = new Set[MAX_IDLE_TIME_IN_SEC];
+
+ private final int granularityInMs = 1000;
+
+ private final Worker worker = new Worker();
+
+ private volatile boolean running = true;
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public void start() {
+ worker.start();
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public void destroy() {
+ running = false;
+ try {
+ // interrupt the sleep
+ worker.interrupt();
+ // wait for worker to stop
+ worker.join();
+ } catch (final InterruptedException e) {
+ // interrupted, we don't care much
+ }
+ }
/**
* {@inheritDoc}
*/
@Override
- public void sessionRead(AbstractIoSession session, long timeInMs) {
+ public void sessionRead(final AbstractIoSession session, final 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);
+ final 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);
+ final 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) + 1;
- int index = nextIdleTimeInSeconds % MAX_IDLE_TIME_IN_SEC;
+ final int nextIdleTimeInSeconds = (int) ((timeInMs + idleTimeInMs) / 1000L) + 1;
+ final int index = nextIdleTimeInSeconds % MAX_IDLE_TIME_IN_SEC;
if (readIdleSessionIndex[index] == null) {
- readIdleSessionIndex[index] = new HashSet<AbstractIoSession>();
+ readIdleSessionIndex[index] = Collections
+ .newSetFromMap(new ConcurrentHashMap<AbstractIoSession, Boolean>());
}
LOG.debug("marking session {} idle for index {}", session, index);
@@ -110,25 +143,26 @@ public class IndexedIdleChecker implemen
* {@inheritDoc}
*/
@Override
- public void sessionWritten(AbstractIoSession session, long timeInMs) {
+ public void sessionWritten(final AbstractIoSession session, final 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);
+ final 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);
+ final 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) + 1;
- int index = nextIdleTimeInSeconds % MAX_IDLE_TIME_IN_SEC;
+ final int nextIdleTimeInSeconds = (int) ((timeInMs + idleTimeInMs) / 1000L) + 1;
+ final int index = nextIdleTimeInSeconds % MAX_IDLE_TIME_IN_SEC;
if (writeIdleSessionIndex[index] == null) {
- writeIdleSessionIndex[index] = new HashSet<AbstractIoSession>();
+ writeIdleSessionIndex[index] = Collections
+ .newSetFromMap(new ConcurrentHashMap<AbstractIoSession, Boolean>());
}
writeIdleSessionIndex[index].add(session);
@@ -140,13 +174,13 @@ public class IndexedIdleChecker implemen
* {@inheritDoc}
*/
@Override
- public int processIdleSession(long time) {
+ public int processIdleSession(final long timeMs) {
int counter = 0;
- long delta = time - lastCheckTime;
+ final long delta = timeMs - lastCheckTimeMs;
if (LOG.isDebugEnabled()) {
- LOG.debug("checking idle time, last = {}, now = {}, delta = {}",
- new Object[] { lastCheckTime, time, delta });
+ LOG.debug("checking idle time, last = {}, now = {}, delta = {}", new Object[] { lastCheckTimeMs, timeMs,
+ delta });
}
if (delta < 1000) {
@@ -154,8 +188,9 @@ public class IndexedIdleChecker implemen
return 0;
}
- int startIdx = ((int) (Math.max(lastCheckTime, time - MAX_IDLE_TIME_IN_MS + 1) / 1000L)) % MAX_IDLE_TIME_IN_SEC;
- int endIdx = ((int) (time / 1000L)) % MAX_IDLE_TIME_IN_SEC;
+ final int startIdx = ((int) (Math.max(lastCheckTimeMs, timeMs - MAX_IDLE_TIME_IN_MS + 1) / 1000L))
+ % MAX_IDLE_TIME_IN_SEC;
+ final int endIdx = ((int) (timeMs / 1000L)) % MAX_IDLE_TIME_IN_SEC;
LOG.debug("scaning from index {} to index {}", startIdx, endIdx);
@@ -170,20 +205,20 @@ public class IndexedIdleChecker implemen
} while (index != endIdx);
// save last check time for next call
- lastCheckTime = time;
+ lastCheckTimeMs = timeMs;
LOG.debug("detected {} idleing sessions", counter);
return counter;
}
- private int processIndex(Set<AbstractIoSession>[] indexByTime, int position, IdleStatus status) {
- Set<AbstractIoSession> sessions = indexByTime[position];
+ private int processIndex(final Set<AbstractIoSession>[] indexByTime, final int position, final IdleStatus status) {
+ final Set<AbstractIoSession> sessions = indexByTime[position];
if (sessions == null) {
return 0;
}
int counter = 0;
- for (AbstractIoSession idleSession : sessions) {
+ for (final 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) {
@@ -191,8 +226,31 @@ public class IndexedIdleChecker implemen
}
counter++;
}
- // clear the processed index entry
+ // clear the processed index entry
indexByTime[position] = null;
return counter;
}
+
+ /**
+ * Thread in charge of checking the idleing sessions and fire events
+ */
+ private class Worker extends Thread {
+
+ public Worker() {
+ super("IdleChecker");
+ setDaemon(true);
+ }
+
+ @Override
+ public void run() {
+ while (running) {
+ try {
+ sleep(granularityInMs);
+ processIdleSession(System.currentTimeMillis());
+ } catch (final InterruptedException e) {
+ break;
+ }
+ }
+ }
+ }
}
Modified: mina/mina/trunk/core/src/main/java/org/apache/mina/transport/nio/FixedSelectorLoopPool.java
URL: http://svn.apache.org/viewvc/mina/mina/trunk/core/src/main/java/org/apache/mina/transport/nio/FixedSelectorLoopPool.java?rev=1406579&r1=1406578&r2=1406579&view=diff
==============================================================================
--- mina/mina/trunk/core/src/main/java/org/apache/mina/transport/nio/FixedSelectorLoopPool.java (original)
+++ mina/mina/trunk/core/src/main/java/org/apache/mina/transport/nio/FixedSelectorLoopPool.java Wed Nov 7 12:02:09 2012
@@ -20,7 +20,6 @@ package org.apache.mina.transport.nio;
import java.util.concurrent.atomic.AtomicInteger;
-
/**
* A fixed size pool of {@link SelectorLoop}.
*
@@ -29,20 +28,21 @@ import java.util.concurrent.atomic.Atomi
public class FixedSelectorLoopPool implements SelectorLoopPool {
// the pool of selector loop
- private SelectorLoop[] pool;
-
+ private final SelectorLoop[] pool;
+
// the index of the next selector loop to be served
- private AtomicInteger nextIndex = new AtomicInteger();
-
+ private final AtomicInteger nextIndex = new AtomicInteger();
+
/**
* Create a pool of "size" {@link SelectorLoop}
+ *
* @param size
*/
- public FixedSelectorLoopPool(int size) {
-
+ public FixedSelectorLoopPool(final int size) {
+
pool = new SelectorLoop[size];
- for(int i=0;i<size;i++) {
- pool[i] = new NioSelectorLoop();
+ for (int i = 0; i < size; i++) {
+ pool[i] = new NioSelectorLoop("I/O", i);
}
}
Modified: mina/mina/trunk/core/src/main/java/org/apache/mina/transport/nio/NioSelectorLoop.java
URL: http://svn.apache.org/viewvc/mina/mina/trunk/core/src/main/java/org/apache/mina/transport/nio/NioSelectorLoop.java?rev=1406579&r1=1406578&r2=1406579&view=diff
==============================================================================
--- mina/mina/trunk/core/src/main/java/org/apache/mina/transport/nio/NioSelectorLoop.java (original)
+++ mina/mina/trunk/core/src/main/java/org/apache/mina/transport/nio/NioSelectorLoop.java Wed Nov 7 12:02:09 2012
@@ -25,6 +25,7 @@ import java.nio.channels.ClosedChannelEx
import java.nio.channels.SelectableChannel;
import java.nio.channels.SelectionKey;
import java.nio.channels.Selector;
+import java.util.Iterator;
import org.apache.mina.api.RuntimeIoException;
import org.slf4j.Logger;
@@ -35,11 +36,10 @@ import org.slf4j.LoggerFactory;
*/
public class NioSelectorLoop implements SelectorLoop {
- private static final Logger LOGGER = LoggerFactory.getLogger(NioSelectorLoop.class);
+ private final Logger logger;
/**
- * A timeout used for the select, as we need to get out to deal with idle
- * sessions
+ * A timeout used for the select, as we need to get out to deal with idle sessions
*/
private static final long SELECT_TIMEOUT = 1000L;
@@ -47,19 +47,22 @@ public class NioSelectorLoop implements
private Selector selector;
/** the worker thread in charge of polling the selector */
- private final SelectorWorker worker = new SelectorWorker();
+ private final SelectorWorker worker;
- /** the number of service using this selector */
+ /** the number of service using this selector */
private int serviceCount = 0;
/** Read buffer for all the incoming bytes (default to 64Kb) */
private final ByteBuffer readBuffer = ByteBuffer.allocate(64 * 1024);
- public NioSelectorLoop() {
+ public NioSelectorLoop(final String prefix, final int index) {
+ logger = LoggerFactory.getLogger(NioSelectorLoop.class.getName() + ":" + prefix + "-" + index);
+ worker = new SelectorWorker(prefix, index);
+
try {
selector = Selector.open();
- } catch (IOException ioe) {
- LOGGER.error("Impossible to open a new NIO selector, O/S is out of file descriptor ?");
+ } catch (final IOException ioe) {
+ logger.error("Impossible to open a new NIO selector, O/S is out of file descriptor ?");
throw new RuntimeIoException(ioe);
}
}
@@ -69,9 +72,9 @@ public class NioSelectorLoop implements
*/
@Override
public void register(final boolean accept, final boolean read, final boolean write,
- final SelectorListener listener, SelectableChannel channel) {
- LOGGER.debug("adding to registration queue : {} for accept : {}, read : {}, write : {}", new Object[] {
- listener, accept, read, write });
+ final SelectorListener listener, final SelectableChannel channel) {
+ logger.debug("registering : {} for accept : {}, read : {}, write : {}", new Object[] { listener, accept, read,
+ write });
int ops = 0;
if (accept) {
ops |= SelectionKey.OP_ACCEPT;
@@ -84,8 +87,8 @@ public class NioSelectorLoop implements
}
try {
channel.register(selector, ops, listener);
- } catch (ClosedChannelException e) {
- LOGGER.error("Trying to register an already closed channel : ", e);
+ } catch (final ClosedChannelException e) {
+ logger.error("Trying to register an already closed channel : ", e);
}
}
@@ -94,13 +97,13 @@ public class NioSelectorLoop implements
*/
@Override
public void modifyRegistration(final boolean accept, final boolean read, final boolean write,
- final SelectorListener listener, SelectableChannel channel) {
- LOGGER.debug("modifying registration : {} for accept : {}, read : {}, write : {}", new Object[] { listener,
- accept, read, write });
+ final SelectorListener listener, final SelectableChannel channel) {
+ logger.debug("modifying registration : {} for accept : {}, read : {}, write : {}", new Object[] { listener,
+ accept, read, write });
- SelectionKey key = channel.keyFor(selector);
+ final SelectionKey key = channel.keyFor(selector);
if (key == null) {
- LOGGER.error("Trying to modify the registration of a not registered channel");
+ logger.error("Trying to modify the registration of a not registered channel");
return;
}
@@ -121,11 +124,11 @@ public class NioSelectorLoop implements
* {@inheritDoc}
*/
@Override
- public void unregister(final SelectorListener listener, SelectableChannel channel) {
- LOGGER.debug("unregistering : {}", listener);
- SelectionKey key = channel.keyFor(selector);
+ public void unregister(final SelectorListener listener, final SelectableChannel channel) {
+ logger.debug("unregistering : {}", listener);
+ final SelectionKey key = channel.keyFor(selector);
if (key == null) {
- LOGGER.error("Trying to modify the registration of a not registered channel");
+ logger.error("Trying to modify the registration of a not registered channel");
return;
}
key.cancel();
@@ -138,7 +141,7 @@ public class NioSelectorLoop implements
@Override
public synchronized void incrementServiceCount() {
serviceCount++;
- LOGGER.debug("service count: {}", serviceCount);
+ logger.debug("service count: {}", serviceCount);
if (serviceCount == 1) {
worker.start();
}
@@ -150,52 +153,60 @@ public class NioSelectorLoop implements
@Override
public synchronized void decrementServiceCount() {
serviceCount--;
- LOGGER.debug("service count: {}", serviceCount);
+ logger.debug("service count: {}", serviceCount);
if (serviceCount < 0) {
- LOGGER.error("service count should not be negative : bug ?");
+ logger.error("service count should not be negative : bug ?");
}
}
/**
- * The worker processing incoming session creation, session destruction
- * requests, session write and reads. It will also bind new servers.
+ * The worker processing incoming session creation, session destruction requests, session write and reads. It will
+ * also bind new servers.
*/
private class SelectorWorker extends Thread {
+ public SelectorWorker(final String prefix, final int index) {
+ super("SelectorWorker " + prefix + "-" + index);
+ }
+
@Override
public void run() {
if (selector == null) {
- LOGGER.debug("opening a new selector");
+ logger.debug("opening a new selector");
try {
selector = Selector.open();
- } catch (IOException e) {
- LOGGER.error("IOException while opening a new Selector", e);
+ } catch (final IOException e) {
+ logger.error("IOException while opening a new Selector", e);
}
}
for (;;) {
try {
- LOGGER.debug("selecting...");
- int readyCount = selector.select(SELECT_TIMEOUT);
- LOGGER.debug("... done selecting : {}", readyCount);
+ logger.debug("selecting...");
+ final int readyCount = selector.select();
+ logger.debug("... done selecting : {} events", readyCount);
if (readyCount > 0) {
- for (SelectionKey key : selector.selectedKeys()) {
- SelectorListener listener = (SelectorListener) key.attachment();
+ final Iterator<SelectionKey> it = selector.selectedKeys().iterator();
+
+ while (it.hasNext()) {
+ final SelectionKey key = it.next();
+ final SelectorListener listener = (SelectorListener) key.attachment();
listener.ready(key.isAcceptable(), key.isReadable(), key.isReadable() ? readBuffer : null,
key.isWritable());
+ it.remove();
}
}
- } catch (Exception e) {
- LOGGER.error("Unexpected exception : ", e);
+ } catch (final Exception e) {
+ logger.error("Unexpected exception : ", e);
}
// stop the worker if needed (no more service)
synchronized (NioSelectorLoop.this) {
- LOGGER.debug("remaing {} service", serviceCount);
+ logger.debug("remaing {} service", serviceCount);
if (serviceCount <= 0) {
- LOGGER.debug("stop the worker");
+ logger.debug("stop the worker");
break;
}
}
Modified: mina/mina/trunk/core/src/main/java/org/apache/mina/transport/nio/NioTcpServer.java
URL: http://svn.apache.org/viewvc/mina/mina/trunk/core/src/main/java/org/apache/mina/transport/nio/NioTcpServer.java?rev=1406579&r1=1406578&r2=1406579&view=diff
==============================================================================
--- mina/mina/trunk/core/src/main/java/org/apache/mina/transport/nio/NioTcpServer.java (original)
+++ mina/mina/trunk/core/src/main/java/org/apache/mina/transport/nio/NioTcpServer.java Wed Nov 7 12:02:09 2012
@@ -55,13 +55,14 @@ public class NioTcpServer extends Abstra
// the server socket for accepting clients
private ServerSocketChannel serverChannel = null;
- private final IdleChecker idleChecker = new IndexedIdleChecker();
+ private IdleChecker idleChecker;
/**
* Create a TCP server with new selector pool of default size.
*/
public NioTcpServer() {
- this(new NioSelectorLoop(), new FixedSelectorLoopPool(Runtime.getRuntime().availableProcessors() + 1));
+ this(new NioSelectorLoop("accept", 0),
+ new FixedSelectorLoopPool(Runtime.getRuntime().availableProcessors() + 1));
}
/**
@@ -114,6 +115,9 @@ public class NioTcpServer extends Abstra
acceptSelectorLoop.register(true, false, false, this, serverChannel);
+ idleChecker = new IndexedIdleChecker();
+ idleChecker.start();
+
// it's the first address bound, let's fire the event
this.fireServiceActivated();
@@ -147,6 +151,8 @@ public class NioTcpServer extends Abstra
// will stop the acceptor processor if we are the last service
acceptSelectorLoop.decrementServiceCount();
+
+ idleChecker.destroy();
}
/**
@@ -254,10 +260,12 @@ public class NioTcpServer extends Abstra
}
// add the session to the queue for being added to the selector
- readWriteSelectorLoop.register(false, true, false, session, socketChannel);
- readWriteSelectorLoop.incrementServiceCount();
+ // readWriteSelectorLoop.register(false, true, false, session, socketChannel);
+ // readWriteSelectorLoop.incrementServiceCount();
session.processSessionOpened();
session.setConnected();
+ idleChecker.sessionRead(session, System.currentTimeMillis());
+ idleChecker.sessionWritten(session, System.currentTimeMillis());
}
}
\ No newline at end of file
Added: mina/mina/trunk/core/src/test/java/org/apache/mina/transport/tcp/IdleTcpServerTest.java
URL: http://svn.apache.org/viewvc/mina/mina/trunk/core/src/test/java/org/apache/mina/transport/tcp/IdleTcpServerTest.java?rev=1406579&view=auto
==============================================================================
--- mina/mina/trunk/core/src/test/java/org/apache/mina/transport/tcp/IdleTcpServerTest.java (added)
+++ mina/mina/trunk/core/src/test/java/org/apache/mina/transport/tcp/IdleTcpServerTest.java Wed Nov 7 12:02:09 2012
@@ -0,0 +1,98 @@
+/*
+ * 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.transport.tcp;
+
+import static junit.framework.Assert.assertTrue;
+import static junit.framework.Assert.fail;
+
+import java.io.IOException;
+import java.net.InetSocketAddress;
+import java.net.Socket;
+import java.util.concurrent.CountDownLatch;
+import java.util.concurrent.TimeUnit;
+
+import org.apache.mina.api.AbstractIoFilter;
+import org.apache.mina.api.IdleStatus;
+import org.apache.mina.api.IoSession;
+import org.apache.mina.transport.nio.NioTcpServer;
+import org.junit.BeforeClass;
+import org.junit.Test;
+
+/**
+ * Run a TCP server and wait for idle events to be generated.
+ *
+ * @author <a href="http://mina.apache.org">Apache MINA Project</a>
+ */
+public class IdleTcpServerTest {
+
+ private static final int CLIENT_COUNT = 3;
+
+ @BeforeClass
+ public static void setup() {
+ // BasicConfigurator.configure();
+ }
+
+ @Test
+ public void readIdleTest() throws IOException {
+ final NioTcpServer server = new NioTcpServer();
+
+ final CountDownLatch idleLatch = new CountDownLatch(CLIENT_COUNT);
+
+ // 3 seconds idle time
+ server.getSessionConfig().setIdleTimeInMillis(IdleStatus.READ_IDLE, 3000);
+
+ // start the server
+ server.bind(new InetSocketAddress(0));
+
+ final int boundPort = server.getServerSocketChannel().socket().getLocalPort();
+ server.setFilters(new IdleHandler(idleLatch));
+
+ // fire the clients and let them idle
+ final Socket[] clients = new Socket[CLIENT_COUNT];
+
+ for (int i = 0; i < CLIENT_COUNT; i++) {
+ clients[i] = new Socket("127.0.0.1", boundPort);
+ }
+
+ try {
+ assertTrue("idle event missing ! ", idleLatch.await(4, TimeUnit.SECONDS));
+ } catch (final InterruptedException e) {
+ fail(e.getMessage());
+ }
+ }
+
+ private class IdleHandler extends AbstractIoFilter {
+
+ private final CountDownLatch latch;
+
+ public IdleHandler(final CountDownLatch latch) {
+ this.latch = latch;
+ }
+
+ @Override
+ public void sessionIdle(final IoSession session, final IdleStatus status) {
+ if (status == IdleStatus.READ_IDLE) {
+ // happy
+ latch.countDown();
+ session.close(true);
+ }
+ }
+ }
+}