Issue #207 - Support javax.websocket version 1.1

WIP
This commit is contained in:
Joakim Erdfelt 2016-04-22 16:52:56 -07:00
parent 5f6cf96fa5
commit 89f45830bc
21 changed files with 198 additions and 205 deletions

View File

@ -18,7 +18,6 @@
package org.eclipse.jetty.websocket.jsr356.messages; package org.eclipse.jetty.websocket.jsr356.messages;
import java.io.IOException;
import java.nio.ByteBuffer; import java.nio.ByteBuffer;
import javax.websocket.MessageHandler; import javax.websocket.MessageHandler;
@ -42,17 +41,16 @@ public class TextPartialMessage implements MessageSink
} }
@Override @Override
public void appendFrame(ByteBuffer payload, boolean isLast) throws IOException public void accept(ByteBuffer payload, Boolean fin)
{ {
String partialText = utf8Partial.toPartialString(payload); String partialText = utf8Partial.toPartialString(payload);
// No decoders for Partial messages per JSR-356 (PFD1 spec) // No decoders for Partial messages per JSR-356 (PFD1 spec)
partialHandler.onMessage(partialText,isLast); partialHandler.onMessage(partialText, fin);
}
@Override if (fin)
public void messageComplete() {
{ utf8Partial.reset();
utf8Partial.reset(); }
} }
} }

View File

@ -24,25 +24,15 @@
</modules> </modules>
<build> <build>
<pluginManagement> <plugins>
<plugins> <plugin>
<plugin> <groupId>org.codehaus.mojo</groupId>
<groupId>org.codehaus.mojo</groupId> <artifactId>findbugs-maven-plugin</artifactId>
<artifactId>findbugs-maven-plugin</artifactId> <configuration>
<configuration> <onlyAnalyze>org.eclipse.jetty.websocket.*</onlyAnalyze>
<onlyAnalyze>org.eclipse.jetty.websocket.*</onlyAnalyze> </configuration>
</configuration> </plugin>
</plugin> </plugins>
<plugin>
<groupId>org.codehaus.mojo</groupId>
<artifactId>clirr-maven-plugin</artifactId>
<configuration>
<minSeverity>info</minSeverity>
<comparisonVersion>9.1.0.v20131115</comparisonVersion>
</configuration>
</plugin>
</plugins>
</pluginManagement>
</build> </build>
</project> </project>

View File

