001: /*
002: * Licensed to the Apache Software Foundation (ASF) under one
003: * or more contributor license agreements. See the NOTICE file
004: * distributed with this work for additional information
005: * regarding copyright ownership. The ASF licenses this file
006: * to you under the Apache License, Version 2.0 (the
007: * "License"); you may not use this file except in compliance
008: * with the License. You may obtain a copy of the License at
009: *
010: * http://www.apache.org/licenses/LICENSE-2.0
011: *
012: * Unless required by applicable law or agreed to in writing,
013: * software distributed under the License is distributed on an
014: * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
015: * KIND, either express or implied. See the License for the
016: * specific language governing permissions and limitations
017: * under the License.
018: *
019: */
020: package org.apache.mina.transport.socket.nio;
021:
022: import java.net.InetSocketAddress;
023:
024: import junit.framework.Assert;
025: import junit.framework.TestCase;
026:
027: import org.apache.mina.common.ConnectFuture;
028: import org.apache.mina.common.ExpiringSessionRecycler;
029: import org.apache.mina.common.IdleStatus;
030: import org.apache.mina.common.IoBuffer;
031: import org.apache.mina.common.IoHandlerAdapter;
032: import org.apache.mina.common.IoSession;
033: import org.apache.mina.common.WriteFuture;
034: import org.apache.mina.util.AvailablePortFinder;
035:
036: /**
037: * Tests if datagram sessions are recycled properly.
038: *
039: * @author The Apache MINA Project (dev@mina.apache.org)
040: * @version $Rev: 600463 $, $Date: 2007-12-03 03:02:19 -0700 (Mon, 03 Dec 2007) $
041: */
042: public class DatagramRecyclerTest extends TestCase {
043: private NioDatagramAcceptor acceptor;
044: private NioDatagramConnector connector;
045:
046: public DatagramRecyclerTest() {
047: }
048:
049: @Override
050: protected void setUp() throws Exception {
051: super .setUp();
052: acceptor = new NioDatagramAcceptor();
053: connector = new NioDatagramConnector();
054: }
055:
056: @Override
057: protected void tearDown() throws Exception {
058: super .tearDown();
059: acceptor.dispose();
060: connector.dispose();
061: }
062:
063: public void testDatagramRecycler() throws Exception {
064: int port = AvailablePortFinder.getNextAvailable(1024);
065: ExpiringSessionRecycler recycler = new ExpiringSessionRecycler(
066: 1, 1);
067:
068: MockHandler acceptorHandler = new MockHandler();
069: MockHandler connectorHandler = new MockHandler();
070:
071: acceptor.setHandler(acceptorHandler);
072: acceptor.setSessionRecycler(recycler);
073: acceptor.bind(new InetSocketAddress(port));
074:
075: try {
076: connector.setHandler(connectorHandler);
077: ConnectFuture future = connector
078: .connect(new InetSocketAddress("localhost", port));
079: future.awaitUninterruptibly();
080:
081: // Write whatever to trigger the acceptor.
082: future.getSession().write(IoBuffer.allocate(1))
083: .awaitUninterruptibly();
084:
085: // Close the client-side connection.
086: // This doesn't mean that the acceptor-side connection is also closed.
087: // The life cycle of the acceptor-side connection is managed by the recycler.
088: future.getSession().close();
089: future.getSession().getCloseFuture().awaitUninterruptibly();
090: Assert.assertTrue(future.getSession().getCloseFuture()
091: .isClosed());
092:
093: // Wait until the acceptor-side connection is closed.
094: while (acceptorHandler.session == null) {
095: Thread.yield();
096: }
097: acceptorHandler.session.getCloseFuture()
098: .awaitUninterruptibly(3000);
099:
100: // Is it closed?
101: Assert.assertTrue(acceptorHandler.session.getCloseFuture()
102: .isClosed());
103:
104: Thread.sleep(1000);
105:
106: Assert.assertEquals("CROPSECL", connectorHandler.result
107: .toString());
108: Assert.assertEquals("CROPRECL", acceptorHandler.result
109: .toString());
110: } finally {
111: acceptor.unbind();
112: }
113: }
114:
115: public void testCloseRequest() throws Exception {
116: int port = AvailablePortFinder.getNextAvailable(1024);
117: ExpiringSessionRecycler recycler = new ExpiringSessionRecycler(
118: 10, 1);
119:
120: MockHandler acceptorHandler = new MockHandler();
121: MockHandler connectorHandler = new MockHandler();
122:
123: acceptor.getSessionConfig().setIdleTime(IdleStatus.READER_IDLE,
124: 1);
125: acceptor.setHandler(acceptorHandler);
126: acceptor.setSessionRecycler(recycler);
127: acceptor.bind(new InetSocketAddress(port));
128:
129: try {
130: connector.setHandler(connectorHandler);
131: ConnectFuture future = connector
132: .connect(new InetSocketAddress("localhost", port));
133: future.awaitUninterruptibly();
134:
135: // Write whatever to trigger the acceptor.
136: future.getSession().write(IoBuffer.allocate(1))
137: .awaitUninterruptibly();
138:
139: // Make sure the connection is closed before recycler closes it.
140: while (acceptorHandler.session == null) {
141: Thread.yield();
142: }
143: acceptorHandler.session.close();
144: Assert.assertTrue(acceptorHandler.session.getCloseFuture()
145: .awaitUninterruptibly(3000));
146:
147: IoSession oldSession = acceptorHandler.session;
148:
149: // Wait until all events are processed and clear the state.
150: long startTime = System.currentTimeMillis();
151: while (acceptorHandler.result.length() < 8) {
152: Thread.yield();
153: if (System.currentTimeMillis() - startTime > 5000) {
154: throw new Exception();
155: }
156: }
157: acceptorHandler.result.setLength(0);
158: acceptorHandler.session = null;
159:
160: // Write whatever to trigger the acceptor again.
161: WriteFuture wf = future.getSession().write(
162: IoBuffer.allocate(1)).awaitUninterruptibly();
163: Assert.assertTrue(wf.isWritten());
164:
165: // Make sure the connection is closed before recycler closes it.
166: while (acceptorHandler.session == null) {
167: Thread.yield();
168: }
169: acceptorHandler.session.close();
170: Assert.assertTrue(acceptorHandler.session.getCloseFuture()
171: .awaitUninterruptibly(3000));
172:
173: future.getSession().close().awaitUninterruptibly();
174:
175: Assert.assertNotSame(oldSession, acceptorHandler.session);
176: } finally {
177: acceptor.unbind();
178: }
179: }
180:
181: private class MockHandler extends IoHandlerAdapter {
182: public volatile IoSession session;
183: public final StringBuffer result = new StringBuffer();
184:
185: @Override
186: public void exceptionCaught(IoSession session, Throwable cause)
187: throws Exception {
188: this .session = session;
189: result.append("CA");
190: }
191:
192: @Override
193: public void messageReceived(IoSession session, Object message)
194: throws Exception {
195: this .session = session;
196: result.append("RE");
197: }
198:
199: @Override
200: public void messageSent(IoSession session, Object message)
201: throws Exception {
202: this .session = session;
203: result.append("SE");
204: }
205:
206: @Override
207: public void sessionClosed(IoSession session) throws Exception {
208: this .session = session;
209: result.append("CL");
210: }
211:
212: @Override
213: public void sessionCreated(IoSession session) throws Exception {
214: this .session = session;
215: result.append("CR");
216: }
217:
218: @Override
219: public void sessionIdle(IoSession session, IdleStatus status)
220: throws Exception {
221: this .session = session;
222: result.append("ID");
223: }
224:
225: @Override
226: public void sessionOpened(IoSession session) throws Exception {
227: this .session = session;
228: result.append("OP");
229: }
230: }
231: }
|