You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@commons.apache.org by wo...@apache.org on 2014/01/04 01:45:45 UTC

svn commit: r1555303 - in /commons/proper/scxml/trunk: ./ src/main/java/org/apache/commons/scxml2/env/groovy/ src/main/java/org/apache/commons/scxml2/env/jexl/ src/test/java/org/apache/commons/scxml2/env/groovy/

Author: woonsan
Date: Sat Jan  4 00:45:45 2014
New Revision: 1555303

URL: http://svn.apache.org/r1555303
Log:
SCXML-186: adding an optional groovy evaluator support
- evaluator operations
- effective context of the chaining of contexts
- SCXML built-in functions support by using  closures

Added:
    commons/proper/scxml/trunk/src/main/java/org/apache/commons/scxml2/env/groovy/
    commons/proper/scxml/trunk/src/main/java/org/apache/commons/scxml2/env/groovy/GroovyBinding.java
    commons/proper/scxml/trunk/src/main/java/org/apache/commons/scxml2/env/groovy/GroovyBuiltin.java
    commons/proper/scxml/trunk/src/main/java/org/apache/commons/scxml2/env/groovy/GroovyContext.java
    commons/proper/scxml/trunk/src/main/java/org/apache/commons/scxml2/env/groovy/GroovyEvaluator.java
    commons/proper/scxml/trunk/src/main/java/org/apache/commons/scxml2/env/groovy/package.html
    commons/proper/scxml/trunk/src/test/java/org/apache/commons/scxml2/env/groovy/
    commons/proper/scxml/trunk/src/test/java/org/apache/commons/scxml2/env/groovy/GroovyEvaluatorTest.java
Modified:
    commons/proper/scxml/trunk/pom.xml
    commons/proper/scxml/trunk/src/main/java/org/apache/commons/scxml2/env/jexl/JexlEvaluator.java

Modified: commons/proper/scxml/trunk/pom.xml
URL: http://svn.apache.org/viewvc/commons/proper/scxml/trunk/pom.xml?rev=1555303&r1=1555302&r2=1555303&view=diff
==============================================================================
--- commons/proper/scxml/trunk/pom.xml (original)
+++ commons/proper/scxml/trunk/pom.xml Sat Jan  4 00:45:45 2014
@@ -168,6 +168,12 @@
       <optional>true</optional>
     </dependency>
     <dependency>
+      <groupId>org.codehaus.groovy</groupId>
+      <artifactId>groovy</artifactId>
+      <version>2.2.1</version>
+      <optional>true</optional>
+    </dependency>
+    <dependency>
       <groupId>org.apache.xmlbeans</groupId>
       <artifactId>xmlbeans</artifactId>
       <version>2.3.0</version>

