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);
metadata.customizeParamsOnMessage(paramsOnMessage);
paramsOnMessage.add(JsrParamIdBinary.INSTANCE);
paramsOnMessage.add(JsrParamIdText.INSTANCE);
paramsOnMessage.add(JsrParamIdBinary.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.decoders.ByteArrayDecoder;
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.
@ -63,7 +64,7 @@ public class JsrParamIdBinary extends JsrParamIdOnMessage implements IJsrParamId
{
assertPartialMessageSupportDisabled(param,callable);
param.bind(Role.MESSAGE_BINARY_STREAM);
// Streaming have no decoder
callable.setDecoderClass(InputStreamDecoder.class);
return true;
}

View File

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

View File

@ -20,6 +20,7 @@ package org.eclipse.jetty.websocket.jsr356.endpoints;
import static org.hamcrest.Matchers.*;
import java.io.InputStream;
import java.lang.reflect.Field;
import java.nio.ByteBuffer;
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.BasicErrorThrowableSessionSocket;
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.BasicOpenSocket;
import org.eclipse.jetty.websocket.jsr356.endpoints.samples.BasicPongMessageSocket;
@ -97,6 +100,7 @@ public class ClientAnnotatedEndpointScanner_GoodSignaturesTest
Field fError = findFieldRef(AnnotatedEndpointMetadata.class,"onError");
Field fText = findFieldRef(AnnotatedEndpointMetadata.class,"onText");
Field fBinary = findFieldRef(AnnotatedEndpointMetadata.class,"onBinary");
Field fBinaryStream = findFieldRef(AnnotatedEndpointMetadata.class,"onBinaryStream");
Field fPong = findFieldRef(AnnotatedEndpointMetadata.class,"onPong");
// @formatter:off
@ -120,6 +124,9 @@ public class ClientAnnotatedEndpointScanner_GoodSignaturesTest
Case.add(data, BasicBinaryMessageByteBufferSocket.class, fBinary, ByteBuffer.class);
// -- Pong Events
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
// 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.OnMessage;
import javax.websocket.OnOpen;
import javax.websocket.RemoteEndpoint.Basic;
import javax.websocket.Session;
@ClientEndpoint
@ -37,6 +38,7 @@ public class EchoClientSocket extends TrackingSocket
{
public final CountDownLatch eventCountLatch;
private Session session;
private Basic remote;
public EchoClientSocket(int expectedEventCount)
{
@ -76,6 +78,7 @@ public class EchoClientSocket extends TrackingSocket
public void onOpen(Session session)
{
this.session = session;
this.remote = session.getBasicRemote();
openLatch.countDown();
}
@ -93,16 +96,16 @@ public class EchoClientSocket extends TrackingSocket
public void sendObject(Object obj) throws IOException, EncodeException
{
session.getBasicRemote().sendObject(obj);
remote.sendObject(obj);
}
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
{
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.MavenTestingUtils;
import org.eclipse.jetty.util.BufferUtil;
import org.eclipse.jetty.webapp.WebAppContext;
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.samples.binary.ByteBufferSocket;
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.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.ShortObjectTextSocket;
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.ReaderSocket;
import org.eclipse.jetty.websocket.jsr356.server.samples.streaming.StringReturnReaderParamSocket;
@ -178,6 +181,12 @@ public class EchoTest
// PathParam based
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
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));
}
}