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