Example usage for io.netty.util.concurrent GenericFutureListener GenericFutureListener

List of usage examples for io.netty.util.concurrent GenericFutureListener GenericFutureListener

Introduction

In this page you can find the example usage for io.netty.util.concurrent GenericFutureListener GenericFutureListener.

Prototype

GenericFutureListener

Source Link

Usage

From source file:com.turo.pushy.apns.ApnsChannelPool.java

License:Open Source License

private void discardChannel(final Channel channel) {
    assert this.executor.inEventLoop();

    this.idleChannels.remove(channel);
    this.allChannels.remove(channel);

    this.metricsListener.handleConnectionRemoved();

    this.channelFactory.destroy(channel, this.executor.<Void>newPromise())
            .addListener(new GenericFutureListener<Future<Void>>() {
                @Override/*www  . j a  va2 s  . co m*/
                public void operationComplete(final Future<Void> destroyFuture) throws Exception {
                    if (!destroyFuture.isSuccess()) {
                        log.warn("Failed to destroy channel.", destroyFuture.cause());
                    }
                }
            });
}

From source file:com.turo.pushy.apns.ApnsChannelPool.java

License:Open Source License

/**
 * Shuts down this channel pool and releases all retained resources.
 *
 * @return a {@code Future} that will be completed when all resources held by this pool have been released
 *//*from ww  w  . j a v  a  2s  .c  o  m*/
public Future<Void> close() {
    return this.allChannels.close().addListener(new GenericFutureListener<Future<Void>>() {
        @Override
        public void operationComplete(final Future<Void> future) throws Exception {
            ApnsChannelPool.this.isClosed = true;

            if (ApnsChannelPool.this.channelFactory instanceof Closeable) {
                ((Closeable) ApnsChannelPool.this.channelFactory).close();
            }

            for (final Promise<Channel> acquisitionPromise : ApnsChannelPool.this.pendingAcquisitionPromises) {
                acquisitionPromise.tryFailure(POOL_CLOSED_EXCEPTION);
            }
        }
    });
}

From source file:com.turo.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>/*from  w ww .jav a  2 s  . c o  m*/
 *
 * @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
 *
 * @see com.turo.pushy.apns.util.concurrent.PushNotificationResponseListener
 *
 * @since 0.8
 */
@SuppressWarnings("unchecked")
public <T extends ApnsPushNotification> PushNotificationFuture<T, PushNotificationResponse<T>> sendNotification(
        final T notification) {
    final PushNotificationFuture<T, PushNotificationResponse<T>> responseFuture;

    if (!this.isClosed.get()) {
        final PushNotificationPromise<T, PushNotificationResponse<T>> responsePromise = new PushNotificationPromise<>(
                this.eventLoopGroup.next(), notification);

        final long notificationId = this.nextNotificationId.getAndIncrement();

        this.channelPool.acquire().addListener(new GenericFutureListener<Future<Channel>>() {
            @Override
            public void operationComplete(final Future<Channel> acquireFuture) throws Exception {
                if (acquireFuture.isSuccess()) {
                    final Channel channel = acquireFuture.getNow();

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

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

                    ApnsClient.this.channelPool.release(channel);
                } else {
                    responsePromise.tryFailure(acquireFuture.cause());
                }
            }
        });

        responsePromise.addListener(new PushNotificationResponseListener<T>() {
            @Override
            public void operationComplete(final PushNotificationFuture<T, PushNotificationResponse<T>> future)
                    throws Exception {
                if (future.isSuccess()) {
                    final PushNotificationResponse 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);
                }
            }
        });

        responseFuture = responsePromise;
    } else {
        final PushNotificationPromise<T, PushNotificationResponse<T>> failedPromise = new PushNotificationPromise<>(
                GlobalEventExecutor.INSTANCE, notification);

        failedPromise.setFailure(CLIENT_CLOSED_EXCEPTION);

        responseFuture = failedPromise;
    }

    return responseFuture;
}

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

License:Open Source License

