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.SocketAddress;
24  import java.nio.channels.SelectionKey;
25  import java.nio.channels.Selector;
26  import java.nio.channels.ServerSocketChannel;
27  import java.nio.channels.SocketChannel;
28  import java.util.Collection;
29  import java.util.Iterator;
30  import java.util.concurrent.Executor;
31  
32  import org.apache.mina.common.AbstractPollingIoAcceptor;
33  import org.apache.mina.common.IoAcceptor;
34  import org.apache.mina.common.IoProcessor;
35  import org.apache.mina.common.TransportMetadata;
36  import org.apache.mina.transport.socket.DefaultSocketSessionConfig;
37  import org.apache.mina.transport.socket.SocketAcceptor;
38  import org.apache.mina.transport.socket.SocketSessionConfig;
39  
40  /**
41   * {@link IoAcceptor} for socket transport (TCP/IP).  This class
42   * handles incoming TCP/IP based socket connections.
43   *
44   * @author The Apache MINA Project (dev@mina.apache.org)
45   * @version $Rev: 389042 $, $Date: 2006-03-27 07:49:41Z $
46   */
47  public final class NioSocketAcceptor
48          extends AbstractPollingIoAcceptor<NioSession, ServerSocketChannel> 
49          implements SocketAcceptor {
50  
51      private int backlog = 50;
52      private boolean reuseAddress = true;
53  
54      private volatile Selector selector;
55  
56      /**
57       * Create an acceptor with a single processing thread using a NewThreadExecutor
58       */
59      public NioSocketAcceptor() {
60          super(new DefaultSocketSessionConfig(), NioProcessor.class);
61      }
62  
63      public NioSocketAcceptor(int processorCount) {
64          super(new DefaultSocketSessionConfig(), NioProcessor.class, processorCount);
65      }
66      
67      public NioSocketAcceptor(IoProcessor<NioSession> processor) {
68          super(new DefaultSocketSessionConfig(), processor);
69      }
70  
71      public NioSocketAcceptor(Executor executor, IoProcessor<NioSession> processor) {
72          super(new DefaultSocketSessionConfig(), executor, processor);
73      }
74  
75      @Override
76      protected void init() throws Exception {
77          // The default reuseAddress of an accepted socket should be 'true'.
78          getSessionConfig().setReuseAddress(true);
79          this.selector = Selector.open();
80      }
81      
82      @Override
83      protected void destroy() throws Exception {
84          if (selector != null) {
85              selector.close();
86          }
87      }
88  
89      public TransportMetadata getTransportMetadata() {
90          return NioSocketSession.METADATA;
91      }
92  
93      @Override
94      public SocketSessionConfig getSessionConfig() {
95          return (SocketSessionConfig) super.getSessionConfig();
96      }
97  
98      @Override
99      public InetSocketAddress getLocalAddress() {
100         return (InetSocketAddress) super.getLocalAddress();
101     }
102     
103     @Override
104     public InetSocketAddress getDefaultLocalAddress() {
105         return (InetSocketAddress) super.getDefaultLocalAddress();
106     }
107 
108     public void setDefaultLocalAddress(InetSocketAddress localAddress) {
109         setDefaultLocalAddress((SocketAddress) localAddress);
110     }
111 
112     public boolean isReuseAddress() {
113         return reuseAddress;
114     }
115 
116     public void setReuseAddress(boolean reuseAddress) {
117         synchronized (bindLock) {
118             if (isActive()) {
119                 throw new IllegalStateException(
120                         "reuseAddress can't be set while the acceptor is bound.");
121             }
122 
123             this.reuseAddress = reuseAddress;
124         }
125     }
126 
127     public int getBacklog() {
128         return backlog;
129     }
130 
131     public void setBacklog(int backlog) {
132         synchronized (bindLock) {
133             if (isActive()) {
134                 throw new IllegalStateException(
135                         "backlog can't be set while the acceptor is bound.");
136             }
137 
138             this.backlog = backlog;
139         }
140     }
141 
142     
143     @Override
144     protected NioSession accept(IoProcessor<NioSession> processor,
145             ServerSocketChannel handle) throws Exception {
146 
147         SelectionKey key = handle.keyFor(selector);
148         if (!key.isAcceptable()) {
149             return null;
150         }
151 
152         // accept the connection from the client
153         SocketChannel ch = handle.accept();
154         if (ch == null) {
155             return null;
156         }
157 
158         return new NioSocketSession(this, processor, ch);
159     }
160 
161     @Override
162     protected ServerSocketChannel open(SocketAddress localAddress)
163             throws Exception {
164         ServerSocketChannel c = ServerSocketChannel.open();
165         boolean success = false;
166         try {
167             c.configureBlocking(false);
168             // Configure the server socket,
169             c.socket().setReuseAddress(isReuseAddress());
170             c.socket().setReceiveBufferSize(
171                     getSessionConfig().getReceiveBufferSize());
172             // and bind.
173             c.socket().bind(localAddress, getBacklog());
174             c.register(selector, SelectionKey.OP_ACCEPT);
175             success = true;
176         } finally {
177             if (!success) {
178                 close(c);
179             }
180         }
181         return c;
182     }
183 
184     @Override
185     protected SocketAddress localAddress(ServerSocketChannel handle)
186             throws Exception {
187         return handle.socket().getLocalSocketAddress();
188     }
189 
190     @Override
191     protected boolean select() throws Exception {
192         return selector.select() > 0;
193     }
194 
195     @Override
196     protected Iterator<ServerSocketChannel> selectedHandles() {
197         return new ServerSocketChannelIterator(selector.selectedKeys());
198     }
199 
200     @Override
201     protected void close(ServerSocketChannel handle) throws Exception {
202         SelectionKey key = handle.keyFor(selector);
203         if (key != null) {
204             key.cancel();
205         }
206         handle.close();
207     }
208 
209     @Override
210     protected void wakeup() {
211         selector.wakeup();
212     }
213 
214     private static class ServerSocketChannelIterator implements Iterator<ServerSocketChannel> {
215         
216         private final Iterator<SelectionKey> i;
217         
218         private ServerSocketChannelIterator(Collection<SelectionKey> selectedKeys) {
219             this.i = selectedKeys.iterator();
220         }
221 
222         public boolean hasNext() {
223             return i.hasNext();
224         }
225 
226         public ServerSocketChannel next() {
227             SelectionKey key = i.next();
228             return (ServerSocketChannel) key.channel();
229         }
230 
231         public void remove() {
232             i.remove();
233         }
234     }
235 }