Example usage for io.netty.util.concurrent Future cause

List of usage examples for io.netty.util.concurrent Future cause

Introduction

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

Prototype

Throwable cause();

Source Link

Document

Returns the cause of the failed I/O operation if the I/O operation has failed.

Usage

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

License:Open Source License

@Override
public void write(final ChannelHandlerContext context, final Object message, final ChannelPromise writePromise)
        throws Http2Exception {
    if (message instanceof PushNotificationAndResponsePromise) {
        final PushNotificationAndResponsePromise pushNotificationAndResponsePromise = (PushNotificationAndResponsePromise) message;

        final ApnsPushNotification pushNotification = pushNotificationAndResponsePromise.getPushNotification();

        if (this.responsePromises.containsKey(pushNotification)) {
            writePromise.tryFailure(new PushNotificationStillPendingException());
        } else {//from   w w  w  .  j  a  v a2s.  c o m
            this.responsePromises.put(pushNotification,
                    pushNotificationAndResponsePromise.getResponsePromise());

            pushNotificationAndResponsePromise.getResponsePromise().addListener(
                    new GenericFutureListener<Future<PushNotificationResponse<ApnsPushNotification>>>() {

                        @Override
                        public void operationComplete(
                                final Future<PushNotificationResponse<ApnsPushNotification>> future) {
                            // Regardless of the outcome, when the response promise is finished, we want to remove it from
                            // the map of pending promises.
                            ApnsClientHandler.this.responsePromises.remove(pushNotification);
                        }
                    });

            this.write(context, pushNotification, writePromise);
        }
    } else if (message instanceof ApnsPushNotification) {
        final ApnsPushNotification pushNotification = (ApnsPushNotification) message;

        try {
            final int streamId = (int) this.nextStreamId;

            final Http2Headers headers = new DefaultHttp2Headers().method(HttpMethod.POST.asciiName())
                    .authority(this.authority).path(APNS_PATH_PREFIX + pushNotification.getToken())
                    .addInt(APNS_EXPIRATION_HEADER, pushNotification.getExpiration() == null ? 0
                            : (int) (pushNotification.getExpiration().getTime() / 1000));

            final String authenticationToken = this.apnsClient
                    .getAuthenticationTokenSupplierForTopic(pushNotification.getTopic()).getToken();
            headers.add(APNS_AUTHORIZATION_HEADER, "bearer " + authenticationToken);

            if (pushNotification.getCollapseId() != null) {
                headers.add(APNS_COLLAPSE_ID_HEADER, pushNotification.getCollapseId());
            }

            if (pushNotification.getPriority() != null) {
                headers.addInt(APNS_PRIORITY_HEADER, pushNotification.getPriority().getCode());
            }

            if (pushNotification.getTopic() != null) {
                headers.add(APNS_TOPIC_HEADER, pushNotification.getTopic());
            }

            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(headersPromise, dataPromise);
            promiseCombiner.finish(writePromise);

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

                @Override
                public void operationComplete(final ChannelPromise future) throws Exception {
                    if (future.isSuccess()) {
                        ApnsClientHandler.this.pushNotificationsByStreamId.put(streamId, pushNotification);
                        ApnsClientHandler.this.authenticationTokensByStreamId.put(streamId,
                                authenticationToken);
                    } else {
                        log.trace("Failed to write push notification on stream {}.", streamId, future.cause());

                        final Promise<PushNotificationResponse<ApnsPushNotification>> responsePromise = ApnsClientHandler.this.responsePromises
                                .get(pushNotification);

                        if (responsePromise != null) {
                            responsePromise.tryFailure(future.cause());
                        } else {
                            log.error("Notification write failed, but no response promise found.");
                        }
                    }
                }
            });

            this.nextStreamId += 2;

            if (this.nextStreamId >= STREAM_ID_RESET_THRESHOLD) {
                // This is very unlikely, but in the event that we run out of stream IDs (the maximum allowed is
                // 2^31, per https://httpwg.github.io/specs/rfc7540.html#StreamIdentifiers), we need to open a new
                // connection. Just closing the context should be enough; automatic reconnection should take things
                // from there.
                context.close();
            }
        } catch (NoKeyForTopicException | SignatureException e) {
            writePromise.tryFailure(e);
        }

    } else {
        // This should never happen, but in case some foreign debris winds up in the pipeline, just pass it through.
        log.error("Unexpected object in pipeline: {}", message);
        context.write(message, writePromise);
    }
}

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  av  a 2 s  .c om*/
@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.FeedbackServiceClient.java

License:Open Source License