/**
 * <p>Gracefully shuts down the client, closing all connections and releasing all persistent resources. The
 * disconnection process will wait until notifications that have been sent to the APNs server have been either
 * accepted or rejected. Note that some notifications passed to
 * {@link ApnsClient#sendNotification(ApnsPushNotification)} may still be enqueued and not yet sent by the time the
 * shutdown process begins; the {@code Futures} associated with those notifications will fail.</p>
 *
 * <p>The returned {@code Future} will be marked as complete when all connections in this client's pool have closed
 * completely and (if no {@code EventLoopGroup} was provided at construction time) the client's event loop group has
 * shut down. If the client has already shut down, the returned {@code Future} will be marked as complete
 * immediately.</p>/*from  w  ww .  j a  va  2s  .c  om*/
 *
 * <p>Clients may not be reused once they have been closed.</p>
 *
 * @return a {@code Future} that will be marked as complete when the client has finished shutting down
 *
 * @since 0.11
 */
@SuppressWarnings({ "rawtypes", "unchecked" })
public Future<Void> close() {
    log.info("Shutting down.");

    final Future<Void> closeFuture;

    if (this.isClosed.compareAndSet(false, true)) {
        // Since we're (maybe) going to clobber the main event loop group, we should have this promise use the global
        // event executor to notify listeners.
        final Promise<Void> closePromise = new DefaultPromise<>(GlobalEventExecutor.INSTANCE);

        this.channelPool.close().addListener(new GenericFutureListener<Future<Void>>() {

            @Override
            public void operationComplete(final Future<Void> closePoolFuture) throws Exception {
                if (ApnsClient.this.shouldShutDownEventLoopGroup) {
                    ApnsClient.this.eventLoopGroup.shutdownGracefully()
                            .addListener(new GenericFutureListener() {

                                @Override
                                public void operationComplete(final Future future) throws Exception {
                                    closePromise.trySuccess(null);
                                }
                            });
                } else {
                    closePromise.trySuccess(null);
                }
            }
        });

        closeFuture = closePromise;
    } else {
        closeFuture = new SucceededFuture<>(GlobalEventExecutor.INSTANCE, null);
    }

    return closeFuture;
}

From source file:com.turo.pushy.apns.ApnsClientBenchmark.java

License:Open Source License

@Benchmark
@BenchmarkMode(Mode.SingleShotTime)/*from   w w w  . j a v a 2  s  .c  om*/
@Threads(1)
@Measurement(iterations = 20, batchSize = 1)
@Warmup(iterations = 20, batchSize = 1)
public long testSendNotifications() throws InterruptedException {
    final CountDownLatch countDownLatch = new CountDownLatch(this.pushNotifications.size());

    for (final SimpleApnsPushNotification notification : this.pushNotifications) {
        this.client.sendNotification(notification).addListener(
                new GenericFutureListener<Future<PushNotificationResponse<SimpleApnsPushNotification>>>() {

                    @Override
                    public void operationComplete(
                            final Future<PushNotificationResponse<SimpleApnsPushNotification>> future) {
                        if (future.isSuccess()) {
                            countDownLatch.countDown();
                        }
                    }
                });
    }

    countDownLatch.await();
    return countDownLatch.getCount();
}

From source file:com.turo.pushy.apns.ApnsClientHandler.java

License:Open Source License

