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.core.service;
21  
22  import java.net.SocketAddress;
23  import java.util.concurrent.Executor;
24  import java.util.concurrent.Executors;
25  
26  import org.apache.mina.core.future.ConnectFuture;
27  import org.apache.mina.core.future.IoFuture;
28  import org.apache.mina.core.future.IoFutureListener;
29  import org.apache.mina.core.session.IdleStatus;
30  import org.apache.mina.core.session.IoSession;
31  import org.apache.mina.core.session.IoSessionConfig;
32  import org.apache.mina.core.session.IoSessionInitializer;
33  
34  /**
35   * A base implementation of {@link IoConnector}.
36   *
37   * @author <a href="http://mina.apache.org">Apache MINA Project</a>
38   */
39  public abstract class AbstractIoConnector extends AbstractIoService implements IoConnector {
40      /**
41       * The minimum timeout value that is supported (in milliseconds).
42       */
43      private long connectTimeoutCheckInterval = 50L;
44  
45      private long connectTimeoutInMillis = 60 * 1000L; // 1 minute by default
46  
47      /** The remote address we are connected to */
48      private SocketAddress defaultRemoteAddress;
49  
50      /** The local address */
51      private SocketAddress defaultLocalAddress;
52  
53      /**
54       * Constructor for {@link AbstractIoConnector}. You need to provide a
55       * default session configuration and an {@link Executor} for handling I/O
56       * events. If null {@link Executor} is provided, a default one will be
57       * created using {@link Executors#newCachedThreadPool()}.
58       * 
59       * @see AbstractIoService#AbstractIoService(IoSessionConfig, Executor)
60       * 
61       * @param sessionConfig
62       *            the default configuration for the managed {@link IoSession}
63       * @param executor
64       *            the {@link Executor} used for handling execution of I/O
65       *            events. Can be <code>null</code>.
66       */
67      protected AbstractIoConnector(IoSessionConfig sessionConfig, Executor executor) {
68          super(sessionConfig, executor);
69      }
70  
71      /**
72       * Returns the minimum connection timeout value for this connector
73       * 
74       * @return
75       *  The minimum time that this connector can have for a connection
76       *  timeout in milliseconds.
77       */
78      public long getConnectTimeoutCheckInterval() {
79          return connectTimeoutCheckInterval;
80      }
81  
82      public void setConnectTimeoutCheckInterval(long minimumConnectTimeout) {
83          if (getConnectTimeoutMillis() < minimumConnectTimeout) {
84              this.connectTimeoutInMillis = minimumConnectTimeout;
85          }
86  
87          this.connectTimeoutCheckInterval = minimumConnectTimeout;
88      }
89  
90      /**
91       * @deprecated
92       *  Take a look at <tt>getConnectTimeoutMillis()</tt>
93       */
94      public final int getConnectTimeout() {
95          return (int) connectTimeoutInMillis / 1000;
96      }
97  
98      /**
99       * {@inheritDoc}
100      */
101     public final long getConnectTimeoutMillis() {
102         return connectTimeoutInMillis;
103     }
104 
105     /**
106      * @deprecated
107      *  Take a look at <tt>setConnectTimeoutMillis(long)</tt>
108      */
109     public final void setConnectTimeout(int connectTimeout) {
110 
111         setConnectTimeoutMillis(connectTimeout * 1000L);
112     }
113 
114     /**
115      * Sets the connect timeout value in milliseconds.
116      * 
117      */
118     public final void setConnectTimeoutMillis(long connectTimeoutInMillis) {
119         if (connectTimeoutInMillis <= connectTimeoutCheckInterval) {
120             this.connectTimeoutCheckInterval = connectTimeoutInMillis;
121         }
122         this.connectTimeoutInMillis = connectTimeoutInMillis;
123     }
124 
125     /**
126      * {@inheritDoc}
127      */
128     public SocketAddress getDefaultRemoteAddress() {
129         return defaultRemoteAddress;
130     }
131 
132     /**
133      * {@inheritDoc}
134      */
135     public final void setDefaultLocalAddress(SocketAddress localAddress) {
136         defaultLocalAddress = localAddress;
137     }
138 
139     /**
140      * {@inheritDoc}
141      */
142     public final SocketAddress getDefaultLocalAddress() {
143         return defaultLocalAddress;
144     }
145 
146     /**
147      * {@inheritDoc}
148      */
149     public final void setDefaultRemoteAddress(SocketAddress defaultRemoteAddress) {
150         if (defaultRemoteAddress == null) {
151             throw new IllegalArgumentException("defaultRemoteAddress");
152         }
153 
154         if (!getTransportMetadata().getAddressType().isAssignableFrom(defaultRemoteAddress.getClass())) {
155             throw new IllegalArgumentException("defaultRemoteAddress type: " + defaultRemoteAddress.getClass()
156                     + " (expected: " + getTransportMetadata().getAddressType() + ")");
157         }
158         this.defaultRemoteAddress = defaultRemoteAddress;
159     }
160 
161     /**
162      * {@inheritDoc}
163      */
164     public final ConnectFuture connect() {
165         SocketAddress defaultRemoteAddress = getDefaultRemoteAddress();
166         if (defaultRemoteAddress == null) {
167             throw new IllegalStateException("defaultRemoteAddress is not set.");
168         }
169 
170         return connect(defaultRemoteAddress, null, null);
171     }
172 
173     /**
174      * {@inheritDoc}
175      */
176     public ConnectFuture connect(IoSessionInitializer<? extends ConnectFuture> sessionInitializer) {
177         SocketAddress defaultRemoteAddress = getDefaultRemoteAddress();
178         if (defaultRemoteAddress == null) {
179             throw new IllegalStateException("defaultRemoteAddress is not set.");
180         }
181 
182         return connect(defaultRemoteAddress, null, sessionInitializer);
183     }
184 
185     /**
186      * {@inheritDoc}
187      */
188     public final ConnectFuture connect(SocketAddress remoteAddress) {
189         return connect(remoteAddress, null, null);
190     }
191 
192     /**
193      * {@inheritDoc}
194      */
195     public ConnectFuture connect(SocketAddress remoteAddress,
196             IoSessionInitializer<? extends ConnectFuture> sessionInitializer) {
197         return connect(remoteAddress, null, sessionInitializer);
198     }
199 
200     /**
201      * {@inheritDoc}
202      */
203     public ConnectFuture connect(SocketAddress remoteAddress, SocketAddress localAddress) {
204         return connect(remoteAddress, localAddress, null);
205     }
206 
207     /**
208      * {@inheritDoc}
209      */
210     public final ConnectFuture connect(SocketAddress remoteAddress, SocketAddress localAddress,
211             IoSessionInitializer<? extends ConnectFuture> sessionInitializer) {
212         if (isDisposing()) {
213             throw new IllegalStateException("The connector has been disposed.");
214         }
215 
216         if (remoteAddress == null) {
217             throw new IllegalArgumentException("remoteAddress");
218         }
219 
220         if (!getTransportMetadata().getAddressType().isAssignableFrom(remoteAddress.getClass())) {
221             throw new IllegalArgumentException("remoteAddress type: " + remoteAddress.getClass() + " (expected: "
222                     + getTransportMetadata().getAddressType() + ")");
223         }
224 
225         if (localAddress != null && !getTransportMetadata().getAddressType().isAssignableFrom(localAddress.getClass())) {
226             throw new IllegalArgumentException("localAddress type: " + localAddress.getClass() + " (expected: "
227                     + getTransportMetadata().getAddressType() + ")");
228         }
229 
230         if (getHandler() == null) {
231             if (getSessionConfig().isUseReadOperation()) {
232                 setHandler(new IoHandler() {
233                     public void exceptionCaught(IoSession session, Throwable cause) throws Exception {
234                         // Empty handler
235                     }
236 
237                     public void messageReceived(IoSession session, Object message) throws Exception {
238                         // Empty handler
239                     }
240 
241                     public void messageSent(IoSession session, Object message) throws Exception {
242                         // Empty handler
243                     }
244 
245                     public void sessionClosed(IoSession session) throws Exception {
246                         // Empty handler
247                     }
248 
249                     public void sessionCreated(IoSession session) throws Exception {
250                         // Empty handler
251                     }
252 
253                     public void sessionIdle(IoSession session, IdleStatus status) throws Exception {
254                         // Empty handler
255                     }
256 
257                     public void sessionOpened(IoSession session) throws Exception {
258                         // Empty handler
259                     }
260 
261                     public void inputClosed(IoSession session) throws Exception {
262                         // Empty handler
263                     }
264                 });
265             } else {
266                 throw new IllegalStateException("handler is not set.");
267             }
268         }
269 
270         return connect0(remoteAddress, localAddress, sessionInitializer);
271     }
272 
273     /**
274      * Implement this method to perform the actual connect operation.
275      *
276      * @param localAddress <tt>null</tt> if no local address is specified
277      */
278     protected abstract ConnectFuture connect0(SocketAddress remoteAddress, SocketAddress localAddress,
279             IoSessionInitializer<? extends ConnectFuture> sessionInitializer);
280 
281     /**
282      * Adds required internal attributes and {@link IoFutureListener}s
283      * related with event notifications to the specified {@code session}
284      * and {@code future}.  Do not call this method directly;
285      */
286     @Override
287     protected final void finishSessionInitialization0(final IoSession session, IoFuture future) {
288         // In case that ConnectFuture.cancel() is invoked before
289         // setSession() is invoked, add a listener that closes the
290         // connection immediately on cancellation.
291         future.addListener(new IoFutureListener<ConnectFuture>() {
292             public void operationComplete(ConnectFuture future) {
293                 if (future.isCanceled()) {
294                     session.close(true);
295                 }
296             }
297         });
298     }
299 
300     /**
301      * {@inheritDoc}
302      */
303     @Override
304     public String toString() {
305         TransportMetadata m = getTransportMetadata();
306         return '(' + m.getProviderName() + ' ' + m.getName() + " connector: " + "managedSessionCount: "
307         + getManagedSessionCount() + ')';
308     }
309 }