use of io.netty.util.concurrent.GenericFutureListener in project jersey by jersey.
the class NettyConnector method apply.
@Override
public Future<?> apply(final ClientRequest jerseyRequest, final AsyncConnectorCallback jerseyCallback) {
final CompletableFuture<Object> settableFuture = new CompletableFuture<>();
final URI requestUri = jerseyRequest.getUri();
String host = requestUri.getHost();
int port = requestUri.getPort() != -1 ? requestUri.getPort() : "https".equals(requestUri.getScheme()) ? 443 : 80;
try {
Bootstrap b = new Bootstrap();
b.group(group).channel(NioSocketChannel.class).handler(new ChannelInitializer<SocketChannel>() {
@Override
protected void initChannel(SocketChannel ch) throws Exception {
ChannelPipeline p = ch.pipeline();
// Enable HTTPS if necessary.
if ("https".equals(requestUri.getScheme())) {
// making client authentication optional for now; it could be extracted to configurable property
JdkSslContext jdkSslContext = new JdkSslContext(client.getSslContext(), true, ClientAuth.NONE);
p.addLast(jdkSslContext.newHandler(ch.alloc()));
}
// http proxy
Configuration config = jerseyRequest.getConfiguration();
final Object proxyUri = config.getProperties().get(ClientProperties.PROXY_URI);
if (proxyUri != null) {
final URI u = getProxyUri(proxyUri);
final String userName = ClientProperties.getValue(config.getProperties(), ClientProperties.PROXY_USERNAME, String.class);
final String password = ClientProperties.getValue(config.getProperties(), ClientProperties.PROXY_PASSWORD, String.class);
p.addLast(new HttpProxyHandler(new InetSocketAddress(u.getHost(), u.getPort() == -1 ? 8080 : u.getPort()), userName, password));
}
p.addLast(new HttpClientCodec());
p.addLast(new ChunkedWriteHandler());
p.addLast(new HttpContentDecompressor());
p.addLast(new JerseyClientHandler(NettyConnector.this, jerseyRequest, jerseyCallback, settableFuture));
}
});
// connect timeout
Integer connectTimeout = ClientProperties.getValue(jerseyRequest.getConfiguration().getProperties(), ClientProperties.CONNECT_TIMEOUT, 0);
if (connectTimeout > 0) {
b.option(ChannelOption.CONNECT_TIMEOUT_MILLIS, connectTimeout);
}
// Make the connection attempt.
final Channel ch = b.connect(host, port).sync().channel();
// guard against prematurely closed channel
final GenericFutureListener<io.netty.util.concurrent.Future<? super Void>> closeListener = new GenericFutureListener<io.netty.util.concurrent.Future<? super Void>>() {
@Override
public void operationComplete(io.netty.util.concurrent.Future<? super Void> future) throws Exception {
if (!settableFuture.isDone()) {
settableFuture.completeExceptionally(new IOException("Channel closed."));
}
}
};
ch.closeFuture().addListener(closeListener);
HttpRequest nettyRequest;
if (jerseyRequest.hasEntity()) {
nettyRequest = new DefaultHttpRequest(HttpVersion.HTTP_1_1, HttpMethod.valueOf(jerseyRequest.getMethod()), requestUri.getRawPath());
} else {
nettyRequest = new DefaultFullHttpRequest(HttpVersion.HTTP_1_1, HttpMethod.valueOf(jerseyRequest.getMethod()), requestUri.getRawPath());
}
// headers
for (final Map.Entry<String, List<String>> e : jerseyRequest.getStringHeaders().entrySet()) {
nettyRequest.headers().add(e.getKey(), e.getValue());
}
// host header - http 1.1
nettyRequest.headers().add(HttpHeaderNames.HOST, jerseyRequest.getUri().getHost());
if (jerseyRequest.hasEntity()) {
if (jerseyRequest.getLengthLong() == -1) {
HttpUtil.setTransferEncodingChunked(nettyRequest, true);
} else {
nettyRequest.headers().add(HttpHeaderNames.CONTENT_LENGTH, jerseyRequest.getLengthLong());
}
}
if (jerseyRequest.hasEntity()) {
// Send the HTTP request.
ch.writeAndFlush(nettyRequest);
final JerseyChunkedInput jerseyChunkedInput = new JerseyChunkedInput(ch);
jerseyRequest.setStreamProvider(new OutboundMessageContext.StreamProvider() {
@Override
public OutputStream getOutputStream(int contentLength) throws IOException {
return jerseyChunkedInput;
}
});
if (HttpUtil.isTransferEncodingChunked(nettyRequest)) {
ch.write(new HttpChunkedInput(jerseyChunkedInput));
} else {
ch.write(jerseyChunkedInput);
}
executorService.execute(new Runnable() {
@Override
public void run() {
// close listener is not needed any more.
ch.closeFuture().removeListener(closeListener);
try {
jerseyRequest.writeEntity();
} catch (IOException e) {
jerseyCallback.failure(e);
settableFuture.completeExceptionally(e);
}
}
});
ch.flush();
} else {
// close listener is not needed any more.
ch.closeFuture().removeListener(closeListener);
// Send the HTTP request.
ch.writeAndFlush(nettyRequest);
}
} catch (InterruptedException e) {
settableFuture.completeExceptionally(e);
return settableFuture;
}
return settableFuture;
}
use of io.netty.util.concurrent.GenericFutureListener in project riposte by Nike-Inc.
the class StreamingAsyncHttpClientTest method StreamingChannel_streamChunk_sets_up_task_in_event_loop_to_call_doStreamChunk_and_adds_listener_to_complete_promise.
@Test
public void StreamingChannel_streamChunk_sets_up_task_in_event_loop_to_call_doStreamChunk_and_adds_listener_to_complete_promise() throws Exception {
// given
ChannelFuture doStreamChunkFutureMock = mock(ChannelFuture.class);
doReturn(doStreamChunkFutureMock).when(streamingChannelSpy).doStreamChunk(any(HttpContent.class));
// when
ChannelFuture result = streamingChannelSpy.streamChunk(contentChunkMock);
// then
assertThat(result).isSameAs(streamChunkChannelPromiseMock);
// not yet completed
verifyZeroInteractions(streamChunkChannelPromiseMock);
ArgumentCaptor<Runnable> taskCaptor = ArgumentCaptor.forClass(Runnable.class);
verify(eventLoopMock).execute(taskCaptor.capture());
Runnable task = taskCaptor.getValue();
// and given
// not yet called
verify(streamingChannelSpy, never()).doStreamChunk(any(HttpContent.class));
// when
task.run();
// then
verify(streamingChannelSpy).doStreamChunk(contentChunkMock);
ArgumentCaptor<GenericFutureListener> listenerCaptor = ArgumentCaptor.forClass(GenericFutureListener.class);
verify(doStreamChunkFutureMock).addListener(listenerCaptor.capture());
GenericFutureListener listener = listenerCaptor.getValue();
assertThat(listener).isNotNull();
// and when
listener.operationComplete(getFutureForCase(true, false, null));
// then
verify(streamChunkChannelPromiseMock).cancel(true);
verifyNoMoreInteractions(streamChunkChannelPromiseMock);
// and when
listener.operationComplete(getFutureForCase(false, true, null));
// then
verify(streamChunkChannelPromiseMock).setSuccess();
verifyNoMoreInteractions(streamChunkChannelPromiseMock);
// and when
Throwable normalFutureFailure = new RuntimeException("normal future failure");
listener.operationComplete(getFutureForCase(false, false, normalFutureFailure));
// then
verify(streamChunkChannelPromiseMock).setFailure(normalFutureFailure);
verifyNoMoreInteractions(streamChunkChannelPromiseMock);
// and when
reset(streamChunkChannelPromiseMock);
listener.operationComplete(getFutureForCase(false, false, null));
// then
ArgumentCaptor<Throwable> throwableCaptor = ArgumentCaptor.forClass(Throwable.class);
verify(streamChunkChannelPromiseMock).setFailure(throwableCaptor.capture());
assertThat(throwableCaptor.getValue()).hasMessage("Received ChannelFuture that was in an impossible state");
verifyNoMoreInteractions(streamChunkChannelPromiseMock);
}
use of io.netty.util.concurrent.GenericFutureListener in project riposte by Nike-Inc.
the class ChannelPipelineFinalizerHandlerTest method finalizeChannelPipeline_should_send_event_to_metricsListener_for_failure_response_and_flush_context.
@Test
public void finalizeChannelPipeline_should_send_event_to_metricsListener_for_failure_response_and_flush_context() throws Exception {
// given
ChannelFuture responseWriterChannelFuture = mock(ChannelFuture.class);
state.setResponseWriterFinalChunkChannelFuture(responseWriterChannelFuture);
HttpProcessingState stateSpy = spy(state);
doReturn(stateSpy).when(stateAttributeMock).get();
ChannelFuture responseWriteFutureResult = mock(ChannelFuture.class);
doReturn(false).when(responseWriteFutureResult).isSuccess();
Assertions.assertThat(stateSpy.isRequestMetricsRecordedOrScheduled()).isFalse();
// when
handler.finalizeChannelPipeline(ctxMock, null, stateSpy, null);
// then
ArgumentCaptor<GenericFutureListener> channelFutureListenerArgumentCaptor = ArgumentCaptor.forClass(GenericFutureListener.class);
verify(responseWriterChannelFuture).addListener(channelFutureListenerArgumentCaptor.capture());
GenericFutureListener futureListener = channelFutureListenerArgumentCaptor.getValue();
assertThat(futureListener, notNullValue());
futureListener.operationComplete(responseWriteFutureResult);
verify(metricsListenerMock).onEvent(ServerMetricsEvent.RESPONSE_WRITE_FAILED, null);
verify(ctxMock).flush();
Assertions.assertThat(stateSpy.isRequestMetricsRecordedOrScheduled()).isTrue();
}
use of io.netty.util.concurrent.GenericFutureListener in project riposte by Nike-Inc.
the class ChannelPipelineFinalizerHandlerTest method finalizeChannelPipeline_should_send_event_to_metricsListener_for_successful_response_and_flush_context.
@Test
public void finalizeChannelPipeline_should_send_event_to_metricsListener_for_successful_response_and_flush_context() throws Exception {
// given
ChannelFuture responseWriterChannelFuture = mock(ChannelFuture.class);
state.setResponseWriterFinalChunkChannelFuture(responseWriterChannelFuture);
HttpProcessingState stateSpy = spy(state);
doReturn(stateSpy).when(stateAttributeMock).get();
ChannelFuture responseWriteFutureResult = mock(ChannelFuture.class);
doReturn(true).when(responseWriteFutureResult).isSuccess();
Assertions.assertThat(stateSpy.isRequestMetricsRecordedOrScheduled()).isFalse();
// when
handler.finalizeChannelPipeline(ctxMock, null, stateSpy, null);
// then
ArgumentCaptor<GenericFutureListener> channelFutureListenerArgumentCaptor = ArgumentCaptor.forClass(GenericFutureListener.class);
verify(responseWriterChannelFuture).addListener(channelFutureListenerArgumentCaptor.capture());
GenericFutureListener futureListener = channelFutureListenerArgumentCaptor.getValue();
assertThat(futureListener, notNullValue());
futureListener.operationComplete(responseWriteFutureResult);
verify(metricsListenerMock).onEvent(eq(ServerMetricsEvent.RESPONSE_SENT), any(HttpProcessingState.class));
verify(ctxMock).flush();
Assertions.assertThat(stateSpy.isRequestMetricsRecordedOrScheduled()).isTrue();
}
use of io.netty.util.concurrent.GenericFutureListener in project riposte by Nike-Inc.
the class OpenChannelLimitHandlerTest method doChannelActive_marks_and_schedules_double_check_timeout_if_too_many_open_channels.
@DataProvider(value = { "0", "1" })
@Test
public void doChannelActive_marks_and_schedules_double_check_timeout_if_too_many_open_channels(int numOpenChannelsGreaterThanMax) throws Exception {
// given
int actualOpenChannels = maxOpenChannelsThreshold + numOpenChannelsGreaterThanMax;
setActualOpenChannels(actualOpenChannels);
// when
PipelineContinuationBehavior result = handler.doChannelActive(ctxMock);
// then
assertThat(result).isEqualTo(CONTINUE);
Pair<Runnable, GenericFutureListener> futureInfoPair = extractDoubleCheckRunnableAndCloseFutureListener();
verify(tooManyOpenConnectionsAttributeMock).set(actualOpenChannels);
verifyDoubleCheckFuture(futureInfoPair.getLeft());
verifyCloseFutureListener(futureInfoPair.getRight());
verify(channelGroupMock, never()).add(channelMock);
}
Aggregations