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