Trailing merge fixes

This commit is contained in:
Joakim Erdfelt 2016-08-02 14:36:51 -07:00
parent 57bbf67735
commit b71be7c808
27 changed files with 663 additions and 649 deletions

View File

@ -0,0 +1,41 @@
//
// ========================================================================
// Copyright (c) 1995-2016 Mort Bay Consulting Pty. Ltd.
// ------------------------------------------------------------------------
// All rights reserved. This program and the accompanying materials
// are made available under the terms of the Eclipse Public License v1.0
// and Apache License v2.0 which accompanies this distribution.
//
// The Eclipse Public License is available at
// http://www.eclipse.org/legal/epl-v10.html
//
// The Apache License v2.0 is available at
// http://www.opensource.org/licenses/apache2.0.php
//
// You may elect to redistribute this code under either of these licenses.
// ========================================================================
//
package org.eclipse.jetty.util.component;
public final class CloseableLifeCycle<T extends LifeCycle> implements AutoCloseable
{
public T lifecycle;
public CloseableLifeCycle(T lifecycle) throws Exception
{
this.lifecycle = lifecycle;
this.lifecycle.start();
}
public T get()
{
return lifecycle;
}
@Override
public void close() throws Exception
{
lifecycle.stop();
}
}

View File

@ -47,7 +47,6 @@ import org.eclipse.jetty.websocket.common.InvalidSignatureException;
import org.eclipse.jetty.websocket.common.function.CommonEndpointFunctions;
import org.eclipse.jetty.websocket.common.reflect.Arg;
import org.eclipse.jetty.websocket.common.reflect.DynamicArgs;
import org.eclipse.jetty.websocket.common.reflect.UnorderedSignature;
import org.eclipse.jetty.websocket.common.util.ReflectUtils;
import org.eclipse.jetty.websocket.jsr356.JsrSession;
import org.eclipse.jetty.websocket.jsr356.decoders.AvailableDecoders;
@ -420,7 +419,7 @@ public class JsrEndpointFunctions extends CommonEndpointFunctions<JsrSession>
}
}
argBuilder.addSignature(new UnorderedSignature(callArgs));
argBuilder.addSignature(callArgs);
return argBuilder;
}

View File

