You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@commons.apache.org by at...@apache.org on 2016/01/02 16:11:39 UTC

commons-scxml git commit: SCXML-245: Reimplement Nashorn Javascript Evaluator - See: https://issues.apache.org/jira/browse/SCXML-245 for details

Repository: commons-scxml
Updated Branches:
  refs/heads/master 031f8ff32 -> 1b91a77c1


SCXML-245: Reimplement Nashorn Javascript Evaluator
- See: https://issues.apache.org/jira/browse/SCXML-245 for details


Project: http://git-wip-us.apache.org/repos/asf/commons-scxml/repo
Commit: http://git-wip-us.apache.org/repos/asf/commons-scxml/commit/1b91a77c
Tree: http://git-wip-us.apache.org/repos/asf/commons-scxml/tree/1b91a77c
Diff: http://git-wip-us.apache.org/repos/asf/commons-scxml/diff/1b91a77c

Branch: refs/heads/master
Commit: 1b91a77c1a41a57799da93ce0ba3a4b58760148e
Parents: 031f8ff
Author: Ate Douma <at...@apache.org>
Authored: Sat Jan 2 16:11:30 2016 +0100
Committer: Ate Douma <at...@apache.org>
Committed: Sat Jan 2 16:11:30 2016 +0100

----------------------------------------------------------------------
 pom.xml                                         |   9 +
 .../scxml2/env/javascript/JSBindings.java       | 277 ++------
 .../scxml2/env/javascript/JSContext.java        |  15 +-
 .../scxml2/env/javascript/JSEvaluator.java      | 192 ++++--
 .../scxml2/env/javascript/JSFunctions.java      |  50 --
 .../scxml2/env/javascript/init_global.js        | 142 ++++
 .../scxml2/env/javascript/JSBindingsTest.java   | 669 -------------------
 .../env/javascript/JavaScriptEngineTest.java    | 108 +--
 .../org/apache/commons/scxml2/w3c/tests.xml     |  14 +-
 9 files changed, 390 insertions(+), 1086 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/commons-scxml/blob/1b91a77c/pom.xml
----------------------------------------------------------------------
diff --git a/pom.xml b/pom.xml
index 06d3a65..a6bf606 100644
--- a/pom.xml
+++ b/pom.xml
@@ -204,6 +204,15 @@
 
   <build>
     <sourceDirectory>src/main/java</sourceDirectory>
