Skip to content

Commit

Permalink
Merge pull request #6119 from eclipse/jetty-10.0.x-6106-WebSocketCDI
Browse files Browse the repository at this point in the history
Issue #6106 - Fix WebSocket/CDI integration in Jetty 10
  • Loading branch information
lachlan-roberts committed Apr 30, 2021
2 parents 7048db0 + a0cca85 commit f828411
Show file tree
Hide file tree
Showing 34 changed files with 849 additions and 135 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,7 @@
import org.eclipse.jetty.io.ByteBufferPool;
import org.eclipse.jetty.io.EndPoint;
import org.eclipse.jetty.util.Callback;
import org.eclipse.jetty.util.MultiException;
import org.eclipse.jetty.util.QuotedStringTokenizer;
import org.eclipse.jetty.util.StringUtil;
import org.eclipse.jetty.websocket.core.Behavior;
Expand Down Expand Up @@ -291,7 +292,12 @@ public void requestComplete()
headers(headers -> headers.add(HttpHeader.SEC_WEBSOCKET_EXTENSIONS, extensionString));

// Notify the listener which may change the headers directly.
notifyUpgradeListeners((listener) -> listener.onHandshakeRequest(this));
Exception listenerError = notifyUpgradeListeners((listener) -> listener.onHandshakeRequest(this));
if (listenerError != null)
{
abort(listenerError);
return;
}

// Check if extensions were set in the headers from the upgrade listener.
String extsAfterListener = String.join(",", getHeaders().getCSV(HttpHeader.SEC_WEBSOCKET_EXTENSIONS, true));
Expand All @@ -306,8 +312,9 @@ public void requestComplete()
}
}

private void notifyUpgradeListeners(Consumer<UpgradeListener> action)
private Exception notifyUpgradeListeners(Consumer<UpgradeListener> action)
{
MultiException multiException = null;
for (UpgradeListener listener : upgradeListeners)
{
try
Expand All @@ -317,8 +324,13 @@ private void notifyUpgradeListeners(Consumer<UpgradeListener> action)
catch (Throwable t)
{
LOG.info("Exception while invoking listener {}", listener, t);
if (multiException == null)
multiException = new MultiException();
multiException.add(t);
}
}

return multiException;
}

public void upgrade(HttpResponse response, EndPoint endPoint)
Expand Down Expand Up @@ -437,7 +449,9 @@ else if (values.length == 1)
WebSocketConnection wsConnection = new WebSocketConnection(endPoint, httpClient.getExecutor(), httpClient.getScheduler(), bufferPool, coreSession);
wsClient.getEventListeners().forEach(wsConnection::addEventListener);
coreSession.setWebSocketConnection(wsConnection);
notifyUpgradeListeners((listener) -> listener.onHandshakeResponse(this, response));
Exception listenerError = notifyUpgradeListeners((listener) -> listener.onHandshakeResponse(this, response));
if (listenerError != null)
throw new WebSocketException("onHandshakeResponse error", listenerError);

// Now swap out the connection
try
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -40,9 +40,9 @@ public class WebSocketServerComponents extends WebSocketComponents
public static final String WEBSOCKET_DEFLATER_POOL_ATTRIBUTE = "jetty.websocket.deflater";
public static final String WEBSOCKET_BUFFER_POOL_ATTRIBUTE = "jetty.websocket.bufferPool";

WebSocketServerComponents(InflaterPool inflaterPool, DeflaterPool deflaterPool, ByteBufferPool bufferPool)
WebSocketServerComponents(InflaterPool inflaterPool, DeflaterPool deflaterPool, ByteBufferPool bufferPool, DecoratedObjectFactory objectFactory)
{
super(null, null, bufferPool, inflaterPool, deflaterPool);
super(null, objectFactory, bufferPool, inflaterPool, deflaterPool);
}

