Example usage for io.netty.channel ChannelFuture cancel

List of usage examples for io.netty.channel ChannelFuture cancel

Introduction

In this page you can find the example usage for io.netty.channel ChannelFuture cancel.

Prototype

@Override
boolean cancel(boolean mayInterruptIfRunning);

Source Link

Document

If the cancellation was successful it will fail the future with a CancellationException .

Usage

From source file:ws.wamp.jawampa.transport.netty.NettyWampClientConnectorProvider.java

License:Apache License

@Override
public IWampConnector createConnector(final URI uri, IWampClientConnectionConfig configuration,
        List<WampSerialization> serializations, final SocketAddress proxyAddress) throws Exception {

    String scheme = uri.getScheme();
    scheme = scheme != null ? scheme : "";

    // Check if the configuration is a netty configuration.
    // However null is an allowed value
    final NettyWampConnectionConfig nettyConfig;
    if (configuration instanceof NettyWampConnectionConfig) {
        nettyConfig = (NettyWampConnectionConfig) configuration;
    } else if (configuration != null) {
        throw new ApplicationError(ApplicationError.INVALID_CONNECTION_CONFIGURATION);
    } else {//from w ww.j  a va 2  s  . c  o m
        nettyConfig = null;
    }

    if (scheme.equalsIgnoreCase("ws") || scheme.equalsIgnoreCase("wss")) {

        // Check the host and port field for validity
        if (uri.getHost() == null || uri.getPort() == 0) {
            throw new ApplicationError(ApplicationError.INVALID_URI);
        }

        // Initialize SSL when required
        final boolean needSsl = uri.getScheme().equalsIgnoreCase("wss");
        final SslContext sslCtx0;
        if (needSsl && (nettyConfig == null || nettyConfig.sslContext() == null)) {
            // Create a default SslContext when we got none provided through the constructor
            try {
                sslCtx0 = SslContext.newClientContext(InsecureTrustManagerFactory.INSTANCE);
            } catch (SSLException e) {
                throw e;
            }
        } else if (needSsl) {
            sslCtx0 = nettyConfig.sslContext();
        } else {
            sslCtx0 = null;
        }

        final String subProtocols = WampSerialization.makeWebsocketSubprotocolList(serializations);

        final int maxFramePayloadLength = (nettyConfig == null)
                ? NettyWampConnectionConfig.DEFAULT_MAX_FRAME_PAYLOAD_LENGTH
                : nettyConfig.getMaxFramePayloadLength();

        // Return a factory that creates a channel for websocket connections
        return new IWampConnector() {
            @Override
            public IPendingWampConnection connect(final ScheduledExecutorService scheduler,
                    final IPendingWampConnectionListener connectListener,
                    final IWampConnectionListener connectionListener) {

                // Use well-known ports if not explicitly specified
                final int port;
                if (uri.getPort() == -1) {
                    if (needSsl)
                        port = 443;
                    else
                        port = 80;
                } else
                    port = uri.getPort();

                final WebSocketClientHandshaker handshaker = WebSocketClientHandshakerFactory.newHandshaker(uri,
                        WebSocketVersion.V13, subProtocols, false, new DefaultHttpHeaders(),
                        maxFramePayloadLength);

                /**
                 * Netty handler for that receives and processes WampMessages and state
                 * events from the pipeline.
                 * A new instance of this is created for each connection attempt.
                 */
                final ChannelHandler connectionHandler = new SimpleChannelInboundHandler<WampMessage>() {
                    boolean connectionWasEstablished = false;
                    /** Guard to prevent forwarding events aftert the channel was closed */
                    boolean wasClosed = false;

                    @Override
                    public void channelInactive(ChannelHandlerContext ctx) throws Exception {
                        if (wasClosed)
                            return;
                        wasClosed = true;
                        if (connectionWasEstablished) {
                            connectionListener.transportClosed();
                        } else {
                            // The transport closed before the websocket handshake was completed
                            connectListener
                                    .connectFailed(new ApplicationError(ApplicationError.TRANSPORT_CLOSED));
                        }
                    }

                    @Override
                    public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception {
                        if (wasClosed)
                            return;
                        wasClosed = true;
                        if (connectionWasEstablished) {
                            connectionListener.transportError(cause);
                        } else {
                            // The transport closed before the websocket handshake was completed
                            connectListener.connectFailed(cause);
                        }
                        super.exceptionCaught(ctx, cause);
                    }

                    @Override
                    public void userEventTriggered(final ChannelHandlerContext ctx, Object evt)
                            throws Exception {
                        if (wasClosed)
                            return;
                        if (evt instanceof ConnectionEstablishedEvent) {
                            ConnectionEstablishedEvent ev = (ConnectionEstablishedEvent) evt;
                            final WampSerialization serialization = ev.serialization();

                            IWampConnection connection = new IWampConnection() {
                                @Override
                                public WampSerialization serialization() {
                                    return serialization;
                                }

                                @Override
                                public boolean isSingleWriteOnly() {
                                    return false;
                                }

                                @Override
                                public void sendMessage(WampMessage message,
                                        final IWampConnectionPromise<Void> promise) {
                                    ChannelFuture f = ctx.writeAndFlush(message);
                                    f.addListener(new ChannelFutureListener() {
                                        @Override
                                        public void operationComplete(ChannelFuture future) throws Exception {
                                            if (future.isSuccess() || future.isCancelled())
                                                promise.fulfill(null);
                                            else
                                                promise.reject(future.cause());
                                        }
                                    });
                                }

                                @Override
                                public void close(boolean sendRemaining,
                                        final IWampConnectionPromise<Void> promise) {
                                    // sendRemaining is ignored. Remaining data is always sent
                                    ctx.writeAndFlush(Unpooled.EMPTY_BUFFER)
                                            .addListener(new ChannelFutureListener() {
                                                @Override
                                                public void operationComplete(ChannelFuture future)
                                                        throws Exception {
                                                    future.channel().close()
                                                            .addListener(new ChannelFutureListener() {
                                                                @Override
                                                                public void operationComplete(
                                                                        ChannelFuture future) throws Exception {
                                                                    if (future.isSuccess()
                                                                            || future.isCancelled())
                                                                        promise.fulfill(null);
                                                                    else
                                                                        promise.reject(future.cause());
                                                                }
                                                            });
                                                }
                                            });
                                }
                            };

                            connectionWasEstablished = true;

                            // Connection to the remote host was established
                            // However the WAMP session is not established until the handshake was finished
                            connectListener.connectSucceeded(connection);
                        }
                    }

                    @Override
                    protected void channelRead0(ChannelHandlerContext ctx, WampMessage msg) throws Exception {
                        if (wasClosed)
                            return;
                        assert (connectionWasEstablished);
                        connectionListener.messageReceived(msg);
                    }
                };

                // If the assigned scheduler is a netty eventloop use this
                final EventLoopGroup nettyEventLoop;
                if (scheduler instanceof EventLoopGroup) {
                    nettyEventLoop = (EventLoopGroup) scheduler;
                } else {
                    connectListener.connectFailed(new ApplicationError(ApplicationError.INCOMATIBLE_SCHEDULER));
                    return IPendingWampConnection.Dummy;
                }

                Bootstrap b = new Bootstrap();

                // things should be resolved on via the socks5 proxy
                if (proxyAddress != null)
                    b.resolver(NoopAddressResolverGroup.INSTANCE);

                b.group(nettyEventLoop).channel(NioSocketChannel.class)
                        .handler(new ChannelInitializer<SocketChannel>() {
                            @Override
                            protected void initChannel(SocketChannel ch) {
                                ChannelPipeline p = ch.pipeline();
                                if (proxyAddress != null) {
                                    p.addFirst("proxy", new Socks5ProxyHandler(proxyAddress));
                                }
                                if (sslCtx0 != null) {
                                    p.addLast(sslCtx0.newHandler(ch.alloc(), uri.getHost(), port));
                                }
                                p.addLast(new HttpClientCodec(), new HttpObjectAggregator(8192),
                                        new WebSocketClientProtocolHandler(handshaker, false),
                                        new WebSocketFrameAggregator(
                                                WampHandlerConfiguration.MAX_WEBSOCKET_FRAME_SIZE),
                                        new WampClientWebsocketHandler(handshaker), connectionHandler);
                            }
                        });

                final ChannelFuture connectFuture = b.connect(uri.getHost(), port);
                connectFuture.addListener(new ChannelFutureListener() {
                    @Override
                    public void operationComplete(ChannelFuture future) throws Exception {
                        if (future.isSuccess()) {
                            // Do nothing. The connection is only successful when the websocket handshake succeeds
                        } else {
                            // Remark: Might be called directly in addListener
                            // Therefore addListener should be the last call
                            // Remark2: This branch will be taken upon cancellation.
                            // This is required by the contract.
                            connectListener.connectFailed(future.cause());
                        }
                    }
                });

                // Return the connection in progress with the ability for cancellation
                return new IPendingWampConnection() {
                    @Override
                    public void cancelConnect() {
                        connectFuture.cancel(false);
                    }
                };
            }
        };
    }

    throw new ApplicationError(ApplicationError.INVALID_URI);
}