    1   /*
    2    *  Licensed to the Apache Software Foundation (ASF) under one
    3    *  or more contributor license agreements.  See the NOTICE file
    4    *  distributed with this work for additional information
    5    *  regarding copyright ownership.  The ASF licenses this file
    6    *  to you under the Apache License, Version 2.0 (the
    7    *  "License"); you may not use this file except in compliance
    8    *  with the License.  You may obtain a copy of the License at
    9    *
    10   *    http://www.apache.org/licenses/LICENSE-2.0
    11   *
    12   *  Unless required by applicable law or agreed to in writing,
    13   *  software distributed under the License is distributed on an
    14   *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
    15   *  KIND, either express or implied.  See the License for the
    16   *  specific language governing permissions and limitations
    17   *  under the License.
    18   *
    19   */
    20  package org.apache.mina.transport.socket.nio;
    21
    22  import java.net.InetSocketAddress;
    23
    24  import junit.framework.Assert;
    25  import junit.framework.TestCase;
    26
    27  import org.apache.mina.common.ByteBuffer;
    28  import org.apache.mina.common.ConnectFuture;
    29  import org.apache.mina.common.ExpiringSessionRecycler;
    30  import org.apache.mina.common.IdleStatus;
    31  import org.apache.mina.common.IoAcceptor;
    32  import org.apache.mina.common.IoConnector;
    33  import org.apache.mina.common.IoHandlerAdapter;
    34  import org.apache.mina.common.IoSession;
    35  import org.apache.mina.util.AvailablePortFinder;
    36
    37  /**
    38   * Tests if datagram sessions are recycled properly.
    39   *
    40   * @author The Apache Directory Project (mina-dev@directory.apache.org)
    41   * @version $Rev: 436993 $, $Date: 2006-08-26 07:36:56 +0900 (토, 26  8월 2006) $
    42   */
    43  public class DatagramRecyclerTest extends TestCase {
    44      private final IoAcceptor acceptor = new DatagramAcceptor();
    45
    46      private final IoConnector connector = new DatagramConnector();
    47
    48      public DatagramRecyclerTest() {
    49      }
    50
    51      public void testDatagramRecycler() throws Exception {
    52          int port = AvailablePortFinder.getNextAvailable(1024);
    53          DatagramAcceptorConfig config = new DatagramAcceptorConfig();
    54          ExpiringSessionRecycler recycler = new ExpiringSessionRecycler(1, 1);
    55          config.setSessionRecycler(recycler);
    56
    57          MockHandler acceptorHandler = new MockHandler();
    58          MockHandler connectorHandler = new MockHandler();
    59
    60          acceptor.bind(new InetSocketAddress(port), acceptorHandler, config);
    61
    62          try {
    63              ConnectFuture future = connector.connect(new InetSocketAddress(
    64                      "localhost", port), connectorHandler, config);
    65              future.join();
    66
    67              // Write whatever to trigger the acceptor.
    68              future.getSession().write(ByteBuffer.allocate(1)).join();
    69
    70              // Wait until the connection is closed.
    71              future.getSession().getCloseFuture().join(3000);
    72              Assert.assertTrue(future.getSession().getCloseFuture().isClosed());
    73              acceptorHandler.session.getCloseFuture().join(3000);
    74              Assert.assertTrue(acceptorHandler.session.getCloseFuture()
    75                      .isClosed());
    76
    77              Thread.sleep(1000);
    78
    79              Assert.assertEquals("CROPSECL", connectorHandler.result.toString());
    80              Assert.assertEquals("CROPRECL", acceptorHandler.result.toString());
    81          } finally {
    82              acceptor.unbind(new InetSocketAddress(port));
    83          }
    84      }
    85
    86      public void testCloseRequest() throws Exception {
    87          int port = AvailablePortFinder.getNextAvailable(1024);
    88          DatagramAcceptorConfig config = new DatagramAcceptorConfig();
    89          ExpiringSessionRecycler recycler = new ExpiringSessionRecycler(10, 1);
    90          config.setSessionRecycler(recycler);
    91
    92          MockHandler acceptorHandler = new MockHandler();
    93          MockHandler connectorHandler = new MockHandler();
    94
    95          acceptor.bind(new InetSocketAddress(port), acceptorHandler, config);
    96
    97          try {
    98              ConnectFuture future = connector.connect(new InetSocketAddress(
    99                      "localhost", port), connectorHandler, config);
    100             future.join();
    101
    102             // Write whatever to trigger the acceptor.
    103             future.getSession().write(ByteBuffer.allocate(1)).join();
    104
    105             // Make sure the connection is closed before recycler closes it.
    106             while (acceptorHandler.session == null) {
    107                 Thread.yield();
    108             }
    109             acceptorHandler.session.close();
    110             Assert.assertTrue(
    111                     acceptorHandler.session.getCloseFuture().join(3000));
    112
    113             IoSession oldSession = acceptorHandler.session;
    114
    115             // Wait until all events are processed and clear the state.
    116             long startTime = System.currentTimeMillis();
    117             while (acceptorHandler.result.length() < 8) {
    118                 Thread.yield();
    119                 if (System.currentTimeMillis() - startTime > 5000) {
    120                     throw new Exception();
    121                 }
    122             }
    123             acceptorHandler.result.setLength(0);
    124             acceptorHandler.session = null;
    125
    126             // Write whatever to trigger the acceptor again.
    127             future.getSession().write(ByteBuffer.allocate(1)).join();
    128
    129             // Make sure the connection is closed before recycler closes it.
    130             while (acceptorHandler.session == null) {
    131                 Thread.yield();
    132             }
    133             acceptorHandler.session.close();
    134             Assert.assertTrue(
    135                     acceptorHandler.session.getCloseFuture().join(3000));
    136
    137             future.getSession().close().join();
    138
    139             Assert.assertNotSame(oldSession, acceptorHandler.session);
    140         } finally {
    141             acceptor.unbind(new InetSocketAddress(port));
    142         }
    143     }
    144
    145     private class MockHandler extends IoHandlerAdapter {
    146         public volatile IoSession session;
    147         public final StringBuffer result = new StringBuffer();
    148
    149         @Override
    150         public void exceptionCaught(IoSession session, Throwable cause)
    151                 throws Exception {
    152             this.session = session;
    153             result.append("CA");
    154         }
    155
    156         @Override
    157         public void messageReceived(IoSession session, Object message)
    158                 throws Exception {
    159             this.session = session;
    160             result.append("RE");
    161         }
    162
    163         @Override
    164         public void messageSent(IoSession session, Object message)
    165                 throws Exception {
    166             this.session = session;
    167             result.append("SE");
    168         }
    169
    170         @Override
    171         public void sessionClosed(IoSession session) throws Exception {
    172             this.session = session;
    173             result.append("CL");
    174         }
    175
    176         @Override
    177         public void sessionCreated(IoSession session) throws Exception {
    178             this.session = session;
    179             result.append("CR");
    180         }
    181
    182         @Override
    183         public void sessionIdle(IoSession session, IdleStatus status)
    184                 throws Exception {
    185             this.session = session;
    186             result.append("ID");
    187         }
    188
    189         @Override
    190         public void sessionOpened(IoSession session) throws Exception {
    191             this.session = session;
    192             result.append("OP");
    193         }
    194     }
    195 }