Added: commons/proper/scxml/trunk/src/main/java/org/apache/commons/scxml2/env/groovy/GroovyBinding.java
URL: http://svn.apache.org/viewvc/commons/proper/scxml/trunk/src/main/java/org/apache/commons/scxml2/env/groovy/GroovyBinding.java?rev=1555303&view=auto
==============================================================================
--- commons/proper/scxml/trunk/src/main/java/org/apache/commons/scxml2/env/groovy/GroovyBinding.java (added)
+++ commons/proper/scxml/trunk/src/main/java/org/apache/commons/scxml2/env/groovy/GroovyBinding.java Sat Jan  4 00:45:45 2014
@@ -0,0 +1,103 @@
+/*
+ * 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.groovy;
+
+import groovy.lang.Binding;
+
+import java.util.LinkedHashMap;
+import java.util.Map;
+
+import org.apache.commons.scxml2.Context;
+
+/**
+ * Wrapper class for the Groovy Binding class that extends the
+ * wrapped Binding to search the SCXML context for variables and predefined
+ * functions that do not exist in the wrapped Binding.
+ */
+public class GroovyBinding extends Binding {
+
+    private Context context;
+    private Binding binding;
+
+    /**
+     * Initialises the internal Bindings delegate and SCXML context.
+     * @param context  SCXML Context to use for script variables.
+     * @param binding GroovyShell bindings for variables.
+     * @throws IllegalArgumentException Thrown if either <code>context</code>
+     *         or <code>binding</code> is <code>null</code>.
+     */
+    public GroovyBinding(Context context, Binding binding) {
+        if (context == null) {
+            throw new IllegalArgumentException("Invalid SCXML context");
+        }
+
+        if (binding == null) {
+            throw new IllegalArgumentException("Invalid GroovyShell Binding");
+        }
+
+        this.context = context;
+        this.binding = binding;
+    }
+
+    @Override
+    public Object getVariable(String name) {
+        if (context.has(name)) {
+            return context.get(name);
+        }
+
+        return binding.getVariable(name);
+    }
+
+    @Override
+    public void setVariable(String name, Object value) {
+        if (context.has(name)) {
+            context.set(name, value);
+        } else if (binding.hasVariable(name)) {
+            binding.setVariable(name, value);
+        } else {
+            context.setLocal(name, value);
+        }
+    }
+
+    @Override
+    public boolean hasVariable(String name) {
+        if (context.has(name)) {
+            return true;
+        }
+
+        return binding.hasVariable(name);
+    }
+
+    @SuppressWarnings({ "unchecked", "rawtypes" })
+    @Override
+    public Map getVariables() {
+        Map<String, Object> variables = new LinkedHashMap<String, Object>(binding.getVariables());
+        variables.putAll(context.getVars());
+        return variables;
+    }
+
+    @Override
+    public Object getProperty(String property) {
+        return binding.getProperty(property);
+    }
+
+    @Override
+    public void setProperty(String property, Object newValue) {
+        binding.setProperty(property, newValue);
+    }
+
+}

Added: commons/proper/scxml/trunk/src/main/java/org/apache/commons/scxml2/env/groovy/GroovyBuiltin.java
URL: http://svn.apache.org/viewvc/commons/proper/scxml/trunk/src/main/java/org/apache/commons/scxml2/env/groovy/GroovyBuiltin.java?rev=1555303&view=auto
==============================================================================
--- commons/proper/scxml/trunk/src/main/java/org/apache/commons/scxml2/env/groovy/GroovyBuiltin.java (added)
+++ commons/proper/scxml/trunk/src/main/java/org/apache/commons/scxml2/env/groovy/GroovyBuiltin.java Sat Jan  4 00:45:45 2014
@@ -0,0 +1,83 @@
+/*
+ * 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.groovy;
+
+import java.util.Map;
+import java.util.Set;
+
+import org.apache.commons.scxml2.Builtin;
+import org.apache.commons.scxml2.model.TransitionTarget;
+
+/**
+ * Global Groovy namespace functor, implements Data() and In() operators.
+ * Cooperates with GroovyContext.
+ */
+public final class GroovyBuiltin {
+    /**
+     * The context currently in use for evaluation.
+     */
+    private final GroovyContext context;
+
+    /**
+     * Creates a new instance, wraps the context.
+     * @param ctxt the context in use
+     */
+    public GroovyBuiltin(final GroovyContext ctxt) {
+        context = ctxt;
+    }
+
+    /**
+     * Gets the ALL_NAMESPACES map from context.
+     * @return the ALL_NAMESPACES map
+     */
+    private Map<String, String> getNamespaces() {
+        return (Map<String, String>) context.get("_ALL_NAMESPACES");
+    }
+
+    /**
+     * Gets the ALL_STATES set from context.
+     * @return the ALL_STATES set
+     */
+    private Set<TransitionTarget> getAllStates() {
+        return (Set<TransitionTarget>) context.get("_ALL_STATES");
+    }
+
+    /**
+     * Implements the Data() predicate for SCXML documents ( see Builtin#data ).
+     * @param data the context node
+     * @param path the XPath expression
+     * @return the first node matching the path
+     */
+    public Object Data(final Object data, final String path) {
+        // first call maps delegates to dataNode(), subsequent ones to data()
+        if (context.isEvaluatingLocation()) {
+            context.setEvaluatingLocation(false);
+            return Builtin.dataNode(getNamespaces(), data, path);
+        } else {
+            return Builtin.data(getNamespaces(), data, path);
+        }
+    }
+
+    /**
+     * Implements the In() predicate for SCXML documents ( see Builtin#isMember )
+     * @param state The State ID to compare with
+     * @return Whether this State belongs to this Set
+     */
+    public boolean In(final String state) {
+        return Builtin.isMember(getAllStates(), state);
+    }
+}

