Issue #6106 - Decorate javax.websocket Encoder & Decoders.

Signed-off-by: Lachlan Roberts <lachlan@webtide.com>
This commit is contained in:
Lachlan Roberts 2021-04-06 15:37:07 +10:00
parent ac5eb54e1e
commit a1e522755b
18 changed files with 127 additions and 79 deletions

View File

@ -48,7 +48,7 @@ public class JavaxWebSocketClientFrameHandlerFactory extends JavaxWebSocketFrame
if (endpointClass.getAnnotation(ClientEndpoint.class) == null)
return null;
JavaxWebSocketFrameHandlerMetadata metadata = new JavaxWebSocketFrameHandlerMetadata(endpointConfig);
JavaxWebSocketFrameHandlerMetadata metadata = new JavaxWebSocketFrameHandlerMetadata(endpointConfig, components);
return discoverJavaxFrameHandlerMetadata(endpointClass, metadata);
}
}

View File

@ -66,6 +66,11 @@ public abstract class JavaxWebSocketContainer extends ContainerLifeCycle impleme
return components.getObjectFactory();
}
public WebSocketComponents getWebSocketComponents()
{
return components;
}
public long getDefaultAsyncSendTimeout()
{
return defaultCustomizer.getWriteTimeout().toMillis();

View File

@ -38,6 +38,7 @@ import javax.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 JavaxWebSocketFrameHandlerFactory
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;
}
@ -248,7 +251,7 @@ public abstract class JavaxWebSocketFrameHandlerFactory
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);

View File

@ -18,6 +18,7 @@ import javax.websocket.Encoder;
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;
@ -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()

View File

@ -74,8 +74,8 @@ public class JavaxWebSocketSession implements javax.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, coreSession.getWebSocketComponents());
this.availableEncoders = new AvailableEncoders(endpointConfig, coreSession.getWebSocketComponents());
if (endpointConfig instanceof PathParamProvider)
{

View File

@ -25,6 +25,7 @@ import java.util.stream.Stream;
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;
@ -33,9 +34,12 @@ public class AvailableDecoders implements Iterable<RegisteredDecoder>
{
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());
@ -72,7 +76,7 @@ public class AvailableDecoders implements Iterable<RegisteredDecoder>
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)
@ -151,7 +155,7 @@ public class AvailableDecoders implements Iterable<RegisteredDecoder>
return;
}
registeredDecoders.add(new RegisteredDecoder(decoder, interfaceClass, objectType, config));
registeredDecoders.add(new RegisteredDecoder(decoder, interfaceClass, objectType, config, components));
}
public RegisteredDecoder getFirstRegisteredDecoder(Class<?> type)

View File

@ -17,10 +17,13 @@ import java.lang.reflect.InvocationTargetException;
import javax.websocket.Decoder;
import javax.websocket.EndpointConfig;
import org.eclipse.jetty.websocket.core.WebSocketComponents;
import org.eclipse.jetty.websocket.javax.common.InitException;
public class RegisteredDecoder
{
private final WebSocketComponents components;
// The user supplied Decoder class
public final Class<? extends Decoder> decoder;
// The javax.websocket.Decoder.* type (eg: Decoder.Binary, Decoder.BinaryStream, Decoder.Text, Decoder.TextStream)
@ -31,18 +34,19 @@ public class RegisteredDecoder
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)
@ -61,7 +65,7 @@ public class RegisteredDecoder
{
try
{
instance = decoder.getConstructor().newInstance();
instance = components.getObjectFactory().createInstance(decoder);
instance.init(config);
return (T)instance;
}

View File

@ -24,6 +24,7 @@ import java.util.stream.Collectors;
import javax.websocket.Encoder;
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;
@ -31,62 +32,16 @@ import org.eclipse.jetty.websocket.javax.common.InitException;
public class AvailableEncoders implements Predicate<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);
}
@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);
@ -267,7 +222,7 @@ public class AvailableEncoders implements Predicate<Class<?>>
return registeredEncoder.instance;
}
registeredEncoder.instance = registeredEncoder.encoder.getConstructor().newInstance();
registeredEncoder.instance = components.getObjectFactory().createInstance(registeredEncoder.encoder);
registeredEncoder.instance.init(this.config);
return registeredEncoder.instance;
}

View File

@ -0,0 +1,64 @@
//
// ========================================================================
// 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.javax.common.encoders;
import javax.websocket.Encoder;
public 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);
}
@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();
}
}

View File

