Example usage for io.netty.channel ChannelPromise channel

List of usage examples for io.netty.channel ChannelPromise channel

Introduction

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

Prototype

@Override
    Channel channel();

Source Link

Usage

From source file:com.relayrides.pushy.apns.ApnsClient.java

License:Open Source License

/**
 * <p>Sends a push notification to the APNs gateway.</p>
 *
 * <p>This method returns a {@code Future} that indicates whether the notification was accepted or rejected by the
 * gateway. If the notification was accepted, it may be delivered to its destination device at some time in the
 * future, but final delivery is not guaranteed. Rejections should be considered permanent failures, and callers
 * should <em>not</em> attempt to re-send the notification.</p>
 *
 * <p>The returned {@code Future} may fail with an exception if the notification could not be sent. Failures to
 * <em>send</em> a notification to the gatewayi.e. those that fail with exceptionsshould generally be considered
 * non-permanent, and callers should attempt to re-send the notification when the underlying problem has been
 * resolved.</p>// w ww . j ava2s . co  m
 *
 * <p>In particular, attempts to send a notification when the client is not connected will fail with a
 * {@link ClientNotConnectedException}. If the client was previously connected and has not been explicitly
 * disconnected (via the {@link ApnsClient#disconnect()} method), the client will attempt to reconnect
 * automatically. Callers may wait for a reconnection attempt to complete by waiting for the {@code Future} returned
 * by the {@link ApnsClient#getReconnectionFuture()} method.</p>
 *
 * @param notification the notification to send to the APNs gateway
 *
 * @param <T> the type of notification to be sent
 *
 * @return a {@code Future} that will complete when the notification has been either accepted or rejected by the
 * APNs gateway
 *
 * @since 0.8
 */
@SuppressWarnings({ "rawtypes", "unchecked" })
public <T extends ApnsPushNotification> Future<PushNotificationResponse<T>> sendNotification(
        final T notification) {
    final Future<PushNotificationResponse<T>> responseFuture;
    final long notificationId = this.nextNotificationId.getAndIncrement();

    // Instead of synchronizing here, we keep a final reference to the connection ready promise. We can get away
    // with this because we're not changing the state of the connection or its promises. Keeping a reference ensures
    // we won't suddenly "lose" the channel and get a NullPointerException, but risks sending a notification after
    // things have shut down. In that case, though, the returned futures should fail quickly, and the benefit of
    // not synchronizing for every write seems worth it.
    final ChannelPromise connectionReadyPromise = this.connectionReadyPromise;

    if (connectionReadyPromise != null && connectionReadyPromise.isSuccess()
            && connectionReadyPromise.channel().isActive()) {
        final Channel channel = connectionReadyPromise.channel();
        final Promise<PushNotificationResponse<ApnsPushNotification>> responsePromise = new DefaultPromise(
                channel.eventLoop());

        channel.writeAndFlush(new PushNotificationAndResponsePromise(notification, responsePromise))
                .addListener(new GenericFutureListener<ChannelFuture>() {

                    @Override
                    public void operationComplete(final ChannelFuture future) throws Exception {
                        if (future.isSuccess()) {
                            ApnsClient.this.metricsListener.handleNotificationSent(ApnsClient.this,
                                    notificationId);
                        } else {
                            responsePromise.tryFailure(future.cause());
                        }
                    }
                });

        responseFuture = (Future) responsePromise;
    } else {
        log.debug("Failed to send push notification because client is not connected: {}", notification);
        responseFuture = new FailedFuture<>(GlobalEventExecutor.INSTANCE, NOT_CONNECTED_EXCEPTION);
    }

    responseFuture.addListener(new GenericFutureListener<Future<PushNotificationResponse<T>>>() {

        @Override
        public void operationComplete(final Future<PushNotificationResponse<T>> future) throws Exception {
            if (future.isSuccess()) {
                final PushNotificationResponse<T> response = future.getNow();

                if (response.isAccepted()) {
                    ApnsClient.this.metricsListener.handleNotificationAccepted(ApnsClient.this, notificationId);
                } else {
                    ApnsClient.this.metricsListener.handleNotificationRejected(ApnsClient.this, notificationId);
                }
            } else {
                ApnsClient.this.metricsListener.handleWriteFailure(ApnsClient.this, notificationId);
            }
        }
    });

    return responseFuture;
}

