Issue #207 - Support javax.websocket version 1.1
This commit is contained in:
parent
2175625537
commit
795246c785
|
@ -119,7 +119,7 @@ public class JsrSession extends WebSocketSession implements javax.websocket.Sess
|
|||
}
|
||||
|
||||
getJsrEndpointFunctions().setMessageHandler(clazz, handler);
|
||||
messageHandlerSet.add(handler);
|
||||
registerMessageHandler(handler);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -136,7 +136,7 @@ public class JsrSession extends WebSocketSession implements javax.websocket.Sess
|
|||
LOG.debug("MessageHandler.Whole class: {}", handler.getClass());
|
||||
}
|
||||
getJsrEndpointFunctions().setMessageHandler(clazz, handler);
|
||||
messageHandlerSet.add(handler);
|
||||
registerMessageHandler(handler);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -150,21 +150,36 @@ public class JsrSession extends WebSocketSession implements javax.websocket.Sess
|
|||
{
|
||||
Objects.requireNonNull(handler, "MessageHandler cannot be null");
|
||||
Class<? extends MessageHandler> handlerClass = handler.getClass();
|
||||
boolean added = false;
|
||||
|
||||
if (MessageHandler.Whole.class.isAssignableFrom(handlerClass))
|
||||
{
|
||||
Class<?> onMessageClass = ReflectUtils.findGenericClassFor(handlerClass, MessageHandler.Whole.class);
|
||||
addMessageHandler(onMessageClass, (MessageHandler.Whole) handler);
|
||||
added = true;
|
||||
}
|
||||
|
||||
if (MessageHandler.Partial.class.isAssignableFrom(handlerClass))
|
||||
{
|
||||
Class<?> onMessageClass = ReflectUtils.findGenericClassFor(handlerClass, MessageHandler.Partial.class);
|
||||
addMessageHandler(onMessageClass, (MessageHandler.Partial) handler);
|
||||
added = true;
|
||||
}
|
||||
|
||||
// Should not be possible
|
||||
throw new IllegalStateException("Not a recognized " + MessageHandler.class.getName() + " type: " + handler.getClass());
|
||||
if (!added)
|
||||
{
|
||||
// Should not be possible
|
||||
throw new IllegalStateException("Not a recognized " + MessageHandler.class.getName() + " type: " + handler.getClass());
|
||||
}
|
||||
}
|
||||
|
||||
protected synchronized void registerMessageHandler(MessageHandler handler)
|
||||
{
|
||||
if (messageHandlerSet == null)
|
||||
{
|
||||
messageHandlerSet = new HashSet<>();
|
||||
}
|
||||
messageHandlerSet.add(handler);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -241,6 +256,11 @@ public class JsrSession extends WebSocketSession implements javax.websocket.Sess
|
|||
@Override
|
||||
public Set<MessageHandler> getMessageHandlers()
|
||||
{
|
||||
if (messageHandlerSet == null)
|
||||
{
|
||||
return Collections.emptySet();
|
||||
}
|
||||
|
||||
// Always return copy of set, as it is common to iterate and remove from the real set.
|
||||
return new HashSet<MessageHandler>(messageHandlerSet);
|
||||
}
|
||||
|
@ -309,7 +329,7 @@ public class JsrSession extends WebSocketSession implements javax.websocket.Sess
|
|||
@Override
|
||||
public synchronized void removeMessageHandler(MessageHandler handler)
|
||||
{
|
||||
if (messageHandlerSet.remove(handler))
|
||||
if (messageHandlerSet != null && messageHandlerSet.remove(handler))
|
||||
{
|
||||
// remove from endpoint functions too
|
||||
getJsrEndpointFunctions().removeMessageHandler(handler);
|
||||
|
|
|
@ -42,13 +42,20 @@ public class AvailableDecoders implements Predicate<Class<?>>
|
|||
public final Class<? extends Decoder> decoder;
|
||||
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)
|
||||
|
@ -61,7 +68,7 @@ public class AvailableDecoders implements Predicate<Class<?>>
|
|||
return objectType.isAssignableFrom(type);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
private final EndpointConfig config;
|
||||
private LinkedList<RegisteredDecoder> registeredDecoders;
|
||||
|
||||
|
@ -71,36 +78,36 @@ public class AvailableDecoders implements Predicate<Class<?>>
|
|||
registeredDecoders = new LinkedList<>();
|
||||
|
||||
// TEXT based [via Class reference]
|
||||
register(BooleanDecoder.class, Decoder.Text.class, Boolean.class);
|
||||
register(ByteDecoder.class, Decoder.Text.class, Byte.class);
|
||||
register(CharacterDecoder.class, Decoder.Text.class, Character.class);
|
||||
register(DoubleDecoder.class, Decoder.Text.class, Double.class);
|
||||
register(FloatDecoder.class, Decoder.Text.class, Float.class);
|
||||
register(IntegerDecoder.class, Decoder.Text.class, Integer.class);
|
||||
register(LongDecoder.class, Decoder.Text.class, Long.class);
|
||||
register(StringDecoder.class, Decoder.Text.class, String.class);
|
||||
registerPrimitive(BooleanDecoder.class, Decoder.Text.class, Boolean.class);
|
||||
registerPrimitive(ByteDecoder.class, Decoder.Text.class, Byte.class);
|
||||
registerPrimitive(CharacterDecoder.class, Decoder.Text.class, Character.class);
|
||||
registerPrimitive(DoubleDecoder.class, Decoder.Text.class, Double.class);
|
||||
registerPrimitive(FloatDecoder.class, Decoder.Text.class, Float.class);
|
||||
registerPrimitive(IntegerDecoder.class, Decoder.Text.class, Integer.class);
|
||||
registerPrimitive(LongDecoder.class, Decoder.Text.class, Long.class);
|
||||
registerPrimitive(StringDecoder.class, Decoder.Text.class, String.class);
|
||||
|
||||
// TEXT based [via Primitive reference]
|
||||
register(BooleanDecoder.class, Decoder.Text.class, Boolean.TYPE);
|
||||
register(ByteDecoder.class, Decoder.Text.class, Byte.TYPE);
|
||||
register(CharacterDecoder.class, Decoder.Text.class, Character.TYPE);
|
||||
register(DoubleDecoder.class, Decoder.Text.class, Double.TYPE);
|
||||
register(FloatDecoder.class, Decoder.Text.class, Float.TYPE);
|
||||
register(IntegerDecoder.class, Decoder.Text.class, Integer.TYPE);
|
||||
register(LongDecoder.class, Decoder.Text.class, Long.TYPE);
|
||||
registerPrimitive(BooleanDecoder.class, Decoder.Text.class, Boolean.TYPE);
|
||||
registerPrimitive(ByteDecoder.class, Decoder.Text.class, Byte.TYPE);
|
||||
registerPrimitive(CharacterDecoder.class, Decoder.Text.class, Character.TYPE);
|
||||
registerPrimitive(DoubleDecoder.class, Decoder.Text.class, Double.TYPE);
|
||||
registerPrimitive(FloatDecoder.class, Decoder.Text.class, Float.TYPE);
|
||||
registerPrimitive(IntegerDecoder.class, Decoder.Text.class, Integer.TYPE);
|
||||
registerPrimitive(LongDecoder.class, Decoder.Text.class, Long.TYPE);
|
||||
|
||||
// BINARY based
|
||||
register(ByteBufferDecoder.class, Decoder.Binary.class, ByteBuffer.class);
|
||||
register(ByteArrayDecoder.class, Decoder.Binary.class, byte[].class);
|
||||
registerPrimitive(ByteBufferDecoder.class, Decoder.Binary.class, ByteBuffer.class);
|
||||
registerPrimitive(ByteArrayDecoder.class, Decoder.Binary.class, byte[].class);
|
||||
|
||||
// STREAMING based
|
||||
register(ReaderDecoder.class, Decoder.TextStream.class, Reader.class);
|
||||
register(InputStreamDecoder.class, Decoder.BinaryStream.class, InputStreamDecoder.class);
|
||||
registerPrimitive(ReaderDecoder.class, Decoder.TextStream.class, Reader.class);
|
||||
registerPrimitive(InputStreamDecoder.class, Decoder.BinaryStream.class, InputStreamDecoder.class);
|
||||
}
|
||||
|
||||
private void register(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));
|
||||
registeredDecoders.add(new RegisteredDecoder(decoderClass, interfaceType, type, true));
|
||||
}
|
||||
|
||||
public void register(Class<? extends Decoder> decoder)
|
||||
|
@ -167,14 +174,34 @@ public class AvailableDecoders implements Predicate<Class<?>>
|
|||
if (objectType == null)
|
||||
{
|
||||
StringBuilder err = new StringBuilder();
|
||||
err.append("Invalid Decoder Object type declared for interface ");
|
||||
err.append("Unknown Decoder Object type declared for interface ");
|
||||
err.append(interfaceClass.getName());
|
||||
err.append(" on class ");
|
||||
err.append(decoder);
|
||||
throw new InvalidWebSocketException(err.toString());
|
||||
}
|
||||
|
||||
registeredDecoders.add(new RegisteredDecoder(decoder, interfaceClass, objectType));
|
||||
try
|
||||
{
|
||||
RegisteredDecoder conflicts = registeredDecoders.stream()
|
||||
.filter(registered -> registered.isType(objectType))
|
||||
.filter(registered -> !registered.primitive)
|
||||
.findFirst()
|
||||
.get();
|
||||
|
||||
StringBuilder err = new StringBuilder();
|
||||
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));
|
||||
}
|
||||
}
|
||||
|
||||
public List<RegisteredDecoder> supporting(Class<? extends Decoder> interfaceType)
|
||||
|
@ -204,28 +231,36 @@ public class AvailableDecoders implements Predicate<Class<?>>
|
|||
}
|
||||
}
|
||||
|
||||
public Decoder getInstanceFor(Class<?> type)
|
||||
public <T extends Decoder> T getInstanceOf(RegisteredDecoder registeredDecoder)
|
||||
{
|
||||
if (registeredDecoder.instance != null)
|
||||
{
|
||||
return (T) registeredDecoder.instance;
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
registeredDecoder.instance = registeredDecoder.decoder.newInstance();
|
||||
registeredDecoder.instance.init(this.config);
|
||||
return (T) registeredDecoder.instance;
|
||||
}
|
||||
catch (InstantiationException | IllegalAccessException e)
|
||||
{
|
||||
throw new InitException("Unable to init Decoder for type:" + registeredDecoder.decoder.getName(), e);
|
||||
}
|
||||
}
|
||||
|
||||
public <T extends Decoder> T getInstanceFor(Class<?> type)
|
||||
{
|
||||
try
|
||||
{
|
||||
RegisteredDecoder registeredDecoder = getRegisteredDecoderFor(type);
|
||||
if (registeredDecoder.instance != null)
|
||||
{
|
||||
return registeredDecoder.instance;
|
||||
}
|
||||
|
||||
registeredDecoder.instance = registeredDecoder.decoder.newInstance();
|
||||
registeredDecoder.instance.init(this.config);
|
||||
return registeredDecoder.instance;
|
||||
return getInstanceOf(registeredDecoder);
|
||||
}
|
||||
catch (NoSuchElementException e)
|
||||
{
|
||||
throw new InvalidWebSocketException("No Decoder found for type " + type);
|
||||
}
|
||||
catch (InstantiationException | IllegalAccessException e)
|
||||
{
|
||||
throw new InitException("Unable to init Decoder for type:" + type.getName(), e);
|
||||
}
|
||||
}
|
||||
|
||||
public static Object decodePrimitive(String value, Class<?> type) throws DecodeException
|
||||
|
|
|
@ -22,6 +22,7 @@ import java.nio.ByteBuffer;
|
|||
import java.util.LinkedList;
|
||||
import java.util.List;
|
||||
import java.util.NoSuchElementException;
|
||||
import java.util.Objects;
|
||||
import java.util.function.Predicate;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
|
@ -65,6 +66,7 @@ public class AvailableEncoders implements Predicate<Class<?>>
|
|||
|
||||
public AvailableEncoders(EndpointConfig config)
|
||||
{
|
||||
Objects.requireNonNull(config);
|
||||
this.config = config;
|
||||
registeredEncoders = new LinkedList<>();
|
||||
|
||||
|
|
|
@ -27,8 +27,10 @@ import java.util.ArrayList;
|
|||
import java.util.Comparator;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.NoSuchElementException;
|
||||
import java.util.concurrent.Executor;
|
||||
import java.util.function.BiFunction;
|
||||
import java.util.function.Function;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
import javax.websocket.ClientEndpoint;
|
||||
|
@ -55,6 +57,7 @@ import org.eclipse.jetty.websocket.api.WebSocketException;
|
|||
import org.eclipse.jetty.websocket.api.WebSocketPolicy;
|
||||
import org.eclipse.jetty.websocket.common.InvalidSignatureException;
|
||||
import org.eclipse.jetty.websocket.common.function.CommonEndpointFunctions;
|
||||
import org.eclipse.jetty.websocket.common.message.MessageSink;
|
||||
import org.eclipse.jetty.websocket.common.message.PartialBinaryMessageSink;
|
||||
import org.eclipse.jetty.websocket.common.message.PartialTextMessageSink;
|
||||
import org.eclipse.jetty.websocket.common.reflect.Arg;
|
||||
|
@ -78,6 +81,42 @@ public class JsrEndpointFunctions extends CommonEndpointFunctions<JsrSession>
|
|||
{
|
||||
private static final Logger LOG = Log.getLogger(JsrEndpointFunctions.class);
|
||||
|
||||
protected static class MessageHandlerPongFunction implements Function<ByteBuffer, Void>
|
||||
{
|
||||
public final MessageHandler messageHandler;
|
||||
public final Function<ByteBuffer, Void> function;
|
||||
|
||||
public MessageHandlerPongFunction(MessageHandler messageHandler, Function<ByteBuffer, Void> function)
|
||||
{
|
||||
this.messageHandler = messageHandler;
|
||||
this.function = function;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Void apply(ByteBuffer byteBuffer)
|
||||
{
|
||||
return function.apply(byteBuffer);
|
||||
}
|
||||
}
|
||||
|
||||
protected static class MessageHandlerSink implements MessageSink
|
||||
{
|
||||
public final MessageHandler messageHandler;
|
||||
public final MessageSink delegateSink;
|
||||
|
||||
public MessageHandlerSink(MessageHandler messageHandler, MessageSink messageSink)
|
||||
{
|
||||
this.messageHandler = messageHandler;
|
||||
this.delegateSink = messageSink;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void accept(ByteBuffer payload, Boolean fin)
|
||||
{
|
||||
this.delegateSink.accept(payload, fin);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Represents a static value (as seen from a URI PathParam)
|
||||
* <p>
|
||||
|
@ -128,6 +167,212 @@ public class JsrEndpointFunctions extends CommonEndpointFunctions<JsrSession>
|
|||
}
|
||||
}
|
||||
|
||||
public AvailableDecoders getAvailableDecoders()
|
||||
{
|
||||
return decoders;
|
||||
}
|
||||
|
||||
/**
|
||||
* Identify the message sink the handler belongs to and remove it.
|
||||
* Block if the message sink is actively being used.
|
||||
*
|
||||
* @param handler the handler to remove from possible message sinks
|
||||
* @see {@link javax.websocket.Session#removeMessageHandler(MessageHandler)}
|
||||
* @since JSR356 v1.0
|
||||
*/
|
||||
public void removeMessageHandler(MessageHandler handler)
|
||||
{
|
||||
Function<ByteBuffer, Void> pongFunction = getOnPongFunction();
|
||||
if (pongFunction instanceof MessageHandlerPongFunction)
|
||||
{
|
||||
MessageHandlerPongFunction handlerFunction = (MessageHandlerPongFunction) pongFunction;
|
||||
if (handlerFunction.messageHandler == handler)
|
||||
clearOnPongFunction();
|
||||
}
|
||||
|
||||
MessageSink textSink = getOnTextSink();
|
||||
if (textSink instanceof MessageHandlerSink)
|
||||
{
|
||||
MessageHandlerSink handlerSink = (MessageHandlerSink) textSink;
|
||||
if (handlerSink.messageHandler == handler)
|
||||
clearOnTextSink();
|
||||
}
|
||||
|
||||
MessageSink binarySink = getOnBinarySink();
|
||||
if (binarySink instanceof MessageHandlerSink)
|
||||
{
|
||||
MessageHandlerSink handlerSink = (MessageHandlerSink) binarySink;
|
||||
if (handlerSink.messageHandler == handler)
|
||||
clearOnBinarySink();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a message sink from the provided partial message handler.
|
||||
*
|
||||
* @param clazz the object type
|
||||
* @param handler the partial message handler
|
||||
* @param <T> the generic defined type
|
||||
* @throws IllegalStateException if unable to process message handler
|
||||
* @see {@link javax.websocket.Session#addMessageHandler(Class, MessageHandler.Partial)}
|
||||
* @since JSR356 v1.1
|
||||
*/
|
||||
public <T> void setMessageHandler(Class<T> clazz, MessageHandler.Partial<T> handler) throws IllegalStateException
|
||||
{
|
||||
if (String.class.isAssignableFrom(clazz))
|
||||
{
|
||||
PartialTextMessageSink sink = new PartialTextMessageSink((partial) ->
|
||||
{
|
||||
handler.onMessage((T) partial.getPayload(), partial.isFin());
|
||||
return null;
|
||||
});
|
||||
setOnText(new MessageHandlerSink(handler, sink), handler);
|
||||
return;
|
||||
}
|
||||
|
||||
if (ByteBuffer.class.isAssignableFrom(clazz))
|
||||
{
|
||||
PartialBinaryMessageSink sink = new PartialBinaryMessageSink((partial) ->
|
||||
{
|
||||
handler.onMessage((T) partial.getPayload(), partial.isFin());
|
||||
return null;
|
||||
});
|
||||
setOnBinary(new MessageHandlerSink(handler, sink), handler);
|
||||
return;
|
||||
}
|
||||
|
||||
if (byte[].class.isAssignableFrom(clazz))
|
||||
{
|
||||
PartialBinaryMessageSink sink = new PartialBinaryMessageSink((partial) ->
|
||||
{
|
||||
handler.onMessage((T) BufferUtil.toArray(partial.getPayload()), partial.isFin());
|
||||
return null;
|
||||
});
|
||||
setOnBinary(new MessageHandlerSink(handler, sink), handler);
|
||||
return;
|
||||
}
|
||||
|
||||
// If we reached this point, then the Partial type is unrecognized
|
||||
StringBuilder err = new StringBuilder();
|
||||
err.append("Unrecognized ").append(MessageHandler.Partial.class.getName());
|
||||
err.append(" type <");
|
||||
err.append(clazz.getName());
|
||||
err.append("> on ");
|
||||
err.append(handler.getClass().getName());
|
||||
throw new IllegalStateException(err.toString());
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a message sink from the provided whole message handler.
|
||||
*
|
||||
* @param clazz the object type
|
||||
* @param handler the whole message handler
|
||||
* @param <T> the generic defined type
|
||||
* @throws IllegalStateException if unable to process message handler
|
||||
* @see {@link javax.websocket.Session#addMessageHandler(Class, MessageHandler.Whole)}
|
||||
* @since JSR356 v1.1
|
||||
*/
|
||||
public <T> void setMessageHandler(Class<T> clazz, MessageHandler.Whole<T> handler) throws IllegalStateException
|
||||
{
|
||||
try
|
||||
{
|
||||
// Is this a PongMessage?
|
||||
if (PongMessage.class.isAssignableFrom(PongMessage.class))
|
||||
{
|
||||
Function<ByteBuffer, Void> pongFunction = (payload) ->
|
||||
{
|
||||
handler.onMessage((T) new JsrPongMessage(payload));
|
||||
return null;
|
||||
};
|
||||
setOnPong(new MessageHandlerPongFunction(handler, pongFunction), handler);
|
||||
return;
|
||||
}
|
||||
|
||||
// Try to determine TEXT / BINARY
|
||||
AvailableDecoders.RegisteredDecoder registeredDecoder = decoders.getRegisteredDecoderFor(clazz);
|
||||
|
||||
if (registeredDecoder.implementsInterface(Decoder.Text.class))
|
||||
{
|
||||
Decoder.Text decoderInstance = decoders.getInstanceOf(registeredDecoder);
|
||||
DecodedTextMessageSink textSink = new DecodedTextMessageSink(
|
||||
policy, this, decoderInstance,
|
||||
(msg) ->
|
||||
{
|
||||
handler.onMessage((T) msg);
|
||||
return null;
|
||||
}
|
||||
);
|
||||
setOnText(new MessageHandlerSink(handler, textSink), handler);
|
||||
return;
|
||||
}
|
||||
|
||||
if (registeredDecoder.implementsInterface(Decoder.Binary.class))
|
||||
{
|
||||
Decoder.Binary decoderInstance = decoders.getInstanceOf(registeredDecoder);
|
||||
DecodedBinaryMessageSink binarySink = new DecodedBinaryMessageSink(
|
||||
policy, this, decoderInstance,
|
||||
(msg) ->
|
||||
{
|
||||
handler.onMessage((T) msg);
|
||||
return null;
|
||||
}
|
||||
);
|
||||
setOnBinary(new MessageHandlerSink(handler, binarySink), handler);
|
||||
return;
|
||||
}
|
||||
|
||||
if (registeredDecoder.implementsInterface(Decoder.TextStream.class))
|
||||
{
|
||||
Decoder.TextStream decoderInstance = decoders.getInstanceOf(registeredDecoder);
|
||||
DecodedReaderMessageSink textSink = new DecodedReaderMessageSink(
|
||||
this, decoderInstance,
|
||||
(msg) ->
|
||||
{
|
||||
handler.onMessage((T) msg);
|
||||
return null;
|
||||
}
|
||||
);
|
||||
setOnText(new MessageHandlerSink(handler, textSink), handler);
|
||||
return;
|
||||
}
|
||||
|
||||
if (registeredDecoder.implementsInterface(Decoder.BinaryStream.class))
|
||||
{
|
||||
Decoder.BinaryStream decoderInstance = decoders.getInstanceOf(registeredDecoder);
|
||||
DecodedInputStreamMessageSink binarySink = new DecodedInputStreamMessageSink(
|
||||
this, decoderInstance,
|
||||
(msg) ->
|
||||
{
|
||||
handler.onMessage((T) msg);
|
||||
return null;
|
||||
}
|
||||
);
|
||||
setOnBinary(new MessageHandlerSink(handler, binarySink), handler);
|
||||
return;
|
||||
}
|
||||
|
||||
// If we reached this point, then the Whole Message Type is unrecognized
|
||||
StringBuilder err = new StringBuilder();
|
||||
err.append("Unrecognized message type ");
|
||||
err.append(MessageHandler.Whole.class.getName());
|
||||
err.append("<").append(clazz.getName());
|
||||
err.append("> on ");
|
||||
err.append(handler.getClass().getName());
|
||||
throw new IllegalStateException(err.toString());
|
||||
}
|
||||
catch (NoSuchElementException e)
|
||||
{
|
||||
// No valid decoder for type found
|
||||
StringBuilder err = new StringBuilder();
|
||||
err.append("Not a valid ").append(MessageHandler.Whole.class.getName());
|
||||
err.append(" type <");
|
||||
err.append(clazz.getName());
|
||||
err.append("> on ");
|
||||
err.append(handler.getClass().getName());
|
||||
throw new IllegalStateException(err.toString());
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void discoverEndpointFunctions(Object endpoint)
|
||||
{
|
||||
|
@ -296,228 +541,21 @@ public class JsrEndpointFunctions extends CommonEndpointFunctions<JsrSession>
|
|||
onmsgloop:
|
||||
for (Method onMsg : onMessages)
|
||||
{
|
||||
boolean foundMatch = false;
|
||||
// Whole TEXT / Binary Message
|
||||
if (discoverOnMessageWholeText(onMsg)) continue onmsgloop;
|
||||
if (discoverOnMessageWholeBinary(onMsg)) continue onmsgloop;
|
||||
|
||||
// Try to determine Message type (BINARY / TEXT) from signature
|
||||
// Partial TEXT / BINARY
|
||||
if (discoverOnMessagePartialText(onMsg)) continue onmsgloop;
|
||||
if (discoverOnMessagePartialBinaryArray(onMsg)) continue onmsgloop;
|
||||
if (discoverOnMessagePartialBinaryBuffer(onMsg)) continue onmsgloop;
|
||||
|
||||
Arg SESSION = new Arg(Session.class);
|
||||
// Streaming TEXT / BINARY
|
||||
if (discoverOnMessageTextStream(onMsg)) continue onmsgloop;
|
||||
if (discoverOnMessageBinaryStream(onMsg)) continue onmsgloop;
|
||||
|
||||
// --------------------
|
||||
// -- Whole Messages --
|
||||
// --------------------
|
||||
|
||||
// Whole TEXT
|
||||
for (AvailableDecoders.RegisteredDecoder decoder : decoders.supporting(Decoder.Text.class))
|
||||
{
|
||||
UnorderedSignature sig = new UnorderedSignature(createCallArgs(SESSION, new Arg(decoder.objectType).required()));
|
||||
if (sig.test(onMsg))
|
||||
{
|
||||
assertOnMessageSignature(onMsg);
|
||||
|
||||
final Object[] args = newCallArgs(sig.getCallArgs());
|
||||
args[0] = getSession();
|
||||
BiFunction<Object, Object[], Object> invoker = sig.newFunction(onMsg);
|
||||
Decoder.Text decoderInstance = getDecoderInstance(decoder, Decoder.Text.class);
|
||||
DecodedTextMessageSink textSink = new DecodedTextMessageSink(
|
||||
getSession(),
|
||||
decoderInstance,
|
||||
(msg) ->
|
||||
{
|
||||
args[1] = msg;
|
||||
return invoker.apply(endpoint, args);
|
||||
}
|
||||
);
|
||||
setOnText(textSink, onMsg);
|
||||
continue onmsgloop;
|
||||
}
|
||||
}
|
||||
|
||||
// Whole BINARY
|
||||
for (AvailableDecoders.RegisteredDecoder decoder : decoders.supporting(Decoder.Binary.class))
|
||||
{
|
||||
UnorderedSignature sig = new UnorderedSignature(createCallArgs(SESSION, new Arg(decoder.objectType).required()));
|
||||
if (sig.test(onMsg))
|
||||
{
|
||||
assertOnMessageSignature(onMsg);
|
||||
|
||||
final Object[] args = newCallArgs(sig.getCallArgs());
|
||||
args[0] = getSession();
|
||||
BiFunction<Object, Object[], Object> invoker = sig.newFunction(onMsg);
|
||||
Decoder.Binary decoderInstance = getDecoderInstance(decoder, Decoder.Binary.class);
|
||||
DecodedBinaryMessageSink binarySink = new DecodedBinaryMessageSink(
|
||||
getSession(),
|
||||
decoderInstance,
|
||||
(msg) ->
|
||||
{
|
||||
args[1] = msg;
|
||||
return invoker.apply(endpoint, args);
|
||||
}
|
||||
);
|
||||
setOnBinary(binarySink, onMsg);
|
||||
continue onmsgloop;
|
||||
}
|
||||
}
|
||||
|
||||
// ----------------------
|
||||
// -- Partial Messages --
|
||||
// ----------------------
|
||||
|
||||
Arg ARG_PARTIAL_BOOL = new Arg(boolean.class).required();
|
||||
|
||||
// Partial Text
|
||||
Arg ARG_STRING = new Arg(String.class).required();
|
||||
UnorderedSignature sigPartialText = new UnorderedSignature(createCallArgs(SESSION, ARG_STRING, ARG_PARTIAL_BOOL));
|
||||
if (sigPartialText.test(onMsg))
|
||||
{
|
||||
// Found partial text args
|
||||
assertOnMessageSignature(onMsg);
|
||||
|
||||
final Object[] args = newCallArgs(sigPartialText.getCallArgs());
|
||||
args[0] = getSession();
|
||||
BiFunction<Object, Object[], Object> invoker = sigPartialText.newFunction(onMsg);
|
||||
// No decoders for Partial messages per JSR-356 (PFD1 spec)
|
||||
setOnText(new PartialTextMessageSink((partial) ->
|
||||
{
|
||||
args[1] = partial.getPayload();
|
||||
args[2] = partial.isFin();
|
||||
invoker.apply(endpoint, args);
|
||||
return null;
|
||||
}), onMsg);
|
||||
continue onmsgloop;
|
||||
}
|
||||
|
||||
// Partial Binary
|
||||
Arg ARG_BYTE_ARRAY = new Arg(byte[].class).required();
|
||||
UnorderedSignature sigPartialBinaryArray = new UnorderedSignature(createCallArgs(SESSION, ARG_BYTE_ARRAY, ARG_PARTIAL_BOOL));
|
||||
if (sigPartialBinaryArray.test(onMsg))
|
||||
{
|
||||
// Found partial binary array args
|
||||
assertOnMessageSignature(onMsg);
|
||||
|
||||
final Object[] args = newCallArgs(sigPartialBinaryArray.getCallArgs());
|
||||
args[0] = getSession();
|
||||
BiFunction<Object, Object[], Object> invoker = sigPartialBinaryArray.newFunction(onMsg);
|
||||
// No decoders for Partial messages per JSR-356 (PFD1 spec)
|
||||
setOnBinary(new PartialBinaryMessageSink((partial) ->
|
||||
{
|
||||
args[1] = BufferUtil.toArray(partial.getPayload());
|
||||
args[2] = partial.isFin();
|
||||
invoker.apply(endpoint, args);
|
||||
return null;
|
||||
}), onMsg);
|
||||
continue onmsgloop;
|
||||
}
|
||||
|
||||
Arg ARG_BYTE_BUFFER = new Arg(ByteBuffer.class).required();
|
||||
UnorderedSignature sigPartialByteBuffer = new UnorderedSignature(createCallArgs(SESSION, ARG_BYTE_BUFFER, ARG_PARTIAL_BOOL));
|
||||
if (sigPartialByteBuffer.test(onMsg))
|
||||
{
|
||||
// Found partial binary array args
|
||||
assertOnMessageSignature(onMsg);
|
||||
|
||||
final Object[] args = newCallArgs(sigPartialBinaryArray.getCallArgs());
|
||||
args[0] = getSession();
|
||||
BiFunction<Object, Object[], Object> invoker = sigPartialBinaryArray.newFunction(onMsg);
|
||||
// No decoders for Partial messages per JSR-356 (PFD1 spec)
|
||||
setOnBinary(new PartialBinaryMessageSink((partial) ->
|
||||
{
|
||||
args[1] = partial.getPayload();
|
||||
args[2] = partial.isFin();
|
||||
invoker.apply(endpoint, args);
|
||||
return null;
|
||||
}), onMsg);
|
||||
continue onmsgloop;
|
||||
}
|
||||
|
||||
// ------------------------
|
||||
// -- Streaming Messages --
|
||||
// ------------------------
|
||||
|
||||
// Streaming TEXT ---
|
||||
for (AvailableDecoders.RegisteredDecoder decoder : decoders.supporting(Decoder.TextStream.class))
|
||||
{
|
||||
UnorderedSignature sig = new UnorderedSignature(createCallArgs(SESSION, new Arg(decoder.objectType).required()));
|
||||
if (sig.test(onMsg))
|
||||
{
|
||||
assertOnMessageSignature(onMsg);
|
||||
|
||||
final Object[] args = newCallArgs(sig.getCallArgs());
|
||||
args[0] = getSession();
|
||||
BiFunction<Object, Object[], Object> invoker = sig.newFunction(onMsg);
|
||||
Decoder.TextStream decoderInstance = getDecoderInstance(decoder, Decoder.TextStream.class);
|
||||
DecodedReaderMessageSink textSink = new DecodedReaderMessageSink(
|
||||
getSession(),
|
||||
decoderInstance,
|
||||
(msg) ->
|
||||
{
|
||||
args[1] = msg;
|
||||
return invoker.apply(endpoint, args);
|
||||
}
|
||||
);
|
||||
setOnText(textSink, onMsg);
|
||||
continue onmsgloop;
|
||||
}
|
||||
}
|
||||
|
||||
// Streaming BINARY ---
|
||||
for (AvailableDecoders.RegisteredDecoder decoder : decoders.supporting(Decoder.BinaryStream.class))
|
||||
{
|
||||
UnorderedSignature sig = new UnorderedSignature(createCallArgs(SESSION, new Arg(decoder.objectType).required()));
|
||||
if (sig.test(onMsg))
|
||||
{
|
||||
assertOnMessageSignature(onMsg);
|
||||
|
||||
final Object[] args = newCallArgs(sig.getCallArgs());
|
||||
args[0] = getSession();
|
||||
BiFunction<Object, Object[], Object> invoker = sig.newFunction(onMsg);
|
||||
Decoder.BinaryStream decoderInstance = getDecoderInstance(decoder, Decoder.BinaryStream.class);
|
||||
DecodedInputStreamMessageSink textSink = new DecodedInputStreamMessageSink(
|
||||
getSession(),
|
||||
decoderInstance,
|
||||
(msg) ->
|
||||
{
|
||||
args[1] = msg;
|
||||
return invoker.apply(endpoint, args);
|
||||
}
|
||||
);
|
||||
setOnText(textSink, onMsg);
|
||||
continue onmsgloop;
|
||||
}
|
||||
}
|
||||
|
||||
// -------------------
|
||||
// -- Pong Messages --
|
||||
// -------------------
|
||||
|
||||
// Test for PONG
|
||||
UnorderedSignature sigPong = new UnorderedSignature(createCallArgs(SESSION, new Arg(PongMessage.class).required()));
|
||||
if (sigPong.test(onMsg))
|
||||
{
|
||||
assertOnMessageSignature(onMsg);
|
||||
|
||||
final Object[] args = newCallArgs(sigPong.getCallArgs());
|
||||
args[0] = getSession();
|
||||
BiFunction<Object, Object[], Object> invoker = sigPong.newFunction(onMsg);
|
||||
// No decoder for PongMessage
|
||||
setOnPing((pong) ->
|
||||
{
|
||||
args[1] = new JsrPongMessage(pong);
|
||||
Object ret = invoker.apply(endpoint, args);
|
||||
if (ret != null)
|
||||
{
|
||||
try
|
||||
{
|
||||
getSession().getBasicRemote().sendObject(ret);
|
||||
}
|
||||
catch (EncodeException | IOException e)
|
||||
{
|
||||
throw new WebSocketException(e);
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}, onMsg);
|
||||
continue onmsgloop;
|
||||
}
|
||||
// PONG
|
||||
if (discoverOnMessagePong(onMsg)) continue onmsgloop;
|
||||
|
||||
// If we reached this point, then we have a @OnMessage annotated method
|
||||
// that doesn't match any known signature above.
|
||||
|
@ -527,58 +565,243 @@ public class JsrEndpointFunctions extends CommonEndpointFunctions<JsrSession>
|
|||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a message sink from the provided partial message handler.
|
||||
*
|
||||
* @param clazz the object type
|
||||
* @param handler the partial message handler
|
||||
* @param <T> the generic defined type
|
||||
* @see {@link javax.websocket.Session#addMessageHandler(Class, MessageHandler.Partial)}
|
||||
*/
|
||||
public <T> void setMessageHandler(Class<T> clazz, MessageHandler.Partial<T> handler)
|
||||
private boolean discoverOnMessagePong(Method onMsg) throws DecodeException
|
||||
{
|
||||
// TODO: implement
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a message sink from the provided whole message handler.
|
||||
*
|
||||
* @param clazz the object type
|
||||
* @param handler the whole message handler
|
||||
* @param <T> the generic defined type
|
||||
* @see {@link javax.websocket.Session#addMessageHandler(Class, MessageHandler.Whole)}
|
||||
*/
|
||||
public <T> void setMessageHandler(Class<T> clazz, MessageHandler.Whole<T> handler)
|
||||
{
|
||||
// TODO: implement
|
||||
}
|
||||
|
||||
/**
|
||||
* Identify the message sink the handler belongs to and remove it.
|
||||
* Block if the message sink is actively being used.
|
||||
* @param handler the handler to remove from possible message sinks
|
||||
* @see {@link javax.websocket.Session#removeMessageHandler(MessageHandler)}
|
||||
*/
|
||||
public void removeMessageHandler(MessageHandler handler)
|
||||
{
|
||||
// TODO: implement
|
||||
}
|
||||
|
||||
private <T extends Decoder> T getDecoderInstance(AvailableDecoders.RegisteredDecoder registeredDecoder, Class<T> interfaceType)
|
||||
{
|
||||
// TODO: Return previous instantiated decoders here
|
||||
|
||||
Class<? extends Decoder> decoderClass = registeredDecoder.decoder;
|
||||
try
|
||||
Arg SESSION = new Arg(Session.class);
|
||||
UnorderedSignature sigPong = new UnorderedSignature(createCallArgs(SESSION, new Arg(PongMessage.class).required()));
|
||||
if (sigPong.test(onMsg))
|
||||
{
|
||||
Decoder decoder = decoderClass.newInstance();
|
||||
decoder.init(this.endpointConfig);
|
||||
return (T) decoder;
|
||||
assertOnMessageSignature(onMsg);
|
||||
|
||||
final Object[] args = newCallArgs(sigPong.getCallArgs());
|
||||
BiFunction<Object, Object[], Object> invoker = sigPong.newFunction(onMsg);
|
||||
// No decoder for PongMessage
|
||||
setOnPong((pong) ->
|
||||
{
|
||||
args[0] = getSession();
|
||||
args[1] = new JsrPongMessage(pong);
|
||||
Object ret = invoker.apply(endpoint, args);
|
||||
if (ret != null)
|
||||
{
|
||||
try
|
||||
{
|
||||
getSession().getBasicRemote().sendObject(ret);
|
||||
}
|
||||
catch (EncodeException | IOException e)
|
||||
{
|
||||
throw new WebSocketException(e);
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}, onMsg);
|
||||
return true;
|
||||
}
|
||||
catch (Throwable t)
|
||||
return false;
|
||||
}
|
||||
|
||||
private boolean discoverOnMessageBinaryStream(Method onMsg) throws DecodeException
|
||||
{
|
||||
Arg SESSION = new Arg(Session.class);
|
||||
for (AvailableDecoders.RegisteredDecoder decoder : decoders.supporting(Decoder.BinaryStream.class))
|
||||
{
|
||||
throw new InvalidWebSocketException("Unable to initialize required Decoder: " + decoderClass.getName(), t);
|
||||
UnorderedSignature sig = new UnorderedSignature(createCallArgs(SESSION, new Arg(decoder.objectType).required()));
|
||||
if (sig.test(onMsg))
|
||||
{
|
||||
assertOnMessageSignature(onMsg);
|
||||
|
||||
final Object[] args = newCallArgs(sig.getCallArgs());
|
||||
BiFunction<Object, Object[], Object> invoker = sig.newFunction(onMsg);
|
||||
Decoder.BinaryStream decoderInstance = decoders.getInstanceOf(decoder);
|
||||
DecodedInputStreamMessageSink streamSink = new DecodedInputStreamMessageSink(
|
||||
this,
|
||||
decoderInstance,
|
||||
(msg) ->
|
||||
{
|
||||
args[0] = getSession();
|
||||
args[1] = msg;
|
||||
return invoker.apply(endpoint, args);
|
||||
}
|
||||
);
|
||||
setOnBinary(streamSink, onMsg);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
private boolean discoverOnMessageTextStream(Method onMsg) throws DecodeException
|
||||
{
|
||||
Arg SESSION = new Arg(Session.class);
|
||||
for (AvailableDecoders.RegisteredDecoder decoder : decoders.supporting(Decoder.TextStream.class))
|
||||
{
|
||||
UnorderedSignature sig = new UnorderedSignature(createCallArgs(SESSION, new Arg(decoder.objectType).required()));
|
||||
if (sig.test(onMsg))
|
||||
{
|
||||
assertOnMessageSignature(onMsg);
|
||||
|
||||
final Object[] args = newCallArgs(sig.getCallArgs());
|
||||
BiFunction<Object, Object[], Object> invoker = sig.newFunction(onMsg);
|
||||
Decoder.TextStream decoderInstance = decoders.getInstanceOf(decoder);
|
||||
DecodedReaderMessageSink streamSink = new DecodedReaderMessageSink(
|
||||
this,
|
||||
decoderInstance,
|
||||
(msg) ->
|
||||
{
|
||||
args[0] = getSession();
|
||||
args[1] = msg;
|
||||
return invoker.apply(endpoint, args);
|
||||
}
|
||||
);
|
||||
setOnText(streamSink, onMsg);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
@SuppressWarnings("Duplicates")
|
||||
private boolean discoverOnMessagePartialBinaryBuffer(Method onMsg) throws DecodeException
|
||||
{
|
||||
Arg SESSION = new Arg(Session.class);
|
||||
Arg ARG_BYTE_BUFFER = new Arg(ByteBuffer.class).required();
|
||||
Arg ARG_PARTIAL_BOOL = new Arg(boolean.class).required();
|
||||
UnorderedSignature sigPartialByteBuffer = new UnorderedSignature(createCallArgs(SESSION, ARG_BYTE_BUFFER, ARG_PARTIAL_BOOL));
|
||||
if (sigPartialByteBuffer.test(onMsg))
|
||||
{
|
||||
// Found partial binary array args
|
||||
assertOnMessageSignature(onMsg);
|
||||
|
||||
final Object[] args = newCallArgs(sigPartialByteBuffer.getCallArgs());
|
||||
BiFunction<Object, Object[], Object> invoker = sigPartialByteBuffer.newFunction(onMsg);
|
||||
// No decoders for Partial messages per JSR-356 (PFD1 spec)
|
||||
setOnBinary(new PartialBinaryMessageSink((partial) ->
|
||||
{
|
||||
args[0] = getSession();
|
||||
args[1] = partial.getPayload();
|
||||
args[2] = partial.isFin();
|
||||
invoker.apply(endpoint, args);
|
||||
return null;
|
||||
}), onMsg);
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
private boolean discoverOnMessagePartialBinaryArray(Method onMsg) throws DecodeException
|
||||
{
|
||||
Arg SESSION = new Arg(Session.class);
|
||||
Arg ARG_BYTE_ARRAY = new Arg(byte[].class).required();
|
||||
Arg ARG_PARTIAL_BOOL = new Arg(boolean.class).required();
|
||||
UnorderedSignature sigPartialBinaryArray = new UnorderedSignature(createCallArgs(SESSION, ARG_BYTE_ARRAY, ARG_PARTIAL_BOOL));
|
||||
if (sigPartialBinaryArray.test(onMsg))
|
||||
{
|
||||
// Found partial binary array args
|
||||
assertOnMessageSignature(onMsg);
|
||||
|
||||
final Object[] args = newCallArgs(sigPartialBinaryArray.getCallArgs());
|
||||
BiFunction<Object, Object[], Object> invoker = sigPartialBinaryArray.newFunction(onMsg);
|
||||
// No decoders for Partial messages per JSR-356 (PFD1 spec)
|
||||
setOnBinary(new PartialBinaryMessageSink((partial) ->
|
||||
{
|
||||
args[0] = getSession();
|
||||
args[1] = BufferUtil.toArray(partial.getPayload());
|
||||
args[2] = partial.isFin();
|
||||
invoker.apply(endpoint, args);
|
||||
return null;
|
||||
}), onMsg);
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
@SuppressWarnings("Duplicates")
|
||||
private boolean discoverOnMessagePartialText(Method onMsg) throws DecodeException
|
||||
{
|
||||
Arg SESSION = new Arg(Session.class);
|
||||
Arg ARG_PARTIAL_BOOL = new Arg(boolean.class).required();
|
||||
Arg ARG_STRING = new Arg(String.class).required();
|
||||
UnorderedSignature sigPartialText = new UnorderedSignature(createCallArgs(SESSION, ARG_STRING, ARG_PARTIAL_BOOL));
|
||||
if (sigPartialText.test(onMsg))
|
||||
{
|
||||
// Found partial text args
|
||||
assertOnMessageSignature(onMsg);
|
||||
|
||||
final Object[] args = newCallArgs(sigPartialText.getCallArgs());
|
||||
BiFunction<Object, Object[], Object> invoker = sigPartialText.newFunction(onMsg);
|
||||
// No decoders for Partial messages per JSR-356 (PFD1 spec)
|
||||
setOnText(new PartialTextMessageSink((partial) ->
|
||||
{
|
||||
args[0] = getSession();
|
||||
args[1] = partial.getPayload();
|
||||
args[2] = partial.isFin();
|
||||
invoker.apply(endpoint, args);
|
||||
return null;
|
||||
}), onMsg);
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
private boolean discoverOnMessageWholeBinary(Method onMsg) throws DecodeException
|
||||
{
|
||||
Arg SESSION = new Arg(Session.class);
|
||||
for (AvailableDecoders.RegisteredDecoder decoder : decoders.supporting(Decoder.Binary.class))
|
||||
{
|
||||
UnorderedSignature sig = new UnorderedSignature(createCallArgs(SESSION, new Arg(decoder.objectType).required()));
|
||||
if (sig.test(onMsg))
|
||||
{
|
||||
assertOnMessageSignature(onMsg);
|
||||
|
||||
final Object[] args = newCallArgs(sig.getCallArgs());
|
||||
BiFunction<Object, Object[], Object> invoker = sig.newFunction(onMsg);
|
||||
Decoder.Binary decoderInstance = decoders.getInstanceOf(decoder);
|
||||
DecodedBinaryMessageSink binarySink = new DecodedBinaryMessageSink(
|
||||
policy,
|
||||
this,
|
||||
decoderInstance,
|
||||
(msg) ->
|
||||
{
|
||||
args[0] = getSession();
|
||||
args[1] = msg;
|
||||
return invoker.apply(endpoint, args);
|
||||
}
|
||||
);
|
||||
setOnBinary(binarySink, onMsg);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
private boolean discoverOnMessageWholeText(Method onMsg) throws DecodeException
|
||||
{
|
||||
Arg SESSION = new Arg(Session.class);
|
||||
for (AvailableDecoders.RegisteredDecoder decoder : decoders.supporting(Decoder.Text.class))
|
||||
{
|
||||
UnorderedSignature sig = new UnorderedSignature(createCallArgs(SESSION, new Arg(decoder.objectType).required()));
|
||||
if (sig.test(onMsg))
|
||||
{
|
||||
assertOnMessageSignature(onMsg);
|
||||
|
||||
final Object[] args = newCallArgs(sig.getCallArgs());
|
||||
BiFunction<Object, Object[], Object> invoker = sig.newFunction(onMsg);
|
||||
Decoder.Text decoderInstance = decoders.getInstanceOf(decoder);
|
||||
DecodedTextMessageSink textSink = new DecodedTextMessageSink(
|
||||
policy,
|
||||
this,
|
||||
decoderInstance,
|
||||
(msg) ->
|
||||
{
|
||||
args[0] = getSession();
|
||||
args[1] = msg;
|
||||
return invoker.apply(endpoint, args);
|
||||
}
|
||||
);
|
||||
setOnText(textSink, onMsg);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
private void assertSignatureValid(DynamicArgs.Signature sig, Class<? extends Annotation> annotationClass, Method method)
|
||||
|
@ -631,11 +854,6 @@ public class JsrEndpointFunctions extends CommonEndpointFunctions<JsrSession>
|
|||
}
|
||||
}
|
||||
|
||||
public AvailableDecoders getAvailableDecoders()
|
||||
{
|
||||
return decoders;
|
||||
}
|
||||
|
||||
protected Object[] newCallArgs(Arg[] callArgs) throws DecodeException
|
||||
{
|
||||
int len = callArgs.length;
|
||||
|
|
|
@ -26,14 +26,15 @@ import javax.websocket.Decoder;
|
|||
import javax.websocket.EncodeException;
|
||||
|
||||
import org.eclipse.jetty.websocket.api.WebSocketException;
|
||||
import org.eclipse.jetty.websocket.api.WebSocketPolicy;
|
||||
import org.eclipse.jetty.websocket.common.message.ByteBufferMessageSink;
|
||||
import org.eclipse.jetty.websocket.jsr356.JsrSession;
|
||||
import org.eclipse.jetty.websocket.jsr356.function.JsrEndpointFunctions;
|
||||
|
||||
public class DecodedBinaryMessageSink extends ByteBufferMessageSink
|
||||
{
|
||||
public DecodedBinaryMessageSink(JsrSession session, Decoder.Binary decoder, Function<Object, Object> onMessageFunction)
|
||||
public DecodedBinaryMessageSink(WebSocketPolicy policy, JsrEndpointFunctions endpointFunctions, Decoder.Binary decoder, Function<Object, Object> onMessageFunction)
|
||||
{
|
||||
super(session.getPolicy(), (byteBuf) ->
|
||||
super(policy, (byteBuf) ->
|
||||
{
|
||||
try
|
||||
{
|
||||
|
@ -47,7 +48,7 @@ public class DecodedBinaryMessageSink extends ByteBufferMessageSink
|
|||
if (ret != null)
|
||||
{
|
||||
// send response
|
||||
session.getBasicRemote().sendObject(ret);
|
||||
endpointFunctions.getSession().getBasicRemote().sendObject(ret);
|
||||
}
|
||||
|
||||
return null;
|
||||
|
|
|
@ -28,14 +28,15 @@ import javax.websocket.EncodeException;
|
|||
import org.eclipse.jetty.websocket.api.WebSocketException;
|
||||
import org.eclipse.jetty.websocket.common.message.InputStreamMessageSink;
|
||||
import org.eclipse.jetty.websocket.jsr356.JsrSession;
|
||||
import org.eclipse.jetty.websocket.jsr356.function.JsrEndpointFunctions;
|
||||
|
||||
public class DecodedInputStreamMessageSink extends InputStreamMessageSink
|
||||
{
|
||||
public DecodedInputStreamMessageSink(JsrSession session,
|
||||
public DecodedInputStreamMessageSink(JsrEndpointFunctions endpointFunctions,
|
||||
Decoder.BinaryStream decoder,
|
||||
Function<Object, Object> onMessageFunction)
|
||||
{
|
||||
super(session.getExecutor(), (reader) ->
|
||||
super(endpointFunctions.getExecutor(), (reader) ->
|
||||
{
|
||||
try
|
||||
{
|
||||
|
@ -47,7 +48,7 @@ public class DecodedInputStreamMessageSink extends InputStreamMessageSink
|
|||
if (ret != null)
|
||||
{
|
||||
// send response
|
||||
session.getBasicRemote().sendObject(ret);
|
||||
endpointFunctions.getSession().getBasicRemote().sendObject(ret);
|
||||
}
|
||||
|
||||
return null;
|
||||
|
|
|
@ -27,13 +27,13 @@ import javax.websocket.EncodeException;
|
|||
|
||||
import org.eclipse.jetty.websocket.api.WebSocketException;
|
||||
import org.eclipse.jetty.websocket.common.message.ReaderMessageSink;
|
||||
import org.eclipse.jetty.websocket.jsr356.JsrSession;
|
||||
import org.eclipse.jetty.websocket.jsr356.function.JsrEndpointFunctions;
|
||||
|
||||
public class DecodedReaderMessageSink extends ReaderMessageSink
|
||||
{
|
||||
public DecodedReaderMessageSink(JsrSession session, Decoder.TextStream decoder, Function<Object, Object> onMessageFunction)
|
||||
public DecodedReaderMessageSink(JsrEndpointFunctions endpointFunctions, Decoder.TextStream decoder, Function<Object, Object> onMessageFunction)
|
||||
{
|
||||
super(session.getExecutor(), (reader) ->
|
||||
super(endpointFunctions.getExecutor(), (reader) ->
|
||||
{
|
||||
try
|
||||
{
|
||||
|
@ -45,7 +45,7 @@ public class DecodedReaderMessageSink extends ReaderMessageSink
|
|||
if (ret != null)
|
||||
{
|
||||
// send response
|
||||
session.getBasicRemote().sendObject(ret);
|
||||
endpointFunctions.getSession().getBasicRemote().sendObject(ret);
|
||||
}
|
||||
|
||||
return null;
|
||||
|
|
|
@ -26,14 +26,15 @@ import javax.websocket.Decoder;
|
|||
import javax.websocket.EncodeException;
|
||||
|
||||
import org.eclipse.jetty.websocket.api.WebSocketException;
|
||||
import org.eclipse.jetty.websocket.api.WebSocketPolicy;
|
||||
import org.eclipse.jetty.websocket.common.message.StringMessageSink;
|
||||
import org.eclipse.jetty.websocket.jsr356.JsrSession;
|
||||
import org.eclipse.jetty.websocket.jsr356.function.JsrEndpointFunctions;
|
||||
|
||||
public class DecodedTextMessageSink extends StringMessageSink
|
||||
{
|
||||
public DecodedTextMessageSink(JsrSession session, Decoder.Text decoder, Function<Object, Object> onMessageFunction)
|
||||
public DecodedTextMessageSink(WebSocketPolicy policy, JsrEndpointFunctions endpointFunctions, Decoder.Text decoder, Function<Object, Object> onMessageFunction)
|
||||
{
|
||||
super(session.getPolicy(), (message) ->
|
||||
super(policy, (message) ->
|
||||
{
|
||||
try
|
||||
{
|
||||
|
@ -45,7 +46,7 @@ public class DecodedTextMessageSink extends StringMessageSink
|
|||
if (ret != null)
|
||||
{
|
||||
// send response
|
||||
session.getBasicRemote().sendObject(ret);
|
||||
endpointFunctions.getSession().getBasicRemote().sendObject(ret);
|
||||
}
|
||||
|
||||
return null;
|
||||
|
|
|
@ -1,112 +0,0 @@
|
|||
//
|
||||
// ========================================================================
|
||||
// Copyright (c) 1995-2016 Mort Bay Consulting Pty. Ltd.
|
||||
// ------------------------------------------------------------------------
|
||||
// All rights reserved. This program and the accompanying materials
|
||||
// are made available under the terms of the Eclipse Public License v1.0
|
||||
// and Apache License v2.0 which accompanies this distribution.
|
||||
//
|
||||
// The Eclipse Public License is available at
|
||||
// http://www.eclipse.org/legal/epl-v10.html
|
||||
//
|
||||
// The Apache License v2.0 is available at
|
||||
// http://www.opensource.org/licenses/apache2.0.php
|
||||
//
|
||||
// You may elect to redistribute this code under either of these licenses.
|
||||
// ========================================================================
|
||||
//
|
||||
|
||||
package org.eclipse.jetty.websocket.jsr356;
|
||||
|
||||
import static org.hamcrest.Matchers.is;
|
||||
|
||||
import java.nio.ByteBuffer;
|
||||
import java.util.Date;
|
||||
|
||||
import javax.websocket.Decoder;
|
||||
|
||||
import org.eclipse.jetty.websocket.api.WebSocketPolicy;
|
||||
import org.eclipse.jetty.websocket.common.scopes.SimpleContainerScope;
|
||||
import org.eclipse.jetty.websocket.common.scopes.WebSocketContainerScope;
|
||||
import org.eclipse.jetty.websocket.jsr356.decoders.ByteArrayDecoder;
|
||||
import org.eclipse.jetty.websocket.jsr356.decoders.ByteBufferDecoder;
|
||||
import org.eclipse.jetty.websocket.jsr356.decoders.DateDecoder;
|
||||
import org.eclipse.jetty.websocket.jsr356.decoders.IntegerDecoder;
|
||||
import org.eclipse.jetty.websocket.jsr356.decoders.LongDecoder;
|
||||
import org.eclipse.jetty.websocket.jsr356.decoders.PrimitiveDecoderMetadataSet;
|
||||
import org.eclipse.jetty.websocket.jsr356.decoders.StringDecoder;
|
||||
import org.eclipse.jetty.websocket.jsr356.metadata.DecoderMetadata;
|
||||
import org.eclipse.jetty.websocket.jsr356.metadata.DecoderMetadataSet;
|
||||
import org.eclipse.jetty.websocket.jsr356.samples.Fruit;
|
||||
import org.eclipse.jetty.websocket.jsr356.samples.FruitDecoder;
|
||||
import org.junit.Assert;
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
|
||||
public class DecoderFactoryTest
|
||||
{
|
||||
private DecoderMetadataSet metadatas;
|
||||
private DecoderFactory factory;
|
||||
|
||||
private void assertMetadataFor(Class<?> type, Class<? extends Decoder> expectedDecoderClass, MessageType expectedType)
|
||||
{
|
||||
DecoderMetadata metadata = factory.getMetadataFor(type);
|
||||
Assert.assertEquals("metadata.coderClass",metadata.getCoderClass(),expectedDecoderClass);
|
||||
Assert.assertThat("metadata.messageType",metadata.getMessageType(),is(expectedType));
|
||||
Assert.assertEquals("metadata.objectType",metadata.getObjectType(),type);
|
||||
}
|
||||
|
||||
@Before
|
||||
public void initDecoderFactory()
|
||||
{
|
||||
WebSocketContainerScope containerScope = new SimpleContainerScope(WebSocketPolicy.newClientPolicy());
|
||||
|
||||
DecoderFactory primitivesFactory = new DecoderFactory(containerScope,PrimitiveDecoderMetadataSet.INSTANCE);
|
||||
metadatas = new DecoderMetadataSet();
|
||||
factory = new DecoderFactory(containerScope,metadatas,primitivesFactory);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testGetMetadataForByteArray()
|
||||
{
|
||||
assertMetadataFor(byte[].class,ByteArrayDecoder.class,MessageType.BINARY);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testGetMetadataForByteBuffer()
|
||||
{
|
||||
assertMetadataFor(ByteBuffer.class,ByteBufferDecoder.class,MessageType.BINARY);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testGetMetadataForDate()
|
||||
{
|
||||
metadatas.add(DateDecoder.class);
|
||||
assertMetadataFor(Date.class,DateDecoder.class,MessageType.TEXT);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testGetMetadataForFruit()
|
||||
{
|
||||
metadatas.add(FruitDecoder.class);
|
||||
assertMetadataFor(Fruit.class,FruitDecoder.class,MessageType.TEXT);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testGetMetadataForInteger()
|
||||
{
|
||||
assertMetadataFor(Integer.TYPE,IntegerDecoder.class,MessageType.TEXT);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testGetMetadataForLong()
|
||||
{
|
||||
assertMetadataFor(Long.TYPE,LongDecoder.class,MessageType.TEXT);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testGetStringDecoder()
|
||||
{
|
||||
assertMetadataFor(String.class,StringDecoder.class,MessageType.TEXT);
|
||||
}
|
||||
}
|
|
@ -1,91 +0,0 @@
|
|||
//
|
||||
// ========================================================================
|
||||
// Copyright (c) 1995-2016 Mort Bay Consulting Pty. Ltd.
|
||||
// ------------------------------------------------------------------------
|
||||
// All rights reserved. This program and the accompanying materials
|
||||
// are made available under the terms of the Eclipse Public License v1.0
|
||||
// and Apache License v2.0 which accompanies this distribution.
|
||||
//
|
||||
// The Eclipse Public License is available at
|
||||
// http://www.eclipse.org/legal/epl-v10.html
|
||||
//
|
||||
// The Apache License v2.0 is available at
|
||||
// http://www.opensource.org/licenses/apache2.0.php
|
||||
//
|
||||
// You may elect to redistribute this code under either of these licenses.
|
||||
// ========================================================================
|
||||
//
|
||||
|
||||
package org.eclipse.jetty.websocket.jsr356;
|
||||
|
||||
import static org.hamcrest.Matchers.is;
|
||||
|
||||
import javax.websocket.Encoder;
|
||||
|
||||
import org.eclipse.jetty.websocket.api.WebSocketPolicy;
|
||||
import org.eclipse.jetty.websocket.common.scopes.SimpleContainerScope;
|
||||
import org.eclipse.jetty.websocket.common.scopes.WebSocketContainerScope;
|
||||
import org.eclipse.jetty.websocket.jsr356.encoders.IntegerEncoder;
|
||||
import org.eclipse.jetty.websocket.jsr356.encoders.LongEncoder;
|
||||
import org.eclipse.jetty.websocket.jsr356.encoders.PrimitiveEncoderMetadataSet;
|
||||
import org.eclipse.jetty.websocket.jsr356.metadata.EncoderMetadata;
|
||||
import org.eclipse.jetty.websocket.jsr356.metadata.EncoderMetadataSet;
|
||||
import org.eclipse.jetty.websocket.jsr356.samples.Fruit;
|
||||
import org.eclipse.jetty.websocket.jsr356.samples.FruitBinaryEncoder;
|
||||
import org.eclipse.jetty.websocket.jsr356.samples.FruitTextEncoder;
|
||||
import org.junit.Assert;
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
|
||||
/**
|
||||
* Tests against the AvailableEncoders class
|
||||
*/
|
||||
public class EncoderFactoryTest
|
||||
{
|
||||
private EncoderMetadataSet metadatas;
|
||||
private EncoderFactory factory;
|
||||
|
||||
private void assertMetadataFor(Class<?> type, Class<? extends Encoder> expectedEncoderClass, MessageType expectedType)
|
||||
{
|
||||
EncoderMetadata metadata = factory.getMetadataFor(type);
|
||||
Assert.assertEquals("metadata.coderClass",metadata.getCoderClass(),expectedEncoderClass);
|
||||
Assert.assertThat("metadata.messageType",metadata.getMessageType(),is(expectedType));
|
||||
Assert.assertEquals("metadata.objectType",metadata.getObjectType(),type);
|
||||
}
|
||||
|
||||
@Before
|
||||
public void initEncoderFactory()
|
||||
{
|
||||
WebSocketContainerScope containerScope = new SimpleContainerScope(WebSocketPolicy.newClientPolicy());
|
||||
|
||||
EncoderFactory primitivesFactory = new EncoderFactory(containerScope,PrimitiveEncoderMetadataSet.INSTANCE);
|
||||
metadatas = new EncoderMetadataSet();
|
||||
factory = new EncoderFactory(containerScope,metadatas,primitivesFactory);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testGetMetadataForFruitBinary()
|
||||
{
|
||||
metadatas.add(FruitBinaryEncoder.class);
|
||||
assertMetadataFor(Fruit.class,FruitBinaryEncoder.class,MessageType.BINARY);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testGetMetadataForFruitText()
|
||||
{
|
||||
metadatas.add(FruitTextEncoder.class);
|
||||
assertMetadataFor(Fruit.class,FruitTextEncoder.class,MessageType.TEXT);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testGetMetadataForInteger()
|
||||
{
|
||||
assertMetadataFor(Integer.TYPE,IntegerEncoder.class,MessageType.TEXT);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testGetMetadataForLong()
|
||||
{
|
||||
assertMetadataFor(Long.TYPE,LongEncoder.class,MessageType.TEXT);
|
||||
}
|
||||
}
|
|
@ -205,6 +205,7 @@ public class EncoderTest
|
|||
}
|
||||
}
|
||||
|
||||
@SuppressWarnings("Duplicates")
|
||||
private Quotes getQuotes(String filename) throws IOException
|
||||
{
|
||||
Quotes quotes = new Quotes();
|
||||
|
|
|
@ -27,7 +27,6 @@ import javax.websocket.MessageHandler;
|
|||
import org.eclipse.jetty.websocket.api.WebSocketPolicy;
|
||||
import org.eclipse.jetty.websocket.common.test.DummyConnection;
|
||||
import org.eclipse.jetty.websocket.jsr356.client.EmptyClientEndpointConfig;
|
||||
import org.eclipse.jetty.websocket.jsr356.client.SimpleEndpointMetadata;
|
||||
import org.eclipse.jetty.websocket.jsr356.handlers.ByteArrayWholeHandler;
|
||||
import org.eclipse.jetty.websocket.jsr356.handlers.ByteBufferPartialHandler;
|
||||
import org.eclipse.jetty.websocket.jsr356.handlers.LongMessageHandler;
|
||||
|
@ -44,29 +43,19 @@ public class JsrSessionTest
|
|||
@Before
|
||||
public void initSession()
|
||||
{
|
||||
container = new ClientContainer();
|
||||
String id = JsrSessionTest.class.getSimpleName();
|
||||
URI requestURI = URI.create("ws://localhost/" + id);
|
||||
WebSocketPolicy policy = WebSocketPolicy.newClientPolicy();
|
||||
DummyConnection connection = new DummyConnection(policy);
|
||||
ClientEndpointConfig config = new EmptyClientEndpointConfig();
|
||||
DummyEndpoint websocket = new DummyEndpoint();
|
||||
SimpleEndpointMetadata metadata = new SimpleEndpointMetadata(websocket.getClass());
|
||||
// Executor executor = null;
|
||||
|
||||
ConfiguredEndpoint ei = new ConfiguredEndpoint(websocket,config);
|
||||
|
||||
// EventDriver driver = new JsrEndpointEventDriver(policy,ei);
|
||||
DummyConnection connection = new DummyConnection();
|
||||
session = new JsrSession(container,id,requestURI,ei,connection);
|
||||
ConfiguredEndpoint ei = new ConfiguredEndpoint(new DummyEndpoint(), config);
|
||||
session = new JsrSession(container, id, requestURI, ei, connection);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testMessageHandlerBinary() throws DeploymentException
|
||||
{
|
||||
session.addMessageHandler(new ByteBufferPartialHandler());
|
||||
// MessageHandlerWrapper wrapper = session.getMessageHandlerWrapper(MessageType.BINARY);
|
||||
// Assert.assertThat("Binary Handler",wrapper.getHandler(),instanceOf(ByteBufferPartialHandler.class));
|
||||
// Assert.assertEquals("Message Class",wrapper.getMetadata().getMessageClass(),ByteBuffer.class);
|
||||
}
|
||||
|
||||
@Test
|
||||
|
@ -74,12 +63,6 @@ public class JsrSessionTest
|
|||
{
|
||||
session.addMessageHandler(new StringWholeHandler());
|
||||
session.addMessageHandler(new ByteArrayWholeHandler());
|
||||
// MessageHandlerWrapper wrapper = session.getMessageHandlerWrapper(MessageType.TEXT);
|
||||
// Assert.assertThat("Text Handler",wrapper.getHandler(),instanceOf(StringWholeHandler.class));
|
||||
// Assert.assertEquals("Message Class",wrapper.getMetadata().getMessageClass(),String.class);
|
||||
// wrapper = session.getMessageHandlerWrapper(MessageType.BINARY);
|
||||
// Assert.assertThat("Binary Handler",wrapper.getHandler(),instanceOf(ByteArrayWholeHandler.class));
|
||||
// Assert.assertEquals("Message Class",wrapper.getMetadata().getMessageClass(),byte[].class);
|
||||
}
|
||||
|
||||
@Test
|
||||
|
@ -90,20 +73,11 @@ public class JsrSessionTest
|
|||
session.addMessageHandler(new ByteArrayWholeHandler()); // add BINARY handler
|
||||
session.removeMessageHandler(oldText); // remove original TEXT handler
|
||||
session.addMessageHandler(new LongMessageHandler()); // add new TEXT handler
|
||||
// MessageHandlerWrapper wrapper = session.getMessageHandlerWrapper(MessageType.BINARY);
|
||||
// Assert.assertThat("Binary Handler",wrapper.getHandler(),instanceOf(ByteArrayWholeHandler.class));
|
||||
// Assert.assertEquals("Message Class",wrapper.getMetadata().getMessageClass(),byte[].class);
|
||||
// wrapper = session.getMessageHandlerWrapper(MessageType.TEXT);
|
||||
// Assert.assertThat("Text Handler",wrapper.getHandler(),instanceOf(LongMessageHandler.class));
|
||||
// Assert.assertEquals("Message Class",wrapper.getMetadata().getMessageClass(),Long.class);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testMessageHandlerText() throws DeploymentException
|
||||
{
|
||||
session.addMessageHandler(new StringWholeHandler());
|
||||
// MessageHandlerWrapper wrapper = session.getMessageHandlerWrapper(MessageType.TEXT);
|
||||
// Assert.assertThat("Text Handler",wrapper.getHandler(),instanceOf(StringWholeHandler.class));
|
||||
// Assert.assertEquals("Message Class",wrapper.getMetadata().getMessageClass(),String.class);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,81 +0,0 @@
|
|||
//
|
||||
// ========================================================================
|
||||
// Copyright (c) 1995-2016 Mort Bay Consulting Pty. Ltd.
|
||||
// ------------------------------------------------------------------------
|
||||
// All rights reserved. This program and the accompanying materials
|
||||
// are made available under the terms of the Eclipse Public License v1.0
|
||||
// and Apache License v2.0 which accompanies this distribution.
|
||||
//
|
||||
// The Eclipse Public License is available at
|
||||
// http://www.eclipse.org/legal/epl-v10.html
|
||||
//
|
||||
// The Apache License v2.0 is available at
|
||||
// http://www.opensource.org/licenses/apache2.0.php
|
||||
//
|
||||
// You may elect to redistribute this code under either of these licenses.
|
||||
// ========================================================================
|
||||
//
|
||||
|
||||
package org.eclipse.jetty.websocket.jsr356;
|
||||
|
||||
import static org.hamcrest.Matchers.is;
|
||||
|
||||
import java.lang.reflect.Type;
|
||||
import java.util.List;
|
||||
|
||||
import javax.websocket.DeploymentException;
|
||||
|
||||
import org.eclipse.jetty.websocket.api.WebSocketPolicy;
|
||||
import org.eclipse.jetty.websocket.common.scopes.SimpleContainerScope;
|
||||
import org.eclipse.jetty.websocket.common.scopes.WebSocketContainerScope;
|
||||
import org.eclipse.jetty.websocket.jsr356.decoders.PrimitiveDecoderMetadataSet;
|
||||
import org.eclipse.jetty.websocket.jsr356.handlers.ByteArrayPartialHandler;
|
||||
import org.eclipse.jetty.websocket.jsr356.handlers.StringPartialHandler;
|
||||
import org.eclipse.jetty.websocket.jsr356.metadata.DecoderMetadata;
|
||||
import org.eclipse.jetty.websocket.jsr356.metadata.DecoderMetadataSet;
|
||||
import org.eclipse.jetty.websocket.jsr356.metadata.MessageHandlerMetadata;
|
||||
import org.junit.Assert;
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
|
||||
public class MessageHandlerFactoryTest
|
||||
{
|
||||
private MessageHandlerFactory factory;
|
||||
private DecoderMetadataSet metadatas;
|
||||
private DecoderFactory decoders;
|
||||
|
||||
@Before
|
||||
public void init() throws DeploymentException
|
||||
{
|
||||
WebSocketContainerScope containerScope = new SimpleContainerScope(WebSocketPolicy.newClientPolicy());
|
||||
|
||||
DecoderFactory primitivesFactory = new DecoderFactory(containerScope,PrimitiveDecoderMetadataSet.INSTANCE);
|
||||
metadatas = new DecoderMetadataSet();
|
||||
decoders = new DecoderFactory(containerScope,metadatas,primitivesFactory);
|
||||
factory = new MessageHandlerFactory();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testByteArrayPartial() throws DeploymentException
|
||||
{
|
||||
List<MessageHandlerMetadata> metadatas = factory.getMetadata(ByteArrayPartialHandler.class);
|
||||
Assert.assertThat("Metadata.list.size",metadatas.size(),is(1));
|
||||
|
||||
MessageHandlerMetadata handlerMetadata = metadatas.get(0);
|
||||
DecoderMetadata decoderMetadata = decoders.getMetadataFor(handlerMetadata.getMessageClass());
|
||||
Assert.assertThat("Message Type",decoderMetadata.getMessageType(),is(MessageType.BINARY));
|
||||
Assert.assertThat("Message Class",handlerMetadata.getMessageClass(),is((Type)byte[].class));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testStringPartial() throws DeploymentException
|
||||
{
|
||||
List<MessageHandlerMetadata> metadatas = factory.getMetadata(StringPartialHandler.class);
|
||||
Assert.assertThat("Metadata.list.size",metadatas.size(),is(1));
|
||||
|
||||
MessageHandlerMetadata handlerMetadata = metadatas.get(0);
|
||||
DecoderMetadata decoderMetadata = decoders.getMetadataFor(handlerMetadata.getMessageClass());
|
||||
Assert.assertThat("Message Type",decoderMetadata.getMessageType(),is(MessageType.TEXT));
|
||||
Assert.assertThat("Message Class",handlerMetadata.getMessageClass(),is((Type)String.class));
|
||||
}
|
||||
}
|
|
@ -1,47 +0,0 @@
|
|||
//
|
||||
// ========================================================================
|
||||
// Copyright (c) 1995-2016 Mort Bay Consulting Pty. Ltd.
|
||||
// ------------------------------------------------------------------------
|
||||
// All rights reserved. This program and the accompanying materials
|
||||
// are made available under the terms of the Eclipse Public License v1.0
|
||||
// and Apache License v2.0 which accompanies this distribution.
|
||||
//
|
||||
// The Eclipse Public License is available at
|
||||
// http://www.eclipse.org/legal/epl-v10.html
|
||||
//
|
||||
// The Apache License v2.0 is available at
|
||||
// http://www.opensource.org/licenses/apache2.0.php
|
||||
//
|
||||
// You may elect to redistribute this code under either of these licenses.
|
||||
// ========================================================================
|
||||
//
|
||||
|
||||
package org.eclipse.jetty.websocket.jsr356.annotations;
|
||||
|
||||
@Deprecated
|
||||
public class JsrParamIdDecoderTest
|
||||
{
|
||||
/*private JsrCallable getOnMessageCallableFrom(Class<?> clazz, String methodName)
|
||||
{
|
||||
for (Method method : clazz.getMethods())
|
||||
{
|
||||
if (method.getName().equals(methodName))
|
||||
{
|
||||
return new OnMessageCallable(clazz,method);
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testMatchDateDecoder()
|
||||
{
|
||||
DecoderMetadata metadata = new DecoderMetadata(DateDecoder.class,Date.class,MessageType.TEXT,false);
|
||||
JsrParamIdDecoder paramId = new JsrParamIdDecoder(metadata);
|
||||
|
||||
JsrCallable callable = getOnMessageCallableFrom(DateTextSocket.class,"onMessage");
|
||||
Param param = new Param(0,Date.class,null);
|
||||
|
||||
Assert.assertThat("Match for Decoder",paramId.process(param,callable),is(true));
|
||||
}*/
|
||||
}
|
|
@ -18,6 +18,7 @@
|
|||
|
||||
package org.eclipse.jetty.websocket.jsr356.decoders;
|
||||
|
||||
import static org.hamcrest.Matchers.containsString;
|
||||
import static org.hamcrest.Matchers.equalTo;
|
||||
import static org.hamcrest.Matchers.is;
|
||||
import static org.hamcrest.Matchers.notNullValue;
|
||||
|
@ -33,10 +34,13 @@ import javax.websocket.DecodeException;
|
|||
import javax.websocket.Decoder;
|
||||
import javax.websocket.EndpointConfig;
|
||||
|
||||
import org.eclipse.jetty.websocket.api.InvalidWebSocketException;
|
||||
import org.eclipse.jetty.websocket.common.util.Hex;
|
||||
import org.eclipse.jetty.websocket.jsr356.client.EmptyClientEndpointConfig;
|
||||
import org.junit.BeforeClass;
|
||||
import org.junit.Rule;
|
||||
import org.junit.Test;
|
||||
import org.junit.rules.ExpectedException;
|
||||
|
||||
public class AvailableDecodersTest
|
||||
{
|
||||
|
@ -47,30 +51,25 @@ public class AvailableDecodersTest
|
|||
{
|
||||
testConfig = new EmptyClientEndpointConfig();
|
||||
}
|
||||
|
||||
private AvailableDecoders decoders = new AvailableDecoders();
|
||||
|
||||
@Rule
|
||||
public ExpectedException expectedException = ExpectedException.none();
|
||||
|
||||
private AvailableDecoders decoders = new AvailableDecoders(testConfig);
|
||||
|
||||
private <T> void assertTextDecoder(Class<T> type, String value, T expectedDecoded) throws IllegalAccessException, InstantiationException, DecodeException
|
||||
{
|
||||
Class<? extends Decoder> decoderClass = decoders.getDecoderFor(type);
|
||||
assertThat("Decoder Class", decoderClass, notNullValue());
|
||||
|
||||
Decoder.Text<T> decoder = (Decoder.Text<T>) decoderClass.newInstance();
|
||||
decoder.init(testConfig);
|
||||
Decoder.Text<T> decoder = (Decoder.Text<T>) decoders.getInstanceFor(type);
|
||||
assertThat("Decoder instance", decoder, notNullValue());
|
||||
T decoded = decoder.decode(value);
|
||||
|
||||
assertThat("Decoded", decoded, is(expectedDecoded));
|
||||
}
|
||||
|
||||
private <T> void assertBinaryDecoder(Class<T> type, ByteBuffer value, T expectedDecoded) throws IllegalAccessException, InstantiationException, DecodeException
|
||||
{
|
||||
Class<? extends Decoder> decoderClass = decoders.getDecoderFor(type);
|
||||
assertThat("Decoder Class", decoderClass, notNullValue());
|
||||
|
||||
Decoder.Binary<T> decoder = (Decoder.Binary<T>) decoderClass.newInstance();
|
||||
decoder.init(testConfig);
|
||||
Decoder.Binary<T> decoder = (Decoder.Binary<T>) decoders.getInstanceFor(type);
|
||||
assertThat("Decoder Class", decoder, notNullValue());
|
||||
T decoded = decoder.decode(value);
|
||||
|
||||
assertThat("Decoded", decoded, equalTo(expectedDecoded));
|
||||
}
|
||||
|
||||
|
@ -194,6 +193,16 @@ public class AvailableDecodersTest
|
|||
byte expected[] = Hex.asByteArray("112233445566778899");
|
||||
assertBinaryDecoder(byte[].class, val, expected);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testCustomDecoder_Integer() throws IllegalAccessException, InstantiationException, DecodeException
|
||||
{
|
||||
decoders.register(IntegerDecoder.class);
|
||||
|
||||
String val = "11223344";
|
||||
int expected = 11223344;
|
||||
assertTextDecoder(Integer.class, val, expected);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testCustomDecoder_Time() throws IllegalAccessException, InstantiationException, DecodeException
|
||||
|
@ -260,6 +269,9 @@ public class AvailableDecodersTest
|
|||
public void testCustomDecoder_ValidDual_Text() throws IllegalAccessException, InstantiationException, DecodeException
|
||||
{
|
||||
decoders.register(ValidDualDecoder.class);
|
||||
|
||||
AvailableDecoders.RegisteredDecoder registered = decoders.getRegisteredDecoderFor(Integer.class);
|
||||
assertThat("Registered Decoder for Integer", registered.decoder.getName(), is(ValidDualDecoder.class.getName()));
|
||||
|
||||
String val = "[1,234,567]";
|
||||
Integer expected = 1234567;
|
||||
|
@ -271,6 +283,9 @@ public class AvailableDecodersTest
|
|||
public void testCustomDecoder_ValidDual_Binary() throws IllegalAccessException, InstantiationException, DecodeException
|
||||
{
|
||||
decoders.register(ValidDualDecoder.class);
|
||||
|
||||
AvailableDecoders.RegisteredDecoder registered = decoders.getRegisteredDecoderFor(Long.class);
|
||||
assertThat("Registered Decoder for Long", registered.decoder.getName(), is(ValidDualDecoder.class.getName()));
|
||||
|
||||
ByteBuffer val = ByteBuffer.allocate(16);
|
||||
val.put((byte) '[');
|
||||
|
@ -281,4 +296,25 @@ public class AvailableDecodersTest
|
|||
|
||||
assertBinaryDecoder(Long.class, val, expected);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testCustomDecoder_Register_Duplicate()
|
||||
{
|
||||
// has duplicated support for the same target Type
|
||||
expectedException.expect(InvalidWebSocketException.class);
|
||||
expectedException.expectMessage(containsString("Duplicate"));
|
||||
decoders.register(BadDualDecoder.class);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testCustomDecoder_Register_OtherDuplicate()
|
||||
{
|
||||
// Register DateDecoder (decodes java.util.Date)
|
||||
decoders.register(DateDecoder.class);
|
||||
|
||||
// Register TimeDecoder (which also wants to decode java.util.Date)
|
||||
expectedException.expect(InvalidWebSocketException.class);
|
||||
expectedException.expectMessage(containsString("Duplicate"));
|
||||
decoders.register(TimeDecoder.class);
|
||||
}
|
||||
}
|
|
@ -1,54 +0,0 @@
|
|||
//
|
||||
// ========================================================================
|
||||
// Copyright (c) 1995-2016 Mort Bay Consulting Pty. Ltd.
|
||||
// ------------------------------------------------------------------------
|
||||
// All rights reserved. This program and the accompanying materials
|
||||
// are made available under the terms of the Eclipse Public License v1.0
|
||||
// and Apache License v2.0 which accompanies this distribution.
|
||||
//
|
||||
// The Eclipse Public License is available at
|
||||
// http://www.eclipse.org/legal/epl-v10.html
|
||||
//
|
||||
// The Apache License v2.0 is available at
|
||||
// http://www.opensource.org/licenses/apache2.0.php
|
||||
//
|
||||
// You may elect to redistribute this code under either of these licenses.
|
||||
// ========================================================================
|
||||
//
|
||||
|
||||
package org.eclipse.jetty.websocket.jsr356.decoders;
|
||||
|
||||
import static org.hamcrest.Matchers.is;
|
||||
import static org.hamcrest.Matchers.notNullValue;
|
||||
|
||||
import javax.websocket.Decoder;
|
||||
|
||||
import org.eclipse.jetty.websocket.jsr356.MessageType;
|
||||
import org.eclipse.jetty.websocket.jsr356.metadata.DecoderMetadata;
|
||||
import org.junit.Assert;
|
||||
import org.junit.Test;
|
||||
|
||||
public class PrimitiveDecoderMetadataSetTest
|
||||
{
|
||||
private void assertClassEquals(String msg, Class<?> actual, Class<?> expected)
|
||||
{
|
||||
Assert.assertThat(msg,actual.getName(),is(expected.getName()));
|
||||
}
|
||||
|
||||
private void assertDecoderType(Class<? extends Decoder> expectedDecoder, MessageType expectedMsgType, Class<?> type)
|
||||
{
|
||||
PrimitiveDecoderMetadataSet primitives = new PrimitiveDecoderMetadataSet();
|
||||
DecoderMetadata metadata = primitives.getMetadataByType(type);
|
||||
String prefix = String.format("Metadata By Type [%s]",type.getName());
|
||||
Assert.assertThat(prefix,metadata,notNullValue());
|
||||
|
||||
assertClassEquals(prefix + ".coderClass",metadata.getCoderClass(),expectedDecoder);
|
||||
Assert.assertThat(prefix + ".messageType",metadata.getMessageType(),is(expectedMsgType));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testGetByteArray()
|
||||
{
|
||||
assertDecoderType(ByteArrayDecoder.class,MessageType.BINARY,byte[].class);
|
||||
}
|
||||
}
|
|
@ -18,6 +18,7 @@
|
|||
|
||||
package org.eclipse.jetty.websocket.jsr356.encoders;
|
||||
|
||||
import static org.hamcrest.Matchers.containsString;
|
||||
import static org.hamcrest.Matchers.is;
|
||||
import static org.hamcrest.Matchers.notNullValue;
|
||||
import static org.junit.Assert.assertThat;
|
||||
|
@ -37,7 +38,9 @@ import javax.websocket.EndpointConfig;
|
|||
import org.eclipse.jetty.websocket.common.util.Hex;
|
||||
import org.eclipse.jetty.websocket.jsr356.client.EmptyClientEndpointConfig;
|
||||
import org.junit.BeforeClass;
|
||||
import org.junit.Rule;
|
||||
import org.junit.Test;
|
||||
import org.junit.rules.ExpectedException;
|
||||
|
||||
public class AvailableEncodersTest
|
||||
{
|
||||
|
@ -48,28 +51,24 @@ public class AvailableEncodersTest
|
|||
{
|
||||
testConfig = new EmptyClientEndpointConfig();
|
||||
}
|
||||
|
||||
private AvailableEncoders encoders = new AvailableEncoders();
|
||||
|
||||
@Rule
|
||||
public ExpectedException expectedException = ExpectedException.none();
|
||||
|
||||
private AvailableEncoders encoders = new AvailableEncoders(testConfig);
|
||||
|
||||
public <T> void assertTextEncoder(Class<T> type, T value, String expectedEncoded) throws IllegalAccessException, InstantiationException, EncodeException
|
||||
{
|
||||
Class<? extends Encoder> encoderClass = encoders.getEncoderFor(type);
|
||||
assertThat("Encoder Class", encoderClass, notNullValue());
|
||||
|
||||
Encoder.Text<T> encoder = (Encoder.Text<T>) encoderClass.newInstance();
|
||||
encoder.init(testConfig);
|
||||
Encoder.Text<T> encoder = (Encoder.Text<T>) encoders.getInstanceFor(type);
|
||||
assertThat("Encoder", encoder, notNullValue());
|
||||
String encoded = encoder.encode(value);
|
||||
|
||||
assertThat("Encoded", encoded, is(expectedEncoded));
|
||||
}
|
||||
|
||||
public <T> void assertTextStreamEncoder(Class<T> type, T value, String expectedEncoded) throws IllegalAccessException, InstantiationException, EncodeException, IOException
|
||||
{
|
||||
Class<? extends Encoder> encoderClass = encoders.getEncoderFor(type);
|
||||
assertThat("Encoder Class", encoderClass, notNullValue());
|
||||
|
||||
Encoder.TextStream<T> encoder = (Encoder.TextStream<T>) encoderClass.newInstance();
|
||||
encoder.init(testConfig);
|
||||
Encoder.TextStream<T> encoder = (Encoder.TextStream<T>) encoders.getInstanceFor(type);
|
||||
assertThat("Encoder", encoder, notNullValue());
|
||||
StringWriter writer = new StringWriter();
|
||||
encoder.encode(value, writer);
|
||||
|
||||
|
@ -78,12 +77,8 @@ public class AvailableEncodersTest
|
|||
|
||||
public <T> void assertBinaryEncoder(Class<T> type, T value, String expectedEncodedHex) throws IllegalAccessException, InstantiationException, EncodeException
|
||||
{
|
||||
AvailableEncoders encoders = new AvailableEncoders();
|
||||
Class<? extends Encoder> encoderClass = encoders.getEncoderFor(type);
|
||||
assertThat("Encoder Class", encoderClass, notNullValue());
|
||||
|
||||
Encoder.Binary<T> encoder = (Encoder.Binary<T>) encoderClass.newInstance();
|
||||
encoder.init(testConfig);
|
||||
Encoder.Binary<T> encoder = (Encoder.Binary<T>) encoders.getInstanceFor(type);
|
||||
assertThat("Encoder", encoder, notNullValue());
|
||||
ByteBuffer encoded = encoder.encode(value);
|
||||
|
||||
String hexEncoded = Hex.asHex(encoded);
|
||||
|
@ -92,11 +87,8 @@ public class AvailableEncodersTest
|
|||
|
||||
public <T> void assertBinaryStreamEncoder(Class<T> type, T value, String expectedEncodedHex) throws IllegalAccessException, InstantiationException, EncodeException, IOException
|
||||
{
|
||||
Class<? extends Encoder> encoderClass = encoders.getEncoderFor(type);
|
||||
assertThat("Encoder Class", encoderClass, notNullValue());
|
||||
|
||||
Encoder.BinaryStream<T> encoder = (Encoder.BinaryStream<T>) encoderClass.newInstance();
|
||||
encoder.init(testConfig);
|
||||
Encoder.BinaryStream<T> encoder = (Encoder.BinaryStream<T>) encoders.getInstanceFor(type);
|
||||
assertThat("Encoder", encoder, notNullValue());
|
||||
ByteArrayOutputStream out = new ByteArrayOutputStream();
|
||||
encoder.encode(value, out);
|
||||
|
||||
|
@ -210,6 +202,15 @@ public class AvailableEncodersTest
|
|||
byte buf[] = Hex.asByteArray("998877665544332211");
|
||||
assertBinaryEncoder(byte[].class, buf, "998877665544332211");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testCustomEncoder_Integer() throws IllegalAccessException, InstantiationException, EncodeException
|
||||
{
|
||||
encoders.register(IntegerEncoder.class);
|
||||
int val = 99887766;
|
||||
String expected = "99887766";
|
||||
assertTextEncoder(Integer.class, val, expected);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testCustomEncoder_Time() throws IllegalAccessException, InstantiationException, EncodeException, IOException
|
||||
|
@ -274,4 +275,25 @@ public class AvailableEncodersTest
|
|||
long value = 0x112233445566L;
|
||||
assertBinaryStreamEncoder(Long.class, value, "5B00001122334455665D");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testCustomEncoder_Register_Duplicate()
|
||||
{
|
||||
// has duplicated support for the same target Type
|
||||
expectedException.expect(IllegalStateException.class);
|
||||
expectedException.expectMessage(containsString("Duplicate"));
|
||||
encoders.register(BadDualEncoder.class);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testCustomEncoder_Register_OtherDuplicate()
|
||||
{
|
||||
// Register DateEncoder (decodes java.util.Date)
|
||||
encoders.register(DateEncoder.class);
|
||||
|
||||
// Register TimeEncoder (which also wants to decode java.util.Date)
|
||||
expectedException.expect(IllegalStateException.class);
|
||||
expectedException.expectMessage(containsString("Duplicate"));
|
||||
encoders.register(TimeEncoder.class);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -51,14 +51,22 @@ public class JsrEndpointFunctions_BadSignaturesTest
|
|||
{
|
||||
container = new ClientContainer();
|
||||
}
|
||||
|
||||
private AvailableEncoders encoders = new AvailableEncoders();
|
||||
private AvailableDecoders decoders = new AvailableDecoders();
|
||||
private Map<String, String> uriParams = new HashMap<>();
|
||||
private EndpointConfig endpointConfig = new EmptyClientEndpointConfig();
|
||||
|
||||
|
||||
@Rule
|
||||
public ExpectedException expectedException = ExpectedException.none();
|
||||
|
||||
private AvailableEncoders encoders;
|
||||
private AvailableDecoders decoders;
|
||||
private Map<String, String> uriParams = new HashMap<>();
|
||||
private EndpointConfig endpointConfig;
|
||||
|
||||
public JsrEndpointFunctions_BadSignaturesTest()
|
||||
{
|
||||
endpointConfig = new EmptyClientEndpointConfig();
|
||||
encoders = new AvailableEncoders(endpointConfig);
|
||||
decoders = new AvailableDecoders(endpointConfig);
|
||||
uriParams = new HashMap<>();
|
||||
}
|
||||
|
||||
private void assertBadSocket(TrackingSocket socket, String expectedString) throws Exception
|
||||
{
|
||||
|
|
|
@ -53,11 +53,19 @@ public class JsrEndpointFunctions_OnCloseTest
|
|||
{
|
||||
container = new ClientContainer();
|
||||
}
|
||||
|
||||
private AvailableEncoders encoders = new AvailableEncoders();
|
||||
private AvailableDecoders decoders = new AvailableDecoders();
|
||||
private Map<String,String> uriParams = new HashMap<>();
|
||||
private EndpointConfig endpointConfig = new EmptyClientEndpointConfig();
|
||||
|
||||
private AvailableEncoders encoders;
|
||||
private AvailableDecoders decoders;
|
||||
private Map<String, String> uriParams = new HashMap<>();
|
||||
private EndpointConfig endpointConfig;
|
||||
|
||||
public JsrEndpointFunctions_OnCloseTest()
|
||||
{
|
||||
endpointConfig = new EmptyClientEndpointConfig();
|
||||
encoders = new AvailableEncoders(endpointConfig);
|
||||
decoders = new AvailableDecoders(endpointConfig);
|
||||
uriParams = new HashMap<>();
|
||||
}
|
||||
|
||||
public JsrSession newSession(Object websocket)
|
||||
{
|
||||
|
|
|
@ -50,11 +50,19 @@ public class JsrEndpointFunctions_OnErrorTest
|
|||
{
|
||||
container = new ClientContainer();
|
||||
}
|
||||
|
||||
private AvailableEncoders encoders = new AvailableEncoders();
|
||||
private AvailableDecoders decoders = new AvailableDecoders();
|
||||
|
||||
private AvailableEncoders encoders;
|
||||
private AvailableDecoders decoders;
|
||||
private Map<String, String> uriParams = new HashMap<>();
|
||||
private EndpointConfig endpointConfig = new EmptyClientEndpointConfig();
|
||||
private EndpointConfig endpointConfig;
|
||||
|
||||
public JsrEndpointFunctions_OnErrorTest()
|
||||
{
|
||||
endpointConfig = new EmptyClientEndpointConfig();
|
||||
encoders = new AvailableEncoders(endpointConfig);
|
||||
decoders = new AvailableDecoders(endpointConfig);
|
||||
uriParams = new HashMap<>();
|
||||
}
|
||||
|
||||
public JsrSession newSession(Object websocket)
|
||||
{
|
||||
|
|
|
@ -21,24 +21,18 @@ package org.eclipse.jetty.websocket.jsr356.function;
|
|||
import static org.hamcrest.CoreMatchers.is;
|
||||
import static org.junit.Assert.assertThat;
|
||||
|
||||
import java.net.URI;
|
||||
import java.nio.ByteBuffer;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
import javax.websocket.ClientEndpoint;
|
||||
import javax.websocket.ClientEndpointConfig;
|
||||
import javax.websocket.EndpointConfig;
|
||||
import javax.websocket.OnMessage;
|
||||
import javax.websocket.Session;
|
||||
|
||||
import org.eclipse.jetty.util.BufferUtil;
|
||||
import org.eclipse.jetty.websocket.api.WebSocketPolicy;
|
||||
import org.eclipse.jetty.websocket.common.test.DummyConnection;
|
||||
import org.eclipse.jetty.websocket.jsr356.ClientContainer;
|
||||
import org.eclipse.jetty.websocket.jsr356.ConfiguredEndpoint;
|
||||
import org.eclipse.jetty.websocket.jsr356.JsrSession;
|
||||
import org.eclipse.jetty.websocket.jsr356.client.EmptyClientEndpointConfig;
|
||||
import org.eclipse.jetty.websocket.jsr356.decoders.AvailableDecoders;
|
||||
import org.eclipse.jetty.websocket.jsr356.encoders.AvailableEncoders;
|
||||
|
@ -56,22 +50,18 @@ public class JsrEndpointFunctions_OnMessage_BinaryTest
|
|||
container = new ClientContainer();
|
||||
}
|
||||
|
||||
private AvailableEncoders encoders = new AvailableEncoders();
|
||||
private AvailableDecoders decoders = new AvailableDecoders();
|
||||
private Map<String, String> uriParams = new HashMap<>();
|
||||
private EndpointConfig endpointConfig = new EmptyClientEndpointConfig();
|
||||
|
||||
private String expectedBuffer;
|
||||
private AvailableEncoders encoders;
|
||||
private AvailableDecoders decoders;
|
||||
private Map<String, String> uriParams = new HashMap<>();
|
||||
private EndpointConfig endpointConfig;
|
||||
|
||||
public JsrSession newSession(Object websocket)
|
||||
public JsrEndpointFunctions_OnMessage_BinaryTest()
|
||||
{
|
||||
String id = JsrEndpointFunctions_OnMessage_BinaryTest.class.getSimpleName();
|
||||
URI requestURI = URI.create("ws://localhost/" + id);
|
||||
WebSocketPolicy policy = WebSocketPolicy.newClientPolicy();
|
||||
DummyConnection connection = new DummyConnection(policy);
|
||||
ClientEndpointConfig config = new EmptyClientEndpointConfig();
|
||||
ConfiguredEndpoint ei = new ConfiguredEndpoint(websocket, config);
|
||||
return new JsrSession(container, id, requestURI, ei, connection);
|
||||
endpointConfig = new EmptyClientEndpointConfig();
|
||||
encoders = new AvailableEncoders(endpointConfig);
|
||||
decoders = new AvailableDecoders(endpointConfig);
|
||||
uriParams = new HashMap<>();
|
||||
}
|
||||
|
||||
private void assertOnMessageInvocation(TrackingSocket socket, String expectedEventFormat, Object... args) throws Exception
|
||||
|
|
|
@ -21,24 +21,18 @@ package org.eclipse.jetty.websocket.jsr356.function;
|
|||
import static org.hamcrest.Matchers.containsString;
|
||||
|
||||
import java.lang.reflect.InvocationTargetException;
|
||||
import java.net.URI;
|
||||
import java.nio.ByteBuffer;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
import javax.websocket.ClientEndpointConfig;
|
||||
import javax.websocket.EndpointConfig;
|
||||
import javax.websocket.OnMessage;
|
||||
import javax.websocket.Session;
|
||||
|
||||
import org.eclipse.jetty.util.BufferUtil;
|
||||
import org.eclipse.jetty.websocket.api.WebSocketPolicy;
|
||||
import org.eclipse.jetty.websocket.common.InvalidSignatureException;
|
||||
import org.eclipse.jetty.websocket.common.test.DummyConnection;
|
||||
import org.eclipse.jetty.websocket.jsr356.ClientContainer;
|
||||
import org.eclipse.jetty.websocket.jsr356.ConfiguredEndpoint;
|
||||
import org.eclipse.jetty.websocket.jsr356.JsrSession;
|
||||
import org.eclipse.jetty.websocket.jsr356.client.EmptyClientEndpointConfig;
|
||||
import org.eclipse.jetty.websocket.jsr356.decoders.AvailableDecoders;
|
||||
import org.eclipse.jetty.websocket.jsr356.encoders.AvailableEncoders;
|
||||
|
@ -57,24 +51,21 @@ public class JsrEndpointFunctions_OnMessage_TextTest
|
|||
{
|
||||
container = new ClientContainer();
|
||||
}
|
||||
|
||||
private AvailableEncoders encoders = new AvailableEncoders();
|
||||
private AvailableDecoders decoders = new AvailableDecoders();
|
||||
private Map<String, String> uriParams = new HashMap<>();
|
||||
private EndpointConfig endpointConfig = new EmptyClientEndpointConfig();
|
||||
|
||||
|
||||
@Rule
|
||||
public ExpectedException expectedException = ExpectedException.none();
|
||||
|
||||
public JsrSession newSession(Object websocket)
|
||||
private AvailableEncoders encoders;
|
||||
private AvailableDecoders decoders;
|
||||
private Map<String, String> uriParams = new HashMap<>();
|
||||
private EndpointConfig endpointConfig;
|
||||
|
||||
public JsrEndpointFunctions_OnMessage_TextTest()
|
||||
{
|
||||
String id = JsrEndpointFunctions_OnMessage_TextTest.class.getSimpleName();
|
||||
URI requestURI = URI.create("ws://localhost/" + id);
|
||||
WebSocketPolicy policy = WebSocketPolicy.newClientPolicy();
|
||||
DummyConnection connection = new DummyConnection(policy);
|
||||
ClientEndpointConfig config = new EmptyClientEndpointConfig();
|
||||
ConfiguredEndpoint ei = new ConfiguredEndpoint(websocket, config);
|
||||
return new JsrSession(container, id, requestURI, ei, connection);
|
||||
endpointConfig = new EmptyClientEndpointConfig();
|
||||
encoders = new AvailableEncoders(endpointConfig);
|
||||
decoders = new AvailableDecoders(endpointConfig);
|
||||
uriParams = new HashMap<>();
|
||||
}
|
||||
|
||||
private void onText(TrackingSocket socket, String msg)
|
||||
|
|
|
@ -49,11 +49,19 @@ public class JsrEndpointFunctions_OnOpenTest
|
|||
{
|
||||
container = new ClientContainer();
|
||||
}
|
||||
|
||||
private AvailableEncoders encoders = new AvailableEncoders();
|
||||
private AvailableDecoders decoders = new AvailableDecoders();
|
||||
private Map<String,String> uriParams = new HashMap<>();
|
||||
private EndpointConfig endpointConfig = new EmptyClientEndpointConfig();
|
||||
|
||||
private AvailableEncoders encoders;
|
||||
private AvailableDecoders decoders;
|
||||
private Map<String, String> uriParams = new HashMap<>();
|
||||
private EndpointConfig endpointConfig;
|
||||
|
||||
public JsrEndpointFunctions_OnOpenTest()
|
||||
{
|
||||
endpointConfig = new EmptyClientEndpointConfig();
|
||||
encoders = new AvailableEncoders(endpointConfig);
|
||||
decoders = new AvailableDecoders(endpointConfig);
|
||||
uriParams = new HashMap<>();
|
||||
}
|
||||
|
||||
public JsrSession newSession(Object websocket)
|
||||
{
|
||||
|
|
|
@ -1,134 +0,0 @@
|
|||
//
|
||||
// ========================================================================
|
||||
// Copyright (c) 1995-2016 Mort Bay Consulting Pty. Ltd.
|
||||
// ------------------------------------------------------------------------
|
||||
// All rights reserved. This program and the accompanying materials
|
||||
// are made available under the terms of the Eclipse Public License v1.0
|
||||
// and Apache License v2.0 which accompanies this distribution.
|
||||
//
|
||||
// The Eclipse Public License is available at
|
||||
// http://www.eclipse.org/legal/epl-v10.html
|
||||
//
|
||||
// The Apache License v2.0 is available at
|
||||
// http://www.opensource.org/licenses/apache2.0.php
|
||||
//
|
||||
// You may elect to redistribute this code under either of these licenses.
|
||||
// ========================================================================
|
||||
//
|
||||
|
||||
package org.eclipse.jetty.websocket.jsr356.metadata;
|
||||
|
||||
import static org.hamcrest.Matchers.containsString;
|
||||
import static org.hamcrest.Matchers.is;
|
||||
import static org.hamcrest.Matchers.notNullValue;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import javax.websocket.Decoder;
|
||||
|
||||
import org.eclipse.jetty.websocket.jsr356.MessageType;
|
||||
import org.eclipse.jetty.websocket.jsr356.decoders.BadDualDecoder;
|
||||
import org.eclipse.jetty.websocket.jsr356.decoders.DateDecoder;
|
||||
import org.eclipse.jetty.websocket.jsr356.decoders.IntegerDecoder;
|
||||
import org.eclipse.jetty.websocket.jsr356.decoders.TimeDecoder;
|
||||
import org.eclipse.jetty.websocket.jsr356.decoders.ValidDualDecoder;
|
||||
import org.junit.Assert;
|
||||
import org.junit.Test;
|
||||
|
||||
public class DecoderMetadataSetTest
|
||||
{
|
||||
private void assertMetadata(CoderMetadata<?> metadata, Class<?> expectedType, Class<?> expectedCoder, MessageType expectedMessageType)
|
||||
{
|
||||
Assert.assertEquals("metadata.coderClass",expectedCoder,metadata.getCoderClass());
|
||||
Assert.assertThat("metadata.messageType",metadata.getMessageType(),is(expectedMessageType));
|
||||
Assert.assertEquals("metadata.objectType",expectedType,metadata.getObjectType());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testAddBadDualDecoders()
|
||||
{
|
||||
try
|
||||
{
|
||||
DecoderMetadataSet coders = new DecoderMetadataSet();
|
||||
|
||||
// has duplicated support for the same target Type
|
||||
coders.add(BadDualDecoder.class);
|
||||
Assert.fail("Should have thrown IllegalStateException for attempting to register Decoders with duplicate implementation");
|
||||
}
|
||||
catch (IllegalStateException e)
|
||||
{
|
||||
Assert.assertThat(e.getMessage(),containsString("Duplicate"));
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testAddDuplicate()
|
||||
{
|
||||
DecoderMetadataSet coders = new DecoderMetadataSet();
|
||||
|
||||
// Add DateDecoder (decodes java.util.Date)
|
||||
coders.add(DateDecoder.class);
|
||||
|
||||
try
|
||||
{
|
||||
// Add TimeDecoder (which also wants to decode java.util.Date)
|
||||
coders.add(TimeDecoder.class);
|
||||
Assert.fail("Should have thrown IllegalStateException for attempting to register Decoders with duplicate implementation");
|
||||
}
|
||||
catch (IllegalStateException e)
|
||||
{
|
||||
Assert.assertThat(e.getMessage(),containsString("Duplicate"));
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testAddGetCoder()
|
||||
{
|
||||
DecoderMetadataSet coders = new DecoderMetadataSet();
|
||||
|
||||
coders.add(IntegerDecoder.class);
|
||||
Class<? extends Decoder> actualClazz = coders.getCoder(Integer.class);
|
||||
Assert.assertEquals("Coder Class",IntegerDecoder.class,actualClazz);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testAddGetMetadataByImpl()
|
||||
{
|
||||
DecoderMetadataSet coders = new DecoderMetadataSet();
|
||||
|
||||
coders.add(IntegerDecoder.class);
|
||||
List<DecoderMetadata> metadatas = coders.getMetadataByImplementation(IntegerDecoder.class);
|
||||
Assert.assertThat("Metadatas (by impl) count",metadatas.size(),is(1));
|
||||
DecoderMetadata metadata = metadatas.get(0);
|
||||
assertMetadata(metadata,Integer.class,IntegerDecoder.class,MessageType.TEXT);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testAddGetMetadataByType()
|
||||
{
|
||||
DecoderMetadataSet coders = new DecoderMetadataSet();
|
||||
|
||||
coders.add(IntegerDecoder.class);
|
||||
DecoderMetadata metadata = coders.getMetadataByType(Integer.class);
|
||||
assertMetadata(metadata,Integer.class,IntegerDecoder.class,MessageType.TEXT);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testAddValidDualDecoders()
|
||||
{
|
||||
DecoderMetadataSet coders = new DecoderMetadataSet();
|
||||
|
||||
coders.add(ValidDualDecoder.class);
|
||||
|
||||
List<Class<? extends Decoder>> decodersList = coders.getList();
|
||||
Assert.assertThat("Decoder List",decodersList,notNullValue());
|
||||
Assert.assertThat("Decoder List count",decodersList.size(),is(2));
|
||||
|
||||
DecoderMetadata metadata;
|
||||
metadata = coders.getMetadataByType(Integer.class);
|
||||
assertMetadata(metadata,Integer.class,ValidDualDecoder.class,MessageType.TEXT);
|
||||
|
||||
metadata = coders.getMetadataByType(Long.class);
|
||||
assertMetadata(metadata,Long.class,ValidDualDecoder.class,MessageType.BINARY);
|
||||
}
|
||||
}
|
|
@ -1,134 +0,0 @@
|
|||
//
|
||||
// ========================================================================
|
||||
// Copyright (c) 1995-2016 Mort Bay Consulting Pty. Ltd.
|
||||
// ------------------------------------------------------------------------
|
||||
// All rights reserved. This program and the accompanying materials
|
||||
// are made available under the terms of the Eclipse Public License v1.0
|
||||
// and Apache License v2.0 which accompanies this distribution.
|
||||
//
|
||||
// The Eclipse Public License is available at
|
||||
// http://www.eclipse.org/legal/epl-v10.html
|
||||
//
|
||||
// The Apache License v2.0 is available at
|
||||
// http://www.opensource.org/licenses/apache2.0.php
|
||||
//
|
||||
// You may elect to redistribute this code under either of these licenses.
|
||||
// ========================================================================
|
||||
//
|
||||
|
||||
package org.eclipse.jetty.websocket.jsr356.metadata;
|
||||
|
||||
import static org.hamcrest.Matchers.containsString;
|
||||
import static org.hamcrest.Matchers.is;
|
||||
import static org.hamcrest.Matchers.notNullValue;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import javax.websocket.Encoder;
|
||||
|
||||
import org.eclipse.jetty.websocket.jsr356.MessageType;
|
||||
import org.eclipse.jetty.websocket.jsr356.encoders.BadDualEncoder;
|
||||
import org.eclipse.jetty.websocket.jsr356.encoders.DateEncoder;
|
||||
import org.eclipse.jetty.websocket.jsr356.encoders.IntegerEncoder;
|
||||
import org.eclipse.jetty.websocket.jsr356.encoders.TimeEncoder;
|
||||
import org.eclipse.jetty.websocket.jsr356.encoders.ValidDualEncoder;
|
||||
import org.junit.Assert;
|
||||
import org.junit.Test;
|
||||
|
||||
public class EncoderMetadataSetTest
|
||||
{
|
||||
private void assertMetadata(CoderMetadata<?> metadata, Class<?> expectedType, Class<?> expectedCoder, MessageType expectedMessageType)
|
||||
{
|
||||
Assert.assertEquals("metadata.coderClass",expectedCoder,metadata.getCoderClass());
|
||||
Assert.assertThat("metadata.messageType",metadata.getMessageType(),is(expectedMessageType));
|
||||
Assert.assertEquals("metadata.objectType",expectedType,metadata.getObjectType());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testAddBadDualEncoders()
|
||||
{
|
||||
try
|
||||
{
|
||||
EncoderMetadataSet coders = new EncoderMetadataSet();
|
||||
|
||||
// has duplicated support for the same target Type
|
||||
coders.add(BadDualEncoder.class);
|
||||
Assert.fail("Should have thrown IllegalStateException for attempting to register AvailableEncoders with duplicate implementation");
|
||||
}
|
||||
catch (IllegalStateException e)
|
||||
{
|
||||
Assert.assertThat(e.getMessage(),containsString("Duplicate"));
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testAddDuplicate()
|
||||
{
|
||||
EncoderMetadataSet coders = new EncoderMetadataSet();
|
||||
|
||||
// Add DateEncoder (decodes java.util.Date)
|
||||
coders.add(DateEncoder.class);
|
||||
|
||||
try
|
||||
{
|
||||
// Add TimeEncoder (which also wants to decode java.util.Date)
|
||||
coders.add(TimeEncoder.class);
|
||||
Assert.fail("Should have thrown IllegalStateException for attempting to register AvailableEncoders with duplicate implementation");
|
||||
}
|
||||
catch (IllegalStateException e)
|
||||
{
|
||||
Assert.assertThat(e.getMessage(),containsString("Duplicate"));
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testAddGetCoder()
|
||||
{
|
||||
EncoderMetadataSet coders = new EncoderMetadataSet();
|
||||
|
||||
coders.add(IntegerEncoder.class);
|
||||
Class<? extends Encoder> actualClazz = coders.getCoder(Integer.class);
|
||||
Assert.assertEquals("Coder Class",IntegerEncoder.class,actualClazz);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testAddGetMetadataByImpl()
|
||||
{
|
||||
EncoderMetadataSet coders = new EncoderMetadataSet();
|
||||
|
||||
coders.add(IntegerEncoder.class);
|
||||
List<EncoderMetadata> metadatas = coders.getMetadataByImplementation(IntegerEncoder.class);
|
||||
Assert.assertThat("Metadatas (by impl) count",metadatas.size(),is(1));
|
||||
EncoderMetadata metadata = metadatas.get(0);
|
||||
assertMetadata(metadata,Integer.class,IntegerEncoder.class,MessageType.TEXT);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testAddGetMetadataByType()
|
||||
{
|
||||
EncoderMetadataSet coders = new EncoderMetadataSet();
|
||||
|
||||
coders.add(IntegerEncoder.class);
|
||||
EncoderMetadata metadata = coders.getMetadataByType(Integer.class);
|
||||
assertMetadata(metadata,Integer.class,IntegerEncoder.class,MessageType.TEXT);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testAddValidDualEncoders()
|
||||
{
|
||||
EncoderMetadataSet coders = new EncoderMetadataSet();
|
||||
|
||||
coders.add(ValidDualEncoder.class);
|
||||
|
||||
List<Class<? extends Encoder>> EncodersList = coders.getList();
|
||||
Assert.assertThat("Encoder List",EncodersList,notNullValue());
|
||||
Assert.assertThat("Encoder List count",EncodersList.size(),is(2));
|
||||
|
||||
EncoderMetadata metadata;
|
||||
metadata = coders.getMetadataByType(Integer.class);
|
||||
assertMetadata(metadata,Integer.class,ValidDualEncoder.class,MessageType.TEXT);
|
||||
|
||||
metadata = coders.getMetadataByType(Long.class);
|
||||
assertMetadata(metadata,Long.class,ValidDualEncoder.class,MessageType.BINARY);
|
||||
}
|
||||
}
|
|
@ -479,16 +479,51 @@ public class CommonEndpointFunctions<T extends Session> extends AbstractLifeCycl
|
|||
throw new InvalidSignatureException(err.toString());
|
||||
}
|
||||
|
||||
protected void clearOnPongFunction()
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
protected void clearOnTextSink()
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
protected void clearOnBinarySink()
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
public BatchMode getBatchMode()
|
||||
{
|
||||
return batchMode;
|
||||
}
|
||||
|
||||
public Executor getExecutor()
|
||||
{
|
||||
return executor;
|
||||
}
|
||||
|
||||
public T getSession()
|
||||
{
|
||||
return session;
|
||||
}
|
||||
|
||||
protected MessageSink getOnTextSink()
|
||||
{
|
||||
return onTextSink;
|
||||
}
|
||||
|
||||
protected MessageSink getOnBinarySink()
|
||||
{
|
||||
return onBinarySink;
|
||||
}
|
||||
|
||||
protected Function<ByteBuffer, Void> getOnPongFunction()
|
||||
{
|
||||
return onPongFunction;
|
||||
}
|
||||
|
||||
public void setOnOpen(Function<T, Void> function, Object origin)
|
||||
{
|
||||
assertNotSet(this.onOpenFunction, "Open Handler", origin);
|
||||
|
|
Loading…
Reference in New Issue