@ -55,7 +55,7 @@ public abstract class ConnectPromise extends FuturePromise<Session> implements R
{ {
if (session != null) if (session != null)
{ {
// Notify websocket of failure to connect // Notify websocket session of failure to connect
session.notifyError(cause); session.notifyError(cause);
} }

View File

@ -65,23 +65,30 @@ public class ClientConnectTest
{ {
// Validate thrown cause // Validate thrown cause
Throwable cause = e.getCause(); Throwable cause = e.getCause();
if(!errorClass.isInstance(cause)) if (!errorClass.isInstance(cause))
{ {
cause.printStackTrace(System.err); cause.printStackTrace(System.err);
Assert.assertThat("ExecutionException.cause",cause,instanceOf(errorClass)); Assert.assertThat("ExecutionException.cause", cause, instanceOf(errorClass));
} }
// Validate websocket captured cause if (wsocket.getSession() != null)
Assert.assertThat("Error Queue Length",wsocket.errorQueue.size(),greaterThanOrEqualTo(1)); {
Throwable capcause = wsocket.errorQueue.poll(); // Validate websocket captured cause
Assert.assertThat("Error Queue[0]",capcause,notNullValue()); Assert.assertThat("Error Queue Length", wsocket.errorQueue.size(), greaterThanOrEqualTo(1));
Assert.assertThat("Error Queue[0]",capcause,instanceOf(errorClass)); Throwable capcause = wsocket.errorQueue.poll();
Assert.assertThat("Error Queue[0]", capcause, notNullValue());
Assert.assertThat("Error Queue[0]", capcause, instanceOf(errorClass));
// Validate that websocket didn't see an open event // Validate that websocket didn't see an open event
wsocket.assertNotOpened(); wsocket.assertNotOpened();
// Return the captured cause // Return the captured cause
return (E)capcause; return (E) capcause;
}
else
{
return (E) cause;
}
} }
@Before @Before

View File

@ -38,18 +38,18 @@ import org.eclipse.jetty.websocket.common.util.ReflectUtils;
public class OnByteArrayFunction implements Function<byte[], Void> public class OnByteArrayFunction implements Function<byte[], Void>
{ {
private static final DynamicArgs.Builder ARGBUILDER; private static final DynamicArgs.Builder ARGBUILDER;
private static final Arg SESSION = new Arg(1,Session.class); private static final Arg ARG_SESSION = new Arg(1, Session.class);
private static final Arg BUFFER = new Arg(2,byte[].class); private static final Arg ARG_BUFFER = new Arg(2, byte[].class);
private static final Arg OFFSET = new Arg(3,int.class); private static final Arg ARG_OFFSET = new Arg(3, int.class);
private static final Arg LENGTH = new Arg(4,int.class); private static final Arg ARG_LENGTH = new Arg(4, int.class);
static static
{ {
ARGBUILDER = new DynamicArgs.Builder(); ARGBUILDER = new DynamicArgs.Builder();
ARGBUILDER.addSignature(new ExactSignature(byte[].class)); ARGBUILDER.addSignature(new ExactSignature(ARG_BUFFER));
ARGBUILDER.addSignature(new ExactSignature(byte[].class,int.class,int.class)); ARGBUILDER.addSignature(new ExactSignature(ARG_BUFFER, ARG_OFFSET, ARG_LENGTH));
ARGBUILDER.addSignature(new ExactSignature(Session.class,byte[].class)); ARGBUILDER.addSignature(new ExactSignature(ARG_SESSION, ARG_BUFFER));
ARGBUILDER.addSignature(new ExactSignature(Session.class,byte[].class,int.class,int.class)); ARGBUILDER.addSignature(new ExactSignature(ARG_SESSION, ARG_BUFFER, ARG_OFFSET, ARG_LENGTH));
} }
public static DynamicArgs.Builder getDynamicArgsBuilder() public static DynamicArgs.Builder getDynamicArgsBuilder()
@ -73,14 +73,14 @@ public class OnByteArrayFunction implements Function<byte[], Void>
this.endpoint = endpoint; this.endpoint = endpoint;
this.method = method; this.method = method;
ReflectUtils.assertIsAnnotated(method,OnWebSocketMessage.class); ReflectUtils.assertIsAnnotated(method, OnWebSocketMessage.class);
ReflectUtils.assertIsPublicNonStatic(method); ReflectUtils.assertIsPublicNonStatic(method);
ReflectUtils.assertIsReturn(method,Void.TYPE); ReflectUtils.assertIsReturn(method, Void.TYPE);
this.callable = ARGBUILDER.build(method,SESSION,BUFFER,OFFSET,LENGTH); this.callable = ARGBUILDER.build(method, ARG_SESSION, ARG_BUFFER, ARG_OFFSET, ARG_LENGTH);
if (this.callable == null) if (this.callable == null)
{ {
throw InvalidSignatureException.build(method,OnWebSocketMessage.class,ARGBUILDER); throw InvalidSignatureException.build(method, OnWebSocketMessage.class, ARGBUILDER);
} }
} }
@ -89,11 +89,11 @@ public class OnByteArrayFunction implements Function<byte[], Void>
{ {
try try
{ {
this.callable.invoke(endpoint,bin,0,bin.length); this.callable.invoke(endpoint, bin, 0, bin.length);
} }
catch (IllegalAccessException | IllegalArgumentException | InvocationTargetException e) catch (IllegalAccessException | IllegalArgumentException | InvocationTargetException e)
{ {
throw new WebSocketException("Unable to call text message method " + ReflectUtils.toString(endpoint.getClass(),method),e); throw new WebSocketException("Unable to call text message method " + ReflectUtils.toString(endpoint.getClass(), method), e);
} }
return null; return null;
} }

View File

@ -39,14 +39,14 @@ import org.eclipse.jetty.websocket.common.util.ReflectUtils;
public class OnByteBufferFunction implements Function<ByteBuffer, Void> public class OnByteBufferFunction implements Function<ByteBuffer, Void>
{ {
private static final DynamicArgs.Builder ARGBUILDER; private static final DynamicArgs.Builder ARGBUILDER;
private static final Arg SESSION = new Arg(1,Session.class); private static final Arg ARG_SESSION = new Arg(1, Session.class);
private static final Arg BUFFER = new Arg(2,ByteBuffer.class); private static final Arg ARG_BUFFER = new Arg(2, ByteBuffer.class);
static static
{ {
ARGBUILDER = new DynamicArgs.Builder(); ARGBUILDER = new DynamicArgs.Builder();
ARGBUILDER.addSignature(new ExactSignature(ByteBuffer.class)); ARGBUILDER.addSignature(new ExactSignature(ARG_BUFFER));
ARGBUILDER.addSignature(new ExactSignature(Session.class,ByteBuffer.class)); ARGBUILDER.addSignature(new ExactSignature(ARG_SESSION, ARG_BUFFER));
} }
public static DynamicArgs.Builder getDynamicArgsBuilder() public static DynamicArgs.Builder getDynamicArgsBuilder()
@ -70,14 +70,14 @@ public class OnByteBufferFunction implements Function<ByteBuffer, Void>
this.endpoint = endpoint; this.endpoint = endpoint;
this.method = method; this.method = method;
ReflectUtils.assertIsAnnotated(method,OnWebSocketMessage.class); ReflectUtils.assertIsAnnotated(method, OnWebSocketMessage.class);
ReflectUtils.assertIsPublicNonStatic(method); ReflectUtils.assertIsPublicNonStatic(method);
ReflectUtils.assertIsReturn(method,Void.TYPE); ReflectUtils.assertIsReturn(method, Void.TYPE);
this.callable = ARGBUILDER.build(method,SESSION,BUFFER); this.callable = ARGBUILDER.build(method, ARG_SESSION, ARG_BUFFER);
if (this.callable == null) if (this.callable == null)
{ {
throw InvalidSignatureException.build(method,OnWebSocketMessage.class,ARGBUILDER); throw InvalidSignatureException.build(method, OnWebSocketMessage.class, ARGBUILDER);
} }
} }
@ -86,11 +86,11 @@ public class OnByteBufferFunction implements Function<ByteBuffer, Void>
{ {
try try
{ {
this.callable.invoke(endpoint,session,bin); this.callable.invoke(endpoint, session, bin);
} }
catch (IllegalAccessException | IllegalArgumentException | InvocationTargetException e) catch (IllegalAccessException | IllegalArgumentException | InvocationTargetException e)
{ {
throw new WebSocketException("Unable to call text message method " + ReflectUtils.toString(endpoint.getClass(),method),e); throw new WebSocketException("Unable to call text message method " + ReflectUtils.toString(endpoint.getClass(), method), e);
} }
return null; return null;
} }

View File

@ -18,6 +18,10 @@
package org.eclipse.jetty.websocket.common.functions; package org.eclipse.jetty.websocket.common.functions;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.function.Function;
import org.eclipse.jetty.websocket.api.Session; import org.eclipse.jetty.websocket.api.Session;
import org.eclipse.jetty.websocket.api.WebSocketException; import org.eclipse.jetty.websocket.api.WebSocketException;
import org.eclipse.jetty.websocket.api.annotations.OnWebSocketClose; import org.eclipse.jetty.websocket.api.annotations.OnWebSocketClose;
@ -29,27 +33,23 @@ import org.eclipse.jetty.websocket.common.util.DynamicArgs.Arg;
import org.eclipse.jetty.websocket.common.util.ExactSignature; import org.eclipse.jetty.websocket.common.util.ExactSignature;
import org.eclipse.jetty.websocket.common.util.ReflectUtils; import org.eclipse.jetty.websocket.common.util.ReflectUtils;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.function.Function;
/** /**
* Jetty {@link WebSocket} {@link OnWebSocketClose} method {@link Function} * Jetty {@link WebSocket} {@link OnWebSocketClose} method {@link Function}
*/ */
public class OnCloseFunction implements Function<CloseInfo, Void> public class OnCloseFunction implements Function<CloseInfo, Void>
{ {
private static final DynamicArgs.Builder ARGBUILDER; private static final DynamicArgs.Builder ARGBUILDER;
private static final Arg SESSION = new Arg(1,Session.class); private static final Arg ARG_SESSION = new Arg(1, Session.class);
private static final Arg STATUS_CODE = new Arg(2,int.class); private static final Arg ARG_STATUS_CODE = new Arg(2, int.class);
private static final Arg REASON = new Arg(3,String.class); private static final Arg ARG_REASON = new Arg(3, String.class);
static static
{ {
ARGBUILDER = new DynamicArgs.Builder(); ARGBUILDER = new DynamicArgs.Builder();
ARGBUILDER.addSignature(new ExactSignature()); ARGBUILDER.addSignature(new ExactSignature());
ARGBUILDER.addSignature(new ExactSignature(Session.class)); ARGBUILDER.addSignature(new ExactSignature(ARG_SESSION));
ARGBUILDER.addSignature(new ExactSignature(int.class,String.class)); ARGBUILDER.addSignature(new ExactSignature(ARG_STATUS_CODE, ARG_REASON));
ARGBUILDER.addSignature(new ExactSignature(Session.class,int.class,String.class)); ARGBUILDER.addSignature(new ExactSignature(ARG_SESSION, ARG_STATUS_CODE, ARG_REASON));
} }
private final Session session; private final Session session;
@ -67,10 +67,10 @@ public class OnCloseFunction implements Function<CloseInfo, Void>
ReflectUtils.assertIsPublicNonStatic(method); ReflectUtils.assertIsPublicNonStatic(method);
ReflectUtils.assertIsReturn(method, Void.TYPE); ReflectUtils.assertIsReturn(method, Void.TYPE);
this.callable = ARGBUILDER.build(method, SESSION, STATUS_CODE, REASON); this.callable = ARGBUILDER.build(method, ARG_SESSION, ARG_STATUS_CODE, ARG_REASON);
if (this.callable == null) if (this.callable == null)
{ {
throw InvalidSignatureException.build(method,OnWebSocketClose.class,ARGBUILDER); throw InvalidSignatureException.build(method, OnWebSocketClose.class, ARGBUILDER);
} }
} }
@ -79,11 +79,11 @@ public class OnCloseFunction implements Function<CloseInfo, Void>
{ {
try try
{ {
this.callable.invoke(endpoint,session,closeinfo.getStatusCode(),closeinfo.getReason()); this.callable.invoke(endpoint, session, closeinfo.getStatusCode(), closeinfo.getReason());
} }
catch (IllegalAccessException | IllegalArgumentException | InvocationTargetException e) catch (IllegalAccessException | IllegalArgumentException | InvocationTargetException e)
{ {
throw new WebSocketException("Unable to call close method " + ReflectUtils.toString(endpoint.getClass(),method),e); throw new WebSocketException("Unable to call close method " + ReflectUtils.toString(endpoint.getClass(), method), e);
} }
return null; return null;
} }

View File

@ -38,14 +38,14 @@ import org.eclipse.jetty.websocket.common.util.ReflectUtils;
public class OnErrorFunction implements Function<Throwable, Void> public class OnErrorFunction implements Function<Throwable, Void>
{ {
private static final DynamicArgs.Builder ARGBUILDER; private static final DynamicArgs.Builder ARGBUILDER;
private static final Arg SESSION = new Arg(1, Session.class); private static final Arg ARG_SESSION = new Arg(1, Session.class);
private static final Arg CAUSE = new Arg(2, Throwable.class); private static final Arg ARG_CAUSE = new Arg(2, Throwable.class);
static static
{ {
ARGBUILDER = new DynamicArgs.Builder(); ARGBUILDER = new DynamicArgs.Builder();
ARGBUILDER.addSignature(new ExactSignature(Throwable.class)); ARGBUILDER.addSignature(new ExactSignature(ARG_CAUSE));
ARGBUILDER.addSignature(new ExactSignature(Session.class,Throwable.class)); ARGBUILDER.addSignature(new ExactSignature(ARG_SESSION, ARG_CAUSE));
} }
private final Session session; private final Session session;
@ -59,14 +59,14 @@ public class OnErrorFunction implements Function<Throwable, Void>
this.endpoint = endpoint; this.endpoint = endpoint;
this.method = method; this.method = method;
ReflectUtils.assertIsAnnotated(method,OnWebSocketError.class); ReflectUtils.assertIsAnnotated(method, OnWebSocketError.class);
ReflectUtils.assertIsPublicNonStatic(method); ReflectUtils.assertIsPublicNonStatic(method);
ReflectUtils.assertIsReturn(method,Void.TYPE); ReflectUtils.assertIsReturn(method, Void.TYPE);
this.callable = ARGBUILDER.build(method,SESSION,CAUSE); this.callable = ARGBUILDER.build(method, ARG_SESSION, ARG_CAUSE);
if (this.callable == null) if (this.callable == null)
{ {
throw InvalidSignatureException.build(method,OnWebSocketError.class,ARGBUILDER); throw InvalidSignatureException.build(method, OnWebSocketError.class, ARGBUILDER);
} }
} }
@ -75,11 +75,11 @@ public class OnErrorFunction implements Function<Throwable, Void>
{ {
try try
{ {
this.callable.invoke(endpoint,session,cause); this.callable.invoke(endpoint, session, cause);
} }
catch (IllegalAccessException | IllegalArgumentException | InvocationTargetException e) catch (IllegalAccessException | IllegalArgumentException | InvocationTargetException e)
{ {
throw new WebSocketException("Unable to call error method " + ReflectUtils.toString(endpoint.getClass(),method),e); throw new WebSocketException("Unable to call error method " + ReflectUtils.toString(endpoint.getClass(), method), e);
} }
return null; return null;
} }

View File

@ -40,14 +40,14 @@ import org.eclipse.jetty.websocket.common.util.ReflectUtils;
public class OnFrameFunction implements Function<Frame, Void> public class OnFrameFunction implements Function<Frame, Void>
{ {
private static final DynamicArgs.Builder ARGBUILDER; private static final DynamicArgs.Builder ARGBUILDER;
private static final Arg SESSION = new Arg(1,Session.class); private static final Arg ARG_SESSION = new Arg(1, Session.class);
private static final Arg FRAME = new Arg(2,Frame.class); private static final Arg ARG_FRAME = new Arg(2, Frame.class);
static static
{ {
ARGBUILDER = new DynamicArgs.Builder(); ARGBUILDER = new DynamicArgs.Builder();
ARGBUILDER.addSignature(new ExactSignature(Frame.class)); ARGBUILDER.addSignature(new ExactSignature(ARG_FRAME));
ARGBUILDER.addSignature(new ExactSignature(Session.class,Frame.class)); ARGBUILDER.addSignature(new ExactSignature(ARG_SESSION, ARG_FRAME));
} }
private final Session session; private final Session session;
@ -61,14 +61,14 @@ public class OnFrameFunction implements Function<Frame, Void>
this.endpoint = endpoint; this.endpoint = endpoint;
this.method = method; this.method = method;
ReflectUtils.assertIsAnnotated(method,OnWebSocketFrame.class); ReflectUtils.assertIsAnnotated(method, OnWebSocketFrame.class);
ReflectUtils.assertIsPublicNonStatic(method); ReflectUtils.assertIsPublicNonStatic(method);
ReflectUtils.assertIsReturn(method,Void.TYPE); ReflectUtils.assertIsReturn(method, Void.TYPE);
this.callable = ARGBUILDER.build(method,SESSION,FRAME); this.callable = ARGBUILDER.build(method, ARG_SESSION, ARG_FRAME);
if (this.callable == null) if (this.callable == null)
{ {
throw InvalidSignatureException.build(method,OnWebSocketFrame.class,ARGBUILDER); throw InvalidSignatureException.build(method, OnWebSocketFrame.class, ARGBUILDER);
} }
} }
@ -78,11 +78,11 @@ public class OnFrameFunction implements Function<Frame, Void>
WebSocketFrame copy = WebSocketFrame.copy(frame); WebSocketFrame copy = WebSocketFrame.copy(frame);
try try
{ {
this.callable.invoke(endpoint,session,copy); this.callable.invoke(endpoint, session, copy);
} }
catch (IllegalAccessException | IllegalArgumentException | InvocationTargetException e) catch (IllegalAccessException | IllegalArgumentException | InvocationTargetException e)
{ {
throw new WebSocketException("Unable to call frame method " + ReflectUtils.toString(endpoint.getClass(),method),e); throw new WebSocketException("Unable to call frame method " + ReflectUtils.toString(endpoint.getClass(), method), e);
} }
return null; return null;
} }