/**
Expand Down Expand Up @@ -79,7 +79,10 @@ public static WebSocketComponents ensureWebSocketComponents(Server server, Servl
if (bufferPool == null)
bufferPool = server.getBean(ByteBufferPool.class);

WebSocketComponents serverComponents = new WebSocketServerComponents(inflaterPool, deflaterPool, bufferPool);
DecoratedObjectFactory objectFactory = (DecoratedObjectFactory)servletContext.getAttribute(DecoratedObjectFactory.ATTR);
WebSocketComponents serverComponents = new WebSocketServerComponents(inflaterPool, deflaterPool, bufferPool, objectFactory);
if (objectFactory != null)
serverComponents.unmanage(objectFactory);

// These components may be managed by the server but not yet started.
// In this case we don't want them to be managed by the components as well.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,17 +18,18 @@
import javax.websocket.ClientEndpoint;
import javax.websocket.ClientEndpointConfig;

import org.eclipse.jetty.websocket.core.WebSocketComponents;
import org.eclipse.jetty.websocket.core.exception.InvalidWebSocketException;
import org.eclipse.jetty.websocket.javax.common.ClientEndpointConfigWrapper;

public class AnnotatedClientEndpointConfig extends ClientEndpointConfigWrapper
{
public AnnotatedClientEndpointConfig(ClientEndpoint anno)
public AnnotatedClientEndpointConfig(ClientEndpoint anno, WebSocketComponents components)
{
Configurator configurator;
try
{
configurator = anno.configurator().getDeclaredConstructor().newInstance();
configurator = components.getObjectFactory().createInstance(anno.configurator());
}
catch (Exception e)
{
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -229,9 +229,16 @@ public Session connectToServer(final Class<?> annotatedEndpointClass, final URI
@Override
public Session connectToServer(final Endpoint endpoint, final ClientEndpointConfig providedConfig, final URI path) throws DeploymentException, IOException
{
ClientEndpointConfig config = providedConfig;
if (config == null)
ClientEndpointConfig config;
if (providedConfig == null)
{
config = new BasicClientEndpointConfig();
}
else
{
config = providedConfig;
components.getObjectFactory().decorate(providedConfig.getConfigurator());
}

ConfiguredEndpoint instance = new ConfiguredEndpoint(endpoint, config);
return connect(instance, path);
Expand All @@ -240,6 +247,7 @@ public Session connectToServer(final Endpoint endpoint, final ClientEndpointConf
@Override
public Session connectToServer(Object endpoint, URI path) throws DeploymentException, IOException
{
// The Configurator will be decorated when it is created in the getAnnotatedConfig method.
ClientEndpointConfig config = getAnnotatedConfig(endpoint);
ConfiguredEndpoint instance = new ConfiguredEndpoint(endpoint, config);
return connect(instance, path);
Expand Down Expand Up @@ -275,7 +283,7 @@ private ClientEndpointConfig getAnnotatedConfig(Object endpoint) throws Deployme
if (anno == null)
throw new DeploymentException("Could not get ClientEndpoint annotation for " + endpoint.getClass().getName());

return new AnnotatedClientEndpointConfig(anno);
return new AnnotatedClientEndpointConfig(anno, components);
}

@Override
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -48,7 +48,7 @@ public JavaxWebSocketFrameHandlerMetadata getMetadata(Class<?> endpointClass, En
if (endpointClass.getAnnotation(ClientEndpoint.class) == null)
return null;

JavaxWebSocketFrameHandlerMetadata metadata = new JavaxWebSocketFrameHandlerMetadata(endpointConfig);
JavaxWebSocketFrameHandlerMetadata metadata = new JavaxWebSocketFrameHandlerMetadata(endpointConfig, components);
return discoverJavaxFrameHandlerMetadata(endpointClass, metadata);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -66,6 +66,11 @@ public DecoratedObjectFactory getObjectFactory()
return components.getObjectFactory();
}

public WebSocketComponents getWebSocketComponents()
{
return components;
}

public long getDefaultAsyncSendTimeout()
{
return defaultCustomizer.getWriteTimeout().toMillis();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,7 @@

import org.eclipse.jetty.http.pathmap.UriTemplatePathSpec;
import org.eclipse.jetty.websocket.core.CoreSession;
import org.eclipse.jetty.websocket.core.WebSocketComponents;
import org.eclipse.jetty.websocket.core.exception.InvalidSignatureException;
import org.eclipse.jetty.websocket.core.exception.InvalidWebSocketException;
import org.eclipse.jetty.websocket.core.internal.messages.MessageSink;
Expand Down Expand Up @@ -102,10 +103,12 @@ static InvokerUtils.Arg[] getArgsFor(Class<?> objectType)

protected final JavaxWebSocketContainer container;
protected final InvokerUtils.ParamIdentifier paramIdentifier;
protected final WebSocketComponents components;

public JavaxWebSocketFrameHandlerFactory(JavaxWebSocketContainer container, InvokerUtils.ParamIdentifier paramIdentifier)
{
this.container = container;
this.components = container.getWebSocketComponents();
this.paramIdentifier = paramIdentifier == null ? InvokerUtils.PARAM_IDENTITY : paramIdentifier;
}

Expand Down Expand Up @@ -165,6 +168,9 @@ public JavaxWebSocketFrameHandler newJavaxWebSocketFrameHandler(Object endpointI
errorHandle = InvokerUtils.bindTo(errorHandle, endpoint);
pongHandle = InvokerUtils.bindTo(pongHandle, endpoint);

// Decorate the endpointInstance while we are still upgrading for access to things like HttpSession.
components.getObjectFactory().decorate(endpoint);

return new JavaxWebSocketFrameHandler(
container,
upgradeRequest,
Expand Down Expand Up @@ -248,7 +254,7 @@ private MethodHandle toMethodHandle(MethodHandles.Lookup lookup, Method method)

protected JavaxWebSocketFrameHandlerMetadata createEndpointMetadata(EndpointConfig endpointConfig)
{
JavaxWebSocketFrameHandlerMetadata metadata = new JavaxWebSocketFrameHandlerMetadata(endpointConfig);
JavaxWebSocketFrameHandlerMetadata metadata = new JavaxWebSocketFrameHandlerMetadata(endpointConfig, container.getWebSocketComponents());
MethodHandles.Lookup lookup = getServerMethodHandleLookup();

Method openMethod = ReflectUtils.findMethod(Endpoint.class, "onOpen", Session.class, EndpointConfig.class);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@
import javax.websocket.EndpointConfig;

import org.eclipse.jetty.http.pathmap.UriTemplatePathSpec;
import org.eclipse.jetty.websocket.core.WebSocketComponents;
import org.eclipse.jetty.websocket.core.exception.InvalidWebSocketException;
import org.eclipse.jetty.websocket.javax.common.decoders.AvailableDecoders;
import org.eclipse.jetty.websocket.javax.common.encoders.AvailableEncoders;
Expand Down Expand Up @@ -64,10 +65,10 @@ public class JavaxWebSocketFrameHandlerMetadata
*/
private UriTemplatePathSpec uriTemplatePathSpec;

