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 The Apache MINA Project (dev@mina.apache.org)
42   * @version $Rev: 751473 $, $Date: 2009-03-08 18:22:14 +0100 (Sun, 08 Mar 2009) $
43   */
44  public class KeepAliveFilterTest extends TestCase {
45      // Constants -----------------------------------------------------
46  
47      private static final IoBuffer PING = IoBuffer.wrap(new byte[] { 1 });
48      private static final IoBuffer PONG = IoBuffer.wrap(new byte[] { 2 });
49      private static final int INTERVAL = 2;
50      private static final int TIMEOUT = 1;
51  
52      private int port;
53      private NioSocketAcceptor acceptor;
54  
55      @Override
56      protected void setUp() throws Exception {
57          super.setUp();
58  
59          acceptor = new NioSocketAcceptor();
60          KeepAliveMessageFactory factory = new ServerFactory();
61          KeepAliveFilter filter = new KeepAliveFilter(factory,
62                  IdleStatus.BOTH_IDLE);
63          acceptor.getFilterChain().addLast("keep-alive", filter);
64          acceptor.setHandler(new IoHandlerAdapter());
65          acceptor.setDefaultLocalAddress(new InetSocketAddress(0));
66          acceptor.bind();
67          port = acceptor.getLocalAddress().getPort();
68      }
69  
70      @Override
71      protected void tearDown() throws Exception {
72          acceptor.unbind();
73          acceptor.dispose();
74          super.tearDown();
75      }
76  
77      public void testKeepAliveFilterForReaderIdle() throws Exception {
78          keepAliveFilterForIdleStatus(IdleStatus.READER_IDLE);
79      }
80  
81      public void testKeepAliveFilterForBothIdle() throws Exception {
82          keepAliveFilterForIdleStatus(IdleStatus.BOTH_IDLE);
83      }
84  
85      public void testKeepAliveFilterForWriterIdle() throws Exception {
86          keepAliveFilterForIdleStatus(IdleStatus.WRITER_IDLE);
87      }
88  
89      // Package protected ---------------------------------------------
90  
91      // Protected -----------------------------------------------------
92  
93      // Private -------------------------------------------------------
94  
95      private void keepAliveFilterForIdleStatus(IdleStatus status)
96              throws Exception {
97          NioSocketConnector connector = new NioSocketConnector();
98          KeepAliveFilter filter = new KeepAliveFilter(new ClientFactory(),
99                  status, EXCEPTION, INTERVAL, TIMEOUT);
100         filter.setForwardEvent(true);
101         connector.getFilterChain().addLast("keep-alive", filter);
102 
103         final AtomicBoolean gotException = new AtomicBoolean(false);
104         connector.setHandler(new IoHandlerAdapter() {
105             @Override
106             public void exceptionCaught(IoSession session, Throwable cause)
107                     throws Exception {
108                 //cause.printStackTrace();
109                 gotException.set(true);
110             }
111 
112             @Override
113             public void sessionIdle(IoSession session, IdleStatus status)
114                     throws Exception {
115                 //System.out.println("client idle:" + status);
116             }
117         });
118 
119         ConnectFuture future = connector.connect(
120                 new InetSocketAddress("127.0.0.1", port)).awaitUninterruptibly();
121         IoSession session = future.getSession();
122         assertNotNull(session);
123 
124         Thread.sleep((INTERVAL + TIMEOUT + 1) * 1000);
125 
126         assertFalse("got an exception on the client", gotException.get());
127 
128         session.close(true);
129         connector.dispose();
130     }
131 
132     private static boolean checkRequest(IoBuffer message) {
133         IoBuffer buff = message;
134         boolean check = buff.get() == 1;
135         buff.rewind();
136         return check;
137     }
138 
139     private static boolean checkResponse(IoBuffer message) {
140         IoBuffer buff = message;
141         boolean check = buff.get() == 2;
142         buff.rewind();
143         return check;
144     }
145 
146     // Inner classes -------------------------------------------------
147 
148     private final class ServerFactory implements KeepAliveMessageFactory {
149         public Object getRequest(IoSession session) {
150             return null;
151         }
152 
153         public Object getResponse(IoSession session, Object request) {
154             return PONG.duplicate();
155         }
156 
157         public boolean isRequest(IoSession session, Object message) {
158             if (message instanceof IoBuffer) {
159                 return checkRequest((IoBuffer) message);
160             }
161             return false;
162         }
163 
164         public boolean isResponse(IoSession session, Object message) {
165             if (message instanceof IoBuffer) {
166                 return checkResponse((IoBuffer) message);
167             }
168             return false;
169         }
170     }
171 
172     private final class ClientFactory implements KeepAliveMessageFactory {
173         public Object getRequest(IoSession session) {
174             return PING.duplicate();
175         }
176 
177         public Object getResponse(IoSession session, Object request) {
178             return null;
179         }
180 
181         public boolean isRequest(IoSession session, Object message) {
182             if (message instanceof IoBuffer) {
183                 return checkRequest((IoBuffer) message);
184             }
185             return false;
186         }
187 
188         public boolean isResponse(IoSession session, Object message) {
189             if (message instanceof IoBuffer) {
190                 return checkResponse((IoBuffer) message);
191             }
192             return false;
193         }
194     }
195 }