commons-commits mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From a..@apache.org
Subject svn commit: r1559139 - in /commons/proper/scxml/trunk/src/main/java/org/apache/commons/scxml2/env/groovy: GroovyBinding.java GroovyBuiltin.java GroovyContext.java GroovyContextBinding.java GroovyEvaluator.java
Date Fri, 17 Jan 2014 15:18:36 GMT
Author: ate
Date: Fri Jan 17 15:18:35 2014
New Revision: 1559139

URL: http://svn.apache.org/r1559139
Log:
SCXML-186: Groovy Expression evaluator support
- completion of this feature: 
  - enhanced GroovyEvaluator using the GroovyEnhancedScriptCache:
    - adding a convenient ScriptPreProcessor, allowing to use Groovy operator aliases for
XML unfriendly operators like < (alias: lt)
    - optionally using a SCXML initial script as base class for following scripts (allowing
the intial script to be used to add extra functions for example)
  - enhanced GroovyContext with proper de-serialization support using the Groovy class loader
during readObject
    - also explicitly disables (de)serialization of Groovy closure objects (by removing them
from the variables before serialization)
  - a GroovyContextBinding to bridge between SCXML and Groovy contexts
  - the original GroovyBinding no longer is needed and replaced by the GroovySCXMLScript base
class

Added:
    commons/proper/scxml/trunk/src/main/java/org/apache/commons/scxml2/env/groovy/GroovyContextBinding.java
      - copied, changed from r1556820, commons/proper/scxml/trunk/src/main/java/org/apache/commons/scxml2/env/groovy/GroovyBinding.java
Removed:
    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
Modified:
    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

Modified: 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=1559139&r1=1559138&r2=1559139&view=diff
==============================================================================
--- commons/proper/scxml/trunk/src/main/java/org/apache/commons/scxml2/env/groovy/GroovyContext.java
(original)
+++ commons/proper/scxml/trunk/src/main/java/org/apache/commons/scxml2/env/groovy/GroovyContext.java
Fri Jan 17 15:18:35 2014
@@ -16,11 +16,22 @@
  */
 package org.apache.commons.scxml2.env.groovy;
 
+import java.io.ByteArrayInputStream;
+import java.io.ByteArrayOutputStream;
+import java.io.IOException;
+import java.io.ObjectInputStream;
+import java.io.ObjectOutputStream;
+import java.io.ObjectStreamClass;
+import java.util.Iterator;
 import java.util.Map;
 
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
 import org.apache.commons.scxml2.Context;
 import org.apache.commons.scxml2.env.SimpleContext;
 
+import groovy.lang.Closure;
+
 /**
  * Groovy Context implementation for Commons SCXML.
  */
@@ -28,12 +39,26 @@ public class GroovyContext extends Simpl
 
     private static final long serialVersionUID = 1L;
 
+    private static final Log log = LogFactory.getLog(GroovyContext.class);
+
     /**
      * Internal flag to indicate whether it is to evaluate a location
      * that returns a Node within an XML data tree.
      */
     private boolean evaluatingLocation = false;
 
+    private String scriptBaseClass;
+    private GroovyEvaluator evaluator;
+    private GroovyContextBinding binding;
+    private Map<String, Object> vars;
+
+    GroovyContextBinding getBinding() {
+        if (binding == null) {
+            binding = new GroovyContextBinding(this);
+        }
+        return  binding;
+    }
+
     /**
      * Constructor.
      */
@@ -46,8 +71,9 @@ public class GroovyContext extends Simpl
      *
      * @param initialVars The initial set of variables.
      */