Added: commons/proper/scxml/trunk/src/main/java/org/apache/commons/scxml2/env/groovy/GroovyContext.java
URL: http://svn.apache.org/viewvc/commons/proper/scxml/trunk/src/main/java/org/apache/commons/scxml2/env/groovy/GroovyContext.java?rev=1555303&view=auto
==============================================================================
--- commons/proper/scxml/trunk/src/main/java/org/apache/commons/scxml2/env/groovy/GroovyContext.java (added)
+++ commons/proper/scxml/trunk/src/main/java/org/apache/commons/scxml2/env/groovy/GroovyContext.java Sat Jan  4 00:45:45 2014
@@ -0,0 +1,78 @@
+/*
+ * 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.groovy;
+
+import java.util.Map;
+
+import org.apache.commons.scxml2.Context;
+import org.apache.commons.scxml2.env.SimpleContext;
+
+/**
+ * Groovy Context implementation for Commons SCXML.
+ */
+public class GroovyContext extends SimpleContext {
+
+    private static final long serialVersionUID = 1L;
+
+    /**
+     * Internal flag to indicate whether it is to evaluate a location
+     * that returns a Node within an XML data tree.
+     */
+    private boolean evaluatingLocation = false;
+
+    /**
+     * Constructor.
+     */
+    public GroovyContext() {
+        super();
+    }
+
+    /**
+     * Constructor with initial vars.
+     *
+     * @param initialVars The initial set of variables.
+     */
+    public GroovyContext(final Map<String, Object> initialVars) {
+        super(initialVars);
+    }
+
+    /**
+     * Constructor with parent context.
+     *
+     * @param parent The parent context.
+     */
+    public GroovyContext(final Context parent) {
+        super(parent);
+    }
+
+    /**
+     * Returns the internal flag to indicate whether it is to evaluate a location
+     * that returns a Node within an XML data tree.
+     */
+    public boolean isEvaluatingLocation() {
+        return evaluatingLocation;
+    }
+
+    /**
+     * Sets the internal flag to indicate whether it is to evaluate a location
+     * that returns a Node within an XML data tree.
+     */
+    public void setEvaluatingLocation(boolean evaluatingLocation) {
+        this.evaluatingLocation = evaluatingLocation;
+    }
+
+}

