List of usage examples for io.netty.util.concurrent GenericFutureListener GenericFutureListener
GenericFutureListener
From source file:com.relayrides.pushy.apns.ApnsClientThread.java
License:Open Source License
private void sendNextNotification(final long timeout, final TimeUnit timeUnit) throws InterruptedException { final T notification = this.pushManager.getQueue().poll(timeout, timeUnit); if (this.isInterrupted()) { this.pushManager.enqueuePushNotification(notification); } else if (notification != null) { final SendableApnsPushNotification<T> sendableNotification = new SendableApnsPushNotification<T>( notification, this.sequenceNumber++); final String threadName = this.getName(); if (log.isTraceEnabled()) { log.trace(String.format("%s sending %s", threadName, sendableNotification)); }/*from w w w. java 2s . co m*/ this.sentNotificationBuffer.addSentNotification(sendableNotification); this.channel.write(sendableNotification).addListener(new GenericFutureListener<ChannelFuture>() { public void operationComplete(final ChannelFuture future) { if (future.cause() != null) { if (log.isTraceEnabled()) { log.trace(String.format("%s failed to write notification %s", threadName, sendableNotification), future.cause()); } requestReconnection(); // Delivery failed for some IO-related reason; re-enqueue for another attempt, but // only if the notification is in the sent notification buffer (i.e. if it hasn't // been re-enqueued for another reason). final T failedNotification = sentNotificationBuffer .getAndRemoveNotificationWithSequenceNumber( sendableNotification.getSequenceNumber()); if (failedNotification != null) { pushManager.enqueuePushNotification(failedNotification); } } else { if (log.isTraceEnabled()) { log.trace(String.format("%s successfully wrote notification %d", threadName, sendableNotification.getSequenceNumber())); } } } }); this.hasEverSentNotification = true; if (++this.writesSinceLastFlush >= ApnsClientThread.BATCH_SIZE) { this.channel.flush(); this.writesSinceLastFlush = 0; } } else { if (this.writesSinceLastFlush > 0) { this.channel.flush(); this.writesSinceLastFlush = 0; } } }
From source file:com.relayrides.pushy.apns.ApnsConnection.java
License:Open Source License
/** * Asynchronously connects to the APNs gateway in this connection's environment. The outcome of the connection * attempt is reported via this connection's listener. * * @see ApnsConnectionListener#handleConnectionSuccess(ApnsConnection) * @see ApnsConnectionListener#handleConnectionFailure(ApnsConnection, Throwable) *///from w ww . j ava2s.c o m @SuppressWarnings("deprecation") public synchronized void connect() { final ApnsConnection<T> apnsConnection = this; if (this.connectFuture != null) { throw new IllegalStateException(String.format("%s already started a connection attempt.", this.name)); } final Bootstrap bootstrap = new Bootstrap(); bootstrap.group(this.eventLoopGroup); bootstrap.channel(NioSocketChannel.class); bootstrap.option(ChannelOption.SO_KEEPALIVE, true); bootstrap.option(ChannelOption.ALLOCATOR, PooledByteBufAllocator.DEFAULT); // TODO Remove this when Netty 5 is available bootstrap.option(ChannelOption.AUTO_CLOSE, false); bootstrap.handler(new ChannelInitializer<SocketChannel>() { @Override protected void initChannel(final SocketChannel channel) { final ChannelPipeline pipeline = channel.pipeline(); final SSLEngine sslEngine = apnsConnection.sslContext.createSSLEngine(); sslEngine.setUseClientMode(true); pipeline.addLast("ssl", new SslHandler(sslEngine)); pipeline.addLast("decoder", new RejectedNotificationDecoder()); pipeline.addLast("encoder", new ApnsPushNotificationEncoder()); pipeline.addLast("handler", new ApnsConnectionHandler(apnsConnection)); } }); log.debug("{} beginning connection process.", apnsConnection.name); this.connectFuture = bootstrap.connect(this.environment.getApnsGatewayHost(), this.environment.getApnsGatewayPort()); this.connectFuture.addListener(new GenericFutureListener<ChannelFuture>() { public void operationComplete(final ChannelFuture connectFuture) { if (connectFuture.isSuccess()) { log.debug("{} connected; waiting for TLS handshake.", apnsConnection.name); final SslHandler sslHandler = connectFuture.channel().pipeline().get(SslHandler.class); try { sslHandler.handshakeFuture().addListener(new GenericFutureListener<Future<Channel>>() { public void operationComplete(final Future<Channel> handshakeFuture) { if (handshakeFuture.isSuccess()) { log.debug("{} successfully completed TLS handshake.", apnsConnection.name); apnsConnection.handshakeCompleted = true; apnsConnection.listener.handleConnectionSuccess(apnsConnection); } else { log.debug("{} failed to complete TLS handshake with APNs gateway.", apnsConnection.name, handshakeFuture.cause()); connectFuture.channel().close(); apnsConnection.listener.handleConnectionFailure(apnsConnection, handshakeFuture.cause()); } } }); } catch (NullPointerException e) { log.warn("{} failed to get SSL handler and could not wait for a TLS handshake.", apnsConnection.name); connectFuture.channel().close(); apnsConnection.listener.handleConnectionFailure(apnsConnection, e); } } else { log.debug("{} failed to connect to APNs gateway.", apnsConnection.name, connectFuture.cause()); apnsConnection.listener.handleConnectionFailure(apnsConnection, connectFuture.cause()); } } }); }
From source file:com.relayrides.pushy.apns.ApnsConnection.java
License:Open Source License
/** * Asynchronously sends a push notification to the connected APNs gateway. Successful notifications are * <strong>not</strong> acknowledged by the APNs gateway; failed attempts to write push notifications to the * outbound buffer and notification rejections are reported via this connection's listener. * * @param notification the notification to send * * @see ApnsConnectionListener#handleWriteFailure(ApnsConnection, ApnsPushNotification, Throwable) * @see ApnsConnectionListener#handleRejectedNotification(ApnsConnection, ApnsPushNotification, RejectedNotificationReason) *///from w w w .j a v a2 s.co m public synchronized void sendNotification(final T notification) { final ApnsConnection<T> apnsConnection = this; if (!this.handshakeCompleted) { throw new IllegalStateException(String.format("%s has not completed handshake.", this.name)); } this.connectFuture.channel().eventLoop().execute(new Runnable() { public void run() { final SendableApnsPushNotification<T> sendableNotification = new SendableApnsPushNotification<T>( notification, apnsConnection.sequenceNumber++); log.trace("{} sending {}", apnsConnection.name, sendableNotification); apnsConnection.pendingWriteCount += 1; apnsConnection.connectFuture.channel().writeAndFlush(sendableNotification) .addListener(new GenericFutureListener<ChannelFuture>() { public void operationComplete(final ChannelFuture writeFuture) { if (writeFuture.isSuccess()) { log.trace("{} successfully wrote notification {}", apnsConnection.name, sendableNotification.getSequenceNumber()); if (apnsConnection.rejectionReceived) { // Even though the write succeeded, we know for sure that this notification was never // processed by the gateway because it had already rejected another notification from // this connection. apnsConnection.listener.handleUnprocessedNotifications(apnsConnection, java.util.Collections.singletonList(notification)); } else { apnsConnection.sentNotificationBuffer .addSentNotification(sendableNotification); } } else { log.trace("{} failed to write notification {}", apnsConnection.name, sendableNotification, writeFuture.cause()); // Assume this is a temporary failure (we know it's not a permanent rejection because we didn't // even manage to write the notification to the wire) and re-enqueue for another send attempt. apnsConnection.listener.handleWriteFailure(apnsConnection, notification, writeFuture.cause()); } apnsConnection.pendingWriteCount -= 1; assert apnsConnection.pendingWriteCount >= 0; if (apnsConnection.pendingWriteCount == 0) { synchronized (apnsConnection.pendingWriteMonitor) { apnsConnection.pendingWriteMonitor.notifyAll(); } } } }); } }); }
From source file:com.relayrides.pushy.apns.ApnsConnection.java
License:Open Source License
/** * <p>Gracefully and asynchronously shuts down this connection. Graceful disconnection is triggered by sending a * known-bad notification to the APNs gateway; when the gateway rejects the notification, it is guaranteed that * preceding notifications were processed successfully and that all following notifications were not processed at * all. The gateway will close the connection after rejecting the notification, and this connection's listener will * be notified when the connection is closed.</p> * * <p>Note that if/when the known-bad notification is rejected by the APNs gateway, this connection's listener will * <em>not</em> be notified of the rejection.</p> * * <p>Calling this method before establishing a connection with the APNs gateway or while a graceful shutdown * attempt is already in progress has no effect.</p> * * @see ApnsConnectionListener#handleRejectedNotification(ApnsConnection, ApnsPushNotification, RejectedNotificationReason) * @see ApnsConnectionListener#handleConnectionClosure(ApnsConnection) *//* w ww .j a v a2 s .c om*/ public synchronized void shutdownGracefully() { final ApnsConnection<T> apnsConnection = this; // We only need to send a known-bad notification if we were ever connected in the first place and if we're // still connected. if (this.handshakeCompleted && this.connectFuture.channel().isActive()) { this.connectFuture.channel().eventLoop().execute(new Runnable() { public void run() { // Don't send a second shutdown notification if we've already started the graceful shutdown process. if (apnsConnection.shutdownNotification == null) { log.debug("{} sending known-bad notification to shut down.", apnsConnection.name); apnsConnection.shutdownNotification = new SendableApnsPushNotification<KnownBadPushNotification>( new KnownBadPushNotification(), apnsConnection.sequenceNumber++); apnsConnection.pendingWriteCount += 1; apnsConnection.connectFuture.channel().writeAndFlush(apnsConnection.shutdownNotification) .addListener(new GenericFutureListener<ChannelFuture>() { public void operationComplete(final ChannelFuture future) { if (future.isSuccess()) { log.trace("{} successfully wrote known-bad notification {}", apnsConnection.name, apnsConnection.shutdownNotification.getSequenceNumber()); } else { log.trace("{} failed to write known-bad notification {}", apnsConnection.name, apnsConnection.shutdownNotification, future.cause()); // Try again! apnsConnection.shutdownNotification = null; apnsConnection.shutdownGracefully(); } apnsConnection.pendingWriteCount -= 1; assert apnsConnection.pendingWriteCount >= 0; if (apnsConnection.pendingWriteCount == 0) { synchronized (apnsConnection.pendingWriteMonitor) { apnsConnection.pendingWriteMonitor.notifyAll(); } } } }); } } }); } else { // While we can't guarantee that the handshake won't complete in another thread, we CAN guarantee that no // new notifications will be sent until shutdownImmediately happens because everything is synchronized. this.shutdownImmediately(); } }
From source file:com.relayrides.pushy.apns.FeedbackServiceConnection.java
License:Open Source License
/** * <p>Connects to the APNs feedback service and waits for expired tokens to arrive. Be warned that this is a * <strong>destructive operation</strong>. According to Apple's documentation:</p> * * <blockquote>The feedback service's list is cleared after you read it. Each time you connect to the feedback * service, the information it returns lists only the failures that have happened since you last * connected.</blockquote>/* w w w . j a va2 s . c o m*/ */ public synchronized void connect() { if (this.connectFuture != null) { throw new IllegalStateException(String.format("%s already started a connection attempt.", this.name)); } final Bootstrap bootstrap = new Bootstrap(); bootstrap.group(this.eventLoopGroup); bootstrap.channel(NioSocketChannel.class); final FeedbackServiceConnection feedbackConnection = this; bootstrap.handler(new ChannelInitializer<SocketChannel>() { @Override protected void initChannel(final SocketChannel channel) throws Exception { final ChannelPipeline pipeline = channel.pipeline(); final SSLEngine sslEngine = feedbackConnection.sslContext.createSSLEngine(); sslEngine.setUseClientMode(true); pipeline.addLast("ssl", new SslHandler(sslEngine)); pipeline.addLast("readTimeoutHandler", new ReadTimeoutHandler(feedbackConnection.configuration.getReadTimeout())); pipeline.addLast("decoder", new ExpiredTokenDecoder()); pipeline.addLast("handler", new FeedbackClientHandler(feedbackConnection)); } }); this.connectFuture = bootstrap.connect(this.environment.getFeedbackHost(), this.environment.getFeedbackPort()); this.connectFuture.addListener(new GenericFutureListener<ChannelFuture>() { @Override public void operationComplete(final ChannelFuture connectFuture) { if (connectFuture.isSuccess()) { log.debug("{} connected; waiting for TLS handshake.", feedbackConnection.name); final SslHandler sslHandler = connectFuture.channel().pipeline().get(SslHandler.class); try { sslHandler.handshakeFuture().addListener(new GenericFutureListener<Future<Channel>>() { @Override public void operationComplete(final Future<Channel> handshakeFuture) { if (handshakeFuture.isSuccess()) { log.debug("{} successfully completed TLS handshake.", feedbackConnection.name); if (feedbackConnection.listener != null) { feedbackConnection.listener.handleConnectionSuccess(feedbackConnection); } } else { log.debug("{} failed to complete TLS handshake with APNs feedback service.", feedbackConnection.name, handshakeFuture.cause()); connectFuture.channel().close(); if (feedbackConnection.listener != null) { feedbackConnection.listener.handleConnectionFailure(feedbackConnection, handshakeFuture.cause()); } } } }); } catch (NullPointerException e) { log.warn("{} failed to get SSL handler and could not wait for a TLS handshake.", feedbackConnection.name); connectFuture.channel().close(); if (feedbackConnection.listener != null) { feedbackConnection.listener.handleConnectionFailure(feedbackConnection, e); } } } else { log.debug("{} failed to connect to APNs feedback service.", feedbackConnection.name, connectFuture.cause()); if (feedbackConnection.listener != null) { feedbackConnection.listener.handleConnectionFailure(feedbackConnection, connectFuture.cause()); } } } }); }
From source file:com.shbxs.netty.SecureChatServerHandler.java
License:Apache License
@Override public void channelActive(final ChannelHandlerContext ctx) {//? // System.out.println("channelactive!"); // Once session is secured, send a greeting and register the channel to the global channel // list so the channel received the messages from others. //??// ww w . j a v a 2 s. co m ctx.pipeline().get(SslHandler.class).handshakeFuture() .addListener(new GenericFutureListener<Future<Channel>>() { @Override public void operationComplete(Future<Channel> future) throws Exception { ctx.writeAndFlush("Welcome to " + InetAddress.getLocalHost().getHostName() + " secure chat service!\n"); ctx.writeAndFlush("Your session is protected by " + ctx.pipeline().get(SslHandler.class).engine().getSession().getCipherSuite() + " cipher suite.\n"); channels.add(ctx.channel()); } }); }
From source file:com.turo.pushy.apns.ApnsChannelFactory.java
License:Open Source License
ApnsChannelFactory(final SslContext sslContext, final ApnsSigningKey signingKey, final ProxyHandlerFactory proxyHandlerFactory, final int connectTimeoutMillis, final long idlePingIntervalMillis, final long gracefulShutdownTimeoutMillis, final Http2FrameLogger frameLogger, final InetSocketAddress apnsServerAddress, final EventLoopGroup eventLoopGroup) { this.sslContext = sslContext; if (this.sslContext instanceof ReferenceCounted) { ((ReferenceCounted) this.sslContext).retain(); }// w w w . jav a 2 s . co m this.addressResolverGroup = proxyHandlerFactory == null ? new RoundRobinDnsAddressResolverGroup( ClientChannelClassUtil.getDatagramChannelClass(eventLoopGroup), DefaultDnsServerAddressStreamProvider.INSTANCE) : NoopAddressResolverGroup.INSTANCE; this.bootstrapTemplate = new Bootstrap(); this.bootstrapTemplate.group(eventLoopGroup); this.bootstrapTemplate.option(ChannelOption.TCP_NODELAY, true); this.bootstrapTemplate.remoteAddress(apnsServerAddress); this.bootstrapTemplate.resolver(this.addressResolverGroup); if (connectTimeoutMillis > 0) { this.bootstrapTemplate.option(ChannelOption.CONNECT_TIMEOUT_MILLIS, connectTimeoutMillis); } this.bootstrapTemplate.handler(new ChannelInitializer<SocketChannel>() { @Override protected void initChannel(final SocketChannel channel) { final ChannelPipeline pipeline = channel.pipeline(); if (proxyHandlerFactory != null) { pipeline.addFirst(proxyHandlerFactory.createProxyHandler()); } final SslHandler sslHandler = sslContext.newHandler(channel.alloc()); sslHandler.handshakeFuture().addListener(new GenericFutureListener<Future<Channel>>() { @Override public void operationComplete(final Future<Channel> handshakeFuture) { if (handshakeFuture.isSuccess()) { final String authority = channel.remoteAddress().getHostName(); final ApnsClientHandler.ApnsClientHandlerBuilder clientHandlerBuilder; if (signingKey != null) { clientHandlerBuilder = new TokenAuthenticationApnsClientHandler.TokenAuthenticationApnsClientHandlerBuilder() .signingKey(signingKey).authority(authority) .idlePingIntervalMillis(idlePingIntervalMillis); } else { clientHandlerBuilder = new ApnsClientHandler.ApnsClientHandlerBuilder() .authority(authority).idlePingIntervalMillis(idlePingIntervalMillis); } if (frameLogger != null) { clientHandlerBuilder.frameLogger(frameLogger); } final ApnsClientHandler apnsClientHandler = clientHandlerBuilder.build(); if (gracefulShutdownTimeoutMillis > 0) { apnsClientHandler.gracefulShutdownTimeoutMillis(gracefulShutdownTimeoutMillis); } // TODO Use a named constant when https://github.com/netty/netty/pull/8683 is available pipeline.addLast(new FlushConsolidationHandler(256, true)); pipeline.addLast( new IdleStateHandler(idlePingIntervalMillis, 0, 0, TimeUnit.MILLISECONDS)); pipeline.addLast(apnsClientHandler); pipeline.remove(ConnectionNegotiationErrorHandler.INSTANCE); channel.attr(CHANNEL_READY_PROMISE_ATTRIBUTE_KEY).get().trySuccess(channel); } else { tryFailureAndLogRejectedCause(channel.attr(CHANNEL_READY_PROMISE_ATTRIBUTE_KEY).get(), handshakeFuture.cause()); } } }); pipeline.addLast(sslHandler); pipeline.addLast(ConnectionNegotiationErrorHandler.INSTANCE); } }); }
From source file:com.turo.pushy.apns.ApnsChannelFactory.java
License:Open Source License
/** * Creates and connects a new channel. The initial connection attempt may be delayed to accommodate exponential * back-off requirements./* w w w.j a va 2 s.c om*/ * * @param channelReadyPromise the promise to be notified when a channel has been created and connected to the APNs * server * * @return a future that will be notified once a channel has been created and connected to the APNs server */ @Override public Future<Channel> create(final Promise<Channel> channelReadyPromise) { final long delay = this.currentDelaySeconds.get(); channelReadyPromise.addListener(new GenericFutureListener<Future<Channel>>() { @Override public void operationComplete(final Future<Channel> future) { final long updatedDelay = future.isSuccess() ? 0 : Math.max(Math.min(delay * 2, MAX_CONNECT_DELAY_SECONDS), MIN_CONNECT_DELAY_SECONDS); ApnsChannelFactory.this.currentDelaySeconds.compareAndSet(delay, updatedDelay); } }); this.bootstrapTemplate.config().group().schedule(new Runnable() { @Override public void run() { final Bootstrap bootstrap = ApnsChannelFactory.this.bootstrapTemplate.clone() .channelFactory(new AugmentingReflectiveChannelFactory<>( ClientChannelClassUtil.getSocketChannelClass( ApnsChannelFactory.this.bootstrapTemplate.config().group()), CHANNEL_READY_PROMISE_ATTRIBUTE_KEY, channelReadyPromise)); final ChannelFuture connectFuture = bootstrap.connect(); connectFuture.addListener(new GenericFutureListener<ChannelFuture>() { @Override public void operationComplete(final ChannelFuture future) { if (!future.isSuccess()) { // This may seem spurious, but our goal here is to accurately report the cause of // connection failure; if we just wait for connection closure, we won't be able to // tell callers anything more specific about what went wrong. tryFailureAndLogRejectedCause(channelReadyPromise, future.cause()); } } }); connectFuture.channel().closeFuture().addListener(new GenericFutureListener<ChannelFuture>() { @Override public void operationComplete(final ChannelFuture future) { // We always want to try to fail the "channel ready" promise if the connection closes; if it has // already succeeded, this will have no effect. channelReadyPromise.tryFailure( new IllegalStateException("Channel closed before HTTP/2 preface completed.")); } }); } }, delay, TimeUnit.SECONDS); return channelReadyPromise; }
From source file:com.turo.pushy.apns.ApnsChannelPool.java
License:Open Source License
/** * <p>Asynchronously acquires a channel from this channel pool. The acquired channel may be a pre-existing channel * stored in the pool or may be a new channel created on demand. If no channels are available and the pool is at * capacity, acquisition may be delayed until another caller releases a channel to the pool.</p> * * <p>When callers are done with a channel, they <em>must</em> release the channel back to the pool via the * {@link ApnsChannelPool#release(Channel)} method.</p> * * @return a {@code Future} that will be notified when a channel is available * * @see ApnsChannelPool#release(Channel) *//*from w ww . ja v a2 s . c om*/ Future<Channel> acquire() { final Promise<Channel> acquirePromise = new DefaultPromise<>(this.executor); if (this.executor.inEventLoop()) { this.acquireWithinEventExecutor(acquirePromise); } else { this.executor.submit(new Runnable() { @Override public void run() { ApnsChannelPool.this.acquireWithinEventExecutor(acquirePromise); } }).addListener(new GenericFutureListener() { @Override public void operationComplete(final Future future) throws Exception { if (!future.isSuccess()) { acquirePromise.tryFailure(future.cause()); } } }); } return acquirePromise; }
From source file:com.turo.pushy.apns.ApnsChannelPool.java
License:Open Source License
private void acquireWithinEventExecutor(final Promise<Channel> acquirePromise) { assert this.executor.inEventLoop(); if (!this.isClosed) { // We always want to open new channels if we have spare capacity. Once the pool is full, we'll start looking // for idle, pre-existing channels. if (this.allChannels.size() + this.pendingCreateChannelFutures.size() < this.capacity) { final Future<Channel> createChannelFuture = this.channelFactory .create(executor.<Channel>newPromise()); this.pendingCreateChannelFutures.add(createChannelFuture); createChannelFuture.addListener(new GenericFutureListener<Future<Channel>>() { @Override// www. j a v a 2s.c o m public void operationComplete(final Future<Channel> future) { ApnsChannelPool.this.pendingCreateChannelFutures.remove(createChannelFuture); if (future.isSuccess()) { final Channel channel = future.getNow(); ApnsChannelPool.this.allChannels.add(channel); ApnsChannelPool.this.metricsListener.handleConnectionAdded(); acquirePromise.trySuccess(channel); } else { ApnsChannelPool.this.metricsListener.handleConnectionCreationFailed(); acquirePromise.tryFailure(future.cause()); // If we failed to open a connection, this is the end of the line for this acquisition // attempt, and callers won't be able to release the channel (since they didn't get one // in the first place). Move on to the next acquisition attempt if one is present. ApnsChannelPool.this.handleNextAcquisition(); } } }); } else { final Channel channelFromIdlePool = ApnsChannelPool.this.idleChannels.poll(); if (channelFromIdlePool != null) { if (channelFromIdlePool.isActive()) { acquirePromise.trySuccess(channelFromIdlePool); } else { // The channel from the idle pool isn't usable; discard it and create a new one instead this.discardChannel(channelFromIdlePool); this.acquireWithinEventExecutor(acquirePromise); } } else { // We don't have any connections ready to go, and don't have any more capacity to create new // channels. Add this acquisition to the queue waiting for channels to become available. pendingAcquisitionPromises.add(acquirePromise); } } } else { acquirePromise.tryFailure(POOL_CLOSED_EXCEPTION); } }