diff --git a/nima/http2/webserver/src/main/java/io/helidon/nima/http2/webserver/Http2ServerRequest.java b/nima/http2/webserver/src/main/java/io/helidon/nima/http2/webserver/Http2ServerRequest.java index c2b863e92fa..9ee3bdcefec 100644 --- a/nima/http2/webserver/src/main/java/io/helidon/nima/http2/webserver/Http2ServerRequest.java +++ b/nima/http2/webserver/src/main/java/io/helidon/nima/http2/webserver/Http2ServerRequest.java @@ -167,7 +167,8 @@ public RoutingRequest prologue(HttpPrologue newPrologue) { public Context context() { if (context == null) { context = Contexts.context().orElseGet(() -> Context.builder() - .id("[" + serverSocketId() + " " + socketId() + "] http/2: " + requestId) + .parent(ctx.context()) + .id("[" + serverSocketId() + " " + socketId() + "] http/1.1: " + requestId) .build()); } return context; diff --git a/nima/testing/junit5/webserver/src/main/java/io/helidon/nima/testing/junit5/webserver/DirectClientConnection.java b/nima/testing/junit5/webserver/src/main/java/io/helidon/nima/testing/junit5/webserver/DirectClientConnection.java index 5053a9e64bd..e0458948c68 100644 --- a/nima/testing/junit5/webserver/src/main/java/io/helidon/nima/testing/junit5/webserver/DirectClientConnection.java +++ b/nima/testing/junit5/webserver/src/main/java/io/helidon/nima/testing/junit5/webserver/DirectClientConnection.java @@ -24,6 +24,7 @@ import io.helidon.common.buffers.BufferData; import io.helidon.common.buffers.DataReader; import io.helidon.common.buffers.DataWriter; +import io.helidon.common.context.Context; import io.helidon.common.socket.PeerInfo; import io.helidon.nima.http.encoding.ContentEncodingContext; import io.helidon.nima.http.media.MediaContext; @@ -152,7 +153,8 @@ private void startServer() { "unit-channel", DirectHandlers.builder().build(), socket, - -1); + -1, + Context.create()); ServerConnection connection = Http1ConnectionProvider.builder() .build() diff --git a/nima/webserver/webserver/src/main/java/io/helidon/nima/webserver/ConnectionContext.java b/nima/webserver/webserver/src/main/java/io/helidon/nima/webserver/ConnectionContext.java index 8f6dc208cca..bfaf422847f 100644 --- a/nima/webserver/webserver/src/main/java/io/helidon/nima/webserver/ConnectionContext.java +++ b/nima/webserver/webserver/src/main/java/io/helidon/nima/webserver/ConnectionContext.java @@ -20,6 +20,7 @@ import io.helidon.common.buffers.DataReader; import io.helidon.common.buffers.DataWriter; +import io.helidon.common.context.Context; import io.helidon.common.socket.HelidonSocket; import io.helidon.common.socket.SocketContext; import io.helidon.nima.http.encoding.ContentEncodingContext; @@ -44,6 +45,7 @@ public interface ConnectionContext extends SocketContext { * @param simpleHandlers error handling configuration * @param socket socket to obtain information about peers * @param maxPayloadSize maximal size of a payload entity + * @param context parent context from web server * @return a new context */ static ConnectionContext create(MediaContext mediaContext, @@ -56,7 +58,8 @@ static ConnectionContext create(MediaContext mediaContext, String channelId, DirectHandlers simpleHandlers, HelidonSocket socket, - long maxPayloadSize) { + long maxPayloadSize, + Context context) { return new ConnectionContextImpl(mediaContext, contentEncodingContext, sharedExecutor, @@ -67,7 +70,8 @@ static ConnectionContext create(MediaContext mediaContext, channelId, simpleHandlers, socket, - maxPayloadSize); + maxPayloadSize, + context); } /** @@ -125,4 +129,11 @@ static ConnectionContext create(MediaContext mediaContext, * @return simple handlers */ DirectHandlers directHandlers(); + + /** + * Parent context from WebServer. + * + * @return parent context. + */ + Context context(); } diff --git a/nima/webserver/webserver/src/main/java/io/helidon/nima/webserver/ConnectionContextImpl.java b/nima/webserver/webserver/src/main/java/io/helidon/nima/webserver/ConnectionContextImpl.java index 9a7de91d8ab..42dc67c0883 100644 --- a/nima/webserver/webserver/src/main/java/io/helidon/nima/webserver/ConnectionContextImpl.java +++ b/nima/webserver/webserver/src/main/java/io/helidon/nima/webserver/ConnectionContextImpl.java @@ -21,6 +21,7 @@ import io.helidon.common.buffers.DataReader; import io.helidon.common.buffers.DataWriter; +import io.helidon.common.context.Context; import io.helidon.common.socket.HelidonSocket; import io.helidon.common.socket.PeerInfo; import io.helidon.nima.http.encoding.ContentEncodingContext; @@ -39,6 +40,7 @@ final class ConnectionContextImpl implements ConnectionContext { private final DirectHandlers simpleHandlers; private final HelidonSocket socket; private final long maxPayloadSize; + private final Context context; ConnectionContextImpl(MediaContext mediaContext, ContentEncodingContext contentEncodingContext, @@ -50,7 +52,8 @@ final class ConnectionContextImpl implements ConnectionContext { String childSocketId, DirectHandlers simpleHandlers, HelidonSocket socket, - long maxPayloadSize) { + long maxPayloadSize, + Context context) { this.mediaContext = mediaContext; this.contentEncodingContext = contentEncodingContext; this.sharedExecutor = sharedExecutor; @@ -62,6 +65,7 @@ final class ConnectionContextImpl implements ConnectionContext { this.simpleHandlers = simpleHandlers; this.socket = socket; this.maxPayloadSize = maxPayloadSize; + this.context = context; } @Override @@ -129,13 +133,18 @@ public String childSocketId() { return childSocketId; } + @Override + public Context context() { + return context; + } + @Override public int hashCode() { return Objects.hash(sharedExecutor, - dataWriter, - router, - socketId, - childSocketId); + dataWriter, + router, + socketId, + childSocketId); } @Override @@ -163,5 +172,4 @@ public String toString() { + "socketId=" + socketId + ", " + "childSocketId=" + childSocketId + ']'; } - } diff --git a/nima/webserver/webserver/src/main/java/io/helidon/nima/webserver/ConnectionHandler.java b/nima/webserver/webserver/src/main/java/io/helidon/nima/webserver/ConnectionHandler.java index c33ff00b687..a5ab7e69790 100644 --- a/nima/webserver/webserver/src/main/java/io/helidon/nima/webserver/ConnectionHandler.java +++ b/nima/webserver/webserver/src/main/java/io/helidon/nima/webserver/ConnectionHandler.java @@ -23,6 +23,7 @@ import io.helidon.common.buffers.BufferData; import io.helidon.common.buffers.DataReader; +import io.helidon.common.context.Context; import io.helidon.common.http.HttpException; import io.helidon.common.http.RequestException; import io.helidon.common.socket.HelidonSocket; @@ -65,7 +66,8 @@ class ConnectionHandler implements Runnable { Router router, int writeQueueLength, long maxPayloadSize, - DirectHandlers simpleHandlers) { + DirectHandlers simpleHandlers, + Context context) { this.connectionProviders = connectionProviders; this.providerCandidates = connectionProviders.providerCandidates(); this.serverChannelId = serverChannelId; @@ -83,7 +85,8 @@ class ConnectionHandler implements Runnable { channelId, simpleHandlers, socket, - maxPayloadSize); + maxPayloadSize, + context); } @Override diff --git a/nima/webserver/webserver/src/main/java/io/helidon/nima/webserver/LoomServer.java b/nima/webserver/webserver/src/main/java/io/helidon/nima/webserver/LoomServer.java index ac6dbcf58d9..2f1751367bd 100644 --- a/nima/webserver/webserver/src/main/java/io/helidon/nima/webserver/LoomServer.java +++ b/nima/webserver/webserver/src/main/java/io/helidon/nima/webserver/LoomServer.java @@ -33,6 +33,7 @@ import java.util.function.Consumer; import io.helidon.common.Version; +import io.helidon.common.context.Context; import io.helidon.nima.http.encoding.ContentEncodingContext; import io.helidon.nima.http.media.MediaContext; import io.helidon.nima.webserver.http.DirectHandlers; @@ -51,6 +52,8 @@ class LoomServer implements WebServer { private volatile List startFutures; private boolean alreadyStarted = false; + private final Context context; + LoomServer(Builder builder, DirectHandlers simpleHandlers) { List connectionProviders = builder.connectionProviders(); @@ -99,6 +102,7 @@ class LoomServer implements WebServer { .allowSetThreadLocals(true) .inheritInheritableThreadLocals(false) .factory()); + this.context = builder.context(); } @Override @@ -161,6 +165,11 @@ public boolean hasTls(String socketName) { return false; } + @Override + public Context context() { + return context; + } + private void stopIt() { parallel("stop", ServerListener::stop); running.set(false); diff --git a/nima/webserver/webserver/src/main/java/io/helidon/nima/webserver/ServerListener.java b/nima/webserver/webserver/src/main/java/io/helidon/nima/webserver/ServerListener.java index 8ac157a1905..0d088210dd1 100644 --- a/nima/webserver/webserver/src/main/java/io/helidon/nima/webserver/ServerListener.java +++ b/nima/webserver/webserver/src/main/java/io/helidon/nima/webserver/ServerListener.java @@ -257,7 +257,8 @@ private void listen() { router, listenerConfig.writeQueueLength(), listenerConfig.maxPayloadSize(), - simpleHandlers); + simpleHandlers, + server.context()); readerExecutor.submit(handler); } catch (RejectedExecutionException e) { diff --git a/nima/webserver/webserver/src/main/java/io/helidon/nima/webserver/WebServer.java b/nima/webserver/webserver/src/main/java/io/helidon/nima/webserver/WebServer.java index 5d1788063fb..9927387f78b 100644 --- a/nima/webserver/webserver/src/main/java/io/helidon/nima/webserver/WebServer.java +++ b/nima/webserver/webserver/src/main/java/io/helidon/nima/webserver/WebServer.java @@ -22,10 +22,12 @@ import java.util.Map; import java.util.Objects; import java.util.ServiceLoader; +import java.util.concurrent.atomic.AtomicInteger; import java.util.function.BiConsumer; import java.util.function.Consumer; import io.helidon.common.HelidonServiceLoader; +import io.helidon.common.context.Context; import io.helidon.common.http.DirectHandler; import io.helidon.config.Config; import io.helidon.logging.common.LogConfig; @@ -120,10 +122,20 @@ default boolean hasTls() { */ boolean hasTls(String socketName); + /** + * Context associated with the {@code WebServer}, used as a parent for request contexts. + * + * @return a server context + */ + Context context(); + /** * Fluent API builder for {@link WebServer}. */ class Builder implements io.helidon.common.Builder, Router.RouterBuilder { + + private static final AtomicInteger WEBSERVER_COUNTER = new AtomicInteger(1); + static { LogConfig.initClass(); } @@ -138,6 +150,8 @@ class Builder implements io.helidon.common.Builder, Router.R private MediaContext mediaContext = MediaContext.create(); private ContentEncodingContext contentEncodingContext = ContentEncodingContext.create(); + private Context context; + Builder(Config rootConfig) { config(rootConfig.get("server")); } @@ -149,6 +163,15 @@ private Builder() { @Override public WebServer build() { + + if (context == null) { + // In case somebody spins a huge number up, the counter will cycle to negative numbers once + // Integer.MAX_VALUE is reached. + context = Context.builder() + .id("web-" + WEBSERVER_COUNTER.getAndIncrement()) + .build(); + } + return new LoomServer(this, simpleHandlers.build()); } @@ -380,6 +403,20 @@ public Builder contentEncodingContext(ContentEncodingContext contentEncodingCont return this; } + /** + * Configure the application scoped context to be used as a parent for webserver request contexts. + * @param context top level context + * @return an updated builder + */ + public Builder context(Context context) { + this.context = context; + return this; + } + + Context context() { + return context; + } + MediaContext mediaContext() { return this.mediaContext; } @@ -391,7 +428,6 @@ ContentEncodingContext contentEncodingContext() { Map socketBuilders() { return socketBuilder; } - /** * Map of socket name to router. * diff --git a/nima/webserver/webserver/src/main/java/io/helidon/nima/webserver/http1/Http1ServerRequest.java b/nima/webserver/webserver/src/main/java/io/helidon/nima/webserver/http1/Http1ServerRequest.java index 2ab22dbdea6..2805db334f2 100644 --- a/nima/webserver/webserver/src/main/java/io/helidon/nima/webserver/http1/Http1ServerRequest.java +++ b/nima/webserver/webserver/src/main/java/io/helidon/nima/webserver/http1/Http1ServerRequest.java @@ -178,6 +178,7 @@ public Http1ServerRequest prologue(HttpPrologue newPrologue) { public Context context() { if (context == null) { context = Contexts.context().orElseGet(() -> Context.builder() + .parent(ctx.context()) .id("[" + serverSocketId() + " " + socketId() + "] http/1.1: " + requestId) .build()); }