Added: commons/proper/scxml/trunk/src/main/java/org/apache/commons/scxml2/env/groovy/GroovyEvaluator.java
URL: http://svn.apache.org/viewvc/commons/proper/scxml/trunk/src/main/java/org/apache/commons/scxml2/env/groovy/GroovyEvaluator.java?rev=1555303&view=auto
==============================================================================
--- commons/proper/scxml/trunk/src/main/java/org/apache/commons/scxml2/env/groovy/GroovyEvaluator.java (added)
+++ commons/proper/scxml/trunk/src/main/java/org/apache/commons/scxml2/env/groovy/GroovyEvaluator.java Sat Jan  4 00:45:45 2014
@@ -0,0 +1,265 @@
+/*
+ * 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.groovy;
+
+import groovy.lang.Binding;
+import groovy.lang.GroovyShell;
+
+import java.io.Serializable;
+import java.util.AbstractMap;
+import java.util.HashSet;
+import java.util.Map;
+import java.util.Set;
+
+import org.apache.commons.scxml2.Context;
+import org.apache.commons.scxml2.Evaluator;
+import org.apache.commons.scxml2.SCXMLExpressionException;
+import org.codehaus.groovy.runtime.MethodClosure;
+import org.w3c.dom.Node;
+
+/**
+ * Evaluator implementation enabling use of Groovy expressions in
+ * SCXML documents.
+ * <P>
+ * This implementation itself is thread-safe, so you can keep singleton for efficiency.
+ * </P>
+ */
+public class GroovyEvaluator implements Evaluator, Serializable {
+
+    /** Serial version UID. */
+    private static final long serialVersionUID = 1L;
+
+    /** Error message if evaluation context is not a GroovyContext. */
+    private static final String ERR_CTX_TYPE = "Error evaluating Groovy "
+            + "expression, Context must be a org.apache.commons.scxml2.env.groovy.GroovyContext";
+
+    /** Constructor. */
+    public GroovyEvaluator() {
+        super();
+    }
+
+    /**
+     * Evaluate an expression.
+     *
+     * @param ctx variable context
+     * @param expr expression
+     * @return a result of the evaluation
+     * @throws SCXMLExpressionException For a malformed expression
+     * @see Evaluator#eval(Context, String)
+     */
+    public Object eval(final Context ctx, final String expr) throws SCXMLExpressionException {
+        if (expr == null) {
+            return null;
+        }
+
+        GroovyContext groovyCtx = null;
+
+        if (ctx instanceof GroovyContext) {
+            groovyCtx = (GroovyContext) ctx;
+        } else {
+            throw new SCXMLExpressionException(ERR_CTX_TYPE);
+        }
+
+        try {
+            final GroovyContext effective = getEffectiveContext(groovyCtx);
+            GroovyShell shell = createGroovyShell(effective);
+            return shell.evaluate(expr);
+        } catch (Exception e) {
+            throw new SCXMLExpressionException("eval('" + expr + "'):" + e.getMessage(), e);
+        }
+    }
+
+    /**
+     * @see Evaluator#evalCond(Context, String)
+     */
+    public Boolean evalCond(final Context ctx, final String expr) throws SCXMLExpressionException {
+        if (expr == null) {
+            return null;
+        }
+
+        GroovyContext groovyCtx = null;
+
+        if (ctx instanceof GroovyContext) {
+            groovyCtx = (GroovyContext) ctx;
+        } else {
+            throw new SCXMLExpressionException(ERR_CTX_TYPE);
+        }
+
+        try {
+            final GroovyContext effective = getEffectiveContext(groovyCtx);
+            GroovyShell shell = createGroovyShell(effective);
+            return (Boolean) shell.evaluate(expr);
+        } catch (Exception e) {
+            throw new SCXMLExpressionException("evalCond('" + expr + "'):" + e.getMessage(), e);
+        }
+    }
+
+    /**
+     * @see Evaluator#evalLocation(Context, String)
+     */
+    public Node evalLocation(final Context ctx, final String expr) throws SCXMLExpressionException {
+        if (expr == null) {
+            return null;
+        }
+
+        GroovyContext groovyCtx = null;
+
+        if (ctx instanceof GroovyContext) {
+            groovyCtx = (GroovyContext) ctx;
+        } else {
+            throw new SCXMLExpressionException(ERR_CTX_TYPE);
+        }
+
+        try {
+            final GroovyContext effective = getEffectiveContext(groovyCtx);
+            effective.setEvaluatingLocation(true);
+            GroovyShell shell = createGroovyShell(effective);
+            return (Node) shell.evaluate(expr);
+        } catch (Exception e) {
+            throw new SCXMLExpressionException("evalLocation('" + expr + "'):" + e.getMessage(), e);
+        }
+    }
+
+    /**
+     * @see Evaluator#evalScript(Context, String)
+     */
+    public Object evalScript(final Context ctx, final String script) throws SCXMLExpressionException {
+        if (script == null) {
+            return null;
+        }
+
+        GroovyContext groovyCtx = null;
+
+        if (ctx instanceof GroovyContext) {
+            groovyCtx = (GroovyContext) ctx;
+        } else {
+            throw new SCXMLExpressionException(ERR_CTX_TYPE);
+        }
+
+        try {
+            final GroovyContext effective = getEffectiveContext(groovyCtx);
+            effective.setEvaluatingLocation(true);
+            GroovyShell shell = createGroovyShell(effective);
+            return shell.evaluate(script);
+        } catch (Exception e) {
+            throw new SCXMLExpressionException("evalScript('" + script + "'):" + e.getMessage(), e);
+        }
+    }
+
+    /**
+     * Create a new child context.
+     *
+     * @param parent parent context
+     * @return new child context
+     * @see Evaluator#newContext(Context)
+     */
+    public Context newContext(final Context parent) {
+        return new GroovyContext(parent);
+    }
+
+    /**
+     * Create a GroovyShell instance.
+     * @param context
+     * @return
+     */
+    protected GroovyShell createGroovyShell(GroovyContext groovyContext) {
+        Binding binding = new Binding();
+        GroovyBuiltin builtin = new GroovyBuiltin(groovyContext);
+        MethodClosure dataClosure = new MethodClosure(builtin, "Data");
+        MethodClosure inClosure = new MethodClosure(builtin, "In");
+        binding.setProperty("Data", dataClosure);
+        binding.setProperty("In", inClosure);
+        GroovyBinding groovyBinding = new GroovyBinding(groovyContext, binding);
+        GroovyShell shell = new GroovyShell(groovyBinding);
+        return shell;
+    }
+
+    /**
+     * Create a new context which is the summation of contexts from the
+     * current state to document root, child has priority over parent
+     * in scoping rules.
+     *
+     * @param nodeCtx The GroovyContext for this state.
+     * @return The effective GroovyContext for the path leading up to
+     *         document root.
+     */
+    private GroovyContext getEffectiveContext(final GroovyContext nodeCtx) {
+        return new GroovyContext(new EffectiveContextMap(nodeCtx));
+    }
+
+    /**
+     * The map that will back the effective context for the
+     * {@link GroovyEvaluator}. The effective context enables the chaining of
+     * {@link Context}s all the way from the current state node to the root.
+     *
+     */
+    private static final class EffectiveContextMap extends AbstractMap<String, Object> {
+
+        /** The {@link Context} for the current state. */
+        private final Context leaf;
+
+        /** Constructor. */
+        public EffectiveContextMap(final GroovyContext ctx) {
+            super();
+            this.leaf = ctx;
+        }
+
+        /**
+         * {@inheritDoc}
+         */
+        @Override
+        public Set<Map.Entry<String, Object>> entrySet() {
+            Set<Map.Entry<String, Object>> entrySet = new HashSet<Map.Entry<String, Object>>();
+            Context current = leaf;
+            while (current != null) {
+                entrySet.addAll(current.getVars().entrySet());
+                current = current.getParent();
+            }
+            return entrySet;
+        }
+
+        /**
+         * {@inheritDoc}
+         */
+        @Override
+        public Object put(final String key, final Object value) {
+            Object old = leaf.get(key);
+            if (leaf.has(key)) {
+                leaf.set(key, value);
+            } else {
+                leaf.setLocal(key, value);
+            }
+            return old;
+        }
+
+        /**
+         * {@inheritDoc}
+         */
+        @Override
+        public Object get(final Object key) {
+            Context current = leaf;
+            while (current != null) {
+                if (current.getVars().containsKey(key)) {
+                    return current.getVars().get(key);
+                }
+                current = current.getParent();
+            }
+            return null;
+        }
+    }
+
+}
\ No newline at end of file

