Merge remote-tracking branch 'origin/jetty-10.0.x' into jetty-11.0.x
This commit is contained in:
commit
409ad3b100
|
@ -40,6 +40,7 @@ import org.eclipse.jetty.http.HttpVersion;
|
|||
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;
|
||||
|
@ -291,7 +292,12 @@ public abstract class CoreClientUpgradeRequest extends HttpRequest implements Re
|
|||
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));
|
||||
|
@ -306,8 +312,9 @@ public abstract class CoreClientUpgradeRequest extends HttpRequest implements Re
|
|||
}
|
||||
}
|
||||
|
||||
private void notifyUpgradeListeners(Consumer<UpgradeListener> action)
|
||||
private Exception notifyUpgradeListeners(Consumer<UpgradeListener> action)
|
||||
{
|
||||
MultiException multiException = null;
|
||||
for (UpgradeListener listener : upgradeListeners)
|
||||
{
|
||||
try
|
||||
|
@ -317,8 +324,13 @@ public abstract class CoreClientUpgradeRequest extends HttpRequest implements Re
|
|||
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)
|
||||
|
@ -437,7 +449,9 @@ public abstract class CoreClientUpgradeRequest extends HttpRequest implements Re
|
|||
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
|
||||
|
|
|
@ -39,9 +39,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);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -78,7 +78,10 @@ public class WebSocketServerComponents extends WebSocketComponents
|
|||
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.
|
||||
|
|
|
@ -18,17 +18,18 @@ import java.util.List;
|
|||
|
||||
import jakarta.websocket.ClientEndpoint;
|
||||
import jakarta.websocket.ClientEndpointConfig;
|
||||
import org.eclipse.jetty.websocket.core.WebSocketComponents;
|
||||
import org.eclipse.jetty.websocket.core.exception.InvalidWebSocketException;
|
||||
import org.eclipse.jetty.websocket.jakarta.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)
|
||||
{
|
||||
|
|
|
@ -229,9 +229,16 @@ public class JakartaWebSocketClientContainer extends JakartaWebSocketContainer i
|
|||
@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);
|
||||
|
@ -240,6 +247,7 @@ public class JakartaWebSocketClientContainer extends JakartaWebSocketContainer i
|
|||
@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);
|
||||
|
@ -275,7 +283,7 @@ public class JakartaWebSocketClientContainer extends JakartaWebSocketContainer i
|
|||
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
|
||||
|
|
|
@ -47,7 +47,7 @@ public class JakartaWebSocketClientFrameHandlerFactory extends JakartaWebSocketF
|
|||
if (endpointClass.getAnnotation(ClientEndpoint.class) == null)
|
||||
return null;
|
||||
|
||||
JakartaWebSocketFrameHandlerMetadata metadata = new JakartaWebSocketFrameHandlerMetadata(endpointConfig);
|
||||
JakartaWebSocketFrameHandlerMetadata metadata = new JakartaWebSocketFrameHandlerMetadata(endpointConfig, components);
|
||||
return discoverJakartaFrameHandlerMetadata(endpointClass, metadata);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -66,6 +66,11 @@ public abstract class JakartaWebSocketContainer extends ContainerLifeCycle imple
|
|||
return components.getObjectFactory();
|
||||
}
|
||||
|
||||
public WebSocketComponents getWebSocketComponents()
|
||||
{
|
||||
return components;
|
||||
}
|
||||
|
||||
public long getDefaultAsyncSendTimeout()
|
||||
{
|
||||
return defaultCustomizer.getWriteTimeout().toMillis();
|
||||
|
|
|
@ -38,6 +38,7 @@ import jakarta.websocket.PongMessage;
|
|||
import jakarta.websocket.Session;
|
||||
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;
|
||||
|
@ -102,10 +103,12 @@ public abstract class JakartaWebSocketFrameHandlerFactory
|
|||
|
||||
protected final JakartaWebSocketContainer container;
|
||||
protected final InvokerUtils.ParamIdentifier paramIdentifier;
|
||||
protected final WebSocketComponents components;
|
||||
|
||||
public JakartaWebSocketFrameHandlerFactory(JakartaWebSocketContainer container, InvokerUtils.ParamIdentifier paramIdentifier)
|
||||
{
|
||||
this.container = container;
|
||||
this.components = container.getWebSocketComponents();
|
||||
this.paramIdentifier = paramIdentifier == null ? InvokerUtils.PARAM_IDENTITY : paramIdentifier;
|
||||
}
|
||||
|
||||
|
@ -165,6 +168,9 @@ public abstract class JakartaWebSocketFrameHandlerFactory
|
|||
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 JakartaWebSocketFrameHandler(
|
||||
container,
|
||||
upgradeRequest,
|
||||
|
@ -248,7 +254,7 @@ public abstract class JakartaWebSocketFrameHandlerFactory
|
|||
|
||||
protected JakartaWebSocketFrameHandlerMetadata createEndpointMetadata(EndpointConfig endpointConfig)
|
||||
{
|
||||
JakartaWebSocketFrameHandlerMetadata metadata = new JakartaWebSocketFrameHandlerMetadata(endpointConfig);
|
||||
JakartaWebSocketFrameHandlerMetadata metadata = new JakartaWebSocketFrameHandlerMetadata(endpointConfig, container.getWebSocketComponents());
|
||||
MethodHandles.Lookup lookup = getServerMethodHandleLookup();
|
||||
|
||||
Method openMethod = ReflectUtils.findMethod(Endpoint.class, "onOpen", Session.class, EndpointConfig.class);
|
||||
|
|
|
@ -18,6 +18,7 @@ import java.lang.invoke.MethodHandle;
|
|||
import jakarta.websocket.Encoder;
|
||||
import jakarta.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.jakarta.common.decoders.AvailableDecoders;
|
||||
import org.eclipse.jetty.websocket.jakarta.common.encoders.AvailableEncoders;
|
||||
|
@ -64,10 +65,10 @@ public class JakartaWebSocketFrameHandlerMetadata
|
|||
*/
|
||||
private UriTemplatePathSpec uriTemplatePathSpec;
|
||||
|
||||
public JakartaWebSocketFrameHandlerMetadata(EndpointConfig endpointConfig)
|
||||
public JakartaWebSocketFrameHandlerMetadata(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()
|
||||
|
|
|
@ -74,8 +74,8 @@ public class JakartaWebSocketSession implements jakarta.websocket.Session
|
|||
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)
|
||||
{
|
||||
|
|
|
@ -26,6 +26,7 @@ import java.util.stream.Stream;
|
|||
|
||||
import jakarta.websocket.Decoder;
|
||||
import jakarta.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;
|
||||
|
@ -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());
|
||||
|
@ -73,7 +77,7 @@ public class AvailableDecoders implements Iterable<RegisteredDecoder>, Closeable
|
|||
|
||||
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)
|
||||
|
@ -152,7 +156,7 @@ public class AvailableDecoders implements Iterable<RegisteredDecoder>, Closeable
|
|||
return;
|
||||
}
|
||||
|
||||
registeredDecoders.add(new RegisteredDecoder(decoder, interfaceClass, objectType, config));
|
||||
registeredDecoders.add(new RegisteredDecoder(decoder, interfaceClass, objectType, config, components));
|
||||
}
|
||||
|
||||
public RegisteredDecoder getFirstRegisteredDecoder(Class<?> type)
|
||||
|
|
|
@ -17,6 +17,7 @@ import java.lang.reflect.InvocationTargetException;
|
|||
|
||||
import jakarta.websocket.Decoder;
|
||||
import jakarta.websocket.EndpointConfig;
|
||||
import org.eclipse.jetty.websocket.core.WebSocketComponents;
|
||||
import org.eclipse.jetty.websocket.jakarta.common.InitException;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
@ -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)
|
||||
|
@ -65,7 +68,7 @@ public class RegisteredDecoder
|
|||
{
|
||||
try
|
||||
{
|
||||
instance = decoder.getConstructor().newInstance();
|
||||
instance = components.getObjectFactory().createInstance(decoder);
|
||||
instance.init(config);
|
||||
return (T)instance;
|
||||
}
|
||||
|
|
|
@ -25,6 +25,7 @@ import java.util.stream.Collectors;
|
|||
|
||||
import jakarta.websocket.Encoder;
|
||||
import jakarta.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;
|
||||
|
@ -36,79 +37,15 @@ public class AvailableEncoders implements Predicate<Class<?>>, Closeable
|
|||
{
|
||||
private static final Logger LOG = LoggerFactory.getLogger(AvailableEncoders.class);
|
||||
|
||||
public static class RegisteredEncoder
|
||||
{
|
||||
public final Class<? extends Encoder> encoder;
|
||||
public final Class<? extends Encoder> interfaceType;
|
||||
public final Class<?> objectType;
|
||||
public final boolean primitive;
|
||||
public Encoder instance;
|
||||
|
||||
public RegisteredEncoder(Class<? extends Encoder> encoder, Class<? extends Encoder> interfaceType, Class<?> objectType)
|
||||
{
|
||||
this(encoder, interfaceType, objectType, false);
|
||||
}
|
||||
|
||||
public RegisteredEncoder(Class<? extends Encoder> encoder, Class<? extends Encoder> interfaceType, Class<?> objectType, boolean primitive)
|
||||
{
|
||||
this.encoder = encoder;
|
||||
this.interfaceType = interfaceType;
|
||||
this.objectType = objectType;
|
||||
this.primitive = primitive;
|
||||
}
|
||||
|
||||
public boolean implementsInterface(Class<? extends Encoder> type)
|
||||
{
|
||||
return interfaceType.isAssignableFrom(type);
|
||||
}
|
||||
|
||||
public boolean isType(Class<?> type)
|
||||
{
|
||||
return objectType.isAssignableFrom(type);
|
||||
}
|
||||
|
||||
public void destroyInstance()
|
||||
{
|
||||
if (instance != null)
|
||||
{
|
||||
try
|
||||
{
|
||||
instance.destroy();
|
||||
}
|
||||
catch (Throwable t)
|
||||
{
|
||||
LOG.warn("Error destroying Decoder", t);
|
||||
}
|
||||
|
||||
instance = null;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString()
|
||||
{
|
||||
StringBuilder str = new StringBuilder();
|
||||
str.append(AvailableEncoders.RegisteredEncoder.class.getSimpleName());
|
||||
str.append('[').append(encoder.getName());
|
||||
str.append(',').append(interfaceType.getName());
|
||||
str.append(',').append(objectType.getName());
|
||||
if (primitive)
|
||||
{
|
||||
str.append(",PRIMITIVE");
|
||||
}
|
||||
str.append(']');
|
||||
return str.toString();
|
||||
}
|
||||
}
|
||||
|
||||
private final EndpointConfig config;
|
||||
private LinkedList<RegisteredEncoder> registeredEncoders;
|
||||
private final WebSocketComponents components;
|
||||
private final LinkedList<RegisteredEncoder> registeredEncoders;
|
||||
|
||||
public AvailableEncoders(EndpointConfig config)
|
||||
public AvailableEncoders(EndpointConfig config, WebSocketComponents components)
|
||||
{
|
||||
Objects.requireNonNull(config);
|
||||
this.config = config;
|
||||
registeredEncoders = new LinkedList<>();
|
||||
this.config = Objects.requireNonNull(config);
|
||||
this.components = Objects.requireNonNull(components);
|
||||
this.registeredEncoders = new LinkedList<>();
|
||||
|
||||
// TEXT based [via Class reference]
|
||||
registerPrimitive(BooleanEncoder.class, Encoder.Text.class, Boolean.class);
|
||||
|
@ -289,7 +226,7 @@ public class AvailableEncoders implements Predicate<Class<?>>, Closeable
|
|||
return registeredEncoder.instance;
|
||||
}
|
||||
|
||||
registeredEncoder.instance = registeredEncoder.encoder.getConstructor().newInstance();
|
||||
registeredEncoder.instance = components.getObjectFactory().createInstance(registeredEncoder.encoder);
|
||||
registeredEncoder.instance.init(this.config);
|
||||
return registeredEncoder.instance;
|
||||
}
|
||||
|
|
|
@ -0,0 +1,85 @@
|
|||
//
|
||||
// ========================================================================
|
||||
// Copyright (c) 1995-2021 Mort Bay Consulting Pty Ltd and others.
|
||||
//
|
||||
// This program and the accompanying materials are made available under the
|
||||
// terms of the Eclipse Public License v. 2.0 which is available at
|
||||
// https://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0
|
||||
// which is available at https://www.apache.org/licenses/LICENSE-2.0.
|
||||
//
|
||||
// SPDX-License-Identifier: EPL-2.0 OR Apache-2.0
|
||||
// ========================================================================
|
||||
//
|
||||
|
||||
package org.eclipse.jetty.websocket.jakarta.common.encoders;
|
||||
|
||||
import jakarta.websocket.Encoder;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
public class RegisteredEncoder
|
||||
{
|
||||
private static final Logger LOG = LoggerFactory.getLogger(RegisteredEncoder.class);
|
||||
|
||||
public final Class<? extends Encoder> encoder;
|
||||
public final Class<? extends Encoder> interfaceType;
|
||||
public final Class<?> objectType;
|
||||
public final boolean primitive;
|
||||
public Encoder instance;
|
||||
|
||||
public RegisteredEncoder(Class<? extends Encoder> encoder, Class<? extends Encoder> interfaceType, Class<?> objectType)
|
||||
{
|
||||
this(encoder, interfaceType, objectType, false);
|
||||
}
|
||||
|
||||
public RegisteredEncoder(Class<? extends Encoder> encoder, Class<? extends Encoder> interfaceType, Class<?> objectType, boolean primitive)
|
||||
{
|
||||
this.encoder = encoder;
|
||||
this.interfaceType = interfaceType;
|
||||
this.objectType = objectType;
|
||||
this.primitive = primitive;
|
||||
}
|
||||
|
||||
public boolean implementsInterface(Class<? extends Encoder> type)
|
||||
{
|
||||
return interfaceType.isAssignableFrom(type);
|
||||
}
|
||||
|
||||
public boolean isType(Class<?> type)
|
||||
{
|
||||
return objectType.isAssignableFrom(type);
|
||||
}
|
||||
|
||||
public void destroyInstance()
|
||||
{
|
||||
if (instance != null)
|
||||
{
|
||||
try
|
||||
{
|
||||
instance.destroy();
|
||||
}
|
||||
catch (Throwable t)
|
||||
{
|
||||
LOG.warn("Error destroying Decoder", t);
|
||||
}
|
||||
|
||||
instance = null;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString()
|
||||
{
|
||||
StringBuilder str = new StringBuilder();
|
||||
str.append(RegisteredEncoder.class.getSimpleName());
|
||||
str.append('[').append(encoder.getName());
|
||||
str.append(',').append(interfaceType.getName());
|
||||
str.append(',').append(objectType.getName());
|
||||
if (primitive)
|
||||
{
|
||||
str.append(",PRIMITIVE");
|
||||
}
|
||||
str.append(']');
|
||||
return str.toString();
|
||||
}
|
||||
}
|
|
@ -19,6 +19,7 @@ import java.util.Map;
|
|||
import jakarta.websocket.ClientEndpointConfig;
|
||||
import jakarta.websocket.EndpointConfig;
|
||||
import org.eclipse.jetty.websocket.core.CoreSession;
|
||||
import org.eclipse.jetty.websocket.core.WebSocketComponents;
|
||||
import org.eclipse.jetty.websocket.jakarta.common.decoders.AvailableDecoders;
|
||||
import org.eclipse.jetty.websocket.jakarta.common.encoders.AvailableEncoders;
|
||||
import org.junit.jupiter.api.AfterAll;
|
||||
|
@ -45,13 +46,22 @@ public abstract class AbstractJakartaWebSocketFrameHandlerTest
|
|||
protected AvailableDecoders decoders;
|
||||
protected Map<String, String> uriParams;
|
||||
protected EndpointConfig endpointConfig;
|
||||
protected CoreSession coreSession = new CoreSession.Empty();
|
||||
protected CoreSession coreSession = new CoreSession.Empty()
|
||||
{
|
||||
private final WebSocketComponents components = new WebSocketComponents();
|
||||
|
||||
@Override
|
||||
public WebSocketComponents getWebSocketComponents()
|
||||
{
|
||||
return components;
|
||||
}
|
||||
};
|
||||
|
||||
public AbstractJakartaWebSocketFrameHandlerTest()
|
||||
{
|
||||
endpointConfig = ClientEndpointConfig.Builder.create().build();
|
||||
encoders = new AvailableEncoders(endpointConfig);
|
||||
decoders = new AvailableDecoders(endpointConfig);
|
||||
encoders = new AvailableEncoders(endpointConfig, coreSession.getWebSocketComponents());
|
||||
decoders = new AvailableDecoders(endpointConfig, coreSession.getWebSocketComponents());
|
||||
uriParams = new HashMap<>();
|
||||
}
|
||||
|
||||
|
|
|
@ -44,7 +44,7 @@ public class DummyFrameHandlerFactory extends JakartaWebSocketFrameHandlerFactor
|
|||
return null;
|
||||
}
|
||||
|
||||
JakartaWebSocketFrameHandlerMetadata metadata = new JakartaWebSocketFrameHandlerMetadata(endpointConfig);
|
||||
JakartaWebSocketFrameHandlerMetadata metadata = new JakartaWebSocketFrameHandlerMetadata(endpointConfig, components);
|
||||
return discoverJakartaFrameHandlerMetadata(endpointClass, metadata);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -20,12 +20,15 @@ import java.util.function.Consumer;
|
|||
|
||||
import jakarta.websocket.ClientEndpointConfig;
|
||||
import jakarta.websocket.Decoder;
|
||||
import org.eclipse.jetty.websocket.core.WebSocketComponents;
|
||||
import org.eclipse.jetty.websocket.jakarta.common.AbstractSessionTest;
|
||||
import org.eclipse.jetty.websocket.jakarta.common.JakartaWebSocketFrameHandlerFactory;
|
||||
import org.eclipse.jetty.websocket.jakarta.common.decoders.RegisteredDecoder;
|
||||
|
||||
public abstract class AbstractMessageSinkTest extends AbstractSessionTest
|
||||
{
|
||||
private final WebSocketComponents _components = new WebSocketComponents();
|
||||
|
||||
public List<RegisteredDecoder> toRegisteredDecoderList(Class<? extends Decoder> clazz, Class<?> objectType)
|
||||
{
|
||||
Class<? extends Decoder> interfaceType;
|
||||
|
@ -40,7 +43,7 @@ public abstract class AbstractMessageSinkTest extends AbstractSessionTest
|
|||
else
|
||||
throw new IllegalStateException();
|
||||
|
||||
return List.of(new RegisteredDecoder(clazz, interfaceType, objectType, ClientEndpointConfig.Builder.create().build()));
|
||||
return List.of(new RegisteredDecoder(clazz, interfaceType, objectType, ClientEndpointConfig.Builder.create().build(), _components));
|
||||
}
|
||||
|
||||
public <T> MethodHandle getAcceptHandle(Consumer<T> copy, Class<T> type)
|
||||
|
|
|
@ -70,9 +70,7 @@ public class AnnotatedServerEndpointConfig extends ServerEndpointConfigWrapper
|
|||
else
|
||||
path = anno.value();
|
||||
|
||||
// Make sure all Configurators obtained are decorated.
|
||||
ServerEndpointConfig.Configurator rawConfigurator = getConfigurator(baseServerConfig, anno);
|
||||
ServerEndpointConfig.Configurator configurator = containerScope.getObjectFactory().decorate(rawConfigurator);
|
||||
ServerEndpointConfig.Configurator configurator = getConfigurator(baseServerConfig, anno, containerScope);
|
||||
|
||||
// Build a ServerEndpointConfig with the Jakarta API builder to wrap.
|
||||
ServerEndpointConfig endpointConfig = ServerEndpointConfig.Builder.create(endpointClass, path)
|
||||
|
@ -90,7 +88,7 @@ public class AnnotatedServerEndpointConfig extends ServerEndpointConfigWrapper
|
|||
init(endpointConfig);
|
||||
}
|
||||
|
||||
private static Configurator getConfigurator(ServerEndpointConfig baseServerConfig, ServerEndpoint anno) throws DeploymentException
|
||||
private static Configurator getConfigurator(ServerEndpointConfig baseServerConfig, ServerEndpoint anno, JakartaWebSocketContainer containerScope) throws DeploymentException
|
||||
{
|
||||
Configurator ret = null;
|
||||
|
||||
|
@ -115,7 +113,7 @@ public class AnnotatedServerEndpointConfig extends ServerEndpointConfigWrapper
|
|||
// Instantiate the provided configurator
|
||||
try
|
||||
{
|
||||
return anno.configurator().getConstructor().newInstance();
|
||||
return containerScope.getObjectFactory().createInstance(anno.configurator());
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
|
|
|
@ -160,8 +160,6 @@ public class JakartaWebSocketCreator implements WebSocketCreator
|
|||
// [JSR] Step 6: create endpoint class
|
||||
Class<?> endpointClass = config.getEndpointClass();
|
||||
Object endpoint = config.getConfigurator().getEndpointInstance(endpointClass);
|
||||
// Do not decorate here (let the Connection and Session start first)
|
||||
// This will allow CDI to see Session for injection into Endpoint classes.
|
||||
return new ConfiguredEndpoint(endpoint, config);
|
||||
}
|
||||
catch (InstantiationException e)
|
||||
|
|
|
@ -233,6 +233,9 @@ public class JakartaWebSocketServerContainer extends JakartaWebSocketClientConta
|
|||
|
||||
if (isStarted() || isStarting())
|
||||
{
|
||||
// Decorate the provided Configurator.
|
||||
components.getObjectFactory().decorate(providedConfig.getConfigurator());
|
||||
|
||||
// If we have annotations merge the annotated ServerEndpointConfig with the provided one.
|
||||
Class<?> endpointClass = providedConfig.getEndpointClass();
|
||||
ServerEndpoint anno = endpointClass.getAnnotation(ServerEndpoint.class);
|
||||
|
|
|
@ -42,7 +42,7 @@ public class JakartaWebSocketServerFrameHandlerFactory extends JakartaWebSocketC
|
|||
return super.getMetadata(endpointClass, endpointConfig);
|
||||
|
||||
UriTemplatePathSpec templatePathSpec = new UriTemplatePathSpec(anno.value());
|
||||
JakartaWebSocketFrameHandlerMetadata metadata = new JakartaWebSocketFrameHandlerMetadata(endpointConfig);
|
||||
JakartaWebSocketFrameHandlerMetadata metadata = new JakartaWebSocketFrameHandlerMetadata(endpointConfig, components);
|
||||
metadata.setUriTemplatePathSpec(templatePathSpec);
|
||||
return discoverJakartaFrameHandlerMetadata(endpointClass, metadata);
|
||||
}
|
||||
|
|
|
@ -26,6 +26,7 @@ import jakarta.websocket.DecodeException;
|
|||
import jakarta.websocket.Decoder;
|
||||
import jakarta.websocket.EndpointConfig;
|
||||
import org.eclipse.jetty.toolchain.test.Hex;
|
||||
import org.eclipse.jetty.websocket.core.WebSocketComponents;
|
||||
import org.eclipse.jetty.websocket.core.exception.InvalidWebSocketException;
|
||||
import org.eclipse.jetty.websocket.jakarta.common.decoders.AvailableDecoders;
|
||||
import org.eclipse.jetty.websocket.jakarta.common.decoders.IntegerDecoder;
|
||||
|
@ -42,6 +43,7 @@ import static org.junit.jupiter.api.Assertions.assertThrows;
|
|||
public class AvailableDecodersTest
|
||||
{
|
||||
private AvailableDecoders availableDecoders;
|
||||
private WebSocketComponents components = new WebSocketComponents();
|
||||
|
||||
@SafeVarargs
|
||||
public final void init(Class<? extends Decoder>... decoder)
|
||||
|
@ -49,7 +51,7 @@ public class AvailableDecodersTest
|
|||
EndpointConfig testConfig = ClientEndpointConfig.Builder.create()
|
||||
.decoders(Arrays.asList(decoder))
|
||||
.build();
|
||||
this.availableDecoders = new AvailableDecoders(testConfig);
|
||||
this.availableDecoders = new AvailableDecoders(testConfig, components);
|
||||
}
|
||||
|
||||
public <T extends Decoder> T getInstanceFor(Class<?> type)
|
||||
|
|
|
@ -25,6 +25,7 @@ import jakarta.websocket.EncodeException;
|
|||
import jakarta.websocket.Encoder;
|
||||
import jakarta.websocket.EndpointConfig;
|
||||
import org.eclipse.jetty.toolchain.test.Hex;
|
||||
import org.eclipse.jetty.websocket.core.WebSocketComponents;
|
||||
import org.eclipse.jetty.websocket.core.exception.InvalidWebSocketException;
|
||||
import org.eclipse.jetty.websocket.jakarta.client.internal.BasicClientEndpointConfig;
|
||||
import org.eclipse.jetty.websocket.jakarta.common.encoders.AvailableEncoders;
|
||||
|
@ -41,6 +42,7 @@ import static org.junit.jupiter.api.Assertions.assertThrows;
|
|||
public class AvailableEncodersTest
|
||||
{
|
||||
private static EndpointConfig testConfig;
|
||||
private final WebSocketComponents components = new WebSocketComponents();
|
||||
|
||||
@BeforeAll
|
||||
public static void initConfig()
|
||||
|
@ -48,7 +50,7 @@ public class AvailableEncodersTest
|
|||
testConfig = new BasicClientEndpointConfig();
|
||||
}
|
||||
|
||||
private AvailableEncoders encoders = new AvailableEncoders(testConfig);
|
||||
private final AvailableEncoders encoders = new AvailableEncoders(testConfig, components);
|
||||
|
||||
public <T> void assertTextEncoder(Class<T> type, T value, String expectedEncoded) throws IllegalAccessException, InstantiationException, EncodeException
|
||||
{
|
||||
|
|
|
@ -28,6 +28,7 @@ import jakarta.websocket.Decoder;
|
|||
import org.eclipse.jetty.toolchain.test.MavenTestingUtils;
|
||||
import org.eclipse.jetty.util.FutureCallback;
|
||||
import org.eclipse.jetty.websocket.core.Frame;
|
||||
import org.eclipse.jetty.websocket.core.WebSocketComponents;
|
||||
import org.eclipse.jetty.websocket.jakarta.common.decoders.RegisteredDecoder;
|
||||
import org.eclipse.jetty.websocket.jakarta.common.messages.DecodedTextStreamMessageSink;
|
||||
import org.eclipse.jetty.websocket.jakarta.tests.FunctionMethod;
|
||||
|
@ -43,6 +44,8 @@ import static org.hamcrest.Matchers.notNullValue;
|
|||
*/
|
||||
public class DecoderTextStreamTest extends AbstractClientSessionTest
|
||||
{
|
||||
private final WebSocketComponents _components = new WebSocketComponents();
|
||||
|
||||
@Test
|
||||
public void testQuotesDecoderDirect() throws Exception
|
||||
{
|
||||
|
@ -119,6 +122,6 @@ public class DecoderTextStreamTest extends AbstractClientSessionTest
|
|||
else
|
||||
throw new IllegalStateException();
|
||||
|
||||
return List.of(new RegisteredDecoder(clazz, interfaceType, objectType, ClientEndpointConfig.Builder.create().build()));
|
||||
return List.of(new RegisteredDecoder(clazz, interfaceType, objectType, ClientEndpointConfig.Builder.create().build(), _components));
|
||||
}
|
||||
}
|
||||
|
|
|
@ -19,6 +19,7 @@ import java.util.Map;
|
|||
import jakarta.websocket.EndpointConfig;
|
||||
import org.eclipse.jetty.server.Server;
|
||||
import org.eclipse.jetty.servlet.ServletContextHandler;
|
||||
import org.eclipse.jetty.websocket.core.WebSocketComponents;
|
||||
import org.eclipse.jetty.websocket.jakarta.client.internal.BasicClientEndpointConfig;
|
||||
import org.eclipse.jetty.websocket.jakarta.common.decoders.AvailableDecoders;
|
||||
import org.eclipse.jetty.websocket.jakarta.common.encoders.AvailableEncoders;
|
||||
|
@ -54,12 +55,13 @@ public abstract class AbstractJakartaWebSocketServerFrameHandlerTest
|
|||
protected AvailableDecoders decoders;
|
||||
protected Map<String, String> uriParams;
|
||||
protected EndpointConfig endpointConfig;
|
||||
private WebSocketComponents components = new WebSocketComponents();
|
||||
|
||||
public AbstractJakartaWebSocketServerFrameHandlerTest()
|
||||
{
|
||||
endpointConfig = new BasicClientEndpointConfig();
|
||||
encoders = new AvailableEncoders(endpointConfig);
|
||||
decoders = new AvailableDecoders(endpointConfig);
|
||||
encoders = new AvailableEncoders(endpointConfig, components);
|
||||
decoders = new AvailableDecoders(endpointConfig, components);
|
||||
uriParams = new HashMap<>();
|
||||
}
|
||||
}
|
||||
|
|
|
@ -89,7 +89,7 @@ public class WebSocketClient extends ContainerLifeCycle implements WebSocketPoli
|
|||
if (httpClient == null)
|
||||
coreClient.getHttpClient().setName("Jetty-WebSocketClient@" + hashCode());
|
||||
|
||||
frameHandlerFactory = new JettyWebSocketFrameHandlerFactory(this);
|
||||
frameHandlerFactory = new JettyWebSocketFrameHandlerFactory(this, components);
|
||||
sessionListeners.add(sessionTracker);
|
||||
addBean(sessionTracker);
|
||||
}
|
||||
|
|
|
@ -46,6 +46,7 @@ import org.eclipse.jetty.websocket.api.annotations.OnWebSocketFrame;
|
|||
import org.eclipse.jetty.websocket.api.annotations.OnWebSocketMessage;
|
||||
import org.eclipse.jetty.websocket.api.annotations.WebSocket;
|
||||
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.ByteArrayMessageSink;
|
||||
|
@ -78,11 +79,18 @@ import org.eclipse.jetty.websocket.core.internal.util.ReflectUtils;
|
|||
public class JettyWebSocketFrameHandlerFactory extends ContainerLifeCycle
|
||||
{
|
||||
private final WebSocketContainer container;
|
||||
private Map<Class<?>, JettyWebSocketFrameHandlerMetadata> metadataMap = new ConcurrentHashMap<>();
|
||||
private final WebSocketComponents components;
|
||||
private final Map<Class<?>, JettyWebSocketFrameHandlerMetadata> metadataMap = new ConcurrentHashMap<>();
|
||||
|
||||
public JettyWebSocketFrameHandlerFactory(WebSocketContainer container)
|
||||
public JettyWebSocketFrameHandlerFactory(WebSocketContainer container, WebSocketComponents components)
|
||||
{
|
||||
this.container = container;
|
||||
this.components = components;
|
||||
}
|
||||
|
||||
public WebSocketComponents getWebSocketComponents()
|
||||
{
|
||||
return components;
|
||||
}
|
||||
|
||||
public JettyWebSocketFrameHandlerMetadata getMetadata(Class<?> endpointClass)
|
||||
|
@ -130,6 +138,9 @@ public class JettyWebSocketFrameHandlerFactory extends ContainerLifeCycle
|
|||
final MethodHandle pongHandle = InvokerUtils.bindTo(metadata.getPongHandle(), endpointInstance);
|
||||
BatchMode batchMode = metadata.getBatchMode();
|
||||
|
||||
// Decorate the endpointInstance while we are still upgrading for access to things like HttpSession.
|
||||
components.getObjectFactory().decorate(endpointInstance);
|
||||
|
||||
return new JettyWebSocketFrameHandler(
|
||||
container,
|
||||
endpointInstance,
|
||||
|
|
|
@ -32,6 +32,7 @@ import org.eclipse.jetty.websocket.core.CloseStatus;
|
|||
import org.eclipse.jetty.websocket.core.CoreSession;
|
||||
import org.eclipse.jetty.websocket.core.Frame;
|
||||
import org.eclipse.jetty.websocket.core.OpCode;
|
||||
import org.eclipse.jetty.websocket.core.WebSocketComponents;
|
||||
import org.junit.jupiter.api.AfterAll;
|
||||
import org.junit.jupiter.api.BeforeAll;
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
@ -39,6 +40,7 @@ import org.junit.jupiter.api.Test;
|
|||
import static org.hamcrest.MatcherAssert.assertThat;
|
||||
import static org.hamcrest.Matchers.notNullValue;
|
||||
import static org.junit.jupiter.api.Assertions.assertTimeout;
|
||||
import static org.junit.jupiter.api.Assertions.assertTrue;
|
||||
|
||||
public class JettyWebSocketFrameHandlerTest
|
||||
{
|
||||
|
@ -57,20 +59,26 @@ public class JettyWebSocketFrameHandlerTest
|
|||
container.stop();
|
||||
}
|
||||
|
||||
private JettyWebSocketFrameHandlerFactory endpointFactory = new JettyWebSocketFrameHandlerFactory(container);
|
||||
private CoreSession coreSession = new CoreSession.Empty()
|
||||
private final WebSocketComponents components = new WebSocketComponents();
|
||||
private final JettyWebSocketFrameHandlerFactory endpointFactory = new JettyWebSocketFrameHandlerFactory(container, components);
|
||||
private final CoreSession coreSession = new CoreSession.Empty()
|
||||
{
|
||||
@Override
|
||||
public Behavior getBehavior()
|
||||
{
|
||||
return Behavior.CLIENT;
|
||||
}
|
||||
|
||||
@Override
|
||||
public WebSocketComponents getWebSocketComponents()
|
||||
{
|
||||
return components;
|
||||
}
|
||||
};
|
||||
|
||||
private JettyWebSocketFrameHandler newLocalFrameHandler(Object wsEndpoint)
|
||||
{
|
||||
JettyWebSocketFrameHandler localEndpoint = endpointFactory.newJettyFrameHandler(wsEndpoint);
|
||||
return localEndpoint;
|
||||
return endpointFactory.newJettyFrameHandler(wsEndpoint);
|
||||
}
|
||||
|
||||
public static class ConnectionOnly implements WebSocketConnectionListener
|
||||
|
@ -97,7 +105,7 @@ public class JettyWebSocketFrameHandlerTest
|
|||
}
|
||||
|
||||
@Test
|
||||
public void testConnectionListener() throws Exception
|
||||
public void testConnectionListener()
|
||||
{
|
||||
ConnectionOnly socket = new ConnectionOnly();
|
||||
JettyWebSocketFrameHandler localEndpoint = newLocalFrameHandler(socket);
|
||||
|
@ -138,7 +146,7 @@ public class JettyWebSocketFrameHandlerTest
|
|||
}
|
||||
|
||||
@Test
|
||||
public void testAnnotatedStreamedTextSingle() throws Exception
|
||||
public void testAnnotatedStreamedTextSingle()
|
||||
{
|
||||
assertTimeout(Duration.ofMillis(1000), () ->
|
||||
{
|
||||
|
@ -160,7 +168,7 @@ public class JettyWebSocketFrameHandlerTest
|
|||
}
|
||||
|
||||
@Test
|
||||
public void testAnnotatedStreamedTextMultipleParts() throws Exception
|
||||
public void testAnnotatedStreamedTextMultipleParts()
|
||||
{
|
||||
assertTimeout(Duration.ofMillis(1000), () ->
|
||||
{
|
||||
|
@ -177,7 +185,7 @@ public class JettyWebSocketFrameHandlerTest
|
|||
localEndpoint.onFrame(CloseStatus.toFrame(StatusCode.NORMAL, "Normal"), Callback.NOOP);
|
||||
|
||||
// Await completion (of threads)
|
||||
socket.streamLatch.await(2, TimeUnit.SECONDS);
|
||||
assertTrue(socket.streamLatch.await(2, TimeUnit.SECONDS));
|
||||
|
||||
// Validate Events
|
||||
socket.events.assertEvents("onTextStream\\(Hello World\\)");
|
||||
|
@ -185,7 +193,7 @@ public class JettyWebSocketFrameHandlerTest
|
|||
}
|
||||
|
||||
@Test
|
||||
public void testListenerPartialSocket() throws Exception
|
||||
public void testListenerPartialSocket()
|
||||
{
|
||||
// Setup
|
||||
EndPoints.ListenerPartialSocket socket = new EndPoints.ListenerPartialSocket();
|
||||
|
@ -216,7 +224,7 @@ public class JettyWebSocketFrameHandlerTest
|
|||
}
|
||||
|
||||
@Test
|
||||
public void testListenerBasicSocket() throws Exception
|
||||
public void testListenerBasicSocket()
|
||||
{
|
||||
// Setup
|
||||
EndPoints.ListenerBasicSocket socket = new EndPoints.ListenerBasicSocket();
|
||||
|
@ -242,7 +250,7 @@ public class JettyWebSocketFrameHandlerTest
|
|||
}
|
||||
|
||||
@Test
|
||||
public void testListenerBasicSocketError() throws Exception
|
||||
public void testListenerBasicSocketError()
|
||||
{
|
||||
// Setup
|
||||
EndPoints.ListenerBasicSocket socket = new EndPoints.ListenerBasicSocket();
|
||||
|
@ -262,7 +270,7 @@ public class JettyWebSocketFrameHandlerTest
|
|||
}
|
||||
|
||||
@Test
|
||||
public void testListenerFrameSocket() throws Exception
|
||||
public void testListenerFrameSocket()
|
||||
{
|
||||
// Setup
|
||||
EndPoints.ListenerFrameSocket socket = new EndPoints.ListenerFrameSocket();
|
||||
|
@ -292,7 +300,7 @@ public class JettyWebSocketFrameHandlerTest
|
|||
}
|
||||
|
||||
@Test
|
||||
public void testListenerPingPongSocket() throws Exception
|
||||
public void testListenerPingPongSocket()
|
||||
{
|
||||
// Setup
|
||||
EndPoints.ListenerPingPongSocket socket = new EndPoints.ListenerPingPongSocket();
|
||||
|
|
|
@ -14,6 +14,7 @@
|
|||
package org.eclipse.jetty.websocket.common;
|
||||
|
||||
import org.eclipse.jetty.websocket.api.exceptions.InvalidWebSocketException;
|
||||
import org.eclipse.jetty.websocket.core.WebSocketComponents;
|
||||
import org.eclipse.jetty.websocket.core.exception.DuplicateAnnotationException;
|
||||
import org.eclipse.jetty.websocket.core.exception.InvalidSignatureException;
|
||||
import org.eclipse.jetty.websocket.core.internal.messages.ByteArrayMessageSink;
|
||||
|
@ -51,7 +52,8 @@ public class LocalEndpointMetadataTest
|
|||
container.stop();
|
||||
}
|
||||
|
||||
private JettyWebSocketFrameHandlerFactory endpointFactory = new JettyWebSocketFrameHandlerFactory(container);
|
||||
private final WebSocketComponents components = new WebSocketComponents();
|
||||
private final JettyWebSocketFrameHandlerFactory endpointFactory = new JettyWebSocketFrameHandlerFactory(container, components);
|
||||
|
||||
private JettyWebSocketFrameHandlerMetadata createMetadata(Class<?> endpointClass)
|
||||
{
|
||||
|
|
|
@ -110,7 +110,7 @@ public class JettyWebSocketServerContainer extends ContainerLifeCycle implements
|
|||
this.webSocketMappings = webSocketMappings;
|
||||
this.components = components;
|
||||
this.executor = executor;
|
||||
this.frameHandlerFactory = new JettyServerFrameHandlerFactory(this);
|
||||
this.frameHandlerFactory = new JettyServerFrameHandlerFactory(this, components);
|
||||
addBean(frameHandlerFactory);
|
||||
|
||||
addSessionListener(sessionTracker);
|
||||
|
|
|
@ -14,10 +14,10 @@
|
|||
package org.eclipse.jetty.websocket.server.internal;
|
||||
|
||||
import jakarta.servlet.ServletContext;
|
||||
import org.eclipse.jetty.websocket.api.WebSocketContainer;
|
||||
import org.eclipse.jetty.websocket.common.JettyWebSocketFrameHandler;
|
||||
import org.eclipse.jetty.websocket.common.JettyWebSocketFrameHandlerFactory;
|
||||
import org.eclipse.jetty.websocket.core.FrameHandler;
|
||||
import org.eclipse.jetty.websocket.core.WebSocketComponents;
|
||||
import org.eclipse.jetty.websocket.core.server.FrameHandlerFactory;
|
||||
import org.eclipse.jetty.websocket.core.server.ServerUpgradeRequest;
|
||||
import org.eclipse.jetty.websocket.core.server.ServerUpgradeResponse;
|
||||
|
@ -31,9 +31,9 @@ public class JettyServerFrameHandlerFactory extends JettyWebSocketFrameHandlerFa
|
|||
return (container == null) ? null : container.getBean(JettyServerFrameHandlerFactory.class);
|
||||
}
|
||||
|
||||
public JettyServerFrameHandlerFactory(WebSocketContainer container)
|
||||
public JettyServerFrameHandlerFactory(JettyWebSocketServerContainer container, WebSocketComponents components)
|
||||
{
|
||||
super(container);
|
||||
super(container, components);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
|
@ -54,6 +54,24 @@
|
|||
<artifactId>jetty-slf4j-impl</artifactId>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.eclipse.jetty.websocket</groupId>
|
||||
<artifactId>websocket-jakarta-server</artifactId>
|
||||
<version>${project.version}</version>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.eclipse.jetty.websocket</groupId>
|
||||
<artifactId>websocket-jetty-server</artifactId>
|
||||
<version>${project.version}</version>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.eclipse.jetty.websocket</groupId>
|
||||
<artifactId>websocket-jetty-client</artifactId>
|
||||
<version>${project.version}</version>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.eclipse.jetty.toolchain</groupId>
|
||||
<artifactId>jetty-test-helper</artifactId>
|
||||
|
|
|
@ -0,0 +1,404 @@
|
|||
//
|
||||
// ========================================================================
|
||||
// Copyright (c) 1995-2021 Mort Bay Consulting Pty Ltd and others.
|
||||
//
|
||||
// This program and the accompanying materials are made available under the
|
||||
// terms of the Eclipse Public License v. 2.0 which is available at
|
||||
// https://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0
|
||||
// which is available at https://www.apache.org/licenses/LICENSE-2.0.
|
||||
//
|
||||
// SPDX-License-Identifier: EPL-2.0 OR Apache-2.0
|
||||
// ========================================================================
|
||||
//
|
||||
|
||||
package org.eclipse.jetty.cdi.tests.websocket;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.net.URI;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.concurrent.CountDownLatch;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
import java.util.logging.Logger;
|
||||
|
||||
import jakarta.inject.Inject;
|
||||
import jakarta.websocket.ClientEndpoint;
|
||||
import jakarta.websocket.ClientEndpointConfig;
|
||||
import jakarta.websocket.CloseReason;
|
||||
import jakarta.websocket.Decoder;
|
||||
import jakarta.websocket.Encoder;
|
||||
import jakarta.websocket.Endpoint;
|
||||
import jakarta.websocket.EndpointConfig;
|
||||
import jakarta.websocket.HandshakeResponse;
|
||||
import jakarta.websocket.MessageHandler;
|
||||
import jakarta.websocket.OnClose;
|
||||
import jakarta.websocket.OnError;
|
||||
import jakarta.websocket.OnMessage;
|
||||
import jakarta.websocket.OnOpen;
|
||||
import jakarta.websocket.Session;
|
||||
import jakarta.websocket.WebSocketContainer;
|
||||
import jakarta.websocket.server.HandshakeRequest;
|
||||
import jakarta.websocket.server.ServerEndpoint;
|
||||
import jakarta.websocket.server.ServerEndpointConfig;
|
||||
import org.eclipse.jetty.cdi.CdiDecoratingListener;
|
||||
import org.eclipse.jetty.cdi.CdiServletContainerInitializer;
|
||||
import org.eclipse.jetty.server.Server;
|
||||
import org.eclipse.jetty.server.ServerConnector;
|
||||
import org.eclipse.jetty.servlet.ServletContextHandler;
|
||||
import org.eclipse.jetty.util.BlockingArrayQueue;
|
||||
import org.eclipse.jetty.util.component.LifeCycle;
|
||||
import org.eclipse.jetty.websocket.core.WebSocketComponents;
|
||||
import org.eclipse.jetty.websocket.core.server.WebSocketServerComponents;
|
||||
import org.eclipse.jetty.websocket.jakarta.client.JakartaWebSocketClientContainerProvider;
|
||||
import org.eclipse.jetty.websocket.jakarta.client.internal.JakartaWebSocketClientContainer;
|
||||
import org.eclipse.jetty.websocket.jakarta.server.config.JakartaWebSocketServletContainerInitializer;
|
||||
import org.eclipse.jetty.websocket.jakarta.server.config.JakartaWebSocketServletContainerInitializer.Configurator;
|
||||
import org.junit.jupiter.api.AfterEach;
|
||||
import org.junit.jupiter.api.BeforeEach;
|
||||
import org.junit.jupiter.api.Disabled;
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
import static org.hamcrest.MatcherAssert.assertThat;
|
||||
import static org.hamcrest.Matchers.containsString;
|
||||
import static org.hamcrest.Matchers.is;
|
||||
import static org.junit.jupiter.api.Assertions.assertTrue;
|
||||
|
||||
public class JavaxWebSocketCdiTest
|
||||
{
|
||||
private Server _server;
|
||||
private WebSocketContainer _client;
|
||||
private ServerConnector _connector;
|
||||
private ServletContextHandler context;
|
||||
|
||||
@BeforeEach
|
||||
public void before()
|
||||
{
|
||||
_server = new Server();
|
||||
_connector = new ServerConnector(_server);
|
||||
_server.addConnector(_connector);
|
||||
|
||||
context = new ServletContextHandler();
|
||||
context.setContextPath("/");
|
||||
|
||||
// Enable Weld + CDI
|
||||
context.setInitParameter(CdiServletContainerInitializer.CDI_INTEGRATION_ATTRIBUTE, CdiDecoratingListener.MODE);
|
||||
context.addServletContainerInitializer(new CdiServletContainerInitializer());
|
||||
context.addServletContainerInitializer(new org.jboss.weld.environment.servlet.EnhancedListener());
|
||||
|
||||
// Add to Server
|
||||
_server.setHandler(context);
|
||||
}
|
||||
|
||||
public void start(Configurator configurator) throws Exception
|
||||
{
|
||||
// Add WebSocket endpoints
|
||||
JakartaWebSocketServletContainerInitializer.configure(context, configurator);
|
||||
|
||||
// Start Server
|
||||
_server.start();
|
||||
|
||||
// Configure the Client with the same DecoratedObjectFactory from the server.
|
||||
WebSocketComponents components = WebSocketServerComponents.getWebSocketComponents(context.getServletContext());
|
||||
_client = new JakartaWebSocketClientContainer(components);
|
||||
LifeCycle.start(_client);
|
||||
}
|
||||
|
||||
@AfterEach
|
||||
public void after() throws Exception
|
||||
{
|
||||
JakartaWebSocketClientContainerProvider.stop(_client);
|
||||
_server.stop();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testAnnotatedEndpoint() throws Exception
|
||||
{
|
||||
start((servletContext, wsContainer) -> wsContainer.addEndpoint(AnnotatedCdiEchoSocket.class));
|
||||
|
||||
// If we can get an echo from the websocket endpoint we know that CDI injection of the logger worked as there was no NPE.
|
||||
AnnotatedCdiClientSocket clientEndpoint = new AnnotatedCdiClientSocket();
|
||||
URI uri = URI.create("ws://localhost:" + _connector.getLocalPort() + "/echo");
|
||||
Session session = _client.connectToServer(clientEndpoint, uri);
|
||||
session.getBasicRemote().sendText("hello world");
|
||||
assertThat(clientEndpoint._textMessages.poll(5, TimeUnit.SECONDS), is("hello world"));
|
||||
session.close();
|
||||
assertTrue(clientEndpoint._closeLatch.await(5, TimeUnit.SECONDS));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testConfiguredEndpoint() throws Exception
|
||||
{
|
||||
ServerEndpointConfig serverEndpointConfig = ServerEndpointConfig.Builder.create(ConfiguredCdiEchoSocket.class, "/echo")
|
||||
.configurator(new ServerConfigurator())
|
||||
.build();
|
||||
start((servletContext, wsContainer) -> wsContainer.addEndpoint(serverEndpointConfig));
|
||||
|
||||
// If we can get an echo from the websocket endpoint we know that CDI injection of the logger worked as there was no NPE.
|
||||
ConfiguredCdiClientSocket clientEndpoint = new ConfiguredCdiClientSocket();
|
||||
ClientEndpointConfig clientEndpointConfig = ClientEndpointConfig.Builder.create()
|
||||
.configurator(new ClientConfigurator())
|
||||
.build();
|
||||
|
||||
URI uri = URI.create("ws://localhost:" + _connector.getLocalPort() + "/echo");
|
||||
Session session = _client.connectToServer(clientEndpoint, clientEndpointConfig, uri);
|
||||
session.getBasicRemote().sendText("hello world");
|
||||
assertThat(clientEndpoint._textMessages.poll(5, TimeUnit.SECONDS), is("hello world"));
|
||||
session.close();
|
||||
assertTrue(clientEndpoint._closeLatch.await(5, TimeUnit.SECONDS));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testEncoderDecoder() throws Exception
|
||||
{
|
||||
start((servletContext, wsContainer) -> wsContainer.addEndpoint(AnnotatedCdiEchoSocket.class));
|
||||
|
||||
// If we can get an echo from the websocket endpoint we know that CDI injection of the logger worked as there was no NPE.
|
||||
AnnotatedEncoderDecoderClientSocket clientEndpoint = new AnnotatedEncoderDecoderClientSocket();
|
||||
URI uri = URI.create("ws://localhost:" + _connector.getLocalPort() + "/echo");
|
||||
Session session = _client.connectToServer(clientEndpoint, uri);
|
||||
session.getBasicRemote().sendObject("hello world");
|
||||
assertThat(clientEndpoint._textMessages.poll(5, TimeUnit.SECONDS), is("decoded(encoded(hello world))"));
|
||||
session.close();
|
||||
assertTrue(clientEndpoint._closeLatch.await(5, TimeUnit.SECONDS));
|
||||
}
|
||||
|
||||
@Test
|
||||
@Disabled("See issue https://github.com/eclipse/jetty.project/issues/6174")
|
||||
public void testHttpSessionInjection() throws Exception
|
||||
{
|
||||
start((servletContext, wsContainer) -> wsContainer.addEndpoint(CdiHttpSessionSocket.class));
|
||||
|
||||
// If we can get an echo from the websocket endpoint we know that CDI injection of the logger worked as there was no NPE.
|
||||
AnnotatedCdiClientSocket clientEndpoint = new AnnotatedCdiClientSocket();
|
||||
URI uri = URI.create("ws://localhost:" + _connector.getLocalPort() + "/echo");
|
||||
Session session = _client.connectToServer(clientEndpoint, uri);
|
||||
session.getBasicRemote().sendObject("hello world");
|
||||
String rcvMessage = clientEndpoint._textMessages.poll(5, TimeUnit.SECONDS);
|
||||
assertThat(rcvMessage, containsString("hello world, SessionID:"));
|
||||
session.close();
|
||||
assertTrue(clientEndpoint._closeLatch.await(5, TimeUnit.SECONDS));
|
||||
}
|
||||
|
||||
public static class ClientConfigurator extends ClientEndpointConfig.Configurator
|
||||
{
|
||||
@Inject
|
||||
public Logger logger;
|
||||
|
||||
@Override
|
||||
public void beforeRequest(Map<String, List<String>> headers)
|
||||
{
|
||||
logger.info("beforeRequest");
|
||||
}
|
||||
}
|
||||
|
||||
public static class ServerConfigurator extends ServerEndpointConfig.Configurator
|
||||
{
|
||||
@Inject
|
||||
public Logger logger;
|
||||
|
||||
@Override
|
||||
public void modifyHandshake(ServerEndpointConfig sec, HandshakeRequest request, HandshakeResponse response)
|
||||
{
|
||||
logger.info("modifyHandshake");
|
||||
}
|
||||
}
|
||||
|
||||
@ClientEndpoint(configurator = ClientConfigurator.class)
|
||||
public static class AnnotatedCdiClientSocket
|
||||
{
|
||||
@Inject
|
||||
public Logger logger;
|
||||
|
||||
BlockingArrayQueue<String> _textMessages = new BlockingArrayQueue<>();
|
||||
CountDownLatch _closeLatch = new CountDownLatch(1);
|
||||
|
||||
@OnOpen
|
||||
public void onOpen(Session session)
|
||||
{
|
||||
logger.info("onOpen: " + session);
|
||||
}
|
||||
|
||||
@OnMessage
|
||||
public void onMessage(String message)
|
||||
{
|
||||
_textMessages.add(message);
|
||||
}
|
||||
|
||||
@OnError
|
||||
public void onError(Throwable t)
|
||||
{
|
||||
t.printStackTrace();
|
||||
}
|
||||
|
||||
@OnClose
|
||||
public void onClose()
|
||||
{
|
||||
_closeLatch.countDown();
|
||||
}
|
||||
}
|
||||
|
||||
@ServerEndpoint(value = "/echo", configurator = ServerConfigurator.class)
|
||||
public static class AnnotatedCdiEchoSocket
|
||||
{
|
||||
@Inject
|
||||
protected Logger logger;
|
||||
protected Session session;
|
||||
|
||||
@OnOpen
|
||||
public void onOpen(Session session)
|
||||
{
|
||||
logger.info("onOpen() session:" + session);
|
||||
this.session = session;
|
||||
}
|
||||
|
||||
@OnMessage
|
||||
public void onMessage(String message) throws IOException
|
||||
{
|
||||
this.session.getBasicRemote().sendText(message);
|
||||
}
|
||||
|
||||
@OnError
|
||||
public void onError(Throwable t)
|
||||
{
|
||||
t.printStackTrace();
|
||||
}
|
||||
}
|
||||
|
||||
public static class ConfiguredCdiClientSocket extends Endpoint implements MessageHandler.Whole<String>
|
||||
{
|
||||
@Inject
|
||||
public Logger logger;
|
||||
|
||||
BlockingArrayQueue<String> _textMessages = new BlockingArrayQueue<>();
|
||||
CountDownLatch _closeLatch = new CountDownLatch(1);
|
||||
|
||||
@Override
|
||||
public void onMessage(String message)
|
||||
{
|
||||
_textMessages.add(message);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onOpen(Session session, EndpointConfig config)
|
||||
{
|
||||
logger.info("onOpen: " + session);
|
||||
session.addMessageHandler(this);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onError(Session session, Throwable thr)
|
||||
{
|
||||
thr.printStackTrace();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onClose(Session session, CloseReason closeReason)
|
||||
{
|
||||
_closeLatch.countDown();
|
||||
}
|
||||
}
|
||||
|
||||
public static class ConfiguredCdiEchoSocket extends Endpoint implements MessageHandler.Whole<String>
|
||||
{
|
||||
@Inject
|
||||
public Logger logger;
|
||||
private Session session;
|
||||
|
||||
@Override
|
||||
public void onMessage(String message)
|
||||
{
|
||||
try
|
||||
{
|
||||
session.getBasicRemote().sendText(message);
|
||||
}
|
||||
catch (IOException e)
|
||||
{
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onOpen(Session session, EndpointConfig config)
|
||||
{
|
||||
logger.info("onOpen() session:" + session);
|
||||
this.session = session;
|
||||
session.addMessageHandler(this);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onError(Session session, Throwable thr)
|
||||
{
|
||||
thr.printStackTrace();
|
||||
}
|
||||
}
|
||||
|
||||
public static class CustomEncoder implements Encoder.Text<String>
|
||||
{
|
||||
@Inject
|
||||
public Logger logger;
|
||||
|
||||
@Override
|
||||
public String encode(String s)
|
||||
{
|
||||
return "encoded(" + s + ")";
|
||||
}
|
||||
|
||||
@Override
|
||||
public void init(EndpointConfig config)
|
||||
{
|
||||
logger.info("init: " + config);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void destroy()
|
||||
{
|
||||
}
|
||||
}
|
||||
|
||||
public static class CustomDecoder implements Decoder.Text<String>
|
||||
{
|
||||
@Inject
|
||||
public Logger logger;
|
||||
|
||||
@Override
|
||||
public String decode(String s)
|
||||
{
|
||||
return "decoded(" + s + ")";
|
||||
}
|
||||
|
||||
@Override
|
||||
public void init(EndpointConfig config)
|
||||
{
|
||||
logger.info("init: " + config);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void destroy()
|
||||
{
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean willDecode(String s)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
@ClientEndpoint(encoders = {CustomEncoder.class}, decoders = {CustomDecoder.class})
|
||||
public static class AnnotatedEncoderDecoderClientSocket extends AnnotatedCdiClientSocket
|
||||
{
|
||||
}
|
||||
|
||||
@ServerEndpoint("/echo")
|
||||
public static class CdiHttpSessionSocket extends AnnotatedCdiEchoSocket
|
||||
{
|
||||
@Inject
|
||||
private jakarta.servlet.http.HttpSession httpSession;
|
||||
|
||||
@Override
|
||||
public void onMessage(String message) throws IOException
|
||||
{
|
||||
session.getBasicRemote().sendText(message + ", SessionID:" + httpSession.getId());
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,153 @@
|
|||
//
|
||||
// ========================================================================
|
||||
// Copyright (c) 1995-2021 Mort Bay Consulting Pty Ltd and others.
|
||||
//
|
||||
// This program and the accompanying materials are made available under the
|
||||
// terms of the Eclipse Public License v. 2.0 which is available at
|
||||
// https://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0
|
||||
// which is available at https://www.apache.org/licenses/LICENSE-2.0.
|
||||
//
|
||||
// SPDX-License-Identifier: EPL-2.0 OR Apache-2.0
|
||||
// ========================================================================
|
||||
//
|
||||
|
||||
package org.eclipse.jetty.cdi.tests.websocket;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.net.URI;
|
||||
import java.util.concurrent.CountDownLatch;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
import java.util.logging.Logger;
|
||||
|
||||
import jakarta.inject.Inject;
|
||||
import org.eclipse.jetty.cdi.CdiDecoratingListener;
|
||||
import org.eclipse.jetty.cdi.CdiServletContainerInitializer;
|
||||
import org.eclipse.jetty.server.Server;
|
||||
import org.eclipse.jetty.server.ServerConnector;
|
||||
import org.eclipse.jetty.servlet.ServletContextHandler;
|
||||
import org.eclipse.jetty.util.BlockingArrayQueue;
|
||||
import org.eclipse.jetty.websocket.api.Session;
|
||||
import org.eclipse.jetty.websocket.api.annotations.OnWebSocketClose;
|
||||
import org.eclipse.jetty.websocket.api.annotations.OnWebSocketConnect;
|
||||
import org.eclipse.jetty.websocket.api.annotations.OnWebSocketError;
|
||||
import org.eclipse.jetty.websocket.api.annotations.OnWebSocketMessage;
|
||||
import org.eclipse.jetty.websocket.api.annotations.WebSocket;
|
||||
import org.eclipse.jetty.websocket.client.WebSocketClient;
|
||||
import org.eclipse.jetty.websocket.server.config.JettyWebSocketServletContainerInitializer;
|
||||
import org.junit.jupiter.api.AfterEach;
|
||||
import org.junit.jupiter.api.BeforeEach;
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
import static org.hamcrest.MatcherAssert.assertThat;
|
||||
import static org.hamcrest.Matchers.is;
|
||||
import static org.junit.jupiter.api.Assertions.assertTrue;
|
||||
|
||||
public class JettyWebSocketCdiTest
|
||||
{
|
||||
private Server _server;
|
||||
private WebSocketClient _client;
|
||||
private ServerConnector _connector;
|
||||
|
||||
@BeforeEach
|
||||
public void before() throws Exception
|
||||
{
|
||||
_server = new Server();
|
||||
_connector = new ServerConnector(_server);
|
||||
_server.addConnector(_connector);
|
||||
|
||||
ServletContextHandler context = new ServletContextHandler();
|
||||
context.setContextPath("/");
|
||||
|
||||
// Enable Weld + CDI
|
||||
context.setInitParameter(CdiServletContainerInitializer.CDI_INTEGRATION_ATTRIBUTE, CdiDecoratingListener.MODE);
|
||||
context.addServletContainerInitializer(new CdiServletContainerInitializer());
|
||||
context.addServletContainerInitializer(new org.jboss.weld.environment.servlet.EnhancedListener());
|
||||
|
||||
// Add WebSocket endpoints
|
||||
JettyWebSocketServletContainerInitializer.configure(context, (servletContext, wsContainer) ->
|
||||
wsContainer.addMapping("/echo", CdiEchoSocket.class));
|
||||
|
||||
// Add to Server
|
||||
_server.setHandler(context);
|
||||
|
||||
// Start Server
|
||||
_server.start();
|
||||
|
||||
_client = new WebSocketClient();
|
||||
_client.start();
|
||||
}
|
||||
|
||||
@AfterEach
|
||||
public void after() throws Exception
|
||||
{
|
||||
_client.stop();
|
||||
_server.stop();
|
||||
}
|
||||
|
||||
@WebSocket
|
||||
public static class TestClientEndpoint
|
||||
{
|
||||
BlockingArrayQueue<String> _textMessages = new BlockingArrayQueue<>();
|
||||
CountDownLatch _closeLatch = new CountDownLatch(1);
|
||||
|
||||
@OnWebSocketMessage
|
||||
public void onMessage(String message)
|
||||
{
|
||||
_textMessages.add(message);
|
||||
}
|
||||
|
||||
@OnWebSocketClose
|
||||
public void onClose()
|
||||
{
|
||||
_closeLatch.countDown();
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testBasicEcho() throws Exception
|
||||
{
|
||||
// If we can get an echo from the websocket endpoint we know that CDI injection of the logger worked as there was no NPE.
|
||||
TestClientEndpoint clientEndpoint = new TestClientEndpoint();
|
||||
URI uri = URI.create("ws://localhost:" + _connector.getLocalPort() + "/echo");
|
||||
Session session = _client.connect(clientEndpoint, uri).get(5, TimeUnit.SECONDS);
|
||||
session.getRemote().sendString("hello world");
|
||||
assertThat(clientEndpoint._textMessages.poll(5, TimeUnit.SECONDS), is("hello world"));
|
||||
session.close();
|
||||
assertTrue(clientEndpoint._closeLatch.await(5, TimeUnit.SECONDS));
|
||||
}
|
||||
|
||||
@WebSocket()
|
||||
public static class CdiEchoSocket
|
||||
{
|
||||
@Inject
|
||||
public Logger logger;
|
||||
|
||||
private Session session;
|
||||
|
||||
@OnWebSocketConnect
|
||||
public void onOpen(Session session)
|
||||
{
|
||||
logger.info("onOpen() session:" + session);
|
||||
this.session = session;
|
||||
}
|
||||
|
||||
@OnWebSocketMessage
|
||||
public void onMessage(String message) throws IOException
|
||||
{
|
||||
this.session.getRemote().sendString(message);
|
||||
}
|
||||
|
||||
@OnWebSocketError
|
||||
public void onError(Throwable t)
|
||||
{
|
||||
t.printStackTrace();
|
||||
}
|
||||
|
||||
@OnWebSocketClose
|
||||
public void onClose(int statusCode, String reason)
|
||||
{
|
||||
logger.info("onClose() close: " + statusCode + ":" + reason);
|
||||
this.session = null;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,30 @@
|
|||
//
|
||||
// ========================================================================
|
||||
// Copyright (c) 1995-2021 Mort Bay Consulting Pty Ltd and others.
|
||||
//
|
||||
// This program and the accompanying materials are made available under the
|
||||
// terms of the Eclipse Public License v. 2.0 which is available at
|
||||
// https://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0
|
||||
// which is available at https://www.apache.org/licenses/LICENSE-2.0.
|
||||
//
|
||||
// SPDX-License-Identifier: EPL-2.0 OR Apache-2.0
|
||||
// ========================================================================
|
||||
//
|
||||
|
||||
package org.eclipse.jetty.cdi.tests.websocket;
|
||||
|
||||
import java.util.logging.Logger;
|
||||
|
||||
import jakarta.enterprise.inject.Default;
|
||||
import jakarta.enterprise.inject.Produces;
|
||||
import jakarta.enterprise.inject.spi.InjectionPoint;
|
||||
|
||||
public class LogFactory
|
||||
{
|
||||
@Produces
|
||||
@Default
|
||||
public Logger createLogger(InjectionPoint injectionPoint)
|
||||
{
|
||||
return Logger.getLogger(injectionPoint.getMember().getDeclaringClass().getName());
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue