Issue #207 - Support javax.websocket version 1.1

This commit is contained in:
Joakim Erdfelt 2016-08-15 13:32:05 -07:00
parent 2175625537
commit 795246c785
26 changed files with 813 additions and 1107 deletions

View File

@ -119,7 +119,7 @@ public class JsrSession extends WebSocketSession implements javax.websocket.Sess
}
getJsrEndpointFunctions().setMessageHandler(clazz, handler);
messageHandlerSet.add(handler);
registerMessageHandler(handler);
}
/**
@ -136,7 +136,7 @@ public class JsrSession extends WebSocketSession implements javax.websocket.Sess
LOG.debug("MessageHandler.Whole class: {}", handler.getClass());
}
getJsrEndpointFunctions().setMessageHandler(clazz, handler);
messageHandlerSet.add(handler);
registerMessageHandler(handler);
}
/**
@ -150,21 +150,36 @@ public class JsrSession extends WebSocketSession implements javax.websocket.Sess
{
Objects.requireNonNull(handler, "MessageHandler cannot be null");
Class<? extends MessageHandler> handlerClass = handler.getClass();
boolean added = false;
if (MessageHandler.Whole.class.isAssignableFrom(handlerClass))
{
Class<?> onMessageClass = ReflectUtils.findGenericClassFor(handlerClass, MessageHandler.Whole.class);
addMessageHandler(onMessageClass, (MessageHandler.Whole) handler);
added = true;
}
if (MessageHandler.Partial.class.isAssignableFrom(handlerClass))
{
Class<?> onMessageClass = ReflectUtils.findGenericClassFor(handlerClass, MessageHandler.Partial.class);
addMessageHandler(onMessageClass, (MessageHandler.Partial) handler);
added = true;
}
// Should not be possible
throw new IllegalStateException("Not a recognized " + MessageHandler.class.getName() + " type: " + handler.getClass());
if (!added)
{
// Should not be possible
throw new IllegalStateException("Not a recognized " + MessageHandler.class.getName() + " type: " + handler.getClass());
}
}
protected synchronized void registerMessageHandler(MessageHandler handler)
{
if (messageHandlerSet == null)
{
messageHandlerSet = new HashSet<>();
}
messageHandlerSet.add(handler);
}
@Override
@ -241,6 +256,11 @@ public class JsrSession extends WebSocketSession implements javax.websocket.Sess
@Override
public Set<MessageHandler> getMessageHandlers()
{
if (messageHandlerSet == null)
{
return Collections.emptySet();
}
// Always return copy of set, as it is common to iterate and remove from the real set.
return new HashSet<MessageHandler>(messageHandlerSet);
}
@ -309,7 +329,7 @@ public class JsrSession extends WebSocketSession implements javax.websocket.Sess
@Override
public synchronized void removeMessageHandler(MessageHandler handler)
{
if (messageHandlerSet.remove(handler))
if (messageHandlerSet != null && messageHandlerSet.remove(handler))
{
// remove from endpoint functions too
getJsrEndpointFunctions().removeMessageHandler(handler);

View File

@ -42,13 +42,20 @@ public class AvailableDecoders implements Predicate<Class<?>>
public final Class<? extends Decoder> decoder;
public final Class<? extends Decoder> interfaceType;
public final Class<?> objectType;
public final boolean primitive;
public Decoder instance;
public RegisteredDecoder(Class<? extends Decoder> decoder, Class<? extends Decoder> interfaceType, Class<?> objectType)
{
this(decoder, interfaceType, objectType, false);
}
public RegisteredDecoder(Class<? extends Decoder> decoder, Class<? extends Decoder> interfaceType, Class<?> objectType, boolean primitive)
{
this.decoder = decoder;
this.interfaceType = interfaceType;
this.objectType = objectType;
this.primitive = primitive;
}
public boolean implementsInterface(Class<? extends Decoder> type)
@ -61,7 +68,7 @@ public class AvailableDecoders implements Predicate<Class<?>>
return objectType.isAssignableFrom(type);
}
}
private final EndpointConfig config;
private LinkedList<RegisteredDecoder> registeredDecoders;
@ -71,36 +78,36 @@ public class AvailableDecoders implements Predicate<Class<?>>
registeredDecoders = new LinkedList<>();
// TEXT based [via Class reference]
register(BooleanDecoder.class, Decoder.Text.class, Boolean.class);
register(ByteDecoder.class, Decoder.Text.class, Byte.class);
register(CharacterDecoder.class, Decoder.Text.class, Character.class);
register(DoubleDecoder.class, Decoder.Text.class, Double.class);
register(FloatDecoder.class, Decoder.Text.class, Float.class);
register(IntegerDecoder.class, Decoder.Text.class, Integer.class);
register(LongDecoder.class, Decoder.Text.class, Long.class);
register(StringDecoder.class, Decoder.Text.class, String.class);
registerPrimitive(BooleanDecoder.class, Decoder.Text.class, Boolean.class);
registerPrimitive(ByteDecoder.class, Decoder.Text.class, Byte.class);
registerPrimitive(CharacterDecoder.class, Decoder.Text.class, Character.class);
registerPrimitive(DoubleDecoder.class, Decoder.Text.class, Double.class);
registerPrimitive(FloatDecoder.class, Decoder.Text.class, Float.class);
registerPrimitive(IntegerDecoder.class, Decoder.Text.class, Integer.class);
registerPrimitive(LongDecoder.class, Decoder.Text.class, Long.class);
registerPrimitive(StringDecoder.class, Decoder.Text.class, String.class);
// TEXT based [via Primitive reference]
register(BooleanDecoder.class, Decoder.Text.class, Boolean.TYPE);
register(ByteDecoder.class, Decoder.Text.class, Byte.TYPE);
register(CharacterDecoder.class, Decoder.Text.class, Character.TYPE);
register(DoubleDecoder.class, Decoder.Text.class, Double.TYPE);
register(FloatDecoder.class, Decoder.Text.class, Float.TYPE);
register(IntegerDecoder.class, Decoder.Text.class, Integer.TYPE);
register(LongDecoder.class, Decoder.Text.class, Long.TYPE);
registerPrimitive(BooleanDecoder.class, Decoder.Text.class, Boolean.TYPE);
registerPrimitive(ByteDecoder.class, Decoder.Text.class, Byte.TYPE);
registerPrimitive(CharacterDecoder.class, Decoder.Text.class, Character.TYPE);
registerPrimitive(DoubleDecoder.class, Decoder.Text.class, Double.TYPE);
registerPrimitive(FloatDecoder.class, Decoder.Text.class, Float.TYPE);
registerPrimitive(IntegerDecoder.class, Decoder.Text.class, Integer.TYPE);
registerPrimitive(LongDecoder.class, Decoder.Text.class, Long.TYPE);
// BINARY based
register(ByteBufferDecoder.class, Decoder.Binary.class, ByteBuffer.class);
register(ByteArrayDecoder.class, Decoder.Binary.class, byte[].class);
registerPrimitive(ByteBufferDecoder.class, Decoder.Binary.class, ByteBuffer.class);
registerPrimitive(ByteArrayDecoder.class, Decoder.Binary.class, byte[].class);
// STREAMING based
register(ReaderDecoder.class, Decoder.TextStream.class, Reader.class);
register(InputStreamDecoder.class, Decoder.BinaryStream.class, InputStreamDecoder.class);
registerPrimitive(ReaderDecoder.class, Decoder.TextStream.class, Reader.class);
registerPrimitive(InputStreamDecoder.class, Decoder.BinaryStream.class, InputStreamDecoder.class);
}
private void register(Class<? extends Decoder> decoderClass, Class<? extends Decoder> interfaceType, Class<?> type)
private void registerPrimitive(Class<? extends Decoder> decoderClass, Class<? extends Decoder> interfaceType, Class<?> type)
{
registeredDecoders.add(new RegisteredDecoder(decoderClass, interfaceType, type));
registeredDecoders.add(new RegisteredDecoder(decoderClass, interfaceType, type, true));
}
public void register(Class<? extends Decoder> decoder)
@ -167,14 +174,34 @@ public class AvailableDecoders implements Predicate<Class<?>>
if (objectType == null)
{
StringBuilder err = new StringBuilder();
err.append("Invalid Decoder Object type declared for interface ");
err.append("Unknown Decoder Object type declared for interface ");
err.append(interfaceClass.getName());
err.append(" on class ");
err.append(decoder);
throw new InvalidWebSocketException(err.toString());
}
registeredDecoders.add(new RegisteredDecoder(decoder, interfaceClass, objectType));
try
{
RegisteredDecoder conflicts = registeredDecoders.stream()
.filter(registered -> registered.isType(objectType))
.filter(registered -> !registered.primitive)
.findFirst()
.get();
StringBuilder err = new StringBuilder();
err.append("Duplicate Decoder Object type ");
err.append(objectType.getName());
err.append(" in ");
err.append(decoder.getName());
err.append(", previously declared in ");
err.append(conflicts.decoder.getName());
throw new InvalidWebSocketException(err.toString());
}
catch (NoSuchElementException e)
{
registeredDecoders.addFirst(new RegisteredDecoder(decoder, interfaceClass, objectType));
}
}
public List<RegisteredDecoder> supporting(Class<? extends Decoder> interfaceType)
@ -204,28 +231,36 @@ public class AvailableDecoders implements Predicate<Class<?>>
}
}
public Decoder getInstanceFor(Class<?> type)
public <T extends Decoder> T getInstanceOf(RegisteredDecoder registeredDecoder)
{
if (registeredDecoder.instance != null)
{
return (T) registeredDecoder.instance;
}
try
{
registeredDecoder.instance = registeredDecoder.decoder.newInstance();
registeredDecoder.instance.init(this.config);
return (T) registeredDecoder.instance;
}
catch (InstantiationException | IllegalAccessException e)
{
throw new InitException("Unable to init Decoder for type:" + registeredDecoder.decoder.getName(), e);
}
}
public <T extends Decoder> T getInstanceFor(Class<?> type)
{
try
{
RegisteredDecoder registeredDecoder = getRegisteredDecoderFor(type);
if (registeredDecoder.instance != null)
{
return registeredDecoder.instance;
}
registeredDecoder.instance = registeredDecoder.decoder.newInstance();
registeredDecoder.instance.init(this.config);
return registeredDecoder.instance;
return getInstanceOf(registeredDecoder);
}
catch (NoSuchElementException e)
{
throw new InvalidWebSocketException("No Decoder found for type " + type);
}
catch (InstantiationException | IllegalAccessException e)
{
throw new InitException("Unable to init Decoder for type:" + type.getName(), e);
}
}
public static Object decodePrimitive(String value, Class<?> type) throws DecodeException

View File

@ -22,6 +22,7 @@ import java.nio.ByteBuffer;
import java.util.LinkedList;
import java.util.List;
import java.util.NoSuchElementException;
import java.util.Objects;
import java.util.function.Predicate;
import java.util.stream.Collectors;
@ -65,6 +66,7 @@ public class AvailableEncoders implements Predicate<Class<?>>
public AvailableEncoders(EndpointConfig config)
{
Objects.requireNonNull(config);
this.config = config;
registeredEncoders = new LinkedList<>();

View File

@ -27,8 +27,10 @@ import java.util.ArrayList;
import java.util.Comparator;
import java.util.List;
import java.util.Map;
import java.util.NoSuchElementException;
import java.util.concurrent.Executor;
import java.util.function.BiFunction;
import java.util.function.Function;
import java.util.stream.Collectors;
import javax.websocket.ClientEndpoint;
@ -55,6 +57,7 @@ import org.eclipse.jetty.websocket.api.WebSocketException;
import org.eclipse.jetty.websocket.api.WebSocketPolicy;
import org.eclipse.jetty.websocket.common.InvalidSignatureException;
import org.eclipse.jetty.websocket.common.function.CommonEndpointFunctions;
import org.eclipse.jetty.websocket.common.message.MessageSink;
import org.eclipse.jetty.websocket.common.message.PartialBinaryMessageSink;
import org.eclipse.jetty.websocket.common.message.PartialTextMessageSink;
import org.eclipse.jetty.websocket.common.reflect.Arg;
@ -78,6 +81,42 @@ public class JsrEndpointFunctions extends CommonEndpointFunctions<JsrSession>
{
private static final Logger LOG = Log.getLogger(JsrEndpointFunctions.class);
protected static class MessageHandlerPongFunction implements Function<ByteBuffer, Void>
{
public final MessageHandler messageHandler;
public final Function<ByteBuffer, Void> function;
public MessageHandlerPongFunction(MessageHandler messageHandler, Function<ByteBuffer, Void> function)
{
this.messageHandler = messageHandler;
this.function = function;
}
@Override
public Void apply(ByteBuffer byteBuffer)
{
return function.apply(byteBuffer);
}
}
protected static class MessageHandlerSink implements MessageSink
{
public final MessageHandler messageHandler;
public final MessageSink delegateSink;
public MessageHandlerSink(MessageHandler messageHandler, MessageSink messageSink)
{
this.messageHandler = messageHandler;
this.delegateSink = messageSink;
}
@Override
public void accept(ByteBuffer payload, Boolean fin)
{
this.delegateSink.accept(payload, fin);
}
}
/**
* Represents a static value (as seen from a URI PathParam)
* <p>
@ -128,6 +167,212 @@ public class JsrEndpointFunctions extends CommonEndpointFunctions<JsrSession>
}
}
public AvailableDecoders getAvailableDecoders()
{
return decoders;
}
/**
* Identify the message sink the handler belongs to and remove it.
* Block if the message sink is actively being used.
*
* @param handler the handler to remove from possible message sinks
* @see {@link javax.websocket.Session#removeMessageHandler(MessageHandler)}
* @since JSR356 v1.0
*/
public void removeMessageHandler(MessageHandler handler)
{
Function<ByteBuffer, Void> pongFunction = getOnPongFunction();
if (pongFunction instanceof MessageHandlerPongFunction)
{
MessageHandlerPongFunction handlerFunction = (MessageHandlerPongFunction) pongFunction;
if (handlerFunction.messageHandler == handler)
clearOnPongFunction();
}
MessageSink textSink = getOnTextSink();
if (textSink instanceof MessageHandlerSink)
{
MessageHandlerSink handlerSink = (MessageHandlerSink) textSink;
if (handlerSink.messageHandler == handler)
clearOnTextSink();
}
MessageSink binarySink = getOnBinarySink();
if (binarySink instanceof MessageHandlerSink)
{
MessageHandlerSink handlerSink = (MessageHandlerSink) binarySink;
if (handlerSink.messageHandler == handler)
clearOnBinarySink();
}
}
/**
* Create a message sink from the provided partial message handler.
*
* @param clazz the object type
* @param handler the partial message handler
* @param <T> the generic defined type
* @throws IllegalStateException if unable to process message handler
* @see {@link javax.websocket.Session#addMessageHandler(Class, MessageHandler.Partial)}
* @since JSR356 v1.1
*/
public <T> void setMessageHandler(Class<T> clazz, MessageHandler.Partial<T> handler) throws IllegalStateException
{
if (String.class.isAssignableFrom(clazz))
{
PartialTextMessageSink sink = new PartialTextMessageSink((partial) ->
{
handler.onMessage((T) partial.getPayload(), partial.isFin());
return null;
});
setOnText(new MessageHandlerSink(handler, sink), handler);
return;
}
if (ByteBuffer.class.isAssignableFrom(clazz))
{
PartialBinaryMessageSink sink = new PartialBinaryMessageSink((partial) ->
{
handler.onMessage((T) partial.getPayload(), partial.isFin());
return null;
});
setOnBinary(new MessageHandlerSink(handler, sink), handler);
return;
}
if (byte[].class.isAssignableFrom(clazz))
{
PartialBinaryMessageSink sink = new PartialBinaryMessageSink((partial) ->
{
handler.onMessage((T) BufferUtil.toArray(partial.getPayload()), partial.isFin());
return null;
});
setOnBinary(new MessageHandlerSink(handler, sink), handler);
return;
}
// If we reached this point, then the Partial type is unrecognized
StringBuilder err = new StringBuilder();
err.append("Unrecognized ").append(MessageHandler.Partial.class.getName());
err.append(" type <");
err.append(clazz.getName());
err.append("> on ");
err.append(handler.getClass().getName());
throw new IllegalStateException(err.toString());
}
/**
* Create a message sink from the provided whole message handler.
*
* @param clazz the object type
* @param handler the whole message handler
* @param <T> the generic defined type
* @throws IllegalStateException if unable to process message handler
* @see {@link javax.websocket.Session#addMessageHandler(Class, MessageHandler.Whole)}
* @since JSR356 v1.1
*/
public <T> void setMessageHandler(Class<T> clazz, MessageHandler.Whole<T> handler) throws IllegalStateException
{
try
{
// Is this a PongMessage?
if (PongMessage.class.isAssignableFrom(PongMessage.class))
{
Function<ByteBuffer, Void> pongFunction = (payload) ->
{
handler.onMessage((T) new JsrPongMessage(payload));
return null;
};
setOnPong(new MessageHandlerPongFunction(handler, pongFunction), handler);
return;
}
// Try to determine TEXT / BINARY
AvailableDecoders.RegisteredDecoder registeredDecoder = decoders.getRegisteredDecoderFor(clazz);
if (registeredDecoder.implementsInterface(Decoder.Text.class))
{
Decoder.Text decoderInstance = decoders.getInstanceOf(registeredDecoder);
DecodedTextMessageSink textSink = new DecodedTextMessageSink(
policy, this, decoderInstance,
(msg) ->
{
handler.onMessage((T) msg);
return null;
}
);
setOnText(new MessageHandlerSink(handler, textSink), handler);
return;
}
if (registeredDecoder.implementsInterface(Decoder.Binary.class))
{
Decoder.Binary decoderInstance = decoders.getInstanceOf(registeredDecoder);
DecodedBinaryMessageSink binarySink = new DecodedBinaryMessageSink(
policy, this, decoderInstance,
(msg) ->
{
handler.onMessage((T) msg);
return null;
}
);
setOnBinary(new MessageHandlerSink(handler, binarySink), handler);
return;
}
if (registeredDecoder.implementsInterface(Decoder.TextStream.class))
{
Decoder.TextStream decoderInstance = decoders.getInstanceOf(registeredDecoder);
DecodedReaderMessageSink textSink = new DecodedReaderMessageSink(
this, decoderInstance,
(msg) ->
{
handler.onMessage((T) msg);
return null;
}
);
setOnText(new MessageHandlerSink(handler, textSink), handler);
return;
}
if (registeredDecoder.implementsInterface(Decoder.BinaryStream.class))
{
Decoder.BinaryStream decoderInstance = decoders.getInstanceOf(registeredDecoder);
DecodedInputStreamMessageSink binarySink = new DecodedInputStreamMessageSink(
this, decoderInstance,
(msg) ->
{
handler.onMessage((T) msg);
return null;
}
);
setOnBinary(new MessageHandlerSink(handler, binarySink), handler);
return;
}
// If we reached this point, then the Whole Message Type is unrecognized
StringBuilder err = new StringBuilder();
err.append("Unrecognized message type ");
err.append(MessageHandler.Whole.class.getName());
err.append("<").append(clazz.getName());
err.append("> on ");
err.append(handler.getClass().getName());
throw new IllegalStateException(err.toString());
}
catch (NoSuchElementException e)
{
// No valid decoder for type found
StringBuilder err = new StringBuilder();
err.append("Not a valid ").append(MessageHandler.Whole.class.getName());
err.append(" type <");
err.append(clazz.getName());
err.append("> on ");
err.append(handler.getClass().getName());
throw new IllegalStateException(err.toString());
}
}
@Override
protected void discoverEndpointFunctions(Object endpoint)
{
@ -296,228 +541,21 @@ public class JsrEndpointFunctions extends CommonEndpointFunctions<JsrSession>
onmsgloop:
for (Method onMsg : onMessages)
{
boolean foundMatch = false;
// Whole TEXT / Binary Message
if (discoverOnMessageWholeText(onMsg)) continue onmsgloop;
if (discoverOnMessageWholeBinary(onMsg)) continue onmsgloop;
// Try to determine Message type (BINARY / TEXT) from signature
// Partial TEXT / BINARY
if (discoverOnMessagePartialText(onMsg)) continue onmsgloop;
if (discoverOnMessagePartialBinaryArray(onMsg)) continue onmsgloop;
if (discoverOnMessagePartialBinaryBuffer(onMsg)) continue onmsgloop;
Arg SESSION = new Arg(Session.class);
// Streaming TEXT / BINARY
if (discoverOnMessageTextStream(onMsg)) continue onmsgloop;
if (discoverOnMessageBinaryStream(onMsg)) continue onmsgloop;
// --------------------
// -- Whole Messages --
// --------------------
// Whole TEXT
for (AvailableDecoders.RegisteredDecoder decoder : decoders.supporting(Decoder.Text.class))
{
UnorderedSignature sig = new UnorderedSignature(createCallArgs(SESSION, new Arg(decoder.objectType).required()));
if (sig.test(onMsg))
{
assertOnMessageSignature(onMsg);
final Object[] args = newCallArgs(sig.getCallArgs());
args[0] = getSession();
BiFunction<Object, Object[], Object> invoker = sig.newFunction(onMsg);
Decoder.Text decoderInstance = getDecoderInstance(decoder, Decoder.Text.class);
DecodedTextMessageSink textSink = new DecodedTextMessageSink(
getSession(),
decoderInstance,
(msg) ->
{
args[1] = msg;
return invoker.apply(endpoint, args);
}
);
setOnText(textSink, onMsg);
continue onmsgloop;
}
}
// Whole BINARY
for (AvailableDecoders.RegisteredDecoder decoder : decoders.supporting(Decoder.Binary.class))
{
UnorderedSignature sig = new UnorderedSignature(createCallArgs(SESSION, new Arg(decoder.objectType).required()));
if (sig.test(onMsg))
{
assertOnMessageSignature(onMsg);
final Object[] args = newCallArgs(sig.getCallArgs());
args[0] = getSession();
BiFunction<Object, Object[], Object> invoker = sig.newFunction(onMsg);
Decoder.Binary decoderInstance = getDecoderInstance(decoder, Decoder.Binary.class);
DecodedBinaryMessageSink binarySink = new DecodedBinaryMessageSink(
getSession(),
decoderInstance,
(msg) ->
{
args[1] = msg;
return invoker.apply(endpoint, args);
}
);
setOnBinary(binarySink, onMsg);
continue onmsgloop;
}
}
// ----------------------
// -- Partial Messages --
// ----------------------
Arg ARG_PARTIAL_BOOL = new Arg(boolean.class).required();
// Partial Text
Arg ARG_STRING = new Arg(String.class).required();
UnorderedSignature sigPartialText = new UnorderedSignature(createCallArgs(SESSION, ARG_STRING, ARG_PARTIAL_BOOL));
if (sigPartialText.test(onMsg))
{
// Found partial text args
assertOnMessageSignature(onMsg);
final Object[] args = newCallArgs(sigPartialText.getCallArgs());
args[0] = getSession();
BiFunction<Object, Object[], Object> invoker = sigPartialText.newFunction(onMsg);
// No decoders for Partial messages per JSR-356 (PFD1 spec)
setOnText(new PartialTextMessageSink((partial) ->
{
args[1] = partial.getPayload();
args[2] = partial.isFin();
invoker.apply(endpoint, args);
return null;
}), onMsg);
continue onmsgloop;
}
// Partial Binary
Arg ARG_BYTE_ARRAY = new Arg(byte[].class).required();
UnorderedSignature sigPartialBinaryArray = new UnorderedSignature(createCallArgs(SESSION, ARG_BYTE_ARRAY, ARG_PARTIAL_BOOL));
if (sigPartialBinaryArray.test(onMsg))
{
// Found partial binary array args
assertOnMessageSignature(onMsg);
final Object[] args = newCallArgs(sigPartialBinaryArray.getCallArgs());
args[0] = getSession();
BiFunction<Object, Object[], Object> invoker = sigPartialBinaryArray.newFunction(onMsg);
// No decoders for Partial messages per JSR-356 (PFD1 spec)
setOnBinary(new PartialBinaryMessageSink((partial) ->
{
args[1] = BufferUtil.toArray(partial.getPayload());
args[2] = partial.isFin();
invoker.apply(endpoint, args);
return null;
}), onMsg);
continue onmsgloop;
}
Arg ARG_BYTE_BUFFER = new Arg(ByteBuffer.class).required();
UnorderedSignature sigPartialByteBuffer = new UnorderedSignature(createCallArgs(SESSION, ARG_BYTE_BUFFER, ARG_PARTIAL_BOOL));
if (sigPartialByteBuffer.test(onMsg))
{
// Found partial binary array args
assertOnMessageSignature(onMsg);
final Object[] args = newCallArgs(sigPartialBinaryArray.getCallArgs());
args[0] = getSession();
BiFunction<Object, Object[], Object> invoker = sigPartialBinaryArray.newFunction(onMsg);
// No decoders for Partial messages per JSR-356 (PFD1 spec)
setOnBinary(new PartialBinaryMessageSink((partial) ->
{
args[1] = partial.getPayload();
args[2] = partial.isFin();
invoker.apply(endpoint, args);
return null;
}), onMsg);
continue onmsgloop;
}
// ------------------------
// -- Streaming Messages --
// ------------------------
// Streaming TEXT ---
for (AvailableDecoders.RegisteredDecoder decoder : decoders.supporting(Decoder.TextStream.class))
{
UnorderedSignature sig = new UnorderedSignature(createCallArgs(SESSION, new Arg(decoder.objectType).required()));
if (sig.test(onMsg))
{
assertOnMessageSignature(onMsg);
final Object[] args = newCallArgs(sig.getCallArgs());
args[0] = getSession();
BiFunction<Object, Object[], Object> invoker = sig.newFunction(onMsg);
Decoder.TextStream decoderInstance = getDecoderInstance(decoder, Decoder.TextStream.class);
DecodedReaderMessageSink textSink = new DecodedReaderMessageSink(
getSession(),
decoderInstance,
(msg) ->
{
args[1] = msg;
return invoker.apply(endpoint, args);
}
);
setOnText(textSink, onMsg);
continue onmsgloop;
}
}
// Streaming BINARY ---
for (AvailableDecoders.RegisteredDecoder decoder : decoders.supporting(Decoder.BinaryStream.class))
{
UnorderedSignature sig = new UnorderedSignature(createCallArgs(SESSION, new Arg(decoder.objectType).required()));
if (sig.test(onMsg))
{
assertOnMessageSignature(onMsg);
final Object[] args = newCallArgs(sig.getCallArgs());
args[0] = getSession();
BiFunction<Object, Object[], Object> invoker = sig.newFunction(onMsg);
Decoder.BinaryStream decoderInstance = getDecoderInstance(decoder, Decoder.BinaryStream.class);
DecodedInputStreamMessageSink textSink = new DecodedInputStreamMessageSink(
getSession(),
decoderInstance,
(msg) ->
{
args[1] = msg;
return invoker.apply(endpoint, args);
}
);
setOnText(textSink, onMsg);
continue onmsgloop;
}
}
// -------------------
// -- Pong Messages --
// -------------------
// Test for PONG
UnorderedSignature sigPong = new UnorderedSignature(createCallArgs(SESSION, new Arg(PongMessage.class).required()));
if (sigPong.test(onMsg))
{
assertOnMessageSignature(onMsg);
final Object[] args = newCallArgs(sigPong.getCallArgs());
args[0] = getSession();
BiFunction<Object, Object[], Object> invoker = sigPong.newFunction(onMsg);
// No decoder for PongMessage
setOnPing((pong) ->
{
args[1] = new JsrPongMessage(pong);
Object ret = invoker.apply(endpoint, args);
if (ret != null)
{
try
{
getSession().getBasicRemote().sendObject(ret);
}
catch (EncodeException | IOException e)
{
throw new WebSocketException(e);
}
}
return null;
}, onMsg);
continue onmsgloop;
}
// PONG
if (discoverOnMessagePong(onMsg)) continue onmsgloop;
// If we reached this point, then we have a @OnMessage annotated method
// that doesn't match any known signature above.
@ -527,58 +565,243 @@ public class JsrEndpointFunctions extends CommonEndpointFunctions<JsrSession>
}
}
/**
* Create a message sink from the provided partial message handler.
*
* @param clazz the object type
* @param handler the partial message handler
* @param <T> the generic defined type
* @see {@link javax.websocket.Session#addMessageHandler(Class, MessageHandler.Partial)}
*/
public <T> void setMessageHandler(Class<T> clazz, MessageHandler.Partial<T> handler)
private boolean discoverOnMessagePong(Method onMsg) throws DecodeException
{
// TODO: implement
}
/**
* Create a message sink from the provided whole message handler.
*
* @param clazz the object type
* @param handler the whole message handler
* @param <T> the generic defined type
* @see {@link javax.websocket.Session#addMessageHandler(Class, MessageHandler.Whole)}
*/
public <T> void setMessageHandler(Class<T> clazz, MessageHandler.Whole<T> handler)
{
// TODO: implement
}
/**
* Identify the message sink the handler belongs to and remove it.
* Block if the message sink is actively being used.
* @param handler the handler to remove from possible message sinks
* @see {@link javax.websocket.Session#removeMessageHandler(MessageHandler)}
*/
public void removeMessageHandler(MessageHandler handler)
{
// TODO: implement
}
private <T extends Decoder> T getDecoderInstance(AvailableDecoders.RegisteredDecoder registeredDecoder, Class<T> interfaceType)
{
// TODO: Return previous instantiated decoders here
Class<? extends Decoder> decoderClass = registeredDecoder.decoder;
try
Arg SESSION = new Arg(Session.class);
UnorderedSignature sigPong = new UnorderedSignature(createCallArgs(SESSION, new Arg(PongMessage.class).required()));
if (sigPong.test(onMsg))
{
Decoder decoder = decoderClass.newInstance();
decoder.init(this.endpointConfig);
return (T) decoder;
assertOnMessageSignature(onMsg);
final Object[] args = newCallArgs(sigPong.getCallArgs());
BiFunction<Object, Object[], Object> invoker = sigPong.newFunction(onMsg);
// No decoder for PongMessage
setOnPong((pong) ->
{
args[0] = getSession();
args[1] = new JsrPongMessage(pong);
Object ret = invoker.apply(endpoint, args);
if (ret != null)
{
try
{
getSession().getBasicRemote().sendObject(ret);
}
catch (EncodeException | IOException e)
{
throw new WebSocketException(e);
}
}
return null;
}, onMsg);
return true;
}
catch (Throwable t)
return false;
}
private boolean discoverOnMessageBinaryStream(Method onMsg) throws DecodeException
{
Arg SESSION = new Arg(Session.class);
for (AvailableDecoders.RegisteredDecoder decoder : decoders.supporting(Decoder.BinaryStream.class))
{
throw new InvalidWebSocketException("Unable to initialize required Decoder: " + decoderClass.getName(), t);
UnorderedSignature sig = new UnorderedSignature(createCallArgs(SESSION, new Arg(decoder.objectType).required()));
if (sig.test(onMsg))
{
assertOnMessageSignature(onMsg);
final Object[] args = newCallArgs(sig.getCallArgs());
BiFunction<Object, Object[], Object> invoker = sig.newFunction(onMsg);
Decoder.BinaryStream decoderInstance = decoders.getInstanceOf(decoder);
DecodedInputStreamMessageSink streamSink = new DecodedInputStreamMessageSink(
this,
decoderInstance,
(msg) ->
{
args[0] = getSession();
args[1] = msg;
return invoker.apply(endpoint, args);
}
);
setOnBinary(streamSink, onMsg);
return true;
}
}
return false;
}
private boolean discoverOnMessageTextStream(Method onMsg) throws DecodeException
{
Arg SESSION = new Arg(Session.class);
for (AvailableDecoders.RegisteredDecoder decoder : decoders.supporting(Decoder.TextStream.class))
{
UnorderedSignature sig = new UnorderedSignature(createCallArgs(SESSION, new Arg(decoder.objectType).required()));
if (sig.test(onMsg))
{
assertOnMessageSignature(onMsg);
final Object[] args = newCallArgs(sig.getCallArgs());
BiFunction<Object, Object[], Object> invoker = sig.newFunction(onMsg);
Decoder.TextStream decoderInstance = decoders.getInstanceOf(decoder);
DecodedReaderMessageSink streamSink = new DecodedReaderMessageSink(
this,
decoderInstance,
(msg) ->
{
args[0] = getSession();
args[1] = msg;
return invoker.apply(endpoint, args);
}
);
setOnText(streamSink, onMsg);
return true;
}
}
return false;
}
@SuppressWarnings("Duplicates")
private boolean discoverOnMessagePartialBinaryBuffer(Method onMsg) throws DecodeException
{
Arg SESSION = new Arg(Session.class);
Arg ARG_BYTE_BUFFER = new Arg(ByteBuffer.class).required();
Arg ARG_PARTIAL_BOOL = new Arg(boolean.class).required();
UnorderedSignature sigPartialByteBuffer = new UnorderedSignature(createCallArgs(SESSION, ARG_BYTE_BUFFER, ARG_PARTIAL_BOOL));
if (sigPartialByteBuffer.test(onMsg))
{
// Found partial binary array args
assertOnMessageSignature(onMsg);
final Object[] args = newCallArgs(sigPartialByteBuffer.getCallArgs());
BiFunction<Object, Object[], Object> invoker = sigPartialByteBuffer.newFunction(onMsg);
// No decoders for Partial messages per JSR-356 (PFD1 spec)
setOnBinary(new PartialBinaryMessageSink((partial) ->
{
args[0] = getSession();
args[1] = partial.getPayload();
args[2] = partial.isFin();
invoker.apply(endpoint, args);
return null;
}), onMsg);
return true;
}
return false;
}
private boolean discoverOnMessagePartialBinaryArray(Method onMsg) throws DecodeException
{
Arg SESSION = new Arg(Session.class);
Arg ARG_BYTE_ARRAY = new Arg(byte[].class).required();
Arg ARG_PARTIAL_BOOL = new Arg(boolean.class).required();
UnorderedSignature sigPartialBinaryArray = new UnorderedSignature(createCallArgs(SESSION, ARG_BYTE_ARRAY, ARG_PARTIAL_BOOL));
if (sigPartialBinaryArray.test(onMsg))
{
// Found partial binary array args
assertOnMessageSignature(onMsg);
final Object[] args = newCallArgs(sigPartialBinaryArray.getCallArgs());
BiFunction<Object, Object[], Object> invoker = sigPartialBinaryArray.newFunction(onMsg);
// No decoders for Partial messages per JSR-356 (PFD1 spec)
setOnBinary(new PartialBinaryMessageSink((partial) ->
{
args[0] = getSession();
args[1] = BufferUtil.toArray(partial.getPayload());
args[2] = partial.isFin();
invoker.apply(endpoint, args);
return null;
}), onMsg);
return true;
}
return false;
}
@SuppressWarnings("Duplicates")
private boolean discoverOnMessagePartialText(Method onMsg) throws DecodeException
{
Arg SESSION = new Arg(Session.class);
Arg ARG_PARTIAL_BOOL = new Arg(boolean.class).required();
Arg ARG_STRING = new Arg(String.class).required();
UnorderedSignature sigPartialText = new UnorderedSignature(createCallArgs(SESSION, ARG_STRING, ARG_PARTIAL_BOOL));
if (sigPartialText.test(onMsg))
{
// Found partial text args
assertOnMessageSignature(onMsg);
final Object[] args = newCallArgs(sigPartialText.getCallArgs());
BiFunction<Object, Object[], Object> invoker = sigPartialText.newFunction(onMsg);
// No decoders for Partial messages per JSR-356 (PFD1 spec)
setOnText(new PartialTextMessageSink((partial) ->
{
args[0] = getSession();
args[1] = partial.getPayload();
args[2] = partial.isFin();
invoker.apply(endpoint, args);
return null;
}), onMsg);
return true;
}
return false;
}
private boolean discoverOnMessageWholeBinary(Method onMsg) throws DecodeException
{
Arg SESSION = new Arg(Session.class);
for (AvailableDecoders.RegisteredDecoder decoder : decoders.supporting(Decoder.Binary.class))
{
UnorderedSignature sig = new UnorderedSignature(createCallArgs(SESSION, new Arg(decoder.objectType).required()));
if (sig.test(onMsg))
{
assertOnMessageSignature(onMsg);
final Object[] args = newCallArgs(sig.getCallArgs());
BiFunction<Object, Object[], Object> invoker = sig.newFunction(onMsg);
Decoder.Binary decoderInstance = decoders.getInstanceOf(decoder);
DecodedBinaryMessageSink binarySink = new DecodedBinaryMessageSink(
policy,
this,
decoderInstance,
(msg) ->
{
args[0] = getSession();
args[1] = msg;
return invoker.apply(endpoint, args);
}
);
setOnBinary(binarySink, onMsg);
return true;
}
}
return false;
}
private boolean discoverOnMessageWholeText(Method onMsg) throws DecodeException
{
Arg SESSION = new Arg(Session.class);
for (AvailableDecoders.RegisteredDecoder decoder : decoders.supporting(Decoder.Text.class))
{
UnorderedSignature sig = new UnorderedSignature(createCallArgs(SESSION, new Arg(decoder.objectType).required()));
if (sig.test(onMsg))
{
assertOnMessageSignature(onMsg);
final Object[] args = newCallArgs(sig.getCallArgs());
BiFunction<Object, Object[], Object> invoker = sig.newFunction(onMsg);
Decoder.Text decoderInstance = decoders.getInstanceOf(decoder);
DecodedTextMessageSink textSink = new DecodedTextMessageSink(
policy,
this,
decoderInstance,
(msg) ->
{
args[0] = getSession();
args[1] = msg;
return invoker.apply(endpoint, args);
}
);
setOnText(textSink, onMsg);
return true;
}
}
return false;
}
private void assertSignatureValid(DynamicArgs.Signature sig, Class<? extends Annotation> annotationClass, Method method)
@ -631,11 +854,6 @@ public class JsrEndpointFunctions extends CommonEndpointFunctions<JsrSession>
}
}
public AvailableDecoders getAvailableDecoders()
{
return decoders;
}
protected Object[] newCallArgs(Arg[] callArgs) throws DecodeException
{
int len = callArgs.length;

View File

@ -26,14 +26,15 @@ import javax.websocket.Decoder;
import javax.websocket.EncodeException;
import org.eclipse.jetty.websocket.api.WebSocketException;
import org.eclipse.jetty.websocket.api.WebSocketPolicy;
import org.eclipse.jetty.websocket.common.message.ByteBufferMessageSink;
import org.eclipse.jetty.websocket.jsr356.JsrSession;
import org.eclipse.jetty.websocket.jsr356.function.JsrEndpointFunctions;
public class DecodedBinaryMessageSink extends ByteBufferMessageSink
{
public DecodedBinaryMessageSink(JsrSession session, Decoder.Binary decoder, Function<Object, Object> onMessageFunction)
public DecodedBinaryMessageSink(WebSocketPolicy policy, JsrEndpointFunctions endpointFunctions, Decoder.Binary decoder, Function<Object, Object> onMessageFunction)
{
super(session.getPolicy(), (byteBuf) ->
super(policy, (byteBuf) ->
{
try
{
@ -47,7 +48,7 @@ public class DecodedBinaryMessageSink extends ByteBufferMessageSink
if (ret != null)
{
// send response
session.getBasicRemote().sendObject(ret);
endpointFunctions.getSession().getBasicRemote().sendObject(ret);
}
return null;

View File

@ -28,14 +28,15 @@ import javax.websocket.EncodeException;
import org.eclipse.jetty.websocket.api.WebSocketException;
import org.eclipse.jetty.websocket.common.message.InputStreamMessageSink;
import org.eclipse.jetty.websocket.jsr356.JsrSession;
import org.eclipse.jetty.websocket.jsr356.function.JsrEndpointFunctions;
public class DecodedInputStreamMessageSink extends InputStreamMessageSink
{
public DecodedInputStreamMessageSink(JsrSession session,
public DecodedInputStreamMessageSink(JsrEndpointFunctions endpointFunctions,
Decoder.BinaryStream decoder,
Function<Object, Object> onMessageFunction)
{
super(session.getExecutor(), (reader) ->
super(endpointFunctions.getExecutor(), (reader) ->
{
try
{
@ -47,7 +48,7 @@ public class DecodedInputStreamMessageSink extends InputStreamMessageSink
if (ret != null)
{
// send response
session.getBasicRemote().sendObject(ret);
endpointFunctions.getSession().getBasicRemote().sendObject(ret);
}
return null;

View File

@ -27,13 +27,13 @@ import javax.websocket.EncodeException;
import org.eclipse.jetty.websocket.api.WebSocketException;
import org.eclipse.jetty.websocket.common.message.ReaderMessageSink;
import org.eclipse.jetty.websocket.jsr356.JsrSession;
import org.eclipse.jetty.websocket.jsr356.function.JsrEndpointFunctions;
public class DecodedReaderMessageSink extends ReaderMessageSink
{
public DecodedReaderMessageSink(JsrSession session, Decoder.TextStream decoder, Function<Object, Object> onMessageFunction)
public DecodedReaderMessageSink(JsrEndpointFunctions endpointFunctions, Decoder.TextStream decoder, Function<Object, Object> onMessageFunction)
{
super(session.getExecutor(), (reader) ->
super(endpointFunctions.getExecutor(), (reader) ->
{
try
{
@ -45,7 +45,7 @@ public class DecodedReaderMessageSink extends ReaderMessageSink
if (ret != null)
{
// send response
session.getBasicRemote().sendObject(ret);
endpointFunctions.getSession().getBasicRemote().sendObject(ret);
}
return null;

View File

@ -26,14 +26,15 @@ import javax.websocket.Decoder;
import javax.websocket.EncodeException;
import org.eclipse.jetty.websocket.api.WebSocketException;
import org.eclipse.jetty.websocket.api.WebSocketPolicy;
import org.eclipse.jetty.websocket.common.message.StringMessageSink;
import org.eclipse.jetty.websocket.jsr356.JsrSession;
import org.eclipse.jetty.websocket.jsr356.function.JsrEndpointFunctions;
public class DecodedTextMessageSink extends StringMessageSink
{
public DecodedTextMessageSink(JsrSession session, Decoder.Text decoder, Function<Object, Object> onMessageFunction)
public DecodedTextMessageSink(WebSocketPolicy policy, JsrEndpointFunctions endpointFunctions, Decoder.Text decoder, Function<Object, Object> onMessageFunction)
{
super(session.getPolicy(), (message) ->
super(policy, (message) ->
{
try
{
@ -45,7 +46,7 @@ public class DecodedTextMessageSink extends StringMessageSink
if (ret != null)
{
// send response
session.getBasicRemote().sendObject(ret);
endpointFunctions.getSession().getBasicRemote().sendObject(ret);
}
return null;

View File

@ -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);
}
}

View File

@ -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);
}
}

View File

@ -205,6 +205,7 @@ public class EncoderTest
}
}
@SuppressWarnings("Duplicates")
private Quotes getQuotes(String filename) throws IOException
{
Quotes quotes = new Quotes();

View File

@ -27,7 +27,6 @@ import javax.websocket.MessageHandler;
import org.eclipse.jetty.websocket.api.WebSocketPolicy;
import org.eclipse.jetty.websocket.common.test.DummyConnection;
import org.eclipse.jetty.websocket.jsr356.client.EmptyClientEndpointConfig;
import org.eclipse.jetty.websocket.jsr356.client.SimpleEndpointMetadata;
import org.eclipse.jetty.websocket.jsr356.handlers.ByteArrayWholeHandler;
import org.eclipse.jetty.websocket.jsr356.handlers.ByteBufferPartialHandler;
import org.eclipse.jetty.websocket.jsr356.handlers.LongMessageHandler;
@ -44,29 +43,19 @@ public class JsrSessionTest
@Before
public void initSession()
{
container = new ClientContainer();
String id = JsrSessionTest.class.getSimpleName();
URI requestURI = URI.create("ws://localhost/" + id);
WebSocketPolicy policy = WebSocketPolicy.newClientPolicy();
DummyConnection connection = new DummyConnection(policy);
ClientEndpointConfig config = new EmptyClientEndpointConfig();
DummyEndpoint websocket = new DummyEndpoint();
SimpleEndpointMetadata metadata = new SimpleEndpointMetadata(websocket.getClass());
// Executor executor = null;
ConfiguredEndpoint ei = new ConfiguredEndpoint(websocket,config);
// EventDriver driver = new JsrEndpointEventDriver(policy,ei);
DummyConnection connection = new DummyConnection();
session = new JsrSession(container,id,requestURI,ei,connection);
ConfiguredEndpoint ei = new ConfiguredEndpoint(new DummyEndpoint(), config);
session = new JsrSession(container, id, requestURI, ei, connection);
}
@Test
public void testMessageHandlerBinary() throws DeploymentException
{
session.addMessageHandler(new ByteBufferPartialHandler());
// MessageHandlerWrapper wrapper = session.getMessageHandlerWrapper(MessageType.BINARY);
// Assert.assertThat("Binary Handler",wrapper.getHandler(),instanceOf(ByteBufferPartialHandler.class));
// Assert.assertEquals("Message Class",wrapper.getMetadata().getMessageClass(),ByteBuffer.class);
}
@Test
@ -74,12 +63,6 @@ public class JsrSessionTest
{
session.addMessageHandler(new StringWholeHandler());
session.addMessageHandler(new ByteArrayWholeHandler());
// MessageHandlerWrapper wrapper = session.getMessageHandlerWrapper(MessageType.TEXT);
// Assert.assertThat("Text Handler",wrapper.getHandler(),instanceOf(StringWholeHandler.class));
// Assert.assertEquals("Message Class",wrapper.getMetadata().getMessageClass(),String.class);
// wrapper = session.getMessageHandlerWrapper(MessageType.BINARY);
// Assert.assertThat("Binary Handler",wrapper.getHandler(),instanceOf(ByteArrayWholeHandler.class));
// Assert.assertEquals("Message Class",wrapper.getMetadata().getMessageClass(),byte[].class);
}
@Test
@ -90,20 +73,11 @@ public class JsrSessionTest
session.addMessageHandler(new ByteArrayWholeHandler()); // add BINARY handler
session.removeMessageHandler(oldText); // remove original TEXT handler
session.addMessageHandler(new LongMessageHandler()); // add new TEXT handler
// MessageHandlerWrapper wrapper = session.getMessageHandlerWrapper(MessageType.BINARY);
// Assert.assertThat("Binary Handler",wrapper.getHandler(),instanceOf(ByteArrayWholeHandler.class));
// Assert.assertEquals("Message Class",wrapper.getMetadata().getMessageClass(),byte[].class);
// wrapper = session.getMessageHandlerWrapper(MessageType.TEXT);
// Assert.assertThat("Text Handler",wrapper.getHandler(),instanceOf(LongMessageHandler.class));
// Assert.assertEquals("Message Class",wrapper.getMetadata().getMessageClass(),Long.class);
}
@Test
public void testMessageHandlerText() throws DeploymentException
{
session.addMessageHandler(new StringWholeHandler());
// MessageHandlerWrapper wrapper = session.getMessageHandlerWrapper(MessageType.TEXT);
// Assert.assertThat("Text Handler",wrapper.getHandler(),instanceOf(StringWholeHandler.class));
// Assert.assertEquals("Message Class",wrapper.getMetadata().getMessageClass(),String.class);
}
}

View File

@ -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));
}
}

View File

@ -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));
}*/
}

View File

@ -18,6 +18,7 @@
package org.eclipse.jetty.websocket.jsr356.decoders;
import static org.hamcrest.Matchers.containsString;
import static org.hamcrest.Matchers.equalTo;
import static org.hamcrest.Matchers.is;
import static org.hamcrest.Matchers.notNullValue;
@ -33,10 +34,13 @@ import javax.websocket.DecodeException;
import javax.websocket.Decoder;
import javax.websocket.EndpointConfig;
import org.eclipse.jetty.websocket.api.InvalidWebSocketException;
import org.eclipse.jetty.websocket.common.util.Hex;
import org.eclipse.jetty.websocket.jsr356.client.EmptyClientEndpointConfig;
import org.junit.BeforeClass;
import org.junit.Rule;
import org.junit.Test;
import org.junit.rules.ExpectedException;
public class AvailableDecodersTest
{
@ -47,30 +51,25 @@ public class AvailableDecodersTest
{
testConfig = new EmptyClientEndpointConfig();
}
private AvailableDecoders decoders = new AvailableDecoders();
@Rule
public ExpectedException expectedException = ExpectedException.none();
private AvailableDecoders decoders = new AvailableDecoders(testConfig);
private <T> void assertTextDecoder(Class<T> type, String value, T expectedDecoded) throws IllegalAccessException, InstantiationException, DecodeException
{
Class<? extends Decoder> decoderClass = decoders.getDecoderFor(type);
assertThat("Decoder Class", decoderClass, notNullValue());
Decoder.Text<T> decoder = (Decoder.Text<T>) decoderClass.newInstance();
decoder.init(testConfig);
Decoder.Text<T> decoder = (Decoder.Text<T>) decoders.getInstanceFor(type);
assertThat("Decoder instance", decoder, notNullValue());
T decoded = decoder.decode(value);
assertThat("Decoded", decoded, is(expectedDecoded));
}
private <T> void assertBinaryDecoder(Class<T> type, ByteBuffer value, T expectedDecoded) throws IllegalAccessException, InstantiationException, DecodeException
{
Class<? extends Decoder> decoderClass = decoders.getDecoderFor(type);
assertThat("Decoder Class", decoderClass, notNullValue());
Decoder.Binary<T> decoder = (Decoder.Binary<T>) decoderClass.newInstance();
decoder.init(testConfig);
Decoder.Binary<T> decoder = (Decoder.Binary<T>) decoders.getInstanceFor(type);
assertThat("Decoder Class", decoder, notNullValue());
T decoded = decoder.decode(value);
assertThat("Decoded", decoded, equalTo(expectedDecoded));
}
@ -194,6 +193,16 @@ public class AvailableDecodersTest
byte expected[] = Hex.asByteArray("112233445566778899");
assertBinaryDecoder(byte[].class, val, expected);
}
@Test
public void testCustomDecoder_Integer() throws IllegalAccessException, InstantiationException, DecodeException
{
decoders.register(IntegerDecoder.class);
String val = "11223344";
int expected = 11223344;
assertTextDecoder(Integer.class, val, expected);
}
@Test
public void testCustomDecoder_Time() throws IllegalAccessException, InstantiationException, DecodeException
@ -260,6 +269,9 @@ public class AvailableDecodersTest
public void testCustomDecoder_ValidDual_Text() throws IllegalAccessException, InstantiationException, DecodeException
{
decoders.register(ValidDualDecoder.class);
AvailableDecoders.RegisteredDecoder registered = decoders.getRegisteredDecoderFor(Integer.class);
assertThat("Registered Decoder for Integer", registered.decoder.getName(), is(ValidDualDecoder.class.getName()));
String val = "[1,234,567]";
Integer expected = 1234567;
@ -271,6 +283,9 @@ public class AvailableDecodersTest
public void testCustomDecoder_ValidDual_Binary() throws IllegalAccessException, InstantiationException, DecodeException
{
decoders.register(ValidDualDecoder.class);
AvailableDecoders.RegisteredDecoder registered = decoders.getRegisteredDecoderFor(Long.class);
assertThat("Registered Decoder for Long", registered.decoder.getName(), is(ValidDualDecoder.class.getName()));
ByteBuffer val = ByteBuffer.allocate(16);
val.put((byte) '[');
@ -281,4 +296,25 @@ public class AvailableDecodersTest
assertBinaryDecoder(Long.class, val, expected);
}
@Test
public void testCustomDecoder_Register_Duplicate()
{
// has duplicated support for the same target Type
expectedException.expect(InvalidWebSocketException.class);
expectedException.expectMessage(containsString("Duplicate"));
decoders.register(BadDualDecoder.class);
}
@Test
public void testCustomDecoder_Register_OtherDuplicate()
{
// Register DateDecoder (decodes java.util.Date)
decoders.register(DateDecoder.class);
// Register TimeDecoder (which also wants to decode java.util.Date)
expectedException.expect(InvalidWebSocketException.class);
expectedException.expectMessage(containsString("Duplicate"));
decoders.register(TimeDecoder.class);
}
}

View File

@ -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);
}
}

View File

@ -18,6 +18,7 @@
package org.eclipse.jetty.websocket.jsr356.encoders;
import static org.hamcrest.Matchers.containsString;
import static org.hamcrest.Matchers.is;
import static org.hamcrest.Matchers.notNullValue;
import static org.junit.Assert.assertThat;
@ -37,7 +38,9 @@ import javax.websocket.EndpointConfig;
import org.eclipse.jetty.websocket.common.util.Hex;
import org.eclipse.jetty.websocket.jsr356.client.EmptyClientEndpointConfig;
import org.junit.BeforeClass;
import org.junit.Rule;
import org.junit.Test;
import org.junit.rules.ExpectedException;
public class AvailableEncodersTest
{
@ -48,28 +51,24 @@ public class AvailableEncodersTest
{
testConfig = new EmptyClientEndpointConfig();
}
private AvailableEncoders encoders = new AvailableEncoders();
@Rule
public ExpectedException expectedException = ExpectedException.none();
private AvailableEncoders encoders = new AvailableEncoders(testConfig);
public <T> void assertTextEncoder(Class<T> type, T value, String expectedEncoded) throws IllegalAccessException, InstantiationException, EncodeException
{
Class<? extends Encoder> encoderClass = encoders.getEncoderFor(type);
assertThat("Encoder Class", encoderClass, notNullValue());
Encoder.Text<T> encoder = (Encoder.Text<T>) encoderClass.newInstance();
encoder.init(testConfig);
Encoder.Text<T> encoder = (Encoder.Text<T>) encoders.getInstanceFor(type);
assertThat("Encoder", encoder, notNullValue());
String encoded = encoder.encode(value);
assertThat("Encoded", encoded, is(expectedEncoded));
}
public <T> void assertTextStreamEncoder(Class<T> type, T value, String expectedEncoded) throws IllegalAccessException, InstantiationException, EncodeException, IOException
{
Class<? extends Encoder> encoderClass = encoders.getEncoderFor(type);
assertThat("Encoder Class", encoderClass, notNullValue());
Encoder.TextStream<T> encoder = (Encoder.TextStream<T>) encoderClass.newInstance();
encoder.init(testConfig);
Encoder.TextStream<T> encoder = (Encoder.TextStream<T>) encoders.getInstanceFor(type);
assertThat("Encoder", encoder, notNullValue());
StringWriter writer = new StringWriter();
encoder.encode(value, writer);
@ -78,12 +77,8 @@ public class AvailableEncodersTest
public <T> void assertBinaryEncoder(Class<T> type, T value, String expectedEncodedHex) throws IllegalAccessException, InstantiationException, EncodeException
{
AvailableEncoders encoders = new AvailableEncoders();
Class<? extends Encoder> encoderClass = encoders.getEncoderFor(type);
assertThat("Encoder Class", encoderClass, notNullValue());
Encoder.Binary<T> encoder = (Encoder.Binary<T>) encoderClass.newInstance();
encoder.init(testConfig);
Encoder.Binary<T> encoder = (Encoder.Binary<T>) encoders.getInstanceFor(type);
assertThat("Encoder", encoder, notNullValue());
ByteBuffer encoded = encoder.encode(value);
String hexEncoded = Hex.asHex(encoded);
@ -92,11 +87,8 @@ public class AvailableEncodersTest
public <T> void assertBinaryStreamEncoder(Class<T> type, T value, String expectedEncodedHex) throws IllegalAccessException, InstantiationException, EncodeException, IOException
{
Class<? extends Encoder> encoderClass = encoders.getEncoderFor(type);
assertThat("Encoder Class", encoderClass, notNullValue());
Encoder.BinaryStream<T> encoder = (Encoder.BinaryStream<T>) encoderClass.newInstance();
encoder.init(testConfig);
Encoder.BinaryStream<T> encoder = (Encoder.BinaryStream<T>) encoders.getInstanceFor(type);
assertThat("Encoder", encoder, notNullValue());
ByteArrayOutputStream out = new ByteArrayOutputStream();
encoder.encode(value, out);
@ -210,6 +202,15 @@ public class AvailableEncodersTest
byte buf[] = Hex.asByteArray("998877665544332211");
assertBinaryEncoder(byte[].class, buf, "998877665544332211");
}
@Test
public void testCustomEncoder_Integer() throws IllegalAccessException, InstantiationException, EncodeException
{
encoders.register(IntegerEncoder.class);
int val = 99887766;
String expected = "99887766";
assertTextEncoder(Integer.class, val, expected);
}
@Test
public void testCustomEncoder_Time() throws IllegalAccessException, InstantiationException, EncodeException, IOException
@ -274,4 +275,25 @@ public class AvailableEncodersTest
long value = 0x112233445566L;
assertBinaryStreamEncoder(Long.class, value, "5B00001122334455665D");
}
@Test
public void testCustomEncoder_Register_Duplicate()
{
// has duplicated support for the same target Type
expectedException.expect(IllegalStateException.class);
expectedException.expectMessage(containsString("Duplicate"));
encoders.register(BadDualEncoder.class);
}
@Test
public void testCustomEncoder_Register_OtherDuplicate()
{
// Register DateEncoder (decodes java.util.Date)
encoders.register(DateEncoder.class);
// Register TimeEncoder (which also wants to decode java.util.Date)
expectedException.expect(IllegalStateException.class);
expectedException.expectMessage(containsString("Duplicate"));
encoders.register(TimeEncoder.class);
}
}

View File

@ -51,14 +51,22 @@ public class JsrEndpointFunctions_BadSignaturesTest
{
container = new ClientContainer();
}
private AvailableEncoders encoders = new AvailableEncoders();
private AvailableDecoders decoders = new AvailableDecoders();
private Map<String, String> uriParams = new HashMap<>();
private EndpointConfig endpointConfig = new EmptyClientEndpointConfig();
@Rule
public ExpectedException expectedException = ExpectedException.none();
private AvailableEncoders encoders;
private AvailableDecoders decoders;
private Map<String, String> uriParams = new HashMap<>();
private EndpointConfig endpointConfig;
public JsrEndpointFunctions_BadSignaturesTest()
{
endpointConfig = new EmptyClientEndpointConfig();
encoders = new AvailableEncoders(endpointConfig);
decoders = new AvailableDecoders(endpointConfig);
uriParams = new HashMap<>();
}
private void assertBadSocket(TrackingSocket socket, String expectedString) throws Exception
{

View File

@ -53,11 +53,19 @@ public class JsrEndpointFunctions_OnCloseTest
{
container = new ClientContainer();
}
private AvailableEncoders encoders = new AvailableEncoders();
private AvailableDecoders decoders = new AvailableDecoders();
private Map<String,String> uriParams = new HashMap<>();
private EndpointConfig endpointConfig = new EmptyClientEndpointConfig();
private AvailableEncoders encoders;
private AvailableDecoders decoders;
private Map<String, String> uriParams = new HashMap<>();
private EndpointConfig endpointConfig;
public JsrEndpointFunctions_OnCloseTest()
{
endpointConfig = new EmptyClientEndpointConfig();
encoders = new AvailableEncoders(endpointConfig);
decoders = new AvailableDecoders(endpointConfig);
uriParams = new HashMap<>();
}
public JsrSession newSession(Object websocket)
{

View File

@ -50,11 +50,19 @@ public class JsrEndpointFunctions_OnErrorTest
{
container = new ClientContainer();
}
private AvailableEncoders encoders = new AvailableEncoders();
private AvailableDecoders decoders = new AvailableDecoders();
private AvailableEncoders encoders;
private AvailableDecoders decoders;
private Map<String, String> uriParams = new HashMap<>();
private EndpointConfig endpointConfig = new EmptyClientEndpointConfig();
private EndpointConfig endpointConfig;
public JsrEndpointFunctions_OnErrorTest()
{
endpointConfig = new EmptyClientEndpointConfig();
encoders = new AvailableEncoders(endpointConfig);
decoders = new AvailableDecoders(endpointConfig);
uriParams = new HashMap<>();
}
public JsrSession newSession(Object websocket)
{

View File

@ -21,24 +21,18 @@ package org.eclipse.jetty.websocket.jsr356.function;
import static org.hamcrest.CoreMatchers.is;
import static org.junit.Assert.assertThat;
import java.net.URI;
import java.nio.ByteBuffer;
import java.nio.charset.StandardCharsets;
import java.util.HashMap;
import java.util.Map;
import javax.websocket.ClientEndpoint;
import javax.websocket.ClientEndpointConfig;
import javax.websocket.EndpointConfig;
import javax.websocket.OnMessage;
import javax.websocket.Session;
import org.eclipse.jetty.util.BufferUtil;
import org.eclipse.jetty.websocket.api.WebSocketPolicy;
import org.eclipse.jetty.websocket.common.test.DummyConnection;
import org.eclipse.jetty.websocket.jsr356.ClientContainer;
import org.eclipse.jetty.websocket.jsr356.ConfiguredEndpoint;
import org.eclipse.jetty.websocket.jsr356.JsrSession;
import org.eclipse.jetty.websocket.jsr356.client.EmptyClientEndpointConfig;
import org.eclipse.jetty.websocket.jsr356.decoders.AvailableDecoders;
import org.eclipse.jetty.websocket.jsr356.encoders.AvailableEncoders;
@ -56,22 +50,18 @@ public class JsrEndpointFunctions_OnMessage_BinaryTest
container = new ClientContainer();
}
private AvailableEncoders encoders = new AvailableEncoders();
private AvailableDecoders decoders = new AvailableDecoders();
private Map<String, String> uriParams = new HashMap<>();
private EndpointConfig endpointConfig = new EmptyClientEndpointConfig();
private String expectedBuffer;
private AvailableEncoders encoders;
private AvailableDecoders decoders;
private Map<String, String> uriParams = new HashMap<>();
private EndpointConfig endpointConfig;
public JsrSession newSession(Object websocket)
public JsrEndpointFunctions_OnMessage_BinaryTest()
{
String id = JsrEndpointFunctions_OnMessage_BinaryTest.class.getSimpleName();
URI requestURI = URI.create("ws://localhost/" + id);
WebSocketPolicy policy = WebSocketPolicy.newClientPolicy();
DummyConnection connection = new DummyConnection(policy);
ClientEndpointConfig config = new EmptyClientEndpointConfig();
ConfiguredEndpoint ei = new ConfiguredEndpoint(websocket, config);
return new JsrSession(container, id, requestURI, ei, connection);
endpointConfig = new EmptyClientEndpointConfig();
encoders = new AvailableEncoders(endpointConfig);
decoders = new AvailableDecoders(endpointConfig);
uriParams = new HashMap<>();
}
private void assertOnMessageInvocation(TrackingSocket socket, String expectedEventFormat, Object... args) throws Exception

View File

@ -21,24 +21,18 @@ package org.eclipse.jetty.websocket.jsr356.function;
import static org.hamcrest.Matchers.containsString;
import java.lang.reflect.InvocationTargetException;
import java.net.URI;
import java.nio.ByteBuffer;
import java.nio.charset.StandardCharsets;
import java.util.HashMap;
import java.util.Map;
import javax.websocket.ClientEndpointConfig;
import javax.websocket.EndpointConfig;
import javax.websocket.OnMessage;
import javax.websocket.Session;
import org.eclipse.jetty.util.BufferUtil;
import org.eclipse.jetty.websocket.api.WebSocketPolicy;
import org.eclipse.jetty.websocket.common.InvalidSignatureException;
import org.eclipse.jetty.websocket.common.test.DummyConnection;
import org.eclipse.jetty.websocket.jsr356.ClientContainer;
import org.eclipse.jetty.websocket.jsr356.ConfiguredEndpoint;
import org.eclipse.jetty.websocket.jsr356.JsrSession;
import org.eclipse.jetty.websocket.jsr356.client.EmptyClientEndpointConfig;
import org.eclipse.jetty.websocket.jsr356.decoders.AvailableDecoders;
import org.eclipse.jetty.websocket.jsr356.encoders.AvailableEncoders;
@ -57,24 +51,21 @@ public class JsrEndpointFunctions_OnMessage_TextTest
{
container = new ClientContainer();
}
private AvailableEncoders encoders = new AvailableEncoders();
private AvailableDecoders decoders = new AvailableDecoders();
private Map<String, String> uriParams = new HashMap<>();
private EndpointConfig endpointConfig = new EmptyClientEndpointConfig();
@Rule
public ExpectedException expectedException = ExpectedException.none();
public JsrSession newSession(Object websocket)
private AvailableEncoders encoders;
private AvailableDecoders decoders;
private Map<String, String> uriParams = new HashMap<>();
private EndpointConfig endpointConfig;
public JsrEndpointFunctions_OnMessage_TextTest()
{
String id = JsrEndpointFunctions_OnMessage_TextTest.class.getSimpleName();
URI requestURI = URI.create("ws://localhost/" + id);
WebSocketPolicy policy = WebSocketPolicy.newClientPolicy();
DummyConnection connection = new DummyConnection(policy);
ClientEndpointConfig config = new EmptyClientEndpointConfig();
ConfiguredEndpoint ei = new ConfiguredEndpoint(websocket, config);
return new JsrSession(container, id, requestURI, ei, connection);
endpointConfig = new EmptyClientEndpointConfig();
encoders = new AvailableEncoders(endpointConfig);
decoders = new AvailableDecoders(endpointConfig);
uriParams = new HashMap<>();
}
private void onText(TrackingSocket socket, String msg)

View File

@ -49,11 +49,19 @@ public class JsrEndpointFunctions_OnOpenTest
{
container = new ClientContainer();
}
private AvailableEncoders encoders = new AvailableEncoders();
private AvailableDecoders decoders = new AvailableDecoders();
private Map<String,String> uriParams = new HashMap<>();
private EndpointConfig endpointConfig = new EmptyClientEndpointConfig();
private AvailableEncoders encoders;
private AvailableDecoders decoders;
private Map<String, String> uriParams = new HashMap<>();
private EndpointConfig endpointConfig;
public JsrEndpointFunctions_OnOpenTest()
{
endpointConfig = new EmptyClientEndpointConfig();
encoders = new AvailableEncoders(endpointConfig);
decoders = new AvailableDecoders(endpointConfig);
uriParams = new HashMap<>();
}
public JsrSession newSession(Object websocket)
{

View File

@ -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);
}
}

View File

@ -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);
}
}

View File

@ -479,16 +479,51 @@ public class CommonEndpointFunctions<T extends Session> extends AbstractLifeCycl
throw new InvalidSignatureException(err.toString());
}
protected void clearOnPongFunction()
{
}
protected void clearOnTextSink()
{
}
protected void clearOnBinarySink()
{
}
public BatchMode getBatchMode()
{
return batchMode;
}
public Executor getExecutor()
{
return executor;
}
public T getSession()
{
return session;
}
protected MessageSink getOnTextSink()
{
return onTextSink;
}
protected MessageSink getOnBinarySink()
{
return onBinarySink;
}
protected Function<ByteBuffer, Void> getOnPongFunction()
{
return onPongFunction;
}
public void setOnOpen(Function<T, Void> function, Object origin)
{
assertNotSet(this.onOpenFunction, "Open Handler", origin);