View File

@ -40,14 +40,14 @@ import org.eclipse.jetty.websocket.common.util.ReflectUtils;
public class OnInputStreamFunction implements Function<InputStream, Void> public class OnInputStreamFunction implements Function<InputStream, Void>
{ {
private static final DynamicArgs.Builder ARGBUILDER; private static final DynamicArgs.Builder ARGBUILDER;
private static final Arg SESSION = new Arg(1,Session.class); private static final Arg ARG_SESSION = new Arg(1, Session.class);
private static final Arg STREAM = new Arg(2, InputStream.class); private static final Arg ARG_STREAM = new Arg(2, InputStream.class);
static static
{ {
ARGBUILDER = new DynamicArgs.Builder(); ARGBUILDER = new DynamicArgs.Builder();
ARGBUILDER.addSignature(new ExactSignature(InputStream.class)); ARGBUILDER.addSignature(new ExactSignature(ARG_STREAM));
ARGBUILDER.addSignature(new ExactSignature(Session.class,InputStream.class)); ARGBUILDER.addSignature(new ExactSignature(ARG_SESSION, ARG_STREAM));
} }
public static DynamicArgs.Builder getDynamicArgsBuilder() public static DynamicArgs.Builder getDynamicArgsBuilder()
@ -71,14 +71,14 @@ public class OnInputStreamFunction implements Function<InputStream, Void>
this.endpoint = endpoint; this.endpoint = endpoint;
this.method = method; this.method = method;
ReflectUtils.assertIsAnnotated(method,OnWebSocketMessage.class); ReflectUtils.assertIsAnnotated(method, OnWebSocketMessage.class);
ReflectUtils.assertIsPublicNonStatic(method); ReflectUtils.assertIsPublicNonStatic(method);
ReflectUtils.assertIsReturn(method,Void.TYPE); ReflectUtils.assertIsReturn(method, Void.TYPE);
this.callable = ARGBUILDER.build(method,SESSION,STREAM); this.callable = ARGBUILDER.build(method, ARG_SESSION, ARG_STREAM);
if (this.callable == null) if (this.callable == null)
{ {
throw InvalidSignatureException.build(method,OnWebSocketMessage.class,ARGBUILDER); throw InvalidSignatureException.build(method, OnWebSocketMessage.class, ARGBUILDER);
} }
} }
@ -87,11 +87,11 @@ public class OnInputStreamFunction implements Function<InputStream, Void>
{ {
try try
{ {
this.callable.invoke(endpoint,session,stream); this.callable.invoke(endpoint, session, stream);
} }
catch (IllegalAccessException | IllegalArgumentException | InvocationTargetException e) catch (IllegalAccessException | IllegalArgumentException | InvocationTargetException e)
{ {
throw new WebSocketException("Unable to call text message method " + ReflectUtils.toString(endpoint.getClass(),method),e); throw new WebSocketException("Unable to call text message method " + ReflectUtils.toString(endpoint.getClass(), method), e);
} }
return null; return null;
} }