Added: commons/proper/scxml/trunk/src/main/java/org/apache/commons/scxml2/env/groovy/package.html
URL: http://svn.apache.org/viewvc/commons/proper/scxml/trunk/src/main/java/org/apache/commons/scxml2/env/groovy/package.html?rev=1555303&view=auto
==============================================================================
--- commons/proper/scxml/trunk/src/main/java/org/apache/commons/scxml2/env/groovy/package.html (added)
+++ commons/proper/scxml/trunk/src/main/java/org/apache/commons/scxml2/env/groovy/package.html Sat Jan  4 00:45:45 2014
@@ -0,0 +1,26 @@
+<html>
+<!-- 
+ * 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.
+-->
+<head>
+</head>
+<body>
+
+  <p>A collection of classes that allow Groovy to be used in expressions
+     within SCXML documents.</p>
+
+</body>
+</html>

Modified: commons/proper/scxml/trunk/src/main/java/org/apache/commons/scxml2/env/jexl/JexlEvaluator.java
URL: http://svn.apache.org/viewvc/commons/proper/scxml/trunk/src/main/java/org/apache/commons/scxml2/env/jexl/JexlEvaluator.java?rev=1555303&r1=1555302&r2=1555303&view=diff
==============================================================================
--- commons/proper/scxml/trunk/src/main/java/org/apache/commons/scxml2/env/jexl/JexlEvaluator.java (original)
+++ commons/proper/scxml/trunk/src/main/java/org/apache/commons/scxml2/env/jexl/JexlEvaluator.java Sat Jan  4 00:45:45 2014
@@ -46,7 +46,7 @@ public class JexlEvaluator implements Ev
 
     /** Error message if evaluation context is not a JexlContext. */
     private static final String ERR_CTX_TYPE = "Error evaluating JEXL "
