Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fix session affinity management (stickiness) in wildfly-http-client #108

Open
wants to merge 16 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from 15 commits
Commits
Show all changes
16 commits
Select commit Hold shift + click to select a range
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,7 @@
import static org.jboss.marshalling.ClassNameTransformer.JAVAEE_TO_JAKARTAEE;
import static org.wildfly.httpclient.common.HttpMarshallerFactory.DEFAULT_FACTORY;
import static org.wildfly.httpclient.common.Protocol.VERSION_ONE_PATH;
import static org.wildfly.httpclient.common.Protocol.VERSION_PATH;
import static org.wildfly.httpclient.common.Protocol.VERSION_TWO_PATH;

/**
Expand Down Expand Up @@ -86,7 +87,12 @@ private EENamespaceInteroperability() {}

/**
* Wraps the HTTP server handler into an EE namespace interoperable handler. Such handler implements the
* EE namespace interoperability at the server side before delegating to the wrapped {@code httpHandler}
* EE namespace interoperability at the server side before delegating to the wrapped {@code httpHandler}.
* The resulting handler handles the EE namespace interoperability according to the value of {@link
* #EE_NAMESPACE_INTEROPERABLE_MODE}. It accepts {@code javax} namespace requests at the path prefix {@code
* "/v1"}, while {@code jakarta} namespace requests are received at the path prefix {@code "/v2"}. Both
* requests are forwarded to {@code handler}, but in case of {@code "/v1"} the {@code javax} namespace is
* converted to {@code jakarta}.
*
* @param httpHandler the handler to be wrapped
* @return handler the ee namespace interoperability handler
Expand All @@ -95,13 +101,46 @@ static HttpHandler createInteroperabilityHandler(HttpHandler httpHandler) {
return createProtocolVersionHttpHandler(new EENamespaceInteroperabilityHandler(httpHandler), new JakartaNamespaceHandler(httpHandler));
}

static HttpHandler createProtocolVersionHttpHandler(HttpHandler interoperabilityHandler, HttpHandler latestProtocolHandler) {
/**
* Wraps the multi-versioned HTTP server handlers into an EE namespace interoperable handler. Such handler
* implements the EE namespace interoperability at the server side before delegating to the wrapped HTTP
* handler. The resulting handler handles the EE namespace interoperability according to the value of
* {@link #EE_NAMESPACE_INTEROPERABLE_MODE}. It accepts {@code javax} namespace requests at the path prefix
* {@code "/v1"}, while {@code jakarta} namespace requests are received at the subsequent path prefixes
* {@code "/v2"}, {@code "/v3"}, and so on. Requests to {@code "/v1"} and {@code "/v2"} path prefixes will be
* forwarded to {@code multiVersionedProtocolHandlers[0]}, while {@code "/v3"} will be forwarded to {@code
* multiVersionedProtocolHandlers[1]}. The sequence of paths follows until each multi-versioned handler
* {@code multiVersionedProtocolHandlers[N]} is associated with a prefix path {@code "/v<N+2>"}.
*
* @param multiVersionedProtocolHandlers the multiple handlers to be wrapped.
* @return handler the ee namespace interoperability handler
*/
static HttpHandler createInteroperabilityHandler(HttpHandler... multiVersionedProtocolHandlers) {
assert multiVersionedProtocolHandlers.length > 0;
HttpHandler[] versionedJakartaNamespaceHandlers = new HttpHandler[multiVersionedProtocolHandlers.length];
for (int i = 0; i < multiVersionedProtocolHandlers.length; i++) {
versionedJakartaNamespaceHandlers[i] = new JakartaNamespaceHandler(multiVersionedProtocolHandlers[i]);
}
return createProtocolVersionHttpHandler(new EENamespaceInteroperabilityHandler(multiVersionedProtocolHandlers[0]), versionedJakartaNamespaceHandlers);
}

private static HttpHandler createProtocolVersionHttpHandler(HttpHandler interoperabilityHandler, HttpHandler latestProtocolHandler) {
final PathHandler versionPathHandler = new PathHandler();
versionPathHandler.addPrefixPath(VERSION_ONE_PATH, interoperabilityHandler);
versionPathHandler.addPrefixPath(VERSION_TWO_PATH, latestProtocolHandler);
return versionPathHandler;
}

private static HttpHandler createProtocolVersionHttpHandler(HttpHandler interoperabilityHandler, HttpHandler... versionedProtocolHandlers) {
final PathHandler versionPathHandler = new PathHandler();
versionPathHandler.addPrefixPath(VERSION_ONE_PATH, interoperabilityHandler);
int version = 2;
for (HttpHandler versionedProtocolHandler: versionedProtocolHandlers) {
versionPathHandler.addPrefixPath(VERSION_PATH + version++, versionedProtocolHandler);
}
return versionPathHandler;
}