+    <resources>
+      <resource>
+        <filtering>false</filtering>
+        <directory>src/main/java</directory>
+        <includes>
+          <include>**/*.js</include>
+        </includes>
+      </resource>
+    </resources>
     <testSourceDirectory>src/test/java</testSourceDirectory>
     <testResources>
       <testResource>

http://git-wip-us.apache.org/repos/asf/commons-scxml/blob/1b91a77c/src/main/java/org/apache/commons/scxml2/env/javascript/JSBindings.java
----------------------------------------------------------------------
diff --git a/src/main/java/org/apache/commons/scxml2/env/javascript/JSBindings.java b/src/main/java/org/apache/commons/scxml2/env/javascript/JSBindings.java
index 6b7142f..dc9ab7c 100644
--- a/src/main/java/org/apache/commons/scxml2/env/javascript/JSBindings.java
+++ b/src/main/java/org/apache/commons/scxml2/env/javascript/JSBindings.java
@@ -18,339 +18,154 @@
 package org.apache.commons.scxml2.env.javascript;
 
 import java.util.Collection;
-import java.util.HashSet;
 import java.util.Map;
 import java.util.Set;
 
 import javax.script.Bindings;
-import javax.script.SimpleBindings;
 
 import org.apache.commons.scxml2.Context;
 
 /**
- * Wrapper class for the JDK Javascript engine Bindings class that extends the
- * wrapped Bindings to search the SCXML context for variables and predefined
- * functions that do not exist in the wrapped Bindings.
- *
+ * JDK Javascript engine Bindings class that delegates to a SCXML context
  */
 public class JSBindings implements Bindings {
 
-    private static final String NASHORN_GLOBAL = "nashorn.global";
-
-    // INSTANCE VARIABLES
-
-    private Bindings bindings;
-    private Context  context;
-
-    // CONSTRUCTORS
+    private JSContext  context;
 
     /**
-     * Initialises the internal Bindings delegate and SCXML context.
+     * Initialise the Bindings
      *
-     * @param context  SCXML Context to use for script variables.
-     * @param bindings Javascript engine bindings for Javascript variables.
+     * @param jsContext initial SCXML Context to use for script variables.
      *
-     * @throws IllegalArgumentException Thrown if either <code>context</code>
-     *         or <code>bindings</code> is <code>null</code>.
+     * @throws IllegalArgumentException Thrown if <code>jsContext</code> is <code>null</code>.
      *
      */
-    public JSBindings(Context context, Bindings bindings) {
-        // ... validate
-
-        if (context == null) {
-           throw new IllegalArgumentException("Invalid SCXML context");
-        }
+    public JSBindings(JSContext jsContext) {
+        setContext(jsContext);
+    }
 
-        if (bindings == null) {
-           throw new IllegalArgumentException("Invalid script Bindings");
+    /**
+     * Set or update the SCXML context delegate
+     *
+     * @param jsContext the SCXML context to use for script variables.
+     * @throws IllegalArgumentException Thrown if <code>jsContext</code> is <code>null</code>.
+     */
+    public void setContext(JSContext jsContext) {
+        if (jsContext == null) {
+            throw new IllegalArgumentException("SCXML context is required");
         }
-
-        // ... initialise
-
-        this.bindings = bindings;
-        this.context = context;
+        this.context = jsContext;
     }
 
-    // INSTANCE METHODS
-
     /**
-     * Returns <code>true</code> if the wrapped Bindings delegate
-     * or SCXML context  contains a variable identified by
-     * <code>key</code>.
-     *
+     * Returns <code>true</code> if the SCXML context contains a variable identified by <code>key</code>.
      */
     @Override
     public boolean containsKey(Object key) {
-        if (hasGlobalBindings() && getGlobalBindings().containsKey(key)) {
-            return true;
-        }
-
-        if (bindings.containsKey(key)) {
-            return true;
-        }
-
         return context.has(key.toString());
     }
 
     /**
-     * Returns a union of the wrapped Bindings entry set and the
-     * SCXML context entry set.
-     * <p>
-     * NOTE: doesn't seem to be invoked ever. Not thread-safe.
-     *
+     * Returns the SCXML context key set
      */
     @Override
     public Set<String> keySet() {
-        Set<String> keys = new HashSet<String>();
-
-        keys.addAll(context.getVars().keySet());
-        keys.addAll(bindings.keySet());
-
-        if (hasGlobalBindings()) {
-            keys.addAll(getGlobalBindings().keySet());
-        }
-
-        return keys;
+        return context.getVars().keySet();
     }
 
     /**
-     * Returns the combined size of the wrapped Bindings entry set and the
-     * SCXML context entry set.
-     * <p>
-     * NOTE: doesn't seem to be invoked ever so not sure if it works in
-     *       context. Not thread-safe.
-     *
+     * Returns the size of the SCXML context size.
      */
     @Override
     public int size() {
-        Set<String> keys = new HashSet<String>();
-
-        keys.addAll(context.getVars().keySet());
-        keys.addAll(bindings.keySet());
-
-        if (hasGlobalBindings()) {
-            keys.addAll(getGlobalBindings().keySet());
-        }
-
-        return keys.size();
+        return context.getVars().size();
     }
 
     /**
-     * Returns <code>true</code> if the wrapped Bindings delegate
-     * or SCXML context contains <code>value</code>.
-     * <p>
-     * NOTE: doesn't seem to be invoked ever so not sure if it works in
-     *       context. Not thread-safe.
+     * Returns <code>true</code> if the SCXML context contains <code>value</code>.
      */
     @Override
     public boolean containsValue(Object value) {
-        if (hasGlobalBindings() && getGlobalBindings().containsValue(value)) {
-            return true;
-        }
-
-        if (bindings.containsValue(value)) {
-            return true;
-        }
-
         return context.getVars().containsValue(value);
     }
 
     /**
-     * Returns a union of the wrapped Bindings entry set and the
-     * SCXML context entry set.
-     * <p>
-     * NOTE: doesn't seem to be invoked ever so not sure if it works in
-     *       context. Not thread-safe.
+     * Returns the SCXML context entry set.
      */
     @Override
     public Set<Map.Entry<String,Object>> entrySet() {
-        return union().entrySet();
+        return context.getVars().entrySet();
     }
 
     /**
-     * Returns a union of the wrapped Bindings value list and the
-     * SCXML context value list.
-     * <p>
-     * NOTE: doesn't seem to be invoked ever so not sure if it works in
-     *       context. Not thread-safe.
+     * Returns the SCXML context values.
      */
     @Override
     public Collection<Object> values() {
-        return union().values();
+        return context.getVars().values();
     }
 
     /**
-     * Returns a <code>true</code> if both the Bindings delegate and
-     * the SCXML context maps are empty.
-     * <p>
-     * NOTE: doesn't seem to be invoked ever so not sure if it works in
-     *       context. Not thread-safe.
+     * Returns <code>true</code> if the SCXML context is empty.
      */
     @Override
     public boolean isEmpty() {
-        if (hasGlobalBindings() && !getGlobalBindings().isEmpty()) {
-            return false;
-        }
-
-        if (!bindings.isEmpty()) {
-            return false;
-        }
-
         return context.getVars().isEmpty();
     }
 
     /**
-     * Returns the value from the wrapped Bindings delegate
-     * or SCXML context contains identified by <code>key</code>.
-     *
+     * Returns the value from the SCXML context identified by <code>key</code>.
      */
     @Override
     public Object get(Object key) {
-        // nashorn.global should be retrieved from the bindings, not from context.
-        if (NASHORN_GLOBAL.equals(key)) {
-            return bindings.get(key);
-        }
-
-        if (hasGlobalBindings() && getGlobalBindings().containsKey(key)) {
-            return getGlobalBindings().get(key);
-        }
-
-        if (bindings.containsKey(key)) {
-            return bindings.get(key);
-        }
-
         return context.get(key.toString());
     }
 
     /**
      * The following delegation model is used to set values:
      * <ol>
-     *   <li>Delegates to {@link Context#set(String,Object)} if the
-     *       {@link Context} contains the key (name), else</li>
-     *   <li>Delegates to the wrapped {@link Bindings#put(String, Object)}
-     *       if the {@link Bindings} contains the key (name), else</li>
+     *   <li>Delegates to {@link Context#set(String,Object)} if the Context contains the key (name), else</li>
      *   <li>Delegates to {@link Context#setLocal(String, Object)}</li>
      * </ol>
-     *
+     * @param name The variable name
+     * @param value The variable value
      */
     @Override
     public Object put(String name, Object value) {
-        Object old = context.get(name);
-
-        // nashorn.global should be put into the bindings, not into context.
-        if (NASHORN_GLOBAL.equals(name)) {
-            return bindings.put(name, value);
-        } else if (context.has(name)) {
+        Object old = null;
+        if (context.has(name)) {
+            old = context.get(name);
             context.set(name, value);
-        } else if (bindings.containsKey(name)) {
-            return bindings.put(name, value);
-        } else if (hasGlobalBindings() && getGlobalBindings().containsKey(name)) {
-            return getGlobalBindings().put(name, value);
         } else {
             context.setLocal(name, value);
         }
-
         return old;
     }
 
     /**
-     * Delegates to the wrapped Bindings <code>putAll</code> method i.e. does
-     * not store variables in the SCXML context.
-     * <p>
-     * NOTE: doesn't seem to be invoked ever so not sure if it works in
-     *       context. Not thread-safe.
+     * Sets all entries in the provided map via {@link #put(String, Object)}
+     * @param toMerge the map of variables to merge
      */
     @Override
     public void putAll(Map<? extends String, ? extends Object> toMerge) {
-        bindings.putAll(toMerge);
+        for (Map.Entry<? extends String, ? extends Object> entry : toMerge.entrySet()) {
+            put(entry.getKey(), entry.getValue());
+        }
     }
 
     /**
-     * Removes the object from the wrapped Bindings instance or the contained
-     * SCXML context. Not entirely sure about this implementation but it
-     * follows the philosophy of using the Javascript Bindings as a child context
-     * of the SCXML context.
-     * <p>
-     * NOTE: doesn't seem to be invoked ever so not sure if it works in
-     *       context. Not thread-safe.
+     * Removes the named variable from the contained SCXML context.
+     * @param name the variable name
      */
     @Override
-    public Object remove(Object key) {
-        if (hasGlobalBindings() && getGlobalBindings().containsKey(key)) {
-            getGlobalBindings().remove(key);
-        }
-
-        if (bindings.containsKey(key)) {
-            return bindings.remove(key);
-        }
-
-        if (context.has(key.toString())) {
-            return context.getVars().remove(key);
-        }
-
-        return Boolean.FALSE;
+    public Object remove(Object name) {
+        return context.getVars().remove(name);
     }
 
     /**
-     * Delegates to the wrapped Bindings <code>clear</code> method. Does not clear
-     * the SCXML context.
-     * <p>
-     * NOTE: doesn't seem to be invoked ever so not sure if it works in
-     *       context. Not thread-safe.
+     * Does nothing - never invoked anyway
      */
     @Override
     public void clear() {
-        bindings.clear();
-    }
-
-    /**
-     * Internal method to create a union of the SCXML context and the Javascript
-     * Bindings. Does a heavyweight copy - and so far only invoked by the
-     * not used methods.
-     */
-    private Bindings union() {
-        Bindings set = new SimpleBindings();
-
-        set.putAll(context.getVars());
-
-        for (String key : bindings.keySet()) {
-            set.put(key, bindings.get(key));
-        }
-
-        if (hasGlobalBindings()) {
-            for (String key : getGlobalBindings().keySet()) {
-                set.put(key, getGlobalBindings().get(key));
-            }
-        }
-
-        return set;
-    }
-
-    /**
-     * Return true if a global bindings (i.e. nashorn Global instance) was ever set by the script engine.
-     * <p>
-     * Note: because the global binding can be set by the script engine when evaluating a script, we should
-     *       check or retrieve the global binding whenever needed instead of initialization time.
-     * </p>
-     * @return true if a global bindings (i.e. nashorn Global instance) was ever set by the script engine
-     */
-    protected boolean hasGlobalBindings() {
-        if (bindings.containsKey(NASHORN_GLOBAL)) {
-            return true;
-        }
-
-        return false;
-    }
-
-    /**
-     * Return the global bindings (i.e. nashorn Global instance) set by the script engine if existing.
-     * @return the global bindings (i.e. nashorn Global instance) set by the script engine, or null if not existing.
-     */
-    protected Bindings getGlobalBindings() {
-        if (bindings.containsKey(NASHORN_GLOBAL)) {
-            return (Bindings) bindings.get(NASHORN_GLOBAL);
-        }
-
-        return null;
     }
 }

http://git-wip-us.apache.org/repos/asf/commons-scxml/blob/1b91a77c/src/main/java/org/apache/commons/scxml2/env/javascript/JSContext.java
----------------------------------------------------------------------
diff --git a/src/main/java/org/apache/commons/scxml2/env/javascript/JSContext.java b/src/main/java/org/apache/commons/scxml2/env/javascript/JSContext.java
index d63d25a..f1b063c 100644
--- a/src/main/java/org/apache/commons/scxml2/env/javascript/JSContext.java
+++ b/src/main/java/org/apache/commons/scxml2/env/javascript/JSContext.java
@@ -27,26 +27,21 @@ import org.apache.commons.scxml2.env.SimpleContext;
  * extension of SimpleContext that has been implemented to reduce the impact
  * if the JSEvaluator requires additional functionality at a later stage.
  * <p>
- * Could easily be dispensed with.
- *
  */
 public class JSContext extends SimpleContext {
 
     /** Serial version UID. */
     private static final long serialVersionUID = 1L;
 
-    // CONSTRUCTORS
-
     /**
-     * Default constructor - just invokes the SimpleContext default
-     * constructor.
+     * Default constructor - just invokes the SimpleContext default constructor.
      */
     public JSContext() {
         super();
     }
 
     /**
-     * Constructor with initial vars.
+     * Constructor with initial vars - Just invokes the identical SimpleContext constructor.
      * @param parent The parent context
      * @param initialVars The initial set of variables.
      */
@@ -55,15 +50,11 @@ public class JSContext extends SimpleContext {
     }
 
     /**
-     * Child constructor. Just invokes the identical SimpleContext
-     * constructor.
-     *
+     * Child constructor - Just invokes the identical SimpleContext constructor.
      * @param parent Parent context for this context.
-     *
      */
     public JSContext(final Context parent) {
         super(parent);
     }
-
 }
 

http://git-wip-us.apache.org/repos/asf/commons-scxml/blob/1b91a77c/src/main/java/org/apache/commons/scxml2/env/javascript/JSEvaluator.java
----------------------------------------------------------------------
diff --git a/src/main/java/org/apache/commons/scxml2/env/javascript/JSEvaluator.java b/src/main/java/org/apache/commons/scxml2/env/javascript/JSEvaluator.java
index 2f9641d..d71933e 100644
--- a/src/main/java/org/apache/commons/scxml2/env/javascript/JSEvaluator.java
+++ b/src/main/java/org/apache/commons/scxml2/env/javascript/JSEvaluator.java
@@ -17,14 +17,17 @@
 
 package org.apache.commons.scxml2.env.javascript;
 
+import java.io.IOException;
 import java.util.UUID;
-import java.util.regex.Pattern;
 
 import javax.script.Bindings;
 import javax.script.ScriptContext;
 import javax.script.ScriptEngine;
 import javax.script.ScriptEngineManager;
+import javax.script.ScriptException;
+import javax.script.SimpleScriptContext;
 
+import org.apache.commons.io.IOUtils;
 import org.apache.commons.scxml2.Context;
 import org.apache.commons.scxml2.Evaluator;
 import org.apache.commons.scxml2.EvaluatorProvider;
@@ -34,11 +37,21 @@ import org.apache.commons.scxml2.env.EffectiveContextMap;
 import org.apache.commons.scxml2.model.SCXML;
 
 /**
- * Embedded JavaScript expression evaluator for SCXML expressions. This
- * implementation is a just a 'thin' wrapper around the Javascript engine in
- * JDK 8.
+ * Embedded JavaScript expression evaluator for SCXML expressions using the JDK 8+ Nashorn Script Engine.
+ * <p>
+ * Each JSEvaluator maintains a single {@link ScriptContext} instance to be used for only a single SCXML instance as
+ * the Nashorn global state is shared through the {@link ScriptContext#ENGINE_SCOPE} binding.
+ * </p>
+ * <p>Sharing and reusing JSEvaluator instances for multiple SCXML instances therefore should <em>not</em> be done.</p>
+ * <p>
+ * As the JDK Script Engine state is <em>not</em> serializable, and neither are Javascript <code>native</code> Objects,
+ * the {@link ScriptContext} state is <em>not</em> retained during serialization (transient).
+ * </p>
+ * <p>
+ * SCXML instance (de)serialization using the javascript language therefore only will work reliably as long as no
+ * Javascript native Objects are used/stored in the context nor (other) modifications are made to the Nashorn global state.
+ * </p>
  */
-
 public class JSEvaluator extends AbstractBaseEvaluator {
 
     /**
@@ -66,33 +79,98 @@ public class JSEvaluator extends AbstractBaseEvaluator {
         }
     }
 
+    private static final String SCXML_SYSTEM_CONTEXT = "_scxmlSystemContext";
+
     /** Error message if evaluation context is not a JexlContext. */
     private static final String ERR_CTX_TYPE = "Error evaluating JavaScript "
             + "expression, Context must be a org.apache.commons.scxml2.env.javascript.JSContext";
 
-    /** Pattern for recognizing the SCXML In() special predicate. */
-    private static final Pattern IN_FN = Pattern.compile("In\\(");
+    /** shared singleton Nashorn ScriptEngine **/
+    private static ScriptEngine engine;
 
-    // INSTANCE VARIABLES
+    /** Nashorn Global initialization script, loaded from <code>init_global.js</code> classpath resource */
+    private static String initGlobalsScript;
 
-    private transient ScriptEngineManager factory;
-
-    // CONSTRUCTORS
+    /** ScriptContext for a single SCXML instance (JSEvaluator also cannot be shared between SCXML instances) */
+    private transient ScriptContext scriptContext;
 
     /**
-     * Initialises the internal Javascript engine factory.
+     * Initialize the singleton Javascript ScriptEngine to be used with a separate ScriptContext for each SCXML instance
+     * not sharing their global scope, see {@link #getScriptContext(JSContext)}.
+     * <p>
+     * The SCXML required protected system variables and (possible) other Javascript global initializations are defined
+     * in a <code>init_global.js</code> script which is pre-loaded as (classpath) resource, to be executed once during
+     * initialization of a new Javascript (Nashorn) Global.
+     * </p>
      */
-    public JSEvaluator() {
-        factory = new ScriptEngineManager();
+    protected synchronized static void initEngine() {
+        if (engine == null) {
+            engine = new ScriptEngineManager().getEngineByName("JavaScript");
+            try {
+                initGlobalsScript = IOUtils.toString(JSEvaluator.class.getResourceAsStream("init_global.js"), "UTF-8");
+            }
+            catch (IOException ioe) {
+                throw new RuntimeException("Failed to load init_global.js from classpath", ioe);
+            }
+        }
     }
 
-    // INSTANCE METHODS
+    /**
+     * Get the singleton ScriptEngine, initializing it on first access
+     * @return The ScriptEngine
+     */
+    protected ScriptEngine getEngine() {
+        if (engine == null) {
+            initEngine();
+        }
+        return engine;
+    }
 
-    protected ScriptEngineManager getFactory() {
-        if (factory == null) {
-            factory = new ScriptEngineManager();
+    /**
+     * Get the current ScriptContext or create a new one.
+     * <p>
+     * The ScriptContext is (to be) shared across invocations for the same SCXML instance as it holds the Javascript 'global'
+     * context.
+     * </p>
+     * <p>
+     * The ScriptContext is using a {@link ScriptContext#ENGINE_SCOPE} as provided by the engine, which in case of Nashorn
+     * is bound to the Javscript global context. Note: do <em>not</em> confuse this with the {@link ScriptContext#GLOBAL_SCOPE} binding.
+     * </p>
+     * <p>For a newly created ScriptContext (and thus a new Javascript global context), the Javascript global context is
+     * initialized with the required and protected SCXML system variables and builtin In() operator via the
+     * <code>init_global.js</code> script, loaded as classpath resource.</p>
+     * <p>
+     * The SCXML system variables are bound as <code>"_scxmlSystemContext"</code> variable in the ENGINE_SCOPE
+     * as needed for the <code>init_global.js</code> script in the global context.
+     * This variable is bound to the ENGINE_SCOPE to ensure it cannot be 'shadowed' by an overriding variable assignment.
+     * </p>
+     * The provided SCXML Context variables are bound via the GLOBAL_SCOPE using a {@link JSBindings} wrapper for each
+     * invocation.
+     * </p>
+     * <p>
+     * As the GLOBAL_SCOPE SCXML context variables <em>can</em> be overridden, which will result in new 'shadow'
+     * variables in the ENGINE_SCOPE, as well as new variables can be added to the ENGINE_SCOPE during script evaluation,
+     * after script execution all ENGINE_SCOPE variables (except the <code>"_scxmlSystemContext"</code> variable) must be
+     * copied/merged into the SCXML context to synchronize the SCXML context.
+     * </p>
+     * @param jsContext The current SCXML context
+     * @return The SCXML instance shared ScriptContext
+     * @throws ScriptException Thrown if the initialization of the Global Javascript engine itself failed
+     */
+    protected ScriptContext getScriptContext(JSContext jsContext) throws ScriptException {
+        if (scriptContext == null) {
+            scriptContext = new SimpleScriptContext();
+            scriptContext.setBindings(getEngine().createBindings(), ScriptContext.ENGINE_SCOPE);
+            scriptContext.setBindings(new JSBindings(jsContext), ScriptContext.GLOBAL_SCOPE);
+            scriptContext.getBindings(ScriptContext.ENGINE_SCOPE).put(SCXML_SYSTEM_CONTEXT, jsContext.getSystemContext().getVars());
+            getEngine().eval(initGlobalsScript, scriptContext);
+        }
+        else {
+            // ensure updated / replaced SystemContext is used (like after SCXML instance go/reset)
+            scriptContext.getBindings(ScriptContext.ENGINE_SCOPE).put(SCXML_SYSTEM_CONTEXT, jsContext.getSystemContext().getVars());
+            ((JSBindings)scriptContext.getBindings(ScriptContext.GLOBAL_SCOPE)).setContext(jsContext);
         }
-        return factory;
+        return scriptContext;
     }
 
     @Override
@@ -121,50 +199,32 @@ public class JSEvaluator extends AbstractBaseEvaluator {
     }
 
     /**
-     * Evaluates the expression using a new Javascript engine obtained from
-     * factory instantiated in the constructor. The engine is supplied with
-     * a new JSBindings that includes the SCXML Context and SCXML builtin
-     * <code>In()</code> function is replaced with an equivalent internal
-     * Javascript function.
-     *
+     * Evaluates a Javascript expression using an SCXML instance shared {@link #getScriptContext(JSContext)}.
+     * <p>
+     * After evaluation all the resulting Javascript Global context (in {@link ScriptContext#ENGINE_SCOPE} are first
+     * copied/merged back into the SCXML context, before the evaluation result (if any) is returned.
+     * </p>
      * @param context    SCXML context.
      * @param expression Expression to evaluate.
-     *
      * @return Result of expression evaluation or <code>null</code>.
-     *
-     * @throws SCXMLExpressionException Thrown if the expression was invalid.
+     * @throws SCXMLExpressionException Thrown if the expression was invalid or the execution raised an error itself.
      */
     @Override
     public Object eval(Context context, String expression) throws SCXMLExpressionException {
         if (expression == null) {
             return null;
         }
-
         if (!(context instanceof JSContext)) {
             throw new SCXMLExpressionException(ERR_CTX_TYPE);
         }
 
         try {
-            JSContext effectiveContext = getEffectiveContext((JSContext) context);
-
-            // ... initialize
-            ScriptEngine engine = getFactory().getEngineByName("JavaScript");
-            Bindings bindings = engine.getBindings(ScriptContext.ENGINE_SCOPE);
-
-            // ... replace built-in functions
-            String jsExpression = IN_FN.matcher(expression).replaceAll("_builtin.In(");
-
-            // ... evaluate
-            JSBindings jsBindings = new JSBindings(effectiveContext, bindings);
-            jsBindings.put("_builtin", new JSFunctions(effectiveContext));
-
-            Object ret = engine.eval(jsExpression, jsBindings);
-
-            // copy global bindings attributes to context, so callers may get access to the evaluated variables.
-            copyGlobalBindingsToContext(jsBindings, effectiveContext);
-
+            JSContext effectiveContext = getEffectiveContext((JSContext)context);
+            ScriptContext scriptContext = getScriptContext(effectiveContext);
+            Object ret = getEngine().eval(expression, scriptContext);
+            // copy Javascript global variables to SCXML context.
+            copyJavascriptGlobalsToScxmlContext(scriptContext.getBindings(ScriptContext.ENGINE_SCOPE), effectiveContext);
             return ret;
-
         } catch (Exception x) {
             throw new SCXMLExpressionException("Error evaluating ['" + expression + "'] " + x);
         }
@@ -177,10 +237,9 @@ public class JSEvaluator extends AbstractBaseEvaluator {
      * @param context    SCXML context.
      * @param expression Expression to evaluate.
      *
-     * @return Boolean or <code>null</code>.
+     * @return Boolean casted result.
      *
-     * @throws SCXMLExpressionException Thrown if the expression was invalid or did
-     *                                  not return a boolean.
+     * @throws SCXMLExpressionException Thrown if the expression was invalid.
      */
     @Override
     public Boolean evalCond(Context context, String expression) throws SCXMLExpressionException {
@@ -202,11 +261,7 @@ public class JSEvaluator extends AbstractBaseEvaluator {
     }
 
     /**
-     * Executes the script using a new Javascript engine obtained from
-     * factory instantiated in the constructor. The engine is supplied with
-     * a new JSBindings that includes the SCXML Context and SCXML builtin
-     * <code>In()</code> function is replaced with an equivalent internal
-     * Javascript function.
+     * Executes the Javascript script using the <code>eval()</code> method
      *
      * @param ctx    SCXML context.
      * @param script Script to execute.
@@ -225,8 +280,8 @@ public class JSEvaluator extends AbstractBaseEvaluator {
      * current state to document root, child has priority over parent
      * in scoping rules.
      *
-     * @param nodeCtx The JexlContext for this state.
-     * @return The effective JexlContext for the path leading up to
+     * @param nodeCtx The JSContext for this state.
+     * @return The effective JSContext for the path leading up to
      *         document root.
      */
     protected JSContext getEffectiveContext(final JSContext nodeCtx) {
@@ -234,18 +289,19 @@ public class JSEvaluator extends AbstractBaseEvaluator {
     }
 
     /**
-     * Copy the global Bindings (i.e. nashorn Global instance) attributes to {@code jsContext}
-     * in order to make sure all the new global variables set by the JavaScript engine after evaluation
+     * Copy the Javscript global context (i.e. nashorn Global instance) variables to SCXML {@code jsContext}
+     * in order to make sure all the new global variables set by the JavaScript engine after evaluation are
      * available from {@link JSContext} instance as well.
-     * @param jsBindings
-     * @param jsContext
+     * <p>Note: the internal <code>"_scxmlSystemContext</code> variable is always skipped.</p>
+     * @param global The Javascript Bindings holding the Javascript Global context variables
+     * @param jsContext The SCXML context to copy/merge the variables into
      */
-    private void copyGlobalBindingsToContext(final JSBindings jsBindings, final JSContext jsContext) {
-        Bindings globalBindings = jsBindings.getGlobalBindings();
-
-        if (globalBindings != null) {
-            for (String key : globalBindings.keySet()) {
-                jsContext.set(key, globalBindings.get(key));
+    private void copyJavascriptGlobalsToScxmlContext(final Bindings global, final JSContext jsContext) {
+        if (global != null) {
+            for (String key : global.keySet()) {
+                if (!SCXML_SYSTEM_CONTEXT.equals(key)) {
+                    jsContext.set(key, global.get(key));
+                }
             }
         }
     }

http://git-wip-us.apache.org/repos/asf/commons-scxml/blob/1b91a77c/src/main/java/org/apache/commons/scxml2/env/javascript/JSFunctions.java
----------------------------------------------------------------------
diff --git a/src/main/java/org/apache/commons/scxml2/env/javascript/JSFunctions.java b/src/main/java/org/apache/commons/scxml2/env/javascript/JSFunctions.java
deleted file mode 100644
index 45771a0..0000000
--- a/src/main/java/org/apache/commons/scxml2/env/javascript/JSFunctions.java
+++ /dev/null
@@ -1,50 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one or more
- * contributor license agreements.  See the NOTICE file distributed with
- * this work for additional information regarding copyright ownership.
- * The ASF licenses this file to You under the Apache License, Version 2.0
- * (the "License"); you may not use this file except in compliance with
- * the License.  You may obtain a copy of the License at
- *
- *     http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package org.apache.commons.scxml2.env.javascript;
-
-import java.io.Serializable;
-
-import org.apache.commons.scxml2.Builtin;
-import org.apache.commons.scxml2.Context;
-
-/**
- * Custom Javascript engine function providing the SCXML In() predicate .
- */
-public class JSFunctions implements Serializable {
-
-    /**
-     * The context currently in use for evaluation.
-     */
-    private Context ctx;
-
-    /**
-     * Creates a new instance, wraps the context.
-     * @param ctx the context in use
-     */
-    public JSFunctions(Context ctx) {
-        this.ctx = ctx;
-    }
-
-    /**
-     * Provides the SCXML standard In() predicate for SCXML documents.
-     * @param state The State ID to compare with
-     * @return true if this state is currently active
-     */
-    public boolean In(final String state) {
-        return Builtin.isMember(ctx, state);
-    }
-}

http://git-wip-us.apache.org/repos/asf/commons-scxml/blob/1b91a77c/src/main/java/org/apache/commons/scxml2/env/javascript/init_global.js
----------------------------------------------------------------------
diff --git a/src/main/java/org/apache/commons/scxml2/env/javascript/init_global.js b/src/main/java/org/apache/commons/scxml2/env/javascript/init_global.js
new file mode 100644
index 0000000..b4cb4fc
--- /dev/null
+++ b/src/main/java/org/apache/commons/scxml2/env/javascript/init_global.js
@@ -0,0 +1,142 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+/*
+    Define global and protected SCXML system properties and builtin functions,
+    all delegating to _scxmlSystemContext variables map provided as a ScriptEngine binding.
+    The _event object is wrapped in additional (frozen) _scxmlEvent property to provide ECMAScript object semantics.
+ */
+Object.defineProperties(this, {
+    // common method to throw 'protected' error
+    "_scxmlProtected":
+    {
+        get: function() {
+            return function(name) {
+                throw new Error(name+" is a protected SCXML system property")
+            }
+        }
+    },
+    "_name": {
+        get: function () {
+            return _scxmlSystemContext._name
+        },
+        set: function () {
+            _scxmlProtected("_name")
+        }
+    },
+    "_sessionid":
+    {
+        get: function() {
+            return _scxmlSystemContext._sessionid
+        },
+        set: function() {
+            _scxmlProtected("_sessionid")
+        }
+    },
+    "_ioprocessors":
+    {
+        get: function() {
+            return _scxmlSystemContext._ioprocessors
+        },
+        set: function() {
+            _scxmlProtected("_ioprocessors")
+        }
+    },
+    // extra wrapper object needed for _event wrapping as defining this inline
+    // on _event.get method somehow doesn't work properly
+    "_scxmlEvent":
+    {
+        value: {
+            get name() {
+                return _scxmlSystemContext._event.name||undefined
+            },
+            set name(val) {
+                _scxmlProtected("_event.name")
+            },
+            get type() {
+                return _scxmlSystemContext._event.type||undefined
+            },
+            set type(val) {
+                _scxmlProtected("_event.type")
+            },
+            get sendid() {
+                return _scxmlSystemContext._event.sendid||undefined
+            },
+            set sendid(val) {
+                _scxmlProtected("_event.sendid")
+            },
+            get orgin() {
+                return _scxmlSystemContext._event.orgin||undefined
+            },
+            set origin(val) {
+                _scxmlProtected("_event.origin")
+            },
+            get origintype() {
+                return _scxmlSystemContext._event.orgintype||undefined
+            },
+            set origintype(val) {
+                _scxmlProtected("_event.origintype")
+            },
+            get invokeid() {
+                return _scxmlSystemContext._event.invokeid||undefined
+            },
+            set invokeid(val) {
+                _scxmlProtected("_event.invokeid")
+            },
+            get data() {
+                return _scxmlSystemContext._event.data||undefined
+            },
+            set data(val) {
+                _scxmlProtected("_event.data")
+            }
+        },
+        writable : false,
+        configurable : false,
+        enumeratable : false,
+    },
+    "_event":
+    {
+        get: function() {
+            return _scxmlSystemContext._event ? _scxmlEvent : undefined;
+        },
+        set: function() {
+            _scxmlProtected("_event")
+        }
+    },
+    "_x":
+    {
+        get: function() {
+            return _scxmlSystemContext._x
+        },
+        set: function() {
+            _scxmlProtected("_x")
+        }
+    },
+    // required SCXML builtin In() predicate
+    "In":
+    {
+        get: function() {
+            return function(state) {
+                return _scxmlSystemContext._x.status.isInState(state)
+            }
+        },
+        set: function() {
+            _scxmlProtected("_In()")
+        }
+    }
+});
+// ensure extra _scxmlEvent wrapper object is deep protected
+Object.freeze(_scxmlEvent);

http://git-wip-us.apache.org/repos/asf/commons-scxml/blob/1b91a77c/src/test/java/org/apache/commons/scxml2/env/javascript/JSBindingsTest.java
----------------------------------------------------------------------
diff --git a/src/test/java/org/apache/commons/scxml2/env/javascript/JSBindingsTest.java b/src/test/java/org/apache/commons/scxml2/env/javascript/JSBindingsTest.java
deleted file mode 100644
index 64447f9..0000000
--- a/src/test/java/org/apache/commons/scxml2/env/javascript/JSBindingsTest.java
+++ /dev/null
@@ -1,669 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one or more
- * contributor license agreements.  See the NOTICE file distributed with
- * this work for additional information regarding copyright ownership.
- * The ASF licenses this file to You under the Apache License, Version 2.0
- * (the "License"); you may not use this file except in compliance with
- * the License.  You may obtain a copy of the License at
- *
- *     http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package org.apache.commons.scxml2.env.javascript;
-
-import java.util.AbstractMap;
-import java.util.HashMap;
-import java.util.Map;
-
-import org.apache.commons.scxml2.Context;
-import org.junit.Assert;
-import org.junit.Before;
-import org.junit.Test;
-
-import javax.script.Bindings;
-import javax.script.SimpleBindings;
-
-/**
- * JUnit 3 test case for the JSBinding implementation that imports
- * SCXML context variables into a JavaScript bindings. Includes tests
- * for:
- * <ul>
- * <li> constructor
- * </ul>
- */
-public class JSBindingsTest {
-    // TEST CONSTANTS
-
-    private static final Map.Entry<String,Object> KOALA   = new AbstractMap.SimpleEntry<String,Object>("bear","koala");
-    private static final Map.Entry<String,Object> GRIZZLY = new AbstractMap.SimpleEntry<String,Object>("bear","grizzly");
-    private static final Map.Entry<String,Object> FELIX   = new AbstractMap.SimpleEntry<String,Object>("cat", "felix");
-    private static final Map.Entry<String,Object> ROVER   = new AbstractMap.SimpleEntry<String,Object>("dog", "rover");
-
-    // TEST VARIABLES
-
-    // TEST SETUP
-
-    /**
-     * Creates and initializes an SCXML data model in the context.
-     */
-    @Before
-    public void setUp() throws Exception {
-    }
-
-    // CLASS METHODS
-
-    /**
-     * Stand-alone test runtime.
-     */
-    public static void main(String args[]) {
-        String[] testCaseName = {JSBindingsTest.class.getName()};
-        junit.textui.TestRunner.main(testCaseName);
-    }
-
-    // INSTANCE METHOD TESTS
-
-    /**
-     * Tests implementation of JSBindings constructor.
-     */    
-    @Test
-    public void testConstructor() {
-        Assert.assertNotNull(new JSBindings(new JSContext(),new SimpleBindings()));
-    }
-
-    /**
-     * Test implementation of JSBindings constructor with invalid SCXML context.
-     */    
-    @Test
-    public void testInvalidContextConstructor() {
-        try {
-             Assert.assertNotNull(new JSBindings(null,new SimpleBindings()));
-             Assert.fail("JSBindings constructor accepted invalid SCXML context");
-
-        } catch (IllegalArgumentException x) {
-             // expected, ignore
-        }
-    }
-
-    /**
-     * Test implementation of JSBindings constructor with invalid Javascript bindings.
-     */    
-    @Test
-    public void testInvalidBindingsConstructor() {
-        try {
-             Assert.assertNotNull(new JSBindings(new JSContext(),null));
-             Assert.fail("JSBindings constructor accepted invalid Javascript bindings");
-
-        } catch (IllegalArgumentException x) {
-             // expected, ignore
-        }
-    }
-
-    /**
-     * Tests the <code>containsKey</code> method with items in the SCXML context as well as the
-     * JavaScript Bindings.
-     *
-     */    
-    @Test
-    public void testContainsKey() {
-        Context    context  = new JSContext     ();
-        Bindings   bindings = new SimpleBindings();
-        JSBindings jsx      = new JSBindings    (context,bindings);
-
-        Assert.assertFalse("Invalid SCXML context",      context.has         ("bear"));
-        Assert.assertFalse("Invalid Javascript bindings",bindings.containsKey("bear"));
-        Assert.assertFalse("Invalid JSbindings",         jsx.containsKey     ("bear"));
-
-        context.set("bear","koala");
-        Assert.assertTrue ("Invalid SCXML context",      context.has         ("bear"));
-        Assert.assertFalse("Invalid Javascript bindings",bindings.containsKey("bear"));
-        Assert.assertTrue ("Invalid JSbindings",         jsx.containsKey     ("bear"));
-
-        context.reset();
-        bindings.put ("bear","grizzly");
-        Assert.assertFalse  ("Invalid SCXML context",      context.has         ("bear"));
-        Assert.assertTrue   ("Invalid Javascript bindings",bindings.containsKey("bear"));
-        Assert.assertTrue   ("Invalid JSbindings",         jsx.containsKey     ("bear"));
-
-        context.set ("bear","koala");
-        bindings.put("bear","grizzly");
-        Assert.assertTrue  ("Invalid SCXML context",      context.has         ("bear"));
-        Assert.assertTrue  ("Invalid Javascript bindings",bindings.containsKey("bear"));
-        Assert.assertTrue  ("Invalid JSbindings",         jsx.containsKey     ("bear"));
-    }
-
-    /**
-     * Tests the <code>keySet</code> method with items in the SCXML context as well as the
-     * JavaScript Bindings.
-     *
-     */    
-    @Test
-    public void testKeySet() {
-        Context    context  = new JSContext     ();
-        Bindings   bindings = new SimpleBindings();
-        JSBindings jsx      = new JSBindings    (context,bindings);
-
-        Assert.assertFalse ("Invalid SCXML context",      context.has          ("bear"));
-        Assert.assertFalse ("Invalid Javascript bindings",bindings.containsKey ("bear"));
-        Assert.assertFalse ("Invalid JSbindings",         jsx.keySet().contains("bear"));
-
-        context.set   ("bear","koala");
-        bindings.clear();
-        Assert.assertTrue    ("Invalid SCXML context",      context.has          ("bear"));
-        Assert.assertFalse   ("Invalid Javascript bindings",bindings.containsKey ("bear"));
-        Assert.assertTrue    ("Invalid JSbindings",         jsx.keySet().contains("bear"));
-
-        context.reset ();
-        bindings.clear();
-        bindings.put  ("bear","grizzly");
-        Assert.assertFalse   ("Invalid SCXML context",      context.has          ("bear"));
-        Assert.assertTrue    ("Invalid Javascript bindings",bindings.containsKey ("bear"));
-        Assert.assertTrue    ("Invalid JSbindings",         jsx.keySet().contains("bear"));
-
-        context.reset ();
-        bindings.clear();
-        context.set  ("cat","felix");
-        bindings.put ("dog","rover");
-        Assert.assertFalse  ("Invalid SCXML context",      context.has          ("bear"));
-        Assert.assertFalse  ("Invalid Javascript bindings",bindings.containsKey ("bear"));
-        Assert.assertTrue   ("Invalid SCXML context",      context.has          ("cat"));
-        Assert.assertTrue   ("Invalid Javascript bindings",bindings.containsKey ("dog"));
-        Assert.assertTrue   ("Invalid JSbindings",         jsx.keySet().contains("cat"));
-        Assert.assertTrue   ("Invalid JSbindings",         jsx.keySet().contains("dog"));
-    }
-
-    /**
-     * Tests the <code>size</code> method with items in the SCXML context as well as the
-     * JavaScript Bindings.
-     *
-     */
-   
-    @Test
-    public void testSize() {
-       Context    context  = new JSContext     ();
-       Bindings   bindings = new SimpleBindings();
-       JSBindings jsx      = new JSBindings    (context,bindings);
-
-       Assert.assertFalse ("Invalid SCXML context",      context.has          ("bear"));
-       Assert.assertFalse ("Invalid Javascript bindings",bindings.containsKey ("bear"));
-       Assert.assertEquals("Invalid JSbindings",0,jsx.size());
-
-       context.set   ("bear","koala");
-       bindings.clear();
-       Assert.assertTrue    ("Invalid SCXML context",      context.has          ("bear"));
-       Assert.assertFalse   ("Invalid Javascript bindings",bindings.containsKey ("bear"));
-       Assert.assertEquals  ("Invalid JSbindings",1,jsx.size());
-
-       context.reset ();
-       bindings.clear();
-       bindings.put  ("bear","grizzly");
-       Assert.assertFalse   ("Invalid SCXML context",      context.has          ("bear"));
-       Assert.assertTrue    ("Invalid Javascript bindings",bindings.containsKey ("bear"));
-       Assert.assertEquals  ("Invalid JSbindings",1,jsx.size());
-
-       context.reset ();
-       bindings.clear();
-       context.set   ("bear","koala");
-       bindings.put  ("bear","grizzly");
-       Assert.assertTrue    ("Invalid SCXML context",      context.has          ("bear"));
-       Assert.assertTrue    ("Invalid Javascript bindings",bindings.containsKey ("bear"));
-       Assert.assertEquals  ("Invalid JSbindings",1,jsx.size());
-
-       context.reset ();
-       bindings.clear();
-       context.set  ("cat","felix");
-       bindings.put ("dog","rover");
-       Assert.assertFalse  ("Invalid SCXML context",      context.has          ("bear"));
-       Assert.assertFalse  ("Invalid Javascript bindings",bindings.containsKey ("bear"));
-       Assert.assertTrue   ("Invalid SCXML context",      context.has          ("cat"));
-       Assert.assertTrue   ("Invalid Javascript bindings",bindings.containsKey ("dog"));
-       Assert.assertEquals ("Invalid JSbindings",2,jsx.size());
-    }
-
-    /**
-     * Tests the <code>containsValue</code> method with items in the SCXML context as well as the
-     * JavaScript Bindings.
-     *
-     */    
-    @Test
-    public void testContainsValue() {
-        Context    context  = new JSContext     ();
-        Bindings   bindings = new SimpleBindings();
-        JSBindings jsx      = new JSBindings    (context,bindings);
-
-        Assert.assertFalse("Invalid SCXML context",      context.getVars().containsValue("koala"));
-        Assert.assertFalse("Invalid Javascript bindings",bindings.containsValue("koala"));
-        Assert.assertFalse("Invalid JSbindings",         jsx.containsValue     ("koala"));
-
-        context.reset ();
-        bindings.clear();
-        context.set   ("bear","koala");
-        Assert.assertTrue    ("Invalid SCXML context",      context.getVars().containsValue("koala"));
-        Assert.assertFalse   ("Invalid Javascript bindings",bindings.containsValue("koala"));
-        Assert.assertTrue    ("Invalid JSbindings",         jsx.containsValue     ("koala"));
-
-        context.reset ();
-        bindings.clear();
-        bindings.put  ("bear","grizzly");
-        Assert.assertFalse   ("Invalid SCXML context",      context.getVars().containsValue("grizzly"));
-        Assert.assertTrue    ("Invalid Javascript bindings",bindings.containsValue("grizzly"));
-        Assert.assertTrue    ("Invalid JSbindings",         jsx.containsValue     ("grizzly"));
-
-        context.reset ();
-        bindings.clear();
-        context.set   ("bear","koala");
-        bindings.put  ("bear","grizzly");
-        Assert.assertTrue    ("Invalid SCXML context",      context.getVars().containsValue("koala"));
-        Assert.assertTrue    ("Invalid Javascript bindings",bindings.containsValue("grizzly"));
-        Assert.assertTrue    ("Invalid JSbindings",         jsx.containsValue     ("koala"));
-        Assert.assertTrue    ("Invalid JSbindings",         jsx.containsValue     ("grizzly"));
-    }
-
-    /**
-     * Tests the <code>entrySet</code> method with items in the SCXML context as well as the
-     * JavaScript Bindings.
-     *
-     */    
-    @Test
-    public void testEntrySet() {
-        Context    context  = new JSContext     ();
-        Bindings   bindings = new SimpleBindings();
-        JSBindings jsx      = new JSBindings    (context,bindings);
-
-        Assert.assertEquals("Invalid SCXML context",      0,context.getVars().entrySet().size());
-        Assert.assertEquals("Invalid Javascript bindings",0,bindings.entrySet().size());
-        Assert.assertEquals("Invalid JSbindings",         0,jsx.entrySet().size());
-
-        context.reset ();
-        bindings.clear();
-        context.set   ("bear","koala");
-        Assert.assertEquals  ("Invalid SCXML context",      1,context.getVars().entrySet().size());
-        Assert.assertTrue    ("Invalid SCXML context",      context.getVars().entrySet().contains(KOALA));
-        Assert.assertEquals  ("Invalid Javascript bindings",0,bindings.entrySet().size());
-        Assert.assertFalse   ("Invalid Javascript bindings",bindings.entrySet().contains(KOALA));
-        Assert.assertEquals  ("Invalid JSBindings",         1,jsx.entrySet().size());
-        Assert.assertTrue    ("Invalid JSbindings",         jsx.entrySet().contains(KOALA));
-
-        context.reset ();
-        bindings.clear();
-        bindings.put  ("bear","grizzly");
-        Assert.assertEquals  ("Invalid SCXML context",      0,context.getVars().entrySet().size());
-        Assert.assertFalse   ("Invalid SCXML context",      context.getVars().entrySet().contains(GRIZZLY));
-        Assert.assertEquals  ("Invalid Javascript bindings",1,bindings.entrySet().size());
-        Assert.assertTrue    ("Invalid Javascript bindings",bindings.entrySet().contains(GRIZZLY));
-        Assert.assertEquals  ("Invalid JSBindings",         1,jsx.entrySet().size());
-        Assert.assertTrue    ("Invalid JSbindings",         jsx.entrySet().contains(GRIZZLY));
-
-        context.reset ();
-        bindings.clear();
-        context.set   ("bear","koala");
-        bindings.put  ("bear","grizzly");
-        Assert.assertEquals  ("Invalid SCXML context",      1,context.getVars().entrySet().size());
-        Assert.assertTrue    ("Invalid SCXML context",      context.getVars().entrySet().contains(KOALA));
-        Assert.assertEquals  ("Invalid Javascript bindings",1,bindings.entrySet().size());
-        Assert.assertTrue    ("Invalid Javascript bindings",bindings.entrySet().contains(GRIZZLY));
-        Assert.assertEquals  ("Invalid JSBindings",         1,jsx.entrySet().size());
-        Assert.assertFalse   ("Invalid JSbindings",         jsx.entrySet().contains(KOALA));
-        Assert.assertTrue    ("Invalid JSbindings",         jsx.entrySet().contains(GRIZZLY));
-
-        context.reset ();
-        bindings.clear();
-        context.set   ("cat","felix");
-        bindings.put  ("dog","rover");
-        Assert.assertEquals  ("Invalid SCXML context",      1,context.getVars().entrySet().size());
-        Assert.assertTrue    ("Invalid SCXML context",      context.getVars().entrySet().contains(FELIX));
-        Assert.assertEquals  ("Invalid Javascript bindings",1,bindings.entrySet().size());
-        Assert.assertTrue    ("Invalid Javascript bindings",bindings.entrySet().contains(ROVER));
-        Assert.assertEquals  ("Invalid JSBindings",         2,jsx.entrySet().size());
-        Assert.assertTrue    ("Invalid JSbindings",         jsx.entrySet().contains(FELIX));
-        Assert.assertTrue    ("Invalid JSbindings",         jsx.entrySet().contains(ROVER));
-    }
-
-    /**
-     * Tests the <code>values</code> method with items in the SCXML context as well as the
-     * JavaScript Bindings.
-     *
-     */    
-    @Test
-    public void testValues() {
-        Context    context  = new JSContext     ();
-        Bindings   bindings = new SimpleBindings();
-        JSBindings jsx      = new JSBindings    (context,bindings);
-
-        Assert.assertEquals("Invalid SCXML context",      0,context.getVars().values().size());
-        Assert.assertEquals("Invalid Javascript bindings",0,bindings.values().size());
-        Assert.assertEquals("Invalid JSbindings",         0,jsx.values().size());
-
-        context.reset ();
-        bindings.clear();
-        context.set   ("bear","koala");
-        Assert.assertEquals  ("Invalid SCXML context",      1,context.getVars().values().size());
-        Assert.assertTrue    ("Invalid SCXML context",      context.getVars().values().contains(KOALA.getValue()));
-        Assert.assertEquals  ("Invalid Javascript bindings",0,bindings.values().size());
-        Assert.assertFalse   ("Invalid Javascript bindings",bindings.values().contains(KOALA.getValue()));
-        Assert.assertEquals  ("Invalid JSBindings",         1,jsx.values().size());
-        Assert.assertTrue    ("Invalid JSbindings",         jsx.values().contains(KOALA.getValue()));
-
-        context.reset ();
-        bindings.clear();
-        bindings.put  ("bear","grizzly");
-        Assert.assertEquals  ("Invalid SCXML context",      0,context.getVars().values().size());
-        Assert.assertFalse   ("Invalid SCXML context",      context.getVars().values().contains(GRIZZLY.getValue()));
-        Assert.assertEquals  ("Invalid Javascript bindings",1,bindings.values().size());
-        Assert.assertTrue    ("Invalid Javascript bindings",bindings.values().contains(GRIZZLY.getValue()));
-        Assert.assertEquals  ("Invalid JSBindings",         1,jsx.values().size());
-        Assert.assertTrue    ("Invalid JSbindings",         jsx.values().contains(GRIZZLY.getValue()));
-
-        context.reset ();
-        bindings.clear();
-        context.set   ("bear","koala");
-        bindings.put  ("bear","grizzly");
-        Assert.assertEquals  ("Invalid SCXML context",      1,context.getVars().values().size());
-        Assert.assertTrue    ("Invalid SCXML context",      context.getVars().values().contains(KOALA.getValue()));
-        Assert.assertEquals  ("Invalid Javascript bindings",1,bindings.values().size());
-        Assert.assertTrue    ("Invalid Javascript bindings",bindings.values().contains(GRIZZLY.getValue()));
-        Assert.assertEquals  ("Invalid JSBindings",         1,jsx.values().size());
-        Assert.assertFalse   ("Invalid JSbindings",         jsx.values().contains(KOALA.getValue()));
-        Assert.assertTrue    ("Invalid JSbindings",         jsx.values().contains(GRIZZLY.getValue()));
-
-        context.reset ();
-        bindings.clear();
-        context.set   ("cat","felix");
-        bindings.put  ("dog","rover");
-        Assert.assertEquals  ("Invalid SCXML context",      1,context.getVars().values().size());
-        Assert.assertTrue    ("Invalid SCXML context",      context.getVars().values().contains(FELIX.getValue()));
-        Assert.assertEquals  ("Invalid Javascript bindings",1,bindings.values().size());
-        Assert.assertTrue    ("Invalid Javascript bindings",bindings.values().contains(ROVER.getValue()));
-        Assert.assertEquals  ("Invalid JSBindings",         2,jsx.values().size());
-        Assert.assertTrue    ("Invalid JSbindings",         jsx.values().contains(FELIX.getValue()));
-        Assert.assertTrue    ("Invalid JSbindings",         jsx.values().contains(ROVER.getValue()));
-    }
-
-    /**
-     * Tests the <code>isEmpty</code> method with items in the SCXML context as well as the
-     * JavaScript Bindings.
-     *
-     */    
-    @Test
-    public void testIsEmpty() {
-        Context    context  = new JSContext     ();
-        Bindings   bindings = new SimpleBindings();
-        JSBindings jsx      = new JSBindings    (context,bindings);
-
-        Assert.assertTrue("Invalid SCXML context",      context.getVars().isEmpty());
-        Assert.assertTrue("Invalid Javascript bindings",bindings.isEmpty());
-        Assert.assertTrue("Invalid JSbindings",         jsx.isEmpty());
-
-        context.set   ("bear","koala");
-        bindings.clear();
-        Assert.assertFalse   ("Invalid SCXML context",      context.getVars().isEmpty());
-        Assert.assertTrue    ("Invalid Javascript bindings",bindings.isEmpty());
-        Assert.assertFalse   ("Invalid JSbindings",         jsx.isEmpty());
-
-        context.reset ();
-        bindings.clear();
-        bindings.put  ("bear","grizzly");
-        Assert.assertTrue    ("Invalid SCXML context",      context.getVars().isEmpty());
-        Assert.assertFalse   ("Invalid Javascript bindings",bindings.isEmpty());
-        Assert.assertFalse   ("Invalid JSbindings",         jsx.isEmpty());
-
-        context.reset ();
-        bindings.clear();
-        context.set   ("bear","koala");
-        bindings.put  ("bear","grizzly");
-        Assert.assertFalse   ("Invalid SCXML context",      context.getVars().isEmpty());
-        Assert.assertFalse   ("Invalid Javascript bindings",bindings.isEmpty());
-        Assert.assertFalse   ("Invalid JSbindings",         jsx.isEmpty());
-
-        context.reset ();
-        bindings.clear();
-        context.set   ("cat","felix");
-        bindings.put  ("dog","rover");
-        Assert.assertFalse   ("Invalid SCXML context",      context.getVars().isEmpty());
-        Assert.assertFalse   ("Invalid Javascript bindings",bindings.isEmpty());
-        Assert.assertFalse   ("Invalid JSbindings",         jsx.isEmpty());
-    }
-
-    /**
-     * Tests the <code>get</code> method with items in the SCXML context as well as the
-     * JavaScript Bindings.
-     *
-     */    
-    @Test
-    public void testGet() {
-        Context    context  = new JSContext     ();
-        Bindings   bindings = new SimpleBindings();
-        JSBindings jsx      = new JSBindings    (context,bindings);
-
-        Assert.assertNull("Invalid SCXML context",      context.get ("bear"));
-        Assert.assertNull("Invalid Javascript bindings",bindings.get("bear"));
-        Assert.assertNull("Invalid JSbindings",         jsx.get     ("bear"));
-
-        context.reset ();
-        bindings.clear();
-        context.set   ("bear","koala");
-        Assert.assertNotNull ("Invalid SCXML context",        context.get ("bear"));
-        Assert.assertEquals  ("Invalid SCXML context","koala",context.get ("bear"));
-        Assert.assertNull    ("Invalid Javascript bindings",  bindings.get("bear"));
-        Assert.assertNotNull ("Invalid JSbindings",           jsx.get     ("bear"));
-        Assert.assertEquals  ("Invalid JSbindings","koala",   jsx.get     ("bear"));
-
-        context.reset ();
-        bindings.clear();
-        bindings.put  ("bear","grizzly");
-        Assert.assertNull    ("Invalid SCXML context",                context.get ("bear"));
-        Assert.assertNotNull ("Invalid Javascript bindings",          bindings.get("bear"));
-        Assert.assertEquals  ("Invalid Javascript bindings","grizzly",bindings.get("bear"));
-        Assert.assertNotNull ("Invalid JSbindings",                   jsx.get     ("bear"));
-        Assert.assertEquals  ("Invalid JSbindings","grizzly",         jsx.get     ("bear"));
-
-        context.reset ();
-        bindings.clear();
-        context.set   ("bear","koala");
-        bindings.put  ("bear","grizzly");
-        Assert.assertNotNull ("Invalid SCXML context",        context.get ("bear"));
-        Assert.assertEquals  ("Invalid SCXML context","koala",context.get ("bear"));
-        Assert.assertNotNull ("Invalid Javascript bindings",          bindings.get("bear"));
-        Assert.assertEquals  ("Invalid Javascript bindings","grizzly",bindings.get("bear"));
-        Assert.assertNotNull ("Invalid JSbindings",                   jsx.get     ("bear"));
-        Assert.assertEquals  ("Invalid JSbindings","grizzly",         jsx.get     ("bear"));
-
-        context.reset ();
-        bindings.clear();
-        context.set   ("cat","felix");
-        bindings.put  ("dog","rover");
-        Assert.assertNotNull ("Invalid SCXML context",              context.get ("cat"));
-        Assert.assertEquals  ("Invalid SCXML context","felix",      context.get ("cat"));
-        Assert.assertNotNull ("Invalid Javascript bindings",        bindings.get("dog"));
-        Assert.assertEquals  ("Invalid Javascript bindings","rover",bindings.get("dog"));
-        Assert.assertNotNull ("Invalid JSbindings",                 jsx.get     ("cat"));
-        Assert.assertEquals  ("Invalid JSbindings","felix",         jsx.get     ("cat"));
-        Assert.assertNotNull ("Invalid JSbindings",                 jsx.get     ("dog"));
-        Assert.assertEquals  ("Invalid JSbindings","rover",         jsx.get     ("dog"));
-    }
-
-    /**
-     * Tests the <code>put</code> method with items in the SCXML context as well as the
-     * JavaScript Bindings.
-     *
-     */    
-    @Test
-    public void testPut() {
-        Context    context  = new JSContext     ();
-        Bindings   bindings = new SimpleBindings();
-        JSBindings jsx      = new JSBindings    (context,bindings);
-
-        Assert.assertNull("Invalid SCXML context",      context.get ("bear"));
-        Assert.assertNull("Invalid Javascript bindings",bindings.get("bear"));
-        Assert.assertNull("Invalid JSbindings",         jsx.get     ("bear"));
-
-        jsx.put       ("bear","koala");
-        Assert.assertNotNull ("Invalid SCXML context",        context.get ("bear"));
-        Assert.assertEquals  ("Invalid SCXML context","koala",context.get("bear"));
-        Assert.assertNotNull ("Invalid JSbindings",           jsx.get ("bear"));
-        Assert.assertNull    ("Invalid Javascript bindings",  bindings.get("bear"));
-    }
-
-    /**
-     * Tests the <code>putAll</code> method with items in the SCXML context as well as the
-     * JavaScript Bindings.
-     *
-     */    
-    @Test
-    public void testPutAll() {
-        Context            context  = new JSContext     ();
-        Bindings           bindings = new SimpleBindings();
-        JSBindings         jsx      = new JSBindings    (context,bindings);
-        Map<String,Object> vars     = new HashMap<String, Object>();
-
-        vars.put("bear","grizzly");
-        vars.put("cat","felix");
-        vars.put("dog","rover");
-
-        Assert.assertNull("Invalid SCXML context",      context.get ("bear"));
-        Assert.assertNull("Invalid SCXML context",      context.get ("cat"));
-        Assert.assertNull("Invalid SCXML context",      context.get ("dog"));
-
-        Assert.assertNull("Invalid Javascript bindings",bindings.get("bear"));
-        Assert.assertNull("Invalid Javascript bindings",bindings.get("cat"));
-        Assert.assertNull("Invalid Javascript bindings",bindings.get("dog"));
-
-        Assert.assertNull("Invalid JSbindings",         jsx.get     ("bear"));
-        Assert.assertNull("Invalid JSbindings",         jsx.get     ("cat"));
-        Assert.assertNull("Invalid JSbindings",         jsx.get     ("dog"));
-
-        context.set("bear","koala");
-        jsx.putAll (vars);
-
-        Assert.assertNotNull ("Invalid SCXML context",        context.get ("bear"));
-        Assert.assertNull    ("Invalid SCXML context",        context.get ("cat"));
-        Assert.assertNull    ("Invalid SCXML context",        context.get ("dog"));
-        Assert.assertEquals  ("Invalid SCXML context","koala",context.get ("bear"));
-        Assert.assertEquals  ("Invalid SCXML context",1,      context.getVars().size());
-
-        Assert.assertNotNull ("Invalid Javascript bindings",          bindings.get("bear"));
-        Assert.assertNotNull ("Invalid Javascript bindings",          bindings.get("cat"));
-        Assert.assertNotNull ("Invalid Javascript bindings",          bindings.get("dog"));
-        Assert.assertEquals  ("Invalid Javascript bindings","grizzly",bindings.get("bear"));
-        Assert.assertEquals  ("Invalid Javascript bindings","felix",  bindings.get("cat"));
-        Assert.assertEquals  ("Invalid Javascript bindings","rover",  bindings.get("dog"));
-        Assert.assertEquals  ("Invalid Javascript bindings",3,        bindings.size());
-    }
-
-    /**
-     * Tests the <code>remove</code> method with items in the SCXML context as well as the
-     * JavaScript Bindings.
-     *
-     */    
-    @Test
-    public void testRemove() {
-        Context            context  = new JSContext     ();
-        Bindings           bindings = new SimpleBindings();
-        JSBindings         jsx      = new JSBindings    (context,bindings);
-
-        context.set ("bear","koala");
-        bindings.put("bear","grizzly");
-        bindings.put("cat", "felix");
-        bindings.put("dog", "rover");
-
-        Assert.assertNotNull("Invalid SCXML context",        context.get("bear"));
-        Assert.assertEquals ("Invalid SCXML context","koala",context.get("bear"));
-        Assert.assertEquals ("Invalid SCXML context",1,      context.getVars().size());
-
-        Assert.assertNotNull("Invalid Javascript bindings",          bindings.get("bear"));
-        Assert.assertNotNull("Invalid Javascript bindings",          bindings.get("cat"));
-        Assert.assertNotNull("Invalid Javascript bindings",          bindings.get("dog"));
-        Assert.assertEquals ("Invalid Javascript bindings","grizzly",bindings.get("bear"));
-        Assert.assertEquals ("Invalid Javascript bindings","felix",  bindings.get("cat"));
-        Assert.assertEquals ("Invalid Javascript bindings","rover",  bindings.get("dog"));
-        Assert.assertEquals ("Invalid Javascript bindings",3,        bindings.size());
-
-        jsx.remove("cat");
-
-        Assert.assertNotNull("Invalid SCXML context",                context.get("bear"));
-        Assert.assertEquals ("Invalid SCXML context","koala",        context.get("bear"));
-        Assert.assertEquals ("Invalid SCXML context",1,              context.getVars().size());
-        Assert.assertNotNull("Invalid Javascript bindings",          bindings.get("bear"));
-        Assert.assertNull   ("Invalid Javascript bindings",          bindings.get("cat"));
-        Assert.assertNotNull("Invalid Javascript bindings",          bindings.get("dog"));
-        Assert.assertEquals ("Invalid Javascript bindings","grizzly",bindings.get("bear"));
-        Assert.assertEquals ("Invalid Javascript bindings","rover",  bindings.get("dog"));
-        Assert.assertEquals ("Invalid Javascript bindings",2,        bindings.size());
-
-        jsx.remove("dog");
-
-        Assert.assertNotNull("Invalid SCXML context",               context.get("bear"));
-        Assert.assertEquals ("Invalid SCXML context","koala",        context.get("bear"));
-        Assert.assertEquals ("Invalid SCXML context",1,              context.getVars().size());
-        Assert.assertNotNull("Invalid Javascript bindings",          bindings.get("bear"));
-        Assert.assertNull   ("Invalid Javascript bindings",          bindings.get("cat"));
-        Assert.assertNull   ("Invalid Javascript bindings",          bindings.get("dog"));
-        Assert.assertEquals ("Invalid Javascript bindings","grizzly",bindings.get("bear"));
-        Assert.assertEquals ("Invalid Javascript bindings",1,        bindings.size());
-
-        jsx.remove("bear");
-
-        Assert.assertNotNull("Invalid SCXML context",       context.get("bear"));
-        Assert.assertEquals("Invalid SCXML context","koala",context.get("bear"));
-        Assert.assertEquals("Invalid SCXML context",1,      context.getVars().size());
-        Assert.assertNull  ("Invalid Javascript bindings",  bindings.get("bear"));
-        Assert.assertNull  ("Invalid Javascript bindings",  bindings.get("cat"));
-        Assert.assertNull  ("Invalid Javascript bindings",  bindings.get("dog"));
-        Assert.assertEquals("Invalid Javascript bindings",0,bindings.size());
-
-        jsx.remove("bear");
-
-        Assert.assertNull  ("Invalid SCXML context",        context.get("bear"));
-        Assert.assertEquals("Invalid SCXML context",0,      context.getVars().size());
-        Assert.assertNull  ("Invalid Javascript bindings",  bindings.get("bear"));
-        Assert.assertNull  ("Invalid Javascript bindings",  bindings.get("cat"));
-        Assert.assertNull  ("Invalid Javascript bindings",  bindings.get("dog"));
-        Assert.assertEquals("Invalid Javascript bindings",0,bindings.size());
-    }
-
-    /**
-     * Tests the <code>clear</code> method with items in the SCXML context as well as the
-     * JavaScript Bindings.
-     *
-     */    
-    @Test
-    public void testClear() {
-        Context            context  = new JSContext     ();
-        Bindings           bindings = new SimpleBindings();
-        JSBindings         jsx      = new JSBindings    (context,bindings);
-
-        context.set ("bear","koala");
-        bindings.put("bear","grizzly");
-        bindings.put("cat", "felix");
-        bindings.put("dog", "rover");
-
-        Assert.assertNotNull("Invalid SCXML context",        context.get("bear"));
-        Assert.assertEquals ("Invalid SCXML context","koala",context.get("bear"));
-        Assert.assertEquals ("Invalid SCXML context",1,      context.getVars().size());
-
-        Assert.assertNotNull("Invalid Javascript bindings",          bindings.get("bear"));
-        Assert.assertNotNull("Invalid Javascript bindings",          bindings.get("cat"));
-        Assert.assertNotNull("Invalid Javascript bindings",          bindings.get("dog"));
-        Assert.assertEquals ("Invalid Javascript bindings","grizzly",bindings.get("bear"));
-        Assert.assertEquals ("Invalid Javascript bindings","felix",  bindings.get("cat"));
-        Assert.assertEquals ("Invalid Javascript bindings","rover",  bindings.get("dog"));
-        Assert.assertEquals ("Invalid Javascript bindings",3,        bindings.size());
-
-        jsx.clear();
-
-        Assert.assertNotNull("Invalid SCXML context",       context.get("bear"));
-        Assert.assertEquals("Invalid SCXML context","koala",context.get("bear"));
-        Assert.assertEquals("Invalid SCXML context",1,      context.getVars().size());
-        Assert.assertNull  ("Invalid Javascript bindings",  bindings.get("bear"));
-        Assert.assertNull  ("Invalid Javascript bindings",  bindings.get("cat"));
-        Assert.assertNull  ("Invalid Javascript bindings",  bindings.get("dog"));
-        Assert.assertEquals("Invalid Javascript bindings",0,bindings.size());
-    }
-
-}
-

http://git-wip-us.apache.org/repos/asf/commons-scxml/blob/1b91a77c/src/test/java/org/apache/commons/scxml2/env/javascript/JavaScriptEngineTest.java
----------------------------------------------------------------------
diff --git a/src/test/java/org/apache/commons/scxml2/env/javascript/JavaScriptEngineTest.java b/src/test/java/org/apache/commons/scxml2/env/javascript/JavaScriptEngineTest.java
index c1bafaf..4ee8f0e 100644
--- a/src/test/java/org/apache/commons/scxml2/env/javascript/JavaScriptEngineTest.java
+++ b/src/test/java/org/apache/commons/scxml2/env/javascript/JavaScriptEngineTest.java
@@ -16,79 +16,89 @@
  */
 package org.apache.commons.scxml2.env.javascript;
 
-import static org.junit.Assert.assertEquals;
-
-import javax.script.Bindings;
-import javax.script.ScriptContext;
-import javax.script.ScriptEngine;
-import javax.script.ScriptEngineManager;
+import java.util.UUID;
 
-import org.apache.commons.scxml2.Context;
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertTrue;
+
+import org.apache.commons.scxml2.SCXMLSystemContext;
+import org.apache.commons.scxml2.StateConfiguration;
+import org.apache.commons.scxml2.Status;
+import org.apache.commons.scxml2.model.Final;
+import org.apache.commons.scxml2.system.EventVariable;
 import org.junit.Before;
 import org.junit.Test;
 
 public class JavaScriptEngineTest {
 
-    private ScriptEngine engine;
-
-    private Context context;
+    private JSEvaluator evaluator;
+    private StateConfiguration stateConfiguration;
+    private JSContext _systemContext;
+    private JSContext context;
 
     @Before
     public void before() throws Exception {
-        ScriptEngineManager factory = new ScriptEngineManager();
-        engine = factory.getEngineByName("JavaScript");
-        context = new JSContext();
+        evaluator = new JSEvaluator();
+        _systemContext = new JSContext();
+        SCXMLSystemContext systemContext = new SCXMLSystemContext(_systemContext);
+        _systemContext.set(SCXMLSystemContext.SESSIONID_KEY, UUID.randomUUID().toString());
+        _systemContext.set(SCXMLSystemContext.SCXML_NAME_KEY, "test");
+        stateConfiguration = new StateConfiguration();
+        systemContext.getPlatformVariables().put(SCXMLSystemContext.STATUS_KEY, new Status(stateConfiguration));
+        context = new JSContext(systemContext);
     }
 
     @Test
-    public void testSimpleEvaluation() throws Exception {
-        Object ret = engine.eval("1.0 + 2.0");
-        assertEquals(3.0, ret);
+    public void testInitScxmlSystemContext() throws Exception {
+        assertEquals("test", evaluator.eval(context, "_name"));
     }
 
     @Test
-    public void testBindingsInput() throws Exception {
-        Bindings bindings = engine.getBindings(ScriptContext.ENGINE_SCOPE);
-        bindings.put("x", 1.0);
-        bindings.put("y", 2.0);
-
-        Object ret = engine.eval("x + y;", bindings);
-        assertEquals(3.0, ret);
+    public void testScxmlEvent() throws Exception {
+        assertTrue(evaluator.evalCond(context, "_event === undefined"));
+        EventVariable event = new EventVariable("myEvent", EventVariable.TYPE_INTERNAL, null, null, null, null,"myData");
+        _systemContext.setLocal(SCXMLSystemContext.EVENT_KEY, event);
+        assertFalse(evaluator.evalCond(context, "_event === undefined"));
+        assertTrue(evaluator.evalCond(context, "_event.name == 'myEvent'"));
+        assertTrue(evaluator.evalCond(context, "_event.type == 'internal'"));
+        assertTrue(evaluator.evalCond(context, "_event.data == 'myData'"));
+        assertTrue(evaluator.evalCond(context, "_event.origin === undefined"));
     }
 
     @Test
-    public void testBindingsInput_WithJSBindings() throws Exception {
-        Bindings bindings = engine.getBindings(ScriptContext.ENGINE_SCOPE);
-        JSBindings jsBindings = new JSBindings(context, bindings);
-        jsBindings.put("x", 1.0);
-        jsBindings.put("y", 2.0);
-
-        Object ret = engine.eval("x + y;", jsBindings);
-        assertEquals(3.0, ret);
+    public void testScxmlInPredicate() throws Exception {
+        assertFalse(evaluator.evalCond(context, "In('foo')"));
+        Final foo = new Final();
+        foo.setId("foo");
+        stateConfiguration.enterState(foo);
+        assertTrue(evaluator.evalCond(context, "In('foo')"));
     }
 
     @Test
-    public void testBindingsGlobal() throws Exception {
-        Bindings bindings = engine.getBindings(ScriptContext.ENGINE_SCOPE);
-        bindings.put("x", 1.0);
-        bindings.put("y", 2.0);
-        bindings.put("z", 0.0);
-
-        engine.eval("z = x + y;", bindings);
-        assertEquals("z variable is expected to set to 3.0 in global, but it was " + bindings.get("z") + ".",
-                     3.0, bindings.get("z"));
+    public void testCopyJavscriptGlobalsToScxmlContext() throws Exception {
+        assertFalse(context.has("x"));
+        evaluator.eval(context, ("x=3"));
+        assertEquals(3, context.get("x"));
     }
 
     @Test
-    public void testBindingsGlobal_WithJSBindings() throws Exception {
-        Bindings bindings = engine.getBindings(ScriptContext.ENGINE_SCOPE);
-        JSBindings jsBindings = new JSBindings(context, bindings);
-        jsBindings.put("x", 1.0);
-        jsBindings.put("y", 2.0);
-        jsBindings.put("z", 0.0);
+    public void testSharedJavscriptGlobalsRetainedAcrossInvocation() throws Exception {
+        assertFalse(context.has("x"));
+        evaluator.eval(context, ("x=3"));
+        context.getVars().remove("x");
+        assertFalse(context.has("x"));
+        assertTrue(evaluator.evalCond(context, "x===3"));
+    }
 
-        engine.eval("z = x + y;", jsBindings);
-        assertEquals("z variable is expected to set to 3.0 in global, but it was " + jsBindings.get("z") + ".",
-                     3.0, jsBindings.get("z"));
+    @Test
+    public void testJavscriptGlobalsNotRetainedAcrossEvaluatorInstances() throws Exception {
+        assertFalse(context.has("x"));
+        evaluator.eval(context, ("x=3"));
+        assertEquals(3, context.get("x"));
+        context.getVars().remove("x");
+        assertFalse(context.has("x"));
+        evaluator = new JSEvaluator();
+        assertTrue(evaluator.evalCond(context, "typeof x=='undefined'"));
     }
 }

http://git-wip-us.apache.org/repos/asf/commons-scxml/blob/1b91a77c/src/test/java/org/apache/commons/scxml2/w3c/tests.xml
----------------------------------------------------------------------
diff --git a/src/test/java/org/apache/commons/scxml2/w3c/tests.xml b/src/test/java/org/apache/commons/scxml2/w3c/tests.xml
index f3657a6..90ee864 100644
--- a/src/test/java/org/apache/commons/scxml2/w3c/tests.xml
+++ b/src/test/java/org/apache/commons/scxml2/w3c/tests.xml
@@ -89,15 +89,15 @@
   <test id="325" mandatory="true"  manual="false" enabled="false"                 ecma="fail"/>
   <test id="326" mandatory="true"  manual="false" enabled="false"                 ecma="fail"/>
   <test id="329" mandatory="true"  manual="false" enabled="true"                  ecma="pass"/>
-  <test id="330" mandatory="true"  manual="false" enabled="false"                 ecma="fail"/>
+  <test id="330" mandatory="true"  manual="false" enabled="true"                  ecma="pass"/>
   <test id="331" mandatory="true"  manual="false" enabled="true"                  ecma="pass"/>
   <test id="332" mandatory="true"  manual="false" enabled="false"                 ecma="fail"/>
-  <test id="333" mandatory="true"  manual="false" enabled="false"                 ecma="fail"/>
-  <test id="335" mandatory="true"  manual="false" enabled="false"                 ecma="fail"/>
+  <test id="333" mandatory="true"  manual="false" enabled="true"                  ecma="pass"/>
+  <test id="335" mandatory="true"  manual="false" enabled="true"                  ecma="pass"/>
   <test id="336" mandatory="true"  manual="false" enabled="true"                  ecma="pass"/>
-  <test id="337" mandatory="true"  manual="false" enabled="false"                 ecma="fail"/>
+  <test id="337" mandatory="true"  manual="false" enabled="true"                  ecma="pass"/>
   <test id="338" mandatory="true"  manual="false" enabled="false"                 ecma=""    >Fails to complete</test>
-  <test id="339" mandatory="true"  manual="false" enabled="false"                 ecma="fail"/>
+  <test id="339" mandatory="true"  manual="false" enabled="true"                  ecma="pass"/>
   <test id="342" mandatory="true"  manual="false" enabled="true"                  ecma="pass"/>
   <test id="346" mandatory="true"  manual="false" enabled="true"                  ecma="pass"/>
   <test id="172" mandatory="true"  manual="false" enabled="true"                  ecma="pass"/>
@@ -118,7 +118,7 @@
   <test id="201" mandatory="false" manual="false" enabled="false"                 ecma="fail"/>
   <test id="205" mandatory="true"  manual="false" enabled="true"                  ecma="pass"/>
   <test id="521" mandatory="true"  manual="false" enabled="false"                 ecma="fail"/>
-  <test id="553" mandatory="true"  manual="false" enabled="false"                 ecma="pass"/>
+  <test id="553" mandatory="true"  manual="false" enabled="true"                  ecma="pass"/>
   <test id="207" mandatory="true"  manual="false" enabled="false"                 ecma=""    >Fails to complete</test>
   <test id="208" mandatory="true"  manual="false" enabled="false"                 ecma="fail"/>
   <test id="210" mandatory="true"  manual="false" enabled="false"                 ecma="fail"/>
@@ -155,7 +155,7 @@
   <test id="278" mandatory="false" manual="false" enabled="false"                 ecma="fail"/>
   <test id="444" mandatory="false" manual="false" enabled="true"                  ecma="pass"/>
   <test id="445" mandatory="false" manual="false" enabled="true"                  ecma="pass"/>
-  <test id="448" mandatory="false" manual="false" enabled="false"                 ecma="fail"/>
+  <test id="448" mandatory="false" manual="false" enabled="true"                  ecma="pass"/>
   <test id="449" mandatory="false" manual="false" enabled="true"                  ecma="pass"/>
   <test id="451" mandatory="false" manual="false" enabled="true"                  ecma="pass"/>
   <test id="452" mandatory="false" manual="false" enabled="true"                  ecma="pass"/>