Package org.jboss.xnio.nio

Source Code of org.jboss.xnio.nio.NioTcpAcceptor$Handler

/*
* JBoss, Home of Professional Open Source
* Copyright 2008, JBoss Inc., and individual contributors as indicated
* by the @authors tag. See the copyright.txt in the distribution for a
* full listing of individual contributors.
*
* This is free software; you can redistribute it and/or modify it
* under the terms of the GNU Lesser General Public License as
* published by the Free Software Foundation; either version 2.1 of
* the License, or (at your option) any later version.
*
* This software is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this software; if not, write to the Free
* Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
* 02110-1301 USA, or see the FSF site: http://www.fsf.org.
*/

package org.jboss.xnio.nio;

import java.io.IOException;
import java.net.ServerSocket;
import java.net.Socket;
import java.net.SocketAddress;
import java.nio.channels.ClosedChannelException;
import java.nio.channels.SelectionKey;
import java.nio.channels.ServerSocketChannel;
import java.nio.channels.SocketChannel;
import java.util.concurrent.Executor;
import org.jboss.xnio.AbstractFutureConnection;
import org.jboss.xnio.CloseableTcpAcceptor;
import org.jboss.xnio.FailedFutureConnection;
import org.jboss.xnio.FinishedFutureConnection;
import org.jboss.xnio.FutureConnection;
import org.jboss.xnio.IoHandler;
import org.jboss.xnio.IoUtils;
import org.jboss.xnio.TcpChannelDestination;
import org.jboss.xnio.channels.TcpChannel;
import org.jboss.xnio.log.Logger;

/**
*
*/
public final class NioTcpAcceptor implements CloseableTcpAcceptor {
    private static final Logger log = Logger.getLogger("org.jboss.xnio.nio.tcp.acceptor");

    private final NioXnio nioXnio;
    private final Executor executor;

    private final Object lock = new Object();

    private boolean closed;

    private final Boolean keepAlive;
    private final Boolean oobInline;
    private final Integer receiveBufferSize;
    private final Boolean reuseAddress;
    private final Boolean tcpNoDelay;
    private final boolean manageConnections;

    private NioTcpAcceptor(NioTcpAcceptorConfig config) {
        nioXnio = config.getXnio();
        executor = config.getExecutor();
        if (nioXnio == null) {
            throw new NullPointerException("nioXnio is null");
        }
        if (executor == null) {
            throw new NullPointerException("executor is null");
        }
        keepAlive = config.getKeepAlive();
        oobInline = config.getOobInline();
        receiveBufferSize = config.getReceiveBuffer();
        reuseAddress = config.getReuseAddresses();
        tcpNoDelay = config.getNoDelay();
        manageConnections = config.isManageConnections();
    }

    static NioTcpAcceptor create(NioTcpAcceptorConfig config) {
        return new NioTcpAcceptor(config);
    }

    public FutureConnection<SocketAddress, TcpChannel> acceptTo(final SocketAddress dest, final IoHandler<? super TcpChannel> handler) {
        try {
            synchronized (lock) {
                if (closed) {
                    throw new ClosedChannelException();
                }
                final ServerSocketChannel serverSocketChannel = ServerSocketChannel.open();
                serverSocketChannel.configureBlocking(false);
                final ServerSocket serverSocket = serverSocketChannel.socket();
                if (receiveBufferSize != null) serverSocket.setReceiveBufferSize(receiveBufferSize.intValue());
                if (reuseAddress != null) serverSocket.setReuseAddress(reuseAddress.booleanValue());
                serverSocket.bind(dest, 1);
                final SocketChannel socketChannel = serverSocketChannel.accept();
                // unlikely, but...
                if (socketChannel != null) {
                    return new FinishedFutureConnection<SocketAddress, TcpChannel>(new NioTcpChannel(nioXnio, socketChannel, handler, executor, manageConnections));
                }
                final Handler nioHandler = new Handler(serverSocketChannel, handler);
                final NioHandle handle = nioXnio.addConnectHandler(serverSocketChannel, nioHandler, true);
                nioHandler.handle = handle;
                handle.resume(SelectionKey.OP_ACCEPT);
                return nioHandler.future;
            }
        } catch (IOException e) {
            return new FailedFutureConnection<SocketAddress, TcpChannel>(e, dest);
        }
    }

