Skip to content

Commit

Permalink
JS<->Java mapping in a common place.
Browse files Browse the repository at this point in the history
  • Loading branch information
tschaub committed Sep 11, 2012
1 parent 2a39c1c commit 279e2ff
Show file tree
Hide file tree
Showing 2 changed files with 76 additions and 35 deletions.
65 changes: 60 additions & 5 deletions src/main/java/org/geoscript/js/GeoObject.java
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand All @@ -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;
Expand Down Expand Up @@ -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<String, Object> jsObjectToMap(Scriptable obj) {
HashMap<String, Object> map = new HashMap<String, Object>();
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.
Expand All @@ -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);
Expand All @@ -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<length; ++i) {
array.put(i, array, javaToJS(list.get(i), scope));
}
return array;
}

/**
* Convert a Java map into a JavaScript object.
* @param map
* @param scope
* @return
*/
public static NativeObject mapToJSObject(Map<?, ?> 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;
}

}
46 changes: 16 additions & 30 deletions src/main/java/org/geoscript/js/process/Process.java
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -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<String, Object> inputsMap = jsObjectToMap(inputsObj);

// validate inputs
Expand All @@ -134,9 +138,11 @@ public Scriptable run(Scriptable inputsObj) {
}

Map<String, Object> 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<String, Parameter<?>> createParameterMap(Scriptable obj) {
Expand Down Expand Up @@ -308,27 +314,6 @@ public static Object constructor(Context cx, Object[] args, Function ctorObj, bo
return process;
}

private Scriptable mapToJSObject(Map<String, Object> 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<String, Object> jsObjectToMap(Scriptable obj) {
HashMap<String, Object> outputsMap = new HashMap<String, Object>();
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<String> processNames = new ArrayList<String>();
Expand All @@ -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);
Expand Down Expand Up @@ -383,9 +368,10 @@ public Map<String, Object> execute(Map<String, Object> inputs,
Scriptable outputsObj;
Map<String, Object> 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) {
Expand Down

0 comments on commit 279e2ff

Please sign in to comment.