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