From 49127140ed2ad91bfcf532b3d2265582cb80b0db Mon Sep 17 00:00:00 2001 From: Stefan Radomski Date: Wed, 14 May 2014 18:51:56 +0200 Subject: Retain interpreter instance for DataModels in Java (Rhino) --- .../datamodel/ecmascript/ECMAScriptDataModel.java | 137 +++++++++++++++-- contrib/java/src/org/uscxml/tests/TestData.java | 2 +- .../java/src/org/uscxml/tests/TestDataModel.java | 162 --------------------- contrib/java/src/org/uscxml/tests/TestW3CECMA.java | 4 +- src/bindings/swig/java/JavaDataModel.h | 7 +- src/bindings/swig/java/uscxml.i | 12 ++ src/uscxml/interpreter/InterpreterDraft6.cpp | 4 +- .../datamodel/ecmascript/v8/V8DataModel.cpp | 2 +- test/uscxml/java/test-ecmascript-datamodel.scxml | 2 +- 9 files changed, 149 insertions(+), 183 deletions(-) delete mode 100644 contrib/java/src/org/uscxml/tests/TestDataModel.java diff --git a/contrib/java/src/org/uscxml/datamodel/ecmascript/ECMAScriptDataModel.java b/contrib/java/src/org/uscxml/datamodel/ecmascript/ECMAScriptDataModel.java index ba4319f..3d77dc5 100644 --- a/contrib/java/src/org/uscxml/datamodel/ecmascript/ECMAScriptDataModel.java +++ b/contrib/java/src/org/uscxml/datamodel/ecmascript/ECMAScriptDataModel.java @@ -1,7 +1,11 @@ package org.uscxml.datamodel.ecmascript; +import java.lang.reflect.Method; + import org.mozilla.javascript.Callable; import org.mozilla.javascript.Context; +import org.mozilla.javascript.EvaluatorException; +import org.mozilla.javascript.FunctionObject; import org.mozilla.javascript.NativeJSON; import org.mozilla.javascript.Scriptable; import org.mozilla.javascript.ScriptableObject; @@ -16,6 +20,8 @@ import org.uscxml.StringVector; public class ECMAScriptDataModel extends JavaDataModel { + public static boolean debug = true; + private class NullCallable implements Callable { @Override public Object call(Context context, Scriptable scope, @@ -26,6 +32,7 @@ public class ECMAScriptDataModel extends JavaDataModel { public Context ctx; public Scriptable scope; + public Interpreter interpreter; public Data getScriptableAsData(Object object) { Data data = new Data(); @@ -65,6 +72,10 @@ public class ECMAScriptDataModel extends JavaDataModel { throw new UnsupportedOperationException("Not implemented"); } + public static boolean jsIn(String stateName) { + return true; + } + @Override public JavaDataModel create(Interpreter interpreter) { /** @@ -72,22 +83,61 @@ public class ECMAScriptDataModel extends JavaDataModel { * Be careful to instantiate attributes of instance returned and not * *this* */ + ECMAScriptDataModel newDM = new ECMAScriptDataModel(); + newDM.interpreter = interpreter; newDM.ctx = Context.enter(); - Data ioProcs = new Data(); - StringVector keys = interpreter.getIOProcessorKeys(); - for (int i = 0; i < keys.size(); i++) { - ioProcs.compound.put(keys.get(i), new Data(interpreter.getIOProcessors().get(keys.get(i)).getDataModelVariables())); - } - try { newDM.scope = newDM.ctx.initStandardObjects(); - newDM.scope.put("_ioprocessors", newDM.scope, new ECMAData(ioProcs)); } catch (Exception e) { System.err.println(e); } + newDM.scope.put("_name", newDM.scope, interpreter.getName()); + newDM.scope.put("_sessionid", newDM.scope, interpreter.getSessionId()); + + // ioProcessors + { + Data ioProcs = new Data(); + StringVector keys = interpreter.getIOProcessorKeys(); + for (int i = 0; i < keys.size(); i++) { + ioProcs.compound.put(keys.get(i), new Data(interpreter + .getIOProcessors().get(keys.get(i)) + .getDataModelVariables())); + } + newDM.scope + .put("_ioprocessors", newDM.scope, new ECMAData(ioProcs)); + } + + // invokers + { + Data invokers = new Data(); + StringVector keys = interpreter.getInvokerKeys(); + for (int i = 0; i < keys.size(); i++) { + invokers.compound.put(keys.get(i), new Data(interpreter + .getInvokers().get(keys.get(i)) + .getDataModelVariables())); + } + newDM.scope + .put("_ioprocessors", newDM.scope, new ECMAData(invokers)); + } + + // In predicate (not working as static is required) see: + // http://stackoverflow.com/questions/3441947/how-do-i-call-a-method-of-a-java-instance-from-javascript/16479685#16479685 + try { + Class[] parameters = new Class[] { String.class }; + Method inMethod = ECMAScriptDataModel.class.getMethod("jsIn", + parameters); + FunctionObject inFunc = new FunctionObject("In", inMethod, + newDM.scope); + newDM.scope.put("In", newDM.scope, inFunc); + } catch (SecurityException e) { + System.err.println(e); + } catch (NoSuchMethodException e) { + System.err.println(e); + } + return newDM; } @@ -113,16 +163,24 @@ public class ECMAScriptDataModel extends JavaDataModel { @Override public void setEvent(Event event) { + if (debug) { + System.out.println(interpreter.getName() + " setEvent"); + } + /** * Make the current event available as the variable _event in the * datamodel. */ - ECMAEvent ecmaEvent = new ECMAEvent(event); + ECMAEvent ecmaEvent = new ECMAEvent(event); scope.put("_event", scope, ecmaEvent); } @Override public DataNative getStringAsData(String content) { + if (debug) { + System.out.println(interpreter.getName() + " getStringAsData"); + } + /** * Evaluate the string as a value expression and transform it into a * JSON-like Data structure @@ -139,8 +197,9 @@ public class ECMAScriptDataModel extends JavaDataModel { return Data.toNative(getScriptableAsData(json)); } } catch (org.mozilla.javascript.EcmaError e) { + System.err.println(e); } - + // is it a function call or variable? Object x = ctx.evaluateString(scope, content, "uscxml", 0, null); if (x == Undefined.instance) { @@ -153,6 +212,10 @@ public class ECMAScriptDataModel extends JavaDataModel { @Override public long getLength(String expr) { + if (debug) { + System.out.println(interpreter.getName() + " getLength"); + } + /** * Return the length of the expression if it were an array, used by * foreach element. @@ -173,6 +236,10 @@ public class ECMAScriptDataModel extends JavaDataModel { @Override public void setForeach(String item, String array, String index, long iteration) { + if (debug) { + System.out.println(interpreter.getName() + " setForeach"); + } + /** * Prepare an iteration of the foreach element, by setting the variable * in index to the current iteration and setting the variable in item to @@ -191,7 +258,7 @@ public class ECMAScriptDataModel extends JavaDataModel { "uscxml", 1, null); } } else { - // we ought to throw a error.execution + handleException(""); } } catch (ClassCastException e) { @@ -201,6 +268,10 @@ public class ECMAScriptDataModel extends JavaDataModel { @Override public void eval(String scriptElem, String expr) { + if (debug) { + System.out.println(interpreter.getName() + " eval"); + } + /** * Evaluate the given expression in the datamodel. This is used foremost * with script elements. @@ -211,15 +282,36 @@ public class ECMAScriptDataModel extends JavaDataModel { @Override public String evalAsString(String expr) { + if (debug) { + System.out.println(interpreter.getName() + " evalAsString: " + expr); + } + /** * Evaluate the expression as a string e.g. for the log element. */ - Object result = ctx.evaluateString(scope, expr, "uscxml", 1, null); - return Context.toString(result); + if (!ctx.stringIsCompilableUnit(expr)) { + handleException(""); + return ""; + } + try { + Object result = ctx.evaluateString(scope, expr, "uscxml", 1, null); + return Context.toString(result); + } catch (IllegalStateException e) { + System.err.println(e); + handleException(""); + } catch (EvaluatorException e) { + System.err.println(e); + handleException(""); + } + return ""; } @Override public boolean evalAsBool(String elem, String expr) { + if (debug) { + System.out.println(interpreter.getName() + " evalAsBool"); + } + /** * Evaluate the expression as a boolean for cond attributes in if and * transition elements. @@ -230,6 +322,10 @@ public class ECMAScriptDataModel extends JavaDataModel { @Override public boolean isDeclared(String expr) { + if (debug) { + System.out.println(interpreter.getName() + " isDeclared"); + } + /** * The interpreter is supposed to raise an error if we assign to an * undeclared variable. This method is used to check whether a location @@ -241,6 +337,10 @@ public class ECMAScriptDataModel extends JavaDataModel { @Override public void init(String dataElem, String location, String content) { + if (debug) { + System.out.println(interpreter.getName() + " init"); + } + /** * Called when we pass data elements. */ @@ -267,6 +367,10 @@ public class ECMAScriptDataModel extends JavaDataModel { @Override public void assign(String assignElem, String location, String content) { + if (debug) { + System.out.println(interpreter.getName() + " assign"); + } + /** * Called when we evaluate assign elements */ @@ -279,7 +383,14 @@ public class ECMAScriptDataModel extends JavaDataModel { } String expr = location + "=" + content; - ctx.evaluateString(scope, expr, "uscxml", 1, null); + ctx.evaluateString(scope, expr, "uscxml", 1, null); } + public void handleException(String cause) { + Event exceptionEvent = new Event(); + exceptionEvent.setName("error.execution"); + exceptionEvent.setEventType(Event.Type.PLATFORM); + + interpreter.receiveInternal(exceptionEvent); + } } diff --git a/contrib/java/src/org/uscxml/tests/TestData.java b/contrib/java/src/org/uscxml/tests/TestData.java index fc8deda..44f1ce0 100644 --- a/contrib/java/src/org/uscxml/tests/TestData.java +++ b/contrib/java/src/org/uscxml/tests/TestData.java @@ -6,7 +6,7 @@ import org.uscxml.DataNative; public class TestData { public static void main(String[] args) { - System.load("/Users/sradomski/Documents/TK/Code/uscxml/build/cli/lib/libuscxmlNativeJava64_d.jnilib"); + System.load("/Users/sradomski/Documents/TK/Code/uscxml/build/cli/lib/libuscxmlNativeJava64.jnilib"); { Data data = Data.fromJSON("[1,2,3,4,5]"); DataNative nData2 = Data.toNative(data); diff --git a/contrib/java/src/org/uscxml/tests/TestDataModel.java b/contrib/java/src/org/uscxml/tests/TestDataModel.java deleted file mode 100644 index e813d66..0000000 --- a/contrib/java/src/org/uscxml/tests/TestDataModel.java +++ /dev/null @@ -1,162 +0,0 @@ -package org.uscxml.tests; - -import org.uscxml.Data; -import org.uscxml.DataNative; -import org.uscxml.Event; -import org.uscxml.Factory; -import org.uscxml.Interpreter; -import org.uscxml.JavaDataModel; -import org.uscxml.StringSet; - -public class TestDataModel extends JavaDataModel { - - @Override - public JavaDataModel create(Interpreter interpreter) { - /** - * Called when an SCXML interpreter wants an instance of this datamodel - */ - System.out.println("create"); - return new TestDataModel(); - } - - @Override - public StringSet getNames() { - /** - * Register with the following names for the datamodel attribute at the - * scxml element. - */ - System.out.println("getNames"); - StringSet ss = new StringSet(); - ss.insert("java"); - return ss; - } - - @Override - public boolean validate(String location, String schema) { - /** - * Validate the datamodel. This make more sense for XML datamodels and - * is pretty much unused but required as per draft. - */ - System.out.println("validate " + location + " " + schema); - return true; - } - - @Override - public void setEvent(Event event) { - /** - * Make the current event available as the variable _event in the - * datamodel. - */ - System.out.println("setEvent " + event); - } - - @Override - public DataNative getStringAsData(String content) { - /** - * Evaluate the string as a value expression and transform it into a - * JSON-like Data structure - */ - System.out.println("getStringAsData " + content); - Data data = new Data(); - return Data.toNative(data); - } - - @Override - public long getLength(String expr) { - /** - * Return the length of the expression if it were an array, used by - * foreach element. - */ - System.out.println("getLength " + expr); - return 0; - } - - @Override - public void setForeach(String item, String array, String index, - long iteration) { - /** - * Prepare an iteration of the foreach element, by setting the variable - * in index to the current iteration and setting the variable in item to - * the current item from array. - */ - System.out - .println("setForeach " + item + " " + index + " " + iteration); - } - - @Override - public void eval(String scriptElem, String expr) { - /** - * Evaluate the given expression in the datamodel. This is used foremost - * with script elements. - */ - System.out.println("eval " + scriptElem + " " + expr); - } - - @Override - public String evalAsString(String expr) { - /** - * Evaluate the expression as a string e.g. for the log element. - */ - System.out.println("evalAsString " + expr); - return ""; - } - - @Override - public boolean evalAsBool(String expr) { - /** - * Evaluate the expression as a boolean for cond attributes in if and - * transition elements. - */ - System.out.println("evalAsBool " + expr); - return true; - } - - @Override - public boolean isDeclared(String expr) { - /** - * The interpreter is supposed to raise an error if we assign to an - * undeclared variable. This method is used to check whether a location - * from assign is declared. - */ - System.out.println("isDeclared " + expr); - return true; - } - - @Override - public void init(String dataElem, String location, String content) { - /** - * Called when we pass data elements. - */ - System.out.println("init " + dataElem + " " + location + " " + content); - } - - @Override - public void assign(String assignElem, String location, String content) { - /** - * Called when we evaluate assign elements - */ - System.out.println("assign " + assignElem + " " + location + " " - + content); - } - - /** - * @param args - */ - public static void main(String[] args) { - // load JNI library from build directory - System.load("/Users/sradomski/Documents/TK/Code/uscxml/build/cli/lib/libuscxmlNativeJava64.jnilib"); - - // register java datamodel at factory - TestDataModel datamodel = new TestDataModel(); - Factory.getInstance().registerDataModel(datamodel); - - // instantiate interpreter with document from file - Interpreter interpreter = Interpreter - .fromURI("/Users/sradomski/Documents/TK/Code/uscxml/test/uscxml/java/test-java-datamodel.scxml"); - - // wait until interpreter has finished - while (true) - interpreter.interpret(); - } - -} diff --git a/contrib/java/src/org/uscxml/tests/TestW3CECMA.java b/contrib/java/src/org/uscxml/tests/TestW3CECMA.java index 9cedee0..0949701 100644 --- a/contrib/java/src/org/uscxml/tests/TestW3CECMA.java +++ b/contrib/java/src/org/uscxml/tests/TestW3CECMA.java @@ -20,10 +20,10 @@ public class TestW3CECMA { // while(true) { // System.out.println("### test235 #####"); -// Interpreter interpreter = Interpreter.fromURI("/Users/sradomski/Documents/TK/Code/uscxml/test/w3c/ecma/test235.scxml"); +// Interpreter interpreter = Interpreter.fromURI("/Users/sradomski/Documents/TK/Code/uscxml/test/w3c/ecma/test144.scxml"); // interpreter.interpret(); // } -// + File dir = new File(testDir); File[] filesList = dir.listFiles(); for (File file : filesList) { diff --git a/src/bindings/swig/java/JavaDataModel.h b/src/bindings/swig/java/JavaDataModel.h index fcfb665..4fe6cbe 100644 --- a/src/bindings/swig/java/JavaDataModel.h +++ b/src/bindings/swig/java/JavaDataModel.h @@ -12,12 +12,13 @@ public: JavaDataModel(); virtual ~JavaDataModel(); - virtual JavaDataModel* create(Interpreter interpreter) { + virtual JavaDataModel* create(const Interpreter& interpreter) { return new JavaDataModel(); } virtual boost::shared_ptr create(InterpreterImpl* interpreter) { - return boost::shared_ptr(create(interpreter->shared_from_this())); + _interpreter = interpreter->shared_from_this(); + return boost::shared_ptr(create(_interpreter)); } virtual std::set getNames() { return std::set(); @@ -131,6 +132,8 @@ public: virtual void assign(const std::string& assignElem, const std::string& location, const std::string& content) {} virtual void eval(const std::string& scriptElem, const std::string& expr) {} +private: + Interpreter _interpreter; }; } diff --git a/src/bindings/swig/java/uscxml.i b/src/bindings/swig/java/uscxml.i index a88ebf1..5dac9d2 100644 --- a/src/bindings/swig/java/uscxml.i +++ b/src/bindings/swig/java/uscxml.i @@ -101,6 +101,7 @@ using namespace Arabica::DOM; %template(ParamPair) std::pair; %template(ParamPairVector) std::vector >; %template(IOProcMap) std::map; +%template(InvokerMap) std::map; %rename Data DataNative; # %typemap(jstype) uscxml::Data "Data" @@ -140,6 +141,17 @@ using namespace Arabica::DOM; } return keys; } + + std::vector getInvokerKeys() { + std::vector keys; + std::map::const_iterator iter = self->getInvokers().begin(); + while(iter != self->getInvokers().end()) { + keys.push_back(iter->first); + iter++; + } + return keys; + } + }; %extend uscxml::Data { diff --git a/src/uscxml/interpreter/InterpreterDraft6.cpp b/src/uscxml/interpreter/InterpreterDraft6.cpp index 31c433c..f80ad24 100644 --- a/src/uscxml/interpreter/InterpreterDraft6.cpp +++ b/src/uscxml/interpreter/InterpreterDraft6.cpp @@ -23,6 +23,8 @@ #include "uscxml/UUID.h" #include "uscxml/DOMUtils.h" +#define VERBOSE 0 + namespace uscxml { using namespace Arabica::XPath; @@ -185,7 +187,7 @@ void InterpreterDraft6::mainEventLoop() { // Here we handle eventless transitions and transitions // triggered by internal events until machine is stable while(_running && !_stable) { -#if 0 +#if VERBOSE std::cout << "Configuration: "; for (int i = 0; i < _configuration.size(); i++) { std::cout << ATTR(_configuration[i], "id") << ", "; diff --git a/src/uscxml/plugins/datamodel/ecmascript/v8/V8DataModel.cpp b/src/uscxml/plugins/datamodel/ecmascript/v8/V8DataModel.cpp index 385ee1c..bddea83 100644 --- a/src/uscxml/plugins/datamodel/ecmascript/v8/V8DataModel.cpp +++ b/src/uscxml/plugins/datamodel/ecmascript/v8/V8DataModel.cpp @@ -712,7 +712,7 @@ void V8DataModel::throwExceptionEvent(const v8::TryCatch& tryCatch) { std::string sourceLine(*v8::String::AsciiValue(message->GetSourceLine())); size_t startpos = sourceLine.find_first_not_of(" \t"); - if(std::string::npos != startpos) // removoe leading white space + if(std::string::npos != startpos) // remove leading white space sourceLine = sourceLine.substr(startpos); exceptionEvent.data.compound["sourceline"] = Data(sourceLine, Data::VERBATIM); diff --git a/test/uscxml/java/test-ecmascript-datamodel.scxml b/test/uscxml/java/test-ecmascript-datamodel.scxml index 4ec157c..14e75b3 100644 --- a/test/uscxml/java/test-ecmascript-datamodel.scxml +++ b/test/uscxml/java/test-ecmascript-datamodel.scxml @@ -1,4 +1,4 @@ - + -- cgit v0.12