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