-    public GroovyContext(final Map<String, Object> initialVars) {
+    public GroovyContext(final Map<String, Object> initialVars, GroovyEvaluator evaluator)
{
         super(initialVars);
+        this.evaluator = evaluator;
     }
 
     /**
@@ -55,8 +81,17 @@ public class GroovyContext extends Simpl
      *
      * @param parent The parent context.
      */
-    public GroovyContext(final Context parent) {
+    public GroovyContext(final Context parent, GroovyEvaluator evaluator) {
         super(parent);
+        this.evaluator = evaluator;
+    }
+
+    protected GroovyEvaluator getGroovyEvaluator() {
+        return evaluator;
+    }
+
+    protected void setGroovyEvaluator(GroovyEvaluator evaluator) {
+        this.evaluator = evaluator;
     }
 
     /**
@@ -75,4 +110,69 @@ public class GroovyContext extends Simpl
         this.evaluatingLocation = evaluatingLocation;
     }
 
+    @Override
+    public Map<String, Object> getVars() {
+        return vars;
+    }
+
+    @Override
+    protected void setVars(final Map<String, Object> vars) {
+        this.vars = vars;
+    }
+
+    protected void setScriptBaseClass(String scriptBaseClass) {
+        this.scriptBaseClass = scriptBaseClass;
+    }
+
+    protected String getScriptBaseClass() {
+        if (scriptBaseClass != null) {
+            return scriptBaseClass;
+        }
+        if (getParent() != null) {
+            return ((GroovyContext)getParent()).getScriptBaseClass();
+        }
+        return null;
+    }
+
+    private void writeObject(ObjectOutputStream out) throws IOException {
+        boolean closureErased = false;
+        if (vars != null) {
+            Iterator<Map.Entry<String, Object>> iterator = getVars().entrySet().iterator();
+            while (iterator.hasNext()) {
+                Map.Entry<String, Object> entry = iterator.next();
+                if (entry.getValue() != null && entry.getValue() instanceof Closure)
{
+                    iterator.remove();
+                    closureErased = true;
+                }
+            }
+            if (closureErased) {
+                log.warn("Encountered and removed Groovy Closure(s) in the GroovyContext
during serialization: these are not supported for (de)serialization");
+            }
+        }
+        out.writeObject(this.scriptBaseClass);
+        out.writeObject(this.evaluator);
+        out.writeObject(this.binding);
+        ByteArrayOutputStream bout = new ByteArrayOutputStream();
+        new ObjectOutputStream(bout).writeObject(this.vars);
+        out.writeObject(bout.toByteArray());
+    }
+
+    @SuppressWarnings("unchecked")
+    private void readObject(ObjectInputStream in) throws IOException,ClassNotFoundException
{
+        this.scriptBaseClass = (String)in.readObject();
+        this.evaluator = (GroovyEvaluator)in.readObject();
+        this.binding = (GroovyContextBinding)in.readObject();
+        byte[] bytes  = (byte[])in.readObject();
+        if (evaluator != null) {
+            this.vars = (Map<String, Object>)
+                    new ObjectInputStream(new ByteArrayInputStream(bytes)) {
+                        protected Class resolveClass(ObjectStreamClass osc) throws IOException,
ClassNotFoundException {
+                            return Class.forName(osc.getName(), true, evaluator.getGroovyClassLoader());
+                        }
+                    }.readObject();
+        }
+        else {
+            this.vars = (Map<String, Object>)new ObjectInputStream(new ByteArrayInputStream(bytes)).readObject();
+        }
+    }
 }

Copied: commons/proper/scxml/trunk/src/main/java/org/apache/commons/scxml2/env/groovy/GroovyContextBinding.java
(from r1556820, 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/GroovyContextBinding.java?p2=commons/proper/scxml/trunk/src/main/java/org/apache/commons/scxml2/env/groovy/GroovyContextBinding.java&p1=commons/proper/scxml/trunk/src/main/java/org/apache/commons/scxml2/env/groovy/GroovyBinding.java&r1=1556820&r2=1559139&rev=1559139&view=diff
==============================================================================
--- commons/proper/scxml/trunk/src/main/java/org/apache/commons/scxml2/env/groovy/GroovyBinding.java
(original)
+++ commons/proper/scxml/trunk/src/main/java/org/apache/commons/scxml2/env/groovy/GroovyContextBinding.java
Fri Jan 17 15:18:35 2014
@@ -17,57 +17,45 @@
 package org.apache.commons.scxml2.env.groovy;
 
 import groovy.lang.Binding;
+import groovy.lang.MissingPropertyException;
 
+import java.io.Serializable;
 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.
+ * Delegating Groovy Binding class which delegates all variables access to its GroovyContext
  */
-public class GroovyBinding extends Binding {
+public class GroovyContextBinding extends Binding implements Serializable {
 
-    private Context context;
-    private Binding binding;
+    private static final long serialVersionUID = 1L;
 
-    /**
-     * 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");
-        }
+    private GroovyContext context;
 
-        if (binding == null) {
-            throw new IllegalArgumentException("Invalid GroovyShell Binding");
+    public GroovyContextBinding(GroovyContext context) {
+        if (context == null) {
+            throw new IllegalArgumentException("Parameter context may not be null");
         }
-
         this.context = context;
-        this.binding = binding;
+    }
+
+    GroovyContext getContext() {
+        return context;
     }
 
     @Override
     public Object getVariable(String name) {
-        if (context.has(name)) {
-            return context.get(name);
+        Object result = context.get(name);
+        if (result == null && !context.has(name)) {
+            throw new MissingPropertyException(name, this.getClass());
         }
-
-        return binding.getVariable(name);
+        return result;
     }
 
     @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);
         }
@@ -75,29 +63,21 @@ public class GroovyBinding extends Bindi
 
     @Override
     public boolean hasVariable(String name) {
-        if (context.has(name)) {
-            return true;
-        }
-
-        return binding.hasVariable(name);
+        return context.has(name);
     }
 
-    @SuppressWarnings({ "unchecked", "rawtypes" })
     @Override
-    public Map getVariables() {
-        Map<String, Object> variables = new LinkedHashMap<String, Object>(binding.getVariables());
-        variables.putAll(context.getVars());
-        return variables;
+    public Map<String, Object> getVariables() {
+        return new LinkedHashMap<String, Object>(context.getVars());
     }
 
     @Override
     public Object getProperty(String property) {
-        return binding.getProperty(property);
+        return getVariable(property);
     }
 
     @Override
     public void setProperty(String property, Object newValue) {
-        binding.setProperty(property, newValue);
+        setVariable(property, newValue);
     }
-
 }

Modified: 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=1559139&r1=1559138&r2=1559139&view=diff
==============================================================================
--- commons/proper/scxml/trunk/src/main/java/org/apache/commons/scxml2/env/groovy/GroovyEvaluator.java
(original)
+++ commons/proper/scxml/trunk/src/main/java/org/apache/commons/scxml2/env/groovy/GroovyEvaluator.java
Fri Jan 17 15:18:35 2014
@@ -16,24 +16,23 @@
  */
 package org.apache.commons.scxml2.env.groovy;
 
-import groovy.lang.Binding;
-import groovy.lang.GroovyShell;
+import groovy.lang.Script;
 
 import java.io.Serializable;
-import java.util.AbstractMap;
-import java.util.HashSet;
+import java.util.Collections;
+import java.util.HashMap;
 import java.util.Map;
-import java.util.Set;
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
 
 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.apache.commons.scxml2.env.EffectiveContextMap;
 import org.w3c.dom.Node;
 
 /**
- * Evaluator implementation enabling use of Groovy expressions in
- * SCXML documents.
+ * 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>
@@ -47,11 +46,75 @@ public class GroovyEvaluator implements 
     private static final String ERR_CTX_TYPE = "Error evaluating Groovy "
             + "expression, Context must be a org.apache.commons.scxml2.env.groovy.GroovyContext";
 
-    /** Constructor. */
+    private static final GroovyExtendableScriptCache.ScriptPreProcessor scriptPreProcessor
= new GroovyExtendableScriptCache.ScriptPreProcessor () {
+
+        /**
+         * Pattern for case-sensitive matching of the Groovy operator aliases, delimited
by whitespace
+         */
+        private final Pattern GROOVY_OPERATOR_ALIASES_PATTERN = Pattern.compile("(?<=\\s)(and|or|not|eq|lt|le|ne|gt|ge)(?=\\s)");
+
+        /**
+         * Groovy operator aliases mapped to their underlying Groovy operator
+         */
+        private final Map<String, String> GROOVY_OPERATOR_ALIASES = Collections.unmodifiableMap(new
HashMap<String, String>() {{
+            put("and", "&& "); put("or",  "||"); put("not", " ! ");
+            put("eq",  "==");  put("lt",  "< "); put("le",  "<=");
+            put("ne",  "!=");  put("gt",  "> "); put("ge",  ">=");
+        }});
+
+        @Override
+        public String preProcess(final String script) {
+            if (script == null || script.length() == 0) {
+                return script;
+            }
+            StringBuffer sb = null;
+            Matcher m = GROOVY_OPERATOR_ALIASES_PATTERN.matcher(script);
+            while (m.find()) {
+                if (sb == null) {
+                    sb = new StringBuffer();
+                }
+                m.appendReplacement(sb, GROOVY_OPERATOR_ALIASES.get(m.group()));
+            }
+            if (sb != null) {
+                m.appendTail(sb);
+                return sb.toString();
+            }
+            return script;
+        }
+    };
+
+    private final boolean useInitialScriptAsBaseScript;
+    private final GroovyExtendableScriptCache scriptCache;
+
     public GroovyEvaluator() {
-        super();
+        this(false);
+    }
+
+    public GroovyEvaluator(boolean useInitialScriptAsBaseScript) {
+        this.useInitialScriptAsBaseScript = useInitialScriptAsBaseScript;
+        this.scriptCache = new GroovyExtendableScriptCache();
+        scriptCache.setScriptPreProcessor(scriptPreProcessor);
+        scriptCache.setScriptBaseClass(GroovySCXMLScript.class.getName());
     }
 
+    @SuppressWarnings("unchecked")
+    protected Script getScript(GroovyContext groovyContext, String scriptBaseClassName, String
scriptSource) {
+        Script script = scriptCache.getScript(scriptBaseClassName, scriptSource);
+        script.setBinding(groovyContext.getBinding());
+        return script;
+    }
+
+    @SuppressWarnings("unused")
+    public void clearCache() {
+        scriptCache.clearCache();
+    }
+
+    public GroovyExtendableScriptCache.ScriptPreProcessor getScriptPreProcessor() {
+        return scriptPreProcessor;
+    }
+
+    /* SCXMLEvaluator implementation methods */
+
     /**
      * Evaluate an expression.
      *
@@ -61,23 +124,22 @@ public class GroovyEvaluator implements 
      * @throws SCXMLExpressionException For a malformed expression
      * @see Evaluator#eval(Context, String)
      */
+    @Override
     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 {
+        if (!(ctx instanceof GroovyContext)) {
             throw new SCXMLExpressionException(ERR_CTX_TYPE);
         }
 
+        GroovyContext groovyCtx = (GroovyContext) ctx;
+        if (groovyCtx.getGroovyEvaluator() == null) {
+            groovyCtx.setGroovyEvaluator(this);
+        }
         try {
-            final GroovyContext effective = getEffectiveContext(groovyCtx);
-            GroovyShell shell = createGroovyShell(effective);
-            return shell.evaluate(expr);
+            return getScript(getEffectiveContext(groovyCtx), groovyCtx.getScriptBaseClass(),
expr).run();
         } catch (Exception e) {
             throw new SCXMLExpressionException("eval('" + expr + "'):" + e.getMessage(),
e);
         }
@@ -86,23 +148,22 @@ public class GroovyEvaluator implements 
     /**
      * @see Evaluator#evalCond(Context, String)
      */
+    @Override
     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 {
+        if (!(ctx instanceof GroovyContext)) {
             throw new SCXMLExpressionException(ERR_CTX_TYPE);
         }
 
+        GroovyContext groovyCtx = (GroovyContext) ctx;
+        if (groovyCtx.getGroovyEvaluator() == null) {
+            groovyCtx.setGroovyEvaluator(this);
+        }
         try {
-            final GroovyContext effective = getEffectiveContext(groovyCtx);
-            GroovyShell shell = createGroovyShell(effective);
-            return (Boolean) shell.evaluate(expr);
+            return (Boolean)getScript(getEffectiveContext(groovyCtx), groovyCtx.getScriptBaseClass(),
expr).run();
         } catch (Exception e) {
             throw new SCXMLExpressionException("evalCond('" + expr + "'):" + e.getMessage(),
e);
         }
@@ -111,24 +172,24 @@ public class GroovyEvaluator implements 
     /**
      * @see Evaluator#evalLocation(Context, String)
      */
+    @Override
     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 {
+        if (!(ctx instanceof GroovyContext)) {
             throw new SCXMLExpressionException(ERR_CTX_TYPE);
         }
 
+        GroovyContext groovyCtx = (GroovyContext) ctx;
+        if (groovyCtx.getGroovyEvaluator() == null) {
+            groovyCtx.setGroovyEvaluator(this);
+        }
         try {
             final GroovyContext effective = getEffectiveContext(groovyCtx);
             effective.setEvaluatingLocation(true);
-            GroovyShell shell = createGroovyShell(effective);
-            return (Node) shell.evaluate(expr);
+            return (Node)getScript(effective, groovyCtx.getScriptBaseClass(), expr).run();
         } catch (Exception e) {
             throw new SCXMLExpressionException("evalLocation('" + expr + "'):" + e.getMessage(),
e);
         }
@@ -137,29 +198,41 @@ public class GroovyEvaluator implements 
     /**
      * @see Evaluator#evalScript(Context, String)
      */
-    public Object evalScript(final Context ctx, final String script) throws SCXMLExpressionException
{
-        if (script == null) {
+    @Override
+    public Object evalScript(final Context ctx, final String scriptSource) throws SCXMLExpressionException
{
+        if (scriptSource == null) {
             return null;
         }
 
-        GroovyContext groovyCtx = null;
-
-        if (ctx instanceof GroovyContext) {
-            groovyCtx = (GroovyContext) ctx;
-        } else {
+        if (!(ctx instanceof GroovyContext)) {
             throw new SCXMLExpressionException(ERR_CTX_TYPE);
         }
 
+        GroovyContext groovyCtx = (GroovyContext) ctx;
+        if (groovyCtx.getGroovyEvaluator() == null) {
+            groovyCtx.setGroovyEvaluator(this);
+        }
         try {
             final GroovyContext effective = getEffectiveContext(groovyCtx);
             effective.setEvaluatingLocation(true);
-            GroovyShell shell = createGroovyShell(effective);
-            return shell.evaluate(script);
+            boolean isInitialScript =  groovyCtx.getParent() != null &&
+                    groovyCtx.getParent().getParent() == null &&
+                    scriptCache.isEmpty();
+            Script script = getScript(effective, groovyCtx.getScriptBaseClass(), scriptSource);
+            Object result = script.run();
+            if (isInitialScript && useInitialScriptAsBaseScript) {
+                groovyCtx.setScriptBaseClass(script.getClass().getName());
+            }
+            return result;
         } catch (Exception e) {
-            throw new SCXMLExpressionException("evalScript('" + script + "'):" + e.getMessage(),
e);
+            throw new SCXMLExpressionException("evalScript('" + scriptSource + "'):" + e.getMessage(),
e);
         }
     }
 
+    protected ClassLoader getGroovyClassLoader() {
+        return scriptCache.getGroovyClassLoader();
+    }
+
     /**
      * Create a new child context.
      *
@@ -167,25 +240,9 @@ public class GroovyEvaluator implements 
      * @return new child context
      * @see Evaluator#newContext(Context)
      */
+    @Override
     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;
+        return new GroovyContext(parent, this);
     }
 
     /**
@@ -198,68 +255,6 @@ public class GroovyEvaluator implements 
      *         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;
-        }
+        return new GroovyContext(new EffectiveContextMap(nodeCtx), this);
     }
-
 }
\ No newline at end of file



Mime
View raw message