private void writePushNotification(final ChannelHandlerContext context,
        final PushNotificationPromise responsePromise, final ChannelPromise writePromise) {
    if (context.channel().isActive()) {
        final int streamId = this.connection().local().incrementAndGetNextStreamId();

        if (streamId > 0) {
            // We'll attach the push notification and response promise to the stream as soon as the stream is created.
            // Because we're using a StreamBufferingEncoder under the hood, there's no guarantee as to when the stream
            // will actually be created, and so we attach these in the onStreamAdded listener to make sure everything
            // is happening in a predictable order.
            this.unattachedResponsePromisesByStreamId.put(streamId, responsePromise);
            final ApnsPushNotification pushNotification = responsePromise.getPushNotification();

            final Http2Headers headers = getHeadersForPushNotification(pushNotification, streamId);

            final ChannelPromise headersPromise = context.newPromise();
            this.encoder().writeHeaders(context, streamId, headers, 0, false, headersPromise);
            log.trace("Wrote headers on stream {}: {}", streamId, headers);

            final ByteBuf payloadBuffer = context.alloc().ioBuffer(INITIAL_PAYLOAD_BUFFER_CAPACITY);
            payloadBuffer.writeBytes(pushNotification.getPayload().getBytes(StandardCharsets.UTF_8));

            final ChannelPromise dataPromise = context.newPromise();
            this.encoder().writeData(context, streamId, payloadBuffer, 0, true, dataPromise);
            log.trace("Wrote payload on stream {}: {}", streamId, pushNotification.getPayload());

            final PromiseCombiner promiseCombiner = new PromiseCombiner();
            promiseCombiner.addAll((ChannelFuture) headersPromise, dataPromise);
            promiseCombiner.finish(writePromise);

            writePromise.addListener(new GenericFutureListener<ChannelPromise>() {

                @Override//from   w w  w . jav  a2s  . c om
                public void operationComplete(final ChannelPromise future) {
                    if (!future.isSuccess()) {
                        log.trace("Failed to write push notification on stream {}.", streamId, future.cause());
                        responsePromise.tryFailure(future.cause());
                    }
                }
            });
        } else {
            // This is very unlikely, but in the event that we run out of stream IDs, we need to open a new
            // connection. Just closing the context should be enough; automatic reconnection should take things
            // from there.
            writePromise.tryFailure(STREAMS_EXHAUSTED_EXCEPTION);
            context.channel().close();
        }
    } else {
        writePromise.tryFailure(STREAM_CLOSED_BEFORE_REPLY_EXCEPTION);
    }
}

From source file:com.turo.pushy.apns.ApnsClientHandler.java

License:Open Source License

@Override
public void userEventTriggered(final ChannelHandlerContext context, final Object event) throws Exception {
    if (event instanceof IdleStateEvent) {
        log.trace("Sending ping due to inactivity.");

        this.encoder().writePing(context, false, System.currentTimeMillis(), context.newPromise())
                .addListener(new GenericFutureListener<ChannelFuture>() {

                    @Override//from   w w w.jav  a2 s .c  o m
                    public void operationComplete(final ChannelFuture future) {
                        if (!future.isSuccess()) {
                            log.debug("Failed to write PING frame.", future.cause());
                            future.channel().close();
                        }
                    }
                });

        this.pingTimeoutFuture = context.channel().eventLoop().schedule(new Runnable() {

            @Override
            public void run() {
                log.debug("Closing channel due to ping timeout.");
                context.channel().close();
            }
        }, pingTimeoutMillis, TimeUnit.MILLISECONDS);

        this.flush(context);
    }

    super.userEventTriggered(context, event);
}

From source file:com.turo.pushy.apns.ApnsClientTest.java

License:Open Source License

@Test
@Parameters({ "true", "false" })
public void testSendManyNotificationsWithListeners(final boolean useTokenAuthentication) throws Exception {
    final int notificationCount = 1000;

    final List<SimpleApnsPushNotification> pushNotifications = new ArrayList<>();

    for (int i = 0; i < notificationCount; i++) {
        final String token = ApnsClientTest.generateRandomDeviceToken();
        final String payload = ApnsClientTest.generateRandomPayload();

        pushNotifications.add(new SimpleApnsPushNotification(token, TOPIC, payload));
    }/*from   w w w. j a  v a2  s. c om*/

    final MockApnsServer server = this.buildServer(new AcceptAllPushNotificationHandlerFactory());
    final ApnsClient client = useTokenAuthentication ? this.buildTokenAuthenticationClient()
            : this.buildTlsAuthenticationClient();

    final CountDownLatch countDownLatch = new CountDownLatch(notificationCount);

    try {
        server.start(PORT).await();

        for (final SimpleApnsPushNotification pushNotification : pushNotifications) {
            final Future<PushNotificationResponse<SimpleApnsPushNotification>> future = client
                    .sendNotification(pushNotification);

            future.addListener(
                    new GenericFutureListener<Future<PushNotificationResponse<SimpleApnsPushNotification>>>() {

                        @Override
                        public void operationComplete(
                                final Future<PushNotificationResponse<SimpleApnsPushNotification>> future) {
                            if (future.isSuccess()) {
                                countDownLatch.countDown();
                            }
                        }
                    });
        }

        countDownLatch.await();
    } finally {
        client.close().await();
        server.shutdown().await();
    }
}

