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