View File

@ -38,13 +38,13 @@ import org.eclipse.jetty.websocket.common.util.ReflectUtils;
public class OnOpenFunction implements Function<Session, Void> public class OnOpenFunction implements Function<Session, Void>
{ {
private static final DynamicArgs.Builder ARGBUILDER; private static final DynamicArgs.Builder ARGBUILDER;
private static final Arg SESSION = new Arg(1,Session.class); private static final Arg ARG_SESSION = new Arg(1, Session.class);
static static
{ {
ARGBUILDER = new DynamicArgs.Builder(); ARGBUILDER = new DynamicArgs.Builder();
ARGBUILDER.addSignature(new ExactSignature()); ARGBUILDER.addSignature(new ExactSignature());
ARGBUILDER.addSignature(new ExactSignature(Session.class)); ARGBUILDER.addSignature(new ExactSignature(ARG_SESSION));
} }
private final Object endpoint; private final Object endpoint;
@ -56,14 +56,14 @@ public class OnOpenFunction implements Function<Session, Void>
this.endpoint = endpoint; this.endpoint = endpoint;
this.method = method; this.method = method;
ReflectUtils.assertIsAnnotated(method,OnWebSocketConnect.class); ReflectUtils.assertIsAnnotated(method, OnWebSocketConnect.class);
ReflectUtils.assertIsPublicNonStatic(method); ReflectUtils.assertIsPublicNonStatic(method);
ReflectUtils.assertIsReturn(method,Void.TYPE); ReflectUtils.assertIsReturn(method, Void.TYPE);
this.callable = ARGBUILDER.build(method,SESSION); this.callable = ARGBUILDER.build(method, ARG_SESSION);
if (this.callable == null) if (this.callable == null)
{ {
throw InvalidSignatureException.build(method,OnWebSocketConnect.class,ARGBUILDER); throw InvalidSignatureException.build(method, OnWebSocketConnect.class, ARGBUILDER);
} }
} }
@ -72,11 +72,11 @@ public class OnOpenFunction implements Function<Session, Void>
{ {
try try
{ {
this.callable.invoke(endpoint,session); this.callable.invoke(endpoint, session);
} }
catch (IllegalAccessException | IllegalArgumentException | InvocationTargetException e) catch (IllegalAccessException | IllegalArgumentException | InvocationTargetException e)
{ {
throw new WebSocketException("Unable to call method " + ReflectUtils.toString(endpoint.getClass(),method),e); throw new WebSocketException("Unable to call method " + ReflectUtils.toString(endpoint.getClass(), method), e);
} }
return null; return null;
} }

