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.io.IOException;
23  import java.net.InetSocketAddress;
24  import java.net.ServerSocket;
25  import java.net.SocketAddress;
26  import java.nio.channels.ClosedSelectorException;
27  import java.nio.channels.SelectionKey;
28  import java.nio.channels.Selector;
29  import java.nio.channels.ServerSocketChannel;
30  import java.nio.channels.SocketChannel;
31  import java.util.Collection;
32  import java.util.Iterator;
33  import java.util.concurrent.Executor;
34  
35  import org.apache.mina.core.polling.AbstractPollingIoAcceptor;
36  import org.apache.mina.core.service.IoAcceptor;
37  import org.apache.mina.core.service.IoProcessor;
38  import org.apache.mina.core.service.IoService;
39  import org.apache.mina.core.service.SimpleIoProcessorPool;
40  import org.apache.mina.core.service.TransportMetadata;
41  import org.apache.mina.transport.socket.DefaultSocketSessionConfig;
42  import org.apache.mina.transport.socket.SocketAcceptor;
43  
44  /**
45   * {@link IoAcceptor} for socket transport (TCP/IP).  This class
46   * handles incoming TCP/IP based socket connections.
47   *
48   * @author <a href="http://mina.apache.org">Apache MINA Project</a>
49   */
50  public final class NioSocketAcceptor extends AbstractPollingIoAcceptor<NioSession, ServerSocketChannel> 
51      implements SocketAcceptor {
52  
53      private volatile Selector selector;
54  
55      /**
56       * Constructor for {@link NioSocketAcceptor} using default parameters (multiple thread model).
57       */
58      public NioSocketAcceptor() {
59          super(new DefaultSocketSessionConfig(), NioProcessor.class);
60          ((DefaultSocketSessionConfig) getSessionConfig()).init(this);
61      }
62  
63      /**
64       * Constructor for {@link NioSocketAcceptor} using default parameters, and 
65       * given number of {@link NioProcessor} for multithreading I/O operations.
66       * 
67       * @param processorCount the number of processor to create and place in a
68       * {@link SimpleIoProcessorPool} 
69       */
70      public NioSocketAcceptor(int processorCount) {
71          super(new DefaultSocketSessionConfig(), NioProcessor.class, processorCount);
72          ((DefaultSocketSessionConfig) getSessionConfig()).init(this);
73      }
74  
75      /**
76      *  Constructor for {@link NioSocketAcceptor} with default configuration but a
77       *  specific {@link IoProcessor}, useful for sharing the same processor over multiple
78       *  {@link IoService} of the same type.
79       * @param processor the processor to use for managing I/O events
80       */
81      public NioSocketAcceptor(IoProcessor<NioSession> processor) {
82          super(new DefaultSocketSessionConfig(), processor);
83          ((DefaultSocketSessionConfig) getSessionConfig()).init(this);
84      }
85  
86      /**
87       *  Constructor for {@link NioSocketAcceptor} with a given {@link Executor} for handling 
88       *  connection events and a given {@link IoProcessor} for handling I/O events, useful for 
89       *  sharing the same processor and executor over multiple {@link IoService} of the same type.
90       * @param executor the executor for connection
91       * @param processor the processor for I/O operations
92       */
93      public NioSocketAcceptor(Executor executor, IoProcessor<NioSession> processor) {
94          super(new DefaultSocketSessionConfig(), executor, processor);
95          ((DefaultSocketSessionConfig) getSessionConfig()).init(this);
96      }
97  
98      /**
99       * {@inheritDoc}
100      */
101     @Override
102     protected void init() throws Exception {
103         selector = Selector.open();
104     }
105 
106     /**
107      * {@inheritDoc}
108      */
109     @Override
110     protected void destroy() throws Exception {
111         if (selector != null) {
112             selector.close();
113         }
114     }
115 
116     /**
117      * {@inheritDoc}
118      */
119     public TransportMetadata getTransportMetadata() {
120         return NioSocketSession.METADATA;
121     }
122 
123     /**
124      * {@inheritDoc}
125      */
126     @Override
127     public InetSocketAddress getLocalAddress() {
128         return (InetSocketAddress) super.getLocalAddress();
129     }
130 
131     /**
132      * {@inheritDoc}
133      */
134     @Override
135     public InetSocketAddress getDefaultLocalAddress() {
136         return (InetSocketAddress) super.getDefaultLocalAddress();
137     }
138 
139     /**
140      * {@inheritDoc}
141      */
142     public void setDefaultLocalAddress(InetSocketAddress localAddress) {
143         setDefaultLocalAddress((SocketAddress) localAddress);
144     }
145 
146     /**
147      * {@inheritDoc}
148      */
149     @Override
150     protected NioSession accept(IoProcessor<NioSession> processor, ServerSocketChannel handle) throws Exception {
151 
152         SelectionKey key = handle.keyFor(selector);
153 
154         if ((key == null) || (!key.isValid()) || (!key.isAcceptable())) {
155             return null;
156         }
157 
158         // accept the connection from the client
159         SocketChannel ch = handle.accept();
160 
161         if (ch == null) {
162             return null;
163         }
164 
165         return new NioSocketSession(this, processor, ch);
166     }
167 
168     /**
169      * {@inheritDoc}
170      */
171     @Override
172     protected ServerSocketChannel open(SocketAddress localAddress) throws Exception {
173         // Creates the listening ServerSocket
174         ServerSocketChannel channel = ServerSocketChannel.open();
175 
176         boolean success = false;
177 
178         try {
179             // This is a non blocking socket channel
180             channel.configureBlocking(false);
181 
182             // Configure the server socket,
183             ServerSocket socket = channel.socket();
184 
185             // Set the reuseAddress flag accordingly with the setting
186             socket.setReuseAddress(isReuseAddress());
187 
188             // and bind.
189             socket.bind(localAddress, getBacklog());
190 
191             // Register the channel within the selector for ACCEPT event
192             channel.register(selector, SelectionKey.OP_ACCEPT);
193             success = true;
194         } finally {
195             if (!success) {
196                 close(channel);
197             }
198         }
199         return channel;
200     }
201 
202     /**
203      * {@inheritDoc}
204      */
205     @Override
206     protected SocketAddress localAddress(ServerSocketChannel handle) throws Exception {
207         return handle.socket().getLocalSocketAddress();
208     }
209 
210     /**
211       * Check if we have at least one key whose corresponding channels is 
212       * ready for I/O operations.
213       *
214       * This method performs a blocking selection operation. 
215       * It returns only after at least one channel is selected, 
216       * this selector's wakeup method is invoked, or the current thread 
217       * is interrupted, whichever comes first.
218       * 
219       * @return The number of keys having their ready-operation set updated
220       * @throws IOException If an I/O error occurs
221       * @throws ClosedSelectorException If this selector is closed 
222       */
223     @Override
224     protected int select() throws Exception {
225         return selector.select();
226     }
227 
228     /**
229      * {@inheritDoc}
230      */
231     @Override
232     protected Iterator<ServerSocketChannel> selectedHandles() {
233         return new ServerSocketChannelIterator(selector.selectedKeys());
234     }
235 
236     /**
237      * {@inheritDoc}
238      */
239     @Override
240     protected void close(ServerSocketChannel handle) throws Exception {
241         SelectionKey key = handle.keyFor(selector);
242 
243         if (key != null) {
244             key.cancel();
245         }
246 
247         handle.close();
248     }
249 
250     /**
251      * {@inheritDoc}
252      */
253     @Override
254     protected void wakeup() {
255         selector.wakeup();
256     }
257 
258     /**
259      * Defines an iterator for the selected-key Set returned by the 
260      * selector.selectedKeys(). It replaces the SelectionKey operator.
261      */
262     private static class ServerSocketChannelIterator implements Iterator<ServerSocketChannel> {
263         /** The selected-key iterator */
264         private final Iterator<SelectionKey> iterator;
265 
266         /**
267          * Build a SocketChannel iterator which will return a SocketChannel instead of
268          * a SelectionKey.
269          * 
270          * @param selectedKeys The selector selected-key set 
271          */
272         private ServerSocketChannelIterator(Collection<SelectionKey> selectedKeys) {
273             iterator = selectedKeys.iterator();
274         }
275 
276         /**
277          * Tells if there are more SockectChannel left in the iterator
278          * @return <code>true</code> if there is at least one more 
279          * SockectChannel object to read
280          */
281         public boolean hasNext() {
282             return iterator.hasNext();
283         }
284 
285         /**
286          * Get the next SocketChannel in the operator we have built from
287          * the selected-key et for this selector.
288          * 
289          * @return The next SocketChannel in the iterator
290          */
291         public ServerSocketChannel next() {
292             SelectionKey key = iterator.next();
293 
294             if (key.isValid() && key.isAcceptable()) {
295                 return (ServerSocketChannel) key.channel();
296             }
297 
298             return null;
299         }
300 
301         /**
302          * Remove the current SocketChannel from the iterator 
303          */
304         public void remove() {
305             iterator.remove();
306         }
307     }
308 }