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);
|
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());
|
LOG.debug("MessageHandler.Whole class: {}", handler.getClass());
|
||||||
}
|
}
|
||||||
getJsrEndpointFunctions().setMessageHandler(clazz, handler);
|
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");
|
Objects.requireNonNull(handler, "MessageHandler cannot be null");
|
||||||
Class<? extends MessageHandler> handlerClass = handler.getClass();
|
Class<? extends MessageHandler> handlerClass = handler.getClass();
|
||||||
|
boolean added = false;
|
||||||
|
|
||||||
if (MessageHandler.Whole.class.isAssignableFrom(handlerClass))
|
if (MessageHandler.Whole.class.isAssignableFrom(handlerClass))
|
||||||
{
|
{
|
||||||
Class<?> onMessageClass = ReflectUtils.findGenericClassFor(handlerClass, MessageHandler.Whole.class);
|
Class<?> onMessageClass = ReflectUtils.findGenericClassFor(handlerClass, MessageHandler.Whole.class);
|
||||||
addMessageHandler(onMessageClass, (MessageHandler.Whole) handler);
|
addMessageHandler(onMessageClass, (MessageHandler.Whole) handler);
|
||||||
|
added = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (MessageHandler.Partial.class.isAssignableFrom(handlerClass))
|
if (MessageHandler.Partial.class.isAssignableFrom(handlerClass))
|
||||||
{
|
{
|
||||||
Class<?> onMessageClass = ReflectUtils.findGenericClassFor(handlerClass, MessageHandler.Partial.class);
|
Class<?> onMessageClass = ReflectUtils.findGenericClassFor(handlerClass, MessageHandler.Partial.class);
|
||||||
addMessageHandler(onMessageClass, (MessageHandler.Partial) handler);
|
addMessageHandler(onMessageClass, (MessageHandler.Partial) handler);
|
||||||
|
added = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Should not be possible
|
if (!added)
|
||||||
throw new IllegalStateException("Not a recognized " + MessageHandler.class.getName() + " type: " + handler.getClass());
|
{
|
||||||
|
// 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
|
@Override
|
||||||
|
@ -241,6 +256,11 @@ public class JsrSession extends WebSocketSession implements javax.websocket.Sess
|
||||||
@Override
|
@Override
|
||||||
public Set<MessageHandler> getMessageHandlers()
|
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.
|
// Always return copy of set, as it is common to iterate and remove from the real set.
|
||||||
return new HashSet<MessageHandler>(messageHandlerSet);
|
return new HashSet<MessageHandler>(messageHandlerSet);
|
||||||
}
|
}
|
||||||
|
@ -309,7 +329,7 @@ public class JsrSession extends WebSocketSession implements javax.websocket.Sess
|
||||||
@Override
|
@Override
|
||||||
public synchronized void removeMessageHandler(MessageHandler handler)
|
public synchronized void removeMessageHandler(MessageHandler handler)
|
||||||
{
|
{
|
||||||
if (messageHandlerSet.remove(handler))
|
if (messageHandlerSet != null && messageHandlerSet.remove(handler))
|
||||||
{
|
{
|
||||||
// remove from endpoint functions too
|
// remove from endpoint functions too
|
||||||
getJsrEndpointFunctions().removeMessageHandler(handler);
|
getJsrEndpointFunctions().removeMessageHandler(handler);
|
||||||
|
|
|
@ -42,13 +42,20 @@ public class AvailableDecoders implements Predicate<Class<?>>
|
||||||
public final Class<? extends Decoder> decoder;
|
public final Class<? extends Decoder> decoder;
|
||||||
public final Class<? extends Decoder> interfaceType;
|
public final Class<? extends Decoder> interfaceType;
|
||||||
public final Class<?> objectType;
|
public final Class<?> objectType;
|
||||||
|
public final boolean primitive;
|
||||||
public Decoder instance;
|
public Decoder instance;
|
||||||
|
|
||||||
public RegisteredDecoder(Class<? extends Decoder> decoder, Class<? extends Decoder> interfaceType, Class<?> objectType)
|
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.decoder = decoder;
|
||||||
this.interfaceType = interfaceType;
|
this.interfaceType = interfaceType;
|
||||||
this.objectType = objectType;
|
this.objectType = objectType;
|
||||||
|
this.primitive = primitive;
|
||||||
}
|
}
|
||||||
|
|
||||||
public boolean implementsInterface(Class<? extends Decoder> type)
|
public boolean implementsInterface(Class<? extends Decoder> type)
|
||||||
|
@ -71,36 +78,36 @@ public class AvailableDecoders implements Predicate<Class<?>>
|
||||||
registeredDecoders = new LinkedList<>();
|
registeredDecoders = new LinkedList<>();
|
||||||
|
|
||||||
// TEXT based [via Class reference]
|
// TEXT based [via Class reference]
|
||||||
register(BooleanDecoder.class, Decoder.Text.class, Boolean.class);
|
registerPrimitive(BooleanDecoder.class, Decoder.Text.class, Boolean.class);
|
||||||
register(ByteDecoder.class, Decoder.Text.class, Byte.class);
|
registerPrimitive(ByteDecoder.class, Decoder.Text.class, Byte.class);
|
||||||
register(CharacterDecoder.class, Decoder.Text.class, Character.class);
|
registerPrimitive(CharacterDecoder.class, Decoder.Text.class, Character.class);
|
||||||
register(DoubleDecoder.class, Decoder.Text.class, Double.class);
|
registerPrimitive(DoubleDecoder.class, Decoder.Text.class, Double.class);
|
||||||
register(FloatDecoder.class, Decoder.Text.class, Float.class);
|
registerPrimitive(FloatDecoder.class, Decoder.Text.class, Float.class);
|
||||||
register(IntegerDecoder.class, Decoder.Text.class, Integer.class);
|
registerPrimitive(IntegerDecoder.class, Decoder.Text.class, Integer.class);
|
||||||
register(LongDecoder.class, Decoder.Text.class, Long.class);
|
registerPrimitive(LongDecoder.class, Decoder.Text.class, Long.class);
|
||||||
register(StringDecoder.class, Decoder.Text.class, String.class);
|
registerPrimitive(StringDecoder.class, Decoder.Text.class, String.class);
|
||||||
|
|
||||||
// TEXT based [via Primitive reference]
|
// TEXT based [via Primitive reference]
|
||||||
register(BooleanDecoder.class, Decoder.Text.class, Boolean.TYPE);
|
registerPrimitive(BooleanDecoder.class, Decoder.Text.class, Boolean.TYPE);
|
||||||
register(ByteDecoder.class, Decoder.Text.class, Byte.TYPE);
|
registerPrimitive(ByteDecoder.class, Decoder.Text.class, Byte.TYPE);
|
||||||
register(CharacterDecoder.class, Decoder.Text.class, Character.TYPE);
|
registerPrimitive(CharacterDecoder.class, Decoder.Text.class, Character.TYPE);
|
||||||
register(DoubleDecoder.class, Decoder.Text.class, Double.TYPE);
|
registerPrimitive(DoubleDecoder.class, Decoder.Text.class, Double.TYPE);
|
||||||
register(FloatDecoder.class, Decoder.Text.class, Float.TYPE);
|
registerPrimitive(FloatDecoder.class, Decoder.Text.class, Float.TYPE);
|
||||||
register(IntegerDecoder.class, Decoder.Text.class, Integer.TYPE);
|
registerPrimitive(IntegerDecoder.class, Decoder.Text.class, Integer.TYPE);
|
||||||
register(LongDecoder.class, Decoder.Text.class, Long.TYPE);
|
registerPrimitive(LongDecoder.class, Decoder.Text.class, Long.TYPE);
|
||||||
|
|
||||||
// BINARY based
|
// BINARY based
|
||||||
register(ByteBufferDecoder.class, Decoder.Binary.class, ByteBuffer.class);
|
registerPrimitive(ByteBufferDecoder.class, Decoder.Binary.class, ByteBuffer.class);
|
||||||
register(ByteArrayDecoder.class, Decoder.Binary.class, byte[].class);
|
registerPrimitive(ByteArrayDecoder.class, Decoder.Binary.class, byte[].class);
|
||||||
|
|
||||||
// STREAMING based
|
// STREAMING based
|
||||||
register(ReaderDecoder.class, Decoder.TextStream.class, Reader.class);
|
registerPrimitive(ReaderDecoder.class, Decoder.TextStream.class, Reader.class);
|
||||||
register(InputStreamDecoder.class, Decoder.BinaryStream.class, InputStreamDecoder.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)
|
public void register(Class<? extends Decoder> decoder)
|
||||||
|
@ -167,14 +174,34 @@ public class AvailableDecoders implements Predicate<Class<?>>
|
||||||
if (objectType == null)
|
if (objectType == null)
|
||||||
{
|
{
|
||||||
StringBuilder err = new StringBuilder();
|
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(interfaceClass.getName());
|
||||||
err.append(" on class ");
|
err.append(" on class ");
|
||||||
err.append(decoder);
|
err.append(decoder);
|
||||||
throw new InvalidWebSocketException(err.toString());
|
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)
|
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
|
try
|
||||||
{
|
{
|
||||||
RegisteredDecoder registeredDecoder = getRegisteredDecoderFor(type);
|
RegisteredDecoder registeredDecoder = getRegisteredDecoderFor(type);
|
||||||
if (registeredDecoder.instance != null)
|
return getInstanceOf(registeredDecoder);
|
||||||
{
|
|
||||||
return registeredDecoder.instance;
|
|
||||||
}
|
|
||||||
|
|
||||||
registeredDecoder.instance = registeredDecoder.decoder.newInstance();
|
|
||||||
registeredDecoder.instance.init(this.config);
|
|
||||||
return registeredDecoder.instance;
|
|
||||||
}
|
}
|
||||||
catch (NoSuchElementException e)
|
catch (NoSuchElementException e)
|
||||||
{
|
{
|
||||||
throw new InvalidWebSocketException("No Decoder found for type " + type);
|
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
|
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.LinkedList;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.NoSuchElementException;
|
import java.util.NoSuchElementException;
|
||||||
|
import java.util.Objects;
|
||||||
import java.util.function.Predicate;
|
import java.util.function.Predicate;
|
||||||
import java.util.stream.Collectors;
|
import java.util.stream.Collectors;
|
||||||
|
|
||||||
|
@ -65,6 +66,7 @@ public class AvailableEncoders implements Predicate<Class<?>>
|
||||||
|
|
||||||
public AvailableEncoders(EndpointConfig config)
|
public AvailableEncoders(EndpointConfig config)
|
||||||
{
|
{
|
||||||
|
Objects.requireNonNull(config);
|
||||||
this.config = config;
|
this.config = config;
|
||||||
registeredEncoders = new LinkedList<>();
|
registeredEncoders = new LinkedList<>();
|
||||||
|
|
||||||
|
|
|
@ -27,8 +27,10 @@ import java.util.ArrayList;
|
||||||
import java.util.Comparator;
|
import java.util.Comparator;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
|
import java.util.NoSuchElementException;
|
||||||
import java.util.concurrent.Executor;
|
import java.util.concurrent.Executor;
|
||||||
import java.util.function.BiFunction;
|
import java.util.function.BiFunction;
|
||||||
|
import java.util.function.Function;
|
||||||
import java.util.stream.Collectors;
|
import java.util.stream.Collectors;
|
||||||
|
|
||||||
import javax.websocket.ClientEndpoint;
|
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.api.WebSocketPolicy;
|
||||||
import org.eclipse.jetty.websocket.common.InvalidSignatureException;
|
import org.eclipse.jetty.websocket.common.InvalidSignatureException;
|
||||||
import org.eclipse.jetty.websocket.common.function.CommonEndpointFunctions;
|
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.PartialBinaryMessageSink;
|
||||||
import org.eclipse.jetty.websocket.common.message.PartialTextMessageSink;
|
import org.eclipse.jetty.websocket.common.message.PartialTextMessageSink;
|
||||||
import org.eclipse.jetty.websocket.common.reflect.Arg;
|
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);
|
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)
|
* Represents a static value (as seen from a URI PathParam)
|
||||||
* <p>
|
* <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
|
@Override
|
||||||
protected void discoverEndpointFunctions(Object endpoint)
|
protected void discoverEndpointFunctions(Object endpoint)
|
||||||
{
|
{
|
||||||
|
@ -296,228 +541,21 @@ public class JsrEndpointFunctions extends CommonEndpointFunctions<JsrSession>
|
||||||
onmsgloop:
|
onmsgloop:
|
||||||
for (Method onMsg : onMessages)
|
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;
|
||||||
|
|
||||||
// --------------------
|
// PONG
|
||||||
// -- Whole Messages --
|
if (discoverOnMessagePong(onMsg)) continue onmsgloop;
|
||||||
// --------------------
|
|
||||||
|
|
||||||
// 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;
|
|
||||||
}
|
|
||||||
|
|
||||||
// If we reached this point, then we have a @OnMessage annotated method
|
// If we reached this point, then we have a @OnMessage annotated method
|
||||||
// that doesn't match any known signature above.
|
// that doesn't match any known signature above.
|
||||||
|
@ -527,58 +565,243 @@ public class JsrEndpointFunctions extends CommonEndpointFunctions<JsrSession>
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
private boolean discoverOnMessagePong(Method onMsg) throws DecodeException
|
||||||
* 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)
|
|
||||||
{
|
{
|
||||||
// TODO: implement
|
Arg SESSION = new Arg(Session.class);
|
||||||
}
|
UnorderedSignature sigPong = new UnorderedSignature(createCallArgs(SESSION, new Arg(PongMessage.class).required()));
|
||||||
|
if (sigPong.test(onMsg))
|
||||||
/**
|
|
||||||
* 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
|
|
||||||
{
|
{
|
||||||
Decoder decoder = decoderClass.newInstance();
|
assertOnMessageSignature(onMsg);
|
||||||
decoder.init(this.endpointConfig);
|
|
||||||
return (T) decoder;
|
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)
|
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
|
protected Object[] newCallArgs(Arg[] callArgs) throws DecodeException
|
||||||
{
|
{
|
||||||
int len = callArgs.length;
|
int len = callArgs.length;
|
||||||
|
|
|
@ -26,14 +26,15 @@ import javax.websocket.Decoder;
|
||||||
import javax.websocket.EncodeException;
|
import javax.websocket.EncodeException;
|
||||||
|
|
||||||
import org.eclipse.jetty.websocket.api.WebSocketException;
|
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.common.message.ByteBufferMessageSink;
|
||||||
import org.eclipse.jetty.websocket.jsr356.JsrSession;
|
import org.eclipse.jetty.websocket.jsr356.function.JsrEndpointFunctions;
|
||||||
|
|
||||||
public class DecodedBinaryMessageSink extends ByteBufferMessageSink
|
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
|
try
|
||||||
{
|
{
|
||||||
|
@ -47,7 +48,7 @@ public class DecodedBinaryMessageSink extends ByteBufferMessageSink
|
||||||
if (ret != null)
|
if (ret != null)
|
||||||
{
|
{
|
||||||
// send response
|
// send response
|
||||||
session.getBasicRemote().sendObject(ret);
|
endpointFunctions.getSession().getBasicRemote().sendObject(ret);
|
||||||
}
|
}
|
||||||
|
|
||||||
return null;
|
return null;
|
||||||
|
|
|
@ -28,14 +28,15 @@ import javax.websocket.EncodeException;
|
||||||
import org.eclipse.jetty.websocket.api.WebSocketException;
|
import org.eclipse.jetty.websocket.api.WebSocketException;
|
||||||
import org.eclipse.jetty.websocket.common.message.InputStreamMessageSink;
|
import org.eclipse.jetty.websocket.common.message.InputStreamMessageSink;
|
||||||
import org.eclipse.jetty.websocket.jsr356.JsrSession;
|
import org.eclipse.jetty.websocket.jsr356.JsrSession;
|
||||||
|
import org.eclipse.jetty.websocket.jsr356.function.JsrEndpointFunctions;
|
||||||
|
|
||||||
public class DecodedInputStreamMessageSink extends InputStreamMessageSink
|
public class DecodedInputStreamMessageSink extends InputStreamMessageSink
|
||||||
{
|
{
|
||||||
public DecodedInputStreamMessageSink(JsrSession session,
|
public DecodedInputStreamMessageSink(JsrEndpointFunctions endpointFunctions,
|
||||||
Decoder.BinaryStream decoder,
|
Decoder.BinaryStream decoder,
|
||||||
Function<Object, Object> onMessageFunction)
|
Function<Object, Object> onMessageFunction)
|
||||||
{
|
{
|
||||||
super(session.getExecutor(), (reader) ->
|
super(endpointFunctions.getExecutor(), (reader) ->
|
||||||
{
|
{
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
|
@ -47,7 +48,7 @@ public class DecodedInputStreamMessageSink extends InputStreamMessageSink
|
||||||
if (ret != null)
|
if (ret != null)
|
||||||
{
|
{
|
||||||
// send response
|
// send response
|
||||||
session.getBasicRemote().sendObject(ret);
|
endpointFunctions.getSession().getBasicRemote().sendObject(ret);
|
||||||
}
|
}
|
||||||
|
|
||||||
return null;
|
return null;
|
||||||
|
|
|
@ -27,13 +27,13 @@ import javax.websocket.EncodeException;
|
||||||
|
|
||||||
import org.eclipse.jetty.websocket.api.WebSocketException;
|
import org.eclipse.jetty.websocket.api.WebSocketException;
|
||||||
import org.eclipse.jetty.websocket.common.message.ReaderMessageSink;
|
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 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
|
try
|
||||||
{
|
{
|
||||||
|
@ -45,7 +45,7 @@ public class DecodedReaderMessageSink extends ReaderMessageSink
|
||||||
if (ret != null)
|
if (ret != null)
|
||||||
{
|
{
|
||||||
// send response
|
// send response
|
||||||
session.getBasicRemote().sendObject(ret);
|
endpointFunctions.getSession().getBasicRemote().sendObject(ret);
|
||||||
}
|
}
|
||||||
|
|
||||||
return null;
|
return null;
|
||||||
|
|
|
@ -26,14 +26,15 @@ import javax.websocket.Decoder;
|
||||||
import javax.websocket.EncodeException;
|
import javax.websocket.EncodeException;
|
||||||
|
|
||||||
import org.eclipse.jetty.websocket.api.WebSocketException;
|
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.common.message.StringMessageSink;
|
||||||
import org.eclipse.jetty.websocket.jsr356.JsrSession;
|
import org.eclipse.jetty.websocket.jsr356.function.JsrEndpointFunctions;
|
||||||
|
|
||||||
public class DecodedTextMessageSink extends StringMessageSink
|
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
|
try
|
||||||
{
|
{
|
||||||
|
@ -45,7 +46,7 @@ public class DecodedTextMessageSink extends StringMessageSink
|
||||||
if (ret != null)
|
if (ret != null)
|
||||||
{
|
{
|
||||||
// send response
|
// send response
|
||||||
session.getBasicRemote().sendObject(ret);
|
endpointFunctions.getSession().getBasicRemote().sendObject(ret);
|
||||||
}
|
}
|
||||||
|
|
||||||
return null;
|
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
|
private Quotes getQuotes(String filename) throws IOException
|
||||||
{
|
{
|
||||||
Quotes quotes = new Quotes();
|
Quotes quotes = new Quotes();
|
||||||
|
|
|
@ -27,7 +27,6 @@ import javax.websocket.MessageHandler;
|
||||||
import org.eclipse.jetty.websocket.api.WebSocketPolicy;
|
import org.eclipse.jetty.websocket.api.WebSocketPolicy;
|
||||||
import org.eclipse.jetty.websocket.common.test.DummyConnection;
|
import org.eclipse.jetty.websocket.common.test.DummyConnection;
|
||||||
import org.eclipse.jetty.websocket.jsr356.client.EmptyClientEndpointConfig;
|
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.ByteArrayWholeHandler;
|
||||||
import org.eclipse.jetty.websocket.jsr356.handlers.ByteBufferPartialHandler;
|
import org.eclipse.jetty.websocket.jsr356.handlers.ByteBufferPartialHandler;
|
||||||
import org.eclipse.jetty.websocket.jsr356.handlers.LongMessageHandler;
|
import org.eclipse.jetty.websocket.jsr356.handlers.LongMessageHandler;
|
||||||
|
@ -44,29 +43,19 @@ public class JsrSessionTest
|
||||||
@Before
|
@Before
|
||||||
public void initSession()
|
public void initSession()
|
||||||
{
|
{
|
||||||
container = new ClientContainer();
|
|
||||||
String id = JsrSessionTest.class.getSimpleName();
|
String id = JsrSessionTest.class.getSimpleName();
|
||||||
URI requestURI = URI.create("ws://localhost/" + id);
|
URI requestURI = URI.create("ws://localhost/" + id);
|
||||||
WebSocketPolicy policy = WebSocketPolicy.newClientPolicy();
|
WebSocketPolicy policy = WebSocketPolicy.newClientPolicy();
|
||||||
|
DummyConnection connection = new DummyConnection(policy);
|
||||||
ClientEndpointConfig config = new EmptyClientEndpointConfig();
|
ClientEndpointConfig config = new EmptyClientEndpointConfig();
|
||||||
DummyEndpoint websocket = new DummyEndpoint();
|
ConfiguredEndpoint ei = new ConfiguredEndpoint(new DummyEndpoint(), config);
|
||||||
SimpleEndpointMetadata metadata = new SimpleEndpointMetadata(websocket.getClass());
|
session = new JsrSession(container, id, requestURI, ei, connection);
|
||||||
// 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);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testMessageHandlerBinary() throws DeploymentException
|
public void testMessageHandlerBinary() throws DeploymentException
|
||||||
{
|
{
|
||||||
session.addMessageHandler(new ByteBufferPartialHandler());
|
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
|
@Test
|
||||||
|
@ -74,12 +63,6 @@ public class JsrSessionTest
|
||||||
{
|
{
|
||||||
session.addMessageHandler(new StringWholeHandler());
|
session.addMessageHandler(new StringWholeHandler());
|
||||||
session.addMessageHandler(new ByteArrayWholeHandler());
|
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
|
@Test
|
||||||
|
@ -90,20 +73,11 @@ public class JsrSessionTest
|
||||||
session.addMessageHandler(new ByteArrayWholeHandler()); // add BINARY handler
|
session.addMessageHandler(new ByteArrayWholeHandler()); // add BINARY handler
|
||||||
session.removeMessageHandler(oldText); // remove original TEXT handler
|
session.removeMessageHandler(oldText); // remove original TEXT handler
|
||||||
session.addMessageHandler(new LongMessageHandler()); // add new 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
|
@Test
|
||||||
public void testMessageHandlerText() throws DeploymentException
|
public void testMessageHandlerText() throws DeploymentException
|
||||||
{
|
{
|
||||||
session.addMessageHandler(new StringWholeHandler());
|
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;
|
package org.eclipse.jetty.websocket.jsr356.decoders;
|
||||||
|
|
||||||
|
import static org.hamcrest.Matchers.containsString;
|
||||||
import static org.hamcrest.Matchers.equalTo;
|
import static org.hamcrest.Matchers.equalTo;
|
||||||
import static org.hamcrest.Matchers.is;
|
import static org.hamcrest.Matchers.is;
|
||||||
import static org.hamcrest.Matchers.notNullValue;
|
import static org.hamcrest.Matchers.notNullValue;
|
||||||
|
@ -33,10 +34,13 @@ import javax.websocket.DecodeException;
|
||||||
import javax.websocket.Decoder;
|
import javax.websocket.Decoder;
|
||||||
import javax.websocket.EndpointConfig;
|
import javax.websocket.EndpointConfig;
|
||||||
|
|
||||||
|
import org.eclipse.jetty.websocket.api.InvalidWebSocketException;
|
||||||
import org.eclipse.jetty.websocket.common.util.Hex;
|
import org.eclipse.jetty.websocket.common.util.Hex;
|
||||||
import org.eclipse.jetty.websocket.jsr356.client.EmptyClientEndpointConfig;
|
import org.eclipse.jetty.websocket.jsr356.client.EmptyClientEndpointConfig;
|
||||||
import org.junit.BeforeClass;
|
import org.junit.BeforeClass;
|
||||||
|
import org.junit.Rule;
|
||||||
import org.junit.Test;
|
import org.junit.Test;
|
||||||
|
import org.junit.rules.ExpectedException;
|
||||||
|
|
||||||
public class AvailableDecodersTest
|
public class AvailableDecodersTest
|
||||||
{
|
{
|
||||||
|
@ -48,29 +52,24 @@ public class AvailableDecodersTest
|
||||||
testConfig = new EmptyClientEndpointConfig();
|
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
|
private <T> void assertTextDecoder(Class<T> type, String value, T expectedDecoded) throws IllegalAccessException, InstantiationException, DecodeException
|
||||||
{
|
{
|
||||||
Class<? extends Decoder> decoderClass = decoders.getDecoderFor(type);
|
Decoder.Text<T> decoder = (Decoder.Text<T>) decoders.getInstanceFor(type);
|
||||||
assertThat("Decoder Class", decoderClass, notNullValue());
|
assertThat("Decoder instance", decoder, notNullValue());
|
||||||
|
|
||||||
Decoder.Text<T> decoder = (Decoder.Text<T>) decoderClass.newInstance();
|
|
||||||
decoder.init(testConfig);
|
|
||||||
T decoded = decoder.decode(value);
|
T decoded = decoder.decode(value);
|
||||||
|
|
||||||
assertThat("Decoded", decoded, is(expectedDecoded));
|
assertThat("Decoded", decoded, is(expectedDecoded));
|
||||||
}
|
}
|
||||||
|
|
||||||
private <T> void assertBinaryDecoder(Class<T> type, ByteBuffer value, T expectedDecoded) throws IllegalAccessException, InstantiationException, DecodeException
|
private <T> void assertBinaryDecoder(Class<T> type, ByteBuffer value, T expectedDecoded) throws IllegalAccessException, InstantiationException, DecodeException
|
||||||
{
|
{
|
||||||
Class<? extends Decoder> decoderClass = decoders.getDecoderFor(type);
|
Decoder.Binary<T> decoder = (Decoder.Binary<T>) decoders.getInstanceFor(type);
|
||||||
assertThat("Decoder Class", decoderClass, notNullValue());
|
assertThat("Decoder Class", decoder, notNullValue());
|
||||||
|
|
||||||
Decoder.Binary<T> decoder = (Decoder.Binary<T>) decoderClass.newInstance();
|
|
||||||
decoder.init(testConfig);
|
|
||||||
T decoded = decoder.decode(value);
|
T decoded = decoder.decode(value);
|
||||||
|
|
||||||
assertThat("Decoded", decoded, equalTo(expectedDecoded));
|
assertThat("Decoded", decoded, equalTo(expectedDecoded));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -195,6 +194,16 @@ public class AvailableDecodersTest
|
||||||
assertBinaryDecoder(byte[].class, val, expected);
|
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
|
@Test
|
||||||
public void testCustomDecoder_Time() throws IllegalAccessException, InstantiationException, DecodeException
|
public void testCustomDecoder_Time() throws IllegalAccessException, InstantiationException, DecodeException
|
||||||
{
|
{
|
||||||
|
@ -261,6 +270,9 @@ public class AvailableDecodersTest
|
||||||
{
|
{
|
||||||
decoders.register(ValidDualDecoder.class);
|
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]";
|
String val = "[1,234,567]";
|
||||||
Integer expected = 1234567;
|
Integer expected = 1234567;
|
||||||
|
|
||||||
|
@ -272,6 +284,9 @@ public class AvailableDecodersTest
|
||||||
{
|
{
|
||||||
decoders.register(ValidDualDecoder.class);
|
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);
|
ByteBuffer val = ByteBuffer.allocate(16);
|
||||||
val.put((byte) '[');
|
val.put((byte) '[');
|
||||||
val.putLong(0x112233445566L);
|
val.putLong(0x112233445566L);
|
||||||
|
@ -281,4 +296,25 @@ public class AvailableDecodersTest
|
||||||
|
|
||||||
assertBinaryDecoder(Long.class, val, expected);
|
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;
|
package org.eclipse.jetty.websocket.jsr356.encoders;
|
||||||
|
|
||||||
|
import static org.hamcrest.Matchers.containsString;
|
||||||
import static org.hamcrest.Matchers.is;
|
import static org.hamcrest.Matchers.is;
|
||||||
import static org.hamcrest.Matchers.notNullValue;
|
import static org.hamcrest.Matchers.notNullValue;
|
||||||
import static org.junit.Assert.assertThat;
|
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.common.util.Hex;
|
||||||
import org.eclipse.jetty.websocket.jsr356.client.EmptyClientEndpointConfig;
|
import org.eclipse.jetty.websocket.jsr356.client.EmptyClientEndpointConfig;
|
||||||
import org.junit.BeforeClass;
|
import org.junit.BeforeClass;
|
||||||
|
import org.junit.Rule;
|
||||||
import org.junit.Test;
|
import org.junit.Test;
|
||||||
|
import org.junit.rules.ExpectedException;
|
||||||
|
|
||||||
public class AvailableEncodersTest
|
public class AvailableEncodersTest
|
||||||
{
|
{
|
||||||
|
@ -49,27 +52,23 @@ public class AvailableEncodersTest
|
||||||
testConfig = new EmptyClientEndpointConfig();
|
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
|
public <T> void assertTextEncoder(Class<T> type, T value, String expectedEncoded) throws IllegalAccessException, InstantiationException, EncodeException
|
||||||
{
|
{
|
||||||
Class<? extends Encoder> encoderClass = encoders.getEncoderFor(type);
|
Encoder.Text<T> encoder = (Encoder.Text<T>) encoders.getInstanceFor(type);
|
||||||
assertThat("Encoder Class", encoderClass, notNullValue());
|
assertThat("Encoder", encoder, notNullValue());
|
||||||
|
|
||||||
Encoder.Text<T> encoder = (Encoder.Text<T>) encoderClass.newInstance();
|
|
||||||
encoder.init(testConfig);
|
|
||||||
String encoded = encoder.encode(value);
|
String encoded = encoder.encode(value);
|
||||||
|
|
||||||
assertThat("Encoded", encoded, is(expectedEncoded));
|
assertThat("Encoded", encoded, is(expectedEncoded));
|
||||||
}
|
}
|
||||||
|
|
||||||
public <T> void assertTextStreamEncoder(Class<T> type, T value, String expectedEncoded) throws IllegalAccessException, InstantiationException, EncodeException, IOException
|
public <T> void assertTextStreamEncoder(Class<T> type, T value, String expectedEncoded) throws IllegalAccessException, InstantiationException, EncodeException, IOException
|
||||||
{
|
{
|
||||||
Class<? extends Encoder> encoderClass = encoders.getEncoderFor(type);
|
Encoder.TextStream<T> encoder = (Encoder.TextStream<T>) encoders.getInstanceFor(type);
|
||||||
assertThat("Encoder Class", encoderClass, notNullValue());
|
assertThat("Encoder", encoder, notNullValue());
|
||||||
|
|
||||||
Encoder.TextStream<T> encoder = (Encoder.TextStream<T>) encoderClass.newInstance();
|
|
||||||
encoder.init(testConfig);
|
|
||||||
StringWriter writer = new StringWriter();
|
StringWriter writer = new StringWriter();
|
||||||
encoder.encode(value, writer);
|
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
|
public <T> void assertBinaryEncoder(Class<T> type, T value, String expectedEncodedHex) throws IllegalAccessException, InstantiationException, EncodeException
|
||||||
{
|
{
|
||||||
AvailableEncoders encoders = new AvailableEncoders();
|
Encoder.Binary<T> encoder = (Encoder.Binary<T>) encoders.getInstanceFor(type);
|
||||||
Class<? extends Encoder> encoderClass = encoders.getEncoderFor(type);
|
assertThat("Encoder", encoder, notNullValue());
|
||||||
assertThat("Encoder Class", encoderClass, notNullValue());
|
|
||||||
|
|
||||||
Encoder.Binary<T> encoder = (Encoder.Binary<T>) encoderClass.newInstance();
|
|
||||||
encoder.init(testConfig);
|
|
||||||
ByteBuffer encoded = encoder.encode(value);
|
ByteBuffer encoded = encoder.encode(value);
|
||||||
|
|
||||||
String hexEncoded = Hex.asHex(encoded);
|
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
|
public <T> void assertBinaryStreamEncoder(Class<T> type, T value, String expectedEncodedHex) throws IllegalAccessException, InstantiationException, EncodeException, IOException
|
||||||
{
|
{
|
||||||
Class<? extends Encoder> encoderClass = encoders.getEncoderFor(type);
|
Encoder.BinaryStream<T> encoder = (Encoder.BinaryStream<T>) encoders.getInstanceFor(type);
|
||||||
assertThat("Encoder Class", encoderClass, notNullValue());
|
assertThat("Encoder", encoder, notNullValue());
|
||||||
|
|
||||||
Encoder.BinaryStream<T> encoder = (Encoder.BinaryStream<T>) encoderClass.newInstance();
|
|
||||||
encoder.init(testConfig);
|
|
||||||
ByteArrayOutputStream out = new ByteArrayOutputStream();
|
ByteArrayOutputStream out = new ByteArrayOutputStream();
|
||||||
encoder.encode(value, out);
|
encoder.encode(value, out);
|
||||||
|
|
||||||
|
@ -211,6 +203,15 @@ public class AvailableEncodersTest
|
||||||
assertBinaryEncoder(byte[].class, buf, "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
|
@Test
|
||||||
public void testCustomEncoder_Time() throws IllegalAccessException, InstantiationException, EncodeException, IOException
|
public void testCustomEncoder_Time() throws IllegalAccessException, InstantiationException, EncodeException, IOException
|
||||||
{
|
{
|
||||||
|
@ -274,4 +275,25 @@ public class AvailableEncodersTest
|
||||||
long value = 0x112233445566L;
|
long value = 0x112233445566L;
|
||||||
assertBinaryStreamEncoder(Long.class, value, "5B00001122334455665D");
|
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);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -52,14 +52,22 @@ public class JsrEndpointFunctions_BadSignaturesTest
|
||||||
container = new ClientContainer();
|
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
|
@Rule
|
||||||
public ExpectedException expectedException = ExpectedException.none();
|
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
|
private void assertBadSocket(TrackingSocket socket, String expectedString) throws Exception
|
||||||
{
|
{
|
||||||
JsrEndpointFunctions functions = new JsrEndpointFunctions(
|
JsrEndpointFunctions functions = new JsrEndpointFunctions(
|
||||||
|
|
|
@ -54,10 +54,18 @@ public class JsrEndpointFunctions_OnCloseTest
|
||||||
container = new ClientContainer();
|
container = new ClientContainer();
|
||||||
}
|
}
|
||||||
|
|
||||||
private AvailableEncoders encoders = new AvailableEncoders();
|
private AvailableEncoders encoders;
|
||||||
private AvailableDecoders decoders = new AvailableDecoders();
|
private AvailableDecoders decoders;
|
||||||
private Map<String,String> uriParams = new HashMap<>();
|
private Map<String, String> uriParams = new HashMap<>();
|
||||||
private EndpointConfig endpointConfig = new EmptyClientEndpointConfig();
|
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)
|
public JsrSession newSession(Object websocket)
|
||||||
{
|
{
|
||||||
|
|
|
@ -51,10 +51,18 @@ public class JsrEndpointFunctions_OnErrorTest
|
||||||
container = new ClientContainer();
|
container = new ClientContainer();
|
||||||
}
|
}
|
||||||
|
|
||||||
private AvailableEncoders encoders = new AvailableEncoders();
|
private AvailableEncoders encoders;
|
||||||
private AvailableDecoders decoders = new AvailableDecoders();
|
private AvailableDecoders decoders;
|
||||||
private Map<String, String> uriParams = new HashMap<>();
|
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)
|
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.hamcrest.CoreMatchers.is;
|
||||||
import static org.junit.Assert.assertThat;
|
import static org.junit.Assert.assertThat;
|
||||||
|
|
||||||
import java.net.URI;
|
|
||||||
import java.nio.ByteBuffer;
|
import java.nio.ByteBuffer;
|
||||||
import java.nio.charset.StandardCharsets;
|
import java.nio.charset.StandardCharsets;
|
||||||
import java.util.HashMap;
|
import java.util.HashMap;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
|
|
||||||
import javax.websocket.ClientEndpoint;
|
import javax.websocket.ClientEndpoint;
|
||||||
import javax.websocket.ClientEndpointConfig;
|
|
||||||
import javax.websocket.EndpointConfig;
|
import javax.websocket.EndpointConfig;
|
||||||
import javax.websocket.OnMessage;
|
import javax.websocket.OnMessage;
|
||||||
import javax.websocket.Session;
|
import javax.websocket.Session;
|
||||||
|
|
||||||
import org.eclipse.jetty.util.BufferUtil;
|
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.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.client.EmptyClientEndpointConfig;
|
||||||
import org.eclipse.jetty.websocket.jsr356.decoders.AvailableDecoders;
|
import org.eclipse.jetty.websocket.jsr356.decoders.AvailableDecoders;
|
||||||
import org.eclipse.jetty.websocket.jsr356.encoders.AvailableEncoders;
|
import org.eclipse.jetty.websocket.jsr356.encoders.AvailableEncoders;
|
||||||
|
@ -56,22 +50,18 @@ public class JsrEndpointFunctions_OnMessage_BinaryTest
|
||||||
container = new ClientContainer();
|
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 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();
|
endpointConfig = new EmptyClientEndpointConfig();
|
||||||
URI requestURI = URI.create("ws://localhost/" + id);
|
encoders = new AvailableEncoders(endpointConfig);
|
||||||
WebSocketPolicy policy = WebSocketPolicy.newClientPolicy();
|
decoders = new AvailableDecoders(endpointConfig);
|
||||||
DummyConnection connection = new DummyConnection(policy);
|
uriParams = new HashMap<>();
|
||||||
ClientEndpointConfig config = new EmptyClientEndpointConfig();
|
|
||||||
ConfiguredEndpoint ei = new ConfiguredEndpoint(websocket, config);
|
|
||||||
return new JsrSession(container, id, requestURI, ei, connection);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private void assertOnMessageInvocation(TrackingSocket socket, String expectedEventFormat, Object... args) throws Exception
|
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 static org.hamcrest.Matchers.containsString;
|
||||||
|
|
||||||
import java.lang.reflect.InvocationTargetException;
|
import java.lang.reflect.InvocationTargetException;
|
||||||
import java.net.URI;
|
|
||||||
import java.nio.ByteBuffer;
|
import java.nio.ByteBuffer;
|
||||||
import java.nio.charset.StandardCharsets;
|
import java.nio.charset.StandardCharsets;
|
||||||
import java.util.HashMap;
|
import java.util.HashMap;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
|
|
||||||
import javax.websocket.ClientEndpointConfig;
|
|
||||||
import javax.websocket.EndpointConfig;
|
import javax.websocket.EndpointConfig;
|
||||||
import javax.websocket.OnMessage;
|
import javax.websocket.OnMessage;
|
||||||
import javax.websocket.Session;
|
import javax.websocket.Session;
|
||||||
|
|
||||||
import org.eclipse.jetty.util.BufferUtil;
|
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.InvalidSignatureException;
|
||||||
import org.eclipse.jetty.websocket.common.test.DummyConnection;
|
|
||||||
import org.eclipse.jetty.websocket.jsr356.ClientContainer;
|
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.client.EmptyClientEndpointConfig;
|
||||||
import org.eclipse.jetty.websocket.jsr356.decoders.AvailableDecoders;
|
import org.eclipse.jetty.websocket.jsr356.decoders.AvailableDecoders;
|
||||||
import org.eclipse.jetty.websocket.jsr356.encoders.AvailableEncoders;
|
import org.eclipse.jetty.websocket.jsr356.encoders.AvailableEncoders;
|
||||||
|
@ -58,23 +52,20 @@ public class JsrEndpointFunctions_OnMessage_TextTest
|
||||||
container = new ClientContainer();
|
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
|
@Rule
|
||||||
public ExpectedException expectedException = ExpectedException.none();
|
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();
|
endpointConfig = new EmptyClientEndpointConfig();
|
||||||
URI requestURI = URI.create("ws://localhost/" + id);
|
encoders = new AvailableEncoders(endpointConfig);
|
||||||
WebSocketPolicy policy = WebSocketPolicy.newClientPolicy();
|
decoders = new AvailableDecoders(endpointConfig);
|
||||||
DummyConnection connection = new DummyConnection(policy);
|
uriParams = new HashMap<>();
|
||||||
ClientEndpointConfig config = new EmptyClientEndpointConfig();
|
|
||||||
ConfiguredEndpoint ei = new ConfiguredEndpoint(websocket, config);
|
|
||||||
return new JsrSession(container, id, requestURI, ei, connection);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private void onText(TrackingSocket socket, String msg)
|
private void onText(TrackingSocket socket, String msg)
|
||||||
|
|
|
@ -50,10 +50,18 @@ public class JsrEndpointFunctions_OnOpenTest
|
||||||
container = new ClientContainer();
|
container = new ClientContainer();
|
||||||
}
|
}
|
||||||
|
|
||||||
private AvailableEncoders encoders = new AvailableEncoders();
|
private AvailableEncoders encoders;
|
||||||
private AvailableDecoders decoders = new AvailableDecoders();
|
private AvailableDecoders decoders;
|
||||||
private Map<String,String> uriParams = new HashMap<>();
|
private Map<String, String> uriParams = new HashMap<>();
|
||||||
private EndpointConfig endpointConfig = new EmptyClientEndpointConfig();
|
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)
|
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());
|
throw new InvalidSignatureException(err.toString());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
protected void clearOnPongFunction()
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
protected void clearOnTextSink()
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
protected void clearOnBinarySink()
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
public BatchMode getBatchMode()
|
public BatchMode getBatchMode()
|
||||||
{
|
{
|
||||||
return batchMode;
|
return batchMode;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public Executor getExecutor()
|
||||||
|
{
|
||||||
|
return executor;
|
||||||
|
}
|
||||||
|
|
||||||
public T getSession()
|
public T getSession()
|
||||||
{
|
{
|
||||||
return session;
|
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)
|
public void setOnOpen(Function<T, Void> function, Object origin)
|
||||||
{
|
{
|
||||||
assertNotSet(this.onOpenFunction, "Open Handler", origin);
|
assertNotSet(this.onOpenFunction, "Open Handler", origin);
|
||||||
|
|
Loading…
Reference in New Issue