Issue #207 - Support javax.websocket version 1.1
This commit is contained in:
parent
795246c785
commit
fc9adbb391
|
@ -23,6 +23,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;
|
||||
|
||||
|
@ -74,6 +75,7 @@ public class AvailableDecoders implements Predicate<Class<?>>
|
|||
|
||||
public AvailableDecoders(EndpointConfig config)
|
||||
{
|
||||
Objects.requireNonNull(config);
|
||||
this.config = config;
|
||||
registeredDecoders = new LinkedList<>();
|
||||
|
||||
|
@ -103,6 +105,9 @@ public class AvailableDecoders implements Predicate<Class<?>>
|
|||
// STREAMING based
|
||||
registerPrimitive(ReaderDecoder.class, Decoder.TextStream.class, Reader.class);
|
||||
registerPrimitive(InputStreamDecoder.class, Decoder.BinaryStream.class, InputStreamDecoder.class);
|
||||
|
||||
// Config Based
|
||||
registerAll(config.getDecoders());
|
||||
}
|
||||
|
||||
private void registerPrimitive(Class<? extends Decoder> decoderClass, Class<? extends Decoder> interfaceType, Class<?> type)
|
||||
|
@ -189,6 +194,12 @@ public class AvailableDecoders implements Predicate<Class<?>>
|
|||
.findFirst()
|
||||
.get();
|
||||
|
||||
if (conflicts.decoder.equals(decoder) && conflicts.implementsInterface(interfaceClass))
|
||||
{
|
||||
// Same decoder as what is there already, don't bother adding it again.
|
||||
return;
|
||||
}
|
||||
|
||||
StringBuilder err = new StringBuilder();
|
||||
err.append("Duplicate Decoder Object type ");
|
||||
err.append(objectType.getName());
|
||||
|
|
|
@ -41,13 +41,20 @@ public class AvailableEncoders implements Predicate<Class<?>>
|
|||
public final Class<? extends Encoder> encoder;
|
||||
public final Class<? extends Encoder> interfaceType;
|
||||
public final Class<?> objectType;
|
||||
public final boolean primitive;
|
||||
public Encoder instance;
|
||||
|
||||
public RegisteredEncoder(Class<? extends Encoder> encoder, Class<? extends Encoder> interfaceType, Class<?> objectType)
|
||||
{
|
||||
this(encoder, interfaceType, objectType, false);
|
||||
}
|
||||
|
||||
public RegisteredEncoder(Class<? extends Encoder> encoder, Class<? extends Encoder> interfaceType, Class<?> objectType, boolean primitive)
|
||||
{
|
||||
this.encoder = encoder;
|
||||
this.interfaceType = interfaceType;
|
||||
this.objectType = objectType;
|
||||
this.primitive = primitive;
|
||||
}
|
||||
|
||||
public boolean implementsInterface(Class<? extends Encoder> type)
|
||||
|
@ -71,27 +78,27 @@ public class AvailableEncoders implements Predicate<Class<?>>
|
|||
registeredEncoders = new LinkedList<>();
|
||||
|
||||
// TEXT based [via Class reference]
|
||||
register(BooleanEncoder.class, Encoder.Text.class, Boolean.class);
|
||||
register(ByteEncoder.class, Encoder.Text.class, Byte.class);
|
||||
register(CharacterEncoder.class, Encoder.Text.class, Character.class);
|
||||
register(DoubleEncoder.class, Encoder.Text.class, Double.class);
|
||||
register(FloatEncoder.class, Encoder.Text.class, Float.class);
|
||||
register(IntegerEncoder.class, Encoder.Text.class, Integer.class);
|
||||
register(LongEncoder.class, Encoder.Text.class, Long.class);
|
||||
register(StringEncoder.class, Encoder.Text.class, String.class);
|
||||
registerPrimitive(BooleanEncoder.class, Encoder.Text.class, Boolean.class);
|
||||
registerPrimitive(ByteEncoder.class, Encoder.Text.class, Byte.class);
|
||||
registerPrimitive(CharacterEncoder.class, Encoder.Text.class, Character.class);
|
||||
registerPrimitive(DoubleEncoder.class, Encoder.Text.class, Double.class);
|
||||
registerPrimitive(FloatEncoder.class, Encoder.Text.class, Float.class);
|
||||
registerPrimitive(IntegerEncoder.class, Encoder.Text.class, Integer.class);
|
||||
registerPrimitive(LongEncoder.class, Encoder.Text.class, Long.class);
|
||||
registerPrimitive(StringEncoder.class, Encoder.Text.class, String.class);
|
||||
|
||||
// TEXT based [via Primitive reference]
|
||||
register(BooleanEncoder.class, Encoder.Text.class, Boolean.TYPE);
|
||||
register(ByteEncoder.class, Encoder.Text.class, Byte.TYPE);
|
||||
register(CharacterEncoder.class, Encoder.Text.class, Character.TYPE);
|
||||
register(DoubleEncoder.class, Encoder.Text.class, Double.TYPE);
|
||||
register(FloatEncoder.class, Encoder.Text.class, Float.TYPE);
|
||||
register(IntegerEncoder.class, Encoder.Text.class, Integer.TYPE);
|
||||
register(LongEncoder.class, Encoder.Text.class, Long.TYPE);
|
||||
registerPrimitive(BooleanEncoder.class, Encoder.Text.class, Boolean.TYPE);
|
||||
registerPrimitive(ByteEncoder.class, Encoder.Text.class, Byte.TYPE);
|
||||
registerPrimitive(CharacterEncoder.class, Encoder.Text.class, Character.TYPE);
|
||||
registerPrimitive(DoubleEncoder.class, Encoder.Text.class, Double.TYPE);
|
||||
registerPrimitive(FloatEncoder.class, Encoder.Text.class, Float.TYPE);
|
||||
registerPrimitive(IntegerEncoder.class, Encoder.Text.class, Integer.TYPE);
|
||||
registerPrimitive(LongEncoder.class, Encoder.Text.class, Long.TYPE);
|
||||
|
||||
// BINARY based
|
||||
register(ByteBufferEncoder.class, Encoder.Binary.class, ByteBuffer.class);
|
||||
register(ByteArrayEncoder.class, Encoder.Binary.class, byte[].class);
|
||||
registerPrimitive(ByteBufferEncoder.class, Encoder.Binary.class, ByteBuffer.class);
|
||||
registerPrimitive(ByteArrayEncoder.class, Encoder.Binary.class, byte[].class);
|
||||
|
||||
// STREAMING based
|
||||
// Note: Streams (Writer / OutputStream) are not present here
|
||||
|
@ -99,11 +106,14 @@ public class AvailableEncoders implements Predicate<Class<?>>
|
|||
// encoder to write an object to a Stream
|
||||
// register(WriterEncoder.class, Encoder.TextStream.class, Writer.class);
|
||||
// register(OutputStreamEncoder.class, Encoder.BinaryStream.class, OutputStream.class);
|
||||
|
||||
// Config Based
|
||||
registerAll(config.getEncoders());
|
||||
}
|
||||
|
||||
private void register(Class<? extends Encoder> encoderClass, Class<? extends Encoder> interfaceType, Class<?> type)
|
||||
private void registerPrimitive(Class<? extends Encoder> encoderClass, Class<? extends Encoder> interfaceType, Class<?> type)
|
||||
{
|
||||
registeredEncoders.add(new RegisteredEncoder(encoderClass, interfaceType, type));
|
||||
registeredEncoders.add(new RegisteredEncoder(encoderClass, interfaceType, type, true));
|
||||
}
|
||||
|
||||
public void register(Class<? extends Encoder> encoder)
|
||||
|
@ -177,7 +187,33 @@ public class AvailableEncoders implements Predicate<Class<?>>
|
|||
throw new InvalidWebSocketException(err.toString());
|
||||
}
|
||||
|
||||
registeredEncoders.add(new RegisteredEncoder(encoder, interfaceClass, objectType));
|
||||
try
|
||||
{
|
||||
RegisteredEncoder conflicts = registeredEncoders.stream()
|
||||
.filter(registered -> registered.isType(objectType))
|
||||
.filter(registered -> !registered.primitive)
|
||||
.findFirst()
|
||||
.get();
|
||||
|
||||
if (conflicts.encoder.equals(encoder) && conflicts.implementsInterface(interfaceClass))
|
||||
{
|
||||
// Same encoder as what is there already, don't bother adding it again.
|
||||
return;
|
||||
}
|
||||
|
||||
StringBuilder err = new StringBuilder();
|
||||
err.append("Duplicate Encoder Object type ");
|
||||
err.append(objectType.getName());
|
||||
err.append(" in ");
|
||||
err.append(encoder.getName());
|
||||
err.append(", previously declared in ");
|
||||
err.append(conflicts.encoder.getName());
|
||||
throw new InvalidWebSocketException(err.toString());
|
||||
}
|
||||
catch (NoSuchElementException e)
|
||||
{
|
||||
registeredEncoders.addFirst(new RegisteredEncoder(encoder, interfaceClass, objectType));
|
||||
}
|
||||
}
|
||||
|
||||
public List<RegisteredEncoder> supporting(Class<? extends Encoder> interfaceType)
|
||||
|
|
|
@ -115,6 +115,12 @@ public class JsrEndpointFunctions extends CommonEndpointFunctions<JsrSession>
|
|||
{
|
||||
this.delegateSink.accept(payload, fin);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString()
|
||||
{
|
||||
return String.format("MessageSink[%s]",messageHandler.getClass().getName());
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -277,7 +283,7 @@ public class JsrEndpointFunctions extends CommonEndpointFunctions<JsrSession>
|
|||
try
|
||||
{
|
||||
// Is this a PongMessage?
|
||||
if (PongMessage.class.isAssignableFrom(PongMessage.class))
|
||||
if (PongMessage.class.isAssignableFrom(clazz))
|
||||
{
|
||||
Function<ByteBuffer, Void> pongFunction = (payload) ->
|
||||
{
|
||||
|
|
|
@ -254,10 +254,10 @@ public class EncoderTest
|
|||
@Test
|
||||
public void testSingleQuotes() throws Exception
|
||||
{
|
||||
EchoServer eserver = new EchoServer(server);
|
||||
EchoServer echoServer = new EchoServer(server);
|
||||
try
|
||||
{
|
||||
eserver.start();
|
||||
echoServer.start();
|
||||
|
||||
QuotesSocket quoter = new QuotesSocket();
|
||||
|
||||
|
@ -278,17 +278,17 @@ public class EncoderTest
|
|||
}
|
||||
finally
|
||||
{
|
||||
eserver.stop();
|
||||
echoServer.stop();
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testTwoQuotes() throws Exception
|
||||
{
|
||||
EchoServer eserver = new EchoServer(server);
|
||||
EchoServer echoServer = new EchoServer(server);
|
||||
try
|
||||
{
|
||||
eserver.start();
|
||||
echoServer.start();
|
||||
|
||||
QuotesSocket quoter = new QuotesSocket();
|
||||
ClientEndpointConfig.Builder builder = ClientEndpointConfig.Builder.create();
|
||||
|
@ -312,7 +312,7 @@ public class EncoderTest
|
|||
}
|
||||
finally
|
||||
{
|
||||
eserver.stop();
|
||||
echoServer.stop();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -25,31 +25,53 @@ import javax.websocket.DeploymentException;
|
|||
import javax.websocket.MessageHandler;
|
||||
|
||||
import org.eclipse.jetty.websocket.api.WebSocketPolicy;
|
||||
import org.eclipse.jetty.websocket.common.test.DummyConnection;
|
||||
import org.eclipse.jetty.websocket.common.io.LocalWebSocketConnection;
|
||||
import org.eclipse.jetty.websocket.common.scopes.SimpleContainerScope;
|
||||
import org.eclipse.jetty.websocket.common.test.LeakTrackingBufferPoolRule;
|
||||
import org.eclipse.jetty.websocket.jsr356.client.EmptyClientEndpointConfig;
|
||||
import org.eclipse.jetty.websocket.jsr356.handlers.ByteArrayWholeHandler;
|
||||
import org.eclipse.jetty.websocket.jsr356.handlers.ByteBufferPartialHandler;
|
||||
import org.eclipse.jetty.websocket.jsr356.handlers.LongMessageHandler;
|
||||
import org.eclipse.jetty.websocket.jsr356.handlers.StringWholeHandler;
|
||||
import org.eclipse.jetty.websocket.jsr356.samples.DummyEndpoint;
|
||||
import org.junit.After;
|
||||
import org.junit.Before;
|
||||
import org.junit.Rule;
|
||||
import org.junit.Test;
|
||||
|
||||
public class JsrSessionTest
|
||||
{
|
||||
@Rule
|
||||
public LeakTrackingBufferPoolRule bufferPool = new LeakTrackingBufferPoolRule("Test");
|
||||
|
||||
private ClientContainer container;
|
||||
private JsrSession session;
|
||||
|
||||
@Before
|
||||
public void initSession()
|
||||
public void initSession() throws Exception
|
||||
{
|
||||
String id = JsrSessionTest.class.getSimpleName();
|
||||
URI requestURI = URI.create("ws://localhost/" + id);
|
||||
|
||||
WebSocketPolicy policy = WebSocketPolicy.newClientPolicy();
|
||||
DummyConnection connection = new DummyConnection(policy);
|
||||
|
||||
// Container
|
||||
container = new ClientContainer(new SimpleContainerScope(policy,bufferPool));
|
||||
container.start();
|
||||
LocalWebSocketConnection connection = new LocalWebSocketConnection(bufferPool);
|
||||
ClientEndpointConfig config = new EmptyClientEndpointConfig();
|
||||
ConfiguredEndpoint ei = new ConfiguredEndpoint(new DummyEndpoint(), config);
|
||||
|
||||
// Session
|
||||
session = new JsrSession(container, id, requestURI, ei, connection);
|
||||
session.start();
|
||||
}
|
||||
|
||||
@After
|
||||
public void stopSession() throws Exception
|
||||
{
|
||||
session.stop();
|
||||
container.stop();
|
||||
}
|
||||
|
||||
@Test
|
||||
|
@ -68,10 +90,10 @@ public class JsrSessionTest
|
|||
@Test
|
||||
public void testMessageHandlerReplaceTextHandler() throws DeploymentException
|
||||
{
|
||||
MessageHandler oldText = new StringWholeHandler();
|
||||
session.addMessageHandler(oldText); // add a TEXT handler
|
||||
MessageHandler strHandler = new StringWholeHandler();
|
||||
session.addMessageHandler(strHandler); // add a TEXT handler
|
||||
session.addMessageHandler(new ByteArrayWholeHandler()); // add BINARY handler
|
||||
session.removeMessageHandler(oldText); // remove original TEXT handler
|
||||
session.removeMessageHandler(strHandler); // remove original TEXT handler
|
||||
session.addMessageHandler(new LongMessageHandler()); // add new TEXT handler
|
||||
}
|
||||
|
||||
|
|
|
@ -35,6 +35,7 @@ import javax.websocket.EncodeException;
|
|||
import javax.websocket.Encoder;
|
||||
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;
|
||||
|
@ -45,7 +46,7 @@ import org.junit.rules.ExpectedException;
|
|||
public class AvailableEncodersTest
|
||||
{
|
||||
private static EndpointConfig testConfig;
|
||||
|
||||
|
||||
@BeforeClass
|
||||
public static void initConfig()
|
||||
{
|
||||
|
@ -56,7 +57,7 @@ public class AvailableEncodersTest
|
|||
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
|
||||
{
|
||||
Encoder.Text<T> encoder = (Encoder.Text<T>) encoders.getInstanceFor(type);
|
||||
|
@ -64,138 +65,138 @@ public class AvailableEncodersTest
|
|||
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
|
||||
{
|
||||
Encoder.TextStream<T> encoder = (Encoder.TextStream<T>) encoders.getInstanceFor(type);
|
||||
assertThat("Encoder", encoder, notNullValue());
|
||||
StringWriter writer = new StringWriter();
|
||||
encoder.encode(value, writer);
|
||||
|
||||
|
||||
assertThat("Encoded", writer.toString(), is(expectedEncoded));
|
||||
}
|
||||
|
||||
|
||||
public <T> void assertBinaryEncoder(Class<T> type, T value, String expectedEncodedHex) throws IllegalAccessException, InstantiationException, EncodeException
|
||||
{
|
||||
Encoder.Binary<T> encoder = (Encoder.Binary<T>) encoders.getInstanceFor(type);
|
||||
assertThat("Encoder", encoder, notNullValue());
|
||||
ByteBuffer encoded = encoder.encode(value);
|
||||
|
||||
|
||||
String hexEncoded = Hex.asHex(encoded);
|
||||
assertThat("Encoded", hexEncoded, is(expectedEncodedHex));
|
||||
}
|
||||
|
||||
|
||||
public <T> void assertBinaryStreamEncoder(Class<T> type, T value, String expectedEncodedHex) throws IllegalAccessException, InstantiationException, EncodeException, IOException
|
||||
{
|
||||
Encoder.BinaryStream<T> encoder = (Encoder.BinaryStream<T>) encoders.getInstanceFor(type);
|
||||
assertThat("Encoder", encoder, notNullValue());
|
||||
ByteArrayOutputStream out = new ByteArrayOutputStream();
|
||||
encoder.encode(value, out);
|
||||
|
||||
|
||||
String hexEncoded = Hex.asHex(out.toByteArray());
|
||||
|
||||
|
||||
assertThat("Encoded", hexEncoded, is(expectedEncodedHex));
|
||||
}
|
||||
|
||||
|
||||
@Test
|
||||
public void testCoreEncoder_Boolean() throws IllegalAccessException, InstantiationException, EncodeException
|
||||
{
|
||||
assertTextEncoder(Boolean.class, Boolean.TRUE, "true");
|
||||
}
|
||||
|
||||
|
||||
@Test
|
||||
public void testCoreEncoder_bool() throws IllegalAccessException, InstantiationException, EncodeException
|
||||
{
|
||||
assertTextEncoder(Boolean.TYPE, true, "true");
|
||||
}
|
||||
|
||||
|
||||
@Test
|
||||
public void testCoreEncoder_Byte() throws IllegalAccessException, InstantiationException, EncodeException
|
||||
{
|
||||
assertTextEncoder(Byte.class, new Byte((byte) 0x21), "33");
|
||||
}
|
||||
|
||||
|
||||
@Test
|
||||
public void testCoreEncoder_byte() throws IllegalAccessException, InstantiationException, EncodeException
|
||||
{
|
||||
assertTextEncoder(Byte.TYPE, (byte) 0x21, "33");
|
||||
}
|
||||
|
||||
|
||||
@Test
|
||||
public void testCoreEncoder_Character() throws IllegalAccessException, InstantiationException, EncodeException
|
||||
{
|
||||
assertTextEncoder(Character.class, new Character('!'), "!");
|
||||
}
|
||||
|
||||
|
||||
@Test
|
||||
public void testCoreEncoder_char() throws IllegalAccessException, InstantiationException, EncodeException
|
||||
{
|
||||
assertTextEncoder(Character.TYPE, '!', "!");
|
||||
}
|
||||
|
||||
|
||||
@Test
|
||||
public void testCoreEncoder_Double() throws IllegalAccessException, InstantiationException, EncodeException
|
||||
{
|
||||
assertTextEncoder(Double.class, new Double(123.45), "123.45");
|
||||
}
|
||||
|
||||
|
||||
@Test
|
||||
public void testCoreEncoder_double() throws IllegalAccessException, InstantiationException, EncodeException
|
||||
{
|
||||
//noinspection RedundantCast
|
||||
assertTextEncoder(Double.TYPE, (double) 123.45, "123.45");
|
||||
}
|
||||
|
||||
|
||||
@Test
|
||||
public void testCoreEncoder_Float() throws IllegalAccessException, InstantiationException, EncodeException
|
||||
{
|
||||
assertTextEncoder(Float.class, new Float(123.4567), "123.4567");
|
||||
}
|
||||
|
||||
|
||||
@Test
|
||||
public void testCoreEncoder_float() throws IllegalAccessException, InstantiationException, EncodeException
|
||||
{
|
||||
//noinspection RedundantCast
|
||||
assertTextEncoder(Float.TYPE, (float) 123.4567, "123.4567");
|
||||
}
|
||||
|
||||
|
||||
@Test
|
||||
public void testCoreEncoder_Integer() throws IllegalAccessException, InstantiationException, EncodeException
|
||||
{
|
||||
assertTextEncoder(Integer.class, new Integer(123), "123");
|
||||
}
|
||||
|
||||
|
||||
@Test
|
||||
public void testCoreEncoder_int() throws IllegalAccessException, InstantiationException, EncodeException
|
||||
{
|
||||
assertTextEncoder(Integer.TYPE, 123, "123");
|
||||
}
|
||||
|
||||
|
||||
@Test
|
||||
public void testCoreEncoder_Long() throws IllegalAccessException, InstantiationException, EncodeException
|
||||
{
|
||||
assertTextEncoder(Long.class, new Long(123_456_789), "123456789");
|
||||
}
|
||||
|
||||
|
||||
@Test
|
||||
public void testCoreEncoder_long() throws IllegalAccessException, InstantiationException, EncodeException
|
||||
{
|
||||
assertTextEncoder(Long.TYPE, 123_456_789L, "123456789");
|
||||
}
|
||||
|
||||
|
||||
@Test
|
||||
public void testCoreEncoder_String() throws IllegalAccessException, InstantiationException, EncodeException
|
||||
{
|
||||
assertTextEncoder(String.class, "Hello World", "Hello World");
|
||||
}
|
||||
|
||||
|
||||
@Test
|
||||
public void testCoreEncoder_ByteBuffer() throws IllegalAccessException, InstantiationException, EncodeException
|
||||
{
|
||||
ByteBuffer buf = Hex.asByteBuffer("1122334455");
|
||||
assertBinaryEncoder(ByteBuffer.class, buf, "1122334455");
|
||||
}
|
||||
|
||||
|
||||
@Test
|
||||
public void testCoreEncoder_ByteArray() throws IllegalAccessException, InstantiationException, EncodeException
|
||||
{
|
||||
|
@ -211,63 +212,63 @@ public class AvailableEncodersTest
|
|||
String expected = "99887766";
|
||||
assertTextEncoder(Integer.class, val, expected);
|
||||
}
|
||||
|
||||
|
||||
@Test
|
||||
public void testCustomEncoder_Time() throws IllegalAccessException, InstantiationException, EncodeException, IOException
|
||||
{
|
||||
encoders.register(TimeEncoder.class);
|
||||
|
||||
|
||||
Calendar calendar = Calendar.getInstance(TimeZone.getTimeZone("GMT"));
|
||||
|
||||
|
||||
calendar.set(Calendar.HOUR_OF_DAY, 12);
|
||||
calendar.set(Calendar.MINUTE, 34);
|
||||
calendar.set(Calendar.SECOND, 56);
|
||||
|
||||
|
||||
Date val = calendar.getTime();
|
||||
assertTextEncoder(Date.class, val, "12:34:56 GMT");
|
||||
}
|
||||
|
||||
|
||||
@Test
|
||||
public void testCustomEncoder_Date() throws IllegalAccessException, InstantiationException, EncodeException, IOException
|
||||
{
|
||||
encoders.register(DateEncoder.class);
|
||||
|
||||
|
||||
Calendar calendar = Calendar.getInstance(TimeZone.getTimeZone("GMT"));
|
||||
|
||||
|
||||
calendar.set(Calendar.YEAR, 2016);
|
||||
calendar.set(Calendar.MONTH, Calendar.AUGUST);
|
||||
calendar.set(Calendar.DAY_OF_MONTH, 22);
|
||||
|
||||
|
||||
Date val = calendar.getTime();
|
||||
assertTextEncoder(Date.class, val, "2016.08.22");
|
||||
}
|
||||
|
||||
|
||||
@Test
|
||||
public void testCustomEncoder_DateTime() throws IllegalAccessException, InstantiationException, EncodeException, IOException
|
||||
{
|
||||
encoders.register(DateTimeEncoder.class);
|
||||
|
||||
|
||||
Calendar calendar = Calendar.getInstance(TimeZone.getTimeZone("GMT"));
|
||||
|
||||
|
||||
calendar.set(Calendar.YEAR, 2016);
|
||||
calendar.set(Calendar.MONTH, Calendar.AUGUST);
|
||||
calendar.set(Calendar.DAY_OF_MONTH, 22);
|
||||
|
||||
|
||||
calendar.set(Calendar.HOUR_OF_DAY, 12);
|
||||
calendar.set(Calendar.MINUTE, 34);
|
||||
calendar.set(Calendar.SECOND, 56);
|
||||
|
||||
|
||||
Date val = calendar.getTime();
|
||||
assertTextEncoder(Date.class, val, "2016.08.22 AD at 12:34:56 GMT");
|
||||
}
|
||||
|
||||
|
||||
@Test
|
||||
public void testCustomEncoder_ValidDual_Text() throws IllegalAccessException, InstantiationException, EncodeException, IOException
|
||||
{
|
||||
encoders.register(ValidDualEncoder.class);
|
||||
assertTextEncoder(Integer.class, 1234567, "[1,234,567]");
|
||||
}
|
||||
|
||||
|
||||
@Test
|
||||
public void testCustomEncoder_ValidDual_Binary() throws IllegalAccessException, InstantiationException, EncodeException, IOException
|
||||
{
|
||||
|
@ -280,7 +281,7 @@ public class AvailableEncodersTest
|
|||
public void testCustomEncoder_Register_Duplicate()
|
||||
{
|
||||
// has duplicated support for the same target Type
|
||||
expectedException.expect(IllegalStateException.class);
|
||||
expectedException.expect(InvalidWebSocketException.class);
|
||||
expectedException.expectMessage(containsString("Duplicate"));
|
||||
encoders.register(BadDualEncoder.class);
|
||||
}
|
||||
|
@ -290,9 +291,9 @@ public class AvailableEncodersTest
|
|||
{
|
||||
// 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.expect(InvalidWebSocketException.class);
|
||||
expectedException.expectMessage(containsString("Duplicate"));
|
||||
encoders.register(TimeEncoder.class);
|
||||
}
|
||||
|
|
|
@ -21,24 +21,33 @@ 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.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;
|
||||
import org.eclipse.jetty.websocket.jsr356.endpoints.TrackingSocket;
|
||||
import org.junit.BeforeClass;
|
||||
import org.junit.Rule;
|
||||
import org.junit.Test;
|
||||
import org.junit.rules.ExpectedException;
|
||||
|
||||
public class JsrEndpointFunctions_OnMessage_BinaryTest
|
||||
{
|
||||
|
@ -50,6 +59,9 @@ public class JsrEndpointFunctions_OnMessage_BinaryTest
|
|||
container = new ClientContainer();
|
||||
}
|
||||
|
||||
@Rule
|
||||
public ExpectedException expectedException = ExpectedException.none();
|
||||
|
||||
private String expectedBuffer;
|
||||
private AvailableEncoders encoders;
|
||||
private AvailableDecoders decoders;
|
||||
|
@ -64,6 +76,17 @@ public class JsrEndpointFunctions_OnMessage_BinaryTest
|
|||
uriParams = new HashMap<>();
|
||||
}
|
||||
|
||||
public JsrSession newSession(Object websocket)
|
||||
{
|
||||
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);
|
||||
}
|
||||
|
||||
private void assertOnMessageInvocation(TrackingSocket socket, String expectedEventFormat, Object... args) throws Exception
|
||||
{
|
||||
JsrEndpointFunctions endpointFunctions = new JsrEndpointFunctions(
|
||||
|
@ -75,6 +98,9 @@ public class JsrEndpointFunctions_OnMessage_BinaryTest
|
|||
endpointConfig
|
||||
);
|
||||
endpointFunctions.start();
|
||||
|
||||
// This invocation is the same for all tests
|
||||
endpointFunctions.onOpen(newSession(socket));
|
||||
|
||||
assertThat("Has BinarySink", endpointFunctions.hasBinarySink(), is(true));
|
||||
|
||||
|
@ -100,6 +126,7 @@ public class JsrEndpointFunctions_OnMessage_BinaryTest
|
|||
@Test
|
||||
public void testInvokeMessage() throws Exception
|
||||
{
|
||||
expectedException.expect(InvalidSignatureException.class);
|
||||
assertOnMessageInvocation(new MessageSocket(), "onMessage()");
|
||||
}
|
||||
|
||||
|
@ -133,6 +160,7 @@ public class JsrEndpointFunctions_OnMessage_BinaryTest
|
|||
@Test
|
||||
public void testInvokeMessageSession() throws Exception
|
||||
{
|
||||
expectedException.expect(InvalidSignatureException.class);
|
||||
assertOnMessageInvocation(new MessageSessionSocket(),
|
||||
"onMessage(JsrSession[CLIENT,%s,DummyConnection])",
|
||||
MessageSessionSocket.class.getName());
|
||||
|
|
|
@ -20,19 +20,25 @@ 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.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.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;
|
||||
|
@ -67,8 +73,19 @@ public class JsrEndpointFunctions_OnMessage_TextTest
|
|||
decoders = new AvailableDecoders(endpointConfig);
|
||||
uriParams = new HashMap<>();
|
||||
}
|
||||
|
||||
private void onText(TrackingSocket socket, String msg)
|
||||
|
||||
public JsrSession newSession(Object websocket)
|
||||
{
|
||||
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);
|
||||
}
|
||||
|
||||
private void onText(TrackingSocket socket, String msg) throws Exception
|
||||
{
|
||||
JsrEndpointFunctions endpointFunctions = new JsrEndpointFunctions(
|
||||
socket, container.getPolicy(),
|
||||
|
@ -78,23 +95,28 @@ public class JsrEndpointFunctions_OnMessage_TextTest
|
|||
uriParams,
|
||||
endpointConfig
|
||||
);
|
||||
|
||||
endpointFunctions.start();
|
||||
|
||||
// This invocation is the same for all tests
|
||||
endpointFunctions.onOpen(newSession(socket));
|
||||
|
||||
ByteBuffer payload = BufferUtil.toBuffer(msg, StandardCharsets.UTF_8);
|
||||
endpointFunctions.onText(payload, true);
|
||||
}
|
||||
|
||||
private void assertOnMessageInvocation(TrackingSocket socket, String expectedEventFormat, Object... args) throws InvocationTargetException, IllegalAccessException
|
||||
private void assertOnMessageInvocation(TrackingSocket socket, String expectedEventFormat, Object... args) throws Exception
|
||||
{
|
||||
onText(socket, "Hello World");
|
||||
socket.assertEvent(String.format(expectedEventFormat, args));
|
||||
}
|
||||
|
||||
|
||||
@ClientEndpoint
|
||||
public static class MessageSocket extends TrackingSocket
|
||||
{
|
||||
/**
|
||||
* Invalid declaration - the type is ambiguous (is it TEXT / BINARY / PONG?)
|
||||
*/
|
||||
@SuppressWarnings("IncorrectOnMessageMethodsInspection")
|
||||
@OnMessage
|
||||
public void onMessage()
|
||||
{
|
||||
|
@ -103,14 +125,15 @@ public class JsrEndpointFunctions_OnMessage_TextTest
|
|||
}
|
||||
|
||||
@Test
|
||||
public void testAmbiguousEmptyMessage() throws InvocationTargetException, IllegalAccessException
|
||||
public void testAmbiguousEmptyMessage() throws Exception
|
||||
{
|
||||
MessageSocket socket = new MessageSocket();
|
||||
expectedException.expect(InvalidSignatureException.class);
|
||||
expectedException.expectMessage(containsString("@OnMessage public void onMessage"));
|
||||
onText(socket, "Hello World");
|
||||
}
|
||||
|
||||
|
||||
@ClientEndpoint
|
||||
public static class MessageTextSocket extends TrackingSocket
|
||||
{
|
||||
@OnMessage
|
||||
|
@ -121,15 +144,16 @@ public class JsrEndpointFunctions_OnMessage_TextTest
|
|||
}
|
||||
|
||||
@Test
|
||||
public void testInvokeMessageText() throws InvocationTargetException, IllegalAccessException
|
||||
public void testInvokeMessageText() throws Exception
|
||||
{
|
||||
assertOnMessageInvocation(new MessageTextSocket(), "onMessage(Hello World)");
|
||||
}
|
||||
|
||||
@ClientEndpoint
|
||||
public static class MessageSessionSocket extends TrackingSocket
|
||||
{
|
||||
/**
|
||||
* Invalid declaration - the type is ambiguous (is it TEXT / BINARY / PONG?)
|
||||
* Invalid declaration - the type is ambiguous (is it TEXT, BINARY, or PONG?)
|
||||
*/
|
||||
@OnMessage
|
||||
public void onMessage(Session session)
|
||||
|
@ -139,7 +163,7 @@ public class JsrEndpointFunctions_OnMessage_TextTest
|
|||
}
|
||||
|
||||
@Test
|
||||
public void testAmbiguousMessageSession() throws InvocationTargetException, IllegalAccessException
|
||||
public void testAmbiguousMessageSession() throws Exception
|
||||
{
|
||||
MessageSessionSocket socket = new MessageSessionSocket();
|
||||
|
||||
|
@ -147,19 +171,19 @@ public class JsrEndpointFunctions_OnMessage_TextTest
|
|||
expectedException.expectMessage(containsString("@OnMessage public void onMessage"));
|
||||
onText(socket, "Hello World");
|
||||
}
|
||||
|
||||
|
||||
@ClientEndpoint
|
||||
public static class MessageSessionTextSocket extends TrackingSocket
|
||||
{
|
||||
@OnMessage
|
||||
public void onMessage(Session session, String msg)
|
||||
{
|
||||
|
||||
addEvent("onMessage(%s, %s)", session, msg);
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testInvokeMessageSessionText() throws InvocationTargetException, IllegalAccessException
|
||||
public void testInvokeMessageSessionText() throws Exception
|
||||
{
|
||||
assertOnMessageInvocation(new MessageSessionTextSocket(),
|
||||
"onMessage(JsrSession[CLIENT,%s,DummyConnection], Hello World)",
|
||||
|
|
|
@ -62,7 +62,7 @@ public class JsrEndpointFunctions_OnOpenTest
|
|||
decoders = new AvailableDecoders(endpointConfig);
|
||||
uriParams = new HashMap<>();
|
||||
}
|
||||
|
||||
|
||||
public JsrSession newSession(Object websocket)
|
||||
{
|
||||
String id = JsrEndpointFunctions_OnOpenTest.class.getSimpleName();
|
||||
|
|
|
@ -161,9 +161,6 @@ public class WebSocketSession extends ContainerLifeCycle implements Session, Rem
|
|||
if (LOG.isDebugEnabled())
|
||||
LOG.debug("starting - {}", this);
|
||||
|
||||
this.endpointFunctions = newEndpointFunctions(this.endpoint);
|
||||
addBean(this.endpointFunctions);
|
||||
|
||||
Iterator<RemoteEndpointFactory> iter = ServiceLoader.load(RemoteEndpointFactory.class).iterator();
|
||||
if (iter.hasNext())
|
||||
remoteEndpointFactory = iter.next();
|
||||
|
@ -173,7 +170,10 @@ public class WebSocketSession extends ContainerLifeCycle implements Session, Rem
|
|||
|
||||
if (LOG.isDebugEnabled())
|
||||
LOG.debug("Using RemoteEndpointFactory: {}", remoteEndpointFactory);
|
||||
|
||||
|
||||
this.endpointFunctions = newEndpointFunctions(this.endpoint);
|
||||
addBean(this.endpointFunctions);
|
||||
|
||||
super.doStart();
|
||||
}
|
||||
|
||||
|
|
|
@ -481,17 +481,17 @@ public class CommonEndpointFunctions<T extends Session> extends AbstractLifeCycl
|
|||
|
||||
protected void clearOnPongFunction()
|
||||
{
|
||||
|
||||
onPongFunction = null;
|
||||
}
|
||||
|
||||
protected void clearOnTextSink()
|
||||
{
|
||||
|
||||
onTextSink = null;
|
||||
}
|
||||
|
||||
protected void clearOnBinarySink()
|
||||
{
|
||||
|
||||
onBinarySink = null;
|
||||
}
|
||||
|
||||
public BatchMode getBatchMode()
|
||||
|
@ -650,8 +650,9 @@ public class CommonEndpointFunctions<T extends Session> extends AbstractLifeCycl
|
|||
return;
|
||||
|
||||
StringBuilder err = new StringBuilder();
|
||||
err.append("Cannot replace previously assigned ");
|
||||
err.append("Cannot replace previously assigned [");
|
||||
err.append(role);
|
||||
err.append("] at ").append(describeOrigin(val));
|
||||
err.append(" with ");
|
||||
err.append(describeOrigin(origin));
|
||||
|
||||
|
|
|
@ -21,6 +21,8 @@ package org.eclipse.jetty.websocket.common.message;
|
|||
import java.nio.ByteBuffer;
|
||||
import java.util.function.Function;
|
||||
|
||||
import org.eclipse.jetty.util.BufferUtil;
|
||||
|
||||
/**
|
||||
* {@link Function} argument for Partial Binary Messages
|
||||
*/
|
||||
|
@ -31,15 +33,15 @@ public class PartialBinaryMessage
|
|||
|
||||
public PartialBinaryMessage(ByteBuffer payload, boolean fin)
|
||||
{
|
||||
this.payload = payload;
|
||||
this.payload = payload == null ? BufferUtil.EMPTY_BUFFER : payload;
|
||||
this.fin = fin;
|
||||
}
|
||||
|
||||
|
||||
public ByteBuffer getPayload()
|
||||
{
|
||||
return payload;
|
||||
}
|
||||
|
||||
|
||||
public boolean isFin()
|
||||
{
|
||||
return fin;
|
||||
|
|
|
@ -18,6 +18,7 @@
|
|||
|
||||
package org.eclipse.jetty.websocket.common;
|
||||
|
||||
import static org.hamcrest.CoreMatchers.allOf;
|
||||
import static org.hamcrest.CoreMatchers.is;
|
||||
import static org.hamcrest.Matchers.containsString;
|
||||
import static org.junit.Assert.assertThat;
|
||||
|
@ -72,7 +73,7 @@ public class AnnotatedEndpointDiscoverTest
|
|||
{
|
||||
// Should toss exception
|
||||
thrown.expect(InvalidWebSocketException.class);
|
||||
thrown.expectMessage(containsString("Cannot replace previously assigned BINARY Handler with "));
|
||||
thrown.expectMessage(allOf(containsString("Cannot replace previously assigned"), containsString("BINARY Handler")));
|
||||
createSession(new BadDuplicateBinarySocket());
|
||||
}
|
||||
|
||||
|
|
|
@ -38,6 +38,7 @@ public class DummyConnection implements LogicalConnection
|
|||
private static final Logger LOG = Log.getLogger(DummyConnection.class);
|
||||
private IOState iostate;
|
||||
private WebSocketPolicy policy;
|
||||
|
||||
|
||||
@Deprecated
|
||||
public DummyConnection()
|
||||
|
|
Loading…
Reference in New Issue