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      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 IllegalArgumentException("defaultRemoteAddress");
134         }
135 
136         if (!getTransportMetadata().getAddressType().isAssignableFrom(defaultRemoteAddress.getClass())) {
137             throw new IllegalArgumentException("defaultRemoteAddress type: " + defaultRemoteAddress.getClass()
138                     + " (expected: " + getTransportMetadata().getAddressType() + ")");
139         }
140         this.defaultRemoteAddress = defaultRemoteAddress;
141     }
142 
143     /**
144      * {@inheritDoc}
145      */
146     public final ConnectFuture connect() {
147         SocketAddress defaultRemoteAddress = getDefaultRemoteAddress();
148         if (defaultRemoteAddress == null) {
149             throw new IllegalStateException("defaultRemoteAddress is not set.");
150         }
151 
152         return connect(defaultRemoteAddress, null, null);
153     }
154 
155     /**
156      * {@inheritDoc}
157      */
158     public ConnectFuture connect(IoSessionInitializer<? extends ConnectFuture> sessionInitializer) {
159         SocketAddress defaultRemoteAddress = getDefaultRemoteAddress();
160         if (defaultRemoteAddress == null) {
161             throw new IllegalStateException("defaultRemoteAddress is not set.");
162         }
163 
164         return connect(defaultRemoteAddress, null, sessionInitializer);
165     }
166 
167     /**
168      * {@inheritDoc}
169      */
170     public final ConnectFuture connect(SocketAddress remoteAddress) {
171         return connect(remoteAddress, null, null);
172     }
173 
174     /**
175      * {@inheritDoc}
176      */
177     public ConnectFuture connect(SocketAddress remoteAddress,
178             IoSessionInitializer<? extends ConnectFuture> sessionInitializer) {
179         return connect(remoteAddress, null, sessionInitializer);
180     }
181 
182     /**
183      * {@inheritDoc}
184      */
185     public ConnectFuture connect(SocketAddress remoteAddress, SocketAddress localAddress) {
186         return connect(remoteAddress, localAddress, null);
187     }
188 
189     /**
190      * {@inheritDoc}
191      */
192     public final ConnectFuture connect(SocketAddress remoteAddress, SocketAddress localAddress,
193             IoSessionInitializer<? extends ConnectFuture> sessionInitializer) {
194         if (isDisposing()) {
195             throw new IllegalStateException("The connector has been disposed.");
196         }
197 
198         if (remoteAddress == null) {
199             throw new IllegalArgumentException("remoteAddress");
200         }
201 
202         if (!getTransportMetadata().getAddressType().isAssignableFrom(remoteAddress.getClass())) {
203             throw new IllegalArgumentException("remoteAddress type: " + remoteAddress.getClass() + " (expected: "
204                     + getTransportMetadata().getAddressType() + ")");
205         }
206 
207         if (localAddress != null && !getTransportMetadata().getAddressType().isAssignableFrom(localAddress.getClass())) {
208             throw new IllegalArgumentException("localAddress type: " + localAddress.getClass() + " (expected: "
209                     + getTransportMetadata().getAddressType() + ")");
210         }
211 
212         if (getHandler() == null) {
213             if (getSessionConfig().isUseReadOperation()) {
214                 setHandler(new IoHandler() {
215                     public void exceptionCaught(IoSession session, Throwable cause) throws Exception {
216                         // Empty handler
217                     }
218 
219                     public void messageReceived(IoSession session, Object message) throws Exception {
220                         // Empty handler
221                     }
222 
223                     public void messageSent(IoSession session, Object message) throws Exception {
224                         // Empty handler
225                     }
226 
227                     public void sessionClosed(IoSession session) throws Exception {
228                         // Empty handler
229                     }
230 
231                     public void sessionCreated(IoSession session) throws Exception {
232                         // Empty handler
233                     }
234 
235                     public void sessionIdle(IoSession session, IdleStatus status) throws Exception {
236                         // Empty handler
237                     }
238 
239                     public void sessionOpened(IoSession session) throws Exception {
240                         // Empty handler
241                     }
242                 });
243             } else {
244                 throw new IllegalStateException("handler is not set.");
245             }
246         }
247 
248         return connect0(remoteAddress, localAddress, sessionInitializer);
249     }
250 
251     /**
252      * Implement this method to perform the actual connect operation.
253      *
254      * @param localAddress <tt>null</tt> if no local address is specified
255      */
256     protected abstract ConnectFuture connect0(SocketAddress remoteAddress, SocketAddress localAddress,
257             IoSessionInitializer<? extends ConnectFuture> sessionInitializer);
258 
259     /**
260      * Adds required internal attributes and {@link IoFutureListener}s
261      * related with event notifications to the specified {@code session}
262      * and {@code future}.  Do not call this method directly;
263      * {@link #finishSessionInitialization(IoSession, IoFuture, IoSessionInitializer)}
264      * will call this method instead.
265      */
266     @Override
267     protected final void finishSessionInitialization0(final IoSession session, IoFuture future) {
268         // In case that ConnectFuture.cancel() is invoked before
269         // setSession() is invoked, add a listener that closes the
270         // connection immediately on cancellation.
271         future.addListener(new IoFutureListener<ConnectFuture>() {
272             public void operationComplete(ConnectFuture future) {
273                 if (future.isCanceled()) {
274                     session.close(true);
275                 }
276             }
277         });
278     }
279 
280     /**
281      * {@inheritDoc}
282      */
283     @Override
284     public String toString() {
285         TransportMetadata m = getTransportMetadata();
286         return '(' + m.getProviderName() + ' ' + m.getName() + " connector: " + "managedSessionCount: "
287                 + getManagedSessionCount() + ')';
288     }
289 }