package dovetaildb.scriptbridge;
import java.lang.reflect.Constructor;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.Collection;
import java.util.Map;
import dovetaildb.apiservice.ApiException;
import dovetaildb.util.Pair;
public class NativeScriptBridge implements ScriptBridge {
Map<String,Object> globals;
static class NativeScriptFunction extends ScriptFunction {
final Object instance;
final Method method;
NativeScriptFunction(Object instance, Method method) {
this.instance = instance;
this.method = method;
}
@Override
public Object call(Object[] parameters) {
try {
return method.invoke(instance, parameters);
} catch (IllegalArgumentException e) {
throw new ApiException("InvalidFunction", e.getMessage());
} catch (IllegalAccessException e) {
throw new ApiException("InvalidFunction", e.getMessage());
} catch (InvocationTargetException e) {
throw new ApiException("InvalidFunction", e.getMessage());
}
}
}
class NativeScriptEnv extends ScriptEnv {
Class clazz;
@Override
public ScriptFunction getFunction(String functionName, int numParameters) {
int lastDot = functionName.lastIndexOf('.');
if (lastDot == -1)
throw new ApiException("InvalidFunction", "funtion name must include a fully qualified class name; do not know how to resolve \""+functionName+"\"");
String className = functionName.substring(0, lastDot);
functionName = functionName.substring(lastDot+1);
Object instance = getObject(className);
Method[] methods = clazz.getMethods();
if (methods.length != 1) {
if (methods.length == 0)
throw new ApiException("InvalidFunction","There is no method named \""+functionName+"\" on "+className);
else
throw new ApiException("InvalidFunction","There is more than one method named \""+functionName+"\" on "+className);
}
return new NativeScriptFunction(instance, methods[0]);
}
@Override
public Object getObject(String className) {
try {
clazz = Class.forName(className);
} catch(ClassNotFoundException e) {
throw new ApiException("InvalidFunction", "There is no class named \""+className+"\"");
}
Constructor constructor = clazz.getConstructors()[0];
try {
return constructor.newInstance(new Object[]{globals});
} catch (IllegalArgumentException e) {
throw new ApiException("InvalidFunction", e.getMessage());
} catch (InstantiationException e) {
throw new ApiException("InvalidFunction", e.getMessage());
} catch (IllegalAccessException e) {
throw new ApiException("InvalidFunction", e.getMessage());
} catch (InvocationTargetException e) {
throw new ApiException("InvalidFunction", e.getMessage());
}
}
}
public ScriptEnv makeEnvFromCodeExecution(Collection<Pair<String,String>> codeFiles, Map<String, Object> globals) {
this.globals = globals;
return new NativeScriptEnv();
}
public Object evaluateExpression(String code, Map<String, Object> globals) {
throw new ApiException("LanguageFeatureNotSupported", "Cannot evaluate a Java expression at runtime");
}
}