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  
21  package org.apache.mina.core.service;
22  
23  import static org.junit.Assert.fail;
24  
25  import org.apache.mina.core.future.CloseFuture;
26  import org.apache.mina.core.future.ConnectFuture;
27  import org.apache.mina.core.session.IdleStatus;
28  import org.apache.mina.core.session.IoSession;
29  import org.apache.mina.filter.codec.ProtocolCodecFilter;
30  import org.apache.mina.filter.codec.textline.TextLineCodecFactory;
31  import org.apache.mina.transport.socket.nio.NioSocketAcceptor;
32  import org.apache.mina.transport.socket.nio.NioSocketConnector;
33  import org.apache.mina.util.AvailablePortFinder;
34  import org.junit.Ignore;
35  import org.junit.Test;
36  
37  import java.io.IOException;
38  import java.net.InetSocketAddress;
39  import java.nio.charset.Charset;
40  import java.nio.charset.StandardCharsets;
41  import java.util.concurrent.CountDownLatch;
42  
43  /**
44   * Test disposal of AbstractIoService. This test should not hang or timeout when DIRMINA-1076 is fixed.
45   * 
46   * @author chrjohn
47   */
48  public class AbstractIoServiceDIRMINA1076Test {
49  
50      @Test( timeout = 15000 )
51      @Ignore
52      public void testDispose()
53          throws Exception {
54  
55          long startTime = System.currentTimeMillis();
56          // without DIRMINA-1076 fixed, the test will hang after short time
57          while ( System.currentTimeMillis() < startTime + 10000 ) {
58              final CountDownLatch disposalLatch = new CountDownLatch( 1 );
59              Thread thread = new Thread() {
60  
61                  public void run() {
62  
63                      final IoAcceptor acceptor = new NioSocketAcceptor();
64                      acceptor.getFilterChain()
65                              .addLast( "codec",
66                                        new ProtocolCodecFilter( new TextLineCodecFactory( StandardCharsets.UTF_8 ) ) );
67  
68                      acceptor.setHandler( new ServerHandler() );
69  
70                      acceptor.getSessionConfig().setReadBufferSize( 2048 );
71                      acceptor.getSessionConfig().setIdleTime( IdleStatus.BOTH_IDLE, 10 );
72                      int nextAvailable = AvailablePortFinder.getNextAvailable();
73                      try {
74                          acceptor.bind( new InetSocketAddress( nextAvailable ) );
75                      } catch ( IOException e1 ) {
76                          throw new RuntimeException( e1 );
77                      }
78  
79                      final NioSocketConnector connector = new NioSocketConnector();
80  
81                      // Set connect timeout.
82                      connector.setConnectTimeoutMillis( 30 * 1000L );
83  
84                      connector.setHandler( new ClientHandler() );
85                      connector.getFilterChain()
86                               .addLast( "codec",
87                                         new ProtocolCodecFilter( new TextLineCodecFactory( StandardCharsets.UTF_8 ) ) );
88  
89                      // Start communication.
90                      ConnectFuture cf = connector.connect( new InetSocketAddress( "localhost", nextAvailable ) );
91                      cf.awaitUninterruptibly();
92  
93                      IoSession session = cf.getSession();
94  
95                      // send a message
96                      session.write( "Hello World!\r" );
97  
98                      // wait until response is received
99                      CountDownLatch latch = (CountDownLatch)session.getAttribute( "latch" );
100                     try {
101                         latch.await();
102                     } catch ( InterruptedException e1 ) {
103                         Thread.currentThread().interrupt();
104                     }
105 
106                     // close the session
107                     CloseFuture closeFuture = session.closeOnFlush();
108 
109                     connector.dispose( true );
110 
111                     closeFuture.awaitUninterruptibly();
112                     acceptor.unbind();
113                     acceptor.dispose( true );
114                     disposalLatch.countDown();
115                 }
116             };
117             thread.setDaemon( true );
118             thread.start();
119             disposalLatch.await();
120             thread.join( 1000 );
121 
122             if ( thread.isAlive() ) {
123                 for ( StackTraceElement stackTraceElement : thread.getStackTrace() ) {
124                     if ( "dispose".equals( stackTraceElement.getMethodName() )
125                          && AbstractIoService.class.getCanonicalName().equals( stackTraceElement.getClassName() ) ) {
126                         System.err.println( "Detected hang in AbstractIoService.dispose()!" );
127                     }
128                 }
129                 fail( "Thread should have died by now, supposed hang in AbstractIoService.dispose()" );
130             }
131         }
132         ;
133     }
134 
135     public static class ClientHandler
136         extends
137         IoHandlerAdapter {
138 
139         @Override
140         public void sessionCreated( IoSession session )
141             throws Exception {
142             session.setAttribute( "latch", new CountDownLatch( 1 ) );
143         }
144 
145 
146 
147         @Override
148         public void messageReceived( IoSession session, Object message )
149             throws Exception {
150             CountDownLatch latch = (CountDownLatch)session.getAttribute( "latch" );
151             latch.countDown();
152         }
153 
154 
155 
156         @Override
157         public void exceptionCaught( IoSession session, Throwable cause )
158             throws Exception {}
159     }
160 
161     public static class ServerHandler
162         extends
163         IoHandlerAdapter {
164 
165         @Override
166         public void messageReceived( IoSession session, Object message )
167             throws Exception {
168             session.write( message.toString() );
169         }
170 
171 
172 
173         @Override
174         public void exceptionCaught( IoSession session, Throwable cause )
175             throws Exception {}
176 
177     }
178 
179 }