/**
 * <p>Retrieves a list of expired tokens from the APNs feedback service. 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  .ja  va  2s.co m
 *
 * @param timeout the time after the last received data after which the connection to the feedback service should
 * be closed
 * @param timeoutUnit the unit of time in which the given {@code timeout} is measured
 *
 * @return a list of tokens that have expired since the last connection to the feedback service
 *
 * @throws InterruptedException if interrupted while waiting for a response from the feedback service
 * @throws FeedbackConnectionException if the connection to the feedback service failed for any reason
 */
public synchronized List<ExpiredToken> getExpiredTokens(final long timeout, final TimeUnit timeoutUnit)
        throws InterruptedException, FeedbackConnectionException {

    this.expiredTokens.clear();

    final Bootstrap bootstrap = new Bootstrap();
    bootstrap.group(this.eventLoopGroup);
    bootstrap.channel(NioSocketChannel.class);

    final FeedbackServiceClient feedbackClient = this;
    bootstrap.handler(new ChannelInitializer<SocketChannel>() {

        @Override
        protected void initChannel(final SocketChannel channel) throws Exception {
            final ChannelPipeline pipeline = channel.pipeline();

            final SSLEngine sslEngine = feedbackClient.sslContext.createSSLEngine();
            sslEngine.setUseClientMode(true);

            pipeline.addLast("ssl", new SslHandler(sslEngine));
            pipeline.addLast("readTimeoutHandler", new ReadTimeoutHandler(timeout, timeoutUnit));
            pipeline.addLast("decoder", new ExpiredTokenDecoder());
            pipeline.addLast("handler", new FeedbackClientHandler(feedbackClient));
        }

    });

    final ChannelFuture connectFuture = bootstrap
            .connect(this.environment.getFeedbackHost(), this.environment.getFeedbackPort()).await();

    if (connectFuture.isSuccess()) {
        log.debug("Connected to feedback service.");

        final SslHandler sslHandler = connectFuture.channel().pipeline().get(SslHandler.class);

        if (sslHandler != null) {
            final Future<Channel> handshakeFuture = sslHandler.handshakeFuture().await();

            if (handshakeFuture.isSuccess()) {
                log.debug("Completed TLS handshake with feedback service.");

                // The feedback service will send us a list of device tokens as soon as we complete the SSL
                // handshake, then hang up. While we're waiting to sync with the connection closure, we'll be
                // receiving messages from the feedback service from another thread.
                connectFuture.channel().closeFuture().await();
            } else {
                log.debug("Failed to complete TLS handshake with feedback service.", handshakeFuture.cause());

                connectFuture.channel().close().await();
                throw new FeedbackConnectionException(handshakeFuture.cause());
            }
        } else {
            log.warn("Feedback client failed to get SSL handler and could not wait for TLS handshake.");

            connectFuture.channel().close().await();
            throw new FeedbackConnectionException(null);
        }
    } else {
        log.debug("Failed to connect to feedback service.", connectFuture.cause());
        throw new FeedbackConnectionException(connectFuture.cause());
    }

    return new ArrayList<ExpiredToken>(this.expiredTokens);
}

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>/*from   w w w  .  j  a v  a  2 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.spotify.heroic.rpc.nativerpc.NativeRpcProtocolServer.java

License:Apache License

private List<AsyncFuture<Void>> teardownThreadpools() {
    final ResolvableFuture<Void> worker = async.future();

    workerGroup.shutdownGracefully().addListener(new FutureListener<Object>() {
        @Override/* www  .  j  ava 2  s.  co  m*/
        public void operationComplete(Future<Object> f) throws Exception {
            if (!f.isSuccess()) {
                worker.fail(f.cause());
                return;
            }

            worker.resolve(null);
        }
    });

    final ResolvableFuture<Void> boss = async.future();

    bossGroup.shutdownGracefully().addListener(new FutureListener<Object>() {
        @Override
        public void operationComplete(Future<Object> f) throws Exception {
            if (!f.isSuccess()) {
                boss.fail(f.cause());
                return;
            }

            boss.resolve(null);
        }
    });

    return ImmutableList.<AsyncFuture<Void>>of(worker, boss);
}

From source file:com.spotify.netty4.handler.codec.zmtp.ListenableFutureAdapter.java

License:Apache License

@Override
public void operationComplete(final Future<V> future) throws Exception {
    if (future.isSuccess()) {
        set(future.getNow());/*from w ww .j a  v a2s  .c  om*/
    } else {
        setException(future.cause());
    }
}

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();
    }/*from   ww  w  . j a  v a 2 s .c  o  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 .ja va  2 s  .  c o m
 *
 * @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 ww w  . j  a  v a  2  s . com
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//w  w  w. j a  va2  s  .co  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);
    }
}