/**
* Returns the HTTPMarshallerFactoryProvider instance responsible for taking care of marshalling
* and unmarshalling according to the values negotiated by the ee namespace interoperability headers.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -78,4 +78,6 @@ interface HttpClientMessages extends BasicLogger {
@Message(id = 14, value = "JavaEE to JakartaEE backward compatibility layer have been installed")
void javaeeToJakartaeeBackwardCompatibilityLayerInstalled();

@Message(id = 15, value = "Failed to acquire backend server")
RuntimeException failedToAcquireBackendServer(@Cause Throwable e);
}
Original file line number Diff line number Diff line change
Expand Up @@ -20,8 +20,6 @@
import io.undertow.server.HttpHandler;
import io.undertow.server.HttpServerExchange;

import java.util.function.Function;

/**
* Mode configuration for http services.
* <p>
Expand All @@ -30,42 +28,72 @@
*
* @author Flavia Rainone
*/
public enum HttpServiceConfig {
public class HttpServiceConfig {

/**
* Default configuration. Used by both EE namespace interoperable and non-interoperable servers
*/
DEFAULT (EENamespaceInteroperability::createInteroperabilityHandler, EENamespaceInteroperability.getHttpMarshallerFactoryProvider());
private static final HttpServiceConfig INSTANCE = new HttpServiceConfig (EENamespaceInteroperability.getHttpMarshallerFactoryProvider());

/**
* Returns the default configuration.
*
* @return the configuration for http services
*/
public static HttpServiceConfig getInstance() {
return DEFAULT;
return INSTANCE;
}

private final Function<HttpHandler, HttpHandler> handlerWrapper;
private final HttpMarshallerFactoryProvider marshallerFactoryProvider;

HttpServiceConfig(Function<HttpHandler, HttpHandler> handlerWrapper, HttpMarshallerFactoryProvider marshallerFactoryProvider) {
this.handlerWrapper = handlerWrapper;
HttpServiceConfig(HttpMarshallerFactoryProvider marshallerFactoryProvider) {
this.marshallerFactoryProvider = marshallerFactoryProvider;
}

/**
* Wraps the http service handler. Should be applied to all http handlers configured by
* a http service.
* <br>
* The resulting handler is compatible with EE namespace interoperability and accepts
* {@code javax} namespace requests at the path prefix {@code "/v1"}, while {@code jakarta}
* namespace requests are received at the path prefix {@code "/v2"}. Both requests are
* forwarded to {@code handler}, but in case of {@code "/v1"} the {@code javax} namespace
* is converted to {@code jakarta}.
*
* @param handler responsible for handling the HTTP service requests directed to a specific
* URI
* URI. This handler must operate on {@code jakarta} namespace.
* @return the HttpHandler that should be provided to Undertow and associated with the HTTP
* service URI. The resulting handler is a wrapper that will add any necessary actions
* before invoking the inner {@code handler}.
*/
public HttpHandler wrap(HttpHandler handler) {
return handlerWrapper.apply(handler);
return EENamespaceInteroperability.createInteroperabilityHandler(handler);
}

/**
* Wraps a multi-version series of handlers. Each handler represents a version of the same operation
* provided by a HTTP service.
* <br>
* The resulting handler receives {@code javax} namespace requests at the path prefix {@code "/v1"},
* translates them to {@code jakarta namespace} and forwards them to {@code multiVersionedHandlers[0]}.
* The subsequent handlers in the {@code multiVersionedHandlers} array are mapped to path {@code "/v2"},
* {@code "/v3"} and so on.
* <br>
* Use this method when the http service supports more than one version of an HTTP Handler. This will be
* the case as http handlers evolve to incorporate new features and fixes that change the particular
* protocol format used by the HTTP handler for the specific operation it represents.
*
* @param multiVersionedHandlers responsible for handling the HTTP service requests directed to a specific
* URI. The handlers must be in crescent protocol number order, i.e., in the
* sequence corresponding to {@code "/v2"}, {@code "/v3}, {@code "/v4"}. All
* the handlers must be compatible with requests in the Jakarta namespace.
*
* @return the HttpHandler that should be provided to Undertow and associated with the HTTP
* service URI. The resulting handler is a wrapper that will take care of protocol
* versioning to invoke the appropriate handler
*/
public HttpHandler wrap(HttpHandler... multiVersionedHandlers) {
return EENamespaceInteroperability.createInteroperabilityHandler(multiVersionedHandlers);
}

/**
Expand Down
Loading