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         if (ch == null) {
220             return null;
221         }
222 
223         return new NioSocketSession(this, processor, ch);
224     }
225 
226     /**
227      * {@inheritDoc}
228      */
229     @Override
230     protected ServerSocketChannel open(SocketAddress localAddress)
231             throws Exception {
232         // Creates the listening ServerSocket
233         ServerSocketChannel channel = ServerSocketChannel.open();
234         
235         boolean success = false;
236         
237         try {
238             channel.configureBlocking(false);
239         
240             // Configure the server socket,
241             ServerSocket socket = channel.socket();
242             
243             socket.setReuseAddress(isReuseAddress());
244             // XXX: Do we need to provide this property? (I think we need to remove it.)
245             socket.setReceiveBufferSize(getSessionConfig().getReceiveBufferSize());
246             // and bind.
247             socket.bind(localAddress, getBacklog());
248             // Register the channel within the selector for ACCEPT event
249             channel.register(selector, SelectionKey.OP_ACCEPT);
250             success = true;
251         } finally {
252             if (!success) {
253                 close(channel);
254             }
255         }
256         return channel;
257     }
258 
259     /**
260      * {@inheritDoc}
261      */
262     @Override
263     protected SocketAddress localAddress(ServerSocketChannel handle)
264             throws Exception {
265         return handle.socket().getLocalSocketAddress();
266     }
267 
268     /**
269       * Check if we have at least one key whose corresponding channels is 
270       * ready for I/O operations.
271       *
272       * This method performs a blocking selection operation. 
273       * It returns only after at least one channel is selected, 
274       * this selector's wakeup method is invoked, or the current thread 
275       * is interrupted, whichever comes first.
276       * 
277       * @return The number of keys having their ready-operation set updated
278       * @throws IOException If an I/O error occurs
279       * @throws ClosedSelectorException If this selector is closed 
280       */
281     @Override
282     protected int select() throws Exception {
283         return selector.select();
284     }
285 
286     /**
287      * {@inheritDoc}
288      */
289     @Override
290     protected Iterator<ServerSocketChannel> selectedHandles() {
291         return new ServerSocketChannelIterator(selector.selectedKeys());
292     }
293 
294     /**
295      * {@inheritDoc}
296      */
297     @Override
298     protected void close(ServerSocketChannel handle) throws Exception {
299         SelectionKey key = handle.keyFor(selector);
300         
301         if (key != null) {
302             key.cancel();
303         }
304         
305         handle.close();
306     }
307 
308     /**
309      * {@inheritDoc}
310      */
311     @Override
312     protected void wakeup() {
313         selector.wakeup();
314     }
315 
316     /**
317      * Defines an iterator for the selected-key Set returned by the 
318      * selector.selectedKeys(). It replaces the SelectionKey operator.
319      */
320     private static class ServerSocketChannelIterator implements Iterator<ServerSocketChannel> {
321         /** The selected-key iterator */
322         private final Iterator<SelectionKey> iterator;
323 
324         /**
325          * Build a SocketChannel iterator which will return a SocketChannel instead of
326          * a SelectionKey.
327          * 
328          * @param selectedKeys The selector selected-key set 
329          */
330         private ServerSocketChannelIterator(Collection<SelectionKey> selectedKeys) {
331             iterator = selectedKeys.iterator();
332         }
333 
334         /**
335          * Tells if there are more SockectChannel left in the iterator
336          * @return <code>true</code> if there is at least one more 
337          * SockectChannel object to read
338          */
339         public boolean hasNext() {
340             return iterator.hasNext();
341         }
342 
343         /**
344          * Get the next SocketChannel in the operator we have built from
345          * the selected-key et for this selector.
346          * 
347          * @return The next SocketChannel in the iterator
348          */
349         public ServerSocketChannel next() {
350             SelectionKey key = iterator.next();
351             
352             if ( key.isValid() && key.isAcceptable() ) {
353                 return (ServerSocketChannel) key.channel();
354             } else {
355                 return null;
356             }
357         }
358 
359         /**
360          * Remove the current SocketChannel from the iterator 
361          */
362         public void remove() {
363             iterator.remove();
364         }
365     }
366 }