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