@ -27,7 +27,6 @@ import javax.websocket.Session;
import org.eclipse.jetty.websocket.common.InvalidSignatureException;
import org.eclipse.jetty.websocket.common.reflect.Arg;
import org.eclipse.jetty.websocket.common.reflect.DynamicArgs;
import org.eclipse.jetty.websocket.common.reflect.UnorderedSignature;
import org.eclipse.jetty.websocket.common.util.ReflectUtils;
/**
@ -80,7 +79,7 @@ public class JsrOnByteArrayFunction implements Function<byte[], Void>
callArgs[idx++] = arg;
}
argBuilder.addSignature(new UnorderedSignature(callArgs));
argBuilder.addSignature(callArgs);
// Attempt to build callable
this.callable = argBuilder.build(method);

View File

@ -28,7 +28,6 @@ import javax.websocket.Session;
import org.eclipse.jetty.websocket.common.InvalidSignatureException;
import org.eclipse.jetty.websocket.common.reflect.Arg;
import org.eclipse.jetty.websocket.common.reflect.DynamicArgs;
import org.eclipse.jetty.websocket.common.reflect.UnorderedSignature;
import org.eclipse.jetty.websocket.common.util.ReflectUtils;
/**
@ -77,7 +76,7 @@ public class JsrOnByteBufferFunction implements Function<ByteBuffer, Void>
callArgs[idx++] = arg;
}
argBuilder.addSignature(new UnorderedSignature(callArgs));
argBuilder.addSignature(callArgs);
// Attempt to build callable
this.callable = argBuilder.build(method);

View File

@ -28,7 +28,6 @@ import javax.websocket.Session;
import org.eclipse.jetty.websocket.common.InvalidSignatureException;
import org.eclipse.jetty.websocket.common.reflect.Arg;
import org.eclipse.jetty.websocket.common.reflect.DynamicArgs;
import org.eclipse.jetty.websocket.common.reflect.UnorderedSignature;
import org.eclipse.jetty.websocket.common.util.ReflectUtils;
/**
@ -78,7 +77,7 @@ public class JsrOnInputStreamFunction implements Function<InputStream, Void>
callArgs[idx++] = arg;
}
argBuilder.addSignature(new UnorderedSignature(callArgs));
argBuilder.addSignature(callArgs);
// Attempt to build callable
this.callable = argBuilder.build(method, callArgs);

View File

@ -18,8 +18,11 @@
package org.eclipse.jetty.websocket.jsr356.server;
import static org.hamcrest.Matchers.is;
import static org.junit.Assert.assertThat;
import java.net.URI;
import java.util.Set;
import java.util.Collection;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.TimeUnit;
@ -33,129 +36,22 @@ import javax.websocket.server.ServerEndpoint;
import org.eclipse.jetty.server.Server;
import org.eclipse.jetty.server.ServerConnector;
import org.eclipse.jetty.servlet.ServletContextHandler;
import org.eclipse.jetty.util.thread.QueuedThreadPool;
import org.eclipse.jetty.util.StringUtil;
import org.eclipse.jetty.websocket.common.WebSocketSession;
import org.eclipse.jetty.websocket.jsr356.ClientContainer;
import org.eclipse.jetty.websocket.jsr356.server.deploy.WebSocketServerContainerInitializer;
import org.eclipse.jetty.websocket.server.WebSocketServerFactory;
import org.hamcrest.Matchers;
import org.junit.After;
import org.junit.Assert;
import org.junit.Before;
import org.junit.AfterClass;
import org.junit.BeforeClass;
import org.junit.Test;
public class SessionTrackingTest
{
private Server server;
private ServerContainer serverContainer;
private WebSocketServerFactory wsServerFactory;
private URI serverURI;
@Before
public void startServer() throws Exception
public static class ClientSocket extends Endpoint
{
QueuedThreadPool serverThreads = new QueuedThreadPool();
serverThreads.setName("server");
server = new Server(serverThreads);
ServerConnector serverConnector = new ServerConnector(server);
serverConnector.setPort(0);
server.addConnector(serverConnector);
ServletContextHandler servletContextHandler = new ServletContextHandler(ServletContextHandler.NO_SESSIONS);
servletContextHandler.setContextPath("/");
server.setHandler(servletContextHandler);
serverContainer = WebSocketServerContainerInitializer.configureContext(servletContextHandler);
serverContainer.addEndpoint(EchoSocket.class);
wsServerFactory = serverContainer.getBean(WebSocketServerFactory.class);
server.start();
serverURI = new URI("ws://localhost:" + serverConnector.getLocalPort());
}
@After
public void stopServer() throws Exception
{
if (server != null)
server.stop();
}
@Test
public void testAddRemoveSessions() throws Exception
{
// Create Client
ClientContainer clientContainer = new ClientContainer();
QueuedThreadPool clientThreads = new QueuedThreadPool();
clientThreads.setName("client");
clientContainer.getClient().setExecutor(clientThreads);
try
{
CountDownLatch openedLatch = new CountDownLatch(2);
CountDownLatch closedLatch = new CountDownLatch(2);
wsServerFactory.addSessionListener(new WebSocketSession.Listener()
{
@Override
public void onOpened(WebSocketSession session)
{
openedLatch.countDown();
}
@Override
public void onClosed(WebSocketSession session)
{
closedLatch.countDown();
}
});
clientContainer.start();
// Establish connections
ClientSocket cli1 = new ClientSocket();
clientContainer.connectToServer(cli1, serverURI.resolve("/test"));
cli1.waitForOpen(1, TimeUnit.SECONDS);
// Establish new connection
ClientSocket cli2 = new ClientSocket();
clientContainer.connectToServer(cli2, serverURI.resolve("/test"));
cli2.waitForOpen(1, TimeUnit.SECONDS);
openedLatch.await(5, TimeUnit.SECONDS);
assertServerOpenConnectionCount(2);
// Establish close both connections
cli1.session.close();
cli2.session.close();
cli1.waitForClose(1, TimeUnit.SECONDS);
cli2.waitForClose(1, TimeUnit.SECONDS);
closedLatch.await(5, TimeUnit.SECONDS);
assertServerOpenConnectionCount(0);
}
finally
{
clientContainer.stop();
}
}
private void assertServerOpenConnectionCount(int expectedCount)
{
Set<Session> sessions = serverContainer.getOpenSessions();
int openCount = 0;
for (Session session : sessions)
{
Assert.assertThat("Session.isopen: " + session, session.isOpen(), Matchers.is(true));
openCount++;
}
Assert.assertThat("Open Session Count", openCount, Matchers.is(expectedCount));
}
private static class ClientSocket extends Endpoint
{
private Session session;
private CountDownLatch openLatch = new CountDownLatch(1);
private CountDownLatch closeLatch = new CountDownLatch(1);
public Session session;
public CountDownLatch openLatch = new CountDownLatch(1);
public CountDownLatch closeLatch = new CountDownLatch(1);
@Override
public void onOpen(Session session, EndpointConfig config)
@ -172,12 +68,12 @@ public class SessionTrackingTest
public void waitForOpen(long timeout, TimeUnit unit) throws InterruptedException
{
Assert.assertThat("ClientSocket opened", openLatch.await(timeout, unit), Matchers.is(true));
assertThat("ClientSocket opened",openLatch.await(timeout,unit),is(true));
}
public void waitForClose(long timeout, TimeUnit unit) throws InterruptedException
{
Assert.assertThat("ClientSocket opened", closeLatch.await(timeout, unit), Matchers.is(true));
assertThat("ClientSocket opened",closeLatch.await(timeout,unit),is(true));
}
}
@ -190,4 +86,98 @@ public class SessionTrackingTest
return msg;
}
}
private static Server server;
private static WebSocketServerFactory wsServerFactory;
private static URI serverURI;
@BeforeClass
public static void startServer() throws Exception
{
Server server = new Server();
ServerConnector serverConnector = new ServerConnector(server);
serverConnector.setPort(0);
server.addConnector(serverConnector);
ServletContextHandler servletContextHandler = new ServletContextHandler(ServletContextHandler.NO_SESSIONS);
servletContextHandler.setContextPath("/");
server.setHandler(servletContextHandler);
ServerContainer serverContainer = WebSocketServerContainerInitializer.configureContext(servletContextHandler);
serverContainer.addEndpoint(EchoSocket.class);
wsServerFactory = serverContainer.getBean(WebSocketServerFactory.class);
server.start();
String host = serverConnector.getHost();
if (StringUtil.isBlank(host))
{
host = "localhost";
}
serverURI = new URI("ws://" + host + ":" + serverConnector.getLocalPort());
}
@AfterClass
public static void stopServer() throws Exception
{
if (server == null)
{
return;
}
server.stop();
}
@Test
public void testAddRemoveSessions() throws Exception
{
// Create Client
ClientContainer clientContainer = new ClientContainer();
try
{
clientContainer.start();
// Establish connections
ClientSocket cli1 = new ClientSocket();
clientContainer.connectToServer(cli1,serverURI.resolve("/test"));
cli1.waitForOpen(1,TimeUnit.SECONDS);
// Assert open connections
assertServerOpenConnectionCount(1);
// Establish new connection
ClientSocket cli2 = new ClientSocket();
clientContainer.connectToServer(cli2,serverURI.resolve("/test"));
cli2.waitForOpen(1,TimeUnit.SECONDS);
// Assert open connections
assertServerOpenConnectionCount(2);
// Establish close both connections
cli1.session.close();
cli2.session.close();
cli1.waitForClose(1,TimeUnit.SECONDS);
cli2.waitForClose(1,TimeUnit.SECONDS);
// Assert open connections
assertServerOpenConnectionCount(0);
}
finally
{
clientContainer.stop();
}
}
private void assertServerOpenConnectionCount(int expectedCount)
{
Collection<javax.websocket.Session> sessions = wsServerFactory.getBeans(javax.websocket.Session.class);
int openCount = 0;
for (javax.websocket.Session session : sessions)
{
assertThat("Session.isopen: " + session,session.isOpen(),is(true));
openCount++;
}
assertThat("Open Session Count",openCount,is(expectedCount));
}
}

View File

@ -27,7 +27,6 @@ import org.eclipse.jetty.websocket.api.annotations.WebSocket;
import org.eclipse.jetty.websocket.common.InvalidSignatureException;
import org.eclipse.jetty.websocket.common.reflect.Arg;
import org.eclipse.jetty.websocket.common.reflect.DynamicArgs;
import org.eclipse.jetty.websocket.common.reflect.ExactSignature;
import org.eclipse.jetty.websocket.common.util.ReflectUtils;
/**
@ -37,17 +36,14 @@ public class OnByteArrayFunction implements Function<byte[], Void>
{
private static final DynamicArgs.Builder ARGBUILDER;
private static final Arg ARG_SESSION = new Arg(1, Session.class);
private static final Arg ARG_BUFFER = new Arg(2, byte[].class);
private static final Arg ARG_BUFFER = new Arg(2, byte[].class).required();
private static final Arg ARG_OFFSET = new Arg(3, int.class);
private static final Arg ARG_LENGTH = new Arg(4, int.class);
static
{
ARGBUILDER = new DynamicArgs.Builder();
ARGBUILDER.addSignature(new ExactSignature(ARG_BUFFER));
ARGBUILDER.addSignature(new ExactSignature(ARG_BUFFER, ARG_OFFSET, ARG_LENGTH));
ARGBUILDER.addSignature(new ExactSignature(ARG_SESSION, ARG_BUFFER));
ARGBUILDER.addSignature(new ExactSignature(ARG_SESSION, ARG_BUFFER, ARG_OFFSET, ARG_LENGTH));
ARGBUILDER.addSignature(ARG_SESSION, ARG_BUFFER, ARG_OFFSET, ARG_LENGTH);
}
public static DynamicArgs.Builder getDynamicArgsBuilder()

View File

@ -28,7 +28,6 @@ import org.eclipse.jetty.websocket.api.annotations.WebSocket;
import org.eclipse.jetty.websocket.common.InvalidSignatureException;
import org.eclipse.jetty.websocket.common.reflect.Arg;
import org.eclipse.jetty.websocket.common.reflect.DynamicArgs;
import org.eclipse.jetty.websocket.common.reflect.ExactSignature;
import org.eclipse.jetty.websocket.common.util.ReflectUtils;
/**
@ -38,13 +37,12 @@ public class OnByteBufferFunction implements Function<ByteBuffer, Void>
{
private static final DynamicArgs.Builder ARGBUILDER;
private static final Arg ARG_SESSION = new Arg(1, Session.class);
private static final Arg ARG_BUFFER = new Arg(2, ByteBuffer.class);
private static final Arg ARG_BUFFER = new Arg(2, ByteBuffer.class).required();
static
{
ARGBUILDER = new DynamicArgs.Builder();
ARGBUILDER.addSignature(new ExactSignature(ARG_BUFFER));
ARGBUILDER.addSignature(new ExactSignature(ARG_SESSION, ARG_BUFFER));
ARGBUILDER.addSignature(ARG_SESSION, ARG_BUFFER);
}
public static DynamicArgs.Builder getDynamicArgsBuilder()

View File

@ -28,7 +28,6 @@ import org.eclipse.jetty.websocket.common.CloseInfo;
import org.eclipse.jetty.websocket.common.InvalidSignatureException;
import org.eclipse.jetty.websocket.common.reflect.Arg;
import org.eclipse.jetty.websocket.common.reflect.DynamicArgs;
import org.eclipse.jetty.websocket.common.reflect.ExactSignature;
import org.eclipse.jetty.websocket.common.util.ReflectUtils;
/**
@ -44,10 +43,7 @@ public class OnCloseFunction implements Function<CloseInfo, Void>
static
{
ARGBUILDER = new DynamicArgs.Builder();
ARGBUILDER.addSignature(new ExactSignature());
ARGBUILDER.addSignature(new ExactSignature(ARG_SESSION));
ARGBUILDER.addSignature(new ExactSignature(ARG_STATUS_CODE, ARG_REASON));
ARGBUILDER.addSignature(new ExactSignature(ARG_SESSION, ARG_STATUS_CODE, ARG_REASON));
ARGBUILDER.addSignature(ARG_SESSION, ARG_STATUS_CODE, ARG_REASON);
}
private final Session session;

View File

@ -27,7 +27,6 @@ import org.eclipse.jetty.websocket.api.annotations.WebSocket;
import org.eclipse.jetty.websocket.common.InvalidSignatureException;
import org.eclipse.jetty.websocket.common.reflect.Arg;
import org.eclipse.jetty.websocket.common.reflect.DynamicArgs;
import org.eclipse.jetty.websocket.common.reflect.ExactSignature;
import org.eclipse.jetty.websocket.common.util.ReflectUtils;
/**
@ -37,13 +36,12 @@ public class OnErrorFunction implements Function<Throwable, Void>
{
private static final DynamicArgs.Builder ARGBUILDER;
private static final Arg ARG_SESSION = new Arg(1, Session.class);
private static final Arg ARG_CAUSE = new Arg(2, Throwable.class);
private static final Arg ARG_CAUSE = new Arg(2, Throwable.class).required();
static
{
ARGBUILDER = new DynamicArgs.Builder();
ARGBUILDER.addSignature(new ExactSignature(ARG_CAUSE));
ARGBUILDER.addSignature(new ExactSignature(ARG_SESSION, ARG_CAUSE));
ARGBUILDER.addSignature(ARG_SESSION, ARG_CAUSE);
}
private final Session session;

View File

@ -29,7 +29,6 @@ import org.eclipse.jetty.websocket.common.InvalidSignatureException;
import org.eclipse.jetty.websocket.common.WebSocketFrame;
import org.eclipse.jetty.websocket.common.reflect.Arg;
import org.eclipse.jetty.websocket.common.reflect.DynamicArgs;
import org.eclipse.jetty.websocket.common.reflect.ExactSignature;
import org.eclipse.jetty.websocket.common.util.ReflectUtils;
/**
@ -39,13 +38,12 @@ public class OnFrameFunction implements Function<Frame, Void>
{
private static final DynamicArgs.Builder ARGBUILDER;
private static final Arg ARG_SESSION = new Arg(1, Session.class);
private static final Arg ARG_FRAME = new Arg(2, Frame.class);
private static final Arg ARG_FRAME = new Arg(2, Frame.class).required();
static
{
ARGBUILDER = new DynamicArgs.Builder();
ARGBUILDER.addSignature(new ExactSignature(ARG_FRAME));
ARGBUILDER.addSignature(new ExactSignature(ARG_SESSION, ARG_FRAME));
ARGBUILDER.addSignature(ARG_SESSION, ARG_FRAME);
}
private final Session session;

View File

@ -28,7 +28,6 @@ import org.eclipse.jetty.websocket.api.annotations.WebSocket;
import org.eclipse.jetty.websocket.common.InvalidSignatureException;
import org.eclipse.jetty.websocket.common.reflect.Arg;
import org.eclipse.jetty.websocket.common.reflect.DynamicArgs;
import org.eclipse.jetty.websocket.common.reflect.ExactSignature;
import org.eclipse.jetty.websocket.common.util.ReflectUtils;
/**
@ -39,13 +38,12 @@ public class OnInputStreamFunction implements Function<InputStream, Void>
{
private static final DynamicArgs.Builder ARGBUILDER;
private static final Arg ARG_SESSION = new Arg(1, Session.class);
private static final Arg ARG_STREAM = new Arg(2, InputStream.class);
private static final Arg ARG_STREAM = new Arg(2, InputStream.class).required();
static
{
ARGBUILDER = new DynamicArgs.Builder();
ARGBUILDER.addSignature(new ExactSignature(ARG_STREAM));
ARGBUILDER.addSignature(new ExactSignature(ARG_SESSION, ARG_STREAM));
ARGBUILDER.addSignature(ARG_SESSION, ARG_STREAM);
}
public static DynamicArgs.Builder getDynamicArgsBuilder()

View File

@ -27,7 +27,6 @@ import org.eclipse.jetty.websocket.api.annotations.WebSocket;
import org.eclipse.jetty.websocket.common.InvalidSignatureException;
import org.eclipse.jetty.websocket.common.reflect.Arg;
import org.eclipse.jetty.websocket.common.reflect.DynamicArgs;
import org.eclipse.jetty.websocket.common.reflect.ExactSignature;
import org.eclipse.jetty.websocket.common.util.ReflectUtils;
/**
@ -36,13 +35,12 @@ import org.eclipse.jetty.websocket.common.util.ReflectUtils;
public class OnOpenFunction<T extends Session> implements Function<T, Void>
{
private static final DynamicArgs.Builder ARGBUILDER;
private static final Arg ARG_SESSION = new Arg(1, Session.class);
private static final Arg ARG_SESSION = new Arg(1, Session.class).required();
static
{
ARGBUILDER = new DynamicArgs.Builder();
ARGBUILDER.addSignature(new ExactSignature());
ARGBUILDER.addSignature(new ExactSignature(ARG_SESSION));
ARGBUILDER.addSignature(ARG_SESSION);
}
private final Object endpoint;

View File

@ -20,15 +20,17 @@ package org.eclipse.jetty.websocket.common.function;
import java.io.Reader;
import java.lang.reflect.Method;
import java.util.Objects;
import java.util.function.Function;
import org.eclipse.jetty.util.log.Log;
import org.eclipse.jetty.util.log.Logger;
import org.eclipse.jetty.websocket.api.Session;
import org.eclipse.jetty.websocket.api.annotations.OnWebSocketMessage;
import org.eclipse.jetty.websocket.api.annotations.WebSocket;
import org.eclipse.jetty.websocket.common.InvalidSignatureException;
import org.eclipse.jetty.websocket.common.reflect.Arg;
import org.eclipse.jetty.websocket.common.reflect.DynamicArgs;
import org.eclipse.jetty.websocket.common.reflect.ExactSignature;
import org.eclipse.jetty.websocket.common.util.ReflectUtils;
/**
@ -36,15 +38,15 @@ import org.eclipse.jetty.websocket.common.util.ReflectUtils;
*/
public class OnReaderFunction implements Function<Reader, Void>
{
private static final Logger LOG = Log.getLogger(OnReaderFunction.class);
private static final DynamicArgs.Builder ARGBUILDER;
private static final Arg ARG_SESSION = new Arg(1, Session.class);
private static final Arg ARG_STREAM = new Arg(2, Reader.class);
private static final Arg ARG_STREAM = new Arg(2, Reader.class).required();
static
{
ARGBUILDER = new DynamicArgs.Builder();
ARGBUILDER.addSignature(new ExactSignature(ARG_STREAM));
ARGBUILDER.addSignature(new ExactSignature(ARG_SESSION, ARG_STREAM));
ARGBUILDER.addSignature(ARG_STREAM, ARG_SESSION);
}
public static DynamicArgs.Builder getDynamicArgsBuilder()
@ -82,6 +84,11 @@ public class OnReaderFunction implements Function<Reader, Void>
@Override
public Void apply(Reader stream)
{
if (LOG.isDebugEnabled())
LOG.debug("apply({}, {}, {})", endpoint, session, stream);
Objects.requireNonNull(stream, "Reader cannot be null");
this.callable.invoke(endpoint, session, stream);
return null;
}

View File

@ -27,7 +27,6 @@ import org.eclipse.jetty.websocket.api.annotations.WebSocket;
import org.eclipse.jetty.websocket.common.InvalidSignatureException;
import org.eclipse.jetty.websocket.common.reflect.Arg;
import org.eclipse.jetty.websocket.common.reflect.DynamicArgs;
import org.eclipse.jetty.websocket.common.reflect.ExactSignature;
import org.eclipse.jetty.websocket.common.util.ReflectUtils;
/**
@ -37,13 +36,12 @@ public class OnTextFunction implements Function<String, Void>
{
private static final DynamicArgs.Builder ARGBUILDER;
private static final Arg ARG_SESSION = new Arg(1, Session.class);
private static final Arg ARG_TEXT = new Arg(2, String.class);
private static final Arg ARG_TEXT = new Arg(2, String.class).required();
static
{
ARGBUILDER = new DynamicArgs.Builder();
ARGBUILDER.addSignature(new ExactSignature(ARG_TEXT));
ARGBUILDER.addSignature(new ExactSignature(ARG_SESSION, ARG_TEXT));
ARGBUILDER.addSignature(ARG_TEXT, ARG_SESSION);
}
public static DynamicArgs.Builder getDynamicArgsBuilder()

View File

@ -23,8 +23,12 @@ import java.nio.ByteBuffer;
import java.util.concurrent.Executor;
import java.util.function.Function;
import org.eclipse.jetty.util.log.Log;
import org.eclipse.jetty.util.log.Logger;
public class ReaderMessageSink implements MessageSink
{
private static final Logger LOG = Log.getLogger(ReaderMessageSink.class);
private final Executor executor;
private final Function<Reader, Void> onStreamFunction;
private MessageReader stream;
@ -54,6 +58,8 @@ public class ReaderMessageSink implements MessageSink
executor.execute(() -> {
// processing of errors is the responsibility
// of the stream function
if(LOG.isDebugEnabled())
LOG.debug("onStreamFunction.apply({})", stream);
onStreamFunction.apply(stream);
});
}
@ -62,7 +68,11 @@ public class ReaderMessageSink implements MessageSink
{
if (fin)
{
if(LOG.isDebugEnabled())
LOG.debug("stream.awaitClose() - {}", stream);
stream.awaitClose();
if(LOG.isDebugEnabled())
LOG.debug("stream recycled - {}", stream);
stream = null;
}
}

View File

@ -123,9 +123,9 @@ public class DynamicArgs
return null;
}
public Builder addSignature(Signature sig)
public Builder addSignature(Arg... args)
{
signatures.add(sig);
signatures.add(new UnorderedSignature(args));
return this;
}

View File

@ -1,173 +0,0 @@
//
// ========================================================================
// Copyright (c) 1995-2016 Mort Bay Consulting Pty. Ltd.
// ------------------------------------------------------------------------
// All rights reserved. This program and the accompanying materials
// are made available under the terms of the Eclipse Public License v1.0
// and Apache License v2.0 which accompanies this distribution.
//
// The Eclipse Public License is available at
// http://www.eclipse.org/legal/epl-v10.html
//
// The Apache License v2.0 is available at
// http://www.opensource.org/licenses/apache2.0.php
//
// You may elect to redistribute this code under either of these licenses.
// ========================================================================
//
package org.eclipse.jetty.websocket.common.reflect;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.function.BiFunction;
import java.util.function.Predicate;
import org.eclipse.jetty.websocket.common.reflect.DynamicArgs.Signature;
import org.eclipse.jetty.websocket.common.util.ReflectUtils;
public class ExactSignature implements Signature, Predicate<Method>
{
private final Arg[] params;
public ExactSignature()
{
this.params = new Arg[0];
}
public ExactSignature(Arg... params)
{
this.params = params;
}
@Override
public Predicate<Method> getPredicate()
{
return this;
}
@Override
public Arg[] getCallArgs()
{
return this.params;
}
@Override
public boolean test(Method method)
{
Class<?>[] types = method.getParameterTypes();
if (types.length != params.length)
return false;
int len = params.length;
for (int i = 0; i < len; i++)
{
if (!params[i].getType().equals(types[i]))
return false;
}
return true;
}
public void appendDescription(StringBuilder str)
{
str.append('(');
boolean delim = false;
for (Arg arg : params)
{
if (delim)
{
str.append(',');
}
str.append(' ');
str.append(arg.getName());
if (arg.isArray())
{
str.append("[]");
}
delim = true;
}
str.append(')');
}
@Override
public BiFunction<Object, Object[], Object> getInvoker(Method method, Arg... callArgs)
{
// Figure out mapping of calling args to method args
Class<?> paramTypes[] = method.getParameterTypes();
int paramTypesLength = paramTypes.length;
// Method argument array pointing to index in calling array
int argMapping[] = new int[paramTypesLength];
int callArgsLen = callArgs.length;
for (int mi = 0; mi < paramTypesLength; mi++)
{
int ref = -1;
// Find reference to argument in callArgs
for (int ci = 0; ci < callArgsLen; ci++)
{
if (callArgs[ci].getIndex() == params[mi].getIndex())
{
ref = ci;
}
}
if (ref < 0)
{
StringBuilder err = new StringBuilder();
err.append("Unable to map type [");
err.append(params[mi]);
err.append("] in method ");
ReflectUtils.append(err,method);
err.append(" to calling args: (");
boolean delim = false;
for (Arg arg : callArgs)
{
if (delim)
err.append(", ");
err.append(arg);
delim = true;
}
err.append(")");
throw new DynamicArgsException(err.toString());
}
argMapping[mi] = ref;
}
// Return function capable of calling method
return (obj, potentialArgs) -> {
Object args[] = new Object[paramTypesLength];
for (int i = 0; i < paramTypesLength; i++)
{
args[i] = potentialArgs[argMapping[i]];
}
try
{
return method.invoke(obj,args);
}
catch (IllegalAccessException | IllegalArgumentException | InvocationTargetException e)
{
StringBuilder err = new StringBuilder();
err.append("Unable to call: ");
ReflectUtils.append(err,obj.getClass(),method);
err.append(" [with ");
boolean delim = false;
for (Object arg : args)
{
if (delim)
err.append(", ");
if (arg == null)
{
err.append("<null>");
}
else
{
err.append(arg.getClass().getSimpleName());
}
delim = true;
}
err.append("]");
throw new DynamicArgsException(err.toString(),e);
}
};
}
}

View File

@ -29,34 +29,34 @@ import org.eclipse.jetty.util.log.Logger;
import org.eclipse.jetty.websocket.common.reflect.DynamicArgs.Signature;
import org.eclipse.jetty.websocket.common.util.ReflectUtils;
public class UnorderedSignature implements Signature, Predicate<Method>
class UnorderedSignature implements Signature, Predicate<Method>
{
private final static Logger LOG = Log.getLogger(UnorderedSignature.class);
private final Arg[] params;
public UnorderedSignature(Arg... args)
{
this.params = args;
}
@Override
public Arg[] getCallArgs()
{
return this.params;
}
@Override
public Predicate<Method> getPredicate()
{
return this;
}
@Override
public boolean test(Method method)
{
return getArgMapping(method, false, params) != null;
}
public void appendDescription(StringBuilder str)
{
str.append('(');
@ -77,36 +77,52 @@ public class UnorderedSignature implements Signature, Predicate<Method>
}
str.append(')');
}
private int[] getArgMapping(Method method, boolean throwOnFailure, Arg... callArgs)
/**
* Identify mapping of argument indexes of the callArgs to method Args.
* <p>
* The callArgs is what the websocket implementation code is
* using to call the method.
* </p>
* <p>
* The method Args are what the user endpoint method args
* are declared as.
* </p>
*
* @param method the method that we want to eventually call
* @param throwOnFailure true to toss a {@link DynamicArgsException} if there is a problem
* attempting to identify the mapping. false to debug log the issue.
* @param callArgs the calling args for this signature
*/
public int[] getArgMapping(Method method, boolean throwOnFailure, Arg... callArgs)
{
int callArgsLen = callArgs.length;
// Figure out mapping of calling args to method args
Class<?> paramTypes[] = method.getParameterTypes();
int paramTypesLength = paramTypes.length;
// Method argument array pointing to index in calling array
int argMapping[] = new int[paramTypesLength];
int argMappingLength = argMapping.length;
// ServiceLoader for argument identification plugins
List<ArgIdentifier> argIdentifiers = DynamicArgs.lookupArgIdentifiers();
Arg methodArgs[] = new Arg[paramTypesLength];
for (int pi = 0; pi < paramTypesLength; pi++)
{
methodArgs[pi] = new Arg(method, pi, paramTypes[pi]);
// Supplement method argument identification from plugins
for (ArgIdentifier argId : argIdentifiers)
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;
// Find reference to argument in callArgs
for (int ci = 0; ci < callArgsLen; ci++)
{
@ -116,7 +132,7 @@ public class UnorderedSignature implements Signature, Predicate<Method>
break;
}
}
if (ref < 0)
{
StringBuilder err = new StringBuilder();
@ -134,19 +150,24 @@ public class UnorderedSignature implements Signature, Predicate<Method>
delim = true;
}
err.append(")");
if (throwOnFailure)
{
throw new DynamicArgsException(err.toString());
}
else
{
LOG.debug("{}", err.toString());
if (LOG.isDebugEnabled())
{
LOG.debug("{}", err.toString());
}
return null;
}
}
argMapping[ai] = ref;
}
// Ensure that required arguments are present in the mapping
for (int ci = 0; ci < callArgsLen; ci++)
{
@ -168,7 +189,7 @@ public class UnorderedSignature implements Signature, Predicate<Method>
err.append(callArgs[ci].getType());
err.append("] in method ");
ReflectUtils.append(err, method);
if (throwOnFailure)
throw new DynamicArgsException(err.toString());
else
@ -179,33 +200,33 @@ public class UnorderedSignature implements Signature, Predicate<Method>
}
}
}
return argMapping;
}
@Override
public BiFunction<Object, Object[], Object> getInvoker(Method method, Arg... callArgs)
{
int argMapping[] = getArgMapping(method, true, callArgs);
// Return function capable of calling method
return new UnorderedParamsFunction(method, argMapping);
}
public static class UnorderedParamsFunction
implements BiFunction<Object, Object[], Object>
{
private final Method method;
private final int paramTypesLength;
private final int argMapping[];
public UnorderedParamsFunction(Method method, int argMapping[])
{
this.method = method;
this.paramTypesLength = method.getParameterTypes().length;
this.argMapping = argMapping;
}
@Override
public Object apply(Object obj, Object[] potentialArgs)
{
@ -244,5 +265,5 @@ public class UnorderedSignature implements Signature, Predicate<Method>
}
}
}
}

