From 279e2ffcfb090c98bfd215e31a1ac7e73c83529a Mon Sep 17 00:00:00 2001 From: tschaub Date: Mon, 10 Sep 2012 18:47:30 -0600 Subject: [PATCH] JS<->Java mapping in a common place. --- src/main/java/org/geoscript/js/GeoObject.java | 65 +++++++++++++++++-- .../org/geoscript/js/process/Process.java | 46 +++++-------- 2 files changed, 76 insertions(+), 35 deletions(-) diff --git a/src/main/java/org/geoscript/js/GeoObject.java b/src/main/java/org/geoscript/js/GeoObject.java index 1856b739..81607485 100644 --- a/src/main/java/org/geoscript/js/GeoObject.java +++ b/src/main/java/org/geoscript/js/GeoObject.java @@ -5,6 +5,9 @@ import java.sql.Date; import java.sql.Time; import java.sql.Timestamp; +import java.util.HashMap; +import java.util.List; +import java.util.Map; import org.geoscript.js.feature.FeatureCollection; import org.geoscript.js.feature.Feature; @@ -16,6 +19,7 @@ import org.mozilla.javascript.Context; import org.mozilla.javascript.NativeArray; import org.mozilla.javascript.NativeJSON; +import org.mozilla.javascript.NativeObject; import org.mozilla.javascript.ScriptRuntime; import org.mozilla.javascript.Scriptable; import org.mozilla.javascript.ScriptableObject; @@ -287,12 +291,29 @@ public static Object jsToJava(Object value) { if (value instanceof Wrapper) { value = ((Wrapper) value).unwrap(); } else if (value instanceof Scriptable) { - if (((Scriptable) value).getClassName().equals("Date")) { + if (value instanceof NativeObject) { + value = jsObjectToMap((Scriptable) value); + } else if (((Scriptable) value).getClassName().equals("Date")) { value = Context.jsToJava(value, java.util.Date.class); } } return value; } + + /** + * Convert a JavaScript object into a Java map. + * @param obj + * @return + */ + public static Map jsObjectToMap(Scriptable obj) { + HashMap map = new HashMap(); + Object[] ids = obj.getIds(); + for (Object id : ids) { + String name = (String) id; + map.put(name, jsToJava(obj.get(name, obj))); + } + return map; + } /** * Convert a Java object into the appropriate JavaScript type. @@ -301,13 +322,16 @@ public static Object jsToJava(Object value) { * @return */ public static Object javaToJS(Object value, Scriptable scope) { - if (value instanceof java.util.Date) { + if (value instanceof Map) { + value = mapToJSObject((Map) value, scope); + } else if (value instanceof List) { + value = listToJSArray((List) value, scope); + } else if (value instanceof java.util.Date) { java.util.Date date = (java.util.Date) value; Object[] args = { new Long(date.getTime()) }; - Context cx = GeoObject.getCurrentContext(); + Context cx = getCurrentContext(); value = cx.newObject(scope, "Date", args); - } - if (value instanceof com.vividsolutions.jts.geom.Geometry) { + } else if (value instanceof com.vividsolutions.jts.geom.Geometry) { value = GeometryWrapper.wrap(scope, (com.vividsolutions.jts.geom.Geometry) value); } else if (value instanceof ReferencedEnvelope) { value = new Bounds(scope, (ReferencedEnvelope) value); @@ -320,5 +344,36 @@ public static Object javaToJS(Object value, Scriptable scope) { } return Context.javaToJS(value, scope); } + + /** + * Convert a Java list to a JavaScript array. + * @param value + * @param scope + * @return + */ + private static NativeArray listToJSArray(List list, Scriptable scope) { + int length = list.size(); + Context cx = getCurrentContext(); + NativeArray array = (NativeArray) cx.newArray(scope, length); + for (int i=0; i map, Scriptable scope) { + Context context = getCurrentContext(); + NativeObject obj = (NativeObject) context.newObject(scope); + for (Object id : map.keySet()) { + obj.put(id.toString(), obj, javaToJS(map.get(id), scope)); + } + return obj; + } } diff --git a/src/main/java/org/geoscript/js/process/Process.java b/src/main/java/org/geoscript/js/process/Process.java index 4300c690..4356d5e1 100644 --- a/src/main/java/org/geoscript/js/process/Process.java +++ b/src/main/java/org/geoscript/js/process/Process.java @@ -24,6 +24,7 @@ import org.mozilla.javascript.NativeObject; import org.mozilla.javascript.ScriptRuntime; import org.mozilla.javascript.Scriptable; +import org.mozilla.javascript.ScriptableObject; import org.mozilla.javascript.Wrapper; import org.mozilla.javascript.annotations.JSConstructor; import org.mozilla.javascript.annotations.JSFunction; @@ -108,7 +109,10 @@ public Process(Scriptable scope, InternationalString title, } @JSFunction - public Scriptable run(Scriptable inputsObj) { + public NativeObject run(Scriptable inputsObj) { + if (!(inputsObj instanceof NativeObject)) { + throw ScriptRuntime.constructError("Error", "The run method takes an inputs object as argument"); + } Map inputsMap = jsObjectToMap(inputsObj); // validate inputs @@ -134,9 +138,11 @@ public Scriptable run(Scriptable inputsObj) { } Map outputsMap = process.execute(inputsMap, null); - - Scriptable outputsObj = mapToJSObject(outputsMap); - return outputsObj; + Object obj = javaToJS(outputsMap, getParentScope()); + if (!(obj instanceof NativeObject)) { + throw ScriptRuntime.constructError("Error", "Unable to parse process outputs"); + } + return (NativeObject) obj; } private Map> createParameterMap(Scriptable obj) { @@ -308,27 +314,6 @@ public static Object constructor(Context cx, Object[] args, Function ctorObj, bo return process; } - private Scriptable mapToJSObject(Map map) { - Context context = getCurrentContext(); - Scriptable scope = getParentScope(); - Scriptable inputsObj = context.newObject(scope); - for (String id : map.keySet()) { - Object value = javaToJS(map.get(id), scope); - inputsObj.put(id, inputsObj, value); - } - return inputsObj; - } - - private Map jsObjectToMap(Scriptable obj) { - HashMap outputsMap = new HashMap(); - Object[] ids = obj.getIds(); - for (Object id : ids) { - String name = (String) id; - outputsMap.put(name, jsToJava(obj.get(name, obj))); - } - return outputsMap; - } - @JSStaticFunction public static NativeArray getNames() { List processNames = new ArrayList(); @@ -345,14 +330,14 @@ public static NativeArray getNames() { } @JSStaticFunction - public static Process get(String processName) { + public static Process get(Scriptable processNameObj) { Process jsProcess = null; - String[] parts = processName.split(":"); + String[] parts = processNameObj.toString().split(":"); Name name = new NameImpl(parts[0], parts[1]); ProcessFactory factory = Processors.createProcessFactory(name); if (factory != null) { org.geotools.process.Process process = factory.create(name); - Scriptable scope = ScriptRuntime.getTopCallScope(getCurrentContext()); + Scriptable scope = ScriptableObject.getTopLevelScope(processNameObj); jsProcess = new Process(scope, factory.getTitle(name), factory.getDescription(name), factory.getParameterInfo(name), factory.getResultInfo(name, null), process); @@ -383,9 +368,10 @@ public Map execute(Map inputs, Scriptable outputsObj; Map outputs = null; Context cx = Context.enter(); + Scriptable scope = runFunc.getParentScope(); try { - Scriptable inputsObj = mapToJSObject(inputs); - outputsObj = (Scriptable) runFunc.call(cx, getParentScope(), + Object inputsObj = javaToJS(inputs, scope); + outputsObj = (Scriptable) runFunc.call(cx, scope, process, new Object[] {inputsObj}); outputs = jsObjectToMap(outputsObj); } catch (Exception e) {