    public TcpChannelDestination createChannelDestination(final SocketAddress dest) {
        return new TcpChannelDestination() {
            public FutureConnection<SocketAddress, TcpChannel> accept(final IoHandler<? super TcpChannel> handler) {
                return acceptTo(dest, handler);
            }
        };
    }

    public void close() throws IOException {
        synchronized (lock) {
            if (! closed) {
                log.trace("Closing %s", this);
                closed = true;
            }
        }
    }

    private final class Handler implements Runnable {
        private final FutureImpl future;
        private final ServerSocketChannel serverSocketChannel;
        private final IoHandler<? super TcpChannel> handler;
        private volatile NioHandle handle;

        public Handler(final ServerSocketChannel serverSocketChannel, final IoHandler<? super TcpChannel> handler) {
            this.serverSocketChannel = serverSocketChannel;
            this.handler = handler;
            future = new FutureImpl(executor, serverSocketChannel.socket().getLocalSocketAddress());
        }

        public void run() {
            try {
                boolean ok = false;
                final SocketChannel socketChannel = serverSocketChannel.accept();
                if (socketChannel == null) {
                    handle.resume(SelectionKey.OP_ACCEPT);
                    return;
                }
                try {
                    IoUtils.safeClose(serverSocketChannel);
                    socketChannel.configureBlocking(false);
                    final Socket socket = socketChannel.socket();
                    if (keepAlive != null) socket.setKeepAlive(keepAlive.booleanValue());
                    if (oobInline != null) socket.setOOBInline(oobInline.booleanValue());
                    if (tcpNoDelay != null) socket.setTcpNoDelay(tcpNoDelay.booleanValue());
                    final NioTcpChannel channel = new NioTcpChannel(nioXnio, socketChannel, handler, executor, manageConnections);
                    ok = HandlerUtils.<TcpChannel>handleOpened(handler, channel);
                    if (ok) {
                        nioXnio.addManaged(channel);
                        log.trace("TCP server accepted connection");
                    }
                    future.setResult(channel);
                } finally {
                    if (! ok) {
                        log.trace("TCP server failed to accept connection");
                        // do NOT call close handler, since open handler was either not called or it failed
                        IoUtils.safeClose(serverSocketChannel);
                        IoUtils.safeClose(socketChannel);
                    }
                }
            } catch (ClosedChannelException e) {
                IoUtils.safeClose(serverSocketChannel);
                log.trace("Channel closed: %s", e.getMessage());
                future.setException(e);
            } catch (IOException e) {
                IoUtils.safeClose(serverSocketChannel);
                log.trace(e, "I/O error on TCP server");
                future.setException(e);
            }
        }

        private final class FutureImpl extends AbstractFutureConnection<SocketAddress, TcpChannel> {
            private final Executor executor;
            private final SocketAddress localAddress;

            public FutureImpl(final Executor executor, final SocketAddress address) {
                this.executor = executor;
                localAddress = address;
            }

            protected boolean setException(final IOException exception) {
                return super.setException(exception);
            }

            protected boolean setResult(final TcpChannel result) {
                return super.setResult(result);
            }

            protected boolean finishCancel() {
                return super.finishCancel();
            }

            protected Executor getNotifierExecutor() {
                return executor;
            }

            public SocketAddress getLocalAddress() {
                return localAddress;
            }

            public FutureConnection<SocketAddress, TcpChannel> cancel() {
                IoUtils.safeClose(serverSocketChannel);
                finishCancel();
                return this;
            }
        }
    }

    public String toString() {
        return String.format("TCP acceptor (NIO) <%s>", Integer.toString(hashCode(), 16));
    }
}
TOP

Related Classes of org.jboss.xnio.nio.NioTcpAcceptor$Handler

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.