View File

@ -39,14 +39,14 @@ import org.eclipse.jetty.websocket.common.util.ReflectUtils;
public class OnReaderFunction implements Function<Reader, Void> public class OnReaderFunction implements Function<Reader, Void>
{ {
private static final DynamicArgs.Builder ARGBUILDER; private static final DynamicArgs.Builder ARGBUILDER;
private static final Arg SESSION = new Arg(1,Session.class); private static final Arg ARG_SESSION = new Arg(1, Session.class);
private static final Arg STREAM = new Arg(2,Reader.class); private static final Arg ARG_STREAM = new Arg(2, Reader.class);
static static
{ {
ARGBUILDER = new DynamicArgs.Builder(); ARGBUILDER = new DynamicArgs.Builder();
ARGBUILDER.addSignature(new ExactSignature(Reader.class)); ARGBUILDER.addSignature(new ExactSignature(ARG_STREAM));
ARGBUILDER.addSignature(new ExactSignature(Session.class,Reader.class)); ARGBUILDER.addSignature(new ExactSignature(ARG_SESSION, ARG_STREAM));
} }
public static DynamicArgs.Builder getDynamicArgsBuilder() public static DynamicArgs.Builder getDynamicArgsBuilder()
@ -70,14 +70,14 @@ public class OnReaderFunction implements Function<Reader, Void>
this.endpoint = endpoint; this.endpoint = endpoint;
this.method = method; this.method = method;
ReflectUtils.assertIsAnnotated(method,OnWebSocketMessage.class); ReflectUtils.assertIsAnnotated(method, OnWebSocketMessage.class);
ReflectUtils.assertIsPublicNonStatic(method); ReflectUtils.assertIsPublicNonStatic(method);
ReflectUtils.assertIsReturn(method,Void.TYPE); ReflectUtils.assertIsReturn(method, Void.TYPE);
this.callable = ARGBUILDER.build(method,SESSION,STREAM); this.callable = ARGBUILDER.build(method, ARG_SESSION, ARG_STREAM);
if (this.callable == null) if (this.callable == null)
{ {
throw InvalidSignatureException.build(method,OnWebSocketMessage.class,ARGBUILDER); throw InvalidSignatureException.build(method, OnWebSocketMessage.class, ARGBUILDER);
} }
} }
@ -86,11 +86,11 @@ public class OnReaderFunction implements Function<Reader, Void>
{ {
try try
{ {
this.callable.invoke(endpoint,session,stream); this.callable.invoke(endpoint, session, stream);
} }
catch (IllegalAccessException | IllegalArgumentException | InvocationTargetException e) catch (IllegalAccessException | IllegalArgumentException | InvocationTargetException e)
{ {
throw new WebSocketException("Unable to call text message method " + ReflectUtils.toString(endpoint.getClass(),method),e); throw new WebSocketException("Unable to call text message method " + ReflectUtils.toString(endpoint.getClass(), method), e);
} }
return null; return null;
} }

View File

@ -33,19 +33,19 @@ import org.eclipse.jetty.websocket.common.util.ExactSignature;
import org.eclipse.jetty.websocket.common.util.ReflectUtils; import org.eclipse.jetty.websocket.common.util.ReflectUtils;
/** /**
* Jetty {@link WebSocket} {@link OnWebSocketMessage} method {@link Function} for TEXT/{@link String} types * Jetty {@link WebSocket} {@link OnWebSocketMessage} method {@link Function} for ARG_TEXT/{@link String} types
*/ */
public class OnTextFunction implements Function<String, Void> public class OnTextFunction implements Function<String, Void>
{ {
private static final DynamicArgs.Builder ARGBUILDER; private static final DynamicArgs.Builder ARGBUILDER;
private static final Arg SESSION = new Arg(1,Session.class); private static final Arg ARG_SESSION = new Arg(1, Session.class);
private static final Arg TEXT = new Arg(2,String.class); private static final Arg ARG_TEXT = new Arg(2, String.class);
static static
{ {
ARGBUILDER = new DynamicArgs.Builder(); ARGBUILDER = new DynamicArgs.Builder();
ARGBUILDER.addSignature(new ExactSignature(String.class)); ARGBUILDER.addSignature(new ExactSignature(ARG_TEXT));
ARGBUILDER.addSignature(new ExactSignature(Session.class,String.class)); ARGBUILDER.addSignature(new ExactSignature(ARG_SESSION, ARG_TEXT));
} }
public static DynamicArgs.Builder getDynamicArgsBuilder() public static DynamicArgs.Builder getDynamicArgsBuilder()
@ -69,14 +69,14 @@ public class OnTextFunction implements Function<String, Void>
this.endpoint = endpoint; this.endpoint = endpoint;
this.method = method; this.method = method;
ReflectUtils.assertIsAnnotated(method,OnWebSocketMessage.class); ReflectUtils.assertIsAnnotated(method, OnWebSocketMessage.class);
ReflectUtils.assertIsPublicNonStatic(method); ReflectUtils.assertIsPublicNonStatic(method);
ReflectUtils.assertIsReturn(method,Void.TYPE); ReflectUtils.assertIsReturn(method, Void.TYPE);
this.callable = ARGBUILDER.build(method,SESSION,TEXT); this.callable = ARGBUILDER.build(method, ARG_SESSION, ARG_TEXT);
if (this.callable == null) if (this.callable == null)
{ {
throw InvalidSignatureException.build(method,OnWebSocketMessage.class,ARGBUILDER); throw InvalidSignatureException.build(method, OnWebSocketMessage.class, ARGBUILDER);
} }
} }
@ -85,11 +85,11 @@ public class OnTextFunction implements Function<String, Void>
{ {
try try
{ {
this.callable.invoke(endpoint,session,text); this.callable.invoke(endpoint, session, text);
} }
catch (IllegalAccessException | IllegalArgumentException | InvocationTargetException e) catch (IllegalAccessException | IllegalArgumentException | InvocationTargetException e)
{ {
throw new WebSocketException("Unable to call text message method " + ReflectUtils.toString(endpoint.getClass(),method),e); throw new WebSocketException("Unable to call text message method " + ReflectUtils.toString(endpoint.getClass(), method), e);
} }
return null; return null;
} }

