use of io.netty.util.concurrent.Future in project jersey by jersey.
the class NettyHttpContainerProvider method createServer.
/**
* Create and start Netty server.
*
* @param baseUri base uri.
* @param configuration Jersey configuration.
* @param sslContext Netty SSL context (can be null).
* @param block when {@code true}, this method will block until the server is stopped. When {@code false}, the
* execution will
* end immediately after the server is started.
* @return Netty channel instance.
* @throws ProcessingException when there is an issue with creating new container.
*/
public static Channel createServer(final URI baseUri, final ResourceConfig configuration, SslContext sslContext, final boolean block) throws ProcessingException {
// Configure the server.
final EventLoopGroup bossGroup = new NioEventLoopGroup(1);
final EventLoopGroup workerGroup = new NioEventLoopGroup();
final NettyHttpContainer container = new NettyHttpContainer(configuration);
try {
ServerBootstrap b = new ServerBootstrap();
b.option(ChannelOption.SO_BACKLOG, 1024);
b.group(bossGroup, workerGroup).channel(NioServerSocketChannel.class).childHandler(new JerseyServerInitializer(baseUri, sslContext, container));
int port = getPort(baseUri);
Channel ch = b.bind(port).sync().channel();
ch.closeFuture().addListener(new GenericFutureListener<Future<? super Void>>() {
@Override
public void operationComplete(Future<? super Void> future) throws Exception {
container.getApplicationHandler().onShutdown(container);
bossGroup.shutdownGracefully();
workerGroup.shutdownGracefully();
}
});
if (block) {
ch.closeFuture().sync();
return ch;
} else {
return ch;
}
} catch (InterruptedException e) {
throw new ProcessingException(e);
}
}
use of io.netty.util.concurrent.Future in project jersey by jersey.
the class JerseyHttp2ServerHandler method createContainerRequest.
/**
* Create Jersey {@link ContainerRequest} based on Netty {@link HttpRequest}.
*
* @param ctx Netty channel context.
* @param http2Headers Netty Http/2 headers.
* @return created Jersey Container Request.
*/
private ContainerRequest createContainerRequest(ChannelHandlerContext ctx, Http2HeadersFrame http2Headers) {
String path = http2Headers.headers().path().toString();
String s = path.startsWith("/") ? path.substring(1) : path;
URI requestUri = URI.create(baseUri + ContainerUtils.encodeUnsafeCharacters(s));
ContainerRequest requestContext = new ContainerRequest(baseUri, requestUri, http2Headers.headers().method().toString(), getSecurityContext(), new PropertiesDelegate() {
private final Map<String, Object> properties = new HashMap<>();
@Override
public Object getProperty(String name) {
return properties.get(name);
}
@Override
public Collection<String> getPropertyNames() {
return properties.keySet();
}
@Override
public void setProperty(String name, Object object) {
properties.put(name, object);
}
@Override
public void removeProperty(String name) {
properties.remove(name);
}
});
// request entity handling.
if (!http2Headers.isEndStream()) {
ctx.channel().closeFuture().addListener(new GenericFutureListener<Future<? super Void>>() {
@Override
public void operationComplete(Future<? super Void> future) throws Exception {
isList.add(NettyInputStream.END_OF_INPUT_ERROR);
}
});
requestContext.setEntityStream(new NettyInputStream(isList));
} else {
requestContext.setEntityStream(new InputStream() {
@Override
public int read() throws IOException {
return -1;
}
});
}
// copying headers from netty request to jersey container request context.
for (CharSequence name : http2Headers.headers().names()) {
requestContext.headers(name.toString(), mapToString(http2Headers.headers().getAll(name)));
}
return requestContext;
}
use of io.netty.util.concurrent.Future in project jersey by jersey.
the class JerseyServerHandler method createContainerRequest.
/**
* Create Jersey {@link ContainerRequest} based on Netty {@link HttpRequest}.
*
* @param ctx Netty channel context.
* @param req Netty Http request.
* @return created Jersey Container Request.
*/
private ContainerRequest createContainerRequest(ChannelHandlerContext ctx, HttpRequest req) {
String s = req.uri().startsWith("/") ? req.uri().substring(1) : req.uri();
URI requestUri = URI.create(baseUri + ContainerUtils.encodeUnsafeCharacters(s));
ContainerRequest requestContext = new ContainerRequest(baseUri, requestUri, req.method().name(), getSecurityContext(), new PropertiesDelegate() {
private final Map<String, Object> properties = new HashMap<>();
@Override
public Object getProperty(String name) {
return properties.get(name);
}
@Override
public Collection<String> getPropertyNames() {
return properties.keySet();
}
@Override
public void setProperty(String name, Object object) {
properties.put(name, object);
}
@Override
public void removeProperty(String name) {
properties.remove(name);
}
});
// request entity handling.
if ((req.headers().contains(HttpHeaderNames.CONTENT_LENGTH) && HttpUtil.getContentLength(req) > 0) || HttpUtil.isTransferEncodingChunked(req)) {
ctx.channel().closeFuture().addListener(new GenericFutureListener<Future<? super Void>>() {
@Override
public void operationComplete(Future<? super Void> future) throws Exception {
isList.add(NettyInputStream.END_OF_INPUT_ERROR);
}
});
requestContext.setEntityStream(new NettyInputStream(isList));
} else {
requestContext.setEntityStream(new InputStream() {
@Override
public int read() throws IOException {
return -1;
}
});
}
// copying headers from netty request to jersey container request context.
for (String name : req.headers().names()) {
requestContext.headers(name, req.headers().getAll(name));
}
return requestContext;
}
use of io.netty.util.concurrent.Future in project riposte by Nike-Inc.
the class StreamingAsyncHttpClient method streamDownstreamCall.
/**
* TODO: Fully document me.
* <br/>
* NOTE: The returned CompletableFuture will only be completed successfully if the connection to the downstream
* server was successful and the initialRequestChunk was successfully written out. This has implications for
* initialRequestChunk regarding releasing its reference count (i.e. calling {@link
* io.netty.util.ReferenceCountUtil#release(Object)} and passing in initialRequestChunk). If the returned
* CompletableFuture is successful it means initialRequestChunk's reference count will already be reduced by one
* relative to when this method was called because it will have been passed to a successful {@link
* ChannelHandlerContext#writeAndFlush(Object)} method call.
* <p/>
* Long story short - assume initialRequestChunk is an object with a reference count of x:
* <ul>
* <li>
* If the returned CompletableFuture is successful, then when it completes successfully
* initialRequestChunk's reference count will be x - 1
* </li>
* <li>
* If the returned CompletableFuture is *NOT* successful, then when it completes initialRequestChunk's
* reference count will still be x
* </li>
* </ul>
*/
public CompletableFuture<StreamingChannel> streamDownstreamCall(String downstreamHost, int downstreamPort, HttpRequest initialRequestChunk, boolean isSecureHttpsCall, boolean relaxedHttpsValidation, StreamingCallback callback, long downstreamCallTimeoutMillis, ChannelHandlerContext ctx) {
CompletableFuture<StreamingChannel> streamingChannel = new CompletableFuture<>();
initialRequestChunk.headers().set(HttpHeaders.Names.HOST, downstreamHost);
boolean performSubSpanAroundDownstreamCalls = true;
ObjectHolder<Long> beforeConnectionStartTimeNanos = new ObjectHolder<>();
beforeConnectionStartTimeNanos.heldObject = System.nanoTime();
// Create a connection to the downstream server.
ChannelPool pool = getPooledChannelFuture(downstreamHost, downstreamPort);
Future<Channel> channelFuture = pool.acquire();
// Add a listener that kicks off the downstream call once the connection is completed.
channelFuture.addListener(future -> {
Pair<Deque<Span>, Map<String, String>> originalThreadInfo = null;
try {
originalThreadInfo = linkTracingAndMdcToCurrentThread(ctx);
if (!future.isSuccess()) {
try {
streamingChannel.completeExceptionally(new WrapperException("Unable to connect to downstream host: " + downstreamHost, future.cause()));
} finally {
Channel ch = channelFuture.getNow();
if (ch != null) {
markChannelAsBroken(ch);
pool.release(ch);
}
}
return;
}
if (logger.isDebugEnabled()) {
logger.debug("CONNECTION SETUP TIME NANOS: {}", (System.nanoTime() - beforeConnectionStartTimeNanos.heldObject));
}
if (performSubSpanAroundDownstreamCalls) {
String spanName = getSubspanSpanName(initialRequestChunk.getMethod().name(), downstreamHost + ":" + downstreamPort + initialRequestChunk.getUri());
if (Tracer.getInstance().getCurrentSpan() == null) {
Tracer.getInstance().startRequestWithRootSpan(spanName);
} else {
Tracer.getInstance().startSubSpan(spanName, Span.SpanPurpose.CLIENT);
}
}
Deque<Span> distributedSpanStackToUse = Tracer.getInstance().getCurrentSpanStackCopy();
Map<String, String> mdcContextToUse = MDC.getCopyOfContextMap();
Span spanForDownstreamCall = (distributedSpanStackToUse == null) ? null : distributedSpanStackToUse.peek();
if (spanForDownstreamCall != null) {
setHeaderIfValueNotNull(initialRequestChunk, TraceHeaders.TRACE_SAMPLED, String.valueOf(spanForDownstreamCall.isSampleable()));
setHeaderIfValueNotNull(initialRequestChunk, TraceHeaders.TRACE_ID, spanForDownstreamCall.getTraceId());
setHeaderIfValueNotNull(initialRequestChunk, TraceHeaders.SPAN_ID, spanForDownstreamCall.getSpanId());
setHeaderIfValueNotNull(initialRequestChunk, TraceHeaders.PARENT_SPAN_ID, spanForDownstreamCall.getParentSpanId());
setHeaderIfValueNotNull(initialRequestChunk, TraceHeaders.SPAN_NAME, spanForDownstreamCall.getSpanName());
}
Channel ch = channelFuture.getNow();
if (logger.isDebugEnabled())
logger.debug("Channel ID of the Channel pulled from the pool: {}", ch.toString());
ch.eventLoop().execute(runnableWithTracingAndMdc(() -> {
BiConsumer<String, Throwable> prepChannelErrorHandler = (errorMessage, cause) -> {
try {
streamingChannel.completeExceptionally(new WrapperException(errorMessage, cause));
} finally {
markChannelAsBroken(ch);
pool.release(ch);
}
};
try {
ObjectHolder<Boolean> callActiveHolder = new ObjectHolder<>();
callActiveHolder.heldObject = true;
ObjectHolder<Boolean> lastChunkSentDownstreamHolder = new ObjectHolder<>();
lastChunkSentDownstreamHolder.heldObject = false;
prepChannelForDownstreamCall(pool, ch, callback, distributedSpanStackToUse, mdcContextToUse, isSecureHttpsCall, relaxedHttpsValidation, performSubSpanAroundDownstreamCalls, downstreamCallTimeoutMillis, callActiveHolder, lastChunkSentDownstreamHolder);
logInitialRequestChunk(initialRequestChunk, downstreamHost, downstreamPort);
ChannelFuture writeFuture = ch.writeAndFlush(initialRequestChunk);
writeFuture.addListener(completedWriteFuture -> {
if (completedWriteFuture.isSuccess())
streamingChannel.complete(new StreamingChannel(ch, pool, callActiveHolder, lastChunkSentDownstreamHolder, distributedSpanStackToUse, mdcContextToUse));
else {
prepChannelErrorHandler.accept("Writing the first HttpRequest chunk to the downstream service failed.", completedWriteFuture.cause());
return;
}
});
} catch (SSLException | NoSuchAlgorithmException | KeyStoreException ex) {
prepChannelErrorHandler.accept("Error setting up SSL context for downstream call", ex);
return;
} catch (Throwable t) {
prepChannelErrorHandler.accept("An unexpected error occurred while prepping the channel pipeline for the downstream call", t);
return;
}
}, ctx));
} catch (Throwable ex) {
try {
String errorMsg = "Error occurred attempting to send first chunk (headers/etc) downstream";
Exception errorToFire = new WrapperException(errorMsg, ex);
logger.warn(errorMsg, errorToFire);
streamingChannel.completeExceptionally(errorToFire);
} finally {
Channel ch = channelFuture.getNow();
if (ch != null) {
markChannelAsBroken(ch);
pool.release(ch);
}
}
} finally {
unlinkTracingAndMdcFromCurrentThread(originalThreadInfo);
}
});
return streamingChannel;
}
use of io.netty.util.concurrent.Future in project redisson by redisson.
the class BaseRemoteService method async.
private <T> T async(final Class<T> remoteInterface, final RemoteInvocationOptions options, final Class<?> syncInterface) {
// local copy of the options, to prevent mutation
final RemoteInvocationOptions optionsCopy = new RemoteInvocationOptions(options);
final String toString = getClass().getSimpleName() + "-" + remoteInterface.getSimpleName() + "-proxy-" + generateRequestId();
InvocationHandler handler = new InvocationHandler() {
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
if (method.getName().equals("toString")) {
return toString;
} else if (method.getName().equals("equals")) {
return proxy == args[0];
} else if (method.getName().equals("hashCode")) {
return toString.hashCode();
}
if (!optionsCopy.isResultExpected() && !(method.getReturnType().equals(Void.class) || method.getReturnType().equals(Void.TYPE) || method.getReturnType().equals(RFuture.class))) {
throw new IllegalArgumentException("The noResult option only supports void return value");
}
final String requestId = generateRequestId();
final String requestQueueName = getRequestQueueName(syncInterface);
final String responseName = getResponseQueueName(syncInterface, requestId);
final String ackName = getAckName(syncInterface, requestId);
final RBlockingQueue<RemoteServiceRequest> requestQueue = redisson.getBlockingQueue(requestQueueName, getCodec());
final RemoteServiceRequest request = new RemoteServiceRequest(requestId, method.getName(), getMethodSignatures(method), args, optionsCopy, System.currentTimeMillis());
final RemotePromise<Object> result = new RemotePromise<Object>(commandExecutor.getConnectionManager().newPromise()) {
@Override
public boolean cancel(boolean mayInterruptIfRunning) {
if (isCancelled()) {
return true;
}
if (isDone()) {
return false;
}
if (optionsCopy.isAckExpected()) {
RFuture<Boolean> future = commandExecutor.evalWriteAsync(responseName, LongCodec.INSTANCE, RedisCommands.EVAL_BOOLEAN, "if redis.call('setnx', KEYS[1], 1) == 1 then " + "redis.call('pexpire', KEYS[1], ARGV[2]);" + "redis.call('lrem', KEYS[3], 1, ARGV[1]);" + "redis.call('pexpire', KEYS[2], ARGV[2]);" + "return 1;" + "end;" + "return 0;", Arrays.<Object>asList(ackName, responseName, requestQueueName), encode(request), request.getOptions().getAckTimeoutInMillis());
boolean ackNotSent = commandExecutor.get(future);
if (ackNotSent) {
super.cancel(mayInterruptIfRunning);
return true;
}
return cancel(syncInterface, requestId, request, mayInterruptIfRunning);
}
boolean removed = remove(requestQueue, request);
if (removed) {
super.cancel(mayInterruptIfRunning);
return true;
}
return cancel(syncInterface, requestId, request, mayInterruptIfRunning);
}
private boolean cancel(Class<?> remoteInterface, String requestId, RemoteServiceRequest request, boolean mayInterruptIfRunning) {
if (isCancelled()) {
return true;
}
if (isDone()) {
return false;
}
String canceRequestName = getCancelRequestQueueName(remoteInterface, requestId);
cancelExecution(optionsCopy, responseName, request, mayInterruptIfRunning, canceRequestName, this);
awaitUninterruptibly(60, TimeUnit.SECONDS);
return isCancelled();
}
};
result.setRequestId(requestId);
RFuture<Boolean> addFuture = addAsync(requestQueue, request, result);
addFuture.addListener(new FutureListener<Boolean>() {
@Override
public void operationComplete(Future<Boolean> future) throws Exception {
if (!future.isSuccess()) {
result.tryFailure(future.cause());
return;
}
if (optionsCopy.isAckExpected()) {
final RBlockingQueue<RemoteServiceAck> responseQueue = redisson.getBlockingQueue(responseName, getCodec());
RFuture<RemoteServiceAck> ackFuture = responseQueue.pollAsync(optionsCopy.getAckTimeoutInMillis(), TimeUnit.MILLISECONDS);
ackFuture.addListener(new FutureListener<RemoteServiceAck>() {
@Override
public void operationComplete(Future<RemoteServiceAck> future) throws Exception {
if (!future.isSuccess()) {
result.tryFailure(future.cause());
return;
}
RemoteServiceAck ack = future.getNow();
if (ack == null) {
RFuture<RemoteServiceAck> ackFutureAttempt = tryPollAckAgainAsync(optionsCopy, responseQueue, ackName);
ackFutureAttempt.addListener(new FutureListener<RemoteServiceAck>() {
@Override
public void operationComplete(Future<RemoteServiceAck> future) throws Exception {
if (!future.isSuccess()) {
result.tryFailure(future.cause());
return;
}
if (future.getNow() == null) {
Exception ex = new RemoteServiceAckTimeoutException("No ACK response after " + optionsCopy.getAckTimeoutInMillis() + "ms for request: " + request);
result.tryFailure(ex);
return;
}
awaitResultAsync(optionsCopy, result, request, responseName, ackName);
}
});
} else {
awaitResultAsync(optionsCopy, result, request, responseName);
}
}
});
} else {
awaitResultAsync(optionsCopy, result, request, responseName);
}
}
});
return result;
}
};
return (T) Proxy.newProxyInstance(remoteInterface.getClassLoader(), new Class[] { remoteInterface }, handler);
}
Aggregations