{
errorResponse(callback, e);
return;
}
final Cancellable pendingGet = pool.get(new Callback<Channel>()
{
@Override
public void onSuccess(final Channel channel)
{
// This handler ensures the channel is returned to the pool at the end of the
// Netty pipeline.
final ChannelPoolHandler channelPoolHandler = channel.getPipeline().get(ChannelPoolHandler.class);
final ChannelHandlerContext channelPoolHandlerContext = channel.getPipeline().getContext(ChannelPoolHandler.class);
channelPoolHandler.setAttachment(channelPoolHandlerContext, pool);
callback.addTimeoutTask(new Runnable()
{
@Override
public void run()
{
AsyncPool<Channel> pool = channelPoolHandler.removeAttachment(channelPoolHandlerContext);
if (pool != null)
{
pool.dispose(channel);
}
}
});
// This handler invokes the callback with the response once it arrives.
channel.getPipeline().get(RAPResponseHandler.class).setAttachment(
channel.getPipeline().getContext(RAPResponseHandler.class),
callback);
final State state = _state.get();
if (state == State.REQUESTS_STOPPING || state == State.SHUTDOWN)
{
// In this case, we acquired a channel from the pool as request processing is halting.
// The shutdown task might not timeout this callback, since it may already have scanned
// all the channels for pending requests before we set the callback as the channel
// attachment. The TimeoutTransportCallback ensures the user callback in never
// invoked more than once, so it is safe to invoke it unconditionally.
errorResponse(callback,
new TimeoutException("Operation did not complete before shutdown"));
return;
}
channel.write(newRequest);
}
@Override
public void onError(Throwable e)
{
errorResponse(callback, e);
}
});
if (pendingGet != null)
{
callback.addTimeoutTask(new Runnable()
{
@Override
public void run()
{
pendingGet.cancel();
}
});
}
}