From source file:com.turo.pushy.apns.ApnsClientTest.java

License:Open Source License

@Test
@Parameters({ "true", "false" })
public void testRepeatedlySendSameNotification(final boolean useTokenAuthentication) throws Exception {
    final int notificationCount = 1000;

    final SimpleApnsPushNotification pushNotification = new SimpleApnsPushNotification(DEVICE_TOKEN, TOPIC,
            PAYLOAD);// w w w . jav  a 2 s .com

    final CountDownLatch countDownLatch = new CountDownLatch(notificationCount);

    final MockApnsServer server = this.buildServer(new AcceptAllPushNotificationHandlerFactory());
    final ApnsClient client = useTokenAuthentication ? this.buildTokenAuthenticationClient()
            : this.buildTlsAuthenticationClient();

    try {
        server.start(PORT).await();

        for (int i = 0; i < notificationCount; i++) {
            final Future<PushNotificationResponse<SimpleApnsPushNotification>> future = client
                    .sendNotification(pushNotification);

            future.addListener(
                    new GenericFutureListener<Future<PushNotificationResponse<SimpleApnsPushNotification>>>() {

                        @Override
                        public void operationComplete(
                                final Future<PushNotificationResponse<SimpleApnsPushNotification>> future) {
                            // All we're concerned with here is that the client told us SOMETHING about what happened to the
                            // notification
                            countDownLatch.countDown();
                        }
                    });
        }

        countDownLatch.await();
    } finally {
        client.close().await();
        server.shutdown().await();
    }
}

From source file:com.turo.pushy.apns.MockApnsServer.java

License:Open Source License

/**
 * <p>Shuts down this server and releases the port to which this server was bound. If a {@code null} event loop
 * group was provided at construction time, the server will also shut down its internally-managed event loop
 * group.</p>// w w w  .  java  2  s .c  om
 *
 * <p>If a non-null {@code EventLoopGroup} was provided at construction time, mock servers may be reconnected and
 * reused after they have been shut down. If no event loop group was provided at construction time, mock servers may
 * not be restarted after they have been shut down via this method.</p>
 *
 * @return a {@code Future} that will succeed once the server has finished unbinding from its port and, if the
 * server was managing its own event loop group, its event loop group has shut down
 */
@SuppressWarnings({ "rawtypes", "unchecked" })
public Future<Void> shutdown() {
    final Future<Void> channelCloseFuture = (this.allChannels != null) ? this.allChannels.close()
            : new SucceededFuture<Void>(GlobalEventExecutor.INSTANCE, null);

    final Future<Void> disconnectFuture;

    if (this.shouldShutDownEventLoopGroup) {
        // Wait for the channel to close before we try to shut down the event loop group
        channelCloseFuture.addListener(new GenericFutureListener<Future<Void>>() {

            @Override
            public void operationComplete(final Future<Void> future) throws Exception {
                MockApnsServer.this.bootstrap.config().group().shutdownGracefully();
            }
        });

        // Since the termination future for the event loop group is a Future<?> instead of a Future<Void>,
        // we'll need to create our own promise and then notify it when the termination future completes.
        disconnectFuture = new DefaultPromise<>(GlobalEventExecutor.INSTANCE);

        this.bootstrap.config().group().terminationFuture().addListener(new GenericFutureListener() {

            @Override
            public void operationComplete(final Future future) throws Exception {
                assert disconnectFuture instanceof DefaultPromise;
                ((DefaultPromise<Void>) disconnectFuture).trySuccess(null);
            }
        });
    } else {
        // We're done once we've closed all the channels, so we can return the closure future directly.
        disconnectFuture = channelCloseFuture;
    }

    return disconnectFuture;
}