View File

@ -32,6 +32,7 @@ import java.util.concurrent.TimeUnit;
import org.eclipse.jetty.util.BufferUtil;
import org.eclipse.jetty.util.IO;
import org.eclipse.jetty.util.component.CloseableLifeCycle;
import org.eclipse.jetty.websocket.api.Session;
import org.eclipse.jetty.websocket.api.StatusCode;
import org.eclipse.jetty.websocket.api.WebSocketConnectionListener;
@ -84,17 +85,21 @@ public class CommonEndpointFunctionsTest
}
@Test
public void testWebSocketConnectionListener_OpenTextClose()
public void testWebSocketConnectionListener_OpenTextClose() throws Exception
{
// Setup
ConnectionOnly socket = new ConnectionOnly();
Session session = initSession(socket);
EndpointFunctions<Session> endpointFunctions = new CommonEndpointFunctions(socket, containerScope.getPolicy(), containerScope.getExecutor());
try (CloseableLifeCycle<CommonEndpointFunctions> lifecycle = new CloseableLifeCycle<>(
new CommonEndpointFunctions(socket, containerScope.getPolicy(), containerScope.getExecutor())))
{
EndpointFunctions<Session> endpointFunctions = lifecycle.get();
// Trigger Events
endpointFunctions.onOpen(session);
endpointFunctions.onText(BufferUtil.toBuffer("Hello World", UTF8), true);
endpointFunctions.onClose(new CloseInfo(StatusCode.NORMAL, "Normal"));
// Trigger Events
endpointFunctions.onOpen(session);
endpointFunctions.onText(BufferUtil.toBuffer("Hello World", UTF8), true);
endpointFunctions.onClose(new CloseInfo(StatusCode.NORMAL, "Normal"));
}
// Validate Events
socket.assertCaptured(
@ -118,17 +123,21 @@ public class CommonEndpointFunctionsTest
}
@Test
public void testWebSocketListener_OpenTextClose()
public void testWebSocketListener_OpenTextClose() throws Exception
{
// Setup
DataConnection socket = new DataConnection();
Session session = initSession(socket);
EndpointFunctions<Session> endpointFunctions = new CommonEndpointFunctions(socket, containerScope.getPolicy(), containerScope.getExecutor());
try (CloseableLifeCycle<CommonEndpointFunctions> lifecycle = new CloseableLifeCycle<>(
new CommonEndpointFunctions(socket, containerScope.getPolicy(), containerScope.getExecutor())))
{
EndpointFunctions<Session> endpointFunctions = lifecycle.get();
// Trigger Events
endpointFunctions.onOpen(session);
endpointFunctions.onText(BufferUtil.toBuffer("Hello World", UTF8), true);
endpointFunctions.onClose(new CloseInfo(StatusCode.NORMAL, "Normal"));
// Trigger Events
endpointFunctions.onOpen(session);
endpointFunctions.onText(BufferUtil.toBuffer("Hello World", UTF8), true);
endpointFunctions.onClose(new CloseInfo(StatusCode.NORMAL, "Normal"));
}
// Validate Events
socket.assertCaptured(
@ -160,18 +169,22 @@ public class CommonEndpointFunctionsTest
}
}
@Test
public void testAnnotatedStreamedText_Single() throws InterruptedException
@Test(timeout = 1000)
public void testAnnotatedStreamedText_Single() throws Exception
{
// Setup
StreamedText socket = new StreamedText(1);
Session session = initSession(socket);
EndpointFunctions<Session> endpointFunctions = new CommonEndpointFunctions(socket, containerScope.getPolicy(), containerScope.getExecutor());
// Trigger Events
endpointFunctions.onOpen(session);
endpointFunctions.onText(BufferUtil.toBuffer("Hello World", UTF8), true);
endpointFunctions.onClose(new CloseInfo(StatusCode.NORMAL, "Normal"));
try (CloseableLifeCycle<CommonEndpointFunctions> lifecycle = new CloseableLifeCycle<>(
new CommonEndpointFunctions(socket, containerScope.getPolicy(), containerScope.getExecutor())))
{
EndpointFunctions<Session> endpointFunctions = lifecycle.get();
// Trigger Events
endpointFunctions.onOpen(session);
endpointFunctions.onText(BufferUtil.toBuffer("Hello World", UTF8), true);
endpointFunctions.onClose(new CloseInfo(StatusCode.NORMAL, "Normal"));
}
// Await completion (of threads)
socket.streamLatch.await(2, TimeUnit.SECONDS);
@ -180,21 +193,24 @@ public class CommonEndpointFunctionsTest
socket.assertCaptured("onTextStream\\(Hello World\\)");
}
@Test
public void testAnnotatedStreamedText_MultipleParts() throws InterruptedException
@Test(timeout = 1000)
public void testAnnotatedStreamedText_MultipleParts() throws Exception
{
// Setup
StreamedText socket = new StreamedText(1);
Session session = initSession(socket);
EndpointFunctions<Session> endpointFunctions = new CommonEndpointFunctions(socket, containerScope.getPolicy(), containerScope.getExecutor());
// Trigger Events
endpointFunctions.onOpen(session);
endpointFunctions.onText(BufferUtil.toBuffer("Hel"), false);
endpointFunctions.onText(BufferUtil.toBuffer("lo "), false);
endpointFunctions.onText(BufferUtil.toBuffer("Wor"), false);
endpointFunctions.onText(BufferUtil.toBuffer("ld"), true);
endpointFunctions.onClose(new CloseInfo(StatusCode.NORMAL, "Normal"));
try (CloseableLifeCycle<CommonEndpointFunctions> lifecycle = new CloseableLifeCycle<>(
new CommonEndpointFunctions(socket, containerScope.getPolicy(), containerScope.getExecutor())))
{
EndpointFunctions<Session> endpointFunctions = lifecycle.get();
// Trigger Events
endpointFunctions.onOpen(session);
endpointFunctions.onText(BufferUtil.toBuffer("Hel"), false);
endpointFunctions.onText(BufferUtil.toBuffer("lo "), false);
endpointFunctions.onText(BufferUtil.toBuffer("Wor"), false);
endpointFunctions.onText(BufferUtil.toBuffer("ld"), true);
endpointFunctions.onClose(new CloseInfo(StatusCode.NORMAL, "Normal"));
}
// Await completion (of threads)
socket.streamLatch.await(2, TimeUnit.SECONDS);
@ -219,20 +235,24 @@ public class CommonEndpointFunctionsTest
}
@Test
public void testWebSocketPartialListener()
public void testWebSocketPartialListener() throws Exception
{
// Setup
PartialData socket = new PartialData();
Session session = initSession(socket);
EndpointFunctions<Session> endpointFunctions = new CommonEndpointFunctions(socket, containerScope.getPolicy(), containerScope.getExecutor());
try (CloseableLifeCycle<CommonEndpointFunctions> lifecycle = new CloseableLifeCycle<>(
new CommonEndpointFunctions(socket, containerScope.getPolicy(), containerScope.getExecutor())))
{
EndpointFunctions<Session> endpointFunctions = lifecycle.get();
// Trigger Events
endpointFunctions.onOpen(session);
endpointFunctions.onText(BufferUtil.toBuffer("Hel"), false);
endpointFunctions.onText(BufferUtil.toBuffer("lo "), false);
endpointFunctions.onText(BufferUtil.toBuffer("Wor"), false);
endpointFunctions.onText(BufferUtil.toBuffer("ld"), true);
endpointFunctions.onClose(new CloseInfo(StatusCode.NORMAL, "Normal"));
// Trigger Events
endpointFunctions.onOpen(session);
endpointFunctions.onText(BufferUtil.toBuffer("Hel"), false);
endpointFunctions.onText(BufferUtil.toBuffer("lo "), false);
endpointFunctions.onText(BufferUtil.toBuffer("Wor"), false);
endpointFunctions.onText(BufferUtil.toBuffer("ld"), true);
endpointFunctions.onClose(new CloseInfo(StatusCode.NORMAL, "Normal"));
}
// Validate Events
socket.assertCaptured(
@ -242,6 +262,6 @@ public class CommonEndpointFunctionsTest
"onWebSocketPartialText\\(Wor, false\\)",
"onWebSocketPartialText\\(ld, true\\)",
"onWebSocketClose\\([^\\)]*\\)"
);
);
}
}