-        + "expression, Context must be a org.apache.commons.jexl2.JexlContext";
+        + "expression, Context must be a org.apache.commons.scxml2.env.jexl.JexlContext";
 
     /** The internal JexlEngine instance to use. */
     private transient volatile JexlEngine jexlEngine;

Added: commons/proper/scxml/trunk/src/test/java/org/apache/commons/scxml2/env/groovy/GroovyEvaluatorTest.java
URL: http://svn.apache.org/viewvc/commons/proper/scxml/trunk/src/test/java/org/apache/commons/scxml2/env/groovy/GroovyEvaluatorTest.java?rev=1555303&view=auto
==============================================================================
--- commons/proper/scxml/trunk/src/test/java/org/apache/commons/scxml2/env/groovy/GroovyEvaluatorTest.java (added)
+++ commons/proper/scxml/trunk/src/test/java/org/apache/commons/scxml2/env/groovy/GroovyEvaluatorTest.java Sat Jan  4 00:45:45 2014
@@ -0,0 +1,95 @@
+/*
+ * 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.groovy;
+
+import java.util.HashSet;
+import java.util.Set;
+
+import org.apache.commons.scxml2.Context;
+import org.apache.commons.scxml2.Evaluator;
+import org.apache.commons.scxml2.SCXMLExpressionException;
+import org.apache.commons.scxml2.model.State;
+import org.apache.commons.scxml2.model.TransitionTarget;
+import org.junit.Assert;
+import org.junit.Before;
+import org.junit.Test;
+
+public class GroovyEvaluatorTest {
+
+    private String BAD_EXPRESSION = ">";
+    private Context ctx;
+
+    @Before
+    public void before() {
+        ctx = new GroovyContext();
+    }
+
+    @Test
+    public void testEval() throws SCXMLExpressionException {
+        Evaluator eval = new GroovyEvaluator();
+        Assert.assertEquals(new Integer(2), eval.eval(ctx, "1 + 1"));
+    }
+
+    @Test
+    public void testPristine() throws SCXMLExpressionException {
+        Evaluator eval = new GroovyEvaluator();
+        Assert.assertTrue(eval.evalCond(ctx, "1 + 1 == 2"));
+    }
+
+    @Test
+    public void testBuiltInFunctions() throws SCXMLExpressionException {
+        Evaluator eval = new GroovyEvaluator();
+
+        Set<TransitionTarget> allStates = new HashSet<TransitionTarget>();
+        State state1 = new State();
+        state1.setId("state1");
+        allStates.add(state1);
+
+        ctx.setLocal("_ALL_STATES", allStates);
+
+        Assert.assertTrue(eval.evalCond(ctx, "In('state1')"));
+    }
+
+    @Test
+    public void testScript() throws SCXMLExpressionException {
+        Evaluator eval = new GroovyEvaluator();
+        ctx.set("x", 3);
+        ctx.set("y", 0);
+        String script = 
+            "if ((x * 2) == 5) {" +
+                "y = 1;\n" +
+            "} else {\n" +
+                "y = 2;\n" +
+            "}";
+        Assert.assertEquals(2, eval.evalScript(ctx, script));
+        Assert.assertEquals(2, ctx.get("y"));
+    }
+
+    @Test
+    public void testErrorMessage() {
+        Evaluator eval = new GroovyEvaluator();
+        Assert.assertNotNull(eval);
+        try {
+            eval.eval(ctx, BAD_EXPRESSION);
+            Assert.fail("GroovyEvaluator should throw SCXMLExpressionException");
+        } catch (SCXMLExpressionException e) {
+            Assert.assertTrue("GroovyEvaluator: Incorrect error message",
+                e.getMessage().startsWith("eval('" + BAD_EXPRESSION + "'):"));
+        }
+    }
+
+}