View File

@ -18,8 +18,6 @@
package org.eclipse.jetty.websocket.common.util; package org.eclipse.jetty.websocket.common.util;
import org.eclipse.jetty.util.annotation.Name;
import java.lang.annotation.Annotation; import java.lang.annotation.Annotation;
import java.lang.reflect.InvocationTargetException; import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method; import java.lang.reflect.Method;
@ -101,7 +99,7 @@ public class DynamicArgs
@Override @Override
public String toString() public String toString()
{ {
return String.format("%s[%d%s]",type.getSimpleName(),index,tag == null ? "" : "/" + tag); return String.format("%s[%d%s]",type.getName(),index,tag == null ? "" : "/" + tag);
} }
public <T extends Annotation> T getAnnotation(Class<T> annoClass) public <T extends Annotation> T getAnnotation(Class<T> annoClass)

View File

@ -22,7 +22,6 @@ import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method; import java.lang.reflect.Method;
import java.util.function.BiFunction; import java.util.function.BiFunction;
import java.util.function.BiPredicate; import java.util.function.BiPredicate;
import java.util.function.Predicate;
import org.eclipse.jetty.websocket.common.util.DynamicArgs.Arg; import org.eclipse.jetty.websocket.common.util.DynamicArgs.Arg;
import org.eclipse.jetty.websocket.common.util.DynamicArgs.Signature; import org.eclipse.jetty.websocket.common.util.DynamicArgs.Signature;
@ -41,17 +40,6 @@ public class ExactSignature implements Signature, BiPredicate<Method,Class<?>[]>
this.params = params; this.params = params;
} }
public ExactSignature(Class<?>... parameters)
{
int len = parameters.length;
this.params = new Arg[len];
for(int i=0; i<len; i++)
{
this.params[i] = new Arg(i, parameters[i]);
}
}
@Override @Override
public BiPredicate<Method,Class<?>[]> getPredicate() public BiPredicate<Method,Class<?>[]> getPredicate()
{ {

View File

@ -20,12 +20,9 @@ package org.eclipse.jetty.websocket.common.util;
import java.lang.reflect.InvocationTargetException; import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method; import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.List; import java.util.List;
import java.util.ServiceLoader;
import java.util.function.BiFunction; import java.util.function.BiFunction;
import java.util.function.BiPredicate; import java.util.function.BiPredicate;
import java.util.function.Predicate;
import org.eclipse.jetty.websocket.common.util.DynamicArgs.Arg; import org.eclipse.jetty.websocket.common.util.DynamicArgs.Arg;
import org.eclipse.jetty.websocket.common.util.DynamicArgs.Signature; import org.eclipse.jetty.websocket.common.util.DynamicArgs.Signature;
@ -34,7 +31,7 @@ public class UnorderedSignature implements Signature, BiPredicate<Method, Class<
{ {
private final Arg[] params; private final Arg[] params;
public UnorderedSignature(Arg ... args) public UnorderedSignature(Arg... args)
{ {
this.params = args; this.params = args;
} }
@ -113,43 +110,55 @@ public class UnorderedSignature implements Signature, BiPredicate<Method, Class<
@Override @Override
public BiFunction<Object, Object[], Object> getInvoker(Method method, Arg... callArgs) public BiFunction<Object, Object[], Object> getInvoker(Method method, Arg... callArgs)
{ {
int callArgsLen = callArgs.length;
// Figure out mapping of calling args to method args // Figure out mapping of calling args to method args
Class<?> paramTypes[] = method.getParameterTypes(); Class<?> paramTypes[] = method.getParameterTypes();
int paramTypesLength = paramTypes.length; int paramTypesLength = paramTypes.length;
// Method argument array pointing to index in calling array // Method argument array pointing to index in calling array
int argMapping[] = new int[paramTypesLength]; int argMapping[] = new int[paramTypesLength];
int callArgsLen = callArgs.length; int argMappingLength = argMapping.length;
// ServiceLoader for argument identification plugins
List<ArgIdentifier> argIdentifiers = DynamicArgs.lookupArgIdentifiers(); List<ArgIdentifier> argIdentifiers = DynamicArgs.lookupArgIdentifiers();
DynamicArgs.Arg methodArgs[] = new DynamicArgs.Arg[paramTypesLength];
for (int mi = 0; mi < paramTypesLength; mi++) for (int pi = 0; pi < paramTypesLength; pi++)
{ {
DynamicArgs.Arg methodArg = new DynamicArgs.Arg(method, mi, paramTypes[mi]); methodArgs[pi] = new DynamicArgs.Arg(method, pi, paramTypes[pi]);
// Supplement method argument identification from plugins
for (ArgIdentifier argId : argIdentifiers) for (ArgIdentifier argId : argIdentifiers)
methodArg = argId.apply(methodArg); methodArgs[pi] = argId.apply(methodArgs[pi]);
}
// Iterate through mappings, looking for a callArg that fits it
for (int ai = 0; ai < argMappingLength; ai++)
{
int ref = -1; int ref = -1;
// Find reference to argument in callArgs // Find reference to argument in callArgs
for (int ci = 0; ci < callArgsLen; ci++) for (int ci = 0; ci < callArgsLen; ci++)
{ {
if (methodArg.tag != null && methodArg.tag.equals(callArgs[ci].tag)) if (methodArgs[ai].tag != null && methodArgs[ai].tag.equals(callArgs[ci].tag))
{ {
ref = ci; ref = ci;
break;
} }
else if (methodArg.index == callArgs[ci].index) else if (methodArgs[ai].index == callArgs[ci].index)
{ {
ref = ci; ref = ci;
break;
} }
} }
if (ref < 0) if (ref < 0)
{ {
StringBuilder err = new StringBuilder(); StringBuilder err = new StringBuilder();
err.append("Unable to map type ["); err.append("Unable to map type [");
err.append(params[mi]); err.append(methodArgs[ai].type);
err.append("] in method "); err.append("] in method ");
ReflectUtils.append(err,method); ReflectUtils.append(err, method);
err.append(" to calling args: ("); err.append(" to calling args: (");
boolean delim = false; boolean delim = false;
for (Arg arg : callArgs) for (Arg arg : callArgs)
@ -163,7 +172,8 @@ public class UnorderedSignature implements Signature, BiPredicate<Method, Class<
throw new DynamicArgsException(err.toString()); throw new DynamicArgsException(err.toString());
} }
argMapping[mi] = ref;
argMapping[ai] = ref;
} }
// Return function capable of calling method // Return function capable of calling method
@ -175,13 +185,13 @@ public class UnorderedSignature implements Signature, BiPredicate<Method, Class<
} }
try try
{ {
return method.invoke(obj,args); return method.invoke(obj, args);
} }
catch (IllegalAccessException | IllegalArgumentException | InvocationTargetException e) catch (IllegalAccessException | IllegalArgumentException | InvocationTargetException e)
{ {
StringBuilder err = new StringBuilder(); StringBuilder err = new StringBuilder();
err.append("Unable to call: "); err.append("Unable to call: ");
ReflectUtils.append(err,obj.getClass(),method); ReflectUtils.append(err, obj.getClass(), method);
err.append(" [with "); err.append(" [with ");
boolean delim = false; boolean delim = false;
for (Object arg : args) for (Object arg : args)
@ -199,7 +209,7 @@ public class UnorderedSignature implements Signature, BiPredicate<Method, Class<
delim = true; delim = true;
} }
err.append("]"); err.append("]");
throw new DynamicArgsException(err.toString(),e); throw new DynamicArgsException(err.toString(), e);
} }
}; };
} }

