package org.oddjob.script;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import org.oddjob.arooa.convert.ArooaConversionException;
import org.oddjob.arooa.convert.ConversionProvider;
import org.oddjob.arooa.convert.ConversionRegistry;
import org.oddjob.arooa.convert.Convertlet;
/**
* An {@link Invoker} for a java method.
*
* @author rob
*
*/
public class MethodInvoker implements Invoker {
public static class Conversions implements ConversionProvider {
public void registerWith(ConversionRegistry registry) {
registry.register(Object.class, Invoker.class,
new Convertlet<Object, Invoker>() {
public Invoker convert(Object from) {
return new MethodInvoker(from);
}
});
}
}
private final Object target;
/**
* Constructor.
*
* @param target The object that contains the method.
*/
public MethodInvoker(Object target) {
if (target == null) {
throw new NullPointerException("No target for invoker");
}
this.target = target;
}
@Override
public Object invoke(String name, InvokerArguments parameters)
throws IllegalArgumentException, IllegalAccessException, InvocationTargetException {
Class<?> cl;
MethodName methodName = new MethodName(name);
Object object = this.target;
if (methodName.staticMethod && object instanceof Class<?>) {
cl = (Class<?>) object;
object = null;
}
else {
cl = object.getClass();
}
Method[] ms = cl.getMethods();
Method found = null;
Method maybe = null;
Object[] args = null;
for (Method m: ms) {
if (!m.getName().equals(methodName.method)) {
continue;
}
maybe = m;
if (parameters.size() != m.getParameterTypes().length) {
continue;
}
args = new Object[parameters.size()];
try {
for (int i = 0; i < args.length; ++i) {
args[i] = parameters.getArgument(i,
m.getParameterTypes()[i]);
}
}
catch (ArooaConversionException e) {
continue;
}
found = m;
break;
}
if (found == null) {
if (maybe == null) {
throw new IllegalArgumentException("No method found on [" +
target + "] " + name);
}
else {
throw new IllegalArgumentException("No method with matching args on [" +
target + "], There is : " + maybe);
}
}
return found.invoke(object, args);
}
class MethodName {
final String method;
final boolean staticMethod;
public MethodName(String name) {
Pattern pattern = Pattern.compile(
"(static\\s+)?(\\w+)");
// 1 2
Matcher matcher = pattern.matcher(name);
if (!matcher.matches()) {
throw new IllegalArgumentException(
"Failed to parse method name " +
name);
}
staticMethod = matcher.group(1) != null;
method = matcher.group(2);
}
}
}