Issue #207 - Support javax.websocket version 1.1

WIP
This commit is contained in:
Joakim Erdfelt 2016-03-08 15:20:28 -07:00
parent cbf8c971aa
commit 0a6fd16b52
16 changed files with 383 additions and 181 deletions

View File

@ -28,6 +28,7 @@ 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.util.DynamicArgs;
import org.eclipse.jetty.websocket.common.util.DynamicArgs.Arg;
import org.eclipse.jetty.websocket.common.util.ExactSignature;
import org.eclipse.jetty.websocket.common.util.ReflectUtils;
@ -37,25 +38,25 @@ import org.eclipse.jetty.websocket.common.util.ReflectUtils;
public class OnByteArrayFunction implements Function<byte[], Void>
{
private static final DynamicArgs.Builder ARGBUILDER;
private static final int SESSION = 1;
private static final int BUFFER = 2;
private static final int OFFSET = 3;
private static final int LENGTH = 4;
private static final Arg SESSION = new Arg(1,Session.class);
private static final Arg BUFFER = new Arg(2,byte[].class);
private static final Arg OFFSET = new Arg(3,int.class);
private static final Arg LENGTH = new Arg(4,int.class);
static
{
ARGBUILDER = new DynamicArgs.Builder();
ARGBUILDER.addSignature(new ExactSignature(byte[].class).indexedAs(BUFFER));
ARGBUILDER.addSignature(new ExactSignature(byte[].class,int.class,int.class).indexedAs(BUFFER,OFFSET,LENGTH));
ARGBUILDER.addSignature(new ExactSignature(Session.class,byte[].class).indexedAs(SESSION,BUFFER));
ARGBUILDER.addSignature(new ExactSignature(Session.class,byte[].class,int.class,int.class).indexedAs(SESSION,BUFFER,OFFSET,LENGTH));
ARGBUILDER.addSignature(new ExactSignature(byte[].class));
ARGBUILDER.addSignature(new ExactSignature(byte[].class,int.class,int.class));
ARGBUILDER.addSignature(new ExactSignature(Session.class,byte[].class));
ARGBUILDER.addSignature(new ExactSignature(Session.class,byte[].class,int.class,int.class));
}
public static DynamicArgs.Builder getDynamicArgsBuilder()
{
return ARGBUILDER;
}
public static boolean hasMatchingSignature(Method method)
{
return ARGBUILDER.hasMatchingSignature(method);
@ -76,21 +77,19 @@ public class OnByteArrayFunction implements Function<byte[], Void>
ReflectUtils.assertIsPublicNonStatic(method);
ReflectUtils.assertIsReturn(method,Void.TYPE);
this.callable = ARGBUILDER.build(method);
this.callable = ARGBUILDER.build(method,SESSION,BUFFER,OFFSET,LENGTH);
if (this.callable == null)
{
throw InvalidSignatureException.build(method,OnWebSocketMessage.class,ARGBUILDER);
}
this.callable.setArgReferences(SESSION,BUFFER,OFFSET,LENGTH);
}
@Override
public Void apply(byte[] bin)
{
Object args[] = this.callable.toArgs(session,bin,0,bin.length);
try
{
method.invoke(endpoint,args);
this.callable.invoke(endpoint,bin,0,bin.length);
}
catch (IllegalAccessException | IllegalArgumentException | InvocationTargetException e)
{

View File

@ -29,6 +29,7 @@ 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.util.DynamicArgs;
import org.eclipse.jetty.websocket.common.util.DynamicArgs.Arg;
import org.eclipse.jetty.websocket.common.util.ExactSignature;
import org.eclipse.jetty.websocket.common.util.ReflectUtils;
@ -38,21 +39,21 @@ import org.eclipse.jetty.websocket.common.util.ReflectUtils;
public class OnByteBufferFunction implements Function<ByteBuffer, Void>
{
private static final DynamicArgs.Builder ARGBUILDER;
private static final int SESSION = 1;
private static final int BUFFER = 2;
private static final Arg SESSION = new Arg(1,Session.class);
private static final Arg BUFFER = new Arg(2,ByteBuffer.class);
static
{
ARGBUILDER = new DynamicArgs.Builder();
ARGBUILDER.addSignature(new ExactSignature(ByteBuffer.class).indexedAs(BUFFER));
ARGBUILDER.addSignature(new ExactSignature(Session.class,ByteBuffer.class).indexedAs(SESSION,BUFFER));
ARGBUILDER.addSignature(new ExactSignature(ByteBuffer.class));
ARGBUILDER.addSignature(new ExactSignature(Session.class,ByteBuffer.class));
}
public static DynamicArgs.Builder getDynamicArgsBuilder()
{
return ARGBUILDER;
}
public static boolean hasMatchingSignature(Method method)
{
return ARGBUILDER.hasMatchingSignature(method);
@ -73,21 +74,19 @@ public class OnByteBufferFunction implements Function<ByteBuffer, Void>
ReflectUtils.assertIsPublicNonStatic(method);
ReflectUtils.assertIsReturn(method,Void.TYPE);
this.callable = ARGBUILDER.build(method);
this.callable = ARGBUILDER.build(method,SESSION,BUFFER);
if (this.callable == null)
{
throw InvalidSignatureException.build(method,OnWebSocketMessage.class,ARGBUILDER);
}
this.callable.setArgReferences(SESSION,BUFFER);
}
@Override
public Void apply(ByteBuffer bin)
{
Object args[] = this.callable.toArgs(session,bin);
try
{
method.invoke(endpoint,args);
this.callable.invoke(endpoint,session,bin);
}
catch (IllegalAccessException | IllegalArgumentException | InvocationTargetException e)
{

View File

@ -18,10 +18,6 @@
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.WebSocketException;
import org.eclipse.jetty.websocket.api.annotations.OnWebSocketClose;
@ -29,26 +25,31 @@ import org.eclipse.jetty.websocket.api.annotations.WebSocket;
import org.eclipse.jetty.websocket.common.CloseInfo;
import org.eclipse.jetty.websocket.common.InvalidSignatureException;
import org.eclipse.jetty.websocket.common.util.DynamicArgs;
import org.eclipse.jetty.websocket.common.util.DynamicArgs.Arg;
import org.eclipse.jetty.websocket.common.util.ExactSignature;
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}
*/
public class OnCloseFunction implements Function<CloseInfo, Void>
{
private static final DynamicArgs.Builder ARGBUILDER;
private static final int SESSION = 1;
private static final int STATUS_CODE = 2;
private static final int REASON = 3;
private static final Arg SESSION = new Arg(1,Session.class);
private static final Arg STATUS_CODE = new Arg(2,int.class);
private static final Arg REASON = new Arg(3,String.class);
static
{
ARGBUILDER = new DynamicArgs.Builder();
ARGBUILDER.addSignature(new ExactSignature().indexedAs());
ARGBUILDER.addSignature(new ExactSignature(Session.class).indexedAs(SESSION));
ARGBUILDER.addSignature(new ExactSignature(int.class,String.class).indexedAs(STATUS_CODE,REASON));
ARGBUILDER.addSignature(new ExactSignature(Session.class,int.class,String.class).indexedAs(SESSION,STATUS_CODE,REASON));
ARGBUILDER.addSignature(new ExactSignature());
ARGBUILDER.addSignature(new ExactSignature(Session.class));
ARGBUILDER.addSignature(new ExactSignature(int.class,String.class));
ARGBUILDER.addSignature(new ExactSignature(Session.class,int.class,String.class));
}
private final Session session;
@ -62,25 +63,23 @@ public class OnCloseFunction implements Function<CloseInfo, Void>
this.endpoint = endpoint;
this.method = method;
ReflectUtils.assertIsAnnotated(method,OnWebSocketClose.class);
ReflectUtils.assertIsAnnotated(method, OnWebSocketClose.class);
ReflectUtils.assertIsPublicNonStatic(method);
ReflectUtils.assertIsReturn(method,Void.TYPE);
ReflectUtils.assertIsReturn(method, Void.TYPE);
this.callable = ARGBUILDER.build(method);
this.callable = ARGBUILDER.build(method, SESSION, STATUS_CODE, REASON);
if (this.callable == null)
{
throw InvalidSignatureException.build(method,OnWebSocketClose.class,ARGBUILDER);
}
this.callable.setArgReferences(SESSION,STATUS_CODE,REASON);
}
@Override
public Void apply(CloseInfo closeinfo)
{
Object args[] = this.callable.toArgs(session,closeinfo.getStatusCode(),closeinfo.getReason());
try
{
method.invoke(endpoint,args);
this.callable.invoke(endpoint,session,closeinfo.getStatusCode(),closeinfo.getReason());
}
catch (IllegalAccessException | IllegalArgumentException | InvocationTargetException e)
{

View File

@ -28,6 +28,7 @@ import org.eclipse.jetty.websocket.api.annotations.OnWebSocketError;
import org.eclipse.jetty.websocket.api.annotations.WebSocket;
import org.eclipse.jetty.websocket.common.InvalidSignatureException;
import org.eclipse.jetty.websocket.common.util.DynamicArgs;
import org.eclipse.jetty.websocket.common.util.DynamicArgs.Arg;
import org.eclipse.jetty.websocket.common.util.ExactSignature;
import org.eclipse.jetty.websocket.common.util.ReflectUtils;
@ -37,14 +38,14 @@ import org.eclipse.jetty.websocket.common.util.ReflectUtils;
public class OnErrorFunction implements Function<Throwable, Void>
{
private static final DynamicArgs.Builder ARGBUILDER;
private static final int SESSION = 1;
private static final int CAUSE = 2;
private static final Arg SESSION = new Arg(1, Session.class);
private static final Arg CAUSE = new Arg(2, Throwable.class);
static
{
ARGBUILDER = new DynamicArgs.Builder();
ARGBUILDER.addSignature(new ExactSignature(Throwable.class).indexedAs(CAUSE));
ARGBUILDER.addSignature(new ExactSignature(Session.class,Throwable.class).indexedAs(SESSION,CAUSE));
ARGBUILDER.addSignature(new ExactSignature(Throwable.class));
ARGBUILDER.addSignature(new ExactSignature(Session.class,Throwable.class));
}
private final Session session;
@ -62,21 +63,19 @@ public class OnErrorFunction implements Function<Throwable, Void>
ReflectUtils.assertIsPublicNonStatic(method);
ReflectUtils.assertIsReturn(method,Void.TYPE);
this.callable = ARGBUILDER.build(method);
this.callable = ARGBUILDER.build(method,SESSION,CAUSE);
if (this.callable == null)
{
throw InvalidSignatureException.build(method,OnWebSocketError.class,ARGBUILDER);
}
this.callable.setArgReferences(SESSION,CAUSE);
}
@Override
public Void apply(Throwable cause)
{
Object args[] = this.callable.toArgs(session,cause);
try
{
method.invoke(endpoint,args);
this.callable.invoke(endpoint,session,cause);
}
catch (IllegalAccessException | IllegalArgumentException | InvocationTargetException e)
{

View File

@ -30,6 +30,7 @@ import org.eclipse.jetty.websocket.api.extensions.Frame;
import org.eclipse.jetty.websocket.common.InvalidSignatureException;
import org.eclipse.jetty.websocket.common.WebSocketFrame;
import org.eclipse.jetty.websocket.common.util.DynamicArgs;
import org.eclipse.jetty.websocket.common.util.DynamicArgs.Arg;
import org.eclipse.jetty.websocket.common.util.ExactSignature;
import org.eclipse.jetty.websocket.common.util.ReflectUtils;
@ -39,14 +40,14 @@ import org.eclipse.jetty.websocket.common.util.ReflectUtils;
public class OnFrameFunction implements Function<Frame, Void>
{
private static final DynamicArgs.Builder ARGBUILDER;
private static final int SESSION = 1;
private static final int FRAME = 2;
private static final Arg SESSION = new Arg(1,Session.class);
private static final Arg FRAME = new Arg(2,Frame.class);
static
{
ARGBUILDER = new DynamicArgs.Builder();
ARGBUILDER.addSignature(new ExactSignature(Frame.class).indexedAs(FRAME));
ARGBUILDER.addSignature(new ExactSignature(Session.class,Frame.class).indexedAs(SESSION,FRAME));
ARGBUILDER.addSignature(new ExactSignature(Frame.class));
ARGBUILDER.addSignature(new ExactSignature(Session.class,Frame.class));
}
private final Session session;
@ -64,22 +65,20 @@ public class OnFrameFunction implements Function<Frame, Void>
ReflectUtils.assertIsPublicNonStatic(method);
ReflectUtils.assertIsReturn(method,Void.TYPE);
this.callable = ARGBUILDER.build(method);
this.callable = ARGBUILDER.build(method,SESSION,FRAME);
if (this.callable == null)
{
throw InvalidSignatureException.build(method,OnWebSocketFrame.class,ARGBUILDER);
}
this.callable.setArgReferences(SESSION,FRAME);
}
@Override
public Void apply(Frame frame)
{
WebSocketFrame copy = WebSocketFrame.copy(frame);
Object args[] = this.callable.toArgs(session,copy);
try
{
method.invoke(endpoint,args);
this.callable.invoke(endpoint,session,copy);
}
catch (IllegalAccessException | IllegalArgumentException | InvocationTargetException e)
{

View File

@ -29,6 +29,7 @@ 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.util.DynamicArgs;
import org.eclipse.jetty.websocket.common.util.DynamicArgs.Arg;
import org.eclipse.jetty.websocket.common.util.ExactSignature;
import org.eclipse.jetty.websocket.common.util.ReflectUtils;
@ -39,21 +40,21 @@ import org.eclipse.jetty.websocket.common.util.ReflectUtils;
public class OnInputStreamFunction implements Function<InputStream, Void>
{
private static final DynamicArgs.Builder ARGBUILDER;
private static final int SESSION = 1;
private static final int STREAM = 2;
private static final Arg SESSION = new Arg(1,Session.class);
private static final Arg STREAM = new Arg(2, InputStream.class);
static
{
ARGBUILDER = new DynamicArgs.Builder();
ARGBUILDER.addSignature(new ExactSignature(InputStream.class).indexedAs(STREAM));
ARGBUILDER.addSignature(new ExactSignature(Session.class,InputStream.class).indexedAs(SESSION,STREAM));
ARGBUILDER.addSignature(new ExactSignature(InputStream.class));
ARGBUILDER.addSignature(new ExactSignature(Session.class,InputStream.class));
}
public static DynamicArgs.Builder getDynamicArgsBuilder()
{
return ARGBUILDER;
}
public static boolean hasMatchingSignature(Method method)
{
return ARGBUILDER.hasMatchingSignature(method);
@ -74,21 +75,19 @@ public class OnInputStreamFunction implements Function<InputStream, Void>
ReflectUtils.assertIsPublicNonStatic(method);
ReflectUtils.assertIsReturn(method,Void.TYPE);
this.callable = ARGBUILDER.build(method);
this.callable = ARGBUILDER.build(method,SESSION,STREAM);
if (this.callable == null)
{
throw InvalidSignatureException.build(method,OnWebSocketMessage.class,ARGBUILDER);
}
this.callable.setArgReferences(SESSION,STREAM);
}
@Override
public Void apply(InputStream stream)
{
Object args[] = this.callable.toArgs(session,stream);
try
{
method.invoke(endpoint,args);
this.callable.invoke(endpoint,session,stream);
}
catch (IllegalAccessException | IllegalArgumentException | InvocationTargetException e)
{

View File

@ -28,6 +28,7 @@ import org.eclipse.jetty.websocket.api.annotations.OnWebSocketConnect;
import org.eclipse.jetty.websocket.api.annotations.WebSocket;
import org.eclipse.jetty.websocket.common.InvalidSignatureException;
import org.eclipse.jetty.websocket.common.util.DynamicArgs;
import org.eclipse.jetty.websocket.common.util.DynamicArgs.Arg;
import org.eclipse.jetty.websocket.common.util.ExactSignature;
import org.eclipse.jetty.websocket.common.util.ReflectUtils;
@ -37,13 +38,13 @@ import org.eclipse.jetty.websocket.common.util.ReflectUtils;
public class OnOpenFunction implements Function<Session, Void>
{
private static final DynamicArgs.Builder ARGBUILDER;
private static final int SESSION = 1;
private static final Arg SESSION = new Arg(1,Session.class);
static
{
ARGBUILDER = new DynamicArgs.Builder();
ARGBUILDER.addSignature(new ExactSignature().indexedAs());
ARGBUILDER.addSignature(new ExactSignature(Session.class).indexedAs(SESSION));
ARGBUILDER.addSignature(new ExactSignature());
ARGBUILDER.addSignature(new ExactSignature(Session.class));
}
private final Object endpoint;
@ -59,22 +60,19 @@ public class OnOpenFunction implements Function<Session, Void>
ReflectUtils.assertIsPublicNonStatic(method);
ReflectUtils.assertIsReturn(method,Void.TYPE);
this.callable = ARGBUILDER.build(method);
this.callable = ARGBUILDER.build(method,SESSION);
if (this.callable == null)
{
throw InvalidSignatureException.build(method,OnWebSocketConnect.class,ARGBUILDER);
}
this.callable.setArgReferences(SESSION);
}
@Override
public Void apply(Session session)
{
Object args[] = this.callable.toArgs(session);
try
{
method.invoke(endpoint,args);
this.callable.invoke(endpoint,session);
}
catch (IllegalAccessException | IllegalArgumentException | InvocationTargetException e)
{

View File

@ -29,6 +29,7 @@ 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.util.DynamicArgs;
import org.eclipse.jetty.websocket.common.util.DynamicArgs.Arg;
import org.eclipse.jetty.websocket.common.util.ExactSignature;
import org.eclipse.jetty.websocket.common.util.ReflectUtils;
@ -38,21 +39,21 @@ import org.eclipse.jetty.websocket.common.util.ReflectUtils;
public class OnReaderFunction implements Function<Reader, Void>
{
private static final DynamicArgs.Builder ARGBUILDER;
private static final int SESSION = 1;
private static final int STREAM = 2;
private static final Arg SESSION = new Arg(1,Session.class);
private static final Arg STREAM = new Arg(2,Reader.class);
static
{
ARGBUILDER = new DynamicArgs.Builder();
ARGBUILDER.addSignature(new ExactSignature(Reader.class).indexedAs(STREAM));
ARGBUILDER.addSignature(new ExactSignature(Session.class,Reader.class).indexedAs(SESSION,STREAM));
ARGBUILDER.addSignature(new ExactSignature(Reader.class));
ARGBUILDER.addSignature(new ExactSignature(Session.class,Reader.class));
}
public static DynamicArgs.Builder getDynamicArgsBuilder()
{
return ARGBUILDER;
}
public static boolean hasMatchingSignature(Method method)
{
return ARGBUILDER.hasMatchingSignature(method);
@ -73,21 +74,19 @@ public class OnReaderFunction implements Function<Reader, Void>
ReflectUtils.assertIsPublicNonStatic(method);
ReflectUtils.assertIsReturn(method,Void.TYPE);
this.callable = ARGBUILDER.build(method);
this.callable = ARGBUILDER.build(method,SESSION,STREAM);
if (this.callable == null)
{
throw InvalidSignatureException.build(method,OnWebSocketMessage.class,ARGBUILDER);
}
this.callable.setArgReferences(SESSION,STREAM);
}
@Override
public Void apply(Reader stream)
{
Object args[] = this.callable.toArgs(session,stream);
try
{
method.invoke(endpoint,args);
this.callable.invoke(endpoint,session,stream);
}
catch (IllegalAccessException | IllegalArgumentException | InvocationTargetException e)
{

View File

@ -28,6 +28,7 @@ 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.util.DynamicArgs;
import org.eclipse.jetty.websocket.common.util.DynamicArgs.Arg;
import org.eclipse.jetty.websocket.common.util.ExactSignature;
import org.eclipse.jetty.websocket.common.util.ReflectUtils;
@ -37,21 +38,21 @@ import org.eclipse.jetty.websocket.common.util.ReflectUtils;
public class OnTextFunction implements Function<String, Void>
{
private static final DynamicArgs.Builder ARGBUILDER;
private static final int SESSION = 1;
private static final int TEXT = 2;
private static final Arg SESSION = new Arg(1,Session.class);
private static final Arg TEXT = new Arg(2,String.class);
static
{
ARGBUILDER = new DynamicArgs.Builder();
ARGBUILDER.addSignature(new ExactSignature(String.class).indexedAs(TEXT));
ARGBUILDER.addSignature(new ExactSignature(Session.class,String.class).indexedAs(SESSION,TEXT));
ARGBUILDER.addSignature(new ExactSignature(String.class));
ARGBUILDER.addSignature(new ExactSignature(Session.class,String.class));
}
public static DynamicArgs.Builder getDynamicArgsBuilder()
{
return ARGBUILDER;
}
public static boolean hasMatchingSignature(Method method)
{
return ARGBUILDER.hasMatchingSignature(method);
@ -72,21 +73,19 @@ public class OnTextFunction implements Function<String, Void>
ReflectUtils.assertIsPublicNonStatic(method);
ReflectUtils.assertIsReturn(method,Void.TYPE);
this.callable = ARGBUILDER.build(method);
this.callable = ARGBUILDER.build(method,SESSION,TEXT);
if (this.callable == null)
{
throw InvalidSignatureException.build(method,OnWebSocketMessage.class,ARGBUILDER);
}
this.callable.setArgReferences(SESSION,TEXT);
}
@Override
public Void apply(String text)
{
Object args[] = this.callable.toArgs(session,text);
try
{
method.invoke(endpoint,args);
this.callable.invoke(endpoint,session,text);
}
catch (IllegalAccessException | IllegalArgumentException | InvocationTargetException e)
{

View File

@ -0,0 +1,24 @@
//
// ========================================================================
// 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.util;
import java.util.function.Function;
public interface ArgIdentifier extends Function<DynamicArgs.Arg,DynamicArgs.Arg> {
}

View File

@ -18,12 +18,16 @@
package org.eclipse.jetty.websocket.common.util;
import org.eclipse.jetty.util.annotation.Name;
import java.lang.annotation.Annotation;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.List;
import java.util.ServiceLoader;
import java.util.function.BiFunction;
import java.util.function.Predicate;
import java.util.function.BiPredicate;
/**
* Provide argument utilities for working with methods that
@ -41,16 +45,16 @@ public class DynamicArgs
{
/**
* Predicate to test if signature matches
*
*
* @return the predicate to test if signature matches
*/
public Predicate<Class<?>[]> getPredicate();
public BiPredicate<Method, Class<?>[]> getPredicate();
/**
* BiFunction to use to invoke method
* against give object, with provided (potential) arguments,
* returning appropriate result from invocation.
*
*
* @param method
* the method to base BiFunction off of.
* @param callArgs
@ -65,21 +69,59 @@ public class DynamicArgs
public static class Arg
{
public final Class<?> type;
public Method method;
public int index;
public Object tag;
public Arg(Class<?> type)
{
this.type = type;
}
public Arg(int idx, Class<?> type)
{
this.index = idx;
this.type = type;
}
public int index;
public Class<?> type;
public Object tag;
public Arg(Method method, int idx, Class<?> type)
{
this.method = method;
this.index = idx;
this.type = type;
}
public Arg setTag(String tag)
{
this.tag = tag;
return this;
}
@Override
public String toString()
{
return String.format("%s[%d%s]",type.getSimpleName(),index,tag == null ? "" : "/" + tag);
}
public <T extends Annotation> T getAnnotation(Class<T> annoClass)
{
if(method == null)
return null;
Annotation annos[] = method.getParameterAnnotations()[index];
if(annos != null || (annos.length > 0))
{
for(Annotation anno: annos)
{
if(anno.annotationType().equals(annoClass))
{
return (T) anno;
}
}
}
return null;
}
}
public static class Builder
@ -88,10 +130,12 @@ public class DynamicArgs
public DynamicArgs build(Method method, Arg... callArgs)
{
// FIXME: add DynamicArgs build cache (key = method+callargs)
Class<?> paramTypes[] = method.getParameterTypes();
for (Signature sig : signatures)
{
if (sig.getPredicate().test(paramTypes))
if (sig.getPredicate().test(method, paramTypes))
{
return new DynamicArgs(sig.getInvoker(method,callArgs));
}
@ -100,6 +144,28 @@ public class DynamicArgs
return null;
}
/**
* Used to identify a possible method signature match.
*
* @param method the method to test
* @return true if it is a match
*/
public boolean hasMatchingSignature(Method method)
{
// FIXME: add match cache (key = method)
Class<?> paramTypes[] = method.getParameterTypes();
for (Signature sig : signatures)
{
if (sig.getPredicate().test(method, paramTypes))
{
return true;
}
}
return false;
}
public Builder addSignature(Signature sig)
{
signatures.add(sig);
@ -116,6 +182,23 @@ public class DynamicArgs
}
}
private static List<ArgIdentifier> argIdentifiers;
public static List<ArgIdentifier> lookupArgIdentifiers()
{
if (argIdentifiers == null)
{
ServiceLoader<ArgIdentifier> loader = ServiceLoader.load(ArgIdentifier.class);
argIdentifiers = new ArrayList<>();
for (ArgIdentifier argId : loader)
{
argIdentifiers.add(argId);
}
}
return argIdentifiers;
}
private final BiFunction<Object, Object[], Object> invoker;
private DynamicArgs(BiFunction<Object, Object[], Object> invoker)
@ -125,7 +208,7 @@ public class DynamicArgs
/**
* Invoke the signature / method with the provided potential args.
*
*
* @param o
* the object to call method on
* @param potentialArgs

View File

@ -21,28 +21,45 @@ package org.eclipse.jetty.websocket.common.util;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.function.BiFunction;
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.Signature;
public class ExactSignature implements Signature, Predicate<Class<?>[]>
public class ExactSignature implements Signature, BiPredicate<Method,Class<?>[]>
{
private final Arg[] params;
public ExactSignature()
{
this.params = new Arg[0];
}
public ExactSignature(Arg... 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
public Predicate<Class<?>[]> getPredicate()
public BiPredicate<Method,Class<?>[]> getPredicate()
{
return this;
}
@Override
public boolean test(Class<?>[] types)
public boolean test(Method method, Class<?>[] types)
{
if (types.length != params.length)
return false;
@ -158,4 +175,4 @@ public class ExactSignature implements Signature, Predicate<Class<?>[]>
}
};
}
}
}

View File

@ -0,0 +1,36 @@
//
// ========================================================================
// 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.util;
import org.eclipse.jetty.util.annotation.Name;
/**
* Arg Identifier based on jetty's {@link org.eclipse.jetty.util.annotation.Name} annotation.
*/
public class NameArgIdentifier implements ArgIdentifier
{
@Override
public DynamicArgs.Arg apply(DynamicArgs.Arg arg)
{
Name name = arg.getAnnotation(Name.class);
if (name != null)
arg.tag = name.value();
return arg;
}
}

View File

@ -22,13 +22,15 @@ import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.List;
import java.util.ServiceLoader;
import java.util.function.BiFunction;
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.Signature;
public class UnorderedSignature implements Signature, Predicate<Class<?>[]>
public class UnorderedSignature implements Signature, BiPredicate<Method, Class<?>[]>
{
private final Arg[] params;
@ -36,31 +38,56 @@ public class UnorderedSignature implements Signature, Predicate<Class<?>[]>
{
this.params = args;
}
@Override
public Predicate<Class<?>[]> getPredicate()
public BiPredicate<Method, Class<?>[]> getPredicate()
{
return this;
}
@Override
public boolean test(Class<?>[] types)
public boolean test(Method method, Class<?>[] types)
{
// Matches if the provided types
// match the valid params in any order
int len = types.length;
for (int i = 0; i < len; i++)
// 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 callArgsLen = params.length;
List<ArgIdentifier> argIdentifiers = DynamicArgs.lookupArgIdentifiers();
for (int mi = 0; mi < paramTypesLength; mi++)
{
UnorderedSignature.Param p = findParam(types[i]);
if (p == null)
DynamicArgs.Arg methodArg = new DynamicArgs.Arg(method, mi, paramTypes[mi]);
for (ArgIdentifier argId : argIdentifiers)
methodArg = argId.apply(methodArg);
int ref = -1;
// Find reference to argument in callArgs
for (int ci = 0; ci < callArgsLen; ci++)
{
if (methodArg.tag != null && methodArg.tag.equals(params[ci].tag))
{
ref = ci;
}
else if (methodArg.type == params[ci].type)
{
ref = ci;
}
}
if (ref < 0)
{
return false;
}
}
return true;
}
public void appendDescription(StringBuilder str)
{
@ -82,7 +109,7 @@ public class UnorderedSignature implements Signature, Predicate<Class<?>[]>
}
str.append(')');
}
@Override
public BiFunction<Object, Object[], Object> getInvoker(Method method, Arg... callArgs)
{
@ -94,17 +121,24 @@ public class UnorderedSignature implements Signature, Predicate<Class<?>[]>
int argMapping[] = new int[paramTypesLength];
int callArgsLen = callArgs.length;
List<ArgIdentifier> argIdentifiers = DynamicArgs.lookupArgIdentifiers();
for (int mi = 0; mi < paramTypesLength; mi++)
{
// TODO: ask optional ArgFunction to populate method.paramTypes[i] Arg
// TODO: perhaps have this be loaded via ServiceLoader
// TODO: jsr356 impl can find @PathParam and populate the Arg.tag entry
DynamicArgs.Arg methodArg = new DynamicArgs.Arg(method, mi, paramTypes[mi]);
for (ArgIdentifier argId : argIdentifiers)
methodArg = argId.apply(methodArg);
int ref = -1;
// Find reference to argument in callArgs
for (int ci = 0; ci < callArgsLen; ci++)
{
if (callArgs[ci].index == params[mi].index)
if (methodArg.tag != null && methodArg.tag.equals(callArgs[ci].tag))
{
ref = ci;
}
else if (methodArg.index == callArgs[ci].index)
{
ref = ci;
}
@ -169,4 +203,4 @@ public class UnorderedSignature implements Signature, Predicate<Class<?>[]>
}
};
}
}
}

View File

@ -0,0 +1 @@
org.eclipse.jetty.websocket.common.util.NameArgIdentifier

View File

@ -25,6 +25,8 @@ import static org.junit.Assert.assertThat;
import java.io.File;
import java.lang.reflect.Method;
import org.eclipse.jetty.util.annotation.Name;
import org.eclipse.jetty.websocket.common.util.DynamicArgs.Arg;
import org.junit.Test;
public class UnorderedSignatureTest
@ -40,23 +42,23 @@ public class UnorderedSignatureTest
{
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, boolean fin)
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, int offset, 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);
}
@ -73,93 +75,108 @@ public class UnorderedSignatureTest
}
throw new AssertionError("Unable to find method: " + name);
}
private static final int ROLE_STR = 1;
private static final int ROLE_BOOL = 2;
private static final int ROLE_FILE = 3;
private static final int ROLE_BYTEARRAY = 4;
private static final int ROLE_OFFSET = 5;
private static final int ROLE_LEN = 6;
private static final int ROLE_FIN = 7;
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
{
DynamicArgs.Builder<String> dab = new DynamicArgs.Builder<>();
dab.addSignature(new UnorderedSignature()
.addParam(String.class,ROLE_STR)
.addParam(File.class,ROLE_FILE)
.addParam(Boolean.class,ROLE_FIN));
DynamicArgs.Builder dab = new DynamicArgs.Builder();
dab.addSignature(new UnorderedSignature());
SampleSignatures ssigs = new SampleSignatures();
Method m = findMethodByName(ssigs, "sigEmpty");
DynamicArgs dargs = dab.build(m);
assertThat("DynamicArgs", dargs, notNullValue());
dargs.setArgReferences(ROLE_STR,ROLE_BOOL,ROLE_FILE);
// Test with potential args
Object args[] = dargs.toArgs("Hello", Boolean.TRUE, new File("bar"));
String result = (String)m.invoke(ssigs,args);
assertThat("result", result, is("sigEmpty<>"));
// Test with empty potential args
args = dargs.toArgs();
result = (String)m.invoke(ssigs,args);
String result = (String) dargs.invoke(ssigs);
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
{
DynamicArgs.Builder dab = new DynamicArgs.Builder();
dab.addSignature(new UnorderedSignature(ARG_STR));
SampleSignatures ssigs = new SampleSignatures();
Method m = findMethodByName(ssigs, "sigEmpty");
DynamicArgs dargs = dab.build(m);
assertThat("DynamicArgs", dargs, notNullValue());
// Test with empty potential args
String result = (String) dargs.invoke(ssigs, "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
{
DynamicArgs.Builder dab = new DynamicArgs.Builder();
dab.addSignature(new UnorderedSignature()
.addParam(String.class,ROLE_STR)
.addParam(File.class,ROLE_FILE)
.addParam(Boolean.class,ROLE_FIN));
dab.addSignature(new UnorderedSignature(ARG_STR));
final Arg CALL_STR = new Arg(String.class);
SampleSignatures ssigs = new SampleSignatures();
Method m = findMethodByName(ssigs, "sigStr");
DynamicArgs dargs = dab.build(m);
DynamicArgs dargs = dab.build(m, CALL_STR);
assertThat("DynamicArgs", dargs, notNullValue());
dargs.setArgReferences(ROLE_STR,ROLE_BOOL,ROLE_FILE);
// Test with potential args
Object args[] = dargs.toArgs("Hello", Boolean.TRUE, new File("bar"));
String result = (String)m.invoke(ssigs,args);
String result = (String) dargs.invoke(ssigs, "Hello");
assertThat("result", result, is("sigStr<Hello>"));
// Test with empty potential args
args = dargs.toArgs();
result = (String)m.invoke(ssigs,args);
assertThat("result", result, is("sigStr<null>"));
}
/**
* 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
{
DynamicArgs.Builder dab = new DynamicArgs.Builder();
dab.addSignature(new UnorderedSignature()
.addParam(String.class,ROLE_STR)
.addParam(File.class,ROLE_FILE)
.addParam(Boolean.class,ROLE_FIN));
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 dargs = dab.build(m);
DynamicArgs dargs = dab.build(m,CALL_BYTEARRAY, CALL_OFFSET, CALL_LENGTH);
assertThat("DynamicArgs", dargs, notNullValue());
dargs.setArgReferences(ROLE_BYTEARRAY,ROLE_OFFSET,ROLE_LEN);
// Test with potential args
byte buf[] = new byte[222];
int offset = 3;
int len = 44;
String result = (String)dargs.invoke(m,ssigs,buf,offset,len);
assertThat("result", result, is("sigByteArray<[222],3,44>"));
// Test with empty potential args
result = (String)dargs.invoke(m,ssigs,null,123,456);
assertThat("result", result, is("sigByteArray<<null>,123,456>"));