View File

@ -155,22 +155,21 @@ public class MessageInputStreamTest
{ {
final AtomicBoolean hadError = new AtomicBoolean(false); final AtomicBoolean hadError = new AtomicBoolean(false);
new Thread(new Runnable() new Thread(() -> {
{ try
@Override
public void run()
{ {
try // wait for a little bit before sending input closed
{ TimeUnit.MILLISECONDS.sleep(400);
// wait for a little bit before sending input closed stream.close();
TimeUnit.MILLISECONDS.sleep(400); }
// TODO: stream.messageComplete(); catch (InterruptedException e)
} {
catch (InterruptedException e) hadError.set(true);
{ e.printStackTrace(System.err);
hadError.set(true); }
e.printStackTrace(System.err); catch (IOException e)
} {
e.printStackTrace(System.err);
} }
}).start(); }).start();
@ -180,7 +179,7 @@ public class MessageInputStreamTest
// Test it // Test it
Assert.assertThat("Error when appending",hadError.get(),is(false)); Assert.assertThat("Error when appending",hadError.get(),is(false));
Assert.assertThat("Initial byte",b,is(-1)); Assert.assertThat("Initial byte (Should be EOF)",b,is(-1));
} }
} }

View File

@ -58,12 +58,13 @@ public class MessageWriterTest
private WebSocketPolicy policy; private WebSocketPolicy policy;
private TrackingSocket remoteSocket; private TrackingSocket remoteSocket;
private WebSocketSession session; private WebSocketSession session;
private WebSocketSession remoteSession;
@After @After
public void closeSession() throws Exception public void closeSession() throws Exception
{ {
session.close(); session.close();
session.stop(); remoteSession.close();
} }
@Before @Before
@ -80,8 +81,9 @@ public class MessageWriterTest
remoteSocket = new TrackingSocket("remote"); remoteSocket = new TrackingSocket("remote");
URI remoteURI = new URI("ws://localhost/remote"); URI remoteURI = new URI("ws://localhost/remote");
LocalWebSocketConnection remoteConnection = new LocalWebSocketConnection(bufferPool); LocalWebSocketConnection remoteConnection = new LocalWebSocketConnection(bufferPool);
WebSocketSession remoteSession = new WebSocketSession(containerScope,remoteURI,remoteSocket,remoteConnection); remoteSession = new WebSocketSession(containerScope,remoteURI,remoteSocket,remoteConnection);
OutgoingFrames socketPipe = FramePipes.to(remoteSession); OutgoingFrames socketPipe = FramePipes.to(remoteSession);
remoteSession.open();
// Local Session // Local Session
TrackingSocket localSocket = new TrackingSocket("local"); TrackingSocket localSocket = new TrackingSocket("local");

View File

