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.transport.socket.nio;
21  
22  import java.net.InetSocketAddress;
23  import java.net.SocketAddress;
24  import java.nio.channels.SelectionKey;
25  import java.nio.channels.Selector;
26  import java.nio.channels.SocketChannel;
27  import java.util.Collection;
28  import java.util.Iterator;
29  import java.util.concurrent.Executor;
30  
31  import org.apache.mina.core.filterchain.IoFilterChain;
32  import org.apache.mina.core.polling.AbstractPollingIoConnector;
33  import org.apache.mina.core.service.IoConnector;
34  import org.apache.mina.core.service.IoProcessor;
35  import org.apache.mina.core.service.IoService;
36  import org.apache.mina.core.service.SimpleIoProcessorPool;
37  import org.apache.mina.core.service.TransportMetadata;
38  import org.apache.mina.core.session.IoSession;
39  import org.apache.mina.transport.socket.DefaultSocketSessionConfig;
40  import org.apache.mina.transport.socket.SocketConnector;
41  import org.apache.mina.transport.socket.SocketSessionConfig;
42  
43  /**
44   * {@link IoConnector} for socket transport (TCP/IP).
45   *
46   * @author <a href="http://mina.apache.org">Apache MINA Project</a>
47   */
48  public final class NioSocketConnector
49          extends AbstractPollingIoConnector<NioSession, SocketChannel>
50          implements SocketConnector {
51  
52      private volatile Selector selector;
53  
54      /**
55       * Constructor for {@link NioSocketConnector} with default configuration (multiple thread model).
56       */
57      public NioSocketConnector() {
58          super(new DefaultSocketSessionConfig(), NioProcessor.class);
59          ((DefaultSocketSessionConfig) getSessionConfig()).init(this);
60      }
61  
62      /**
63       * Constructor for {@link NioSocketConnector} with default configuration, and 
64       * given number of {@link NioProcessor} for multithreading I/O operations
65       * @param processorCount the number of processor to create and place in a
66       * {@link SimpleIoProcessorPool} 
67       */
68      public NioSocketConnector(int processorCount) {
69          super(new DefaultSocketSessionConfig(), NioProcessor.class, processorCount);
70          ((DefaultSocketSessionConfig) getSessionConfig()).init(this);
71      }
72  
73      /**
74       *  Constructor for {@link NioSocketConnector} with default configuration but a
75       *  specific {@link IoProcessor}, useful for sharing the same processor over multiple
76       *  {@link IoService} of the same type.
77       * @param processor the processor to use for managing I/O events
78       */
79      public NioSocketConnector(IoProcessor<NioSession> processor) {
80          super(new DefaultSocketSessionConfig(), processor);
81          ((DefaultSocketSessionConfig) getSessionConfig()).init(this);
82      }
83  
84      /**
85       *  Constructor for {@link NioSocketConnector} with a given {@link Executor} for handling 
86       *  connection events and a given {@link IoProcessor} for handling I/O events, useful for sharing 
87       *  the same processor and executor over multiple {@link IoService} of the same type.
88       * @param executor the executor for connection
89       * @param processor the processor for I/O operations
90       */
91      public NioSocketConnector(Executor executor, IoProcessor<NioSession> processor) {
92          super(new DefaultSocketSessionConfig(), executor, processor);
93          ((DefaultSocketSessionConfig) getSessionConfig()).init(this);
94      }
95      
96      /**
97       * Constructor for {@link NioSocketConnector} with default configuration which will use a built-in 
98       * thread pool executor to manage the given number of processor instances. The processor class must have 
99       * a constructor that accepts ExecutorService or Executor as its single argument, or, failing that, a 
100      * no-arg constructor.
101      * 
102      * @param processorClass the processor class.
103      * @param processorCount the number of processors to instantiate.
104      * @see org.apache.mina.core.service.SimpleIoProcessorPool#SimpleIoProcessorPool(Class, Executor, int)
105      * @since 2.0.0-M4
106      */
107     public NioSocketConnector(Class<? extends IoProcessor<NioSession>> processorClass,
108             int processorCount) {
109         super(new DefaultSocketSessionConfig(), processorClass, processorCount);
110     }
111 
112     /**
113      * Constructor for {@link NioSocketConnector} with default configuration with default configuration which will use a built-in 
114      * thread pool executor to manage the default number of processor instances. The processor class must have 
115      * a constructor that accepts ExecutorService or Executor as its single argument, or, failing that, a 
116      * no-arg constructor. The default number of instances is equal to the number of processor cores 
117      * in the system, plus one.
118      * 
119      * @param processorClass the processor class.
120      * @see org.apache.mina.core.service.SimpleIoProcessorPool#SimpleIoProcessorPool(Class, Executor, int)
121      * @see org.apache.mina.core.service.SimpleIoProcessorPool#DEFAULT_SIZE
122      * @since 2.0.0-M4
123      */
124     public NioSocketConnector(Class<? extends IoProcessor<NioSession>> processorClass) {
125         super(new DefaultSocketSessionConfig(), processorClass);
126     }
127 
128     /**
129      * {@inheritDoc}
130      */
131     @Override
132     protected void init() throws Exception {
133         this.selector = Selector.open();
134     }
135 
136     /**
137      * {@inheritDoc}
138      */
139     @Override
140     protected void destroy() throws Exception {
141         if (selector != null) {
142             selector.close();
143         }
144     }
145 
146     /**
147      * {@inheritDoc}
148      */
149     public TransportMetadata getTransportMetadata() {
150         return NioSocketSession.METADATA;
151     }
152 
153     /**
154      * {@inheritDoc}
155      */
156     @Override
157     public SocketSessionConfig getSessionConfig() {
158         return (SocketSessionConfig) super.getSessionConfig();
159     }
160     
161     /**
162      * {@inheritDoc}
163      */
164     @Override
165     public InetSocketAddress getDefaultRemoteAddress() {
166         return (InetSocketAddress) super.getDefaultRemoteAddress();
167     }
168     
169     /**
170      * {@inheritDoc}
171      */
172     public void setDefaultRemoteAddress(InetSocketAddress defaultRemoteAddress) {
173         super.setDefaultRemoteAddress(defaultRemoteAddress);
174     }
175 
176     /**
177      * {@inheritDoc}
178      */
179     @Override
180     protected Iterator<SocketChannel> allHandles() {
181         return new SocketChannelIterator(selector.keys());
182     }
183 
184     /**
185      * {@inheritDoc}
186      */
187     @Override
188     protected boolean connect(SocketChannel handle, SocketAddress remoteAddress)
189             throws Exception {
190         return handle.connect(remoteAddress);
191     }
192 
193     /**
194      * {@inheritDoc}
195      */
196     @Override
197     protected ConnectionRequest getConnectionRequest(SocketChannel handle) {
198         SelectionKey key = handle.keyFor(selector);
199         
200         if ((key == null) || (!key.isValid())) { 
201             return null;
202         }
203 
204         return (ConnectionRequest) key.attachment();
205     }
206 
207     /**
208      * {@inheritDoc}
209      */
210     @Override
211     protected void close(SocketChannel handle) throws Exception {
212         SelectionKey key = handle.keyFor(selector);
213         
214         if (key != null) {
215             key.cancel();
216         }
217         
218         IoSession session = (IoSession)key.attach(null);
219         IoFilterChain filterChain = session.getFilterChain(); 
220         filterChain.fireSessionClosed();
221         
222         handle.close();
223     }
224 
225     /**
226      * {@inheritDoc}
227      */
228     @Override
229     protected boolean finishConnect(SocketChannel handle) throws Exception {
230         if (handle.finishConnect()) {
231             SelectionKey key = handle.keyFor(selector);
232 
233             if (key != null) {
234                 key.cancel();
235             }
236             
237             return true;
238         }
239 
240         return false;
241     }
242 
243     /**
244      * {@inheritDoc}
245      */
246     @Override
247     protected SocketChannel newHandle(SocketAddress localAddress)
248             throws Exception {
249         SocketChannel ch = SocketChannel.open();
250 
251         int receiveBufferSize =
252             (getSessionConfig()).getReceiveBufferSize();
253         if (receiveBufferSize > 65535) {
254             ch.socket().setReceiveBufferSize(receiveBufferSize);
255         }
256 
257         if (localAddress != null) {
258             ch.socket().bind(localAddress);
259         }
260         ch.configureBlocking(false);
261         return ch;
262     }
263 
264     /**
265      * {@inheritDoc}
266      */
267     @Override
268     protected NioSession newSession(IoProcessor<NioSession> processor, SocketChannel handle) {
269         return new NioSocketSession(this, processor, handle);
270     }
271 
272     /**
273      * {@inheritDoc}
274      */
275     @Override
276     protected void register(SocketChannel handle, ConnectionRequest request)
277             throws Exception {
278         handle.register(selector, SelectionKey.OP_CONNECT, request);
279     }
280 
281     /**
282      * {@inheritDoc}
283      */
284     @Override
285     protected int select(int timeout) throws Exception {
286         return selector.select(timeout);
287     }
288 
289     /**
290      * {@inheritDoc}
291      */
292     @Override
293     protected Iterator<SocketChannel> selectedHandles() {
294         return new SocketChannelIterator(selector.selectedKeys());
295     }
296 
297     /**
298      * {@inheritDoc}
299      */
300     @Override
301     protected void wakeup() {
302         selector.wakeup();
303     }
304 
305     private static class SocketChannelIterator implements Iterator<SocketChannel> {
306 
307         private final Iterator<SelectionKey> i;
308 
309         private SocketChannelIterator(Collection<SelectionKey> selectedKeys) {
310             this.i = selectedKeys.iterator();
311         }
312 
313         /**
314          * {@inheritDoc}
315          */
316         public boolean hasNext() {
317             return i.hasNext();
318         }
319 
320         /**
321          * {@inheritDoc}
322          */
323         public SocketChannel next() {
324             SelectionKey key = i.next();
325             return (SocketChannel) key.channel();
326         }
327 
328         /**
329          * {@inheritDoc}
330          */
331         public void remove() {
332             i.remove();
333         }
334     }
335 }