package dovetaildb.scriptbridge;
import java.util.Collection;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import org.mozilla.javascript.Context;
import org.mozilla.javascript.Function;
import org.mozilla.javascript.NativeObject;
import org.mozilla.javascript.Scriptable;
import org.mozilla.javascript.ScriptableObject;
import dovetaildb.apiservice.ApiException;
import dovetaildb.util.Pair;
import dovetaildb.util.Util;
public class RhinoScriptBridge implements ScriptBridge {
NativeObject scope;
static class RhinoScriptFunction extends ScriptFunction {
final Function function;
final Object[] argArray;
final NativeObject scope;
RhinoScriptFunction(Function function, int numArgs, NativeObject scope) {
this.function = function;
this.argArray = new Object[numArgs];
this.scope = scope;
}
static class ScriptableAs
private Object JsToJavaJson(Object obj, Scriptable scope) {
if (obj instanceof Scriptable) {
Scriptable scriptable = (Scriptable)obj;
Context.getElements();
HashMap<Object,Object> ret = new HashMap<Object,Object>();
boolean isNumberKeys
for(Object key: ScriptableObject.getPropertyIds(scriptable)) {
Object val;
if (key.getClass() == String.class) {
val = ScriptableObject.getProperty(scriptable, (String)key);
} else {
val = ScriptableObject.getProperty(scriptable, ((Number)key).intValue());
}
ret.put(key, val);
}
}
Context.jsToJava(o, ?);
}
private Object javaJsonToJS(Object o) {
if (o instanceof Scriptable) {
return o;
} else if (o instanceof Map) {
Map map = (Map)o;
NativeObject nativeObj = new NativeObject();
for(Object entryObj : map.entrySet()) {
Map.Entry entry = (Map.Entry) entryObj;
Object val = javaJsonToJS(entry.getValue());
nativeObj.put((String)entry.getKey(), scope, val);
}
return nativeObj;
} else if (o instanceof List) {
List list = (List)o;
NativeObject nativeObj = new NativeObject();
int idx = 0;
for(Object subObj : list) {
Object val = javaJsonToJS(subObj);
nativeObj.put(idx++, scope, val);
}
return nativeObj;
} else {
return Context.javaToJS(o, scope);
}
}
@Override
public Object call(Object[] arguments) {
Context jsContext = Context.enter();
try {
int i=0;
for (Object arg : arguments) {
argArray[i++] = javaJsonToJS(arg);
}
Object result = function.call(jsContext, scope, null, argArray);
//result = wrapScriptable(result);
return result;
} finally {
Context.exit();
}
}
}
class RhinoScriptEnv extends ScriptEnv {
@Override
public ScriptFunction getFunction(String fnname, int numParameters) {
Object functionObject = scope.get(fnname, scope);
if (functionObject == null) return null;
if (!(functionObject instanceof Function))
throw new ApiException("InvalidFunction","The object named \""+fnname+"\" is not a function.");
Function function = (Function)functionObject;
return new RhinoScriptFunction(function, numParameters, scope);
}
@Override
public Object getObject(String objectName) {
return scope.get(objectName, scope);
}
}
public ScriptEnv makeEnvFromCodeExecution(Collection<Pair<String,String>> codeFiles, Map<String, Object> globals) {
Context jsContext = Context.enter();
try {
NativeObject scope = (NativeObject)jsContext.initStandardObjects();
for(Map.Entry<String,Object> entry : globals.entrySet()) {
ScriptableObject.putProperty(scope, entry.getKey(), Context.javaToJS(entry.getValue(), scope));
}
for(Pair<String,String> file : codeFiles) {
String fileName = file.getLeft();
String code = file.getRight();
jsContext.evaluateString(scope, code, fileName, 1, null);
}
return new RhinoScriptEnv();
} finally {
Context.exit();
}
}
public Object evaluateExpression(String string, Map<String, Object> globals) {
Context jsContext = Context.enter();
try {
NativeObject scope = (NativeObject)jsContext.initStandardObjects();
for(Map.Entry<String,Object> entry : globals.entrySet()) {
ScriptableObject.putProperty(scope, entry.getKey(), Context.javaToJS(entry.getValue(), scope));
}
return jsContext.evaluateString(scope, string, "<execute>", 1, null);
} finally {
Context.exit();
}
}
}