@ -39,12 +39,12 @@ public class ExactSignatureTest
public String sigStr(String str) public String sigStr(String str)
{ {
return String.format("sigStr<%s>",str); return String.format("sigStr<%s>", str);
} }
public String sigByteArray(byte[] buf, int offset, int len) public String sigByteArray(byte[] buf, int offset, int len)
{ {
return String.format("sigByteArray<%s,%d,%d>",buf == null ? "<null>" : ("[" + buf.length + "]"),offset,len); return String.format("sigByteArray<%s,%d,%d>", buf == null ? "<null>" : ("[" + buf.length + "]"), offset, len);
} }
} }
@ -60,12 +60,12 @@ public class ExactSignatureTest
throw new AssertionError("Unable to find method: " + name); throw new AssertionError("Unable to find method: " + name);
} }
private static final Arg ARG_STR = new Arg(1,String.class); private static final Arg ARG_STR = new Arg(1, String.class);
private static final Arg ARG_BOOL = new Arg(2,Boolean.class); private static final Arg ARG_BOOL = new Arg(2, Boolean.class);
private static final Arg ARG_FILE = new Arg(3,File.class); private static final Arg ARG_FILE = new Arg(3, File.class);
private static final Arg ARG_BYTEARRAY = new Arg(4,byte[].class); private static final Arg ARG_BYTEARRAY = new Arg(4, byte[].class);
private static final Arg ARG_OFFSET = new Arg(5,int.class); private static final Arg ARG_OFFSET = new Arg(5, int.class);
private static final Arg ARG_LEN = new Arg(6,int.class); private static final Arg ARG_LEN = new Arg(6, int.class);
@Test @Test
public void testEmptySignature() throws Exception public void testEmptySignature() throws Exception
@ -75,11 +75,11 @@ public class ExactSignatureTest
SampleSignatures ssigs = new SampleSignatures(); SampleSignatures ssigs = new SampleSignatures();
Method m = findMethodByName(ssigs, "sigEmpty"); Method m = findMethodByName(ssigs, "sigEmpty");
DynamicArgs dargs = dab.build(m,ARG_STR,ARG_BOOL,ARG_FILE); DynamicArgs dargs = dab.build(m, ARG_STR, ARG_BOOL, ARG_FILE);
assertThat("DynamicArgs", dargs, notNullValue()); assertThat("DynamicArgs", dargs, notNullValue());
// Test with potential args // Test with potential args
String result = (String)dargs.invoke(ssigs,"Hello", Boolean.TRUE, new File("bar")); String result = (String) dargs.invoke(ssigs, "Hello", Boolean.TRUE, new File("bar"));
assertThat("result", result, is("sigEmpty<>")); assertThat("result", result, is("sigEmpty<>"));
} }
@ -91,11 +91,11 @@ public class ExactSignatureTest
SampleSignatures ssigs = new SampleSignatures(); SampleSignatures ssigs = new SampleSignatures();
Method m = findMethodByName(ssigs, "sigStr"); Method m = findMethodByName(ssigs, "sigStr");
DynamicArgs dargs = dab.build(m,ARG_STR,ARG_BOOL,ARG_FILE); DynamicArgs dargs = dab.build(m, ARG_STR, ARG_BOOL, ARG_FILE);
assertThat("DynamicArgs", dargs, notNullValue()); assertThat("DynamicArgs", dargs, notNullValue());
// Test with potential args // Test with potential args
String result = (String)dargs.invoke(ssigs,"Hello", Boolean.TRUE, new File("bar")); String result = (String) dargs.invoke(ssigs, "Hello", Boolean.TRUE, new File("bar"));
assertThat("result", result, is("sigStr<Hello>")); assertThat("result", result, is("sigStr<Hello>"));
} }
@ -103,22 +103,22 @@ public class ExactSignatureTest
public void testByteArraySignature() throws Exception public void testByteArraySignature() throws Exception
{ {
DynamicArgs.Builder dab = new DynamicArgs.Builder(); DynamicArgs.Builder dab = new DynamicArgs.Builder();
dab.addSignature(new ExactSignature(ARG_BYTEARRAY,ARG_OFFSET,ARG_LEN)); dab.addSignature(new ExactSignature(ARG_BYTEARRAY, ARG_OFFSET, ARG_LEN));
SampleSignatures ssigs = new SampleSignatures(); SampleSignatures ssigs = new SampleSignatures();
Method m = findMethodByName(ssigs, "sigByteArray"); Method m = findMethodByName(ssigs, "sigByteArray");
DynamicArgs dargs = dab.build(m,ARG_BYTEARRAY,ARG_OFFSET,ARG_LEN); DynamicArgs dargs = dab.build(m, ARG_BYTEARRAY, ARG_OFFSET, ARG_LEN);
assertThat("DynamicArgs", dargs, notNullValue()); assertThat("DynamicArgs", dargs, notNullValue());
// Test with potential args // Test with potential args
byte buf[] = new byte[222]; byte buf[] = new byte[222];
int offset = 3; int offset = 3;
int len = 44; int len = 44;
String result = (String)dargs.invoke(ssigs,buf,offset,len); String result = (String) dargs.invoke(ssigs, buf, offset, len);
assertThat("result", result, is("sigByteArray<[222],3,44>")); assertThat("result", result, is("sigByteArray<[222],3,44>"));
// Test with empty potential args // Test with empty potential args
result = (String)dargs.invoke(ssigs,null,123,456); result = (String) dargs.invoke(ssigs, null, 123, 456);
assertThat("result", result, is("sigByteArray<<null>,123,456>")); assertThat("result", result, is("sigByteArray<<null>,123,456>"));
} }
} }

View File

@ -174,11 +174,11 @@ public class UnorderedSignatureTest
byte buf[] = new byte[222]; byte buf[] = new byte[222];
int offset = 3; int offset = 3;
int len = 44; int len = 44;
String result = (String)dargs.invoke(m,ssigs,buf,offset,len); String result = (String)dargs.invoke(ssigs,buf,offset,len);
assertThat("result", result, is("sigByteArray<[222],3,44>")); assertThat("result", result, is("sigByteArray<[222],3,44>"));
// Test with empty potential args // Test with empty potential args
result = (String)dargs.invoke(m,ssigs,null,123,456); result = (String)dargs.invoke(ssigs,null,123,456);
assertThat("result", result, is("sigByteArray<<null>,123,456>")); assertThat("result", result, is("sigByteArray<<null>,123,456>"));
} }
} }

View File

@ -5,3 +5,4 @@ org.eclipse.jetty.LEVEL=WARN
# org.eclipse.jetty.websocket.protocol.LEVEL=DEBUG # org.eclipse.jetty.websocket.protocol.LEVEL=DEBUG
# org.eclipse.jetty.websocket.io.payload.LEVEL=DEBUG # org.eclipse.jetty.websocket.io.payload.LEVEL=DEBUG
# org.eclipse.jetty.websocket.common.extensions.LEVEL=DEBUG # org.eclipse.jetty.websocket.common.extensions.LEVEL=DEBUG
# org.eclipse.jetty.websocket.common.message.LEVEL=DEBUG