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.filter.keepalive;
21  
22  import static org.apache.mina.filter.keepalive.KeepAliveRequestTimeoutHandler.*;
23  
24  import java.net.InetSocketAddress;
25  import java.util.concurrent.atomic.AtomicBoolean;
26  
27  import junit.framework.TestCase;
28  
29  import org.apache.mina.core.buffer.IoBuffer;
30  import org.apache.mina.core.future.ConnectFuture;
31  import org.apache.mina.core.service.IoHandlerAdapter;
32  import org.apache.mina.core.session.IdleStatus;
33  import org.apache.mina.core.session.IoSession;
34  import org.apache.mina.transport.socket.nio.NioSocketAcceptor;
35  import org.apache.mina.transport.socket.nio.NioSocketConnector;
36  
37  /**
38   * Tests {@link KeepAliveFilter} used by the connector with different
39   * interested {@link IdleStatus}es.
40   *
41   * @author <a href="http://mina.apache.org">Apache MINA Project</a>
42   */
43  public class KeepAliveFilterTest extends TestCase {
44      // Constants -----------------------------------------------------
45      static final IoBuffer PING = IoBuffer.wrap(new byte[] { 1 });
46      static final IoBuffer PONG = IoBuffer.wrap(new byte[] { 2 });
47      private static final int INTERVAL = 2;
48      private static final int TIMEOUT = 1;
49  
50      private int port;
51      private NioSocketAcceptor acceptor;
52  
53      @Override
54      protected void setUp() throws Exception {
55          super.setUp();
56  
57          acceptor = new NioSocketAcceptor();
58          KeepAliveMessageFactory factory = new ServerFactory();
59          KeepAliveFilter filter = new KeepAliveFilter(factory,
60                  IdleStatus.BOTH_IDLE);
61          acceptor.getFilterChain().addLast("keep-alive", filter);
62          acceptor.setHandler(new IoHandlerAdapter());
63          acceptor.setDefaultLocalAddress(new InetSocketAddress(0));
64          acceptor.bind();
65          port = acceptor.getLocalAddress().getPort();
66      }
67  
68      @Override
69      protected void tearDown() throws Exception {
70          acceptor.unbind();
71          acceptor.dispose();
72          super.tearDown();
73      }
74  
75      public void testKeepAliveFilterForReaderIdle() throws Exception {
76          keepAliveFilterForIdleStatus(IdleStatus.READER_IDLE);
77      }
78  
79      public void testKeepAliveFilterForBothIdle() throws Exception {
80          keepAliveFilterForIdleStatus(IdleStatus.BOTH_IDLE);
81      }
82  
83      public void testKeepAliveFilterForWriterIdle() throws Exception {
84          keepAliveFilterForIdleStatus(IdleStatus.WRITER_IDLE);
85      }
86  
87      // Package protected ---------------------------------------------
88  
89      // Protected -----------------------------------------------------
90  
91      // Private -------------------------------------------------------
92  
93      private void keepAliveFilterForIdleStatus(IdleStatus status)
94              throws Exception {
95          NioSocketConnector connector = new NioSocketConnector();
96          KeepAliveFilter filter = new KeepAliveFilter(new ClientFactory(),
97                  status, EXCEPTION, INTERVAL, TIMEOUT);
98          filter.setForwardEvent(true);
99          connector.getFilterChain().addLast("keep-alive", filter);
100 
101         final AtomicBoolean gotException = new AtomicBoolean(false);
102         connector.setHandler(new IoHandlerAdapter() {
103             @Override
104             public void exceptionCaught(IoSession session, Throwable cause)
105                     throws Exception {
106                 //cause.printStackTrace();
107                 gotException.set(true);
108             }
109 
110             @Override
111             public void sessionIdle(IoSession session, IdleStatus status)
112                     throws Exception {
113                 // Do nothing
114             }
115         });
116 
117         ConnectFuture future = connector.connect(
118                 new InetSocketAddress("127.0.0.1", port)).awaitUninterruptibly();
119         IoSession session = future.getSession();
120         assertNotNull(session);
121 
122         Thread.sleep((INTERVAL + TIMEOUT + 1) * 1000);
123 
124         assertFalse("got an exception on the client", gotException.get());
125 
126         session.close(true);
127         connector.dispose();
128     }
129 
130     static boolean checkRequest(IoBuffer message) {
131         IoBuffer buff = message;
132         boolean check = buff.get() == 1;
133         buff.rewind();
134         return check;
135     }
136 
137     static boolean checkResponse(IoBuffer message) {
138         IoBuffer buff = message;
139         boolean check = buff.get() == 2;
140         buff.rewind();
141         return check;
142     }
143 
144     // Inner classes -------------------------------------------------
145     private final class ServerFactory implements KeepAliveMessageFactory {
146         /**
147          * Default constructor
148          */
149         public ServerFactory() {
150             super();
151         }
152         
153         public Object getRequest(IoSession session) {
154             return null;
155         }
156 
157         public Object getResponse(IoSession session, Object request) {
158             return PONG.duplicate();
159         }
160 
161         public boolean isRequest(IoSession session, Object message) {
162             if (message instanceof IoBuffer) {
163                 return checkRequest((IoBuffer) message);
164             }
165             return false;
166         }
167 
168         public boolean isResponse(IoSession session, Object message) {
169             if (message instanceof IoBuffer) {
170                 return checkResponse((IoBuffer) message);
171             }
172             return false;
173         }
174     }
175 
176     private final class ClientFactory implements KeepAliveMessageFactory {
177         /**
178          * Default constructor
179          */
180         public ClientFactory() {
181             super();
182         }
183         
184         public Object getRequest(IoSession session) {
185             return PING.duplicate();
186         }
187 
188         public Object getResponse(IoSession session, Object request) {
189             return null;
190         }
191 
192         public boolean isRequest(IoSession session, Object message) {
193             if (message instanceof IoBuffer) {
194                 return checkRequest((IoBuffer) message);
195             }
196             return false;
197         }
198 
199         public boolean isResponse(IoSession session, Object message) {
200             if (message instanceof IoBuffer) {
201                 return checkResponse((IoBuffer) message);
202             }
203             return false;
204         }
205     }
206 }