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      * @return
73       *  The minimum time that this connector can have for a connection
74       *  timeout in milliseconds.
75       */
76      public long getConnectTimeoutCheckInterval() {
77          return connectTimeoutCheckInterval;
78      }
79  
80      /**
81       * Sets the timeout for the connection check
82       *  
83       * @param minimumConnectTimeout The delay we wait before checking the connection
84       */
85      public void setConnectTimeoutCheckInterval(long minimumConnectTimeout) {
86          if (getConnectTimeoutMillis() < minimumConnectTimeout) {
87              this.connectTimeoutInMillis = minimumConnectTimeout;
88          }
89  
90          this.connectTimeoutCheckInterval = minimumConnectTimeout;
91      }
92  
93      /**
94       * @deprecated Take a look at <tt>getConnectTimeoutMillis()</tt>
95       */
96      @Deprecated
97      @Override
98      public final int getConnectTimeout() {
99          return (int) connectTimeoutInMillis / 1000;
100     }
101 
102     /**
103      * {@inheritDoc}
104      */
105     @Override
106     public final long getConnectTimeoutMillis() {
107         return connectTimeoutInMillis;
108     }
109 
110     /**
111      * @deprecated
112      *  Take a look at <tt>setConnectTimeoutMillis(long)</tt>
113      */
114     @Deprecated
115     @Override
116     public final void setConnectTimeout(int connectTimeout) {
117 
118         setConnectTimeoutMillis(connectTimeout * 1000L);
119     }
120 
121     /**
122      * Sets the connect timeout value in milliseconds.
123      * 
124      */
125     @Override
126     public final void setConnectTimeoutMillis(long connectTimeoutInMillis) {
127         if (connectTimeoutInMillis <= connectTimeoutCheckInterval) {
128             this.connectTimeoutCheckInterval = connectTimeoutInMillis;
129         }
130         this.connectTimeoutInMillis = connectTimeoutInMillis;
131     }
132 
133     /**
134      * {@inheritDoc}
135      */
136     @Override
137     public SocketAddress getDefaultRemoteAddress() {
138         return defaultRemoteAddress;
139     }
140 
141     /**
142      * {@inheritDoc}
143      */
144     @Override
145     public final void setDefaultLocalAddress(SocketAddress localAddress) {
146         defaultLocalAddress = localAddress;
147     }
148 
149     /**
150      * {@inheritDoc}
151      */
152     @Override
153     public final SocketAddress getDefaultLocalAddress() {
154         return defaultLocalAddress;
155     }
156 
157     /**
158      * {@inheritDoc}
159      */
160     @Override
161     public final void setDefaultRemoteAddress(SocketAddress defaultRemoteAddress) {
162         if (defaultRemoteAddress == null) {
163             throw new IllegalArgumentException("defaultRemoteAddress");
164         }
165 
166         if (!getTransportMetadata().getAddressType().isAssignableFrom(defaultRemoteAddress.getClass())) {
167             throw new IllegalArgumentException("defaultRemoteAddress type: " + defaultRemoteAddress.getClass()
168                     + " (expected: " + getTransportMetadata().getAddressType() + ")");
169         }
170         this.defaultRemoteAddress = defaultRemoteAddress;
171     }
172 
173     /**
174      * {@inheritDoc}
175      */
176     @Override
177     public final ConnectFuture connect() {
178         SocketAddress remoteAddress = getDefaultRemoteAddress();
179         
180         if (remoteAddress == null) {
181             throw new IllegalStateException("defaultRemoteAddress is not set.");
182         }
183 
184         return connect(remoteAddress, null, null);
185     }
186 
187     /**
188      * {@inheritDoc}
189      */
190     @Override
191     public ConnectFuture connect(IoSessionInitializer<? extends ConnectFuture> sessionInitializer) {
192         SocketAddress remoteAddress = getDefaultRemoteAddress();
193         
194         if (remoteAddress == null) {
195             throw new IllegalStateException("defaultRemoteAddress is not set.");
196         }
197 
198         return connect(remoteAddress, null, sessionInitializer);
199     }
200 
201     /**
202      * {@inheritDoc}
203      */
204     @Override
205     public final ConnectFuture connect(SocketAddress remoteAddress) {
206         return connect(remoteAddress, null, null);
207     }
208 
209     /**
210      * {@inheritDoc}
211      */
212     @Override
213     public ConnectFuture connect(SocketAddress remoteAddress,
214             IoSessionInitializer<? extends ConnectFuture> sessionInitializer) {
215         return connect(remoteAddress, null, sessionInitializer);
216     }
217 
218     /**
219      * {@inheritDoc}
220      */
221     @Override
222     public ConnectFuture connect(SocketAddress remoteAddress, SocketAddress localAddress) {
223         return connect(remoteAddress, localAddress, null);
224     }
225 
226     /**
227      * {@inheritDoc}
228      */
229     @Override
230     public final ConnectFuture connect(SocketAddress remoteAddress, SocketAddress localAddress,
231             IoSessionInitializer<? extends ConnectFuture> sessionInitializer) {
232         if (isDisposing()) {
233             throw new IllegalStateException("The connector is being disposed.");
234         }
235 
236         if (remoteAddress == null) {
237             throw new IllegalArgumentException("remoteAddress");
238         }
239 
240         if (!getTransportMetadata().getAddressType().isAssignableFrom(remoteAddress.getClass())) {
241             throw new IllegalArgumentException("remoteAddress type: " + remoteAddress.getClass() + " (expected: "
242                     + getTransportMetadata().getAddressType() + ")");
243         }
244 
245         if (localAddress != null && !getTransportMetadata().getAddressType().isAssignableFrom(localAddress.getClass())) {
246             throw new IllegalArgumentException("localAddress type: " + localAddress.getClass() + " (expected: "
247                     + getTransportMetadata().getAddressType() + ")");
248         }
249 
250         if (getHandler() == null) {
251             if (getSessionConfig().isUseReadOperation()) {
252                 setHandler(new IoHandler() {
253                     /**
254                      * {@inheritDoc}
255                      */
256                     @Override
257                     public void exceptionCaught(IoSession session, Throwable cause) throws Exception {
258                         // Empty handler
259                     }
260 
261                     /**
262                      * {@inheritDoc}
263                      */
264                     @Override
265                     public void messageReceived(IoSession session, Object message) throws Exception {
266                         // Empty handler
267                     }
268 
269                     /**
270                      * {@inheritDoc}
271                      */
272                     @Override
273                     public void messageSent(IoSession session, Object message) throws Exception {
274                         // Empty handler
275                     }
276 
277                     /**
278                      * {@inheritDoc}
279                      */
280                     @Override
281                     public void sessionClosed(IoSession session) throws Exception {
282                         // Empty handler
283                     }
284 
285                     /**
286                      * {@inheritDoc}
287                      */
288                     @Override
289                     public void sessionCreated(IoSession session) throws Exception {
290                         // Empty handler
291                     }
292 
293                     /**
294                      * {@inheritDoc}
295                      */
296                     @Override
297                     public void sessionIdle(IoSession session, IdleStatus status) throws Exception {
298                         // Empty handler
299                     }
300 
301                     /**
302                      * {@inheritDoc}
303                      */
304                     @Override
305                     public void sessionOpened(IoSession session) throws Exception {
306                         // Empty handler
307                     }
308 
309                     /**
310                      * {@inheritDoc}
311                      */
312                     @Override
313                     public void inputClosed(IoSession session) throws Exception {
314                         // Empty handler
315                     }
316                 });
317             } else {
318                 throw new IllegalStateException("handler is not set.");
319             }
320         }
321 
322         return connect0(remoteAddress, localAddress, sessionInitializer);
323     }
324 
325     /**
326      * Implement this method to perform the actual connect operation.
327      *
328      * @param remoteAddress The remote address to connect from
329      * @param localAddress <tt>null</tt> if no local address is specified
330      * @param sessionInitializer The IoSessionInitializer to use when the connection s successful
331      * @return The ConnectFuture associated with this asynchronous operation
332      * 
333      */
334     protected abstract ConnectFuture connect0(SocketAddress remoteAddress, SocketAddress localAddress,
335             IoSessionInitializer<? extends ConnectFuture> sessionInitializer);
336 
337     /**
338      * Adds required internal attributes and {@link IoFutureListener}s
339      * related with event notifications to the specified {@code session}
340      * and {@code future}.  Do not call this method directly;
341      */
342     @Override
343     protected final void finishSessionInitialization0(final IoSession session, IoFuture future) {
344         // In case that ConnectFuture.cancel() is invoked before
345         // setSession() is invoked, add a listener that closes the
346         // connection immediately on cancellation.
347         future.addListener(new IoFutureListener<ConnectFuture>() {
348             /**
349              * {@inheritDoc}
350              */
351             @Override
352             public void operationComplete(ConnectFuture future) {
353                 if (future.isCanceled()) {
354                     session.closeNow();
355                 }
356             }
357         });
358     }
359 
360     /**
361      * {@inheritDoc}
362      */
363     @Override
364     public String toString() {
365         TransportMetadata m = getTransportMetadata();
366         return '(' + m.getProviderName() + ' ' + m.getName() + " connector: " + "managedSessionCount: "
367         + getManagedSessionCount() + ')';
368     }
369 }