@ -19,6 +19,7 @@ import javax.websocket.ClientEndpointConfig;
import javax.websocket.EndpointConfig;
import org.eclipse.jetty.websocket.core.CoreSession;
import org.eclipse.jetty.websocket.core.WebSocketComponents;
import org.eclipse.jetty.websocket.javax.common.decoders.AvailableDecoders;
import org.eclipse.jetty.websocket.javax.common.encoders.AvailableEncoders;
import org.junit.jupiter.api.AfterAll;
@ -46,12 +47,13 @@ public abstract class AbstractJavaxWebSocketFrameHandlerTest
protected Map<String, String> uriParams;
protected EndpointConfig endpointConfig;
protected CoreSession coreSession = new CoreSession.Empty();
private WebSocketComponents components = new WebSocketComponents();
public AbstractJavaxWebSocketFrameHandlerTest()
{
endpointConfig = ClientEndpointConfig.Builder.create().build();
encoders = new AvailableEncoders(endpointConfig);
decoders = new AvailableDecoders(endpointConfig);
encoders = new AvailableEncoders(endpointConfig, components);
decoders = new AvailableDecoders(endpointConfig, components);
uriParams = new HashMap<>();
}

View File

@ -45,7 +45,7 @@ public class DummyFrameHandlerFactory extends JavaxWebSocketFrameHandlerFactory
return null;
}
JavaxWebSocketFrameHandlerMetadata metadata = new JavaxWebSocketFrameHandlerMetadata(endpointConfig);
JavaxWebSocketFrameHandlerMetadata metadata = new JavaxWebSocketFrameHandlerMetadata(endpointConfig, components);
return discoverJavaxFrameHandlerMetadata(endpointClass, metadata);
}
}

View File

@ -20,12 +20,15 @@ import java.util.function.Consumer;
import javax.websocket.ClientEndpointConfig;
import javax.websocket.Decoder;
import org.eclipse.jetty.websocket.core.WebSocketComponents;
import org.eclipse.jetty.websocket.javax.common.AbstractSessionTest;
import org.eclipse.jetty.websocket.javax.common.JavaxWebSocketFrameHandlerFactory;
import org.eclipse.jetty.websocket.javax.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)

View File

@ -159,8 +159,6 @@ public class JavaxWebSocketCreator 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)

View File

@ -43,7 +43,7 @@ public class JavaxWebSocketServerFrameHandlerFactory extends JavaxWebSocketClien
return super.getMetadata(endpointClass, endpointConfig);
UriTemplatePathSpec templatePathSpec = new UriTemplatePathSpec(anno.value());
JavaxWebSocketFrameHandlerMetadata metadata = new JavaxWebSocketFrameHandlerMetadata(endpointConfig);
JavaxWebSocketFrameHandlerMetadata metadata = new JavaxWebSocketFrameHandlerMetadata(endpointConfig, components);
metadata.setUriTemplatePathSpec(templatePathSpec);
return discoverJavaxFrameHandlerMetadata(endpointClass, metadata);
}

View File

@ -26,6 +26,7 @@ import javax.websocket.Decoder;
import javax.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.javax.common.decoders.AvailableDecoders;
import org.eclipse.jetty.websocket.javax.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)

View File

@ -25,6 +25,7 @@ import javax.websocket.Encoder;
import javax.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.javax.client.internal.BasicClientEndpointConfig;
import org.eclipse.jetty.websocket.javax.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
{

View File

@ -28,6 +28,7 @@ import javax.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.javax.common.decoders.RegisteredDecoder;
import org.eclipse.jetty.websocket.javax.common.messages.DecodedTextStreamMessageSink;
import org.eclipse.jetty.websocket.javax.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));
}
}

View File

@ -19,6 +19,7 @@ import javax.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.javax.client.internal.BasicClientEndpointConfig;
import org.eclipse.jetty.websocket.javax.common.decoders.AvailableDecoders;
import org.eclipse.jetty.websocket.javax.common.encoders.AvailableEncoders;
@ -54,12 +55,13 @@ public abstract class AbstractJavaxWebSocketServerFrameHandlerTest
protected AvailableDecoders decoders;
protected Map<String, String> uriParams;
protected EndpointConfig endpointConfig;
private WebSocketComponents components = new WebSocketComponents();
public AbstractJavaxWebSocketServerFrameHandlerTest()
{
endpointConfig = new BasicClientEndpointConfig();
encoders = new AvailableEncoders(endpointConfig);
decoders = new AvailableDecoders(endpointConfig);
encoders = new AvailableEncoders(endpointConfig, components);
decoders = new AvailableDecoders(endpointConfig, components);
uriParams = new HashMap<>();
}
}