418632 - WebSocket / Jsr annotated @OnMessage with InputStream fails to be called

+ Fixed load order issue with binary vs text
+ Fixed decoder assignment for InputStream
+ Added unit tests to prevent regression of this feature
This commit is contained in:
Joakim Erdfelt 2013-10-03 16:06:47 -07:00
parent d535cb9c92
commit a0ddb2c5d7
10 changed files with 214 additions and 6 deletions

View File

@ -64,8 +64,8 @@ public class AnnotatedEndpointScanner<T extends Annotation, C extends EndpointCo
paramsOnError.add(JsrParamIdOnError.INSTANCE); paramsOnError.add(JsrParamIdOnError.INSTANCE);
metadata.customizeParamsOnMessage(paramsOnMessage); metadata.customizeParamsOnMessage(paramsOnMessage);
paramsOnMessage.add(JsrParamIdBinary.INSTANCE);
paramsOnMessage.add(JsrParamIdText.INSTANCE); paramsOnMessage.add(JsrParamIdText.INSTANCE);
paramsOnMessage.add(JsrParamIdBinary.INSTANCE);
paramsOnMessage.add(JsrParamIdPong.INSTANCE); paramsOnMessage.add(JsrParamIdPong.INSTANCE);
} }

View File

@ -27,6 +27,7 @@ import org.eclipse.jetty.websocket.common.events.annotated.InvalidSignatureExcep
import org.eclipse.jetty.websocket.jsr356.annotations.Param.Role; import org.eclipse.jetty.websocket.jsr356.annotations.Param.Role;
import org.eclipse.jetty.websocket.jsr356.decoders.ByteArrayDecoder; import org.eclipse.jetty.websocket.jsr356.decoders.ByteArrayDecoder;
import org.eclipse.jetty.websocket.jsr356.decoders.ByteBufferDecoder; import org.eclipse.jetty.websocket.jsr356.decoders.ByteBufferDecoder;
import org.eclipse.jetty.websocket.jsr356.decoders.InputStreamDecoder;
/** /**
* Param handling for static Binary &#064;{@link OnMessage} parameters. * Param handling for static Binary &#064;{@link OnMessage} parameters.
@ -63,7 +64,7 @@ public class JsrParamIdBinary extends JsrParamIdOnMessage implements IJsrParamId
{ {
assertPartialMessageSupportDisabled(param,callable); assertPartialMessageSupportDisabled(param,callable);
param.bind(Role.MESSAGE_BINARY_STREAM); param.bind(Role.MESSAGE_BINARY_STREAM);
// Streaming have no decoder callable.setDecoderClass(InputStreamDecoder.class);
return true; return true;
} }

View File

@ -18,7 +18,6 @@
package org.eclipse.jetty.websocket.jsr356.metadata; package org.eclipse.jetty.websocket.jsr356.metadata;
import java.nio.ByteBuffer;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Iterator; import java.util.Iterator;
import java.util.List; import java.util.List;

View File

@ -20,6 +20,7 @@ package org.eclipse.jetty.websocket.jsr356.endpoints;
import static org.hamcrest.Matchers.*; import static org.hamcrest.Matchers.*;
import java.io.InputStream;
import java.lang.reflect.Field; import java.lang.reflect.Field;
import java.nio.ByteBuffer; import java.nio.ByteBuffer;
import java.util.ArrayList; import java.util.ArrayList;
@ -43,6 +44,8 @@ import org.eclipse.jetty.websocket.jsr356.endpoints.samples.BasicErrorSessionThr
import org.eclipse.jetty.websocket.jsr356.endpoints.samples.BasicErrorSocket; import org.eclipse.jetty.websocket.jsr356.endpoints.samples.BasicErrorSocket;
import org.eclipse.jetty.websocket.jsr356.endpoints.samples.BasicErrorThrowableSessionSocket; import org.eclipse.jetty.websocket.jsr356.endpoints.samples.BasicErrorThrowableSessionSocket;
import org.eclipse.jetty.websocket.jsr356.endpoints.samples.BasicErrorThrowableSocket; import org.eclipse.jetty.websocket.jsr356.endpoints.samples.BasicErrorThrowableSocket;
import org.eclipse.jetty.websocket.jsr356.endpoints.samples.BasicInputStreamSocket;
import org.eclipse.jetty.websocket.jsr356.endpoints.samples.BasicInputStreamWithThrowableSocket;
import org.eclipse.jetty.websocket.jsr356.endpoints.samples.BasicOpenSessionSocket; import org.eclipse.jetty.websocket.jsr356.endpoints.samples.BasicOpenSessionSocket;
import org.eclipse.jetty.websocket.jsr356.endpoints.samples.BasicOpenSocket; import org.eclipse.jetty.websocket.jsr356.endpoints.samples.BasicOpenSocket;
import org.eclipse.jetty.websocket.jsr356.endpoints.samples.BasicPongMessageSocket; import org.eclipse.jetty.websocket.jsr356.endpoints.samples.BasicPongMessageSocket;
@ -97,6 +100,7 @@ public class ClientAnnotatedEndpointScanner_GoodSignaturesTest
Field fError = findFieldRef(AnnotatedEndpointMetadata.class,"onError"); Field fError = findFieldRef(AnnotatedEndpointMetadata.class,"onError");
Field fText = findFieldRef(AnnotatedEndpointMetadata.class,"onText"); Field fText = findFieldRef(AnnotatedEndpointMetadata.class,"onText");
Field fBinary = findFieldRef(AnnotatedEndpointMetadata.class,"onBinary"); Field fBinary = findFieldRef(AnnotatedEndpointMetadata.class,"onBinary");
Field fBinaryStream = findFieldRef(AnnotatedEndpointMetadata.class,"onBinaryStream");
Field fPong = findFieldRef(AnnotatedEndpointMetadata.class,"onPong"); Field fPong = findFieldRef(AnnotatedEndpointMetadata.class,"onPong");
// @formatter:off // @formatter:off
@ -120,6 +124,9 @@ public class ClientAnnotatedEndpointScanner_GoodSignaturesTest
Case.add(data, BasicBinaryMessageByteBufferSocket.class, fBinary, ByteBuffer.class); Case.add(data, BasicBinaryMessageByteBufferSocket.class, fBinary, ByteBuffer.class);
// -- Pong Events // -- Pong Events
Case.add(data, BasicPongMessageSocket.class, fPong, PongMessage.class); Case.add(data, BasicPongMessageSocket.class, fPong, PongMessage.class);
// -- InputStream Events
Case.add(data, BasicInputStreamSocket.class, fBinaryStream, InputStream.class);
Case.add(data, BasicInputStreamWithThrowableSocket.class, fBinaryStream, InputStream.class);
// @formatter:on // @formatter:on
// TODO: validate return types // TODO: validate return types

View File

@ -0,0 +1,47 @@
//
// ========================================================================
// Copyright (c) 1995-2013 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.endpoints.samples;
import java.io.IOException;
import java.io.InputStream;
import javax.websocket.ClientEndpoint;
import javax.websocket.OnMessage;
import org.eclipse.jetty.util.IO;
import org.eclipse.jetty.websocket.jsr356.endpoints.TrackingSocket;
@ClientEndpoint
public class BasicInputStreamSocket extends TrackingSocket
{
@OnMessage
public void onBinary(InputStream stream)
{
try
{
String msg = IO.toString(stream);
addEvent("onBinary(%s)",msg);
}
catch (IOException e)
{
super.errorQueue.add(e);
}
dataLatch.countDown();
}
}

View File

@ -0,0 +1,39 @@
//
// ========================================================================
// Copyright (c) 1995-2013 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.endpoints.samples;
import java.io.IOException;
import java.io.InputStream;
import javax.websocket.ClientEndpoint;
import javax.websocket.OnMessage;
import org.eclipse.jetty.util.IO;
import org.eclipse.jetty.websocket.jsr356.endpoints.TrackingSocket;
@ClientEndpoint
public class BasicInputStreamWithThrowableSocket extends TrackingSocket
{
@OnMessage
public void onBinary(InputStream stream) throws IOException
{
String msg = IO.toString(stream);
addEvent("onBinary(%s)",msg);
}
}

View File

@ -30,6 +30,7 @@ import javax.websocket.OnClose;
import javax.websocket.OnError; import javax.websocket.OnError;
import javax.websocket.OnMessage; import javax.websocket.OnMessage;
import javax.websocket.OnOpen; import javax.websocket.OnOpen;
import javax.websocket.RemoteEndpoint.Basic;
import javax.websocket.Session; import javax.websocket.Session;
@ClientEndpoint @ClientEndpoint
@ -37,6 +38,7 @@ public class EchoClientSocket extends TrackingSocket
{ {
public final CountDownLatch eventCountLatch; public final CountDownLatch eventCountLatch;
private Session session; private Session session;
private Basic remote;
public EchoClientSocket(int expectedEventCount) public EchoClientSocket(int expectedEventCount)
{ {
@ -76,6 +78,7 @@ public class EchoClientSocket extends TrackingSocket
public void onOpen(Session session) public void onOpen(Session session)
{ {
this.session = session; this.session = session;
this.remote = session.getBasicRemote();
openLatch.countDown(); openLatch.countDown();
} }
@ -93,16 +96,16 @@ public class EchoClientSocket extends TrackingSocket
public void sendObject(Object obj) throws IOException, EncodeException public void sendObject(Object obj) throws IOException, EncodeException
{ {
session.getBasicRemote().sendObject(obj); remote.sendObject(obj);
} }
public void sendPartialBinary(ByteBuffer part, boolean fin) throws IOException public void sendPartialBinary(ByteBuffer part, boolean fin) throws IOException
{ {
session.getBasicRemote().sendBinary(part,fin); remote.sendBinary(part,fin);
} }
public void sendPartialText(String part, boolean fin) throws IOException public void sendPartialText(String part, boolean fin) throws IOException
{ {
session.getBasicRemote().sendText(part,fin); remote.sendText(part,fin);
} }
} }

View File

@ -32,9 +32,11 @@ import javax.websocket.WebSocketContainer;
import org.eclipse.jetty.toolchain.test.EventQueue; import org.eclipse.jetty.toolchain.test.EventQueue;
import org.eclipse.jetty.toolchain.test.MavenTestingUtils; import org.eclipse.jetty.toolchain.test.MavenTestingUtils;
import org.eclipse.jetty.util.BufferUtil;
import org.eclipse.jetty.webapp.WebAppContext; import org.eclipse.jetty.webapp.WebAppContext;
import org.eclipse.jetty.websocket.jsr356.server.EchoCase.PartialBinary; import org.eclipse.jetty.websocket.jsr356.server.EchoCase.PartialBinary;
import org.eclipse.jetty.websocket.jsr356.server.EchoCase.PartialText; import org.eclipse.jetty.websocket.jsr356.server.EchoCase.PartialText;
import org.eclipse.jetty.websocket.jsr356.server.samples.binary.ByteBufferSocket;
import org.eclipse.jetty.websocket.jsr356.server.samples.partial.PartialTextSessionSocket; import org.eclipse.jetty.websocket.jsr356.server.samples.partial.PartialTextSessionSocket;
import org.eclipse.jetty.websocket.jsr356.server.samples.partial.PartialTextSocket; import org.eclipse.jetty.websocket.jsr356.server.samples.partial.PartialTextSocket;
import org.eclipse.jetty.websocket.jsr356.server.samples.primitives.BooleanObjectTextSocket; import org.eclipse.jetty.websocket.jsr356.server.samples.primitives.BooleanObjectTextSocket;
@ -54,6 +56,7 @@ import org.eclipse.jetty.websocket.jsr356.server.samples.primitives.LongObjectTe
import org.eclipse.jetty.websocket.jsr356.server.samples.primitives.LongTextSocket; import org.eclipse.jetty.websocket.jsr356.server.samples.primitives.LongTextSocket;
import org.eclipse.jetty.websocket.jsr356.server.samples.primitives.ShortObjectTextSocket; import org.eclipse.jetty.websocket.jsr356.server.samples.primitives.ShortObjectTextSocket;
import org.eclipse.jetty.websocket.jsr356.server.samples.primitives.ShortTextSocket; import org.eclipse.jetty.websocket.jsr356.server.samples.primitives.ShortTextSocket;
import org.eclipse.jetty.websocket.jsr356.server.samples.streaming.InputStreamSocket;
import org.eclipse.jetty.websocket.jsr356.server.samples.streaming.ReaderParamSocket; import org.eclipse.jetty.websocket.jsr356.server.samples.streaming.ReaderParamSocket;
import org.eclipse.jetty.websocket.jsr356.server.samples.streaming.ReaderSocket; import org.eclipse.jetty.websocket.jsr356.server.samples.streaming.ReaderSocket;
import org.eclipse.jetty.websocket.jsr356.server.samples.streaming.StringReturnReaderParamSocket; import org.eclipse.jetty.websocket.jsr356.server.samples.streaming.StringReturnReaderParamSocket;
@ -178,6 +181,12 @@ public class EchoTest
// PathParam based // PathParam based
EchoCase.add(TESTCASES,IntParamTextSocket.class).requestPath("/echo/primitives/integer/params/5678").addMessage(1234).expect("1234|5678"); EchoCase.add(TESTCASES,IntParamTextSocket.class).requestPath("/echo/primitives/integer/params/5678").addMessage(1234).expect("1234|5678");
// ByteBuffer based
EchoCase.add(TESTCASES,ByteBufferSocket.class).addMessage(BufferUtil.toBuffer("Hello World")).expect("Hello World");
// InputStream based
EchoCase.add(TESTCASES,InputStreamSocket.class).addMessage(BufferUtil.toBuffer("Hello World")).expect("Hello World");
// Reader based // Reader based
EchoCase.add(TESTCASES,ReaderSocket.class).addMessage("Hello World").expect("Hello World"); EchoCase.add(TESTCASES,ReaderSocket.class).addMessage("Hello World").expect("Hello World");

View File

@ -0,0 +1,51 @@
//
// ========================================================================
// Copyright (c) 1995-2013 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.server.samples.binary;
import java.io.IOException;
import java.nio.ByteBuffer;
import javax.websocket.OnError;
import javax.websocket.OnMessage;
import javax.websocket.Session;
import javax.websocket.server.ServerEndpoint;
import org.eclipse.jetty.util.BufferUtil;
import org.eclipse.jetty.util.log.Log;
import org.eclipse.jetty.util.log.Logger;
import org.eclipse.jetty.websocket.jsr356.server.StackUtil;
@ServerEndpoint("/echo/binary/bytebuffer")
public class ByteBufferSocket
{
private static final Logger LOG = Log.getLogger(ByteBufferSocket.class);
@OnMessage
public String onByteBuffer(ByteBuffer bbuf)
{
return BufferUtil.toUTF8String(bbuf);
}
@OnError
public void onError(Session session, Throwable cause) throws IOException
{
LOG.warn("Error",cause);
session.getBasicRemote().sendText("Exception: " + StackUtil.toString(cause));
}
}

View File

@ -0,0 +1,52 @@
//
// ========================================================================
// Copyright (c) 1995-2013 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.server.samples.streaming;
import java.io.IOException;
import java.io.InputStream;
import javax.websocket.OnError;
import javax.websocket.OnMessage;
import javax.websocket.Session;
import javax.websocket.server.ServerEndpoint;
import org.eclipse.jetty.util.IO;
import org.eclipse.jetty.util.StringUtil;
import org.eclipse.jetty.util.log.Log;
import org.eclipse.jetty.util.log.Logger;
import org.eclipse.jetty.websocket.jsr356.server.StackUtil;
@ServerEndpoint("/echo/streaming/inputstream")
public class InputStreamSocket
{
private static final Logger LOG = Log.getLogger(InputStreamSocket.class);
@OnMessage
public String onInputStream(InputStream stream) throws IOException
{
return IO.toString(stream, StringUtil.__UTF8);
}
@OnError
public void onError(Session session, Throwable cause) throws IOException
{
LOG.warn("Error",cause);
session.getBasicRemote().sendText("Exception: " + StackUtil.toString(cause));
}
}