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