View File

@ -18,15 +18,14 @@
package org.eclipse.jetty.websocket.common.io;
import org.eclipse.jetty.websocket.common.events.EventDriver;
import org.eclipse.jetty.websocket.common.scopes.WebSocketContainerScope;
import org.junit.rules.TestName;
public class CloseableLocalWebSocketSession extends LocalWebSocketSession implements AutoCloseable
{
public CloseableLocalWebSocketSession(WebSocketContainerScope containerScope, TestName testname, EventDriver driver)
public CloseableLocalWebSocketSession(WebSocketContainerScope containerScope, TestName testname, Object websocket)
{
super(containerScope, testname, driver);
super(containerScope, testname, websocket);
// LifeCycle start
try
{

View File

@ -18,7 +18,10 @@
package org.eclipse.jetty.websocket.common.message;
import java.net.URISyntaxException;
import static org.hamcrest.Matchers.allOf;
import static org.hamcrest.Matchers.containsString;
import static org.hamcrest.Matchers.is;
import java.util.Arrays;
import org.eclipse.jetty.toolchain.test.TestTracker;
@ -39,10 +42,6 @@ import org.junit.Rule;
import org.junit.Test;
import org.junit.rules.TestName;
import static org.hamcrest.Matchers.allOf;
import static org.hamcrest.Matchers.containsString;
import static org.hamcrest.Matchers.is;
public class MessageOutputStreamTest
{
private static final Logger LOG = Log.getLogger(MessageOutputStreamTest.class);
@ -59,16 +58,19 @@ public class MessageOutputStreamTest
private WebSocketPolicy policy;
private TrackingSocket remoteSocket;
private LocalWebSocketSession session;
private WebSocketSession remoteSession;
@After
public void closeSession() throws Exception
{
session.close();
session.stop();
remoteSession.close();
remoteSession.stop();
}
@Before
public void setupSession() throws URISyntaxException
public void setupSession() throws Exception
{
policy = WebSocketPolicy.newServerPolicy();
policy.setInputBufferSize(1024);
@ -79,8 +81,9 @@ public class MessageOutputStreamTest
// remote socket
remoteSocket = new TrackingSocket("remote");
WebSocketSession remoteSession = new LocalWebSocketSession(containerScope,testname,remoteSocket);
remoteSession = new LocalWebSocketSession(containerScope,testname,remoteSocket);
OutgoingFrames socketPipe = FramePipes.to(remoteSession);
remoteSession.start();
remoteSession.open();
// Local Session

View File

@ -21,7 +21,6 @@ package org.eclipse.jetty.websocket.common.message;
import static org.hamcrest.Matchers.is;
import java.net.URI;
import java.net.URISyntaxException;
import java.util.Arrays;
import org.eclipse.jetty.toolchain.test.TestTracker;
@ -65,10 +64,11 @@ public class MessageWriterTest
{
session.close();
remoteSession.close();
remoteSession.stop();
}
@Before
public void setupSession() throws URISyntaxException
public void setupSession() throws Exception
{
policy = WebSocketPolicy.newServerPolicy();
policy.setInputBufferSize(1024);
@ -83,6 +83,7 @@ public class MessageWriterTest
LocalWebSocketConnection remoteConnection = new LocalWebSocketConnection(bufferPool);
remoteSession = new WebSocketSession(containerScope,remoteURI,remoteSocket,remoteConnection);
OutgoingFrames socketPipe = FramePipes.to(remoteSession);
remoteSession.start();
remoteSession.open();
// Local Session

View File

@ -0,0 +1,187 @@
//
// ========================================================================
// Copyright (c) 1995-2016 Mort Bay Consulting Pty. Ltd.
// ------------------------------------------------------------------------
// All rights reserved. This program and the accompanying materials
// are made available under the terms of the Eclipse Public License v1.0
// and Apache License v2.0 which accompanies this distribution.
//
// The Eclipse Public License is available at
// http://www.eclipse.org/legal/epl-v10.html
//
// The Apache License v2.0 is available at
// http://www.opensource.org/licenses/apache2.0.php
//
// You may elect to redistribute this code under either of these licenses.
// ========================================================================
//
package org.eclipse.jetty.websocket.common.reflect;
import static org.hamcrest.Matchers.is;
import static org.hamcrest.Matchers.notNullValue;
import static org.junit.Assert.assertThat;
import java.io.File;
import java.lang.reflect.Method;
import org.eclipse.jetty.util.annotation.Name;
import org.junit.Test;
public class DynamicArgsTest
{
@SuppressWarnings("unused")
public static class SampleSignatures
{
public String sigEmpty()
{
return "sigEmpty<>";
}
public String sigStr(String str)
{
return String.format("sigStr<%s>", str);
}
public String sigStrFile(String str, File foo)
{
return String.format("sigStrFile<%s,%s>", str, foo);
}
public String sigFileStr(File foo, String str)
{
return String.format("sigFileStr<%s,%s>", foo, str);
}
public String sigFileStrFin(File foo, String str, @Name("fin") boolean fin)
{
return String.format("sigFileStrFin<%s,%s,%b>", foo, str, fin);
}
public String sigByteArray(byte[] buf, @Name("offset") int offset, @Name("length") int len)
{
return String.format("sigByteArray<%s,%d,%d>", buf == null ? "<null>" : ("[" + buf.length + "]"), offset, len);
}
}
public static Method findMethodByName(Object obj, String name)
{
for (Method method : obj.getClass().getMethods())
{
if (method.getName().equals(name))
{
return method;
}
}
throw new AssertionError("Unable to find method: " + name);
}
/**
* Test with method that has empty signature,
* and desired callable that also has an empty signature
*
* @throws Exception on error
*/
@Test
public void testEmptySignature() throws Exception
{
DynamicArgs.Builder dab = new DynamicArgs.Builder();
dab.addSignature(); // intentionally empty
SampleSignatures samples = new SampleSignatures();
Method m = findMethodByName(samples, "sigEmpty");
DynamicArgs dynamicArgs = dab.build(m);
assertThat("DynamicArgs", dynamicArgs, notNullValue());
// Test with empty potential args
String result = (String) dynamicArgs.invoke(samples);
assertThat("result", result, is("sigEmpty<>"));
}
/**
* Test with method that has empty signature,
* and desired callable that has a String (optional) signature
*
* @throws Exception on error
*/
@Test
public void testEmptySignature_StringCallable() throws Exception
{
final Arg ARG_STR = new Arg(String.class);
DynamicArgs.Builder dab = new DynamicArgs.Builder();
dab.addSignature(ARG_STR);
SampleSignatures samples = new SampleSignatures();
Method m = findMethodByName(samples, "sigEmpty");
DynamicArgs dynamicArgs = dab.build(m);
assertThat("DynamicArgs", dynamicArgs, notNullValue());
// Test with empty potential args
String result = (String) dynamicArgs.invoke(samples, "Hello");
assertThat("result", result, is("sigEmpty<>"));
}
/**
* Test with method that has String signature, and
* a desired callable that also has String signature.
*
* @throws Exception on error
*/
@Test
public void testStringSignature() throws Exception
{
final Arg ARG_STR = new Arg(String.class);
DynamicArgs.Builder dab = new DynamicArgs.Builder();
dab.addSignature(ARG_STR);
final Arg CALL_STR = new Arg(String.class);
SampleSignatures samples = new SampleSignatures();
Method m = findMethodByName(samples, "sigStr");
DynamicArgs dynamicArgs = dab.build(m, CALL_STR);
assertThat("DynamicArgs", dynamicArgs, notNullValue());
// Test with potential args
String result = (String) dynamicArgs.invoke(samples, "Hello");
assertThat("result", result, is("sigStr<Hello>"));
}
/**
* Test of finding a match on a method that is tagged
* via the ArgIdentifier concepts.
*
* @throws Exception on error
*/
@Test
public void testByteArraySignature() throws Exception
{
final Arg ARG_BYTEARRAY = new Arg(byte[].class);
final Arg ARG_OFFSET = new Arg(int.class).setTag("offset");
final Arg ARG_LENGTH = new Arg(int.class).setTag("length");
DynamicArgs.Builder dab = new DynamicArgs.Builder();
dab.addSignature(ARG_BYTEARRAY, ARG_OFFSET, ARG_LENGTH);
final Arg CALL_BYTEARRAY = new Arg(byte[].class);
final Arg CALL_OFFSET = new Arg(int.class).setTag("offset");
final Arg CALL_LENGTH = new Arg(int.class).setTag("length");
SampleSignatures ssigs = new SampleSignatures();
Method m = findMethodByName(ssigs, "sigByteArray");
DynamicArgs dynamicArgs = dab.build(m, CALL_BYTEARRAY, CALL_OFFSET, CALL_LENGTH);
assertThat("DynamicArgs", dynamicArgs, notNullValue());
// Test with potential args
byte buf[] = new byte[222];
int offset = 3;
int len = 44;
String result = (String) dynamicArgs.invoke(ssigs, buf, offset, len);
assertThat("result", result, is("sigByteArray<[222],3,44>"));
// Test with empty potential args
result = (String) dynamicArgs.invoke(ssigs, null, 123, 456);
assertThat("result", result, is("sigByteArray<<null>,123,456>"));
}
}

View File

@ -1,123 +0,0 @@
//
// ========================================================================
// Copyright (c) 1995-2016 Mort Bay Consulting Pty. Ltd.
// ------------------------------------------------------------------------
// All rights reserved. This program and the accompanying materials
// are made available under the terms of the Eclipse Public License v1.0
// and Apache License v2.0 which accompanies this distribution.
//
// The Eclipse Public License is available at
// http://www.eclipse.org/legal/epl-v10.html
//
// The Apache License v2.0 is available at
// http://www.opensource.org/licenses/apache2.0.php
//
// You may elect to redistribute this code under either of these licenses.
// ========================================================================
//
package org.eclipse.jetty.websocket.common.reflect;
import static org.hamcrest.Matchers.is;
import static org.hamcrest.Matchers.notNullValue;
import static org.junit.Assert.assertThat;
import java.io.File;
import java.lang.reflect.Method;
import org.junit.Test;
public class ExactSignatureTest
{
public static class SampleSignatures
{
public String sigEmpty()
{
return "sigEmpty<>";
}
public String sigStr(String str)
{
return String.format("sigStr<%s>", str);
}
public String sigByteArray(byte[] buf, int offset, int len)
{
return String.format("sigByteArray<%s,%d,%d>", buf == null ? "<null>" : ("[" + buf.length + "]"), offset, len);
}
}
public static Method findMethodByName(Object obj, String name)
{
for (Method method : obj.getClass().getMethods())
{
if (method.getName().equals(name))
{
return method;
}
}
throw new AssertionError("Unable to find method: " + name);
}
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_FILE = new Arg(3, File.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_LEN = new Arg(6, int.class);
@Test
public void testEmptySignature() throws Exception
{
DynamicArgs.Builder dab = new DynamicArgs.Builder();
dab.addSignature(new ExactSignature());
SampleSignatures ssigs = new SampleSignatures();
Method m = findMethodByName(ssigs, "sigEmpty");
DynamicArgs dargs = dab.build(m, ARG_STR, ARG_BOOL, ARG_FILE);
assertThat("DynamicArgs", dargs, notNullValue());
// Test with potential args
String result = (String) dargs.invoke(ssigs, "Hello", Boolean.TRUE, new File("bar"));
assertThat("result", result, is("sigEmpty<>"));
}
@Test
public void testStringSignature() throws Exception
{
DynamicArgs.Builder dab = new DynamicArgs.Builder();
dab.addSignature(new ExactSignature(ARG_STR));
SampleSignatures ssigs = new SampleSignatures();
Method m = findMethodByName(ssigs, "sigStr");
DynamicArgs dargs = dab.build(m, ARG_STR, ARG_BOOL, ARG_FILE);
assertThat("DynamicArgs", dargs, notNullValue());
// Test with potential args
String result = (String) dargs.invoke(ssigs, "Hello", Boolean.TRUE, new File("bar"));
assertThat("result", result, is("sigStr<Hello>"));
}
@Test
public void testByteArraySignature() throws Exception
{
DynamicArgs.Builder dab = new DynamicArgs.Builder();
dab.addSignature(new ExactSignature(ARG_BYTEARRAY, ARG_OFFSET, ARG_LEN));
SampleSignatures ssigs = new SampleSignatures();
Method m = findMethodByName(ssigs, "sigByteArray");
DynamicArgs dargs = dab.build(m, ARG_BYTEARRAY, ARG_OFFSET, ARG_LEN);
assertThat("DynamicArgs", dargs, notNullValue());
// Test with potential args
byte buf[] = new byte[222];
int offset = 3;
int len = 44;
String result = (String) dargs.invoke(ssigs, buf, offset, len);
assertThat("result", result, is("sigByteArray<[222],3,44>"));
// Test with empty potential args
result = (String) dargs.invoke(ssigs, null, 123, 456);
assertThat("result", result, is("sigByteArray<<null>,123,456>"));
}
}

View File

@ -26,44 +26,52 @@ import java.io.File;
import java.lang.reflect.Method;
import org.eclipse.jetty.util.annotation.Name;
import org.eclipse.jetty.websocket.api.Session;
import org.junit.Test;
public class UnorderedSignatureTest
{
@SuppressWarnings("unused")
public static class SampleSignatures
{
public String sigEmpty()
{
return "sigEmpty<>";
}
public String sigStr(String str)
{
return String.format("sigStr<%s>",str);
return String.format("sigStr<%s>", str);
}
public String sigStrFile(String str, File foo)
{
return String.format("sigStrFile<%s,%s>",str,foo);
return String.format("sigStrFile<%s,%s>", str, q(foo));
}
public String sigFileStr(File foo, String str)
{
return String.format("sigFileStr<%s,%s>",foo,str);
return String.format("sigFileStr<%s,%s>", q(foo), str);
}
public String sigFileStrFin(File foo, String str, @Name("fin") boolean fin)
{
return String.format("sigFileStrFin<%s,%s,%b>",foo,str,fin);
return String.format("sigFileStrFin<%s,%s,%b>", q(foo), q(str), fin);
}
public String sigByteArray(byte[] buf, @Name("offset")int offset, @Name("length")int len)
public String sigByteArray(byte[] buf, @Name("offset") int offset, @Name("length") 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);
}
private String q(Object obj)
{
if (obj == null)
return "<null>";
else
return obj.toString();
}
}
public static Method findMethodByName(Object obj, String name)
{
for (Method method : obj.getClass().getMethods())
@ -75,110 +83,156 @@ public class UnorderedSignatureTest
}
throw new AssertionError("Unable to find method: " + name);
}
private static final Arg ARG_STR = new Arg(String.class);
private static final Arg ARG_BOOL = new Arg(Boolean.class);
private static final Arg ARG_FILE = new Arg(File.class);
private static final Arg ARG_BYTEARRAY = new Arg(byte[].class);
private static final Arg ARG_OFFSET = new Arg(int.class).setTag("offset");
private static final Arg ARG_LENGTH = new Arg(int.class).setTag("length");
private static final Arg ARG_FIN = new Arg(Boolean.class).setTag("fin");
/**
* Test with method that has empty signature,
* and desired callable that also has an empty signature
* @throws Exception on error
*/
@Test
public void testEmptySignature() throws Exception
private void assertMappings(int actualMapping[], int... expectedMapping)
{
DynamicArgs.Builder dab = new DynamicArgs.Builder();
dab.addSignature(new UnorderedSignature());
SampleSignatures samples = new SampleSignatures();
Method m = findMethodByName(samples, "sigEmpty");
DynamicArgs dynamicArgs = dab.build(m);
assertThat("DynamicArgs", dynamicArgs, notNullValue());
// Test with empty potential args
String result = (String) dynamicArgs.invoke(samples);
assertThat("result", result, is("sigEmpty<>"));
assertThat("mapping", actualMapping, notNullValue());
assertThat("mapping.length", actualMapping.length, is(expectedMapping.length));
if (expectedMapping.length > 0)
{
for (int i = 0; i < expectedMapping.length; i++)
{
assertThat("mapping[" + i + "]", actualMapping[i], is(expectedMapping[i]));
}
}
}
/**
* Test with method that has empty signature,
* and desired callable that has a String (optional) signature
* @throws Exception on error
*/
@Test
public void testEmptySignature_StringCallable
() throws Exception
public void testEmpty_Call_Session()
{
DynamicArgs.Builder dab = new DynamicArgs.Builder();
dab.addSignature(new UnorderedSignature(ARG_STR));
UnorderedSignature sig = new UnorderedSignature(new Arg(Session.class));
SampleSignatures samples = new SampleSignatures();
Method m = findMethodByName(samples, "sigEmpty");
DynamicArgs dynamicArgs = dab.build(m);
assertThat("DynamicArgs", dynamicArgs, notNullValue());
// Test with empty potential args
String result = (String) dynamicArgs.invoke(samples, "Hello");
assertThat("result", result, is("sigEmpty<>"));
Method method = findMethodByName(samples, "sigEmpty");
int mapping[] = sig.getArgMapping(method, false, new Arg(Session.class));
assertMappings(mapping);
}
/**
* Test with method that has String signature, and
* a desired callable that also has String signature.
* @throws Exception on error
*/
@Test
public void testStringSignature() throws Exception
public void testEmpty_Call_None()
{
DynamicArgs.Builder dab = new DynamicArgs.Builder();
dab.addSignature(new UnorderedSignature(ARG_STR));
final Arg CALL_STR = new Arg(String.class);
UnorderedSignature sig = new UnorderedSignature();
SampleSignatures samples = new SampleSignatures();
Method m = findMethodByName(samples, "sigStr");
DynamicArgs dynamicArgs = dab.build(m, CALL_STR);
assertThat("DynamicArgs", dynamicArgs, notNullValue());
// Test with potential args
String result = (String) dynamicArgs.invoke(samples, "Hello");
assertThat("result", result, is("sigStr<Hello>"));
Method method = findMethodByName(samples, "sigEmpty");
int mapping[] = sig.getArgMapping(method, false);
assertMappings(mapping);
}
/**
* Test of finding a match on a method that is tagged
* via a the ArgIdentifier concepts.
* @throws Exception on error
*/
@Test
public void testByteArraySignature() throws Exception
public void testString_Call_String()
{
DynamicArgs.Builder dab = new DynamicArgs.Builder();
dab.addSignature(new UnorderedSignature(ARG_BYTEARRAY, ARG_OFFSET, ARG_LENGTH));
final Arg CALL_BYTEARRAY = new Arg(byte[].class);
final Arg CALL_OFFSET = new Arg(int.class).setTag("offset");
final Arg CALL_LENGTH = new Arg(int.class).setTag("length");
SampleSignatures ssigs = new SampleSignatures();
Method m = findMethodByName(ssigs, "sigByteArray");
DynamicArgs dynamicArgs = dab.build(m,CALL_BYTEARRAY, CALL_OFFSET, CALL_LENGTH);
assertThat("DynamicArgs", dynamicArgs, notNullValue());
// Test with potential args
byte buf[] = new byte[222];
int offset = 3;
int len = 44;
String result = (String)dynamicArgs.invoke(ssigs,buf,offset,len);
assertThat("result", result, is("sigByteArray<[222],3,44>"));
// Test with empty potential args
result = (String)dynamicArgs.invoke(ssigs,null,123,456);
assertThat("result", result, is("sigByteArray<<null>,123,456>"));
UnorderedSignature sig = new UnorderedSignature();
SampleSignatures samples = new SampleSignatures();
Method method = findMethodByName(samples, "sigStr");
int mapping[] = sig.getArgMapping(method, false, new Arg(String.class));
assertMappings(mapping, 0);
}
@Test
public void testString_Call_Session_String()
{
UnorderedSignature sig = new UnorderedSignature();
SampleSignatures samples = new SampleSignatures();
Method method = findMethodByName(samples, "sigStr");
int mapping[] = sig.getArgMapping(method, false, new Arg(Session.class), new Arg(String.class));
assertMappings(mapping, 1);
}
@Test
public void testStringFile_Call_String_File()
{
UnorderedSignature sig = new UnorderedSignature();
SampleSignatures samples = new SampleSignatures();
Method method = findMethodByName(samples, "sigStrFile");
int mapping[] = sig.getArgMapping(method, false, new Arg(String.class), new Arg(File.class));
assertMappings(mapping, 0, 1);
}
@Test
public void testStringFile_Call_File_String()
{
UnorderedSignature sig = new UnorderedSignature();
SampleSignatures samples = new SampleSignatures();
Method method = findMethodByName(samples, "sigStrFile");
int mapping[] = sig.getArgMapping(method, false, new Arg(File.class), new Arg(String.class));
assertMappings(mapping, 1, 0);
}
@Test
public void testFileString_Call_String_File()
{
UnorderedSignature sig = new UnorderedSignature();
SampleSignatures samples = new SampleSignatures();
Method method = findMethodByName(samples, "sigFileStr");
int mapping[] = sig.getArgMapping(method, false, new Arg(String.class), new Arg(File.class));
assertMappings(mapping, 1, 0);
}
@Test
public void testFileString_Call_File_String()
{
UnorderedSignature sig = new UnorderedSignature();
SampleSignatures samples = new SampleSignatures();
Method method = findMethodByName(samples, "sigFileStr");
int mapping[] = sig.getArgMapping(method, false, new Arg(File.class), new Arg(String.class));
assertMappings(mapping, 0, 1);
}
@Test
public void testFileStringFin_Call_File_String_BoolTag()
{
UnorderedSignature sig = new UnorderedSignature();
SampleSignatures samples = new SampleSignatures();
Method method = findMethodByName(samples, "sigFileStrFin");
Arg callArgs[] = {new Arg(File.class), new Arg(String.class), new Arg(boolean.class).setTag("fin")};
int mapping[] = sig.getArgMapping(method, false, callArgs);
assertMappings(mapping, 0, 1, 2);
Object params[] = {new File("foo"), "bar", true};
String resp = (String) sig.getInvoker(method, callArgs).apply(samples, params);
assertThat("Invoked response", resp, is("sigFileStrFin<foo,bar,true>"));
}
@Test
public void testFileStringFin_Call_BoolTag_File_String()
{
UnorderedSignature sig = new UnorderedSignature();
SampleSignatures samples = new SampleSignatures();
Method method = findMethodByName(samples, "sigFileStrFin");
Arg callArgs[] = {new Arg(boolean.class).setTag("fin"), new Arg(File.class), new Arg(String.class)};
int mapping[] = sig.getArgMapping(method, false, callArgs);
assertMappings(mapping, 1, 2, 0);
Object params[] = {true, new File("foo"), "bar"};
String resp = (String) sig.getInvoker(method, callArgs).apply(samples, params);
assertThat("Invoked response", resp, is("sigFileStrFin<foo,bar,true>"));
}
@Test
public void testFileStringFin_Call_BoolTag_Null_String()
{
UnorderedSignature sig = new UnorderedSignature();
SampleSignatures samples = new SampleSignatures();
Method method = findMethodByName(samples, "sigFileStrFin");
Arg callArgs[] = {new Arg(boolean.class).setTag("fin"), new Arg(File.class), new Arg(String.class)};
int mapping[] = sig.getArgMapping(method, false, callArgs);
assertMappings(mapping, 1, 2, 0);
Object params[] = {true, null, "bar"};
String resp = (String) sig.getInvoker(method, callArgs).apply(samples, params);
assertThat("Invoked response", resp, is("sigFileStrFin<<null>,bar,true>"));
}
}

View File

@ -1,8 +1,9 @@
org.eclipse.jetty.util.log.class=org.eclipse.jetty.util.log.StdErrLog
org.eclipse.jetty.LEVEL=WARN
# org.eclipse.jetty.websocket.LEVEL=DEBUG
org.eclipse.jetty.websocket.LEVEL=DEBUG
# org.eclipse.jetty.websocket.protocol.Parser.LEVEL=DEBUG
# org.eclipse.jetty.websocket.protocol.LEVEL=DEBUG
# org.eclipse.jetty.websocket.io.payload.LEVEL=DEBUG
# org.eclipse.jetty.websocket.common.extensions.LEVEL=DEBUG
# org.eclipse.jetty.websocket.common.message.LEVEL=DEBUG
org.eclipse.jetty.websocket.common.function.LEVEL=DEBUG