You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@commons.apache.org by ra...@apache.org on 2008/03/08 00:19:02 UTC

svn commit: r634858 [1/2] - in /commons/proper/scxml/branches/J5: ./ src/main/java/org/apache/commons/scxml/env/javascript/ src/test/java/org/apache/commons/scxml/ src/test/java/org/apache/commons/scxml/env/javascript/

Author: rahul
Date: Fri Mar  7 15:18:48 2008
New Revision: 634858

URL: http://svn.apache.org/viewvc?rev=634858&view=rev
Log:
Enable JavaScript as one of the pluggable ELs in SCXML documents:
 * Bumped up JDK requirement to 1.6.
 * Added new env.javascript package to hold the necessary javax.script bindings, and corresponding context and evaluator impls.
 * Includes JUnit tests and a sample using JavaScript as the EL.
TODO: m2 build does not execute javascript package tests, TBD why.
Contributed by (and thanks to): Tony Seebregts <tony at iveri dot com>
 * Also added Tony to list of contributors in pom files.
SCXML-68

Added:
    commons/proper/scxml/branches/J5/src/main/java/org/apache/commons/scxml/env/javascript/
    commons/proper/scxml/branches/J5/src/main/java/org/apache/commons/scxml/env/javascript/JSBindings.java   (with props)
    commons/proper/scxml/branches/J5/src/main/java/org/apache/commons/scxml/env/javascript/JSContext.java   (with props)
    commons/proper/scxml/branches/J5/src/main/java/org/apache/commons/scxml/env/javascript/JSEvaluator.java   (with props)
    commons/proper/scxml/branches/J5/src/test/java/org/apache/commons/scxml/env/javascript/
    commons/proper/scxml/branches/J5/src/test/java/org/apache/commons/scxml/env/javascript/EnvJavaScriptTestSuite.java   (with props)
    commons/proper/scxml/branches/J5/src/test/java/org/apache/commons/scxml/env/javascript/JSBindingsTest.java   (with props)
    commons/proper/scxml/branches/J5/src/test/java/org/apache/commons/scxml/env/javascript/JSContextTest.java   (with props)
    commons/proper/scxml/branches/J5/src/test/java/org/apache/commons/scxml/env/javascript/JSEvaluatorTest.java   (with props)
    commons/proper/scxml/branches/J5/src/test/java/org/apache/commons/scxml/env/javascript/JSExampleTest.java   (with props)
    commons/proper/scxml/branches/J5/src/test/java/org/apache/commons/scxml/env/javascript/example-01.xml   (with props)
Modified:
    commons/proper/scxml/branches/J5/BRANCHINFO.txt
    commons/proper/scxml/branches/J5/build.xml
    commons/proper/scxml/branches/J5/pom.xml
    commons/proper/scxml/branches/J5/project.properties
    commons/proper/scxml/branches/J5/project.xml
    commons/proper/scxml/branches/J5/src/test/java/org/apache/commons/scxml/AllSCXMLTestSuite.java

Modified: commons/proper/scxml/branches/J5/BRANCHINFO.txt
URL: http://svn.apache.org/viewvc/commons/proper/scxml/branches/J5/BRANCHINFO.txt?rev=634858&r1=634857&r2=634858&view=diff
==============================================================================
--- commons/proper/scxml/branches/J5/BRANCHINFO.txt (original)
+++ commons/proper/scxml/branches/J5/BRANCHINFO.txt Fri Mar  7 15:18:48 2008
@@ -50,5 +50,5 @@
  * Switch to javax.xml.xpath - TODO
  * Static imports - WONTFIX
 J6
- * Use javax.script for more pluggable ELs
+ * Use javax.script for more pluggable ELs - Added env.javascript package
 

Modified: commons/proper/scxml/branches/J5/build.xml
URL: http://svn.apache.org/viewvc/commons/proper/scxml/branches/J5/build.xml?rev=634858&r1=634857&r2=634858&view=diff
==============================================================================
--- commons/proper/scxml/branches/J5/build.xml (original)
+++ commons/proper/scxml/branches/J5/build.xml Fri Mar  7 15:18:48 2008
@@ -127,6 +127,8 @@
           </include>
           <include name="org/apache/commons/scxml/env/faces/EnvFacesTestSuite.java">
           </include>
+          <include name="org/apache/commons/scxml/env/javascript/EnvJavaScriptTestSuite.java">
+          </include>
           <include name="org/apache/commons/scxml/env/jexl/EnvJexlTestSuite.java">
           </include>
           <include name="org/apache/commons/scxml/env/jsp/EnvJspTestSuite.java">

Modified: commons/proper/scxml/branches/J5/pom.xml
URL: http://svn.apache.org/viewvc/commons/proper/scxml/branches/J5/pom.xml?rev=634858&r1=634857&r2=634858&view=diff
==============================================================================
--- commons/proper/scxml/branches/J5/pom.xml (original)
+++ commons/proper/scxml/branches/J5/pom.xml Fri Mar  7 15:18:48 2008
@@ -97,6 +97,9 @@
     <contributor>
       <name>Ross Yakulis</name>
     </contributor>
+    <contributor>
+      <name>Tony Seebregts</name>
+    </contributor>
   </contributors>
 
   <dependencies>
@@ -164,8 +167,8 @@
   </dependencies>
 
   <properties>
-    <maven.compile.source>1.5</maven.compile.source>
-    <maven.compile.target>1.5</maven.compile.target>
+    <maven.compile.source>1.6</maven.compile.source>
+    <maven.compile.target>1.6</maven.compile.target>
     <commons.componentid>scxml</commons.componentid>
     <commons.release.version>0.7</commons.release.version>
     <commons.binary.suffix></commons.binary.suffix>
@@ -194,6 +197,7 @@
             <include>org/apache/commons/scxml/SCXMLTestSuite.java</include>
             <include>org/apache/commons/scxml/env/EnvTestSuite.java</include>
             <include>org/apache/commons/scxml/env/faces/EnvFacesTestSuite.java</include>
+            <include>org/apache/commons/scxml/env/javascript/EnvJavaScriptTestSuite.java</include>
             <include>org/apache/commons/scxml/env/jexl/EnvJexlTestSuite.java</include>
             <include>org/apache/commons/scxml/env/jsp/EnvJspTestSuite.java</include>
             <include>org/apache/commons/scxml/env/servlet/EnvServletTestSuite.java</include>

