Issue #3428 - Initial refactor to support javax websocket decoderLists
Signed-off-by: Lachlan Roberts <lachlan@webtide.com>
This commit is contained in:
parent
aa52d67dbf
commit
4b19c19815
|
@ -49,14 +49,10 @@ public class JavaxWebSocketClientFrameHandlerFactory extends JavaxWebSocketFrame
|
||||||
public JavaxWebSocketFrameHandlerMetadata getMetadata(Class<?> endpointClass, EndpointConfig endpointConfig)
|
public JavaxWebSocketFrameHandlerMetadata getMetadata(Class<?> endpointClass, EndpointConfig endpointConfig)
|
||||||
{
|
{
|
||||||
if (javax.websocket.Endpoint.class.isAssignableFrom(endpointClass))
|
if (javax.websocket.Endpoint.class.isAssignableFrom(endpointClass))
|
||||||
{
|
|
||||||
return createEndpointMetadata((Class<? extends Endpoint>)endpointClass, endpointConfig);
|
return createEndpointMetadata((Class<? extends Endpoint>)endpointClass, endpointConfig);
|
||||||
}
|
|
||||||
|
|
||||||
if (endpointClass.getAnnotation(ClientEndpoint.class) == null)
|
if (endpointClass.getAnnotation(ClientEndpoint.class) == null)
|
||||||
{
|
|
||||||
return null;
|
return null;
|
||||||
}
|
|
||||||
|
|
||||||
JavaxWebSocketFrameHandlerMetadata metadata = new JavaxWebSocketFrameHandlerMetadata(endpointConfig);
|
JavaxWebSocketFrameHandlerMetadata metadata = new JavaxWebSocketFrameHandlerMetadata(endpointConfig);
|
||||||
return discoverJavaxFrameHandlerMetadata(endpointClass, metadata);
|
return discoverJavaxFrameHandlerMetadata(endpointClass, metadata);
|
||||||
|
|
|
@ -0,0 +1,79 @@
|
||||||
|
//
|
||||||
|
// ========================================================================
|
||||||
|
// Copyright (c) 1995-2020 Mort Bay Consulting Pty Ltd and others.
|
||||||
|
//
|
||||||
|
// This program and the accompanying materials are made available under
|
||||||
|
// the terms of the Eclipse Public License 2.0 which is available at
|
||||||
|
// https://www.eclipse.org/legal/epl-2.0
|
||||||
|
//
|
||||||
|
// This Source Code may also be made available under the following
|
||||||
|
// Secondary Licenses when the conditions for such availability set
|
||||||
|
// forth in the Eclipse Public License, v. 2.0 are satisfied:
|
||||||
|
// the Apache License v2.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;
|
||||||
|
|
||||||
|
import java.io.InputStream;
|
||||||
|
import java.io.Reader;
|
||||||
|
import java.nio.ByteBuffer;
|
||||||
|
import javax.websocket.PongMessage;
|
||||||
|
import javax.websocket.Session;
|
||||||
|
|
||||||
|
import org.eclipse.jetty.websocket.util.InvokerUtils;
|
||||||
|
|
||||||
|
// The different kind of @OnMessage method parameter signatures expected.
|
||||||
|
public class JavaxWebSocketCallingArgs
|
||||||
|
{
|
||||||
|
static final InvokerUtils.Arg[] textCallingArgs = new InvokerUtils.Arg[]{
|
||||||
|
new InvokerUtils.Arg(Session.class),
|
||||||
|
new InvokerUtils.Arg(String.class).required()
|
||||||
|
};
|
||||||
|
|
||||||
|
static final InvokerUtils.Arg[] textPartialCallingArgs = new InvokerUtils.Arg[]{
|
||||||
|
new InvokerUtils.Arg(Session.class),
|
||||||
|
new InvokerUtils.Arg(String.class).required(),
|
||||||
|
new InvokerUtils.Arg(boolean.class).required()
|
||||||
|
};
|
||||||
|
|
||||||
|
static final InvokerUtils.Arg[] binaryBufferCallingArgs = new InvokerUtils.Arg[]{
|
||||||
|
new InvokerUtils.Arg(Session.class),
|
||||||
|
new InvokerUtils.Arg(ByteBuffer.class).required()
|
||||||
|
};
|
||||||
|
|
||||||
|
static final InvokerUtils.Arg[] binaryPartialBufferCallingArgs = new InvokerUtils.Arg[]{
|
||||||
|
new InvokerUtils.Arg(Session.class),
|
||||||
|
new InvokerUtils.Arg(ByteBuffer.class).required(),
|
||||||
|
new InvokerUtils.Arg(boolean.class).required()
|
||||||
|
};
|
||||||
|
|
||||||
|
static final InvokerUtils.Arg[] binaryArrayCallingArgs = new InvokerUtils.Arg[]{
|
||||||
|
new InvokerUtils.Arg(Session.class),
|
||||||
|
new InvokerUtils.Arg(byte[].class).required()
|
||||||
|
};
|
||||||
|
|
||||||
|
static final InvokerUtils.Arg[] binaryPartialArrayCallingArgs = new InvokerUtils.Arg[]{
|
||||||
|
new InvokerUtils.Arg(Session.class),
|
||||||
|
new InvokerUtils.Arg(byte[].class).required(),
|
||||||
|
new InvokerUtils.Arg(boolean.class).required()
|
||||||
|
};
|
||||||
|
|
||||||
|
static final InvokerUtils.Arg[] inputStreamCallingArgs = new InvokerUtils.Arg[]{
|
||||||
|
new InvokerUtils.Arg(Session.class),
|
||||||
|
new InvokerUtils.Arg(InputStream.class).required()
|
||||||
|
};
|
||||||
|
|
||||||
|
static final InvokerUtils.Arg[] readerCallingArgs = new InvokerUtils.Arg[]{
|
||||||
|
new InvokerUtils.Arg(Session.class),
|
||||||
|
new InvokerUtils.Arg(Reader.class).required()
|
||||||
|
};
|
||||||
|
|
||||||
|
static final InvokerUtils.Arg[] pongCallingArgs = new InvokerUtils.Arg[]{
|
||||||
|
new InvokerUtils.Arg(Session.class),
|
||||||
|
new InvokerUtils.Arg(PongMessage.class).required()
|
||||||
|
};
|
||||||
|
}
|
|
@ -23,6 +23,7 @@ import java.lang.invoke.MethodHandles;
|
||||||
import java.lang.invoke.MethodType;
|
import java.lang.invoke.MethodType;
|
||||||
import java.nio.ByteBuffer;
|
import java.nio.ByteBuffer;
|
||||||
import java.util.HashMap;
|
import java.util.HashMap;
|
||||||
|
import java.util.List;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
import java.util.Optional;
|
import java.util.Optional;
|
||||||
import java.util.Set;
|
import java.util.Set;
|
||||||
|
@ -46,6 +47,7 @@ import org.eclipse.jetty.websocket.core.OpCode;
|
||||||
import org.eclipse.jetty.websocket.core.exception.ProtocolException;
|
import org.eclipse.jetty.websocket.core.exception.ProtocolException;
|
||||||
import org.eclipse.jetty.websocket.core.exception.WebSocketException;
|
import org.eclipse.jetty.websocket.core.exception.WebSocketException;
|
||||||
import org.eclipse.jetty.websocket.javax.common.decoders.AvailableDecoders;
|
import org.eclipse.jetty.websocket.javax.common.decoders.AvailableDecoders;
|
||||||
|
import org.eclipse.jetty.websocket.javax.common.decoders.RegisteredDecoder;
|
||||||
import org.eclipse.jetty.websocket.javax.common.messages.DecodedBinaryMessageSink;
|
import org.eclipse.jetty.websocket.javax.common.messages.DecodedBinaryMessageSink;
|
||||||
import org.eclipse.jetty.websocket.javax.common.messages.DecodedBinaryStreamMessageSink;
|
import org.eclipse.jetty.websocket.javax.common.messages.DecodedBinaryStreamMessageSink;
|
||||||
import org.eclipse.jetty.websocket.javax.common.messages.DecodedTextMessageSink;
|
import org.eclipse.jetty.websocket.javax.common.messages.DecodedTextMessageSink;
|
||||||
|
@ -95,9 +97,9 @@ public class JavaxWebSocketFrameHandler implements FrameHandler
|
||||||
private MethodHandle openHandle;
|
private MethodHandle openHandle;
|
||||||
private MethodHandle closeHandle;
|
private MethodHandle closeHandle;
|
||||||
private MethodHandle errorHandle;
|
private MethodHandle errorHandle;
|
||||||
private JavaxWebSocketFrameHandlerMetadata.MessageMetadata textMetadata;
|
|
||||||
private JavaxWebSocketFrameHandlerMetadata.MessageMetadata binaryMetadata;
|
|
||||||
private MethodHandle pongHandle;
|
private MethodHandle pongHandle;
|
||||||
|
private JavaxWebSocketMessageMetadata textMetadata;
|
||||||
|
private JavaxWebSocketMessageMetadata binaryMetadata;
|
||||||
|
|
||||||
private UpgradeRequest upgradeRequest;
|
private UpgradeRequest upgradeRequest;
|
||||||
|
|
||||||
|
@ -114,8 +116,8 @@ public class JavaxWebSocketFrameHandler implements FrameHandler
|
||||||
public JavaxWebSocketFrameHandler(JavaxWebSocketContainer container,
|
public JavaxWebSocketFrameHandler(JavaxWebSocketContainer container,
|
||||||
Object endpointInstance,
|
Object endpointInstance,
|
||||||
MethodHandle openHandle, MethodHandle closeHandle, MethodHandle errorHandle,
|
MethodHandle openHandle, MethodHandle closeHandle, MethodHandle errorHandle,
|
||||||
JavaxWebSocketFrameHandlerMetadata.MessageMetadata textMetadata,
|
JavaxWebSocketMessageMetadata textMetadata,
|
||||||
JavaxWebSocketFrameHandlerMetadata.MessageMetadata binaryMetadata,
|
JavaxWebSocketMessageMetadata binaryMetadata,
|
||||||
MethodHandle pongHandle,
|
MethodHandle pongHandle,
|
||||||
EndpointConfig endpointConfig)
|
EndpointConfig endpointConfig)
|
||||||
{
|
{
|
||||||
|
@ -170,26 +172,32 @@ public class JavaxWebSocketFrameHandler implements FrameHandler
|
||||||
errorHandle = InvokerUtils.bindTo(errorHandle, session);
|
errorHandle = InvokerUtils.bindTo(errorHandle, session);
|
||||||
pongHandle = InvokerUtils.bindTo(pongHandle, session);
|
pongHandle = InvokerUtils.bindTo(pongHandle, session);
|
||||||
|
|
||||||
JavaxWebSocketFrameHandlerMetadata.MessageMetadata actualTextMetadata = JavaxWebSocketFrameHandlerMetadata.MessageMetadata.copyOf(textMetadata);
|
JavaxWebSocketMessageMetadata actualTextMetadata = JavaxWebSocketMessageMetadata.copyOf(textMetadata);
|
||||||
if (actualTextMetadata != null)
|
if (actualTextMetadata != null)
|
||||||
{
|
{
|
||||||
if (actualTextMetadata.isMaxMessageSizeSet())
|
if (actualTextMetadata.isMaxMessageSizeSet())
|
||||||
session.setMaxTextMessageBufferSize(actualTextMetadata.maxMessageSize);
|
session.setMaxTextMessageBufferSize(actualTextMetadata.getMaxMessageSize());
|
||||||
|
|
||||||
|
MethodHandle methodHandle = actualTextMetadata.getMethodHandle();
|
||||||
|
methodHandle = InvokerUtils.bindTo(methodHandle, endpointInstance, endpointConfig, session);
|
||||||
|
methodHandle = JavaxWebSocketFrameHandlerFactory.wrapNonVoidReturnType(methodHandle, session);
|
||||||
|
actualTextMetadata.setMethodHandle(methodHandle);
|
||||||
|
|
||||||
actualTextMetadata.handle = InvokerUtils.bindTo(actualTextMetadata.handle, endpointInstance, endpointConfig, session);
|
|
||||||
actualTextMetadata.handle = JavaxWebSocketFrameHandlerFactory.wrapNonVoidReturnType(actualTextMetadata.handle, session);
|
|
||||||
textSink = JavaxWebSocketFrameHandlerFactory.createMessageSink(session, actualTextMetadata);
|
textSink = JavaxWebSocketFrameHandlerFactory.createMessageSink(session, actualTextMetadata);
|
||||||
textMetadata = actualTextMetadata;
|
textMetadata = actualTextMetadata;
|
||||||
}
|
}
|
||||||
|
|
||||||
JavaxWebSocketFrameHandlerMetadata.MessageMetadata actualBinaryMetadata = JavaxWebSocketFrameHandlerMetadata.MessageMetadata.copyOf(binaryMetadata);
|
JavaxWebSocketMessageMetadata actualBinaryMetadata = JavaxWebSocketMessageMetadata.copyOf(binaryMetadata);
|
||||||
if (actualBinaryMetadata != null)
|
if (actualBinaryMetadata != null)
|
||||||
{
|
{
|
||||||
if (actualBinaryMetadata.isMaxMessageSizeSet())
|
if (actualBinaryMetadata.isMaxMessageSizeSet())
|
||||||
session.setMaxBinaryMessageBufferSize(actualBinaryMetadata.maxMessageSize);
|
session.setMaxBinaryMessageBufferSize(actualBinaryMetadata.getMaxMessageSize());
|
||||||
|
|
||||||
|
MethodHandle methodHandle = actualBinaryMetadata.getMethodHandle();
|
||||||
|
methodHandle = InvokerUtils.bindTo(methodHandle, endpointInstance, endpointConfig, session);
|
||||||
|
methodHandle = JavaxWebSocketFrameHandlerFactory.wrapNonVoidReturnType(methodHandle, session);
|
||||||
|
actualBinaryMetadata.setMethodHandle(methodHandle);
|
||||||
|
|
||||||
actualBinaryMetadata.handle = InvokerUtils.bindTo(actualBinaryMetadata.handle, endpointInstance, endpointConfig, session);
|
|
||||||
actualBinaryMetadata.handle = JavaxWebSocketFrameHandlerFactory.wrapNonVoidReturnType(actualBinaryMetadata.handle, session);
|
|
||||||
binarySink = JavaxWebSocketFrameHandlerFactory.createMessageSink(session, actualBinaryMetadata);
|
binarySink = JavaxWebSocketFrameHandlerFactory.createMessageSink(session, actualBinaryMetadata);
|
||||||
binaryMetadata = actualBinaryMetadata;
|
binaryMetadata = actualBinaryMetadata;
|
||||||
}
|
}
|
||||||
|
@ -350,12 +358,12 @@ public class JavaxWebSocketFrameHandler implements FrameHandler
|
||||||
return messageHandlerMap;
|
return messageHandlerMap;
|
||||||
}
|
}
|
||||||
|
|
||||||
public JavaxWebSocketFrameHandlerMetadata.MessageMetadata getBinaryMetadata()
|
public JavaxWebSocketMessageMetadata getBinaryMetadata()
|
||||||
{
|
{
|
||||||
return binaryMetadata;
|
return binaryMetadata;
|
||||||
}
|
}
|
||||||
|
|
||||||
public JavaxWebSocketFrameHandlerMetadata.MessageMetadata getTextMetadata()
|
public JavaxWebSocketMessageMetadata getTextMetadata()
|
||||||
{
|
{
|
||||||
return textMetadata;
|
return textMetadata;
|
||||||
}
|
}
|
||||||
|
@ -369,7 +377,7 @@ public class JavaxWebSocketFrameHandler implements FrameHandler
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public <T> void addMessageHandler(JavaxWebSocketSession session, Class<T> clazz, MessageHandler.Partial<T> handler)
|
public <T> void addMessageHandler(Class<T> clazz, MessageHandler.Partial<T> handler)
|
||||||
{
|
{
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
|
@ -384,9 +392,9 @@ public class JavaxWebSocketFrameHandler implements FrameHandler
|
||||||
assertBasicTypeNotRegistered(OpCode.BINARY, this.binaryMetadata, handler.getClass().getName());
|
assertBasicTypeNotRegistered(OpCode.BINARY, this.binaryMetadata, handler.getClass().getName());
|
||||||
MessageSink messageSink = new PartialByteArrayMessageSink(coreSession, partialMessageHandler);
|
MessageSink messageSink = new PartialByteArrayMessageSink(coreSession, partialMessageHandler);
|
||||||
this.binarySink = registerMessageHandler(OpCode.BINARY, clazz, handler, messageSink);
|
this.binarySink = registerMessageHandler(OpCode.BINARY, clazz, handler, messageSink);
|
||||||
JavaxWebSocketFrameHandlerMetadata.MessageMetadata metadata = new JavaxWebSocketFrameHandlerMetadata.MessageMetadata();
|
JavaxWebSocketMessageMetadata metadata = new JavaxWebSocketMessageMetadata();
|
||||||
metadata.handle = partialMessageHandler;
|
metadata.setMethodHandle(partialMessageHandler);
|
||||||
metadata.sinkClass = PartialByteArrayMessageSink.class;
|
metadata.setSinkClass(PartialByteArrayMessageSink.class);
|
||||||
this.binaryMetadata = metadata;
|
this.binaryMetadata = metadata;
|
||||||
}
|
}
|
||||||
else if (ByteBuffer.class.isAssignableFrom(clazz))
|
else if (ByteBuffer.class.isAssignableFrom(clazz))
|
||||||
|
@ -394,9 +402,9 @@ public class JavaxWebSocketFrameHandler implements FrameHandler
|
||||||
assertBasicTypeNotRegistered(OpCode.BINARY, this.binaryMetadata, handler.getClass().getName());
|
assertBasicTypeNotRegistered(OpCode.BINARY, this.binaryMetadata, handler.getClass().getName());
|
||||||
MessageSink messageSink = new PartialByteBufferMessageSink(coreSession, partialMessageHandler);
|
MessageSink messageSink = new PartialByteBufferMessageSink(coreSession, partialMessageHandler);
|
||||||
this.binarySink = registerMessageHandler(OpCode.BINARY, clazz, handler, messageSink);
|
this.binarySink = registerMessageHandler(OpCode.BINARY, clazz, handler, messageSink);
|
||||||
JavaxWebSocketFrameHandlerMetadata.MessageMetadata metadata = new JavaxWebSocketFrameHandlerMetadata.MessageMetadata();
|
JavaxWebSocketMessageMetadata metadata = new JavaxWebSocketMessageMetadata();
|
||||||
metadata.handle = partialMessageHandler;
|
metadata.setMethodHandle(partialMessageHandler);
|
||||||
metadata.sinkClass = PartialByteBufferMessageSink.class;
|
metadata.setSinkClass(PartialByteBufferMessageSink.class);
|
||||||
this.binaryMetadata = metadata;
|
this.binaryMetadata = metadata;
|
||||||
}
|
}
|
||||||
else if (String.class.isAssignableFrom(clazz))
|
else if (String.class.isAssignableFrom(clazz))
|
||||||
|
@ -404,9 +412,9 @@ public class JavaxWebSocketFrameHandler implements FrameHandler
|
||||||
assertBasicTypeNotRegistered(OpCode.TEXT, this.textMetadata, handler.getClass().getName());
|
assertBasicTypeNotRegistered(OpCode.TEXT, this.textMetadata, handler.getClass().getName());
|
||||||
MessageSink messageSink = new PartialStringMessageSink(coreSession, partialMessageHandler);
|
MessageSink messageSink = new PartialStringMessageSink(coreSession, partialMessageHandler);
|
||||||
this.textSink = registerMessageHandler(OpCode.TEXT, clazz, handler, messageSink);
|
this.textSink = registerMessageHandler(OpCode.TEXT, clazz, handler, messageSink);
|
||||||
JavaxWebSocketFrameHandlerMetadata.MessageMetadata metadata = new JavaxWebSocketFrameHandlerMetadata.MessageMetadata();
|
JavaxWebSocketMessageMetadata metadata = new JavaxWebSocketMessageMetadata();
|
||||||
metadata.handle = partialMessageHandler;
|
metadata.setMethodHandle(partialMessageHandler);
|
||||||
metadata.sinkClass = PartialStringMessageSink.class;
|
metadata.setSinkClass(PartialStringMessageSink.class);
|
||||||
this.textMetadata = metadata;
|
this.textMetadata = metadata;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
|
@ -426,67 +434,67 @@ public class JavaxWebSocketFrameHandler implements FrameHandler
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public <T> void addMessageHandler(JavaxWebSocketSession session, Class<T> clazz, MessageHandler.Whole<T> handler)
|
public <T> void addMessageHandler(Class<T> clazz, MessageHandler.Whole<T> handler)
|
||||||
{
|
{
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
MethodHandles.Lookup lookup = JavaxWebSocketFrameHandlerFactory.getServerMethodHandleLookup();
|
MethodHandle methodHandle = JavaxWebSocketFrameHandlerFactory.getServerMethodHandleLookup()
|
||||||
MethodHandle wholeMsgMethodHandle = lookup.findVirtual(MessageHandler.Whole.class, "onMessage", MethodType.methodType(void.class, Object.class));
|
.findVirtual(MessageHandler.Whole.class, "onMessage", MethodType.methodType(void.class, Object.class))
|
||||||
wholeMsgMethodHandle = wholeMsgMethodHandle.bindTo(handler);
|
.bindTo(handler);
|
||||||
|
|
||||||
if (PongMessage.class.isAssignableFrom(clazz))
|
if (PongMessage.class.isAssignableFrom(clazz))
|
||||||
{
|
{
|
||||||
assertBasicTypeNotRegistered(OpCode.PONG, this.pongHandle, handler.getClass().getName());
|
assertBasicTypeNotRegistered(OpCode.PONG, this.pongHandle, handler.getClass().getName());
|
||||||
this.pongHandle = wholeMsgMethodHandle;
|
this.pongHandle = methodHandle;
|
||||||
registerMessageHandler(OpCode.PONG, clazz, handler, null);
|
registerMessageHandler(OpCode.PONG, clazz, handler, null);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
AvailableDecoders availableDecoders = session.getDecoders();
|
AvailableDecoders availableDecoders = session.getDecoders();
|
||||||
|
|
||||||
AvailableDecoders.RegisteredDecoder registeredDecoder = availableDecoders.getRegisteredDecoderFor(clazz);
|
RegisteredDecoder registeredDecoder = availableDecoders.getFirstRegisteredDecoder(clazz);
|
||||||
if (registeredDecoder == null)
|
if (registeredDecoder == null)
|
||||||
{
|
{
|
||||||
throw new IllegalStateException("Unable to find Decoder for type: " + clazz);
|
throw new IllegalStateException("Unable to find Decoder for type: " + clazz);
|
||||||
}
|
}
|
||||||
|
|
||||||
JavaxWebSocketFrameHandlerMetadata.MessageMetadata metadata = new JavaxWebSocketFrameHandlerMetadata.MessageMetadata();
|
JavaxWebSocketMessageMetadata metadata = new JavaxWebSocketMessageMetadata();
|
||||||
metadata.handle = wholeMsgMethodHandle;
|
metadata.setMethodHandle(methodHandle);
|
||||||
metadata.registeredDecoder = registeredDecoder;
|
metadata.setRegisteredDecoder(registeredDecoder);
|
||||||
|
|
||||||
if (registeredDecoder.implementsInterface(Decoder.Binary.class))
|
if (registeredDecoder.implementsInterface(Decoder.Binary.class))
|
||||||
{
|
{
|
||||||
assertBasicTypeNotRegistered(OpCode.BINARY, this.binaryMetadata, handler.getClass().getName());
|
assertBasicTypeNotRegistered(OpCode.BINARY, this.binaryMetadata, handler.getClass().getName());
|
||||||
Decoder.Binary<T> decoder = availableDecoders.getInstanceOf(registeredDecoder);
|
List<RegisteredDecoder> binaryDecoders = availableDecoders.getBinaryDecoders(clazz);
|
||||||
MessageSink messageSink = new DecodedBinaryMessageSink(coreSession, decoder, wholeMsgMethodHandle);
|
MessageSink messageSink = new DecodedBinaryMessageSink<T>(coreSession, methodHandle, binaryDecoders);
|
||||||
metadata.sinkClass = messageSink.getClass();
|
metadata.setSinkClass(messageSink.getClass());
|
||||||
this.binarySink = registerMessageHandler(OpCode.BINARY, clazz, handler, messageSink);
|
this.binarySink = registerMessageHandler(OpCode.BINARY, clazz, handler, messageSink);
|
||||||
this.binaryMetadata = metadata;
|
this.binaryMetadata = metadata;
|
||||||
}
|
}
|
||||||
else if (registeredDecoder.implementsInterface(Decoder.BinaryStream.class))
|
else if (registeredDecoder.implementsInterface(Decoder.BinaryStream.class))
|
||||||
{
|
{
|
||||||
assertBasicTypeNotRegistered(OpCode.BINARY, this.binaryMetadata, handler.getClass().getName());
|
assertBasicTypeNotRegistered(OpCode.BINARY, this.binaryMetadata, handler.getClass().getName());
|
||||||
Decoder.BinaryStream<T> decoder = availableDecoders.getInstanceOf(registeredDecoder);
|
List<RegisteredDecoder> binaryStreamDecoders = availableDecoders.getBinaryStreamDecoders(clazz);
|
||||||
MessageSink messageSink = new DecodedBinaryStreamMessageSink(coreSession, decoder, wholeMsgMethodHandle);
|
MessageSink messageSink = new DecodedBinaryStreamMessageSink<T>(coreSession, methodHandle, binaryStreamDecoders);
|
||||||
metadata.sinkClass = messageSink.getClass();
|
metadata.setSinkClass(messageSink.getClass());
|
||||||
this.binarySink = registerMessageHandler(OpCode.BINARY, clazz, handler, messageSink);
|
this.binarySink = registerMessageHandler(OpCode.BINARY, clazz, handler, messageSink);
|
||||||
this.binaryMetadata = metadata;
|
this.binaryMetadata = metadata;
|
||||||
}
|
}
|
||||||
else if (registeredDecoder.implementsInterface(Decoder.Text.class))
|
else if (registeredDecoder.implementsInterface(Decoder.Text.class))
|
||||||
{
|
{
|
||||||
assertBasicTypeNotRegistered(OpCode.TEXT, this.textMetadata, handler.getClass().getName());
|
assertBasicTypeNotRegistered(OpCode.TEXT, this.textMetadata, handler.getClass().getName());
|
||||||
Decoder.Text<T> decoder = availableDecoders.getInstanceOf(registeredDecoder);
|
List<RegisteredDecoder> textDecoders = availableDecoders.getTextDecoders(clazz);
|
||||||
MessageSink messageSink = new DecodedTextMessageSink(coreSession, decoder, wholeMsgMethodHandle);
|
MessageSink messageSink = new DecodedTextMessageSink<T>(coreSession, methodHandle, textDecoders);
|
||||||
metadata.sinkClass = messageSink.getClass();
|
metadata.setSinkClass(messageSink.getClass());
|
||||||
this.textSink = registerMessageHandler(OpCode.TEXT, clazz, handler, messageSink);
|
this.textSink = registerMessageHandler(OpCode.TEXT, clazz, handler, messageSink);
|
||||||
this.textMetadata = metadata;
|
this.textMetadata = metadata;
|
||||||
}
|
}
|
||||||
else if (registeredDecoder.implementsInterface(Decoder.TextStream.class))
|
else if (registeredDecoder.implementsInterface(Decoder.TextStream.class))
|
||||||
{
|
{
|
||||||
assertBasicTypeNotRegistered(OpCode.TEXT, this.textMetadata, handler.getClass().getName());
|
assertBasicTypeNotRegistered(OpCode.TEXT, this.textMetadata, handler.getClass().getName());
|
||||||
Decoder.TextStream<T> decoder = availableDecoders.getInstanceOf(registeredDecoder);
|
List<RegisteredDecoder> textStreamDecoders = availableDecoders.getTextStreamDecoders(clazz);
|
||||||
MessageSink messageSink = new DecodedTextStreamMessageSink(coreSession, decoder, wholeMsgMethodHandle);
|
MessageSink messageSink = new DecodedTextStreamMessageSink<T>(coreSession, methodHandle, textStreamDecoders);
|
||||||
metadata.sinkClass = messageSink.getClass();
|
metadata.setSinkClass(messageSink.getClass());
|
||||||
this.textSink = registerMessageHandler(OpCode.TEXT, clazz, handler, messageSink);
|
this.textSink = registerMessageHandler(OpCode.TEXT, clazz, handler, messageSink);
|
||||||
this.textMetadata = metadata;
|
this.textMetadata = metadata;
|
||||||
}
|
}
|
||||||
|
|
|
@ -18,8 +18,6 @@
|
||||||
|
|
||||||
package org.eclipse.jetty.websocket.javax.common;
|
package org.eclipse.jetty.websocket.javax.common;
|
||||||
|
|
||||||
import java.io.InputStream;
|
|
||||||
import java.io.Reader;
|
|
||||||
import java.lang.annotation.Annotation;
|
import java.lang.annotation.Annotation;
|
||||||
import java.lang.invoke.MethodHandle;
|
import java.lang.invoke.MethodHandle;
|
||||||
import java.lang.invoke.MethodHandles;
|
import java.lang.invoke.MethodHandles;
|
||||||
|
@ -27,11 +25,11 @@ import java.lang.invoke.MethodType;
|
||||||
import java.lang.reflect.InvocationTargetException;
|
import java.lang.reflect.InvocationTargetException;
|
||||||
import java.lang.reflect.Method;
|
import java.lang.reflect.Method;
|
||||||
import java.lang.reflect.Modifier;
|
import java.lang.reflect.Modifier;
|
||||||
import java.nio.ByteBuffer;
|
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
import java.util.function.Function;
|
import java.util.function.Function;
|
||||||
|
import java.util.stream.Stream;
|
||||||
import javax.websocket.CloseReason;
|
import javax.websocket.CloseReason;
|
||||||
import javax.websocket.Decoder;
|
import javax.websocket.Decoder;
|
||||||
import javax.websocket.EndpointConfig;
|
import javax.websocket.EndpointConfig;
|
||||||
|
@ -39,15 +37,14 @@ import javax.websocket.OnClose;
|
||||||
import javax.websocket.OnError;
|
import javax.websocket.OnError;
|
||||||
import javax.websocket.OnMessage;
|
import javax.websocket.OnMessage;
|
||||||
import javax.websocket.OnOpen;
|
import javax.websocket.OnOpen;
|
||||||
import javax.websocket.PongMessage;
|
|
||||||
import javax.websocket.Session;
|
import javax.websocket.Session;
|
||||||
|
|
||||||
import org.eclipse.jetty.http.pathmap.UriTemplatePathSpec;
|
import org.eclipse.jetty.http.pathmap.UriTemplatePathSpec;
|
||||||
import org.eclipse.jetty.websocket.core.CoreSession;
|
import org.eclipse.jetty.websocket.core.CoreSession;
|
||||||
import org.eclipse.jetty.websocket.javax.common.decoders.AvailableDecoders;
|
import org.eclipse.jetty.websocket.javax.common.decoders.RegisteredDecoder;
|
||||||
|
import org.eclipse.jetty.websocket.javax.common.messages.AbstractDecodedMessageSink;
|
||||||
import org.eclipse.jetty.websocket.javax.common.messages.DecodedBinaryMessageSink;
|
import org.eclipse.jetty.websocket.javax.common.messages.DecodedBinaryMessageSink;
|
||||||
import org.eclipse.jetty.websocket.javax.common.messages.DecodedBinaryStreamMessageSink;
|
import org.eclipse.jetty.websocket.javax.common.messages.DecodedBinaryStreamMessageSink;
|
||||||
import org.eclipse.jetty.websocket.javax.common.messages.DecodedMessageSink;
|
|
||||||
import org.eclipse.jetty.websocket.javax.common.messages.DecodedTextMessageSink;
|
import org.eclipse.jetty.websocket.javax.common.messages.DecodedTextMessageSink;
|
||||||
import org.eclipse.jetty.websocket.javax.common.messages.DecodedTextStreamMessageSink;
|
import org.eclipse.jetty.websocket.javax.common.messages.DecodedTextStreamMessageSink;
|
||||||
import org.eclipse.jetty.websocket.util.InvalidSignatureException;
|
import org.eclipse.jetty.websocket.util.InvalidSignatureException;
|
||||||
|
@ -65,61 +62,11 @@ import org.eclipse.jetty.websocket.util.messages.ReaderMessageSink;
|
||||||
import org.eclipse.jetty.websocket.util.messages.StringMessageSink;
|
import org.eclipse.jetty.websocket.util.messages.StringMessageSink;
|
||||||
|
|
||||||
import static java.nio.charset.StandardCharsets.UTF_8;
|
import static java.nio.charset.StandardCharsets.UTF_8;
|
||||||
import static org.eclipse.jetty.websocket.javax.common.JavaxWebSocketFrameHandlerMetadata.MessageMetadata;
|
|
||||||
|
|
||||||
public abstract class JavaxWebSocketFrameHandlerFactory
|
public abstract class JavaxWebSocketFrameHandlerFactory
|
||||||
{
|
{
|
||||||
private static final MethodHandle FILTER_RETURN_TYPE_METHOD;
|
private static final MethodHandle FILTER_RETURN_TYPE_METHOD;
|
||||||
|
|
||||||
// The different kind of @OnMessage method parameter signatures expected.
|
|
||||||
private static final InvokerUtils.Arg[] textCallingArgs = new InvokerUtils.Arg[]{
|
|
||||||
new InvokerUtils.Arg(Session.class),
|
|
||||||
new InvokerUtils.Arg(String.class).required()
|
|
||||||
};
|
|
||||||
|
|
||||||
private static final InvokerUtils.Arg[] textPartialCallingArgs = new InvokerUtils.Arg[]{
|
|
||||||
new InvokerUtils.Arg(Session.class),
|
|
||||||
new InvokerUtils.Arg(String.class).required(),
|
|
||||||
new InvokerUtils.Arg(boolean.class).required()
|
|
||||||
};
|
|
||||||
|
|
||||||
private static final InvokerUtils.Arg[] binaryBufferCallingArgs = new InvokerUtils.Arg[]{
|
|
||||||
new InvokerUtils.Arg(Session.class),
|
|
||||||
new InvokerUtils.Arg(ByteBuffer.class).required()
|
|
||||||
};
|
|
||||||
|
|
||||||
private static final InvokerUtils.Arg[] binaryPartialBufferCallingArgs = new InvokerUtils.Arg[]{
|
|
||||||
new InvokerUtils.Arg(Session.class),
|
|
||||||
new InvokerUtils.Arg(ByteBuffer.class).required(),
|
|
||||||
new InvokerUtils.Arg(boolean.class).required()
|
|
||||||
};
|
|
||||||
|
|
||||||
private static final InvokerUtils.Arg[] binaryArrayCallingArgs = new InvokerUtils.Arg[]{
|
|
||||||
new InvokerUtils.Arg(Session.class),
|
|
||||||
new InvokerUtils.Arg(byte[].class).required()
|
|
||||||
};
|
|
||||||
|
|
||||||
private static final InvokerUtils.Arg[] binaryPartialArrayCallingArgs = new InvokerUtils.Arg[]{
|
|
||||||
new InvokerUtils.Arg(Session.class),
|
|
||||||
new InvokerUtils.Arg(byte[].class).required(),
|
|
||||||
new InvokerUtils.Arg(boolean.class).required()
|
|
||||||
};
|
|
||||||
|
|
||||||
private static final InvokerUtils.Arg[] inputStreamCallingArgs = new InvokerUtils.Arg[]{
|
|
||||||
new InvokerUtils.Arg(Session.class),
|
|
||||||
new InvokerUtils.Arg(InputStream.class).required()
|
|
||||||
};
|
|
||||||
|
|
||||||
private static final InvokerUtils.Arg[] readerCallingArgs = new InvokerUtils.Arg[]{
|
|
||||||
new InvokerUtils.Arg(Session.class),
|
|
||||||
new InvokerUtils.Arg(Reader.class).required()
|
|
||||||
};
|
|
||||||
|
|
||||||
private static final InvokerUtils.Arg[] pongCallingArgs = new InvokerUtils.Arg[]{
|
|
||||||
new InvokerUtils.Arg(Session.class),
|
|
||||||
new InvokerUtils.Arg(PongMessage.class).required()
|
|
||||||
};
|
|
||||||
|
|
||||||
static
|
static
|
||||||
{
|
{
|
||||||
try
|
try
|
||||||
|
@ -172,8 +119,8 @@ public abstract class JavaxWebSocketFrameHandlerFactory
|
||||||
MethodHandle errorHandle = metadata.getErrorHandle();
|
MethodHandle errorHandle = metadata.getErrorHandle();
|
||||||
MethodHandle pongHandle = metadata.getPongHandle();
|
MethodHandle pongHandle = metadata.getPongHandle();
|
||||||
|
|
||||||
MessageMetadata textMetadata = MessageMetadata.copyOf(metadata.getTextMetadata());
|
JavaxWebSocketMessageMetadata textMetadata = JavaxWebSocketMessageMetadata.copyOf(metadata.getTextMetadata());
|
||||||
MessageMetadata binaryMetadata = MessageMetadata.copyOf(metadata.getBinaryMetadata());
|
JavaxWebSocketMessageMetadata binaryMetadata = JavaxWebSocketMessageMetadata.copyOf(metadata.getBinaryMetadata());
|
||||||
|
|
||||||
UriTemplatePathSpec templatePathSpec = metadata.getUriTemplatePathSpec();
|
UriTemplatePathSpec templatePathSpec = metadata.getUriTemplatePathSpec();
|
||||||
if (templatePathSpec != null)
|
if (templatePathSpec != null)
|
||||||
|
@ -188,9 +135,9 @@ public abstract class JavaxWebSocketFrameHandlerFactory
|
||||||
pongHandle = bindTemplateVariables(pongHandle, namedVariables, pathParams);
|
pongHandle = bindTemplateVariables(pongHandle, namedVariables, pathParams);
|
||||||
|
|
||||||
if (textMetadata != null)
|
if (textMetadata != null)
|
||||||
textMetadata.handle = bindTemplateVariables(textMetadata.handle, namedVariables, pathParams);
|
textMetadata.setMethodHandle(bindTemplateVariables(textMetadata.getMethodHandle(), namedVariables, pathParams));
|
||||||
if (binaryMetadata != null)
|
if (binaryMetadata != null)
|
||||||
binaryMetadata.handle = bindTemplateVariables(binaryMetadata.handle, namedVariables, pathParams);
|
binaryMetadata.setMethodHandle(bindTemplateVariables(binaryMetadata.getMethodHandle(), namedVariables, pathParams));
|
||||||
}
|
}
|
||||||
|
|
||||||
openHandle = InvokerUtils.bindTo(openHandle, endpoint);
|
openHandle = InvokerUtils.bindTo(openHandle, endpoint);
|
||||||
|
@ -313,8 +260,7 @@ public abstract class JavaxWebSocketFrameHandlerFactory
|
||||||
return retHandle;
|
return retHandle;
|
||||||
}
|
}
|
||||||
|
|
||||||
@SuppressWarnings("Duplicates")
|
public static MessageSink createMessageSink(JavaxWebSocketSession session, JavaxWebSocketMessageMetadata msgMetadata)
|
||||||
public static MessageSink createMessageSink(JavaxWebSocketSession session, MessageMetadata msgMetadata)
|
|
||||||
{
|
{
|
||||||
if (msgMetadata == null)
|
if (msgMetadata == null)
|
||||||
return null;
|
return null;
|
||||||
|
@ -322,27 +268,27 @@ public abstract class JavaxWebSocketFrameHandlerFactory
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
MethodHandles.Lookup lookup = getServerMethodHandleLookup();
|
MethodHandles.Lookup lookup = getServerMethodHandleLookup();
|
||||||
if (DecodedMessageSink.class.isAssignableFrom(msgMetadata.sinkClass))
|
if (AbstractDecodedMessageSink.class.isAssignableFrom(msgMetadata.getSinkClass()))
|
||||||
{
|
{
|
||||||
MethodHandle ctorHandle = lookup.findConstructor(msgMetadata.sinkClass,
|
MethodHandle ctorHandle = lookup.findConstructor(msgMetadata.getSinkClass(),
|
||||||
MethodType.methodType(void.class, CoreSession.class, msgMetadata.registeredDecoder.interfaceType, MethodHandle.class));
|
MethodType.methodType(void.class, CoreSession.class, MethodHandle.class, List.class));
|
||||||
Decoder decoder = session.getDecoders().getInstanceOf(msgMetadata.registeredDecoder);
|
List<RegisteredDecoder> registeredDecoders = msgMetadata.getRegisteredDecoders();
|
||||||
return (MessageSink)ctorHandle.invoke(session.getCoreSession(), decoder, msgMetadata.handle);
|
return (MessageSink)ctorHandle.invoke(session.getCoreSession(), msgMetadata.getMethodHandle(), registeredDecoders);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
MethodHandle ctorHandle = lookup.findConstructor(msgMetadata.sinkClass,
|
MethodHandle ctorHandle = lookup.findConstructor(msgMetadata.getSinkClass(),
|
||||||
MethodType.methodType(void.class, CoreSession.class, MethodHandle.class));
|
MethodType.methodType(void.class, CoreSession.class, MethodHandle.class));
|
||||||
return (MessageSink)ctorHandle.invoke(session.getCoreSession(), msgMetadata.handle);
|
return (MessageSink)ctorHandle.invoke(session.getCoreSession(), msgMetadata.getMethodHandle());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
catch (NoSuchMethodException e)
|
catch (NoSuchMethodException e)
|
||||||
{
|
{
|
||||||
throw new RuntimeException("Missing expected MessageSink constructor found at: " + msgMetadata.sinkClass.getName(), e);
|
throw new RuntimeException("Missing expected MessageSink constructor found at: " + msgMetadata.getSinkClass().getName(), e);
|
||||||
}
|
}
|
||||||
catch (IllegalAccessException | InstantiationException | InvocationTargetException e)
|
catch (IllegalAccessException | InstantiationException | InvocationTargetException e)
|
||||||
{
|
{
|
||||||
throw new RuntimeException("Unable to create MessageSink: " + msgMetadata.sinkClass.getName(), e);
|
throw new RuntimeException("Unable to create MessageSink: " + msgMetadata.getSinkClass().getName(), e);
|
||||||
}
|
}
|
||||||
catch (RuntimeException e)
|
catch (RuntimeException e)
|
||||||
{
|
{
|
||||||
|
@ -456,15 +402,19 @@ public abstract class JavaxWebSocketFrameHandlerFactory
|
||||||
for (Method onMsg : onMessages)
|
for (Method onMsg : onMessages)
|
||||||
{
|
{
|
||||||
assertSignatureValid(endpointClass, onMsg, OnMessage.class);
|
assertSignatureValid(endpointClass, onMsg, OnMessage.class);
|
||||||
|
|
||||||
MessageMetadata msgMetadata = new MessageMetadata();
|
|
||||||
OnMessage onMessageAnno = onMsg.getAnnotation(OnMessage.class);
|
OnMessage onMessageAnno = onMsg.getAnnotation(OnMessage.class);
|
||||||
if (onMessageAnno.maxMessageSize() > Integer.MAX_VALUE)
|
|
||||||
|
long annotationMaxMessageSize = onMessageAnno.maxMessageSize();
|
||||||
|
if (annotationMaxMessageSize > Integer.MAX_VALUE)
|
||||||
{
|
{
|
||||||
throw new InvalidWebSocketException(String.format("Value too large: %s#%s - @OnMessage.maxMessageSize=%,d > Integer.MAX_VALUE",
|
throw new InvalidWebSocketException(String.format("Value too large: %s#%s - @OnMessage.maxMessageSize=%,d > Integer.MAX_VALUE",
|
||||||
endpointClass.getName(), onMsg.getName(), onMessageAnno.maxMessageSize()));
|
endpointClass.getName(), onMsg.getName(), annotationMaxMessageSize));
|
||||||
}
|
}
|
||||||
msgMetadata.maxMessageSize = (int)onMessageAnno.maxMessageSize();
|
|
||||||
|
// Create MessageMetadata and set annotated maxMessageSize if it is not the default value.
|
||||||
|
JavaxWebSocketMessageMetadata msgMetadata = new JavaxWebSocketMessageMetadata();
|
||||||
|
if (annotationMaxMessageSize != -1)
|
||||||
|
msgMetadata.setMaxMessageSize((int)annotationMaxMessageSize);
|
||||||
|
|
||||||
// Function to search for matching MethodHandle for the endpointClass given a signature.
|
// Function to search for matching MethodHandle for the endpointClass given a signature.
|
||||||
Function<InvokerUtils.Arg[], MethodHandle> getMethodHandle = (signature) ->
|
Function<InvokerUtils.Arg[], MethodHandle> getMethodHandle = (signature) ->
|
||||||
|
@ -486,91 +436,91 @@ public abstract class JavaxWebSocketFrameHandlerFactory
|
||||||
return metadata;
|
return metadata;
|
||||||
}
|
}
|
||||||
|
|
||||||
private boolean matchOnMessage(Method onMsg, JavaxWebSocketFrameHandlerMetadata metadata, MessageMetadata msgMetadata,
|
private boolean matchOnMessage(Method onMsg, JavaxWebSocketFrameHandlerMetadata metadata, JavaxWebSocketMessageMetadata msgMetadata,
|
||||||
Function<InvokerUtils.Arg[], MethodHandle> getMethodHandle)
|
Function<InvokerUtils.Arg[], MethodHandle> getMethodHandle)
|
||||||
{
|
{
|
||||||
// Whole Text Message.
|
// Whole Text Message.
|
||||||
MethodHandle methodHandle = getMethodHandle.apply(textCallingArgs);
|
MethodHandle methodHandle = getMethodHandle.apply(JavaxWebSocketCallingArgs.textCallingArgs);
|
||||||
if (methodHandle != null)
|
if (methodHandle != null)
|
||||||
{
|
{
|
||||||
msgMetadata.sinkClass = StringMessageSink.class;
|
msgMetadata.setSinkClass(StringMessageSink.class);
|
||||||
msgMetadata.handle = methodHandle;
|
msgMetadata.setMethodHandle(methodHandle);
|
||||||
metadata.setTextMetadata(msgMetadata, onMsg);
|
metadata.setTextMetadata(msgMetadata, onMsg);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Partial Text Message.
|
// Partial Text Message.
|
||||||
methodHandle = getMethodHandle.apply(textPartialCallingArgs);
|
methodHandle = getMethodHandle.apply(JavaxWebSocketCallingArgs.textPartialCallingArgs);
|
||||||
if (methodHandle != null)
|
if (methodHandle != null)
|
||||||
{
|
{
|
||||||
msgMetadata.sinkClass = PartialStringMessageSink.class;
|
msgMetadata.setSinkClass(PartialStringMessageSink.class);
|
||||||
msgMetadata.handle = methodHandle;
|
msgMetadata.setMethodHandle(methodHandle);
|
||||||
metadata.setTextMetadata(msgMetadata, onMsg);
|
metadata.setTextMetadata(msgMetadata, onMsg);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Whole ByteBuffer Binary Message.
|
// Whole ByteBuffer Binary Message.
|
||||||
methodHandle = getMethodHandle.apply(binaryBufferCallingArgs);
|
methodHandle = getMethodHandle.apply(JavaxWebSocketCallingArgs.binaryBufferCallingArgs);
|
||||||
if (methodHandle != null)
|
if (methodHandle != null)
|
||||||
{
|
{
|
||||||
msgMetadata.sinkClass = ByteBufferMessageSink.class;
|
msgMetadata.setSinkClass(ByteBufferMessageSink.class);
|
||||||
msgMetadata.handle = methodHandle;
|
msgMetadata.setMethodHandle(methodHandle);
|
||||||
metadata.setBinaryMetadata(msgMetadata, onMsg);
|
metadata.setBinaryMetadata(msgMetadata, onMsg);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Partial ByteBuffer Binary Message.
|
// Partial ByteBuffer Binary Message.
|
||||||
methodHandle = getMethodHandle.apply(binaryPartialBufferCallingArgs);
|
methodHandle = getMethodHandle.apply(JavaxWebSocketCallingArgs.binaryPartialBufferCallingArgs);
|
||||||
if (methodHandle != null)
|
if (methodHandle != null)
|
||||||
{
|
{
|
||||||
msgMetadata.sinkClass = PartialByteBufferMessageSink.class;
|
msgMetadata.setSinkClass(PartialByteBufferMessageSink.class);
|
||||||
msgMetadata.handle = methodHandle;
|
msgMetadata.setMethodHandle(methodHandle);
|
||||||
metadata.setBinaryMetadata(msgMetadata, onMsg);
|
metadata.setBinaryMetadata(msgMetadata, onMsg);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Whole byte[] Binary Message.
|
// Whole byte[] Binary Message.
|
||||||
methodHandle = getMethodHandle.apply(binaryArrayCallingArgs);
|
methodHandle = getMethodHandle.apply(JavaxWebSocketCallingArgs.binaryArrayCallingArgs);
|
||||||
if (methodHandle != null)
|
if (methodHandle != null)
|
||||||
{
|
{
|
||||||
msgMetadata.sinkClass = ByteArrayMessageSink.class;
|
msgMetadata.setSinkClass(ByteArrayMessageSink.class);
|
||||||
msgMetadata.handle = methodHandle;
|
msgMetadata.setMethodHandle(methodHandle);
|
||||||
metadata.setBinaryMetadata(msgMetadata, onMsg);
|
metadata.setBinaryMetadata(msgMetadata, onMsg);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Partial byte[] Binary Message.
|
// Partial byte[] Binary Message.
|
||||||
methodHandle = getMethodHandle.apply(binaryPartialArrayCallingArgs);
|
methodHandle = getMethodHandle.apply(JavaxWebSocketCallingArgs.binaryPartialArrayCallingArgs);
|
||||||
if (methodHandle != null)
|
if (methodHandle != null)
|
||||||
{
|
{
|
||||||
msgMetadata.sinkClass = PartialByteArrayMessageSink.class;
|
msgMetadata.setSinkClass(PartialByteArrayMessageSink.class);
|
||||||
msgMetadata.handle = methodHandle;
|
msgMetadata.setMethodHandle(methodHandle);
|
||||||
metadata.setBinaryMetadata(msgMetadata, onMsg);
|
metadata.setBinaryMetadata(msgMetadata, onMsg);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
// InputStream Binary Message.
|
// InputStream Binary Message.
|
||||||
methodHandle = getMethodHandle.apply(inputStreamCallingArgs);
|
methodHandle = getMethodHandle.apply(JavaxWebSocketCallingArgs.inputStreamCallingArgs);
|
||||||
if (methodHandle != null)
|
if (methodHandle != null)
|
||||||
{
|
{
|
||||||
msgMetadata.sinkClass = InputStreamMessageSink.class;
|
msgMetadata.setSinkClass(InputStreamMessageSink.class);
|
||||||
msgMetadata.handle = methodHandle;
|
msgMetadata.setMethodHandle(methodHandle);
|
||||||
metadata.setBinaryMetadata(msgMetadata, onMsg);
|
metadata.setBinaryMetadata(msgMetadata, onMsg);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Reader Text Message.
|
// Reader Text Message.
|
||||||
methodHandle = getMethodHandle.apply(readerCallingArgs);
|
methodHandle = getMethodHandle.apply(JavaxWebSocketCallingArgs.readerCallingArgs);
|
||||||
if (methodHandle != null)
|
if (methodHandle != null)
|
||||||
{
|
{
|
||||||
msgMetadata.sinkClass = ReaderMessageSink.class;
|
msgMetadata.setSinkClass(ReaderMessageSink.class);
|
||||||
msgMetadata.handle = methodHandle;
|
msgMetadata.setMethodHandle(methodHandle);
|
||||||
metadata.setTextMetadata(msgMetadata, onMsg);
|
metadata.setTextMetadata(msgMetadata, onMsg);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Pong Message.
|
// Pong Message.
|
||||||
MethodHandle pongHandle = getMethodHandle.apply(pongCallingArgs);
|
MethodHandle pongHandle = getMethodHandle.apply(JavaxWebSocketCallingArgs.pongCallingArgs);
|
||||||
if (pongHandle != null)
|
if (pongHandle != null)
|
||||||
{
|
{
|
||||||
metadata.setPongHandle(pongHandle, onMsg);
|
metadata.setPongHandle(pongHandle, onMsg);
|
||||||
|
@ -580,88 +530,70 @@ public abstract class JavaxWebSocketFrameHandlerFactory
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
private boolean matchDecoders(Method onMsg, JavaxWebSocketFrameHandlerMetadata metadata, MessageMetadata msgMetadata,
|
private boolean matchDecoders(Method onMsg, JavaxWebSocketFrameHandlerMetadata metadata, JavaxWebSocketMessageMetadata msgMetadata,
|
||||||
Function<InvokerUtils.Arg[], MethodHandle> getMethodHandle)
|
Function<InvokerUtils.Arg[], MethodHandle> getMethodHandle)
|
||||||
{
|
{
|
||||||
// TODO: we should be able to get this information directly from the AvailableDecoders in the metadata.
|
// We need to get all the decoders which match not just the first.
|
||||||
List<DecodedArgs> decodedTextCallingArgs = new ArrayList<>();
|
Stream<RegisteredDecoder> matchedDecodersStream = metadata.getAvailableDecoders().stream().filter(registeredDecoder ->
|
||||||
List<DecodedArgs> decodedTextStreamCallingArgs = new ArrayList<>();
|
|
||||||
List<DecodedArgs> decodedBinaryCallingArgs = new ArrayList<>();
|
|
||||||
List<DecodedArgs> decodedBinaryStreamCallingArgs = new ArrayList<>();
|
|
||||||
for (AvailableDecoders.RegisteredDecoder decoder : metadata.getAvailableDecoders())
|
|
||||||
{
|
{
|
||||||
InvokerUtils.Arg[] args = {new InvokerUtils.Arg(Session.class), new InvokerUtils.Arg(decoder.objectType).required()};
|
InvokerUtils.Arg[] args = {new InvokerUtils.Arg(Session.class), new InvokerUtils.Arg(registeredDecoder.objectType).required()};
|
||||||
DecodedArgs decodedArgs = new DecodedArgs(decoder, args);
|
return getMethodHandle.apply(args) != null;
|
||||||
|
});
|
||||||
if (decoder.implementsInterface(Decoder.Text.class))
|
|
||||||
decodedTextCallingArgs.add(decodedArgs);
|
|
||||||
if (decoder.implementsInterface(Decoder.TextStream.class))
|
|
||||||
decodedTextStreamCallingArgs.add(decodedArgs);
|
|
||||||
if (decoder.implementsInterface(Decoder.Binary.class))
|
|
||||||
decodedBinaryCallingArgs.add(decodedArgs);
|
|
||||||
if (decoder.implementsInterface(Decoder.BinaryStream.class))
|
|
||||||
decodedBinaryStreamCallingArgs.add(decodedArgs);
|
|
||||||
}
|
|
||||||
|
|
||||||
MethodHandle methodHandle;
|
|
||||||
|
|
||||||
// Decoder.Text
|
|
||||||
for (DecodedArgs decodedArgs : decodedTextCallingArgs)
|
|
||||||
{
|
|
||||||
methodHandle = getMethodHandle.apply(decodedArgs.args);
|
|
||||||
if (methodHandle != null)
|
|
||||||
{
|
|
||||||
msgMetadata.sinkClass = DecodedTextMessageSink.class;
|
|
||||||
msgMetadata.handle = methodHandle;
|
|
||||||
msgMetadata.registeredDecoder = decodedArgs.registeredDecoder;
|
|
||||||
metadata.setTextMetadata(msgMetadata, onMsg);
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Decoder.Binary
|
|
||||||
for (DecodedArgs decodedArgs : decodedBinaryCallingArgs)
|
|
||||||
{
|
|
||||||
methodHandle = getMethodHandle.apply(decodedArgs.args);
|
|
||||||
if (methodHandle != null)
|
|
||||||
{
|
|
||||||
msgMetadata.sinkClass = DecodedBinaryMessageSink.class;
|
|
||||||
msgMetadata.handle = methodHandle;
|
|
||||||
msgMetadata.registeredDecoder = decodedArgs.registeredDecoder;
|
|
||||||
metadata.setBinaryMetadata(msgMetadata, onMsg);
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Try to match Text Stream decoders.
|
|
||||||
for (DecodedArgs decodedArgs : decodedTextStreamCallingArgs)
|
|
||||||
{
|
|
||||||
methodHandle = getMethodHandle.apply(decodedArgs.args);
|
|
||||||
if (methodHandle != null)
|
|
||||||
{
|
|
||||||
msgMetadata.sinkClass = DecodedTextStreamMessageSink.class;
|
|
||||||
msgMetadata.handle = methodHandle;
|
|
||||||
msgMetadata.registeredDecoder = decodedArgs.registeredDecoder;
|
|
||||||
metadata.setTextMetadata(msgMetadata, onMsg);
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Decoder.BinaryStream
|
|
||||||
for (DecodedArgs decodedArgs : decodedBinaryStreamCallingArgs)
|
|
||||||
{
|
|
||||||
methodHandle = getMethodHandle.apply(decodedArgs.args);
|
|
||||||
if (methodHandle != null)
|
|
||||||
{
|
|
||||||
msgMetadata.sinkClass = DecodedBinaryStreamMessageSink.class;
|
|
||||||
msgMetadata.handle = methodHandle;
|
|
||||||
msgMetadata.registeredDecoder = decodedArgs.registeredDecoder;
|
|
||||||
metadata.setBinaryMetadata(msgMetadata, onMsg);
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
// Use the interface type of the first matched decoder.
|
||||||
|
RegisteredDecoder firstDecoder = matchedDecodersStream.findFirst().orElse(null);
|
||||||
|
if (firstDecoder == null)
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
|
|
||||||
|
// TODO: COMMENT
|
||||||
|
List<RegisteredDecoder> decoders = new ArrayList<>();
|
||||||
|
Class<? extends Decoder> interfaceType = firstDecoder.interfaceType;
|
||||||
|
metadata.getAvailableDecoders().stream()
|
||||||
|
.filter(registeredDecoder -> registeredDecoder.interfaceType.equals(interfaceType))
|
||||||
|
.forEach(decoders::add);
|
||||||
|
|
||||||
|
|
||||||
|
// Get the original argument type.
|
||||||
|
Class<?> type = firstDecoder.objectType;
|
||||||
|
for (Class<?> clazz : onMsg.getParameterTypes())
|
||||||
|
{
|
||||||
|
if (clazz.isAssignableFrom(firstDecoder.objectType))
|
||||||
|
type = clazz;
|
||||||
|
}
|
||||||
|
InvokerUtils.Arg[] generalArgs = {new InvokerUtils.Arg(Session.class), new InvokerUtils.Arg(type).required()};
|
||||||
|
MethodHandle generalMethodHandle = getMethodHandle.apply(generalArgs);
|
||||||
|
if (generalMethodHandle == null)
|
||||||
|
{
|
||||||
|
// TODO: warn or throw
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
msgMetadata.setRegisteredDecoders(decoders);
|
||||||
|
msgMetadata.setMethodHandle(generalMethodHandle);
|
||||||
|
|
||||||
|
if (interfaceType.equals(Decoder.Text.class))
|
||||||
|
{
|
||||||
|
msgMetadata.setSinkClass(DecodedTextMessageSink.class);
|
||||||
|
metadata.setTextMetadata(msgMetadata, onMsg);
|
||||||
|
}
|
||||||
|
else if (interfaceType.equals(Decoder.Binary.class))
|
||||||
|
{
|
||||||
|
msgMetadata.setSinkClass(DecodedBinaryMessageSink.class);
|
||||||
|
metadata.setBinaryMetadata(msgMetadata, onMsg);
|
||||||
|
}
|
||||||
|
else if (interfaceType.equals(Decoder.TextStream.class))
|
||||||
|
{
|
||||||
|
msgMetadata.setSinkClass(DecodedTextStreamMessageSink.class);
|
||||||
|
metadata.setTextMetadata(msgMetadata, onMsg);
|
||||||
|
}
|
||||||
|
else if (interfaceType.equals(Decoder.BinaryStream.class))
|
||||||
|
{
|
||||||
|
msgMetadata.setSinkClass(DecodedBinaryStreamMessageSink.class);
|
||||||
|
metadata.setBinaryMetadata(msgMetadata, onMsg);
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
private void assertSignatureValid(Class<?> endpointClass, Method method, Class<? extends Annotation> annotationClass)
|
private void assertSignatureValid(Class<?> endpointClass, Method method, Class<? extends Annotation> annotationClass)
|
||||||
|
@ -752,16 +684,4 @@ public abstract class JavaxWebSocketFrameHandlerFactory
|
||||||
{
|
{
|
||||||
return MethodHandles.publicLookup().in(lookupClass);
|
return MethodHandles.publicLookup().in(lookupClass);
|
||||||
}
|
}
|
||||||
|
|
||||||
private static class DecodedArgs
|
|
||||||
{
|
|
||||||
public final AvailableDecoders.RegisteredDecoder registeredDecoder;
|
|
||||||
public final InvokerUtils.Arg[] args;
|
|
||||||
|
|
||||||
public DecodedArgs(AvailableDecoders.RegisteredDecoder registeredDecoder, InvokerUtils.Arg... args)
|
|
||||||
{
|
|
||||||
this.registeredDecoder = registeredDecoder;
|
|
||||||
this.args = args;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -19,7 +19,6 @@
|
||||||
package org.eclipse.jetty.websocket.javax.common;
|
package org.eclipse.jetty.websocket.javax.common;
|
||||||
|
|
||||||
import java.lang.invoke.MethodHandle;
|
import java.lang.invoke.MethodHandle;
|
||||||
import javax.websocket.Decoder;
|
|
||||||
import javax.websocket.Encoder;
|
import javax.websocket.Encoder;
|
||||||
import javax.websocket.EndpointConfig;
|
import javax.websocket.EndpointConfig;
|
||||||
|
|
||||||
|
@ -27,25 +26,21 @@ import org.eclipse.jetty.http.pathmap.UriTemplatePathSpec;
|
||||||
import org.eclipse.jetty.websocket.javax.common.decoders.AvailableDecoders;
|
import org.eclipse.jetty.websocket.javax.common.decoders.AvailableDecoders;
|
||||||
import org.eclipse.jetty.websocket.javax.common.encoders.AvailableEncoders;
|
import org.eclipse.jetty.websocket.javax.common.encoders.AvailableEncoders;
|
||||||
import org.eclipse.jetty.websocket.util.InvalidWebSocketException;
|
import org.eclipse.jetty.websocket.util.InvalidWebSocketException;
|
||||||
import org.eclipse.jetty.websocket.util.messages.MessageSink;
|
|
||||||
|
|
||||||
public class JavaxWebSocketFrameHandlerMetadata
|
public class JavaxWebSocketFrameHandlerMetadata
|
||||||
{
|
{
|
||||||
private static final String[] NO_VARIABLES = new String[0];
|
private static final String[] NO_VARIABLES = new String[0];
|
||||||
|
|
||||||
// EndpointConfig entries
|
// EndpointConfig entries
|
||||||
private final EndpointConfig endpointConfig;
|
|
||||||
private final AvailableDecoders availableDecoders;
|
private final AvailableDecoders availableDecoders;
|
||||||
private final AvailableEncoders availableEncoders;
|
private final AvailableEncoders availableEncoders;
|
||||||
|
|
||||||
private MethodHandle openHandle;
|
private MethodHandle openHandle;
|
||||||
private MethodHandle closeHandle;
|
private MethodHandle closeHandle;
|
||||||
private MethodHandle errorHandle;
|
private MethodHandle errorHandle;
|
||||||
|
|
||||||
private MessageMetadata textMetadata;
|
|
||||||
private MessageMetadata binaryMetadata;
|
|
||||||
|
|
||||||
private MethodHandle pongHandle;
|
private MethodHandle pongHandle;
|
||||||
|
private JavaxWebSocketMessageMetadata textMetadata;
|
||||||
|
private JavaxWebSocketMessageMetadata binaryMetadata;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* For {@code @ServerEndpoint} or {@code ServerEndpointConfig} based endpoints, this
|
* For {@code @ServerEndpoint} or {@code ServerEndpointConfig} based endpoints, this
|
||||||
|
@ -76,7 +71,6 @@ public class JavaxWebSocketFrameHandlerMetadata
|
||||||
|
|
||||||
public JavaxWebSocketFrameHandlerMetadata(EndpointConfig endpointConfig)
|
public JavaxWebSocketFrameHandlerMetadata(EndpointConfig endpointConfig)
|
||||||
{
|
{
|
||||||
this.endpointConfig = endpointConfig;
|
|
||||||
this.availableDecoders = new AvailableDecoders(endpointConfig);
|
this.availableDecoders = new AvailableDecoders(endpointConfig);
|
||||||
this.availableEncoders = new AvailableEncoders(endpointConfig);
|
this.availableEncoders = new AvailableEncoders(endpointConfig);
|
||||||
}
|
}
|
||||||
|
@ -91,7 +85,7 @@ public class JavaxWebSocketFrameHandlerMetadata
|
||||||
return availableEncoders;
|
return availableEncoders;
|
||||||
}
|
}
|
||||||
|
|
||||||
public MessageMetadata getBinaryMetadata()
|
public JavaxWebSocketMessageMetadata getBinaryMetadata()
|
||||||
{
|
{
|
||||||
return binaryMetadata;
|
return binaryMetadata;
|
||||||
}
|
}
|
||||||
|
@ -133,7 +127,7 @@ public class JavaxWebSocketFrameHandlerMetadata
|
||||||
return pongHandle;
|
return pongHandle;
|
||||||
}
|
}
|
||||||
|
|
||||||
public MessageMetadata getTextMetadata()
|
public JavaxWebSocketMessageMetadata getTextMetadata()
|
||||||
{
|
{
|
||||||
return textMetadata;
|
return textMetadata;
|
||||||
}
|
}
|
||||||
|
@ -148,7 +142,7 @@ public class JavaxWebSocketFrameHandlerMetadata
|
||||||
return (textMetadata != null);
|
return (textMetadata != null);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void setBinaryMetadata(MessageMetadata metadata, Object origin)
|
public void setBinaryMetadata(JavaxWebSocketMessageMetadata metadata, Object origin)
|
||||||
{
|
{
|
||||||
assertNotSet(this.binaryMetadata, "BINARY Message Metadata", origin);
|
assertNotSet(this.binaryMetadata, "BINARY Message Metadata", origin);
|
||||||
this.binaryMetadata = metadata;
|
this.binaryMetadata = metadata;
|
||||||
|
@ -160,11 +154,6 @@ public class JavaxWebSocketFrameHandlerMetadata
|
||||||
this.closeHandle = close;
|
this.closeHandle = close;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void setDecoders(Class<? extends Decoder>[] decoders)
|
|
||||||
{
|
|
||||||
this.availableDecoders.registerAll(decoders);
|
|
||||||
}
|
|
||||||
|
|
||||||
public void setEncoders(Class<? extends Encoder>[] encoders)
|
public void setEncoders(Class<? extends Encoder>[] encoders)
|
||||||
{
|
{
|
||||||
this.availableEncoders.registerAll(encoders);
|
this.availableEncoders.registerAll(encoders);
|
||||||
|
@ -188,7 +177,7 @@ public class JavaxWebSocketFrameHandlerMetadata
|
||||||
this.pongHandle = pong;
|
this.pongHandle = pong;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void setTextMetadata(MessageMetadata metadata, Object origin)
|
public void setTextMetadata(JavaxWebSocketMessageMetadata metadata, Object origin)
|
||||||
{
|
{
|
||||||
assertNotSet(this.textMetadata, "TEXT Messsage Metadata", origin);
|
assertNotSet(this.textMetadata, "TEXT Messsage Metadata", origin);
|
||||||
this.textMetadata = metadata;
|
this.textMetadata = metadata;
|
||||||
|
@ -219,33 +208,4 @@ public class JavaxWebSocketFrameHandlerMetadata
|
||||||
|
|
||||||
return obj.toString();
|
return obj.toString();
|
||||||
}
|
}
|
||||||
|
|
||||||
public static class MessageMetadata
|
|
||||||
{
|
|
||||||
private static final int UNSET = -1;
|
|
||||||
|
|
||||||
public MethodHandle handle;
|
|
||||||
public Class<? extends MessageSink> sinkClass;
|
|
||||||
public AvailableDecoders.RegisteredDecoder registeredDecoder;
|
|
||||||
public int maxMessageSize = UNSET;
|
|
||||||
|
|
||||||
public static MessageMetadata copyOf(MessageMetadata metadata)
|
|
||||||
{
|
|
||||||
if (metadata == null)
|
|
||||||
return null;
|
|
||||||
|
|
||||||
MessageMetadata copy = new MessageMetadata();
|
|
||||||
copy.handle = metadata.handle;
|
|
||||||
copy.sinkClass = metadata.sinkClass;
|
|
||||||
copy.registeredDecoder = metadata.registeredDecoder;
|
|
||||||
copy.maxMessageSize = metadata.maxMessageSize;
|
|
||||||
|
|
||||||
return copy;
|
|
||||||
}
|
|
||||||
|
|
||||||
public boolean isMaxMessageSizeSet()
|
|
||||||
{
|
|
||||||
return maxMessageSize != UNSET;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,115 @@
|
||||||
|
//
|
||||||
|
// ========================================================================
|
||||||
|
// Copyright (c) 1995-2020 Mort Bay Consulting Pty Ltd and others.
|
||||||
|
//
|
||||||
|
// This program and the accompanying materials are made available under
|
||||||
|
// the terms of the Eclipse Public License 2.0 which is available at
|
||||||
|
// https://www.eclipse.org/legal/epl-2.0
|
||||||
|
//
|
||||||
|
// This Source Code may also be made available under the following
|
||||||
|
// Secondary Licenses when the conditions for such availability set
|
||||||
|
// forth in the Eclipse Public License, v. 2.0 are satisfied:
|
||||||
|
// the Apache License v2.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;
|
||||||
|
|
||||||
|
import java.lang.invoke.MethodHandle;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
import org.eclipse.jetty.websocket.javax.common.decoders.RegisteredDecoder;
|
||||||
|
import org.eclipse.jetty.websocket.util.messages.MessageSink;
|
||||||
|
|
||||||
|
public class JavaxWebSocketMessageMetadata
|
||||||
|
{
|
||||||
|
public static enum Type
|
||||||
|
{
|
||||||
|
TEXT,
|
||||||
|
BINARY,
|
||||||
|
TEXT_STREAM,
|
||||||
|
BINARY_STREAM
|
||||||
|
}
|
||||||
|
|
||||||
|
private MethodHandle methodHandle;
|
||||||
|
private Class<? extends MessageSink> sinkClass;
|
||||||
|
private List<RegisteredDecoder> registeredDecoders;
|
||||||
|
|
||||||
|
private int maxMessageSize = -1;
|
||||||
|
private boolean maxMessageSizeSet = false;
|
||||||
|
|
||||||
|
public static JavaxWebSocketMessageMetadata copyOf(JavaxWebSocketMessageMetadata metadata)
|
||||||
|
{
|
||||||
|
if (metadata == null)
|
||||||
|
return null;
|
||||||
|
|
||||||
|
JavaxWebSocketMessageMetadata copy = new JavaxWebSocketMessageMetadata();
|
||||||
|
copy.methodHandle = metadata.methodHandle;
|
||||||
|
copy.sinkClass = metadata.sinkClass;
|
||||||
|
copy.registeredDecoders = metadata.registeredDecoders;
|
||||||
|
copy.maxMessageSize = metadata.maxMessageSize;
|
||||||
|
copy.maxMessageSizeSet = metadata.maxMessageSizeSet;
|
||||||
|
return copy;
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean isMaxMessageSizeSet()
|
||||||
|
{
|
||||||
|
return maxMessageSizeSet;
|
||||||
|
}
|
||||||
|
|
||||||
|
public int getMaxMessageSize()
|
||||||
|
{
|
||||||
|
return maxMessageSize;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setMaxMessageSize(int maxMessageSize)
|
||||||
|
{
|
||||||
|
this.maxMessageSize = maxMessageSize;
|
||||||
|
this.maxMessageSizeSet = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
public MethodHandle getMethodHandle()
|
||||||
|
{
|
||||||
|
return methodHandle;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setMethodHandle(MethodHandle methodHandle)
|
||||||
|
{
|
||||||
|
this.methodHandle = methodHandle;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Class<? extends MessageSink> getSinkClass()
|
||||||
|
{
|
||||||
|
return sinkClass;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setSinkClass(Class<? extends MessageSink> sinkClass)
|
||||||
|
{
|
||||||
|
this.sinkClass = sinkClass;
|
||||||
|
}
|
||||||
|
|
||||||
|
public RegisteredDecoder getRegisteredDecoder()
|
||||||
|
{
|
||||||
|
if (registeredDecoders == null || registeredDecoders.isEmpty())
|
||||||
|
return null;
|
||||||
|
return registeredDecoders.get(0);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setRegisteredDecoder(RegisteredDecoder registeredDecoder)
|
||||||
|
{
|
||||||
|
this.registeredDecoders = List.of(registeredDecoder);
|
||||||
|
}
|
||||||
|
|
||||||
|
public List<RegisteredDecoder> getRegisteredDecoders()
|
||||||
|
{
|
||||||
|
return registeredDecoders;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setRegisteredDecoders(List<RegisteredDecoder> decoders)
|
||||||
|
{
|
||||||
|
this.registeredDecoders = decoders;
|
||||||
|
}
|
||||||
|
}
|
|
@ -59,12 +59,11 @@ public class JavaxWebSocketSession implements javax.websocket.Session
|
||||||
private final JavaxWebSocketContainer container;
|
private final JavaxWebSocketContainer container;
|
||||||
private final CoreSession coreSession;
|
private final CoreSession coreSession;
|
||||||
private final JavaxWebSocketFrameHandler frameHandler;
|
private final JavaxWebSocketFrameHandler frameHandler;
|
||||||
private final EndpointConfig config;
|
|
||||||
private final AvailableDecoders availableDecoders;
|
private final AvailableDecoders availableDecoders;
|
||||||
private final AvailableEncoders availableEncoders;
|
private final AvailableEncoders availableEncoders;
|
||||||
private final Map<String, String> pathParameters;
|
private final Map<String, String> pathParameters;
|
||||||
private final String sessionId;
|
private final String sessionId;
|
||||||
private Map<String, Object> userProperties;
|
private final Map<String, Object> userProperties;
|
||||||
|
|
||||||
private List<Extension> negotiatedExtensions;
|
private List<Extension> negotiatedExtensions;
|
||||||
private JavaxWebSocketAsyncRemote asyncRemote;
|
private JavaxWebSocketAsyncRemote asyncRemote;
|
||||||
|
@ -75,17 +74,17 @@ public class JavaxWebSocketSession implements javax.websocket.Session
|
||||||
JavaxWebSocketFrameHandler frameHandler,
|
JavaxWebSocketFrameHandler frameHandler,
|
||||||
EndpointConfig endpointConfig)
|
EndpointConfig endpointConfig)
|
||||||
{
|
{
|
||||||
|
Objects.requireNonNull(endpointConfig);
|
||||||
this.container = container;
|
this.container = container;
|
||||||
this.coreSession = coreSession;
|
this.coreSession = coreSession;
|
||||||
this.frameHandler = frameHandler;
|
this.frameHandler = frameHandler;
|
||||||
this.sessionId = UUID.randomUUID().toString();
|
this.sessionId = UUID.randomUUID().toString();
|
||||||
this.config = Objects.requireNonNull(endpointConfig);
|
this.availableDecoders = new AvailableDecoders(endpointConfig);
|
||||||
this.availableDecoders = new AvailableDecoders(this.config);
|
this.availableEncoders = new AvailableEncoders(endpointConfig);
|
||||||
this.availableEncoders = new AvailableEncoders(this.config);
|
|
||||||
|
|
||||||
if (this.config instanceof PathParamProvider)
|
if (endpointConfig instanceof PathParamProvider)
|
||||||
{
|
{
|
||||||
PathParamProvider pathParamProvider = (PathParamProvider)this.config;
|
PathParamProvider pathParamProvider = (PathParamProvider)endpointConfig;
|
||||||
this.pathParameters = new HashMap<>(pathParamProvider.getPathParams());
|
this.pathParameters = new HashMap<>(pathParamProvider.getPathParams());
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
|
@ -93,7 +92,7 @@ public class JavaxWebSocketSession implements javax.websocket.Session
|
||||||
this.pathParameters = Collections.emptyMap();
|
this.pathParameters = Collections.emptyMap();
|
||||||
}
|
}
|
||||||
|
|
||||||
this.userProperties = this.config.getUserProperties();
|
this.userProperties = endpointConfig.getUserProperties();
|
||||||
}
|
}
|
||||||
|
|
||||||
public CoreSession getCoreSession()
|
public CoreSession getCoreSession()
|
||||||
|
@ -116,7 +115,7 @@ public class JavaxWebSocketSession implements javax.websocket.Session
|
||||||
LOG.debug("Add MessageHandler.Partial: {}", handler);
|
LOG.debug("Add MessageHandler.Partial: {}", handler);
|
||||||
}
|
}
|
||||||
|
|
||||||
frameHandler.addMessageHandler(this, clazz, handler);
|
frameHandler.addMessageHandler(clazz, handler);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -134,7 +133,7 @@ public class JavaxWebSocketSession implements javax.websocket.Session
|
||||||
LOG.debug("Add MessageHandler.Whole: {}", handler);
|
LOG.debug("Add MessageHandler.Whole: {}", handler);
|
||||||
}
|
}
|
||||||
|
|
||||||
frameHandler.addMessageHandler(this, clazz, handler);
|
frameHandler.addMessageHandler(clazz, handler);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
|
@ -20,82 +20,28 @@ package org.eclipse.jetty.websocket.javax.common.decoders;
|
||||||
|
|
||||||
import java.io.InputStream;
|
import java.io.InputStream;
|
||||||
import java.io.Reader;
|
import java.io.Reader;
|
||||||
import java.lang.reflect.InvocationTargetException;
|
|
||||||
import java.nio.ByteBuffer;
|
import java.nio.ByteBuffer;
|
||||||
import java.util.Iterator;
|
import java.util.Iterator;
|
||||||
import java.util.LinkedList;
|
import java.util.LinkedList;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.NoSuchElementException;
|
|
||||||
import java.util.Objects;
|
import java.util.Objects;
|
||||||
import java.util.stream.Collectors;
|
import java.util.stream.Collectors;
|
||||||
|
import java.util.stream.Stream;
|
||||||
import javax.websocket.Decoder;
|
import javax.websocket.Decoder;
|
||||||
import javax.websocket.EndpointConfig;
|
import javax.websocket.EndpointConfig;
|
||||||
|
|
||||||
import org.eclipse.jetty.websocket.javax.common.InitException;
|
|
||||||
import org.eclipse.jetty.websocket.util.InvalidSignatureException;
|
import org.eclipse.jetty.websocket.util.InvalidSignatureException;
|
||||||
import org.eclipse.jetty.websocket.util.InvalidWebSocketException;
|
import org.eclipse.jetty.websocket.util.InvalidWebSocketException;
|
||||||
import org.eclipse.jetty.websocket.util.ReflectUtils;
|
import org.eclipse.jetty.websocket.util.ReflectUtils;
|
||||||
|
|
||||||
public class AvailableDecoders implements Iterable<AvailableDecoders.RegisteredDecoder>
|
public class AvailableDecoders implements Iterable<RegisteredDecoder>
|
||||||
{
|
{
|
||||||
public static class RegisteredDecoder
|
private final List<RegisteredDecoder> registeredDecoders = new LinkedList<>();
|
||||||
{
|
|
||||||
// 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)
|
|
||||||
public final Class<? extends Decoder> interfaceType;
|
|
||||||
public final Class<?> objectType;
|
|
||||||
public final boolean primitive;
|
|
||||||
public Decoder instance;
|
|
||||||
|
|
||||||
public RegisteredDecoder(Class<? extends Decoder> decoder, Class<? extends Decoder> interfaceType, Class<?> objectType)
|
|
||||||
{
|
|
||||||
this(decoder, interfaceType, objectType, false);
|
|
||||||
}
|
|
||||||
|
|
||||||
public RegisteredDecoder(Class<? extends Decoder> decoder, Class<? extends Decoder> interfaceType, Class<?> objectType, boolean primitive)
|
|
||||||
{
|
|
||||||
this.decoder = decoder;
|
|
||||||
this.interfaceType = interfaceType;
|
|
||||||
this.objectType = objectType;
|
|
||||||
this.primitive = primitive;
|
|
||||||
}
|
|
||||||
|
|
||||||
public boolean implementsInterface(Class<? extends Decoder> type)
|
|
||||||
{
|
|
||||||
return interfaceType.isAssignableFrom(type);
|
|
||||||
}
|
|
||||||
|
|
||||||
public boolean isType(Class<?> type)
|
|
||||||
{
|
|
||||||
return objectType.isAssignableFrom(type);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public String toString()
|
|
||||||
{
|
|
||||||
StringBuilder str = new StringBuilder();
|
|
||||||
str.append(RegisteredDecoder.class.getSimpleName());
|
|
||||||
str.append('[').append(decoder.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 final EndpointConfig config;
|
||||||
private LinkedList<RegisteredDecoder> registeredDecoders;
|
|
||||||
|
|
||||||
public AvailableDecoders(EndpointConfig config)
|
public AvailableDecoders(EndpointConfig config)
|
||||||
{
|
{
|
||||||
Objects.requireNonNull(config);
|
this.config = Objects.requireNonNull(config);
|
||||||
this.config = config;
|
|
||||||
registeredDecoders = new LinkedList<>();
|
|
||||||
|
|
||||||
// TEXT based [via Class reference]
|
// TEXT based [via Class reference]
|
||||||
registerPrimitive(BooleanDecoder.class, Decoder.Text.class, Boolean.class);
|
registerPrimitive(BooleanDecoder.class, Decoder.Text.class, Boolean.class);
|
||||||
|
@ -132,7 +78,7 @@ public class AvailableDecoders implements Iterable<AvailableDecoders.RegisteredD
|
||||||
|
|
||||||
private void registerPrimitive(Class<? extends Decoder> decoderClass, Class<? extends Decoder> interfaceType, Class<?> type)
|
private void registerPrimitive(Class<? extends Decoder> decoderClass, Class<? extends Decoder> interfaceType, Class<?> type)
|
||||||
{
|
{
|
||||||
registeredDecoders.add(new RegisteredDecoder(decoderClass, interfaceType, type, true));
|
registeredDecoders.add(new RegisteredDecoder(decoderClass, interfaceType, type, config, true));
|
||||||
}
|
}
|
||||||
|
|
||||||
public void register(Class<? extends Decoder> decoder)
|
public void register(Class<? extends Decoder> decoder)
|
||||||
|
@ -175,23 +121,10 @@ public class AvailableDecoders implements Iterable<AvailableDecoders.RegisteredD
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO: consider removing (if not used)
|
|
||||||
public void registerAll(Class<? extends Decoder>[] decoders)
|
|
||||||
{
|
|
||||||
if (decoders == null)
|
|
||||||
return;
|
|
||||||
|
|
||||||
for (Class<? extends Decoder> decoder : decoders)
|
|
||||||
{
|
|
||||||
register(decoder);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public void registerAll(List<Class<? extends Decoder>> decoders)
|
public void registerAll(List<Class<? extends Decoder>> decoders)
|
||||||
{
|
{
|
||||||
if (decoders == null)
|
if (decoders == null)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
decoders.forEach(this::register);
|
decoders.forEach(this::register);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -200,52 +133,20 @@ public class AvailableDecoders implements Iterable<AvailableDecoders.RegisteredD
|
||||||
Class<?> objectType = ReflectUtils.findGenericClassFor(decoder, interfaceClass);
|
Class<?> objectType = ReflectUtils.findGenericClassFor(decoder, interfaceClass);
|
||||||
if (objectType == null)
|
if (objectType == null)
|
||||||
{
|
{
|
||||||
StringBuilder err = new StringBuilder();
|
String err = "Unknown Decoder Object type declared for interface " +
|
||||||
err.append("Unknown Decoder Object type declared for interface ");
|
interfaceClass.getName() + " on class " + decoder;
|
||||||
err.append(interfaceClass.getName());
|
throw new InvalidWebSocketException(err);
|
||||||
err.append(" on class ");
|
|
||||||
err.append(decoder);
|
|
||||||
throw new InvalidWebSocketException(err.toString());
|
|
||||||
}
|
}
|
||||||
|
|
||||||
try
|
boolean alreadyRegistered = registeredDecoders.stream().anyMatch(registered ->
|
||||||
{
|
registered.decoder.equals(decoder) && registered.interfaceType.equals(interfaceClass));
|
||||||
RegisteredDecoder conflicts = registeredDecoders.stream()
|
|
||||||
.filter(registered -> registered.isType(objectType))
|
|
||||||
.filter(registered -> !registered.primitive)
|
|
||||||
.findFirst()
|
|
||||||
.get();
|
|
||||||
|
|
||||||
if (conflicts.decoder.equals(decoder) && conflicts.implementsInterface(interfaceClass))
|
// If decoder is already registered for this interfaceType, don't bother adding it again.
|
||||||
{
|
if (!alreadyRegistered)
|
||||||
// Same decoder as what is there already, don't bother adding it again.
|
registeredDecoders.add(0, new RegisteredDecoder(decoder, interfaceClass, objectType, config));
|
||||||
return;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
StringBuilder err = new StringBuilder();
|
public RegisteredDecoder getFirstRegisteredDecoder(Class<?> type)
|
||||||
err.append("Duplicate Decoder Object type ");
|
|
||||||
err.append(objectType.getName());
|
|
||||||
err.append(" in ");
|
|
||||||
err.append(decoder.getName());
|
|
||||||
err.append(", previously declared in ");
|
|
||||||
err.append(conflicts.decoder.getName());
|
|
||||||
throw new InvalidWebSocketException(err.toString());
|
|
||||||
}
|
|
||||||
catch (NoSuchElementException e)
|
|
||||||
{
|
|
||||||
registeredDecoders.addFirst(new RegisteredDecoder(decoder, interfaceClass, objectType));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// TODO: consider removing (if not used)
|
|
||||||
public List<RegisteredDecoder> supporting(Class<? extends Decoder> interfaceType)
|
|
||||||
{
|
|
||||||
return registeredDecoders.stream()
|
|
||||||
.filter(registered -> registered.implementsInterface(interfaceType))
|
|
||||||
.collect(Collectors.toList());
|
|
||||||
}
|
|
||||||
|
|
||||||
public RegisteredDecoder getRegisteredDecoderFor(Class<?> type)
|
|
||||||
{
|
{
|
||||||
return registeredDecoders.stream()
|
return registeredDecoders.stream()
|
||||||
.filter(registered -> registered.isType(type))
|
.filter(registered -> registered.isType(type))
|
||||||
|
@ -253,49 +154,38 @@ public class AvailableDecoders implements Iterable<AvailableDecoders.RegisteredD
|
||||||
.orElse(null);
|
.orElse(null);
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO: consider removing (if not used)
|
public List<RegisteredDecoder> getRegisteredDecoders(Class<?> returnType)
|
||||||
public Class<? extends Decoder> getDecoderFor(Class<?> type)
|
|
||||||
{
|
{
|
||||||
try
|
return registeredDecoders.stream()
|
||||||
{
|
.filter(registered -> registered.isType(returnType))
|
||||||
return getRegisteredDecoderFor(type).decoder;
|
.collect(Collectors.toList());
|
||||||
}
|
|
||||||
catch (NoSuchElementException e)
|
|
||||||
{
|
|
||||||
throw new InvalidWebSocketException("No Decoder found for type " + type);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public <T extends Decoder> T getInstanceOf(RegisteredDecoder registeredDecoder)
|
public List<RegisteredDecoder> getRegisteredDecoders(Class<? extends Decoder> interfaceType, Class<?> returnType)
|
||||||
{
|
{
|
||||||
if (registeredDecoder.instance != null)
|
return registeredDecoders.stream()
|
||||||
{
|
.filter(registered -> registered.interfaceType.equals(interfaceType) && registered.isType(returnType))
|
||||||
return (T)registeredDecoder.instance;
|
.collect(Collectors.toList());
|
||||||
}
|
}
|
||||||
|
|
||||||
try
|
public List<RegisteredDecoder> getTextDecoders(Class<?> returnType)
|
||||||
{
|
{
|
||||||
registeredDecoder.instance = registeredDecoder.decoder.getConstructor().newInstance();
|
return getRegisteredDecoders(Decoder.Text.class, returnType);
|
||||||
registeredDecoder.instance.init(this.config);
|
|
||||||
return (T)registeredDecoder.instance;
|
|
||||||
}
|
|
||||||
catch (InstantiationException | IllegalAccessException | NoSuchMethodException | InvocationTargetException e)
|
|
||||||
{
|
|
||||||
throw new InitException("Unable to init Decoder for type:" + registeredDecoder.decoder.getName(), e);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public <T extends Decoder> T getInstanceFor(Class<?> type)
|
public List<RegisteredDecoder> getBinaryDecoders(Class<?> returnType)
|
||||||
{
|
{
|
||||||
try
|
return getRegisteredDecoders(Decoder.Binary.class, returnType);
|
||||||
{
|
|
||||||
RegisteredDecoder registeredDecoder = getRegisteredDecoderFor(type);
|
|
||||||
return getInstanceOf(registeredDecoder);
|
|
||||||
}
|
}
|
||||||
catch (NoSuchElementException e)
|
|
||||||
|
public List<RegisteredDecoder> getTextStreamDecoders(Class<?> returnType)
|
||||||
{
|
{
|
||||||
throw new InvalidWebSocketException("No Decoder found for type " + type);
|
return getRegisteredDecoders(Decoder.TextStream.class, returnType);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public List<RegisteredDecoder> getBinaryStreamDecoders(Class<?> returnType)
|
||||||
|
{
|
||||||
|
return getRegisteredDecoders(Decoder.BinaryStream.class, returnType);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -303,4 +193,9 @@ public class AvailableDecoders implements Iterable<AvailableDecoders.RegisteredD
|
||||||
{
|
{
|
||||||
return registeredDecoders.iterator();
|
return registeredDecoders.iterator();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public Stream<RegisteredDecoder> stream()
|
||||||
|
{
|
||||||
|
return registeredDecoders.stream();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,97 @@
|
||||||
|
//
|
||||||
|
// ========================================================================
|
||||||
|
// Copyright (c) 1995-2020 Mort Bay Consulting Pty Ltd and others.
|
||||||
|
//
|
||||||
|
// This program and the accompanying materials are made available under
|
||||||
|
// the terms of the Eclipse Public License 2.0 which is available at
|
||||||
|
// https://www.eclipse.org/legal/epl-2.0
|
||||||
|
//
|
||||||
|
// This Source Code may also be made available under the following
|
||||||
|
// Secondary Licenses when the conditions for such availability set
|
||||||
|
// forth in the Eclipse Public License, v. 2.0 are satisfied:
|
||||||
|
// the Apache License v2.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.decoders;
|
||||||
|
|
||||||
|
import java.lang.reflect.InvocationTargetException;
|
||||||
|
import javax.websocket.Decoder;
|
||||||
|
import javax.websocket.EndpointConfig;
|
||||||
|
|
||||||
|
import org.eclipse.jetty.websocket.javax.common.InitException;
|
||||||
|
|
||||||
|
public class RegisteredDecoder
|
||||||
|
{
|
||||||
|
// 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)
|
||||||
|
public final Class<? extends Decoder> interfaceType;
|
||||||
|
public final Class<?> objectType;
|
||||||
|
public final boolean primitive;
|
||||||
|
public final EndpointConfig config;
|
||||||
|
|
||||||
|
private Decoder instance;
|
||||||
|
|
||||||
|
public RegisteredDecoder(Class<? extends Decoder> decoder, Class<? extends Decoder> interfaceType, Class<?> objectType, EndpointConfig endpointConfig)
|
||||||
|
{
|
||||||
|
this(decoder, interfaceType, objectType, endpointConfig, false);
|
||||||
|
}
|
||||||
|
|
||||||
|
public RegisteredDecoder(Class<? extends Decoder> decoder, Class<? extends Decoder> interfaceType, Class<?> objectType, EndpointConfig endpointConfig, boolean primitive)
|
||||||
|
{
|
||||||
|
this.decoder = decoder;
|
||||||
|
this.interfaceType = interfaceType;
|
||||||
|
this.objectType = objectType;
|
||||||
|
this.primitive = primitive;
|
||||||
|
this.config = endpointConfig;
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean implementsInterface(Class<? extends Decoder> type)
|
||||||
|
{
|
||||||
|
return interfaceType.isAssignableFrom(type);
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean isType(Class<?> type)
|
||||||
|
{
|
||||||
|
return objectType.isAssignableFrom(type);
|
||||||
|
}
|
||||||
|
|
||||||
|
public <T extends Decoder> T getInstance()
|
||||||
|
{
|
||||||
|
if (instance == null)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
instance = decoder.getConstructor().newInstance();
|
||||||
|
instance.init(config);
|
||||||
|
return (T)instance;
|
||||||
|
}
|
||||||
|
catch (InstantiationException | IllegalAccessException | NoSuchMethodException | InvocationTargetException e)
|
||||||
|
{
|
||||||
|
throw new InitException("Unable to init Decoder for type:" + decoder.getName(), e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return (T)instance;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String toString()
|
||||||
|
{
|
||||||
|
StringBuilder str = new StringBuilder();
|
||||||
|
str.append(RegisteredDecoder.class.getSimpleName());
|
||||||
|
str.append('[').append(decoder.getName());
|
||||||
|
str.append(',').append(interfaceType.getName());
|
||||||
|
str.append(',').append(objectType.getName());
|
||||||
|
if (primitive)
|
||||||
|
{
|
||||||
|
str.append(",PRIMITIVE");
|
||||||
|
}
|
||||||
|
str.append(']');
|
||||||
|
return str.toString();
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,75 @@
|
||||||
|
//
|
||||||
|
// ========================================================================
|
||||||
|
// Copyright (c) 1995-2020 Mort Bay Consulting Pty Ltd and others.
|
||||||
|
//
|
||||||
|
// This program and the accompanying materials are made available under
|
||||||
|
// the terms of the Eclipse Public License 2.0 which is available at
|
||||||
|
// https://www.eclipse.org/legal/epl-2.0
|
||||||
|
//
|
||||||
|
// This Source Code may also be made available under the following
|
||||||
|
// Secondary Licenses when the conditions for such availability set
|
||||||
|
// forth in the Eclipse Public License, v. 2.0 are satisfied:
|
||||||
|
// the Apache License v2.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.messages;
|
||||||
|
|
||||||
|
import java.lang.invoke.MethodHandle;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.stream.Collectors;
|
||||||
|
import javax.websocket.Decoder;
|
||||||
|
|
||||||
|
import org.eclipse.jetty.util.Callback;
|
||||||
|
import org.eclipse.jetty.websocket.core.CoreSession;
|
||||||
|
import org.eclipse.jetty.websocket.core.Frame;
|
||||||
|
import org.eclipse.jetty.websocket.javax.common.decoders.RegisteredDecoder;
|
||||||
|
import org.eclipse.jetty.websocket.util.messages.MessageSink;
|
||||||
|
import org.slf4j.Logger;
|
||||||
|
import org.slf4j.LoggerFactory;
|
||||||
|
|
||||||
|
public abstract class AbstractDecodedMessageSink<T extends Decoder> implements MessageSink
|
||||||
|
{
|
||||||
|
protected final Logger _logger;
|
||||||
|
protected final CoreSession _coreSession;
|
||||||
|
protected final MethodHandle _methodHandle;
|
||||||
|
protected final MessageSink _messageSink;
|
||||||
|
protected final List<T> _decoders;
|
||||||
|
|
||||||
|
public AbstractDecodedMessageSink(CoreSession coreSession, MethodHandle methodHandle, List<RegisteredDecoder> decoders)
|
||||||
|
{
|
||||||
|
_logger = LoggerFactory.getLogger(getClass());
|
||||||
|
_coreSession = coreSession;
|
||||||
|
_methodHandle = methodHandle;
|
||||||
|
_decoders = decoders.stream()
|
||||||
|
.map(RegisteredDecoder::<T>getInstance)
|
||||||
|
.collect(Collectors.toList());
|
||||||
|
|
||||||
|
try
|
||||||
|
{
|
||||||
|
_messageSink = getMessageSink();
|
||||||
|
}
|
||||||
|
catch (Exception e)
|
||||||
|
{
|
||||||
|
// Throwing from here is an error implementation of the DecodedMessageSink.
|
||||||
|
throw new RuntimeException(e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return a message sink which will first decode the message then pass it to {@link #_methodHandle}.
|
||||||
|
* @throws Exception for any error in creating the message sink.
|
||||||
|
*/
|
||||||
|
abstract MessageSink getMessageSink() throws Exception;
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void accept(Frame frame, Callback callback)
|
||||||
|
{
|
||||||
|
if (_logger.isDebugEnabled())
|
||||||
|
_logger.debug("accepting frame {} for {}", frame, _messageSink);
|
||||||
|
_messageSink.accept(frame, callback);
|
||||||
|
}
|
||||||
|
}
|
|
@ -21,6 +21,7 @@ package org.eclipse.jetty.websocket.javax.common.messages;
|
||||||
import java.lang.invoke.MethodHandle;
|
import java.lang.invoke.MethodHandle;
|
||||||
import java.lang.invoke.MethodType;
|
import java.lang.invoke.MethodType;
|
||||||
import java.nio.ByteBuffer;
|
import java.nio.ByteBuffer;
|
||||||
|
import java.util.List;
|
||||||
import javax.websocket.CloseReason;
|
import javax.websocket.CloseReason;
|
||||||
import javax.websocket.DecodeException;
|
import javax.websocket.DecodeException;
|
||||||
import javax.websocket.Decoder;
|
import javax.websocket.Decoder;
|
||||||
|
@ -28,46 +29,38 @@ import javax.websocket.Decoder;
|
||||||
import org.eclipse.jetty.websocket.core.CoreSession;
|
import org.eclipse.jetty.websocket.core.CoreSession;
|
||||||
import org.eclipse.jetty.websocket.core.exception.CloseException;
|
import org.eclipse.jetty.websocket.core.exception.CloseException;
|
||||||
import org.eclipse.jetty.websocket.javax.common.JavaxWebSocketFrameHandlerFactory;
|
import org.eclipse.jetty.websocket.javax.common.JavaxWebSocketFrameHandlerFactory;
|
||||||
|
import org.eclipse.jetty.websocket.javax.common.decoders.RegisteredDecoder;
|
||||||
import org.eclipse.jetty.websocket.util.messages.ByteBufferMessageSink;
|
import org.eclipse.jetty.websocket.util.messages.ByteBufferMessageSink;
|
||||||
import org.eclipse.jetty.websocket.util.messages.MessageSink;
|
import org.eclipse.jetty.websocket.util.messages.MessageSink;
|
||||||
|
|
||||||
public class DecodedBinaryMessageSink<T> extends DecodedMessageSink<Decoder.Binary<T>>
|
public class DecodedBinaryMessageSink<T> extends AbstractDecodedMessageSink<Decoder.Binary<T>>
|
||||||
{
|
{
|
||||||
public DecodedBinaryMessageSink(CoreSession session,
|
public DecodedBinaryMessageSink(CoreSession session, MethodHandle methodHandle, List<RegisteredDecoder> decoders)
|
||||||
Decoder.Binary<T> decoder,
|
|
||||||
MethodHandle methodHandle)
|
|
||||||
throws NoSuchMethodException, IllegalAccessException
|
|
||||||
{
|
{
|
||||||
super(session, decoder, methodHandle);
|
super(session, methodHandle, decoders);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected MethodHandle newRawMethodHandle() throws NoSuchMethodException, IllegalAccessException
|
MessageSink getMessageSink() throws Exception
|
||||||
{
|
{
|
||||||
return JavaxWebSocketFrameHandlerFactory.getServerMethodHandleLookup().findVirtual(DecodedBinaryMessageSink.class,
|
MethodHandle methodHandle = JavaxWebSocketFrameHandlerFactory.getServerMethodHandleLookup().findVirtual(DecodedBinaryMessageSink.class,
|
||||||
"onWholeMessage", MethodType.methodType(void.class, ByteBuffer.class))
|
"onWholeMessage", MethodType.methodType(void.class, ByteBuffer.class))
|
||||||
.bindTo(this);
|
.bindTo(this);
|
||||||
}
|
return new ByteBufferMessageSink(_coreSession, methodHandle);
|
||||||
|
|
||||||
@Override
|
|
||||||
protected MessageSink newRawMessageSink(CoreSession session, MethodHandle rawMethodHandle)
|
|
||||||
{
|
|
||||||
return new ByteBufferMessageSink(session, rawMethodHandle);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@SuppressWarnings("Duplicates")
|
@SuppressWarnings("Duplicates")
|
||||||
public void onWholeMessage(ByteBuffer wholeMessage)
|
public void onWholeMessage(ByteBuffer wholeMessage)
|
||||||
{
|
{
|
||||||
if (!getDecoder().willDecode(wholeMessage))
|
for (Decoder.Binary<T> decoder : _decoders)
|
||||||
|
{
|
||||||
|
if (decoder.willDecode(wholeMessage))
|
||||||
{
|
{
|
||||||
logger.warn("Message lost, decoder " + getDecoder().getClass().getName() + "#willDecode() has rejected it.");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
T obj = getDecoder().decode(wholeMessage);
|
T obj = decoder.decode(wholeMessage);
|
||||||
methodHandle.invoke(obj);
|
_methodHandle.invoke(obj);
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
catch (DecodeException e)
|
catch (DecodeException e)
|
||||||
{
|
{
|
||||||
|
@ -79,3 +72,5 @@ public class DecodedBinaryMessageSink<T> extends DecodedMessageSink<Decoder.Bina
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
@ -21,6 +21,7 @@ package org.eclipse.jetty.websocket.javax.common.messages;
|
||||||
import java.io.InputStream;
|
import java.io.InputStream;
|
||||||
import java.lang.invoke.MethodHandle;
|
import java.lang.invoke.MethodHandle;
|
||||||
import java.lang.invoke.MethodType;
|
import java.lang.invoke.MethodType;
|
||||||
|
import java.util.List;
|
||||||
import javax.websocket.CloseReason;
|
import javax.websocket.CloseReason;
|
||||||
import javax.websocket.DecodeException;
|
import javax.websocket.DecodeException;
|
||||||
import javax.websocket.Decoder;
|
import javax.websocket.Decoder;
|
||||||
|
@ -28,40 +29,36 @@ import javax.websocket.Decoder;
|
||||||
import org.eclipse.jetty.websocket.core.CoreSession;
|
import org.eclipse.jetty.websocket.core.CoreSession;
|
||||||
import org.eclipse.jetty.websocket.core.exception.CloseException;
|
import org.eclipse.jetty.websocket.core.exception.CloseException;
|
||||||
import org.eclipse.jetty.websocket.javax.common.JavaxWebSocketFrameHandlerFactory;
|
import org.eclipse.jetty.websocket.javax.common.JavaxWebSocketFrameHandlerFactory;
|
||||||
|
import org.eclipse.jetty.websocket.javax.common.decoders.RegisteredDecoder;
|
||||||
import org.eclipse.jetty.websocket.util.messages.InputStreamMessageSink;
|
import org.eclipse.jetty.websocket.util.messages.InputStreamMessageSink;
|
||||||
import org.eclipse.jetty.websocket.util.messages.MessageSink;
|
import org.eclipse.jetty.websocket.util.messages.MessageSink;
|
||||||
|
|
||||||
public class DecodedBinaryStreamMessageSink<T> extends DecodedMessageSink<Decoder.BinaryStream<T>>
|
public class DecodedBinaryStreamMessageSink<T> extends AbstractDecodedMessageSink<Decoder.BinaryStream<T>>
|
||||||
{
|
{
|
||||||
public DecodedBinaryStreamMessageSink(CoreSession session,
|
public DecodedBinaryStreamMessageSink(CoreSession session, MethodHandle methodHandle, List<RegisteredDecoder> decoders) throws NoSuchMethodException, IllegalAccessException
|
||||||
Decoder.BinaryStream<T> decoder,
|
|
||||||
MethodHandle methodHandle)
|
|
||||||
throws NoSuchMethodException, IllegalAccessException
|
|
||||||
{
|
{
|
||||||
super(session, decoder, methodHandle);
|
super(session, methodHandle, decoders);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected MethodHandle newRawMethodHandle() throws NoSuchMethodException, IllegalAccessException
|
MessageSink getMessageSink() throws Exception
|
||||||
{
|
{
|
||||||
return JavaxWebSocketFrameHandlerFactory.getServerMethodHandleLookup().findVirtual(DecodedBinaryStreamMessageSink.class,
|
MethodHandle methodHandle = JavaxWebSocketFrameHandlerFactory.getServerMethodHandleLookup().findVirtual(DecodedBinaryStreamMessageSink.class,
|
||||||
"onStreamStart", MethodType.methodType(void.class, InputStream.class))
|
"onStreamStart", MethodType.methodType(void.class, InputStream.class))
|
||||||
.bindTo(this);
|
.bindTo(this);
|
||||||
}
|
return new InputStreamMessageSink(_coreSession, methodHandle);
|
||||||
|
|
||||||
@Override
|
|
||||||
protected MessageSink newRawMessageSink(CoreSession session, MethodHandle rawMethodHandle)
|
|
||||||
{
|
|
||||||
return new InputStreamMessageSink(session, rawMethodHandle);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@SuppressWarnings("Duplicates")
|
@SuppressWarnings("Duplicates")
|
||||||
public void onStreamStart(InputStream stream)
|
public void onStreamStart(InputStream stream)
|
||||||
|
{
|
||||||
|
for (Decoder.BinaryStream<T> decoder : _decoders)
|
||||||
{
|
{
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
T obj = getDecoder().decode(stream);
|
T obj = decoder.decode(stream);
|
||||||
methodHandle.invoke(obj);
|
_methodHandle.invoke(obj);
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
catch (DecodeException e)
|
catch (DecodeException e)
|
||||||
{
|
{
|
||||||
|
@ -73,3 +70,4 @@ public class DecodedBinaryStreamMessageSink<T> extends DecodedMessageSink<Decode
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
|
@ -1,64 +0,0 @@
|
||||||
//
|
|
||||||
// ========================================================================
|
|
||||||
// Copyright (c) 1995-2020 Mort Bay Consulting Pty Ltd and others.
|
|
||||||
//
|
|
||||||
// This program and the accompanying materials are made available under
|
|
||||||
// the terms of the Eclipse Public License 2.0 which is available at
|
|
||||||
// https://www.eclipse.org/legal/epl-2.0
|
|
||||||
//
|
|
||||||
// This Source Code may also be made available under the following
|
|
||||||
// Secondary Licenses when the conditions for such availability set
|
|
||||||
// forth in the Eclipse Public License, v. 2.0 are satisfied:
|
|
||||||
// the Apache License v2.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.messages;
|
|
||||||
|
|
||||||
import java.lang.invoke.MethodHandle;
|
|
||||||
import javax.websocket.Decoder;
|
|
||||||
|
|
||||||
import org.eclipse.jetty.util.Callback;
|
|
||||||
import org.eclipse.jetty.websocket.core.CoreSession;
|
|
||||||
import org.eclipse.jetty.websocket.core.Frame;
|
|
||||||
import org.eclipse.jetty.websocket.util.messages.AbstractMessageSink;
|
|
||||||
import org.eclipse.jetty.websocket.util.messages.MessageSink;
|
|
||||||
import org.slf4j.Logger;
|
|
||||||
import org.slf4j.LoggerFactory;
|
|
||||||
|
|
||||||
public abstract class DecodedMessageSink<T extends Decoder> extends AbstractMessageSink
|
|
||||||
{
|
|
||||||
protected final Logger logger;
|
|
||||||
private final T decoder;
|
|
||||||
private final MethodHandle rawMethodHandle;
|
|
||||||
private final MessageSink rawMessageSink;
|
|
||||||
|
|
||||||
public DecodedMessageSink(CoreSession session, T decoder, MethodHandle methodHandle)
|
|
||||||
throws NoSuchMethodException, IllegalAccessException
|
|
||||||
{
|
|
||||||
super(session, methodHandle);
|
|
||||||
this.logger = LoggerFactory.getLogger(this.getClass());
|
|
||||||
this.decoder = decoder;
|
|
||||||
this.rawMethodHandle = newRawMethodHandle();
|
|
||||||
this.rawMessageSink = newRawMessageSink(session, rawMethodHandle);
|
|
||||||
}
|
|
||||||
|
|
||||||
protected abstract MethodHandle newRawMethodHandle()
|
|
||||||
throws NoSuchMethodException, IllegalAccessException;
|
|
||||||
|
|
||||||
protected abstract MessageSink newRawMessageSink(CoreSession session, MethodHandle rawMethodHandle);
|
|
||||||
|
|
||||||
public T getDecoder()
|
|
||||||
{
|
|
||||||
return decoder;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void accept(Frame frame, Callback callback)
|
|
||||||
{
|
|
||||||
this.rawMessageSink.accept(frame, callback);
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -20,6 +20,7 @@ package org.eclipse.jetty.websocket.javax.common.messages;
|
||||||
|
|
||||||
import java.lang.invoke.MethodHandle;
|
import java.lang.invoke.MethodHandle;
|
||||||
import java.lang.invoke.MethodType;
|
import java.lang.invoke.MethodType;
|
||||||
|
import java.util.List;
|
||||||
import javax.websocket.CloseReason;
|
import javax.websocket.CloseReason;
|
||||||
import javax.websocket.DecodeException;
|
import javax.websocket.DecodeException;
|
||||||
import javax.websocket.Decoder;
|
import javax.websocket.Decoder;
|
||||||
|
@ -27,46 +28,37 @@ import javax.websocket.Decoder;
|
||||||
import org.eclipse.jetty.websocket.core.CoreSession;
|
import org.eclipse.jetty.websocket.core.CoreSession;
|
||||||
import org.eclipse.jetty.websocket.core.exception.CloseException;
|
import org.eclipse.jetty.websocket.core.exception.CloseException;
|
||||||
import org.eclipse.jetty.websocket.javax.common.JavaxWebSocketFrameHandlerFactory;
|
import org.eclipse.jetty.websocket.javax.common.JavaxWebSocketFrameHandlerFactory;
|
||||||
|
import org.eclipse.jetty.websocket.javax.common.decoders.RegisteredDecoder;
|
||||||
import org.eclipse.jetty.websocket.util.messages.MessageSink;
|
import org.eclipse.jetty.websocket.util.messages.MessageSink;
|
||||||
import org.eclipse.jetty.websocket.util.messages.StringMessageSink;
|
import org.eclipse.jetty.websocket.util.messages.StringMessageSink;
|
||||||
|
|
||||||
public class DecodedTextMessageSink<T> extends DecodedMessageSink<Decoder.Text<T>>
|
public class DecodedTextMessageSink<T> extends AbstractDecodedMessageSink<Decoder.Text<T>>
|
||||||
{
|
{
|
||||||
public DecodedTextMessageSink(CoreSession session,
|
public DecodedTextMessageSink(CoreSession session, MethodHandle methodHandle, List<RegisteredDecoder> decoders) throws NoSuchMethodException, IllegalAccessException
|
||||||
Decoder.Text<T> decoder,
|
|
||||||
MethodHandle methodHandle)
|
|
||||||
throws NoSuchMethodException, IllegalAccessException
|
|
||||||
{
|
{
|
||||||
super(session, decoder, methodHandle);
|
super(session, methodHandle, decoders);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected MethodHandle newRawMethodHandle() throws NoSuchMethodException, IllegalAccessException
|
MessageSink getMessageSink() throws NoSuchMethodException, IllegalAccessException
|
||||||
{
|
{
|
||||||
return JavaxWebSocketFrameHandlerFactory.getServerMethodHandleLookup().findVirtual(DecodedTextMessageSink.class,
|
MethodHandle methodHandle = JavaxWebSocketFrameHandlerFactory.getServerMethodHandleLookup()
|
||||||
"onWholeMessage", MethodType.methodType(void.class, String.class))
|
.findVirtual(getClass(), "onMessage", MethodType.methodType(void.class, String.class))
|
||||||
.bindTo(this);
|
.bindTo(this);
|
||||||
|
return new StringMessageSink(_coreSession, methodHandle);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
public void onMessage(String wholeMessage)
|
||||||
protected MessageSink newRawMessageSink(CoreSession session, MethodHandle rawMethodHandle)
|
|
||||||
{
|
{
|
||||||
return new StringMessageSink(session, rawMethodHandle);
|
for (Decoder.Text<T> decoder : _decoders)
|
||||||
}
|
|
||||||
|
|
||||||
@SuppressWarnings("Duplicates")
|
|
||||||
public void onWholeMessage(String wholeMessage)
|
|
||||||
{
|
{
|
||||||
if (!getDecoder().willDecode(wholeMessage))
|
if (decoder.willDecode(wholeMessage))
|
||||||
{
|
{
|
||||||
logger.warn("Message lost, decoder " + getDecoder().getClass().getName() + "#willDecode() has rejected it.");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
T obj = getDecoder().decode(wholeMessage);
|
T obj = decoder.decode(wholeMessage);
|
||||||
methodHandle.invoke(obj);
|
_methodHandle.invoke(obj);
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
catch (DecodeException e)
|
catch (DecodeException e)
|
||||||
{
|
{
|
||||||
|
@ -78,3 +70,5 @@ public class DecodedTextMessageSink<T> extends DecodedMessageSink<Decoder.Text<T
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
@ -21,6 +21,7 @@ package org.eclipse.jetty.websocket.javax.common.messages;
|
||||||
import java.io.Reader;
|
import java.io.Reader;
|
||||||
import java.lang.invoke.MethodHandle;
|
import java.lang.invoke.MethodHandle;
|
||||||
import java.lang.invoke.MethodType;
|
import java.lang.invoke.MethodType;
|
||||||
|
import java.util.List;
|
||||||
import javax.websocket.CloseReason;
|
import javax.websocket.CloseReason;
|
||||||
import javax.websocket.DecodeException;
|
import javax.websocket.DecodeException;
|
||||||
import javax.websocket.Decoder;
|
import javax.websocket.Decoder;
|
||||||
|
@ -28,40 +29,35 @@ import javax.websocket.Decoder;
|
||||||
import org.eclipse.jetty.websocket.core.CoreSession;
|
import org.eclipse.jetty.websocket.core.CoreSession;
|
||||||
import org.eclipse.jetty.websocket.core.exception.CloseException;
|
import org.eclipse.jetty.websocket.core.exception.CloseException;
|
||||||
import org.eclipse.jetty.websocket.javax.common.JavaxWebSocketFrameHandlerFactory;
|
import org.eclipse.jetty.websocket.javax.common.JavaxWebSocketFrameHandlerFactory;
|
||||||
|
import org.eclipse.jetty.websocket.javax.common.decoders.RegisteredDecoder;
|
||||||
import org.eclipse.jetty.websocket.util.messages.MessageSink;
|
import org.eclipse.jetty.websocket.util.messages.MessageSink;
|
||||||
import org.eclipse.jetty.websocket.util.messages.ReaderMessageSink;
|
import org.eclipse.jetty.websocket.util.messages.ReaderMessageSink;
|
||||||
|
|
||||||
public class DecodedTextStreamMessageSink<T> extends DecodedMessageSink<Decoder.TextStream<T>>
|
public class DecodedTextStreamMessageSink<T> extends AbstractDecodedMessageSink<Decoder.TextStream<T>>
|
||||||
{
|
{
|
||||||
public DecodedTextStreamMessageSink(CoreSession session,
|
public DecodedTextStreamMessageSink(CoreSession session, MethodHandle methodHandle, List<RegisteredDecoder> decoders) throws NoSuchMethodException, IllegalAccessException
|
||||||
Decoder.TextStream<T> decoder,
|
|
||||||
MethodHandle methodHandle)
|
|
||||||
throws NoSuchMethodException, IllegalAccessException
|
|
||||||
{
|
{
|
||||||
super(session, decoder, methodHandle);
|
super(session, methodHandle, decoders);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected MethodHandle newRawMethodHandle() throws NoSuchMethodException, IllegalAccessException
|
MessageSink getMessageSink() throws Exception
|
||||||
{
|
{
|
||||||
return JavaxWebSocketFrameHandlerFactory.getServerMethodHandleLookup().findVirtual(DecodedTextStreamMessageSink.class,
|
MethodHandle methodHandle = JavaxWebSocketFrameHandlerFactory.getServerMethodHandleLookup().findVirtual(DecodedTextStreamMessageSink.class,
|
||||||
"onStreamStart", MethodType.methodType(void.class, Reader.class))
|
"onStreamStart", MethodType.methodType(void.class, Reader.class))
|
||||||
.bindTo(this);
|
.bindTo(this);
|
||||||
|
return new ReaderMessageSink(_coreSession, methodHandle);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
|
||||||
protected MessageSink newRawMessageSink(CoreSession session, MethodHandle rawMethodHandle)
|
|
||||||
{
|
|
||||||
return new ReaderMessageSink(session, rawMethodHandle);
|
|
||||||
}
|
|
||||||
|
|
||||||
@SuppressWarnings("Duplicates")
|
|
||||||
public void onStreamStart(Reader reader)
|
public void onStreamStart(Reader reader)
|
||||||
|
{
|
||||||
|
for (Decoder.TextStream<T> decoder : _decoders)
|
||||||
{
|
{
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
T obj = getDecoder().decode(reader);
|
T obj = decoder.decode(reader);
|
||||||
methodHandle.invoke(obj);
|
_methodHandle.invoke(obj);
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
catch (DecodeException e)
|
catch (DecodeException e)
|
||||||
{
|
{
|
||||||
|
@ -73,3 +69,4 @@ public class DecodedTextStreamMessageSink<T> extends DecodedMessageSink<Decoder.
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
|
@ -20,13 +20,34 @@ package org.eclipse.jetty.websocket.javax.common.messages;
|
||||||
|
|
||||||
import java.lang.invoke.MethodHandle;
|
import java.lang.invoke.MethodHandle;
|
||||||
import java.lang.invoke.MethodType;
|
import java.lang.invoke.MethodType;
|
||||||
|
import java.util.List;
|
||||||
import java.util.function.Consumer;
|
import java.util.function.Consumer;
|
||||||
|
import javax.websocket.ClientEndpointConfig;
|
||||||
|
import javax.websocket.Decoder;
|
||||||
|
|
||||||
import org.eclipse.jetty.websocket.javax.common.AbstractSessionTest;
|
import org.eclipse.jetty.websocket.javax.common.AbstractSessionTest;
|
||||||
import org.eclipse.jetty.websocket.javax.common.JavaxWebSocketFrameHandlerFactory;
|
import org.eclipse.jetty.websocket.javax.common.JavaxWebSocketFrameHandlerFactory;
|
||||||
|
import org.eclipse.jetty.websocket.javax.common.decoders.RegisteredDecoder;
|
||||||
|
|
||||||
public abstract class AbstractMessageSinkTest extends AbstractSessionTest
|
public abstract class AbstractMessageSinkTest extends AbstractSessionTest
|
||||||
{
|
{
|
||||||
|
public List<RegisteredDecoder> toRegisteredDecoderList(Class<? extends Decoder> clazz, Class<?> objectType)
|
||||||
|
{
|
||||||
|
Class<? extends Decoder> interfaceType;
|
||||||
|
if (Decoder.Text.class.isAssignableFrom(clazz))
|
||||||
|
interfaceType = Decoder.Text.class;
|
||||||
|
else if (Decoder.Binary.class.isAssignableFrom(clazz))
|
||||||
|
interfaceType = Decoder.Binary.class;
|
||||||
|
else if (Decoder.TextStream.class.isAssignableFrom(clazz))
|
||||||
|
interfaceType = Decoder.TextStream.class;
|
||||||
|
else if (Decoder.BinaryStream.class.isAssignableFrom(clazz))
|
||||||
|
interfaceType = Decoder.BinaryStream.class;
|
||||||
|
else
|
||||||
|
throw new IllegalStateException();
|
||||||
|
|
||||||
|
return List.of(new RegisteredDecoder(clazz, interfaceType, objectType, ClientEndpointConfig.Builder.create().build()));
|
||||||
|
}
|
||||||
|
|
||||||
public <T> MethodHandle getAcceptHandle(Consumer<T> copy, Class<T> type)
|
public <T> MethodHandle getAcceptHandle(Consumer<T> copy, Class<T> type)
|
||||||
{
|
{
|
||||||
try
|
try
|
||||||
|
|
|
@ -22,6 +22,7 @@ import java.lang.invoke.MethodHandle;
|
||||||
import java.nio.ByteBuffer;
|
import java.nio.ByteBuffer;
|
||||||
import java.text.SimpleDateFormat;
|
import java.text.SimpleDateFormat;
|
||||||
import java.util.Calendar;
|
import java.util.Calendar;
|
||||||
|
import java.util.List;
|
||||||
import java.util.TimeZone;
|
import java.util.TimeZone;
|
||||||
import java.util.concurrent.CompletableFuture;
|
import java.util.concurrent.CompletableFuture;
|
||||||
import java.util.concurrent.TimeUnit;
|
import java.util.concurrent.TimeUnit;
|
||||||
|
@ -34,6 +35,7 @@ import org.eclipse.jetty.util.FutureCallback;
|
||||||
import org.eclipse.jetty.websocket.core.Frame;
|
import org.eclipse.jetty.websocket.core.Frame;
|
||||||
import org.eclipse.jetty.websocket.core.OpCode;
|
import org.eclipse.jetty.websocket.core.OpCode;
|
||||||
import org.eclipse.jetty.websocket.javax.common.AbstractSessionTest;
|
import org.eclipse.jetty.websocket.javax.common.AbstractSessionTest;
|
||||||
|
import org.eclipse.jetty.websocket.javax.common.decoders.RegisteredDecoder;
|
||||||
import org.junit.jupiter.api.Test;
|
import org.junit.jupiter.api.Test;
|
||||||
|
|
||||||
import static org.hamcrest.MatcherAssert.assertThat;
|
import static org.hamcrest.MatcherAssert.assertThat;
|
||||||
|
@ -49,8 +51,8 @@ public class DecodedBinaryMessageSinkTest extends AbstractMessageSinkTest
|
||||||
CompletableFuture<Calendar> copyFuture = new CompletableFuture<>();
|
CompletableFuture<Calendar> copyFuture = new CompletableFuture<>();
|
||||||
DecodedCalendarCopy copy = new DecodedCalendarCopy(copyFuture);
|
DecodedCalendarCopy copy = new DecodedCalendarCopy(copyFuture);
|
||||||
MethodHandle copyHandle = getAcceptHandle(copy, Calendar.class);
|
MethodHandle copyHandle = getAcceptHandle(copy, Calendar.class);
|
||||||
Decoder.Binary<Calendar> decoder = new GmtDecoder();
|
List<RegisteredDecoder> decoders = toRegisteredDecoderList(GmtDecoder.class, Calendar.class);
|
||||||
DecodedBinaryMessageSink sink = new DecodedBinaryMessageSink(AbstractSessionTest.session.getCoreSession(), decoder, copyHandle);
|
DecodedBinaryMessageSink<Calendar> sink = new DecodedBinaryMessageSink<>(AbstractSessionTest.session.getCoreSession(), copyHandle, decoders);
|
||||||
|
|
||||||
FutureCallback finCallback = new FutureCallback();
|
FutureCallback finCallback = new FutureCallback();
|
||||||
ByteBuffer data = ByteBuffer.allocate(16);
|
ByteBuffer data = ByteBuffer.allocate(16);
|
||||||
|
@ -72,8 +74,8 @@ public class DecodedBinaryMessageSinkTest extends AbstractMessageSinkTest
|
||||||
CompletableFuture<Calendar> copyFuture = new CompletableFuture<>();
|
CompletableFuture<Calendar> copyFuture = new CompletableFuture<>();
|
||||||
DecodedCalendarCopy copy = new DecodedCalendarCopy(copyFuture);
|
DecodedCalendarCopy copy = new DecodedCalendarCopy(copyFuture);
|
||||||
MethodHandle copyHandle = getAcceptHandle(copy, Calendar.class);
|
MethodHandle copyHandle = getAcceptHandle(copy, Calendar.class);
|
||||||
Decoder.Binary<Calendar> decoder = new GmtDecoder();
|
List<RegisteredDecoder> decoders = toRegisteredDecoderList(GmtDecoder.class, Calendar.class);
|
||||||
DecodedBinaryMessageSink sink = new DecodedBinaryMessageSink(AbstractSessionTest.session.getCoreSession(), decoder, copyHandle);
|
DecodedBinaryMessageSink<Calendar> sink = new DecodedBinaryMessageSink<>(AbstractSessionTest.session.getCoreSession(), copyHandle, decoders);
|
||||||
|
|
||||||
FutureCallback callback1 = new FutureCallback();
|
FutureCallback callback1 = new FutureCallback();
|
||||||
FutureCallback callback2 = new FutureCallback();
|
FutureCallback callback2 = new FutureCallback();
|
||||||
|
|
|
@ -24,6 +24,7 @@ import java.lang.invoke.MethodHandle;
|
||||||
import java.nio.ByteBuffer;
|
import java.nio.ByteBuffer;
|
||||||
import java.text.SimpleDateFormat;
|
import java.text.SimpleDateFormat;
|
||||||
import java.util.Calendar;
|
import java.util.Calendar;
|
||||||
|
import java.util.List;
|
||||||
import java.util.TimeZone;
|
import java.util.TimeZone;
|
||||||
import java.util.concurrent.CompletableFuture;
|
import java.util.concurrent.CompletableFuture;
|
||||||
import java.util.concurrent.TimeUnit;
|
import java.util.concurrent.TimeUnit;
|
||||||
|
@ -36,6 +37,7 @@ import org.eclipse.jetty.util.BufferUtil;
|
||||||
import org.eclipse.jetty.util.FutureCallback;
|
import org.eclipse.jetty.util.FutureCallback;
|
||||||
import org.eclipse.jetty.websocket.core.Frame;
|
import org.eclipse.jetty.websocket.core.Frame;
|
||||||
import org.eclipse.jetty.websocket.core.OpCode;
|
import org.eclipse.jetty.websocket.core.OpCode;
|
||||||
|
import org.eclipse.jetty.websocket.javax.common.decoders.RegisteredDecoder;
|
||||||
import org.junit.jupiter.api.Test;
|
import org.junit.jupiter.api.Test;
|
||||||
|
|
||||||
import static org.hamcrest.MatcherAssert.assertThat;
|
import static org.hamcrest.MatcherAssert.assertThat;
|
||||||
|
@ -51,8 +53,8 @@ public class DecodedBinaryStreamMessageSinkTest extends AbstractMessageSinkTest
|
||||||
CompletableFuture<Calendar> copyFuture = new CompletableFuture<>();
|
CompletableFuture<Calendar> copyFuture = new CompletableFuture<>();
|
||||||
DecodedCalendarCopy copy = new DecodedCalendarCopy(copyFuture);
|
DecodedCalendarCopy copy = new DecodedCalendarCopy(copyFuture);
|
||||||
MethodHandle copyHandle = getAcceptHandle(copy, Calendar.class);
|
MethodHandle copyHandle = getAcceptHandle(copy, Calendar.class);
|
||||||
Decoder.BinaryStream<Calendar> decoder = new GmtDecoder();
|
List<RegisteredDecoder> decoders = toRegisteredDecoderList(GmtDecoder.class, Calendar.class);
|
||||||
DecodedBinaryStreamMessageSink sink = new DecodedBinaryStreamMessageSink(session.getCoreSession(), decoder, copyHandle);
|
DecodedBinaryStreamMessageSink<Calendar> sink = new DecodedBinaryStreamMessageSink<>(session.getCoreSession(), copyHandle, decoders);
|
||||||
|
|
||||||
FutureCallback finCallback = new FutureCallback();
|
FutureCallback finCallback = new FutureCallback();
|
||||||
ByteBuffer data = ByteBuffer.allocate(16);
|
ByteBuffer data = ByteBuffer.allocate(16);
|
||||||
|
@ -74,8 +76,8 @@ public class DecodedBinaryStreamMessageSinkTest extends AbstractMessageSinkTest
|
||||||
CompletableFuture<Calendar> copyFuture = new CompletableFuture<>();
|
CompletableFuture<Calendar> copyFuture = new CompletableFuture<>();
|
||||||
DecodedCalendarCopy copy = new DecodedCalendarCopy(copyFuture);
|
DecodedCalendarCopy copy = new DecodedCalendarCopy(copyFuture);
|
||||||
MethodHandle copyHandle = getAcceptHandle(copy, Calendar.class);
|
MethodHandle copyHandle = getAcceptHandle(copy, Calendar.class);
|
||||||
Decoder.BinaryStream<Calendar> decoder = new GmtDecoder();
|
List<RegisteredDecoder> decoders = toRegisteredDecoderList(GmtDecoder.class, Calendar.class);
|
||||||
DecodedBinaryStreamMessageSink sink = new DecodedBinaryStreamMessageSink(session.getCoreSession(), decoder, copyHandle);
|
DecodedBinaryStreamMessageSink<Calendar> sink = new DecodedBinaryStreamMessageSink<>(session.getCoreSession(), copyHandle, decoders);
|
||||||
|
|
||||||
FutureCallback callback1 = new FutureCallback();
|
FutureCallback callback1 = new FutureCallback();
|
||||||
FutureCallback callback2 = new FutureCallback();
|
FutureCallback callback2 = new FutureCallback();
|
||||||
|
|
|
@ -21,7 +21,9 @@ package org.eclipse.jetty.websocket.javax.common.messages;
|
||||||
import java.lang.invoke.MethodHandle;
|
import java.lang.invoke.MethodHandle;
|
||||||
import java.text.ParseException;
|
import java.text.ParseException;
|
||||||
import java.text.SimpleDateFormat;
|
import java.text.SimpleDateFormat;
|
||||||
|
import java.util.Calendar;
|
||||||
import java.util.Date;
|
import java.util.Date;
|
||||||
|
import java.util.List;
|
||||||
import java.util.TimeZone;
|
import java.util.TimeZone;
|
||||||
import java.util.concurrent.CompletableFuture;
|
import java.util.concurrent.CompletableFuture;
|
||||||
import java.util.concurrent.TimeUnit;
|
import java.util.concurrent.TimeUnit;
|
||||||
|
@ -33,6 +35,7 @@ import javax.websocket.EndpointConfig;
|
||||||
import org.eclipse.jetty.util.FutureCallback;
|
import org.eclipse.jetty.util.FutureCallback;
|
||||||
import org.eclipse.jetty.websocket.core.Frame;
|
import org.eclipse.jetty.websocket.core.Frame;
|
||||||
import org.eclipse.jetty.websocket.core.OpCode;
|
import org.eclipse.jetty.websocket.core.OpCode;
|
||||||
|
import org.eclipse.jetty.websocket.javax.common.decoders.RegisteredDecoder;
|
||||||
import org.junit.jupiter.api.Test;
|
import org.junit.jupiter.api.Test;
|
||||||
|
|
||||||
import static org.hamcrest.MatcherAssert.assertThat;
|
import static org.hamcrest.MatcherAssert.assertThat;
|
||||||
|
@ -48,8 +51,8 @@ public class DecodedTextMessageSinkTest extends AbstractMessageSinkTest
|
||||||
CompletableFuture<Date> copyFuture = new CompletableFuture<>();
|
CompletableFuture<Date> copyFuture = new CompletableFuture<>();
|
||||||
DecodedDateCopy copy = new DecodedDateCopy(copyFuture);
|
DecodedDateCopy copy = new DecodedDateCopy(copyFuture);
|
||||||
MethodHandle copyHandle = getAcceptHandle(copy, Date.class);
|
MethodHandle copyHandle = getAcceptHandle(copy, Date.class);
|
||||||
Decoder.Text<Date> decoder = new GmtDecoder();
|
List<RegisteredDecoder> decoders = toRegisteredDecoderList(DecodedBinaryStreamMessageSinkTest.GmtDecoder.class, Calendar.class);
|
||||||
DecodedTextMessageSink sink = new DecodedTextMessageSink(session.getCoreSession(), decoder, copyHandle);
|
DecodedTextMessageSink<Calendar> sink = new DecodedTextMessageSink<>(session.getCoreSession(), copyHandle, decoders);
|
||||||
|
|
||||||
FutureCallback finCallback = new FutureCallback();
|
FutureCallback finCallback = new FutureCallback();
|
||||||
sink.accept(new Frame(OpCode.TEXT).setPayload("2018.02.13").setFin(true), finCallback);
|
sink.accept(new Frame(OpCode.TEXT).setPayload("2018.02.13").setFin(true), finCallback);
|
||||||
|
@ -66,8 +69,8 @@ public class DecodedTextMessageSinkTest extends AbstractMessageSinkTest
|
||||||
CompletableFuture<Date> copyFuture = new CompletableFuture<>();
|
CompletableFuture<Date> copyFuture = new CompletableFuture<>();
|
||||||
DecodedDateCopy copy = new DecodedDateCopy(copyFuture);
|
DecodedDateCopy copy = new DecodedDateCopy(copyFuture);
|
||||||
MethodHandle copyHandle = getAcceptHandle(copy, Date.class);
|
MethodHandle copyHandle = getAcceptHandle(copy, Date.class);
|
||||||
Decoder.Text<Date> decoder = new GmtDecoder();
|
List<RegisteredDecoder> decoders = toRegisteredDecoderList(DecodedBinaryStreamMessageSinkTest.GmtDecoder.class, Calendar.class);
|
||||||
DecodedTextMessageSink sink = new DecodedTextMessageSink(session.getCoreSession(), decoder, copyHandle);
|
DecodedTextMessageSink<Calendar> sink = new DecodedTextMessageSink<>(session.getCoreSession(), copyHandle, decoders);
|
||||||
|
|
||||||
FutureCallback callback1 = new FutureCallback();
|
FutureCallback callback1 = new FutureCallback();
|
||||||
FutureCallback callback2 = new FutureCallback();
|
FutureCallback callback2 = new FutureCallback();
|
||||||
|
|
|
@ -23,7 +23,9 @@ import java.io.Reader;
|
||||||
import java.lang.invoke.MethodHandle;
|
import java.lang.invoke.MethodHandle;
|
||||||
import java.text.ParseException;
|
import java.text.ParseException;
|
||||||
import java.text.SimpleDateFormat;
|
import java.text.SimpleDateFormat;
|
||||||
|
import java.util.Calendar;
|
||||||
import java.util.Date;
|
import java.util.Date;
|
||||||
|
import java.util.List;
|
||||||
import java.util.TimeZone;
|
import java.util.TimeZone;
|
||||||
import java.util.concurrent.CompletableFuture;
|
import java.util.concurrent.CompletableFuture;
|
||||||
import java.util.concurrent.TimeUnit;
|
import java.util.concurrent.TimeUnit;
|
||||||
|
@ -36,6 +38,7 @@ import org.eclipse.jetty.util.FutureCallback;
|
||||||
import org.eclipse.jetty.util.IO;
|
import org.eclipse.jetty.util.IO;
|
||||||
import org.eclipse.jetty.websocket.core.Frame;
|
import org.eclipse.jetty.websocket.core.Frame;
|
||||||
import org.eclipse.jetty.websocket.core.OpCode;
|
import org.eclipse.jetty.websocket.core.OpCode;
|
||||||
|
import org.eclipse.jetty.websocket.javax.common.decoders.RegisteredDecoder;
|
||||||
import org.junit.jupiter.api.Test;
|
import org.junit.jupiter.api.Test;
|
||||||
|
|
||||||
import static org.hamcrest.MatcherAssert.assertThat;
|
import static org.hamcrest.MatcherAssert.assertThat;
|
||||||
|
@ -51,8 +54,8 @@ public class DecodedTextStreamMessageSinkTest extends AbstractMessageSinkTest
|
||||||
CompletableFuture<Date> copyFuture = new CompletableFuture<>();
|
CompletableFuture<Date> copyFuture = new CompletableFuture<>();
|
||||||
DecodedDateCopy copy = new DecodedDateCopy(copyFuture);
|
DecodedDateCopy copy = new DecodedDateCopy(copyFuture);
|
||||||
MethodHandle copyHandle = getAcceptHandle(copy, Date.class);
|
MethodHandle copyHandle = getAcceptHandle(copy, Date.class);
|
||||||
Decoder.TextStream<Date> decoder = new GmtDecoder();
|
List<RegisteredDecoder> decoders = toRegisteredDecoderList(DecodedBinaryStreamMessageSinkTest.GmtDecoder.class, Calendar.class);
|
||||||
DecodedTextStreamMessageSink sink = new DecodedTextStreamMessageSink(session.getCoreSession(), decoder, copyHandle);
|
DecodedTextStreamMessageSink<Calendar> sink = new DecodedTextStreamMessageSink<>(session.getCoreSession(), copyHandle, decoders);
|
||||||
|
|
||||||
FutureCallback finCallback = new FutureCallback();
|
FutureCallback finCallback = new FutureCallback();
|
||||||
sink.accept(new Frame(OpCode.TEXT).setPayload("2018.02.13").setFin(true), finCallback);
|
sink.accept(new Frame(OpCode.TEXT).setPayload("2018.02.13").setFin(true), finCallback);
|
||||||
|
@ -69,8 +72,8 @@ public class DecodedTextStreamMessageSinkTest extends AbstractMessageSinkTest
|
||||||
CompletableFuture<Date> copyFuture = new CompletableFuture<>();
|
CompletableFuture<Date> copyFuture = new CompletableFuture<>();
|
||||||
DecodedDateCopy copy = new DecodedDateCopy(copyFuture);
|
DecodedDateCopy copy = new DecodedDateCopy(copyFuture);
|
||||||
MethodHandle copyHandle = getAcceptHandle(copy, Date.class);
|
MethodHandle copyHandle = getAcceptHandle(copy, Date.class);
|
||||||
Decoder.TextStream<Date> decoder = new GmtDecoder();
|
List<RegisteredDecoder> decoders = toRegisteredDecoderList(DecodedBinaryStreamMessageSinkTest.GmtDecoder.class, Calendar.class);
|
||||||
DecodedTextStreamMessageSink sink = new DecodedTextStreamMessageSink(session.getCoreSession(), decoder, copyHandle);
|
DecodedTextStreamMessageSink<Calendar> sink = new DecodedTextStreamMessageSink<>(session.getCoreSession(), copyHandle, decoders);
|
||||||
|
|
||||||
FutureCallback callback1 = new FutureCallback();
|
FutureCallback callback1 = new FutureCallback();
|
||||||
FutureCallback callback2 = new FutureCallback();
|
FutureCallback callback2 = new FutureCallback();
|
||||||
|
|
|
@ -42,15 +42,11 @@ public class JavaxWebSocketServerFrameHandlerFactory extends JavaxWebSocketClien
|
||||||
public JavaxWebSocketFrameHandlerMetadata getMetadata(Class<?> endpointClass, EndpointConfig endpointConfig)
|
public JavaxWebSocketFrameHandlerMetadata getMetadata(Class<?> endpointClass, EndpointConfig endpointConfig)
|
||||||
{
|
{
|
||||||
if (javax.websocket.Endpoint.class.isAssignableFrom(endpointClass))
|
if (javax.websocket.Endpoint.class.isAssignableFrom(endpointClass))
|
||||||
{
|
|
||||||
return createEndpointMetadata((Class<? extends Endpoint>)endpointClass, endpointConfig);
|
return createEndpointMetadata((Class<? extends Endpoint>)endpointClass, endpointConfig);
|
||||||
}
|
|
||||||
|
|
||||||
ServerEndpoint anno = endpointClass.getAnnotation(ServerEndpoint.class);
|
ServerEndpoint anno = endpointClass.getAnnotation(ServerEndpoint.class);
|
||||||
if (anno == null)
|
if (anno == null)
|
||||||
{
|
|
||||||
return super.getMetadata(endpointClass, endpointConfig);
|
return super.getMetadata(endpointClass, endpointConfig);
|
||||||
}
|
|
||||||
|
|
||||||
UriTemplatePathSpec templatePathSpec = new UriTemplatePathSpec(anno.value());
|
UriTemplatePathSpec templatePathSpec = new UriTemplatePathSpec(anno.value());
|
||||||
JavaxWebSocketFrameHandlerMetadata metadata = new JavaxWebSocketFrameHandlerMetadata(endpointConfig);
|
JavaxWebSocketFrameHandlerMetadata metadata = new JavaxWebSocketFrameHandlerMetadata(endpointConfig);
|
||||||
|
|
|
@ -23,7 +23,7 @@ import javax.websocket.MessageHandler;
|
||||||
import javax.websocket.PongMessage;
|
import javax.websocket.PongMessage;
|
||||||
|
|
||||||
import org.eclipse.jetty.websocket.javax.common.JavaxWebSocketSession;
|
import org.eclipse.jetty.websocket.javax.common.JavaxWebSocketSession;
|
||||||
import org.eclipse.jetty.websocket.javax.common.decoders.AvailableDecoders;
|
import org.eclipse.jetty.websocket.javax.common.decoders.RegisteredDecoder;
|
||||||
import org.eclipse.jetty.websocket.javax.tests.MessageType;
|
import org.eclipse.jetty.websocket.javax.tests.MessageType;
|
||||||
import org.eclipse.jetty.websocket.util.ReflectUtils;
|
import org.eclipse.jetty.websocket.util.ReflectUtils;
|
||||||
import org.hamcrest.Description;
|
import org.hamcrest.Description;
|
||||||
|
@ -78,7 +78,7 @@ public class IsMessageHandlerType extends TypeSafeMatcher<MessageHandler>
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
AvailableDecoders.RegisteredDecoder registeredDecoder = session.getDecoders().getRegisteredDecoderFor(onMessageClass);
|
RegisteredDecoder registeredDecoder = session.getDecoders().getFirstRegisteredDecoder(onMessageClass);
|
||||||
if (registeredDecoder == null)
|
if (registeredDecoder == null)
|
||||||
{
|
{
|
||||||
return false;
|
return false;
|
||||||
|
|
|
@ -25,7 +25,7 @@ import javax.websocket.PongMessage;
|
||||||
|
|
||||||
import org.eclipse.jetty.websocket.javax.common.JavaxWebSocketSession;
|
import org.eclipse.jetty.websocket.javax.common.JavaxWebSocketSession;
|
||||||
import org.eclipse.jetty.websocket.javax.common.RegisteredMessageHandler;
|
import org.eclipse.jetty.websocket.javax.common.RegisteredMessageHandler;
|
||||||
import org.eclipse.jetty.websocket.javax.common.decoders.AvailableDecoders;
|
import org.eclipse.jetty.websocket.javax.common.decoders.RegisteredDecoder;
|
||||||
import org.eclipse.jetty.websocket.javax.tests.MessageType;
|
import org.eclipse.jetty.websocket.javax.tests.MessageType;
|
||||||
import org.hamcrest.Description;
|
import org.hamcrest.Description;
|
||||||
import org.hamcrest.TypeSafeMatcher;
|
import org.hamcrest.TypeSafeMatcher;
|
||||||
|
@ -60,7 +60,7 @@ public class IsMessageHandlerTypeRegistered extends TypeSafeMatcher<JavaxWebSock
|
||||||
{
|
{
|
||||||
Class<?> onMessageType = registeredMessageHandler.getHandlerType();
|
Class<?> onMessageType = registeredMessageHandler.getHandlerType();
|
||||||
|
|
||||||
AvailableDecoders.RegisteredDecoder registeredDecoder = session.getDecoders().getRegisteredDecoderFor(onMessageType);
|
RegisteredDecoder registeredDecoder = session.getDecoders().getFirstRegisteredDecoder(onMessageType);
|
||||||
if (registeredDecoder == null)
|
if (registeredDecoder == null)
|
||||||
{
|
{
|
||||||
continue;
|
continue;
|
||||||
|
@ -130,7 +130,7 @@ public class IsMessageHandlerTypeRegistered extends TypeSafeMatcher<JavaxWebSock
|
||||||
|
|
||||||
mismatchDescription.appendText("<" + onMessageType.getName() + ">");
|
mismatchDescription.appendText("<" + onMessageType.getName() + ">");
|
||||||
|
|
||||||
AvailableDecoders.RegisteredDecoder registeredDecoder = session.getDecoders().getRegisteredDecoderFor(onMessageType);
|
RegisteredDecoder registeredDecoder = session.getDecoders().getFirstRegisteredDecoder(onMessageType);
|
||||||
if (registeredDecoder == null)
|
if (registeredDecoder == null)
|
||||||
{
|
{
|
||||||
mismatchDescription.appendText("(!NO-DECODER!)");
|
mismatchDescription.appendText("(!NO-DECODER!)");
|
||||||
|
|
|
@ -0,0 +1,162 @@
|
||||||
|
//
|
||||||
|
// ========================================================================
|
||||||
|
// Copyright (c) 1995-2020 Mort Bay Consulting Pty Ltd and others.
|
||||||
|
//
|
||||||
|
// This program and the accompanying materials are made available under
|
||||||
|
// the terms of the Eclipse Public License 2.0 which is available at
|
||||||
|
// https://www.eclipse.org/legal/epl-2.0
|
||||||
|
//
|
||||||
|
// This Source Code may also be made available under the following
|
||||||
|
// Secondary Licenses when the conditions for such availability set
|
||||||
|
// forth in the Eclipse Public License, v. 2.0 are satisfied:
|
||||||
|
// the Apache License v2.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.tests;
|
||||||
|
|
||||||
|
import java.net.URI;
|
||||||
|
import java.util.concurrent.TimeUnit;
|
||||||
|
import java.util.stream.Stream;
|
||||||
|
import javax.websocket.Decoder;
|
||||||
|
import javax.websocket.EndpointConfig;
|
||||||
|
import javax.websocket.OnMessage;
|
||||||
|
import javax.websocket.Session;
|
||||||
|
import javax.websocket.server.ServerEndpoint;
|
||||||
|
|
||||||
|
import org.eclipse.jetty.server.Server;
|
||||||
|
import org.eclipse.jetty.server.ServerConnector;
|
||||||
|
import org.eclipse.jetty.servlet.ServletContextHandler;
|
||||||
|
import org.eclipse.jetty.websocket.javax.client.internal.JavaxWebSocketClientContainer;
|
||||||
|
import org.eclipse.jetty.websocket.javax.server.config.JavaxWebSocketServletContainerInitializer;
|
||||||
|
import org.junit.jupiter.api.AfterEach;
|
||||||
|
import org.junit.jupiter.api.BeforeEach;
|
||||||
|
import org.junit.jupiter.params.ParameterizedTest;
|
||||||
|
import org.junit.jupiter.params.provider.Arguments;
|
||||||
|
import org.junit.jupiter.params.provider.MethodSource;
|
||||||
|
|
||||||
|
import static org.hamcrest.MatcherAssert.assertThat;
|
||||||
|
import static org.hamcrest.Matchers.is;
|
||||||
|
|
||||||
|
public class DecoderListTest
|
||||||
|
{
|
||||||
|
private Server server;
|
||||||
|
private URI serverUri;
|
||||||
|
private JavaxWebSocketClientContainer client;
|
||||||
|
|
||||||
|
@BeforeEach
|
||||||
|
public void before() throws Exception
|
||||||
|
{
|
||||||
|
server = new Server();
|
||||||
|
ServerConnector connector = new ServerConnector(server);
|
||||||
|
server.addConnector(connector);
|
||||||
|
|
||||||
|
ServletContextHandler contextHandler = new ServletContextHandler();
|
||||||
|
contextHandler.setContextPath("/");
|
||||||
|
server.setHandler(contextHandler);
|
||||||
|
JavaxWebSocketServletContainerInitializer.configure(contextHandler, (context, container) ->
|
||||||
|
container.addEndpoint(DecoderListEndpoint.class));
|
||||||
|
server.start();
|
||||||
|
serverUri = WSURI.toWebsocket(server.getURI());
|
||||||
|
|
||||||
|
client = new JavaxWebSocketClientContainer();
|
||||||
|
client.start();
|
||||||
|
}
|
||||||
|
|
||||||
|
@AfterEach
|
||||||
|
public void after() throws Exception
|
||||||
|
{
|
||||||
|
server.stop();
|
||||||
|
client.stop();
|
||||||
|
}
|
||||||
|
|
||||||
|
public static Stream<Arguments> getArguments()
|
||||||
|
{
|
||||||
|
return Stream.of(
|
||||||
|
Arguments.of("=DecodeEquals", "DecodeEquals="),
|
||||||
|
Arguments.of("+DecodePlus", "DecodePlus+"),
|
||||||
|
Arguments.of("-DecodeMinus", "DecodeMinus-"),
|
||||||
|
Arguments.of("DecodeNoMatch", null)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
@ParameterizedTest
|
||||||
|
@MethodSource("getArguments")
|
||||||
|
public void testDecoderList(String request, String expected) throws Exception
|
||||||
|
{
|
||||||
|
EventSocket clientEndpoint = new EventSocket();
|
||||||
|
Session session = client.connectToServer(clientEndpoint, serverUri);
|
||||||
|
session.getBasicRemote().sendText(request);
|
||||||
|
String response = clientEndpoint.textMessages.poll(3, TimeUnit.SECONDS);
|
||||||
|
assertThat(response, is(expected));
|
||||||
|
}
|
||||||
|
|
||||||
|
@ServerEndpoint(value = "/", decoders = {EqualsDecoder.class, PlusDecoder.class, MinusDecoder.class})
|
||||||
|
public static class DecoderListEndpoint
|
||||||
|
{
|
||||||
|
@OnMessage
|
||||||
|
public String echo(String message)
|
||||||
|
{
|
||||||
|
return message;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static class EqualsDecoder extends PrefixStringDecoder
|
||||||
|
{
|
||||||
|
public EqualsDecoder()
|
||||||
|
{
|
||||||
|
super("=");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static class PlusDecoder extends PrefixStringDecoder
|
||||||
|
{
|
||||||
|
public PlusDecoder()
|
||||||
|
{
|
||||||
|
super("+");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static class MinusDecoder extends PrefixStringDecoder
|
||||||
|
{
|
||||||
|
public MinusDecoder()
|
||||||
|
{
|
||||||
|
super("-");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static class PrefixStringDecoder implements Decoder.Text<String>
|
||||||
|
{
|
||||||
|
private final String prefix;
|
||||||
|
|
||||||
|
public PrefixStringDecoder(String prefix)
|
||||||
|
{
|
||||||
|
this.prefix = prefix;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String decode(String s)
|
||||||
|
{
|
||||||
|
return s.substring(prefix.length()) + prefix;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean willDecode(String s)
|
||||||
|
{
|
||||||
|
return s.startsWith(prefix);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void init(EndpointConfig config)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void destroy()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -22,6 +22,7 @@ import java.nio.ByteBuffer;
|
||||||
import java.time.Instant;
|
import java.time.Instant;
|
||||||
import java.util.Calendar;
|
import java.util.Calendar;
|
||||||
import java.util.Date;
|
import java.util.Date;
|
||||||
|
import java.util.NoSuchElementException;
|
||||||
import java.util.TimeZone;
|
import java.util.TimeZone;
|
||||||
import javax.websocket.DecodeException;
|
import javax.websocket.DecodeException;
|
||||||
import javax.websocket.Decoder;
|
import javax.websocket.Decoder;
|
||||||
|
@ -31,6 +32,7 @@ import org.eclipse.jetty.toolchain.test.Hex;
|
||||||
import org.eclipse.jetty.websocket.javax.client.internal.BasicClientEndpointConfig;
|
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.decoders.AvailableDecoders;
|
||||||
import org.eclipse.jetty.websocket.javax.common.decoders.IntegerDecoder;
|
import org.eclipse.jetty.websocket.javax.common.decoders.IntegerDecoder;
|
||||||
|
import org.eclipse.jetty.websocket.javax.common.decoders.RegisteredDecoder;
|
||||||
import org.eclipse.jetty.websocket.util.InvalidWebSocketException;
|
import org.eclipse.jetty.websocket.util.InvalidWebSocketException;
|
||||||
import org.junit.jupiter.api.BeforeAll;
|
import org.junit.jupiter.api.BeforeAll;
|
||||||
import org.junit.jupiter.api.Test;
|
import org.junit.jupiter.api.Test;
|
||||||
|
@ -52,132 +54,145 @@ public class AvailableDecodersTest
|
||||||
testConfig = new BasicClientEndpointConfig();
|
testConfig = new BasicClientEndpointConfig();
|
||||||
}
|
}
|
||||||
|
|
||||||
private AvailableDecoders decoders = new AvailableDecoders(testConfig);
|
private final AvailableDecoders decoders = new AvailableDecoders(testConfig);
|
||||||
|
|
||||||
private <T> void assertTextDecoder(Class<T> type, String value, T expectedDecoded) throws IllegalAccessException, InstantiationException, DecodeException
|
public <T extends Decoder> T getInstanceFor(Class<?> type)
|
||||||
{
|
{
|
||||||
Decoder.Text<T> decoder = (Decoder.Text<T>)decoders.getInstanceFor(type);
|
try
|
||||||
|
{
|
||||||
|
RegisteredDecoder registeredDecoder = decoders.getFirstRegisteredDecoder(type);
|
||||||
|
return registeredDecoder.getInstance();
|
||||||
|
}
|
||||||
|
catch (NoSuchElementException e)
|
||||||
|
{
|
||||||
|
throw new InvalidWebSocketException("No Decoder found for type " + type);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private <T> void assertTextDecoder(Class<T> type, String value, T expectedDecoded) throws DecodeException
|
||||||
|
{
|
||||||
|
Decoder.Text<T> decoder = getInstanceFor(type);
|
||||||
assertThat("Decoder instance", decoder, notNullValue());
|
assertThat("Decoder instance", decoder, notNullValue());
|
||||||
T decoded = decoder.decode(value);
|
T decoded = decoder.decode(value);
|
||||||
assertThat("Decoded", decoded, is(expectedDecoded));
|
assertThat("Decoded", decoded, is(expectedDecoded));
|
||||||
}
|
}
|
||||||
|
|
||||||
private <T> void assertBinaryDecoder(Class<T> type, ByteBuffer value, T expectedDecoded)
|
private <T> void assertBinaryDecoder(Class<T> type, ByteBuffer value, T expectedDecoded)
|
||||||
throws IllegalAccessException, InstantiationException, DecodeException
|
throws DecodeException
|
||||||
{
|
{
|
||||||
Decoder.Binary<T> decoder = (Decoder.Binary<T>)decoders.getInstanceFor(type);
|
Decoder.Binary<T> decoder = getInstanceFor(type);
|
||||||
assertThat("Decoder Class", decoder, notNullValue());
|
assertThat("Decoder Class", decoder, notNullValue());
|
||||||
T decoded = decoder.decode(value);
|
T decoded = decoder.decode(value);
|
||||||
assertThat("Decoded", decoded, equalTo(expectedDecoded));
|
assertThat("Decoded", decoded, equalTo(expectedDecoded));
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testCoreDecodeBoolean() throws IllegalAccessException, InstantiationException, DecodeException
|
public void testCoreDecodeBoolean() throws DecodeException
|
||||||
{
|
{
|
||||||
Boolean expected = Boolean.TRUE;
|
Boolean expected = Boolean.TRUE;
|
||||||
assertTextDecoder(Boolean.class, "true", expected);
|
assertTextDecoder(Boolean.class, "true", expected);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testCoreDecodeboolean() throws IllegalAccessException, InstantiationException, DecodeException
|
public void testCoreDecodeboolean() throws DecodeException
|
||||||
{
|
{
|
||||||
boolean expected = false;
|
boolean expected = false;
|
||||||
assertTextDecoder(Boolean.TYPE, "false", expected);
|
assertTextDecoder(Boolean.TYPE, "false", expected);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testCoreDecodeByte() throws IllegalAccessException, InstantiationException, DecodeException
|
public void testCoreDecodeByte() throws DecodeException
|
||||||
{
|
{
|
||||||
Byte expected = (byte)0x21;
|
Byte expected = (byte)0x21;
|
||||||
assertTextDecoder(Byte.class, "33", expected);
|
assertTextDecoder(Byte.class, "33", expected);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testCoreDecodebyte() throws IllegalAccessException, InstantiationException, DecodeException
|
public void testCoreDecodebyte() throws DecodeException
|
||||||
{
|
{
|
||||||
byte expected = 0x21;
|
byte expected = 0x21;
|
||||||
assertTextDecoder(Byte.TYPE, "33", expected);
|
assertTextDecoder(Byte.TYPE, "33", expected);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testCoreDecodeCharacter() throws IllegalAccessException, InstantiationException, DecodeException
|
public void testCoreDecodeCharacter() throws DecodeException
|
||||||
{
|
{
|
||||||
Character expected = '!';
|
Character expected = '!';
|
||||||
assertTextDecoder(Character.class, "!", expected);
|
assertTextDecoder(Character.class, "!", expected);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testCoreDecodechar() throws IllegalAccessException, InstantiationException, DecodeException
|
public void testCoreDecodechar() throws DecodeException
|
||||||
{
|
{
|
||||||
char expected = '!';
|
char expected = '!';
|
||||||
assertTextDecoder(Character.TYPE, "!", expected);
|
assertTextDecoder(Character.TYPE, "!", expected);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testCoreDecodeDouble() throws IllegalAccessException, InstantiationException, DecodeException
|
public void testCoreDecodeDouble() throws DecodeException
|
||||||
{
|
{
|
||||||
Double expected = 123.45D;
|
Double expected = 123.45D;
|
||||||
assertTextDecoder(Double.class, "123.45", expected);
|
assertTextDecoder(Double.class, "123.45", expected);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testCoreDecodedouble() throws IllegalAccessException, InstantiationException, DecodeException
|
public void testCoreDecodedouble() throws DecodeException
|
||||||
{
|
{
|
||||||
double expected = 123.45D;
|
double expected = 123.45D;
|
||||||
assertTextDecoder(Double.TYPE, "123.45", expected);
|
assertTextDecoder(Double.TYPE, "123.45", expected);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testCoreDecodeFloat() throws IllegalAccessException, InstantiationException, DecodeException
|
public void testCoreDecodeFloat() throws DecodeException
|
||||||
{
|
{
|
||||||
Float expected = 123.4567F;
|
Float expected = 123.4567F;
|
||||||
assertTextDecoder(Float.class, "123.4567", expected);
|
assertTextDecoder(Float.class, "123.4567", expected);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testCoreDecodefloat() throws IllegalAccessException, InstantiationException, DecodeException
|
public void testCoreDecodefloat() throws DecodeException
|
||||||
{
|
{
|
||||||
float expected = 123.4567F;
|
float expected = 123.4567F;
|
||||||
assertTextDecoder(Float.TYPE, "123.4567", expected);
|
assertTextDecoder(Float.TYPE, "123.4567", expected);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testCoreDecodeInteger() throws IllegalAccessException, InstantiationException, DecodeException
|
public void testCoreDecodeInteger() throws DecodeException
|
||||||
{
|
{
|
||||||
Integer expected = 1234;
|
Integer expected = 1234;
|
||||||
assertTextDecoder(Integer.class, "1234", expected);
|
assertTextDecoder(Integer.class, "1234", expected);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testCoreDecodeint() throws IllegalAccessException, InstantiationException, DecodeException
|
public void testCoreDecodeint() throws DecodeException
|
||||||
{
|
{
|
||||||
int expected = 1234;
|
int expected = 1234;
|
||||||
assertTextDecoder(Integer.TYPE, "1234", expected);
|
assertTextDecoder(Integer.TYPE, "1234", expected);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testCoreDecodeLong() throws IllegalAccessException, InstantiationException, DecodeException
|
public void testCoreDecodeLong() throws DecodeException
|
||||||
{
|
{
|
||||||
Long expected = 123_456_789L;
|
Long expected = 123_456_789L;
|
||||||
assertTextDecoder(Long.class, "123456789", expected);
|
assertTextDecoder(Long.class, "123456789", expected);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testCoreDecodelong() throws IllegalAccessException, InstantiationException, DecodeException
|
public void testCoreDecodelong() throws DecodeException
|
||||||
{
|
{
|
||||||
long expected = 123_456_789L;
|
long expected = 123_456_789L;
|
||||||
assertTextDecoder(Long.TYPE, "123456789", expected);
|
assertTextDecoder(Long.TYPE, "123456789", expected);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testCoreDecodeString() throws IllegalAccessException, InstantiationException, DecodeException
|
public void testCoreDecodeString() throws DecodeException
|
||||||
{
|
{
|
||||||
String expected = "Hello World";
|
String expected = "Hello World";
|
||||||
assertTextDecoder(String.class, "Hello World", expected);
|
assertTextDecoder(String.class, "Hello World", expected);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testCoreDecodeByteBuffer() throws IllegalAccessException, InstantiationException, DecodeException
|
public void testCoreDecodeByteBuffer() throws DecodeException
|
||||||
{
|
{
|
||||||
ByteBuffer val = Hex.asByteBuffer("112233445566778899");
|
ByteBuffer val = Hex.asByteBuffer("112233445566778899");
|
||||||
ByteBuffer expected = Hex.asByteBuffer("112233445566778899");
|
ByteBuffer expected = Hex.asByteBuffer("112233445566778899");
|
||||||
|
@ -185,7 +200,7 @@ public class AvailableDecodersTest
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testCoreDecodeByteArray() throws IllegalAccessException, InstantiationException, DecodeException
|
public void testCoreDecodeByteArray() throws DecodeException
|
||||||
{
|
{
|
||||||
ByteBuffer val = Hex.asByteBuffer("112233445566778899");
|
ByteBuffer val = Hex.asByteBuffer("112233445566778899");
|
||||||
byte[] expected = Hex.asByteArray("112233445566778899");
|
byte[] expected = Hex.asByteArray("112233445566778899");
|
||||||
|
@ -193,7 +208,7 @@ public class AvailableDecodersTest
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testCustomDecoderInteger() throws IllegalAccessException, InstantiationException, DecodeException
|
public void testCustomDecoderInteger() throws DecodeException
|
||||||
{
|
{
|
||||||
decoders.register(IntegerDecoder.class);
|
decoders.register(IntegerDecoder.class);
|
||||||
|
|
||||||
|
@ -203,7 +218,7 @@ public class AvailableDecodersTest
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testCustomDecoderTime() throws IllegalAccessException, InstantiationException, DecodeException
|
public void testCustomDecoderTime() throws DecodeException
|
||||||
{
|
{
|
||||||
decoders.register(TimeDecoder.class);
|
decoders.register(TimeDecoder.class);
|
||||||
|
|
||||||
|
@ -222,7 +237,7 @@ public class AvailableDecodersTest
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testCustomDecoderDate() throws IllegalAccessException, InstantiationException, DecodeException
|
public void testCustomDecoderDate() throws DecodeException
|
||||||
{
|
{
|
||||||
decoders.register(DateDecoder.class);
|
decoders.register(DateDecoder.class);
|
||||||
|
|
||||||
|
@ -241,7 +256,7 @@ public class AvailableDecodersTest
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testCustomDecoderDateTime() throws IllegalAccessException, InstantiationException, DecodeException
|
public void testCustomDecoderDateTime() throws DecodeException
|
||||||
{
|
{
|
||||||
decoders.register(DateTimeDecoder.class);
|
decoders.register(DateTimeDecoder.class);
|
||||||
|
|
||||||
|
@ -264,11 +279,11 @@ public class AvailableDecodersTest
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testCustomDecoderValidDualText() throws IllegalAccessException, InstantiationException, DecodeException
|
public void testCustomDecoderValidDualText() throws DecodeException
|
||||||
{
|
{
|
||||||
decoders.register(ValidDualDecoder.class);
|
decoders.register(ValidDualDecoder.class);
|
||||||
|
|
||||||
AvailableDecoders.RegisteredDecoder registered = decoders.getRegisteredDecoderFor(Integer.class);
|
RegisteredDecoder registered = decoders.getFirstRegisteredDecoder(Integer.class);
|
||||||
assertThat("Registered Decoder for Integer", registered.decoder.getName(), is(ValidDualDecoder.class.getName()));
|
assertThat("Registered Decoder for Integer", registered.decoder.getName(), is(ValidDualDecoder.class.getName()));
|
||||||
|
|
||||||
String val = "[1,234,567]";
|
String val = "[1,234,567]";
|
||||||
|
@ -278,11 +293,11 @@ public class AvailableDecodersTest
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testCustomDecoderValidDualBinary() throws IllegalAccessException, InstantiationException, DecodeException
|
public void testCustomDecoderValidDualBinary() throws DecodeException
|
||||||
{
|
{
|
||||||
decoders.register(ValidDualDecoder.class);
|
decoders.register(ValidDualDecoder.class);
|
||||||
|
|
||||||
AvailableDecoders.RegisteredDecoder registered = decoders.getRegisteredDecoderFor(Long.class);
|
RegisteredDecoder registered = decoders.getFirstRegisteredDecoder(Long.class);
|
||||||
assertThat("Registered Decoder for Long", registered.decoder.getName(), is(ValidDualDecoder.class.getName()));
|
assertThat("Registered Decoder for Long", registered.decoder.getName(), is(ValidDualDecoder.class.getName()));
|
||||||
|
|
||||||
ByteBuffer val = ByteBuffer.allocate(16);
|
ByteBuffer val = ByteBuffer.allocate(16);
|
||||||
|
|
|
@ -27,11 +27,13 @@ import java.util.List;
|
||||||
import java.util.concurrent.CompletableFuture;
|
import java.util.concurrent.CompletableFuture;
|
||||||
import java.util.concurrent.TimeUnit;
|
import java.util.concurrent.TimeUnit;
|
||||||
import java.util.function.Function;
|
import java.util.function.Function;
|
||||||
|
import javax.websocket.ClientEndpointConfig;
|
||||||
import javax.websocket.Decoder;
|
import javax.websocket.Decoder;
|
||||||
|
|
||||||
import org.eclipse.jetty.toolchain.test.MavenTestingUtils;
|
import org.eclipse.jetty.toolchain.test.MavenTestingUtils;
|
||||||
import org.eclipse.jetty.util.FutureCallback;
|
import org.eclipse.jetty.util.FutureCallback;
|
||||||
import org.eclipse.jetty.websocket.core.Frame;
|
import org.eclipse.jetty.websocket.core.Frame;
|
||||||
|
import org.eclipse.jetty.websocket.javax.common.decoders.RegisteredDecoder;
|
||||||
import org.eclipse.jetty.websocket.javax.common.messages.DecodedTextStreamMessageSink;
|
import org.eclipse.jetty.websocket.javax.common.messages.DecodedTextStreamMessageSink;
|
||||||
import org.eclipse.jetty.websocket.javax.tests.FunctionMethod;
|
import org.eclipse.jetty.websocket.javax.tests.FunctionMethod;
|
||||||
import org.eclipse.jetty.websocket.javax.tests.client.AbstractClientSessionTest;
|
import org.eclipse.jetty.websocket.javax.tests.client.AbstractClientSessionTest;
|
||||||
|
@ -64,7 +66,6 @@ public class DecoderTextStreamTest extends AbstractClientSessionTest
|
||||||
@Test
|
@Test
|
||||||
public void testQuotesDecodedReaderMessageSink() throws Exception
|
public void testQuotesDecodedReaderMessageSink() throws Exception
|
||||||
{
|
{
|
||||||
Decoder.TextStream<Quotes> decoder = new QuotesDecoder();
|
|
||||||
CompletableFuture<Quotes> futureQuotes = new CompletableFuture<>();
|
CompletableFuture<Quotes> futureQuotes = new CompletableFuture<>();
|
||||||
MethodHandle functionHandle = FunctionMethod.getFunctionApplyMethodHandle();
|
MethodHandle functionHandle = FunctionMethod.getFunctionApplyMethodHandle();
|
||||||
MethodHandle quoteHandle = functionHandle.bindTo((Function<Quotes, Void>)(quotes) ->
|
MethodHandle quoteHandle = functionHandle.bindTo((Function<Quotes, Void>)(quotes) ->
|
||||||
|
@ -80,7 +81,8 @@ public class DecoderTextStreamTest extends AbstractClientSessionTest
|
||||||
return null;
|
return null;
|
||||||
});
|
});
|
||||||
|
|
||||||
DecodedTextStreamMessageSink sink = new DecodedTextStreamMessageSink(session.getCoreSession(), decoder, quoteHandle);
|
List<RegisteredDecoder> decoders = toRegisteredDecoderList(QuotesDecoder.class, Quotes.class);
|
||||||
|
DecodedTextStreamMessageSink<Quotes> sink = new DecodedTextStreamMessageSink<>(session.getCoreSession(), quoteHandle, decoders);
|
||||||
|
|
||||||
List<FutureCallback> callbacks = new ArrayList<>();
|
List<FutureCallback> callbacks = new ArrayList<>();
|
||||||
FutureCallback finCallback = null;
|
FutureCallback finCallback = null;
|
||||||
|
@ -107,4 +109,21 @@ public class DecoderTextStreamTest extends AbstractClientSessionTest
|
||||||
assertThat("Quotes.author", quotes.getAuthor(), is("Benjamin Franklin"));
|
assertThat("Quotes.author", quotes.getAuthor(), is("Benjamin Franklin"));
|
||||||
assertThat("Quotes.count", quotes.getQuotes().size(), is(3));
|
assertThat("Quotes.count", quotes.getQuotes().size(), is(3));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public List<RegisteredDecoder> toRegisteredDecoderList(Class<? extends Decoder> clazz, Class<?> objectType)
|
||||||
|
{
|
||||||
|
Class<? extends Decoder> interfaceType;
|
||||||
|
if (Decoder.Text.class.isAssignableFrom(clazz))
|
||||||
|
interfaceType = Decoder.Text.class;
|
||||||
|
else if (Decoder.Binary.class.isAssignableFrom(clazz))
|
||||||
|
interfaceType = Decoder.Binary.class;
|
||||||
|
else if (Decoder.TextStream.class.isAssignableFrom(clazz))
|
||||||
|
interfaceType = Decoder.TextStream.class;
|
||||||
|
else if (Decoder.BinaryStream.class.isAssignableFrom(clazz))
|
||||||
|
interfaceType = Decoder.BinaryStream.class;
|
||||||
|
else
|
||||||
|
throw new IllegalStateException();
|
||||||
|
|
||||||
|
return List.of(new RegisteredDecoder(clazz, interfaceType, objectType, ClientEndpointConfig.Builder.create().build()));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue