View Javadoc

    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 static org.junit.Assert.assertEquals;
    23  import static org.junit.Assert.assertNotSame;
    24  import static org.junit.Assert.assertTrue;
    25
    26  import java.net.InetSocketAddress;
    27
    28  import org.apache.mina.core.buffer.IoBuffer;
    29  import org.apache.mina.core.future.ConnectFuture;
    30  import org.apache.mina.core.future.WriteFuture;
    31  import org.apache.mina.core.service.IoHandlerAdapter;
    32  import org.apache.mina.core.session.ExpiringSessionRecycler;
    33  import org.apache.mina.core.session.IdleStatus;
    34  import org.apache.mina.core.session.IoSession;
    35  import org.apache.mina.util.AvailablePortFinder;
    36  import org.junit.After;
    37  import org.junit.Before;
    38  import org.junit.Test;
    39
    40  /**
    41   * Tests if datagram sessions are recycled properly.
    42   *
    43   * @author <a href="http://mina.apache.org">Apache MINA Project</a>
    44   */
    45  public class DatagramRecyclerTest {
    46      private NioDatagramAcceptor acceptor;
    47
    48      private NioDatagramConnector connector;
    49
    50      public DatagramRecyclerTest() {
    51          // Do nothing
    52      }
    53
    54      @Before
    55      public void setUp() throws Exception {
    56          acceptor = new NioDatagramAcceptor();
    57          connector = new NioDatagramConnector();
    58      }
    59
    60      @After
    61      public void tearDown() throws Exception {
    62          acceptor.dispose();
    63          connector.dispose();
    64      }
    65
    66      @Test
    67      public void testDatagramRecycler() throws Exception {
    68          int port = AvailablePortFinder.getNextAvailable(1024);
    69          ExpiringSessionRecycler recycler = new ExpiringSessionRecycler(1, 1);
    70
    71          MockHandler acceptorHandler = new MockHandler();
    72          MockHandler connectorHandler = new MockHandler();
    73
    74          acceptor.setHandler(acceptorHandler);
    75          acceptor.setSessionRecycler(recycler);
    76          acceptor.bind(new InetSocketAddress(port));
    77
    78          try {
    79              connector.setHandler(connectorHandler);
    80              ConnectFuture future = connector.connect(new InetSocketAddress("localhost", port));
    81              future.awaitUninterruptibly();
    82
    83              // Write whatever to trigger the acceptor.
    84              future.getSession().write(IoBuffer.allocate(1)).awaitUninterruptibly();
    85
    86              // Close the client-side connection.
    87              // This doesn't mean that the acceptor-side connection is also closed.
    88              // The life cycle of the acceptor-side connection is managed by the recycler.
    89              future.getSession().close(true);
    90              future.getSession().getCloseFuture().awaitUninterruptibly();
    91              assertTrue(future.getSession().getCloseFuture().isClosed());
    92
    93              // Wait until the acceptor-side connection is closed.
    94              while (acceptorHandler.session == null) {
    95                  Thread.yield();
    96              }
    97              acceptorHandler.session.getCloseFuture().awaitUninterruptibly(3000);
    98
    99              // Is it closed?
    100             assertTrue(acceptorHandler.session.getCloseFuture().isClosed());
    101
    102             Thread.sleep(1000);
    103
    104             assertEquals("CROPSECL", connectorHandler.result.toString());
    105             assertEquals("CROPRECL", acceptorHandler.result.toString());
    106         } finally {
    107             acceptor.unbind();
    108         }
    109     }
    110
    111     @Test
    112     public void testCloseRequest() throws Exception {
    113         int port = AvailablePortFinder.getNextAvailable(1024);
    114         ExpiringSessionRecycler recycler = new ExpiringSessionRecycler(10, 1);
    115
    116         MockHandler acceptorHandler = new MockHandler();
    117         MockHandler connectorHandler = new MockHandler();
    118
    119         acceptor.getSessionConfig().setIdleTime(IdleStatus.READER_IDLE, 1);
    120         acceptor.setHandler(acceptorHandler);
    121         acceptor.setSessionRecycler(recycler);
    122         acceptor.bind(new InetSocketAddress(port));
    123
    124         try {
    125             connector.setHandler(connectorHandler);
    126             ConnectFuture future = connector.connect(new InetSocketAddress("localhost", port));
    127             future.awaitUninterruptibly();
    128
    129             // Write whatever to trigger the acceptor.
    130             future.getSession().write(IoBuffer.allocate(1)).awaitUninterruptibly();
    131
    132             // Make sure the connection is closed before recycler closes it.
    133             while (acceptorHandler.session == null) {
    134                 Thread.yield();
    135             }
    136             acceptorHandler.session.close(true);
    137             assertTrue(acceptorHandler.session.getCloseFuture().awaitUninterruptibly(3000));
    138
    139             IoSession oldSession = acceptorHandler.session;
    140
    141             // Wait until all events are processed and clear the state.
    142             long startTime = System.currentTimeMillis();
    143             while (acceptorHandler.result.length() < 8) {
    144                 Thread.yield();
    145                 if (System.currentTimeMillis() - startTime > 5000) {
    146                     throw new Exception();
    147                 }
    148             }
    149             acceptorHandler.result.setLength(0);
    150             acceptorHandler.session = null;
    151
    152             // Write whatever to trigger the acceptor again.
    153             WriteFuture wf = future.getSession().write(IoBuffer.allocate(1)).awaitUninterruptibly();
    154             assertTrue(wf.isWritten());
    155
    156             // Make sure the connection is closed before recycler closes it.
    157             while (acceptorHandler.session == null) {
    158                 Thread.yield();
    159             }
    160             acceptorHandler.session.close(true);
    161             assertTrue(acceptorHandler.session.getCloseFuture().awaitUninterruptibly(3000));
    162
    163             future.getSession().close(true).awaitUninterruptibly();
    164
    165             assertNotSame(oldSession, acceptorHandler.session);
    166         } finally {
    167             acceptor.unbind();
    168         }
    169     }
    170
    171     private class MockHandler extends IoHandlerAdapter {
    172         public volatile IoSession session;
    173
    174         public final StringBuffer result = new StringBuffer();
    175
    176         /**
    177          * Default constructor
    178          */
    179         public MockHandler() {
    180             super();
    181         }
    182
    183         @Override
    184         public void exceptionCaught(IoSession session, Throwable cause) throws Exception {
    185             this.session = session;
    186             result.append("CA");
    187         }
    188
    189         @Override
    190         public void messageReceived(IoSession session, Object message) throws Exception {
    191             this.session = session;
    192             result.append("RE");
    193         }
    194
    195         @Override
    196         public void messageSent(IoSession session, Object message) throws Exception {
    197             this.session = session;
    198             result.append("SE");
    199         }
    200
    201         @Override
    202         public void sessionClosed(IoSession session) throws Exception {
    203             this.session = session;
    204             result.append("CL");
    205         }
    206
    207         @Override
    208         public void sessionCreated(IoSession session) throws Exception {
    209             this.session = session;
    210             result.append("CR");
    211         }
    212
    213         @Override
    214         public void sessionIdle(IoSession session, IdleStatus status) throws Exception {
    215             this.session = session;
    216             result.append("ID");
    217         }
    218
    219         @Override
    220         public void sessionOpened(IoSession session) throws Exception {
    221             this.session = session;
    222             result.append("OP");
    223         }
    224     }
    225 }