public JavaxWebSocketFrameHandlerMetadata(EndpointConfig endpointConfig)
public JavaxWebSocketFrameHandlerMetadata(EndpointConfig endpointConfig, WebSocketComponents components)
{
this.availableDecoders = new AvailableDecoders(endpointConfig);
this.availableEncoders = new AvailableEncoders(endpointConfig);
this.availableDecoders = new AvailableDecoders(endpointConfig, components);
this.availableEncoders = new AvailableEncoders(endpointConfig, components);
}

public AvailableDecoders getAvailableDecoders()
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -74,8 +74,8 @@ public JavaxWebSocketSession(JavaxWebSocketContainer container,
this.coreSession = coreSession;
this.frameHandler = frameHandler;
this.sessionId = UUID.randomUUID().toString();
this.availableDecoders = new AvailableDecoders(endpointConfig);
this.availableEncoders = new AvailableEncoders(endpointConfig);
this.availableDecoders = new AvailableDecoders(endpointConfig, container.getWebSocketComponents());
this.availableEncoders = new AvailableEncoders(endpointConfig, container.getWebSocketComponents());

if (endpointConfig instanceof PathParamProvider)
{
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@
import javax.websocket.Decoder;
import javax.websocket.EndpointConfig;

import org.eclipse.jetty.websocket.core.WebSocketComponents;
import org.eclipse.jetty.websocket.core.exception.InvalidSignatureException;
import org.eclipse.jetty.websocket.core.exception.InvalidWebSocketException;
import org.eclipse.jetty.websocket.core.internal.util.ReflectUtils;
Expand All @@ -34,9 +35,12 @@ public class AvailableDecoders implements Iterable<RegisteredDecoder>, Closeable
{
private final List<RegisteredDecoder> registeredDecoders = new ArrayList<>();
private final EndpointConfig config;
private final WebSocketComponents components;

public AvailableDecoders(EndpointConfig config)
public AvailableDecoders(EndpointConfig config, WebSocketComponents components)
{
this.components = Objects.requireNonNull(components);

// Register the Config Based Decoders.
this.config = Objects.requireNonNull(config);
registerAll(config.getDecoders());
Expand Down Expand Up @@ -73,7 +77,7 @@ public AvailableDecoders(EndpointConfig config)

private void registerPrimitive(Class<? extends Decoder> decoderClass, Class<? extends Decoder> interfaceType, Class<?> type)
{
registeredDecoders.add(new RegisteredDecoder(decoderClass, interfaceType, type, config, true));
registeredDecoders.add(new RegisteredDecoder(decoderClass, interfaceType, type, config, components, true));
}

private void register(Class<? extends Decoder> decoder)
Expand Down Expand Up @@ -152,7 +156,7 @@ private void add(Class<? extends Decoder> decoder, Class<? extends Decoder> inte
return;
}

registeredDecoders.add(new RegisteredDecoder(decoder, interfaceClass, objectType, config));
registeredDecoders.add(new RegisteredDecoder(decoder, interfaceClass, objectType, config, components));
}

public RegisteredDecoder getFirstRegisteredDecoder(Class<?> type)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@
import javax.websocket.Decoder;
import javax.websocket.EndpointConfig;

import org.eclipse.jetty.websocket.core.WebSocketComponents;
import org.eclipse.jetty.websocket.javax.common.InitException;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
Expand All @@ -32,21 +33,23 @@ public class RegisteredDecoder
public final Class<?> objectType;
public final boolean primitive;
public final EndpointConfig config;
private final WebSocketComponents components;

private Decoder instance;

public RegisteredDecoder(Class<? extends Decoder> decoder, Class<? extends Decoder> interfaceType, Class<?> objectType, EndpointConfig endpointConfig)
public RegisteredDecoder(Class<? extends Decoder> decoder, Class<? extends Decoder> interfaceType, Class<?> objectType, EndpointConfig endpointConfig, WebSocketComponents components)
{
this(decoder, interfaceType, objectType, endpointConfig, false);
this(decoder, interfaceType, objectType, endpointConfig, components, false);
}

public RegisteredDecoder(Class<? extends Decoder> decoder, Class<? extends Decoder> interfaceType, Class<?> objectType, EndpointConfig endpointConfig, boolean primitive)
public RegisteredDecoder(Class<? extends Decoder> decoder, Class<? extends Decoder> interfaceType, Class<?> objectType, EndpointConfig endpointConfig, WebSocketComponents components, boolean primitive)
{
this.decoder = decoder;
this.interfaceType = interfaceType;
this.objectType = objectType;
this.primitive = primitive;
this.config = endpointConfig;
this.components = components;
}

public boolean implementsInterface(Class<? extends Decoder> type)
Expand All @@ -65,7 +68,7 @@ public <T extends Decoder> T getInstance()
{
try
{
instance = decoder.getConstructor().newInstance();
instance = components.getObjectFactory().createInstance(decoder);
instance.init(config);
return (T)instance;
}
Expand Down

0 comments on commit f828411

Please sign in to comment.