001: /*
002: * Licensed to the Apache Software Foundation (ASF) under one
003: * or more contributor license agreements. See the NOTICE file
004: * distributed with this work for additional information
005: * regarding copyright ownership. The ASF licenses this file
006: * to you under the Apache License, Version 2.0 (the
007: * "License"); you may not use this file except in compliance
008: * with the License. You may obtain a copy of the License at
009: *
010: * http://www.apache.org/licenses/LICENSE-2.0
011: *
012: * Unless required by applicable law or agreed to in writing,
013: * software distributed under the License is distributed on an
014: * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
015: * KIND, either express or implied. See the License for the
016: * specific language governing permissions and limitations
017: * under the License.
018: *
019: */
020: package org.apache.mina.transport.socket.nio;
021:
022: import java.net.InetSocketAddress;
023: import java.net.SocketAddress;
024: import java.nio.channels.SelectionKey;
025: import java.nio.channels.Selector;
026: import java.nio.channels.ServerSocketChannel;
027: import java.nio.channels.SocketChannel;
028: import java.util.Collection;
029: import java.util.Iterator;
030: import java.util.concurrent.Executor;
031:
032: import org.apache.mina.common.AbstractPollingIoAcceptor;
033: import org.apache.mina.common.IoAcceptor;
034: import org.apache.mina.common.IoProcessor;
035: import org.apache.mina.common.TransportMetadata;
036: import org.apache.mina.transport.socket.DefaultSocketSessionConfig;
037: import org.apache.mina.transport.socket.SocketAcceptor;
038: import org.apache.mina.transport.socket.SocketSessionConfig;
039:
040: /**
041: * {@link IoAcceptor} for socket transport (TCP/IP). This class
042: * handles incoming TCP/IP based socket connections.
043: *
044: * @author The Apache MINA Project (dev@mina.apache.org)
045: * @version $Rev: 389042 $, $Date: 2006-03-27 07:49:41Z $
046: */
047: public final class NioSocketAcceptor extends
048: AbstractPollingIoAcceptor<NioSession, ServerSocketChannel>
049: implements SocketAcceptor {
050:
051: private int backlog = 50;
052: private boolean reuseAddress = true;
053:
054: private volatile Selector selector;
055:
056: /**
057: * Create an acceptor with a single processing thread using a NewThreadExecutor
058: */
059: public NioSocketAcceptor() {
060: super (new DefaultSocketSessionConfig(), NioProcessor.class);
061: }
062:
063: public NioSocketAcceptor(int processorCount) {
064: super (new DefaultSocketSessionConfig(), NioProcessor.class,
065: processorCount);
066: }
067:
068: public NioSocketAcceptor(IoProcessor<NioSession> processor) {
069: super (new DefaultSocketSessionConfig(), processor);
070: }
071:
072: public NioSocketAcceptor(Executor executor,
073: IoProcessor<NioSession> processor) {
074: super (new DefaultSocketSessionConfig(), executor, processor);
075: }
076:
077: @Override
078: protected void init() throws Exception {
079: // The default reuseAddress of an accepted socket should be 'true'.
080: getSessionConfig().setReuseAddress(true);
081: this .selector = Selector.open();
082: }
083:
084: @Override
085: protected void destroy() throws Exception {
086: if (selector != null) {
087: selector.close();
088: }
089: }
090:
091: public TransportMetadata getTransportMetadata() {
092: return NioSocketSession.METADATA;
093: }
094:
095: @Override
096: public SocketSessionConfig getSessionConfig() {
097: return (SocketSessionConfig) super .getSessionConfig();
098: }
099:
100: @Override
101: public InetSocketAddress getLocalAddress() {
102: return (InetSocketAddress) super .getLocalAddress();
103: }
104:
105: @Override
106: public InetSocketAddress getDefaultLocalAddress() {
107: return (InetSocketAddress) super .getDefaultLocalAddress();
108: }
109:
110: public void setDefaultLocalAddress(InetSocketAddress localAddress) {
111: setDefaultLocalAddress((SocketAddress) localAddress);
112: }
113:
114: public boolean isReuseAddress() {
115: return reuseAddress;
116: }
117:
118: public void setReuseAddress(boolean reuseAddress) {
119: synchronized (bindLock) {
120: if (isActive()) {
121: throw new IllegalStateException(
122: "reuseAddress can't be set while the acceptor is bound.");
123: }
124:
125: this .reuseAddress = reuseAddress;
126: }
127: }
128:
129: public int getBacklog() {
130: return backlog;
131: }
132:
133: public void setBacklog(int backlog) {
134: synchronized (bindLock) {
135: if (isActive()) {
136: throw new IllegalStateException(
137: "backlog can't be set while the acceptor is bound.");
138: }
139:
140: this .backlog = backlog;
141: }
142: }
143:
144: @Override
145: protected NioSession accept(IoProcessor<NioSession> processor,
146: ServerSocketChannel handle) throws Exception {
147:
148: SelectionKey key = handle.keyFor(selector);
149: if (!key.isAcceptable()) {
150: return null;
151: }
152:
153: // accept the connection from the client
154: SocketChannel ch = handle.accept();
155: if (ch == null) {
156: return null;
157: }
158:
159: return new NioSocketSession(this , processor, ch);
160: }
161:
162: @Override
163: protected ServerSocketChannel open(SocketAddress localAddress)
164: throws Exception {
165: ServerSocketChannel c = ServerSocketChannel.open();
166: boolean success = false;
167: try {
168: c.configureBlocking(false);
169: // Configure the server socket,
170: c.socket().setReuseAddress(isReuseAddress());
171: c.socket().setReceiveBufferSize(
172: getSessionConfig().getReceiveBufferSize());
173: // and bind.
174: c.socket().bind(localAddress, getBacklog());
175: c.register(selector, SelectionKey.OP_ACCEPT);
176: success = true;
177: } finally {
178: if (!success) {
179: close(c);
180: }
181: }
182: return c;
183: }
184:
185: @Override
186: protected SocketAddress localAddress(ServerSocketChannel handle)
187: throws Exception {
188: return handle.socket().getLocalSocketAddress();
189: }
190:
191: @Override
192: protected boolean select() throws Exception {
193: return selector.select() > 0;
194: }
195:
196: @Override
197: protected Iterator<ServerSocketChannel> selectedHandles() {
198: return new ServerSocketChannelIterator(selector.selectedKeys());
199: }
200:
201: @Override
202: protected void close(ServerSocketChannel handle) throws Exception {
203: SelectionKey key = handle.keyFor(selector);
204: if (key != null) {
205: key.cancel();
206: }
207: handle.close();
208: }
209:
210: @Override
211: protected void wakeup() {
212: selector.wakeup();
213: }
214:
215: private static class ServerSocketChannelIterator implements
216: Iterator<ServerSocketChannel> {
217:
218: private final Iterator<SelectionKey> i;
219:
220: private ServerSocketChannelIterator(
221: Collection<SelectionKey> selectedKeys) {
222: this .i = selectedKeys.iterator();
223: }
224:
225: public boolean hasNext() {
226: return i.hasNext();
227: }
228:
229: public ServerSocketChannel next() {
230: SelectionKey key = i.next();
231: return (ServerSocketChannel) key.channel();
232: }
233:
234: public void remove() {
235: i.remove();
236: }
237: }
238: }
|