From source file:dorkbox.network.connection.registration.remote.RegistrationRemoteHandler.java

License:Apache License

final void cleanupPipeline(final MetaChannel metaChannel, final Runnable onConnectFinishRunnable) {
    final int idleTimeout = this.registrationWrapper.getIdleTimeout();

    try {/*  w w  w  . ja  v a  2  s .co m*/
        // REMOVE our channel wrapper (only used for encryption) with the actual connection
        ChannelHandler handler = metaChannel.connection = ((ConnectionRegistrationImpl) metaChannel.connection).connection;

        Channel channel;
        if (metaChannel.tcpChannel != null) {
            channel = metaChannel.tcpChannel;
        } else {
            channel = metaChannel.udpChannel;
        }

        // channel should NEVER == null! (we will always have TCP or UDP!)
        // we also ONLY want to add this to a single cleanup, NOT BOTH, because this must only run once!!
        final ChannelPromise channelPromise = channel.newPromise();
        channelPromise.addListener(new FutureListener<Void>() {
            @Override
            public void operationComplete(final Future<Void> future) throws Exception {
                EventLoop loop = channelPromise.channel().eventLoop();
                loop.execute(new Runnable() {
                    @Override
                    public void run() {
                        logger.trace("Notify Connection");

                        // safe cast, because it's always this way...
                        registrationWrapper.connectionConnected0((ConnectionImpl) metaChannel.connection);

                        // run things AFTER the onConnect() method is called...
                        // CLIENT - runs the deferred 'onMessage' events in the connection as needed
                        // SERVER - send 'onConnect' bounce back message to client
                        onConnectFinishRunnable.run();
                    }
                });
            }
        });

        if (metaChannel.tcpChannel != null) {
            cleanupPipeline0(idleTimeout, handler, metaChannel.tcpChannel, channelPromise, true);
        }

        if (metaChannel.udpChannel != null) {
            cleanupPipeline0(idleTimeout, handler, metaChannel.udpChannel, channelPromise, false);
        }
    } catch (Exception e) {
        logger.error("Error during pipeline replace", e);
    }
}

From source file:dorkbox.network.connection.registration.remote.RegistrationRemoteHandler.java

License:Apache License

private void cleanupPipeline0(final int idleTimeout, final ChannelHandler connection, final Channel channel,
        final ChannelPromise channelPromise, final boolean isTcp) {
    final ChannelPipeline pipeline = channel.pipeline();

    // have to explicitly remove handlers based on the input type. Cannot use this.getClass()....
    boolean isClient = registrationWrapper.isClient();
    if (isClient) {
        if (isTcp) {
            pipeline.remove(RegistrationRemoteHandlerClientTCP.class);
        } else {/*from   w  ww  .j  av a  2s .  com*/
            pipeline.remove(RegistrationRemoteHandlerClientUDP.class);
        }
    } else {
        if (isTcp) {
            pipeline.remove(RegistrationRemoteHandlerServerTCP.class);
        } else {
            pipeline.remove(RegistrationRemoteHandlerServerUDP.class);
        }
    }

    pipeline.remove(ConnectionRegistrationImpl.class);

    if (idleTimeout > 0) {
        pipeline.replace(IDLE_HANDLER, IDLE_HANDLER_FULL,
                new IdleStateHandler(0, 0, idleTimeout, TimeUnit.MILLISECONDS));
    } else {
        pipeline.remove(IDLE_HANDLER);
    }

    pipeline.addLast(CONNECTION_HANDLER, connection);

    // we also DEREGISTER from the HANDSHAKE event-loop and run on the worker event-loop!
    ChannelFuture future = channel.deregister();
    future.addListener(new GenericFutureListener<Future<? super Void>>() {
        @Override
        public void operationComplete(final Future<? super Void> f) throws Exception {
            if (f.isSuccess()) {
                // TCP and UDP register on DIFFERENT event loops. The channel promise ONLY runs on 1 of them...
                if (channelPromise.channel() == channel) {
                    workerEventLoop.register(channelPromise);
                } else {
                    workerEventLoop.register(channel);
                }
            }
        }
    });
}