Package org.jboss.xnio.nio

Source Code of org.jboss.xnio.nio.NioTcpConnector$ConnectionHandler

/*
* 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.Socket;
import java.net.SocketAddress;
import java.net.SocketException;
import java.nio.channels.SelectionKey;
import java.nio.channels.SocketChannel;
import java.nio.channels.ClosedChannelException;
import java.util.concurrent.Executor;
import org.jboss.xnio.IoHandler;
import org.jboss.xnio.IoUtils;
import org.jboss.xnio.TcpChannelSource;
import org.jboss.xnio.channels.TcpChannel;
import org.jboss.xnio.FutureConnection;
import org.jboss.xnio.FinishedFutureConnection;
import org.jboss.xnio.AbstractFutureConnection;
import org.jboss.xnio.FailedFutureConnection;
import org.jboss.xnio.CloseableTcpConnector;
import org.jboss.xnio.log.Logger;

/**
*
*/
public final class NioTcpConnector implements CloseableTcpConnector {

    private static final Logger log = Logger.getLogger("org.jboss.xnio.nio.tcp.connector");

    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 Integer sendBufferSize;
    private final Boolean tcpNoDelay;
    private final boolean manageConnections;

    private NioTcpConnector(NioTcpConnectorConfig 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();
        sendBufferSize = config.getSendBuffer();
        tcpNoDelay = config.getNoDelay();
        manageConnections = config.isManageConnections();
    }

    private void configureStream(final Socket socket) throws SocketException {
        if (keepAlive != null) socket.setKeepAlive(keepAlive.booleanValue());
        if (oobInline != null) socket.setOOBInline(oobInline.booleanValue());
        if (receiveBufferSize != null) socket.setReceiveBufferSize(receiveBufferSize.intValue());
        if (reuseAddress != null) socket.setReuseAddress(reuseAddress.booleanValue());
        if (sendBufferSize != null) socket.setSendBufferSize(sendBufferSize.intValue());
        if (tcpNoDelay != null) socket.setTcpNoDelay(tcpNoDelay.booleanValue());
    }

    public FutureConnection<SocketAddress, TcpChannel> connectTo(final SocketAddress dest, final IoHandler<? super TcpChannel> handler) {
        if (dest == null) {
            throw new NullPointerException("dest is null");
        }
        if (handler == null) {
            throw new NullPointerException("handler is null");
        }
        return doConnectTo(null, dest, handler);
    }

    public FutureConnection<SocketAddress, TcpChannel> connectTo(final SocketAddress src, final SocketAddress dest, final IoHandler<? super TcpChannel> handler) {
        if (src == null) {
            throw new NullPointerException("src is null");
        }
        if (dest == null) {
            throw new NullPointerException("dest is null");
        }
        if (handler == null) {
            throw new NullPointerException("handler is null");
        }
        return doConnectTo(src, dest, handler);
    }

    public TcpChannelSource createChannelSource(final SocketAddress dest) {
        if (dest == null) {
            throw new NullPointerException("dest is null");
        }
        return new TcpChannelSource() {
            public FutureConnection<SocketAddress, TcpChannel> open(final IoHandler<? super TcpChannel> handler) {
                if (handler == null) {
                    throw new NullPointerException("handler is null");
                }
                return doConnectTo(null, dest, handler);
            }
        };
    }

    public TcpChannelSource createChannelSource(final SocketAddress src, final SocketAddress dest) {
        if (src == null) {
            throw new NullPointerException("src is null");
        }
        if (dest == null) {
            throw new NullPointerException("dest is null");
        }
        return new TcpChannelSource() {
            public FutureConnection<SocketAddress, TcpChannel> open(final IoHandler<? super TcpChannel> handler) {
                if (handler == null) {
                    throw new NullPointerException("handler is null");
                }
                return doConnectTo(src, dest, handler);
            }
        };
    }

    private FutureConnection<SocketAddress, TcpChannel> doConnectTo(final SocketAddress src, final SocketAddress dest, final IoHandler<? super TcpChannel> handler) {
        try {
            synchronized (lock) {
                if (closed) {
                    throw new ClosedChannelException();
                }
                log.trace("Connecting from %s to %s", src == null ? "-any-" : src, dest);
                final SocketChannel socketChannel = SocketChannel.open();
                socketChannel.configureBlocking(false);
                final Socket socket = socketChannel.socket();
                if (src != null) socket.bind(src);
                configureStream(socket);
                if (socketChannel.connect(dest)) {
                    final NioTcpChannel channel = new NioTcpChannel(nioXnio, socketChannel, handler, executor, manageConnections);
                    nioXnio.addManaged(channel);
                    executor.execute(new Runnable() {
                        public void run() {
                            log.trace("Connection from %s to %s is up (immediate)", src == null ? "-any-" : src, dest);
                            if (! HandlerUtils.<TcpChannel>handleOpened(handler, channel)) {
                                IoUtils.safeClose(socketChannel);
                                nioXnio.removeManaged(channel);
                            }
                        }
                    });
                    return new FinishedFutureConnection<SocketAddress, TcpChannel>(channel);
                } else {
                    final ConnectionHandler connectionHandler = new ConnectionHandler(executor, socketChannel, nioXnio, handler);
                    connectionHandler.handle.resume(SelectionKey.OP_CONNECT);
                    return connectionHandler.future;
                }
            }
        } catch (IOException e) {
            return new FailedFutureConnection<SocketAddress, TcpChannel>(e, src);
        }
    }

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

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

    static NioTcpConnector create(final NioTcpConnectorConfig config) {
        return new NioTcpConnector(config);
    }

    /**
     *
     */
    private final class ConnectionHandler implements Runnable {
        private final FutureImpl future;
        private final SocketChannel socketChannel;
        private final NioHandle handle;
        private final IoHandler<? super TcpChannel> handler;

        public ConnectionHandler(final Executor executor, final SocketChannel socketChannel, final NioXnio nioXnio, final IoHandler<? super TcpChannel> handler) throws IOException {
            this.socketChannel = socketChannel;
            this.handler = handler;
            // *should* be safe...
            //noinspection ThisEscapedInObjectConstruction
            handle = nioXnio.addConnectHandler(socketChannel, this, true);
            future = new FutureImpl(executor, socketChannel.socket().getLocalSocketAddress());
        }

        public void run() {
            try {
                if (socketChannel.finishConnect()) {
                    log.trace("Connection is up (deferred)");
                    final NioTcpChannel channel = new NioTcpChannel(nioXnio, socketChannel, handler, executor, manageConnections);
                    future.setResult(channel);
                    handler.handleOpened(channel);
                    handle.cancelKey();
                } else {
                    log.trace("Connection is not yet up (deferred)");
                    handle.resume(SelectionKey.OP_CONNECT);
                    return;
                }
            } catch (IOException e) {
                future.setException(e);
                handle.cancelKey();
            } catch (Exception e) {
                final String message = e.getMessage();
                final IOException ioexception = new IOException("Connection failed unexpectedly: " + message);
                ioexception.setStackTrace(e.getStackTrace());
                future.setException(ioexception);
                handle.cancelKey();
            }
        }

        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() {
                if (finishCancel()) {
                    IoUtils.safeClose(socketChannel);
                }
                return this;
            }
        }
    }
}
TOP

Related Classes of org.jboss.xnio.nio.NioTcpConnector$ConnectionHandler

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.