Modified: commons/proper/scxml/branches/J5/project.properties
URL: http://svn.apache.org/viewvc/commons/proper/scxml/branches/J5/project.properties?rev=634858&r1=634857&r2=634858&view=diff
==============================================================================
--- commons/proper/scxml/branches/J5/project.properties (original)
+++ commons/proper/scxml/branches/J5/project.properties Fri Mar  7 15:18:48 2008
@@ -23,8 +23,8 @@
 maven.xdoc.xml.copy=usecases/rdc-group/*.xml,usecases/shale-dialogs/*.xml
 
 # Compile targets
-maven.compile.source=1.5
-maven.compile.target=1.5
+maven.compile.source=1.6
+maven.compile.target=1.6
 
 # Jar Manifest Additional Attributes
 maven.jar.manifest.attributes.list=Implementation-Vendor-Id,X-Compile-Source-JDK,X-Compile-Target-JDK

Modified: commons/proper/scxml/branches/J5/project.xml
URL: http://svn.apache.org/viewvc/commons/proper/scxml/branches/J5/project.xml?rev=634858&r1=634857&r2=634858&view=diff
==============================================================================
--- commons/proper/scxml/branches/J5/project.xml (original)
+++ commons/proper/scxml/branches/J5/project.xml Fri Mar  7 15:18:48 2008
@@ -141,6 +141,9 @@
     <contributor>
       <name>Ross Yakulis</name>
     </contributor>
+    <contributor>
+      <name>Tony Seebregts</name>
+    </contributor>
   </contributors>
   
   <dependencies>
@@ -288,6 +291,7 @@
         <include>org/apache/commons/scxml/SCXMLTestSuite.java</include>
         <include>org/apache/commons/scxml/env/EnvTestSuite.java</include>
         <include>org/apache/commons/scxml/env/faces/EnvFacesTestSuite.java</include>
+        <include>org/apache/commons/scxml/env/javascript/EnvJavaScriptTestSuite.java</include>
         <include>org/apache/commons/scxml/env/jexl/EnvJexlTestSuite.java</include>
         <include>org/apache/commons/scxml/env/jsp/EnvJspTestSuite.java</include>
         <include>org/apache/commons/scxml/env/servlet/EnvServletTestSuite.java</include>

Added: commons/proper/scxml/branches/J5/src/main/java/org/apache/commons/scxml/env/javascript/JSBindings.java
URL: http://svn.apache.org/viewvc/commons/proper/scxml/branches/J5/src/main/java/org/apache/commons/scxml/env/javascript/JSBindings.java?rev=634858&view=auto
==============================================================================
--- commons/proper/scxml/branches/J5/src/main/java/org/apache/commons/scxml/env/javascript/JSBindings.java (added)
+++ commons/proper/scxml/branches/J5/src/main/java/org/apache/commons/scxml/env/javascript/JSBindings.java Fri Mar  7 15:18:48 2008
@@ -0,0 +1,268 @@
+/*
+ * 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.scxml.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.scxml.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.
+ *
+ */
+public class JSBindings implements Bindings {
+
+    // INSTANCE VARIABLES
+
+    private Bindings bindings;
+    private Context  context;
+
+    // CONSTRUCTORS
+
+    /**
+     * Initialises the internal Bindings delegate and SCXML context.
+     *
+     * @param context  SCXML Context to use for script variables.
+     * @param bindings Javascript engine bindings for Javascript variables.
+     *
+     * @throws IllegalArgumentException Thrown if either <code>context</code>
+     *         or <code>bindings</code> is <code>null</code>.
+     *
+     */
+    @SuppressWarnings("unchecked")
+    public JSBindings(Context context,Bindings bindings) {
+        // ... validate
+
+        if (context == null) {
+           throw new IllegalArgumentException("Invalid SCXML context");
+        }
+
+        if (bindings == null) {
+           throw new IllegalArgumentException("Invalid script Bindings");
+        }
+
+         // ... initialise
+
+         this.bindings = bindings;
+         this.context  = context;
+    }
+
+    // INSTANCE METHODS
+
+    /**
+     * Returns <code>true</code> if the wrapped Bindings delegate
+     * or SCXML context  contains a variable identified by
+     * <code>key</code>.
+     *
+     */
+    @Override
+    public boolean containsKey(Object key) {
+        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.
+     *
+     */
+    @SuppressWarnings("unchecked")
+    @Override
+    public Set<String> keySet() {
+        Set<String> keys = new HashSet<String>();
+
+        keys.addAll(context.getVars().keySet());
+        keys.addAll(bindings.keySet());
+
+        return keys;
+    }
+
+    /**
+     * 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.
+     *
+     */
+    @SuppressWarnings("unchecked")
+    @Override
+    public int size() {
+        Set<String> keys = new HashSet<String>();
+
+        keys.addAll(context.getVars().keySet());
+        keys.addAll(bindings.keySet());
+
+        return keys.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.
+     */
+    @Override
+    public boolean containsValue(Object value) {
+        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.
+     */
+    @SuppressWarnings("unchecked")
+    @Override
+    public Set<Map.Entry<String,Object>> entrySet() {
+        return union().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.
+     */
+    @SuppressWarnings("unchecked")
+    @Override
+    public Collection<Object> values() {
+        return union().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.
+     */
+    @Override
+    public boolean isEmpty() {
+        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>.
+     *
+     */
+    @Override
+    public Object get(Object key) {
+        if (bindings.containsKey(key))
+           return bindings.get(key);
+
+        return context.get(key.toString());
+    }
+
+    /**
+     * Delegates to the wrapped Bindings <code>put</code> method i.e. does
+     * not store variables in the SCXML context. Not entirely sure what it
+     * should return if shadowing a variable name in the SCXML context though.
+     *
+     */
+    @Override
+    public Object put(String name, Object value) {
+            return bindings.put(name,value);
+    }
+
+    /**
+     * 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.
+     */
+    @Override
+    public void putAll(Map<? extends String, ? extends Object> list) {
+            bindings.putAll(list);
+    }
+
+    /**
+     * 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.
+     */
+    @Override
+    public Object remove(Object key) {
+        if (bindings.containsKey(key))
+           return bindings.remove(key);
+
+        if (context.has(key.toString()))
+           return context.getVars().remove(key);
+
+        return false;
+    }
+
+    /**
+     * 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.
+     */
+    @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.
+     */
+    @SuppressWarnings("unchecked")
+    private Bindings union() {
+        Bindings set = new SimpleBindings();
+
+        set.putAll(context.getVars());
+
+        for (String key: bindings.keySet())
+            set.put(key,bindings.get(key));
+
+        return set;
+    }
+
+}
+

Propchange: commons/proper/scxml/branches/J5/src/main/java/org/apache/commons/scxml/env/javascript/JSBindings.java
------------------------------------------------------------------------------
    svn:eol-style = native

Propchange: commons/proper/scxml/branches/J5/src/main/java/org/apache/commons/scxml/env/javascript/JSBindings.java
------------------------------------------------------------------------------
    svn:keywords = Date Author Id Revision HeadURL

Added: commons/proper/scxml/branches/J5/src/main/java/org/apache/commons/scxml/env/javascript/JSContext.java
URL: http://svn.apache.org/viewvc/commons/proper/scxml/branches/J5/src/main/java/org/apache/commons/scxml/env/javascript/JSContext.java?rev=634858&view=auto
==============================================================================
--- commons/proper/scxml/branches/J5/src/main/java/org/apache/commons/scxml/env/javascript/JSContext.java (added)
+++ commons/proper/scxml/branches/J5/src/main/java/org/apache/commons/scxml/env/javascript/JSContext.java Fri Mar  7 15:18:48 2008
@@ -0,0 +1,55 @@
+/*
+ * 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.scxml.env.javascript;
+
+import org.apache.commons.scxml.Context;
+import org.apache.commons.scxml.env.SimpleContext;
+
+/**
+ * SCXML Context for use by the JSEvaluator. It is simply a 'no functionality'
+ * 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 {
+
+       // CONSTRUCTORS
+
+       /**
+        * Default constructor - just invokes the SimpleContext default
+        * constructor.
+        */
+       public JSContext() {
+           super();
+       }
+
+       /**
+        * Child constructor. Just invokes the identical SimpleContext
+	* constructor.
+        *
+        * @param parent Parent context for this context.
+        *
+        */
+       public JSContext(Context parent) {
+           super(parent);
+       }
+
+}
+

Propchange: commons/proper/scxml/branches/J5/src/main/java/org/apache/commons/scxml/env/javascript/JSContext.java
------------------------------------------------------------------------------
    svn:eol-style = native

Propchange: commons/proper/scxml/branches/J5/src/main/java/org/apache/commons/scxml/env/javascript/JSContext.java
------------------------------------------------------------------------------
    svn:keywords = Date Author Id Revision HeadURL

Added: commons/proper/scxml/branches/J5/src/main/java/org/apache/commons/scxml/env/javascript/JSEvaluator.java
URL: http://svn.apache.org/viewvc/commons/proper/scxml/branches/J5/src/main/java/org/apache/commons/scxml/env/javascript/JSEvaluator.java?rev=634858&view=auto
==============================================================================
--- commons/proper/scxml/branches/J5/src/main/java/org/apache/commons/scxml/env/javascript/JSEvaluator.java (added)
+++ commons/proper/scxml/branches/J5/src/main/java/org/apache/commons/scxml/env/javascript/JSEvaluator.java Fri Mar  7 15:18:48 2008
@@ -0,0 +1,230 @@
+/*
+ * 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.scxml.env.javascript;
+
+import java.util.Map;
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
+
+import javax.script.Bindings;
+import javax.script.ScriptContext;
+import javax.script.ScriptEngine;
+import javax.script.ScriptEngineManager;
+
+import org.apache.commons.scxml.Builtin;
+import org.apache.commons.scxml.Context;
+import org.apache.commons.scxml.Evaluator;
+import org.apache.commons.scxml.SCXMLExpressionException;
+import org.apache.commons.scxml.SCXMLHelper;
+import org.w3c.dom.Node;
+
+/**
+ * Embedded JavaScript expression evaluator for SCXML expressions. This
+ * implementation is a just a 'thin' wrapper around the Javascript engine in
+ * JDK 6 (based on on Mozilla Rhino 1.6.2).
+ * <p>
+ * Mozilla Rhino 1.6.2 does not support E4X so accessing the SCXML data model
+ * is implemented in the same way as the JEXL expression evaluator i.e. using
+ * the Data() function, for example,
+ * &lt;assign location="Data(hotelbooking,'hotel/rooms')" expr="2" /&gt;
+ *
+ */
+
+public class JSEvaluator implements Evaluator {
+
+    // CONSTANTS
+
+    private static final Pattern XPATH =
+        Pattern.compile("Data\\s*\\(\\s*(\\w+)\\s*,\\s*((?:'.*?')|(?:\".*?\"))\\s*\\)");
+
+    // INSTANCE VARIABLES
+
+    private ScriptEngineManager factory;
+
+    // CONSTRUCTORS
+
+    /**
+     * Initialises the internal Javascript engine factory.
+     */
+    public JSEvaluator() {
+        factory = new ScriptEngineManager();
+
+        factory.put("xpath",this);
+    }
+
+    // INSTANCE METHODS
+
+    /**
+     * Creates a child context.
+     *
+     * @param  context FSM parent context.
+     * @return Returns a new child JSContext.
+     *
+     */
+    @Override
+    public Context newContext(Context parent) {
+        return new JSContext(parent);
+    }
+
+    /**
+     * 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
+     * <code>Data()</code> functions are replaced with an equivalent internal
+     * Javascript function.
+     *
+     * @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.
+     */
+    @SuppressWarnings("unchecked")
+    @Override
+    public Object eval(Context context,String expression) throws SCXMLExpressionException {
+        try {
+            // ... initialise
+
+            Matcher      matcher  = XPATH.matcher   (expression);
+            StringBuffer buffer   = new StringBuffer();
+            ScriptEngine engine   = factory.getEngineByName("JavaScript");
+            Bindings     bindings = engine.getBindings     (ScriptContext.ENGINE_SCOPE);
+
+            // ... replace Data() functions
+
+            while (matcher.find()) {
+                  matcher.appendReplacement(buffer,"xpath.evaluate(_ALL_NAMESPACES," + matcher.group(1) + "," + matcher.group(2) + ")");
+            }
+
+            matcher.appendTail(buffer);
+
+            // ... evaluate
+
+            return engine.eval(buffer.toString(),new JSBindings(context,bindings));
+        } catch (Throwable x) {
+            throw new SCXMLExpressionException("Error evaluating ['" + expression + "'] " + x);
+        }
+    }
+
+    /**
+     * Evaluates a conditional expression using the <code>eval()</code> method and
+     * casting the result to a Boolean.
+     *
+     * @param context    SCXML context.
+     * @param expression Expression to evaluate.
+     *
+     * @return Boolean or <code>null</code>.
+     *
+     * @throws SCXMLExpressionException Thrown if the expression was invalid or did
+     *                                  not return a boolean.
+     */
+    @Override
+    public Boolean evalCond(Context context,String expression) throws SCXMLExpressionException {
+        Object object;
+
+        if ((object = eval(context,expression)) == null) {
+           return null;
+        }
+
+        if (object instanceof Boolean) {
+           return (Boolean) object;
+        }
+
+        throw new SCXMLExpressionException("Invalid boolean expression: " + expression);
+    }
+
+    /**
+     * Evaluates a location 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
+     * <code>Data()</code> functions are replaced with an equivalent internal
+     * Javascript function.
+     *
+     * @param context    FSM context.
+     * @param expression Expression to evaluate.
+     *
+     * @throws SCXMLExpressionException Thrown if the expression was invalid.
+     */
+    @SuppressWarnings("unchecked")
+    @Override
+    public Node evalLocation(Context context,String expression) throws SCXMLExpressionException {
+        try {
+            // ... initialise
+
+            Matcher        matcher  = XPATH.matcher   (expression);
+            StringBuffer   buffer   = new StringBuffer();
+            ScriptEngine   engine   = factory.getEngineByName("JavaScript");
+            Bindings       bindings = engine.getBindings(ScriptContext.ENGINE_SCOPE);
+
+            // ... replace Data() function
+
+            while (matcher.find()) {
+                  matcher.appendReplacement(buffer,"xpath.node(_ALL_NAMESPACES," + matcher.group(1) + "," + matcher.group(2) + ")");
+            }
+
+            matcher.appendTail(buffer);
+
+            // ... evaluate
+
+            return (Node) engine.eval(buffer.toString(),new JSBindings(context,bindings));
+        } catch (Throwable x) {
+            throw new SCXMLExpressionException("Error evaluating ['" + expression + "'] " + x);
+        }
+    }
+
+    /**
+     * Implementation of Javascript function equivalent for the Data() function when
+     * used in an SCXML <code>expr</code> attribute.
+     * <p>
+     * NOTE: Only declared public for access by script engine - not intended to be
+     *       used by anything else.
+     *
+     * @param namespaces SCXML namespace map.
+     * @param node       Data() function root node.
+     * @param query      Data() function expression.
+     *
+     * @return Value stored at SCXML data model node represented by the <code>query</code>
+     *         expression or <code>null</code>.
+     */
+    @SuppressWarnings("unchecked")
+    public Object evaluate(Map namespaces,Object node,String query) {
+        return SCXMLHelper.getNodeValue(node(namespaces,node,query));
+    }
+
+    /**
+     * Implementation of Javascript function equivalent for the Data() function when used
+     * in an SCXML <code>location</code> attribute.
+     * <p>
+     * NOTE: Only declared public for access by script engine - not intended to be
+     *       used by anything else.
+     *
+     * @param namespaces SCXML namespace map.
+     * @param node       Data() function root node.
+     * @param query      Data() function expression.
+     *
+     * @return Node at SCXML data model node represented by the <code>query</code>
+     *         expression or <code>null</code>.
+     */
+    @SuppressWarnings("unchecked")
+    public Node node(Map namespaces,Object node,String query) {
+        return Builtin.dataNode(namespaces,node,query);
+    }
+
+}
+

Propchange: commons/proper/scxml/branches/J5/src/main/java/org/apache/commons/scxml/env/javascript/JSEvaluator.java
------------------------------------------------------------------------------
    svn:eol-style = native

Propchange: commons/proper/scxml/branches/J5/src/main/java/org/apache/commons/scxml/env/javascript/JSEvaluator.java
------------------------------------------------------------------------------
    svn:keywords = Date Author Id Revision HeadURL

Modified: commons/proper/scxml/branches/J5/src/test/java/org/apache/commons/scxml/AllSCXMLTestSuite.java
URL: http://svn.apache.org/viewvc/commons/proper/scxml/branches/J5/src/test/java/org/apache/commons/scxml/AllSCXMLTestSuite.java?rev=634858&r1=634857&r2=634858&view=diff
==============================================================================
--- commons/proper/scxml/branches/J5/src/test/java/org/apache/commons/scxml/AllSCXMLTestSuite.java (original)
+++ commons/proper/scxml/branches/J5/src/test/java/org/apache/commons/scxml/AllSCXMLTestSuite.java Fri Mar  7 15:18:48 2008
@@ -23,6 +23,7 @@
 
 import org.apache.commons.scxml.env.EnvTestSuite;
 import org.apache.commons.scxml.env.faces.EnvFacesTestSuite;
+import org.apache.commons.scxml.env.javascript.EnvJavaScriptTestSuite;
 import org.apache.commons.scxml.env.jexl.EnvJexlTestSuite;
 import org.apache.commons.scxml.env.jsp.EnvJspTestSuite;
 import org.apache.commons.scxml.env.servlet.EnvServletTestSuite;
@@ -61,6 +62,7 @@
         TestSuite suite = new TestSuite();
         suite.setName("Commons-SCXML (all) Tests");
         suite.addTest(EnvFacesTestSuite.suite());
+        suite.addTest(EnvJavaScriptTestSuite.suite());
         suite.addTest(EnvJexlTestSuite.suite());
         suite.addTest(EnvJspTestSuite.suite());
         suite.addTest(EnvServletTestSuite.suite());

Added: commons/proper/scxml/branches/J5/src/test/java/org/apache/commons/scxml/env/javascript/EnvJavaScriptTestSuite.java
URL: http://svn.apache.org/viewvc/commons/proper/scxml/branches/J5/src/test/java/org/apache/commons/scxml/env/javascript/EnvJavaScriptTestSuite.java?rev=634858&view=auto
==============================================================================
--- commons/proper/scxml/branches/J5/src/test/java/org/apache/commons/scxml/env/javascript/EnvJavaScriptTestSuite.java (added)
+++ commons/proper/scxml/branches/J5/src/test/java/org/apache/commons/scxml/env/javascript/EnvJavaScriptTestSuite.java Fri Mar  7 15:18:48 2008
@@ -0,0 +1,69 @@
+/*
+ * 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.scxml.env.javascript;
+
+import junit.framework.Test;
+import junit.framework.TestCase;
+import junit.framework.TestSuite;
+import junit.textui.TestRunner;
+
+/**
+ * JUnit 3 test suite for the JavaScript environment. Tests:
+ * <ul>
+ * <li>JSEValuator
+ * <li>JSBindings
+ * <li>JSContext
+ * </ul>
+ * Also includes a sample SCXML document with JavaScript expressions.
+ *
+ */
+public class EnvJavaScriptTestSuite extends TestCase {
+    // CLASS METHODS
+
+    /**
+     * Returns the test suite for the JavaScript environment.
+     */
+    public static Test suite() {
+        TestSuite suite = new TestSuite("Commons-SCXML JavaScript Environment Tests");
+
+        suite.addTest(JSBindingsTest.suite());
+        suite.addTest(JSContextTest.suite());
+        suite.addTest(JSEvaluatorTest.suite());
+        suite.addTest(JSExampleTest.suite());
+
+        return suite;
+    }
+
+    /**
+     * Command-line interface.
+     */
+    public static void main(String[] args) {
+        TestRunner.run(suite());
+    }
+
+    // CONSTRUCTOR
+
+    /**
+     * Instantiates and initializes a new test suite.
+     */
+    public EnvJavaScriptTestSuite(String name) {
+        super(name);
+    }
+
+}
+

Propchange: commons/proper/scxml/branches/J5/src/test/java/org/apache/commons/scxml/env/javascript/EnvJavaScriptTestSuite.java
------------------------------------------------------------------------------
    svn:eol-style = native

Propchange: commons/proper/scxml/branches/J5/src/test/java/org/apache/commons/scxml/env/javascript/EnvJavaScriptTestSuite.java
------------------------------------------------------------------------------
    svn:keywords = Date Author Id Revision HeadURL

Added: commons/proper/scxml/branches/J5/src/test/java/org/apache/commons/scxml/env/javascript/JSBindingsTest.java
URL: http://svn.apache.org/viewvc/commons/proper/scxml/branches/J5/src/test/java/org/apache/commons/scxml/env/javascript/JSBindingsTest.java?rev=634858&view=auto
==============================================================================
--- commons/proper/scxml/branches/J5/src/test/java/org/apache/commons/scxml/env/javascript/JSBindingsTest.java (added)
+++ commons/proper/scxml/branches/J5/src/test/java/org/apache/commons/scxml/env/javascript/JSBindingsTest.java Fri Mar  7 15:18:48 2008
@@ -0,0 +1,667 @@
+/*
+ * 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.scxml.env.javascript;
+
+import java.util.AbstractMap;
+import java.util.HashMap;
+import java.util.Map;
+
+import javax.script.Bindings;
+import javax.script.SimpleBindings;
+
+import org.apache.commons.scxml.Context;
+import org.apache.commons.scxml.SCXMLExpressionException;
+
+import junit.framework.Test;
+import junit.framework.TestCase;
+import junit.framework.TestSuite;
+
+/**
+ * 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 extends TestCase {
+    // 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.
+     */
+    protected 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);
+    }
+
+    /**
+     * Returns a JUnit test suite containing the JSBindingsTest class only.
+     */
+    public static Test suite() {
+        return new TestSuite(JSBindingsTest.class);
+    }
+
+    // CONSTRUCTORS
+
+    /**
+     * Initializes the test case with a name.
+     */
+    public JSBindingsTest(String testName) {
+        super(testName);
+    }
+
+    // INSTANCE METHOD TESTS
+
+    /**
+     * Tests implementation of JSBindings constructor.
+     */
+    public void testConstructor() throws SCXMLExpressionException {
+        assertNotNull(new JSBindings(new JSContext(),new SimpleBindings()));
+    }
+
+    /**
+     * Test implementation of JSBindings constructor with invalid SCXML context.
+     */
+    public void testInvalidContextConstructor() throws SCXMLExpressionException {
+        try {
+             assertNotNull(new JSBindings(null,new SimpleBindings()));
+             fail("JSBindings constructor accepted invalid SCXML context");
+
+        } catch (IllegalArgumentException x) {
+        }
+    }
+
+    /**
+     * Test implementation of JSBindings constructor with invalid Javascript bindings.
+     */
+    public void testInvalidBindingsConstructor() throws SCXMLExpressionException {
+        try {
+             assertNotNull(new JSBindings(new JSContext(),null));
+             fail("JSBindings constructor accepted invalid Javascript bindings");
+
+        } catch (IllegalArgumentException x) {
+        }
+    }
+
+    /**
+     * Tests the <code>containsKey</code> method with items in the SCXML context as well as the
+     * JavaScript Bindings.
+     *
+     */
+    public void testContainsKey() {
+        Context    context  = new JSContext     ();
+        Bindings   bindings = new SimpleBindings();
+        JSBindings jsx      = new JSBindings    (context,bindings);
+
+        assertFalse("Invalid SCXML context",      context.has         ("bear"));
+        assertFalse("Invalid Javascript bindings",bindings.containsKey("bear"));
+        assertFalse("Invalid JSbindings",         jsx.containsKey     ("bear"));
+
+        context.set("bear","koala");
+        assertTrue ("Invalid SCXML context",      context.has         ("bear"));
+        assertFalse("Invalid Javascript bindings",bindings.containsKey("bear"));
+        assertTrue ("Invalid JSbindings",         jsx.containsKey     ("bear"));
+
+        context.reset();
+        bindings.put ("bear","grizzly");
+        assertFalse  ("Invalid SCXML context",      context.has         ("bear"));
+        assertTrue   ("Invalid Javascript bindings",bindings.containsKey("bear"));
+        assertTrue   ("Invalid JSbindings",         jsx.containsKey     ("bear"));
+
+        context.set ("bear","koala");
+        bindings.put("bear","grizzly");
+        assertTrue  ("Invalid SCXML context",      context.has         ("bear"));
+        assertTrue  ("Invalid Javascript bindings",bindings.containsKey("bear"));
+        assertTrue  ("Invalid JSbindings",         jsx.containsKey     ("bear"));
+    }
+
+    /**
+     * Tests the <code>keySet</code> method with items in the SCXML context as well as the
+     * JavaScript Bindings.
+     *
+     */
+    public void testKeySet() {
+        Context    context  = new JSContext     ();
+        Bindings   bindings = new SimpleBindings();
+        JSBindings jsx      = new JSBindings    (context,bindings);
+
+        assertFalse ("Invalid SCXML context",      context.has          ("bear"));
+        assertFalse ("Invalid Javascript bindings",bindings.containsKey ("bear"));
+        assertFalse ("Invalid JSbindings",         jsx.keySet().contains("bear"));
+
+        context.set   ("bear","koala");
+        bindings.clear();
+        assertTrue    ("Invalid SCXML context",      context.has          ("bear"));
+        assertFalse   ("Invalid Javascript bindings",bindings.containsKey ("bear"));
+        assertTrue    ("Invalid JSbindings",         jsx.keySet().contains("bear"));
+
+        context.reset ();
+        bindings.clear();
+        bindings.put  ("bear","grizzly");
+        assertFalse   ("Invalid SCXML context",      context.has          ("bear"));
+        assertTrue    ("Invalid Javascript bindings",bindings.containsKey ("bear"));
+        assertTrue    ("Invalid JSbindings",         jsx.keySet().contains("bear"));
+
+        context.reset ();
+        bindings.clear();
+        context.set  ("cat","felix");
+        bindings.put ("dog","rover");
+        assertFalse  ("Invalid SCXML context",      context.has          ("bear"));
+        assertFalse  ("Invalid Javascript bindings",bindings.containsKey ("bear"));
+        assertTrue   ("Invalid SCXML context",      context.has          ("cat"));
+        assertTrue   ("Invalid Javascript bindings",bindings.containsKey ("dog"));
+        assertTrue   ("Invalid JSbindings",         jsx.keySet().contains("cat"));
+        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.
+     *
+     */
+   public void testSize() {
+       Context    context  = new JSContext     ();
+       Bindings   bindings = new SimpleBindings();
+       JSBindings jsx      = new JSBindings    (context,bindings);
+
+       assertFalse ("Invalid SCXML context",      context.has          ("bear"));
+       assertFalse ("Invalid Javascript bindings",bindings.containsKey ("bear"));
+       assertEquals("Invalid JSbindings",0,jsx.size());
+
+       context.set   ("bear","koala");
+       bindings.clear();
+       assertTrue    ("Invalid SCXML context",      context.has          ("bear"));
+       assertFalse   ("Invalid Javascript bindings",bindings.containsKey ("bear"));
+       assertEquals  ("Invalid JSbindings",1,jsx.size());
+
+       context.reset ();
+       bindings.clear();
+       bindings.put  ("bear","grizzly");
+       assertFalse   ("Invalid SCXML context",      context.has          ("bear"));
+       assertTrue    ("Invalid Javascript bindings",bindings.containsKey ("bear"));
+       assertEquals  ("Invalid JSbindings",1,jsx.size());
+
+       context.reset ();
+       bindings.clear();
+       context.set   ("bear","koala");
+       bindings.put  ("bear","grizzly");
+       assertTrue    ("Invalid SCXML context",      context.has          ("bear"));
+       assertTrue    ("Invalid Javascript bindings",bindings.containsKey ("bear"));
+       assertEquals  ("Invalid JSbindings",1,jsx.size());
+
+       context.reset ();
+       bindings.clear();
+       context.set  ("cat","felix");
+       bindings.put ("dog","rover");
+       assertFalse  ("Invalid SCXML context",      context.has          ("bear"));
+       assertFalse  ("Invalid Javascript bindings",bindings.containsKey ("bear"));
+       assertTrue   ("Invalid SCXML context",      context.has          ("cat"));
+       assertTrue   ("Invalid Javascript bindings",bindings.containsKey ("dog"));
+       assertEquals ("Invalid JSbindings",2,jsx.size());
+    }
+
+    /**
+     * Tests the <code>containsValue</code> method with items in the SCXML context as well as the
+     * JavaScript Bindings.
+     *
+     */
+    public void testContainsValue() {
+        Context    context  = new JSContext     ();
+        Bindings   bindings = new SimpleBindings();
+        JSBindings jsx      = new JSBindings    (context,bindings);
+
+        assertFalse("Invalid SCXML context",      context.getVars().containsValue("koala"));
+        assertFalse("Invalid Javascript bindings",bindings.containsValue("koala"));
+        assertFalse("Invalid JSbindings",         jsx.containsValue     ("koala"));
+
+        context.reset ();
+        bindings.clear();
+        context.set   ("bear","koala");
+        assertTrue    ("Invalid SCXML context",      context.getVars().containsValue("koala"));
+        assertFalse   ("Invalid Javascript bindings",bindings.containsValue("koala"));
+        assertTrue    ("Invalid JSbindings",         jsx.containsValue     ("koala"));
+
+        context.reset ();
+        bindings.clear();
+        bindings.put  ("bear","grizzly");
+        assertFalse   ("Invalid SCXML context",      context.getVars().containsValue("grizzly"));
+        assertTrue    ("Invalid Javascript bindings",bindings.containsValue("grizzly"));
+        assertTrue    ("Invalid JSbindings",         jsx.containsValue     ("grizzly"));
+
+        context.reset ();
+        bindings.clear();
+        context.set   ("bear","koala");
+        bindings.put  ("bear","grizzly");
+        assertTrue    ("Invalid SCXML context",      context.getVars().containsValue("koala"));
+        assertTrue    ("Invalid Javascript bindings",bindings.containsValue("grizzly"));
+        assertTrue    ("Invalid JSbindings",         jsx.containsValue     ("koala"));
+        assertTrue    ("Invalid JSbindings",         jsx.containsValue     ("grizzly"));
+    }
+
+    /**
+     * Tests the <code>entrySet</code> method with items in the SCXML context as well as the
+     * JavaScript Bindings.
+     *
+     */
+    public void testEntrySet() {
+        Context    context  = new JSContext     ();
+        Bindings   bindings = new SimpleBindings();
+        JSBindings jsx      = new JSBindings    (context,bindings);
+
+        assertEquals("Invalid SCXML context",      0,context.getVars().entrySet().size());
+        assertEquals("Invalid Javascript bindings",0,bindings.entrySet().size());
+        assertEquals("Invalid JSbindings",         0,jsx.entrySet().size());
+
+        context.reset ();
+        bindings.clear();
+        context.set   ("bear","koala");
+        assertEquals  ("Invalid SCXML context",      1,context.getVars().entrySet().size());
+        assertTrue    ("Invalid SCXML context",      context.getVars().entrySet().contains(KOALA));
+        assertEquals  ("Invalid Javascript bindings",0,bindings.entrySet().size());
+        assertFalse   ("Invalid Javascript bindings",bindings.entrySet().contains(KOALA));
+        assertEquals  ("Invalid JSBindings",         1,jsx.entrySet().size());
+        assertTrue    ("Invalid JSbindings",         jsx.entrySet().contains(KOALA));
+
+        context.reset ();
+        bindings.clear();
+        bindings.put  ("bear","grizzly");
+        assertEquals  ("Invalid SCXML context",      0,context.getVars().entrySet().size());
+        assertFalse   ("Invalid SCXML context",      context.getVars().entrySet().contains(GRIZZLY));
+        assertEquals  ("Invalid Javascript bindings",1,bindings.entrySet().size());
+        assertTrue    ("Invalid Javascript bindings",bindings.entrySet().contains(GRIZZLY));
+        assertEquals  ("Invalid JSBindings",         1,jsx.entrySet().size());
+        assertTrue    ("Invalid JSbindings",         jsx.entrySet().contains(GRIZZLY));
+
+        context.reset ();
+        bindings.clear();
+        context.set   ("bear","koala");
+        bindings.put  ("bear","grizzly");
+        assertEquals  ("Invalid SCXML context",      1,context.getVars().entrySet().size());
+        assertTrue    ("Invalid SCXML context",      context.getVars().entrySet().contains(KOALA));
+        assertEquals  ("Invalid Javascript bindings",1,bindings.entrySet().size());
+        assertTrue    ("Invalid Javascript bindings",bindings.entrySet().contains(GRIZZLY));
+        assertEquals  ("Invalid JSBindings",         1,jsx.entrySet().size());
+        assertFalse   ("Invalid JSbindings",         jsx.entrySet().contains(KOALA));
+        assertTrue    ("Invalid JSbindings",         jsx.entrySet().contains(GRIZZLY));
+
+        context.reset ();
+        bindings.clear();
+        context.set   ("cat","felix");
+        bindings.put  ("dog","rover");
+        assertEquals  ("Invalid SCXML context",      1,context.getVars().entrySet().size());
+        assertTrue    ("Invalid SCXML context",      context.getVars().entrySet().contains(FELIX));
+        assertEquals  ("Invalid Javascript bindings",1,bindings.entrySet().size());
+        assertTrue    ("Invalid Javascript bindings",bindings.entrySet().contains(ROVER));
+        assertEquals  ("Invalid JSBindings",         2,jsx.entrySet().size());
+        assertTrue    ("Invalid JSbindings",         jsx.entrySet().contains(FELIX));
+        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.
+     *
+     */
+    public void testValues() {
+        Context    context  = new JSContext     ();
+        Bindings   bindings = new SimpleBindings();
+        JSBindings jsx      = new JSBindings    (context,bindings);
+
+        assertEquals("Invalid SCXML context",      0,context.getVars().values().size());
+        assertEquals("Invalid Javascript bindings",0,bindings.values().size());
+        assertEquals("Invalid JSbindings",         0,jsx.values().size());
+
+        context.reset ();
+        bindings.clear();
+        context.set   ("bear","koala");
+        assertEquals  ("Invalid SCXML context",      1,context.getVars().values().size());
+        assertTrue    ("Invalid SCXML context",      context.getVars().values().contains(KOALA.getValue()));
+        assertEquals  ("Invalid Javascript bindings",0,bindings.values().size());
+        assertFalse   ("Invalid Javascript bindings",bindings.values().contains(KOALA.getValue()));
+        assertEquals  ("Invalid JSBindings",         1,jsx.values().size());
+        assertTrue    ("Invalid JSbindings",         jsx.values().contains(KOALA.getValue()));
+
+        context.reset ();
+        bindings.clear();
+        bindings.put  ("bear","grizzly");
+        assertEquals  ("Invalid SCXML context",      0,context.getVars().values().size());
+        assertFalse   ("Invalid SCXML context",      context.getVars().values().contains(GRIZZLY.getValue()));
+        assertEquals  ("Invalid Javascript bindings",1,bindings.values().size());
+        assertTrue    ("Invalid Javascript bindings",bindings.values().contains(GRIZZLY.getValue()));
+        assertEquals  ("Invalid JSBindings",         1,jsx.values().size());
+        assertTrue    ("Invalid JSbindings",         jsx.values().contains(GRIZZLY.getValue()));
+
+        context.reset ();
+        bindings.clear();
+        context.set   ("bear","koala");
+        bindings.put  ("bear","grizzly");
+        assertEquals  ("Invalid SCXML context",      1,context.getVars().values().size());
+        assertTrue    ("Invalid SCXML context",      context.getVars().values().contains(KOALA.getValue()));
+        assertEquals  ("Invalid Javascript bindings",1,bindings.values().size());
+        assertTrue    ("Invalid Javascript bindings",bindings.values().contains(GRIZZLY.getValue()));
+        assertEquals  ("Invalid JSBindings",         1,jsx.values().size());
+        assertFalse   ("Invalid JSbindings",         jsx.values().contains(KOALA.getValue()));
+        assertTrue    ("Invalid JSbindings",         jsx.values().contains(GRIZZLY.getValue()));
+
+        context.reset ();
+        bindings.clear();
+        context.set   ("cat","felix");
+        bindings.put  ("dog","rover");
+        assertEquals  ("Invalid SCXML context",      1,context.getVars().values().size());
+        assertTrue    ("Invalid SCXML context",      context.getVars().values().contains(FELIX.getValue()));
+        assertEquals  ("Invalid Javascript bindings",1,bindings.values().size());
+        assertTrue    ("Invalid Javascript bindings",bindings.values().contains(ROVER.getValue()));
+        assertEquals  ("Invalid JSBindings",         2,jsx.values().size());
+        assertTrue    ("Invalid JSbindings",         jsx.values().contains(FELIX.getValue()));
+        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.
+     *
+     */
+    public void testIsEmpty() {
+        Context    context  = new JSContext     ();
+        Bindings   bindings = new SimpleBindings();
+        JSBindings jsx      = new JSBindings    (context,bindings);
+
+        assertTrue("Invalid SCXML context",      context.getVars().isEmpty());
+        assertTrue("Invalid Javascript bindings",bindings.isEmpty());
+        assertTrue("Invalid JSbindings",         jsx.isEmpty());
+
+        context.set   ("bear","koala");
+        bindings.clear();
+        assertFalse   ("Invalid SCXML context",      context.getVars().isEmpty());
+        assertTrue    ("Invalid Javascript bindings",bindings.isEmpty());
+        assertFalse   ("Invalid JSbindings",         jsx.isEmpty());
+
+        context.reset ();
+        bindings.clear();
+        bindings.put  ("bear","grizzly");
+        assertTrue    ("Invalid SCXML context",      context.getVars().isEmpty());
+        assertFalse   ("Invalid Javascript bindings",bindings.isEmpty());
+        assertFalse   ("Invalid JSbindings",         jsx.isEmpty());
+
+        context.reset ();
+        bindings.clear();
+        context.set   ("bear","koala");
+        bindings.put  ("bear","grizzly");
+        assertFalse   ("Invalid SCXML context",      context.getVars().isEmpty());
+        assertFalse   ("Invalid Javascript bindings",bindings.isEmpty());
+        assertFalse   ("Invalid JSbindings",         jsx.isEmpty());
+
+        context.reset ();
+        bindings.clear();
+        context.set   ("cat","felix");
+        bindings.put  ("dog","rover");
+        assertFalse   ("Invalid SCXML context",      context.getVars().isEmpty());
+        assertFalse   ("Invalid Javascript bindings",bindings.isEmpty());
+        assertFalse   ("Invalid JSbindings",         jsx.isEmpty());
+    }
+
+    /**
+     * Tests the <code>get</code> method with items in the SCXML context as well as the
+     * JavaScript Bindings.
+     *
+     */
+    public void testGet() {
+        Context    context  = new JSContext     ();
+        Bindings   bindings = new SimpleBindings();
+        JSBindings jsx      = new JSBindings    (context,bindings);
+
+        assertNull("Invalid SCXML context",      context.get ("bear"));
+        assertNull("Invalid Javascript bindings",bindings.get("bear"));
+        assertNull("Invalid JSbindings",         jsx.get     ("bear"));
+
+        context.reset ();
+        bindings.clear();
+        context.set   ("bear","koala");
+        assertNotNull ("Invalid SCXML context",        context.get ("bear"));
+        assertEquals  ("Invalid SCXML context","koala",context.get ("bear"));
+        assertNull    ("Invalid Javascript bindings",  bindings.get("bear"));
+        assertNotNull ("Invalid JSbindings",           jsx.get     ("bear"));
+        assertEquals  ("Invalid JSbindings","koala",   jsx.get     ("bear"));
+
+        context.reset ();
+        bindings.clear();
+        bindings.put  ("bear","grizzly");
+        assertNull    ("Invalid SCXML context",                context.get ("bear"));
+        assertNotNull ("Invalid Javascript bindings",          bindings.get("bear"));
+        assertEquals  ("Invalid Javascript bindings","grizzly",bindings.get("bear"));
+        assertNotNull ("Invalid JSbindings",                   jsx.get     ("bear"));
+        assertEquals  ("Invalid JSbindings","grizzly",         jsx.get     ("bear"));
+
+        context.reset ();
+        bindings.clear();
+        context.set   ("bear","koala");
+        bindings.put  ("bear","grizzly");
+        assertNotNull ("Invalid SCXML context",        context.get ("bear"));
+        assertEquals  ("Invalid SCXML context","koala",context.get ("bear"));
+        assertNotNull ("Invalid Javascript bindings",          bindings.get("bear"));
+        assertEquals  ("Invalid Javascript bindings","grizzly",bindings.get("bear"));
+        assertNotNull ("Invalid JSbindings",                   jsx.get     ("bear"));
+        assertEquals  ("Invalid JSbindings","grizzly",         jsx.get     ("bear"));
+
+        context.reset ();
+        bindings.clear();
+        context.set   ("cat","felix");
+        bindings.put  ("dog","rover");
+        assertNotNull ("Invalid SCXML context",              context.get ("cat"));
+        assertEquals  ("Invalid SCXML context","felix",      context.get ("cat"));
+        assertNotNull ("Invalid Javascript bindings",        bindings.get("dog"));
+        assertEquals  ("Invalid Javascript bindings","rover",bindings.get("dog"));
+        assertNotNull ("Invalid JSbindings",                 jsx.get     ("cat"));
+        assertEquals  ("Invalid JSbindings","felix",         jsx.get     ("cat"));
+        assertNotNull ("Invalid JSbindings",                 jsx.get     ("dog"));
+        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.
+     *
+     */
+    public void testPut() {
+        Context    context  = new JSContext     ();
+        Bindings   bindings = new SimpleBindings();
+        JSBindings jsx      = new JSBindings    (context,bindings);
+
+        assertNull("Invalid SCXML context",      context.get ("bear"));
+        assertNull("Invalid Javascript bindings",bindings.get("bear"));
+        assertNull("Invalid JSbindings",         jsx.get     ("bear"));
+
+        jsx.put       ("bear","koala");
+        assertNull    ("Invalid SCXML context",        context.get ("bear"));
+        assertNotNull ("Invalid Javascript bindings",  bindings.get("bear"));
+        assertEquals  ("Invalid Javascript","koala",   bindings.get("bear"));
+    }
+
+    /**
+     * Tests the <code>putAll</code> method with items in the SCXML context as well as the
+     * JavaScript Bindings.
+     *
+     */
+    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");
+
+        assertNull("Invalid SCXML context",      context.get ("bear"));
+        assertNull("Invalid SCXML context",      context.get ("cat"));
+        assertNull("Invalid SCXML context",      context.get ("dog"));
+
+        assertNull("Invalid Javascript bindings",bindings.get("bear"));
+        assertNull("Invalid Javascript bindings",bindings.get("cat"));
+        assertNull("Invalid Javascript bindings",bindings.get("dog"));
+
+        assertNull("Invalid JSbindings",         jsx.get     ("bear"));
+        assertNull("Invalid JSbindings",         jsx.get     ("cat"));
+        assertNull("Invalid JSbindings",         jsx.get     ("dog"));
+
+        context.set("bear","koala");
+        jsx.putAll (vars);
+
+        assertNotNull ("Invalid SCXML context",        context.get ("bear"));
+        assertNull    ("Invalid SCXML context",        context.get ("cat"));
+        assertNull    ("Invalid SCXML context",        context.get ("dog"));
+        assertEquals  ("Invalid SCXML context","koala",context.get ("bear"));
+        assertEquals  ("Invalid SCXML context",1,      context.getVars().size());
+
+        assertNotNull ("Invalid Javascript bindings",          bindings.get("bear"));
+        assertNotNull ("Invalid Javascript bindings",          bindings.get("cat"));
+        assertNotNull ("Invalid Javascript bindings",          bindings.get("dog"));
+        assertEquals  ("Invalid Javascript bindings","grizzly",bindings.get("bear"));
+        assertEquals  ("Invalid Javascript bindings","felix",  bindings.get("cat"));
+        assertEquals  ("Invalid Javascript bindings","rover",  bindings.get("dog"));
+        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.
+     *
+     */
+    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");
+
+        assertNotNull("Invalid SCXML context",        context.get("bear"));
+        assertEquals ("Invalid SCXML context","koala",context.get("bear"));
+        assertEquals ("Invalid SCXML context",1,      context.getVars().size());
+
+        assertNotNull("Invalid Javascript bindings",          bindings.get("bear"));
+        assertNotNull("Invalid Javascript bindings",          bindings.get("cat"));
+        assertNotNull("Invalid Javascript bindings",          bindings.get("dog"));
+        assertEquals ("Invalid Javascript bindings","grizzly",bindings.get("bear"));
+        assertEquals ("Invalid Javascript bindings","felix",  bindings.get("cat"));
+        assertEquals ("Invalid Javascript bindings","rover",  bindings.get("dog"));
+        assertEquals ("Invalid Javascript bindings",3,        bindings.size());
+
+        jsx.remove("cat");
+
+        assertNotNull("Invalid SCXML context",                context.get("bear"));
+        assertEquals ("Invalid SCXML context","koala",        context.get("bear"));
+        assertEquals ("Invalid SCXML context",1,              context.getVars().size());
+        assertNotNull("Invalid Javascript bindings",          bindings.get("bear"));
+        assertNull   ("Invalid Javascript bindings",          bindings.get("cat"));
+        assertNotNull("Invalid Javascript bindings",          bindings.get("dog"));
+        assertEquals ("Invalid Javascript bindings","grizzly",bindings.get("bear"));
+        assertEquals ("Invalid Javascript bindings","rover",  bindings.get("dog"));
+        assertEquals ("Invalid Javascript bindings",2,        bindings.size());
+
+        jsx.remove("dog");
+
+        assertNotNull("Invalid SCXML context",               context.get("bear"));
+        assertEquals ("Invalid SCXML context","koala",        context.get("bear"));
+        assertEquals ("Invalid SCXML context",1,              context.getVars().size());
+        assertNotNull("Invalid Javascript bindings",          bindings.get("bear"));
+        assertNull   ("Invalid Javascript bindings",          bindings.get("cat"));
+        assertNull   ("Invalid Javascript bindings",          bindings.get("dog"));
+        assertEquals ("Invalid Javascript bindings","grizzly",bindings.get("bear"));
+        assertEquals ("Invalid Javascript bindings",1,        bindings.size());
+
+        jsx.remove("bear");
+
+        assertNotNull("Invalid SCXML context",       context.get("bear"));
+        assertEquals("Invalid SCXML context","koala",context.get("bear"));
+        assertEquals("Invalid SCXML context",1,      context.getVars().size());
+        assertNull  ("Invalid Javascript bindings",  bindings.get("bear"));
+        assertNull  ("Invalid Javascript bindings",  bindings.get("cat"));
+        assertNull  ("Invalid Javascript bindings",  bindings.get("dog"));
+        assertEquals("Invalid Javascript bindings",0,bindings.size());
+
+        jsx.remove("bear");
+
+        assertNull  ("Invalid SCXML context",        context.get("bear"));
+        assertEquals("Invalid SCXML context",0,      context.getVars().size());
+        assertNull  ("Invalid Javascript bindings",  bindings.get("bear"));
+        assertNull  ("Invalid Javascript bindings",  bindings.get("cat"));
+        assertNull  ("Invalid Javascript bindings",  bindings.get("dog"));
+        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.
+     *
+     */
+    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");
+
+        assertNotNull("Invalid SCXML context",        context.get("bear"));
+        assertEquals ("Invalid SCXML context","koala",context.get("bear"));
+        assertEquals ("Invalid SCXML context",1,      context.getVars().size());
+
+        assertNotNull("Invalid Javascript bindings",          bindings.get("bear"));
+        assertNotNull("Invalid Javascript bindings",          bindings.get("cat"));
+        assertNotNull("Invalid Javascript bindings",          bindings.get("dog"));
+        assertEquals ("Invalid Javascript bindings","grizzly",bindings.get("bear"));
+        assertEquals ("Invalid Javascript bindings","felix",  bindings.get("cat"));
+        assertEquals ("Invalid Javascript bindings","rover",  bindings.get("dog"));
+        assertEquals ("Invalid Javascript bindings",3,        bindings.size());
+
+        jsx.clear();
+
+        assertNotNull("Invalid SCXML context",       context.get("bear"));
+        assertEquals("Invalid SCXML context","koala",context.get("bear"));
+        assertEquals("Invalid SCXML context",1,      context.getVars().size());
+        assertNull  ("Invalid Javascript bindings",  bindings.get("bear"));
+        assertNull  ("Invalid Javascript bindings",  bindings.get("cat"));
+        assertNull  ("Invalid Javascript bindings",  bindings.get("dog"));
+        assertEquals("Invalid Javascript bindings",0,bindings.size());
+    }
+
+}
+

Propchange: commons/proper/scxml/branches/J5/src/test/java/org/apache/commons/scxml/env/javascript/JSBindingsTest.java
------------------------------------------------------------------------------
    svn:eol-style = native

Propchange: commons/proper/scxml/branches/J5/src/test/java/org/apache/commons/scxml/env/javascript/JSBindingsTest.java
------------------------------------------------------------------------------
    svn:keywords = Date Author Id Revision HeadURL

Added: commons/proper/scxml/branches/J5/src/test/java/org/apache/commons/scxml/env/javascript/JSContextTest.java
URL: http://svn.apache.org/viewvc/commons/proper/scxml/branches/J5/src/test/java/org/apache/commons/scxml/env/javascript/JSContextTest.java?rev=634858&view=auto
==============================================================================
--- commons/proper/scxml/branches/J5/src/test/java/org/apache/commons/scxml/env/javascript/JSContextTest.java (added)
+++ commons/proper/scxml/branches/J5/src/test/java/org/apache/commons/scxml/env/javascript/JSContextTest.java Fri Mar  7 15:18:48 2008
@@ -0,0 +1,87 @@
+/*
+ * 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.scxml.env.javascript;
+
+import org.apache.commons.scxml.env.SimpleContext;
+
+import junit.framework.Test;
+import junit.framework.TestCase;
+import junit.framework.TestSuite;
+
+/**
+ * JUnit 3 test case for the JSContext SCXML Context implementation for
+ * the Javascript expression evaluator.
+ *
+ */
+public class JSContextTest extends TestCase {
+        // TEST CONSTANTS
+
+        // TEST VARIABLES
+
+        // TEST SETUP
+
+        // CLASS METHODS
+
+        /**
+         * Standalone test runtime.
+         *
+         */
+        public static void main(String args[]) {
+            String[] testCaseName = {JSContextTest.class.getName()};
+
+            junit.textui.TestRunner.main(testCaseName);
+        }
+
+        /**
+         * Returns a JUnit test suite containing the JSContextTest class only.
+         *
+         */
+        public static Test suite() {
+                return new TestSuite(JSContextTest.class);
+        }
+
+        // CONSTRUCTORS
+
+        /**
+         * Initialises the test case with the supplied name.
+         *
+         */
+        public JSContextTest(String testName) {
+                super(testName);
+        }
+
+        // INSTANCE METHOD TESTS
+
+        /**
+         * Tests implementation of JSContext default constructor.
+         *
+         */
+        public void testDefaultConstructor() {
+            assertNotNull("Error in JSContext default constructor",new JSContext());
+        }
+
+        /**
+         * Tests implementation of JSContext 'child' constructor.
+         *
+         */
+        public void testChildConstructor() {
+                assertNotNull("Error in JSContext child constructor",new JSContext(new SimpleContext()));
+        }
+
+}
+

Propchange: commons/proper/scxml/branches/J5/src/test/java/org/apache/commons/scxml/env/javascript/JSContextTest.java
------------------------------------------------------------------------------
    svn:eol-style = native

Propchange: commons/proper/scxml/branches/J5/src/test/java/org/apache/commons/scxml/env/javascript/JSContextTest.java
------------------------------------------------------------------------------
    svn:keywords = Date Author Id Revision HeadURL

Added: commons/proper/scxml/branches/J5/src/test/java/org/apache/commons/scxml/env/javascript/JSEvaluatorTest.java
URL: http://svn.apache.org/viewvc/commons/proper/scxml/branches/J5/src/test/java/org/apache/commons/scxml/env/javascript/JSEvaluatorTest.java?rev=634858&view=auto
==============================================================================
--- commons/proper/scxml/branches/J5/src/test/java/org/apache/commons/scxml/env/javascript/JSEvaluatorTest.java (added)
+++ commons/proper/scxml/branches/J5/src/test/java/org/apache/commons/scxml/env/javascript/JSEvaluatorTest.java Fri Mar  7 15:18:48 2008
@@ -0,0 +1,350 @@
+/*
+ * 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.scxml.env.javascript;
+
+import java.io.StringReader;
+
+import javax.xml.xpath.XPath;
+import javax.xml.xpath.XPathConstants;
+import javax.xml.xpath.XPathFactory;
+
+import org.apache.commons.scxml.Context;
+import org.apache.commons.scxml.Evaluator;
+import org.apache.commons.scxml.SCXMLExecutor;
+import org.apache.commons.scxml.SCXMLExpressionException;
+import org.apache.commons.scxml.io.SCXMLParser;
+import org.apache.commons.scxml.model.SCXML;
+import org.apache.xml.utils.DefaultErrorHandler;
+import org.w3c.dom.Element;
+import org.w3c.dom.Node;
+import org.xml.sax.ErrorHandler;
+import org.xml.sax.InputSource;
+
+import junit.framework.Test;
+import junit.framework.TestCase;
+import junit.framework.TestSuite;
+
+/** JUnit 3 test case for the JSEvaluator expression evaluator
+ *  class. Includes basic tests for:
+ *  <ul>
+ *  <li> constructor
+ *  <li> simple standard Javascript expressions
+ *  <li> Javascript expressions referencing SCXML &lt;var..&gt; variables.
+ *  <li> Javascript expressions referencing SCXML data model elements.
+ *  <li> Javascript expressions referencing SCXML data model locations.
+ *  <li> Javascript functions referencing SCXML context variables.
+ *  </ul>
+ */
+
+public class JSEvaluatorTest extends TestCase {
+    // TEST CONSTANTS
+
+    private static final String BAD_EXPRESSION = ">";
+    private static final String SCRIPT         = "<?xml version='1.0'?>" +
+                                                 "<scxml xmlns        = 'http://www.w3.org/2005/07/scxml' " +
+                                                        "xmlns:scxml  = 'http://commons.apache.org/scxml' " +
+                                                        "initialstate = 'start' "  +
+                                                        "version      = '1.0'>" +
+                                                  "<datamodel>"           +
+                                                  "<data name='forest'>"  +
+                                                   "<tree xmlns=''>"      +
+                                                   "<branch>"             +
+                                                   "<twig>leaf</twig>"    +
+                                                   "</branch>"            +
+                                                   "</tree>"              +
+                                                  "</data>"               +
+                                                  "</datamodel>"          +
+                                                  "<state id='start'>"              +
+                                                  "<transition target='end' />"     +
+                                                  "</state>"                        +
+                                                  "<state id='end' final='true' />" +
+                                                  "</scxml>";
+
+    private static final TestItem[] SIMPLE_EXPRESSIONS = {
+            new TestItem("'FIB: ' + (1 + 1 + 2 + 3 + 5)",new String("FIB: 12")),
+            new TestItem("1 + 1 + 2 + 3 + 5",            new Double(12)),
+            new TestItem("(1 + 1 + 2 + 3 + 5) == 12",    new Boolean(true)),
+            new TestItem("(1 + 1 + 2 + 3 + 5) == 13",    new Boolean(false)),
+    };
+
+    private static final TestItem[] VAR_EXPRESSIONS = {
+            new TestItem("'FIB: ' + fibonacci",new String("FIB: 12")),
+            new TestItem("fibonacci * 2",      new Double(24)),
+    };
+
+    private static final String FUNCTION = "function factorial(N) {\r\n" +
+                                                        "if (N == 1)\r\n"    +
+                                                        "   return N;\r\n"   +
+                                                        "\r\n"               +
+                                                        "return N * factorial(N-1);\r\n" +
+                                                "};\r\n" +
+                                                "\r\n"   +
+                                                "function fact5() {\r\n" +
+                                                "         return factorial(FIVE);\r\n" +
+                                                "};\r\n" +
+                                                "\r\n" +
+                                                "fact5()";
+
+    // TEST VARIABLES
+
+    private SCXML         scxml;
+    private Context       context;
+    private Evaluator     evaluator;
+    private SCXMLExecutor fsm;
+
+    // TEST SETUP
+
+    /**
+     * Creates and initialises an SCXML data model in the context.
+     *
+     */
+    protected void setUp() throws Exception {
+            StringReader reader = new StringReader(SCRIPT);
+            InputSource  source = new InputSource (reader);
+            ErrorHandler errors = new DefaultErrorHandler();
+
+            scxml     = SCXMLParser.parse(source,errors);
+            context   = new JSContext();
+            evaluator = new JSEvaluator();
+            fsm       = new SCXMLExecutor();
+
+            context.set("_ALL_NAMESPACES",null);
+
+            fsm.setEvaluator   (evaluator);
+            fsm.setRootContext (context);
+            fsm.setStateMachine(scxml);
+            fsm.reset          ();
+    }
+
+    // CLASS METHODS
+
+    /**
+     * Standalone test runtime.
+     *
+     */
+    public static void main(String args[]) {
+        String[] testCaseName = {JSEvaluatorTest.class.getName()};
+
+        junit.textui.TestRunner.main(testCaseName);
+    }
+
+    /**
+     * Returns a JUnit test suite containing the JSEvaluatorTest class only.
+     *
+     */
+    public static Test suite() {
+            return new TestSuite(JSEvaluatorTest.class);
+    }
+
+    // CONSTRUCTORS
+
+    /**
+     * Initialises the test case with a name.
+     *
+     */
+    public JSEvaluatorTest(String testName) {
+            super(testName);
+    }
+
+    // INSTANCE METHOD TESTS
+
+    /**
+     * Ensures implementation of JSEvaluator default constructor and test basic
+     * expression evaluation.
+     *
+     */
+    public void testBasic() throws SCXMLExpressionException {
+        Evaluator evaluator = new JSEvaluator();
+
+        assertNotNull(evaluator);
+        assertTrue   (((Boolean) evaluator.eval(context, "1+1 == 2")).booleanValue());
+    }
+
+    /**
+     * Tests handling of illegal expressions.
+     *
+     */
+    public void testIllegalExpresssion() {
+        Evaluator evaluator = new JSEvaluator();
+
+        assertNotNull(evaluator);
+
+        try {
+            evaluator.eval(context,BAD_EXPRESSION);
+            fail          ("JSEvaluator should throw SCXMLExpressionException");
+
+        } catch (SCXMLExpressionException x) {
+            assertTrue("JSEvaluator: Incorrect error message",
+                       x.getMessage().startsWith("Error evaluating ['" + BAD_EXPRESSION + "']"));
+        }
+    }
+
+    /**
+     * Tests evaluation with simple standard expressions.
+     *
+     */
+    public void testStandardExpressions() {
+        try {
+            for (TestItem item: SIMPLE_EXPRESSIONS) {
+                assertEquals("Invalid result: " + item.expression,
+                             item.result,
+                             evaluator.eval(context,item.expression));
+            }
+
+        } catch (Exception x) {
+            fail(x.getMessage());
+        }
+    }
+
+    /**
+     * Tests evaluation with SCXML context variables.
+     *
+     */
+    public void testVarExpressions() {
+        try {
+            context.set("fibonacci",12);
+
+            for (TestItem item: VAR_EXPRESSIONS) {
+                assertNotNull(context.get("fibonacci"));
+                assertEquals (12,context.get("fibonacci"));
+                assertEquals ("Invalid result: " + item.expression,
+                              item.result,
+                              evaluator.eval(context,item.expression));
+            }
+        } catch (Exception x) {
+            fail(x.getMessage());
+        }
+    }
+
+    /**
+     * Tests evaluation with invalid SCXML context variables.
+     *
+     */
+    public void testInvalidVarExpressions() {
+        for (TestItem item: VAR_EXPRESSIONS) {
+            try {
+                assertNull    (context.get("fibonacci"));
+                evaluator.eval(context,item.expression);
+                fail          ("Evaluated invalid <var... expression: " + item.expression);
+
+            } catch (SCXMLExpressionException x) {
+            }
+        }
+    }
+
+    /**
+     * Tests evaluation with SCXML data model expressions.
+     *
+     */
+    public void testDataModelExpressions() {
+        try {
+            assertEquals("Invalid result: " + "Data(forest,'tree/branch/twig')",
+                         "leaf",
+                         evaluator.eval(context,"Data(forest,'tree/branch/twig')"));
+
+        } catch (Exception x) {
+            fail(x.getMessage());
+        }
+    }
+
+    /**
+     * Tests evaluation with invalid SCXML data model expressions.
+     *
+     */
+    public void testInvalidDataModelExpressions() {
+        assertNull(context.get("forestx"));
+
+        try {
+            evaluator.eval(context,"Data(forestx,'tree/branch/twig')");
+            fail          ("Evaluated invalid Data() expression: " + "Data(forestx,'tree/branch/twig')");
+
+        } catch (SCXMLExpressionException x) {
+        }
+    }
+
+    /**
+     * Tests evaluation of SCXML data model locations.
+     *
+     */
+    public void testDataModelLocations() {
+            assertNotNull(context.get("forest"));
+
+            try {
+                XPath  xpath = XPathFactory.newInstance().newXPath();
+                Node   node  = (Node)   context.get("forest");
+                Node   twig  = (Node)   xpath.evaluate("tree/branch/twig",        node,XPathConstants.NODE);
+
+                assertTrue  ("Invalid result: " + "Data(forest,'tree/branch/twig')",
+                              evaluator.evalLocation(context,"Data(forest,'tree/branch/twig')") instanceof Element);
+
+                assertSame ("Incorrect node returned: " + "Data(forest,'tree/branch/twig')",
+                             twig,
+                             evaluator.evalLocation(context,"Data(forest,'tree/branch/twig')"));
+
+            } catch (Exception x) {
+                fail(x.getMessage());
+            }
+    }
+
+    /**
+     * Tests evaluation of invalid SCXML data model locations.
+     *
+     */
+    public void testInvalidDataModelLocations() {
+            assertNotNull(context.get("forest"));
+
+            try {
+                assertNull("Invalid result: " + "Data(forest,'tree/branch/twigx')",
+                           evaluator.evalLocation(context,"Data(forest,'tree/branch/twigx')"));
+
+            } catch (Exception x) {
+                fail(x.getMessage());
+            }
+    }
+
+    /**
+     * Tests evaluation of Javascript functions with variables from SCXML context.
+     *
+     */
+    public void testScriptFunctions() {
+            context.set("FIVE",5);
+
+        try {
+            assertEquals(5,context.get("FIVE"));
+            assertEquals("Invalid function result",120.0,evaluator.eval(context,FUNCTION));
+
+        } catch (Exception x) {
+            fail(x.getMessage());
+        }
+    }
+
+
+    // INNER CLASSES
+
+    private static class TestItem {
+        private String expression;
+        private Object result;
+
+        private TestItem(String expression,Object result) {
+            this.expression = expression;
+            this.result     = result;
+        }
+    }
+
+}
+

Propchange: commons/proper/scxml/branches/J5/src/test/java/org/apache/commons/scxml/env/javascript/JSEvaluatorTest.java
------------------------------------------------------------------------------
    svn:eol-style = native

Propchange: commons/proper/scxml/branches/J5/src/test/java/org/apache/commons/scxml/env/javascript/JSEvaluatorTest.java
------------------------------------------------------------------------------
    svn:keywords = Date Author Id Revision HeadURL

Added: commons/proper/scxml/branches/J5/src/test/java/org/apache/commons/scxml/env/javascript/JSExampleTest.java
URL: http://svn.apache.org/viewvc/commons/proper/scxml/branches/J5/src/test/java/org/apache/commons/scxml/env/javascript/JSExampleTest.java?rev=634858&view=auto
==============================================================================
--- commons/proper/scxml/branches/J5/src/test/java/org/apache/commons/scxml/env/javascript/JSExampleTest.java (added)
+++ commons/proper/scxml/branches/J5/src/test/java/org/apache/commons/scxml/env/javascript/JSExampleTest.java Fri Mar  7 15:18:48 2008
@@ -0,0 +1,90 @@
+/*
+ * 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.scxml.env.javascript;
+
+import java.net.URL;
+import java.util.Set;
+
+import junit.framework.Test;
+import junit.framework.TestCase;
+import junit.framework.TestSuite;
+
+import org.apache.commons.scxml.Context;
+import org.apache.commons.scxml.Evaluator;
+import org.apache.commons.scxml.SCXMLExecutor;
+import org.apache.commons.scxml.SCXMLTestHelper;
+import org.apache.commons.scxml.model.SCXML;
+import org.apache.commons.scxml.model.State;
+
+/**
+ * SCXML application for the example JavaScript scripts.
+ *
+ */
+public class JSExampleTest extends TestCase {
+
+    public JSExampleTest(String name) {
+        super(name);
+    }
+
+    public static Test suite() {
+        TestSuite suite = new TestSuite(JSExampleTest.class);
+        suite.setName("SCXML JavaScript Environment Example Tests");
+        return suite;
+    }
+
+    // Test data
+    private URL example01;
+    private SCXMLExecutor exec;
+
+    /**
+     * Set up instance variables required by this test case.
+     */
+    public void setUp() {
+        example01 = this.getClass().getClassLoader().
+            getResource("org/apache/commons/scxml/env/javascript/example-01.xml");
+    }
+
+    /**
+     * Tear down instance variables required by this test case.
+     */
+    public void tearDown() {
+        example01 = null;
+    }
+
+    // TEST METHODS
+
+    public void testExample01Sample() {
+        
+		SCXML scxml = SCXMLTestHelper.parse(example01);
+		Evaluator evaluator = new JSEvaluator();
+        Context context = new JSContext();
+		exec = SCXMLTestHelper.getExecutor(scxml, context, evaluator);
+
+        assertNotNull(exec);
+        try {
+            Set currentStates = exec.getCurrentStatus().getStates();
+            assertEquals(1, currentStates.size());
+            assertEquals("end", ((State)currentStates.iterator().
+                next()).getId());
+        } catch (Exception e) {
+            fail(e.getMessage());
+        }
+   }
+
+}
+

Propchange: commons/proper/scxml/branches/J5/src/test/java/org/apache/commons/scxml/env/javascript/JSExampleTest.java
------------------------------------------------------------------------------
    svn:eol-style = native

Propchange: commons/proper/scxml/branches/J5/src/test/java/org/apache/commons/scxml/env/javascript/JSExampleTest.java
------------------------------------------------------------------------------
    svn:keywords = Date Author Id Revision HeadURL