List of usage examples for io.netty.util.concurrent GenericFutureListener GenericFutureListener
GenericFutureListener
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; }