svn commit: r1299040 - in /ofbiz/trunk/framework: base/src/org/ofbiz/base/util/ScriptUtil.java base/src/org/ofbiz/base/util/string/FlexibleStringExpander.java service/src/org/ofbiz/service/engine/ScriptEngine.java

Previous Topic Next Topic
 
classic Classic list List threaded Threaded
1 message Options
Reply | Threaded
Open this post in threaded view
|

svn commit: r1299040 - in /ofbiz/trunk/framework: base/src/org/ofbiz/base/util/ScriptUtil.java base/src/org/ofbiz/base/util/string/FlexibleStringExpander.java service/src/org/ofbiz/service/engine/ScriptEngine.java

adrianc
Author: adrianc
Date: Fri Mar  9 20:41:18 2012
New Revision: 1299040

URL: http://svn.apache.org/viewvc?rev=1299040&view=rev
Log:
More JSR-223 work - added the ability to protect the bindings, plus some minor code formatting changes.

Modified:
    ofbiz/trunk/framework/base/src/org/ofbiz/base/util/ScriptUtil.java
    ofbiz/trunk/framework/base/src/org/ofbiz/base/util/string/FlexibleStringExpander.java
    ofbiz/trunk/framework/service/src/org/ofbiz/service/engine/ScriptEngine.java

Modified: ofbiz/trunk/framework/base/src/org/ofbiz/base/util/ScriptUtil.java
URL: http://svn.apache.org/viewvc/ofbiz/trunk/framework/base/src/org/ofbiz/base/util/ScriptUtil.java?rev=1299040&r1=1299039&r2=1299040&view=diff
==============================================================================
--- ofbiz/trunk/framework/base/src/org/ofbiz/base/util/ScriptUtil.java (original)
+++ ofbiz/trunk/framework/base/src/org/ofbiz/base/util/ScriptUtil.java Fri Mar  9 20:41:18 2012
@@ -23,8 +23,10 @@ import java.io.FileNotFoundException;
 import java.io.FileReader;
 import java.net.MalformedURLException;
 import java.net.URL;
+import java.util.Collection;
 import java.util.List;
 import java.util.Map;
+import java.util.Set;
 
 import javax.script.Bindings;
 import javax.script.Compilable;
@@ -35,6 +37,7 @@ import javax.script.ScriptEngine;
 import javax.script.ScriptEngineFactory;
 import javax.script.ScriptEngineManager;
 import javax.script.ScriptException;
+import javax.script.SimpleBindings;
 import javax.script.SimpleScriptContext;
 
 import org.codehaus.groovy.runtime.InvokerHelper;
@@ -43,6 +46,10 @@ import org.ofbiz.base.util.cache.UtilCac
 
 /**
  * Scripting utility methods. This is a facade class that is used to connect OFBiz to JSR-223 scripting engines.
+ * <p><b>Important:</b> To avoid a lot of <code>Map</code> copying, all methods that accept a context
+ * <code>Map</code> argument will pass that <code>Map</code> directly to the scripting engine. Any variables that
+ * are declared or modified in the script will affect the original <code>Map</code>. Client code that wishes to preserve
+ * the state of the <code>Map</code> argument should pass a copy of the <code>Map</code>.</p>
  *
  */
 public final class ScriptUtil {
@@ -167,11 +174,31 @@ public final class ScriptUtil {
      * @param context
      * @return
      */
-    public static ScriptContext createScriptContext(Map<String, ? extends Object> context) {
+    public static ScriptContext createScriptContext(Map<String, Object> context) {
+        Assert.notNull("context", context);
+        context.put("context", context);
         ScriptContext scriptContext = new SimpleScriptContext();
-        Bindings bindings = scriptContext.getBindings(ScriptContext.ENGINE_SCOPE);
-        bindings.putAll(context);
-        bindings.put("context", context);
+        Bindings bindings = new SimpleBindings(context);
+        scriptContext.setBindings(bindings, ScriptContext.ENGINE_SCOPE);
+        return scriptContext;
+    }
+
+    /**
+     * Returns a <code>ScriptContext</code> that contains the members of <code>context</code>.
+     * <p>If a <code>CompiledScript</code> instance is to be shared by multiple threads, then
+     * each thread must create its own <code>ScriptContext</code> and pass it to the
+     * <code>CompiledScript</code> eval method.</p>
+     *
+     * @param context
+     * @param protectedKeys
+     * @return
+     */
+    public static ScriptContext createScriptContext(Map<String, Object> context, Set<String> protectedKeys) {
+        Assert.notNull("context", context, "protectedKeys", protectedKeys);
+        context.put("context", context);
+        ScriptContext scriptContext = new SimpleScriptContext();
+        Bindings bindings = new ProtectedBindings(context, protectedKeys);
+        scriptContext.setBindings(bindings, ScriptContext.ENGINE_SCOPE);
         return scriptContext;
     }
 
@@ -181,19 +208,19 @@ public final class ScriptUtil {
      * @param language
      * @param script
      * @param scriptClass
-     * @param inputMap
+     * @param context
      * @return The script result.
      * @throws Exception
      */
-    public static Object evaluate(String language, String script, Class<?> scriptClass, Map<String, ? extends Object> inputMap) throws Exception {
-        Assert.notNull("inputMap", inputMap);
+    public static Object evaluate(String language, String script, Class<?> scriptClass, Map<String, Object> context) throws Exception {
+        Assert.notNull("context", context);
         if (scriptClass != null) {
-            return InvokerHelper.createScript(scriptClass, GroovyUtil.getBinding(inputMap)).run();
+            return InvokerHelper.createScript(scriptClass, GroovyUtil.getBinding(context)).run();
         }
         try {
             CompiledScript compiledScript = compileScriptString(language, script);
             if (compiledScript != null) {
-                return executeScript(compiledScript, null, createScriptContext(inputMap), null);
+                return executeScript(compiledScript, null, createScriptContext(context), null);
             }
             ScriptEngineManager manager = new ScriptEngineManager();
             ScriptEngine engine = manager.getEngineByName(language);
@@ -203,7 +230,7 @@ public final class ScriptUtil {
             if (Debug.verboseOn()) {
                 Debug.logVerbose("Begin processing script [" + script + "] using engine " + engine.getClass().getName(), module);
             }
-            ScriptContext scriptContext = createScriptContext(inputMap);
+            ScriptContext scriptContext = createScriptContext(context);
             return engine.eval(script, scriptContext);
         } catch (Exception e) {
             String errMsg = "Error running " + language + " script [" + script + "]: " + e.toString();
@@ -248,7 +275,7 @@ public final class ScriptUtil {
      * @return The script result.
      * @throws IllegalArgumentException
      */
-    public static Object executeScript(String filePath, String functionName, Map<String, ? extends Object> context) {
+    public static Object executeScript(String filePath, String functionName, Map<String, Object> context) {
         return executeScript(filePath, functionName, context, EMPTY_ARGS);
     }
 
@@ -257,6 +284,27 @@ public final class ScriptUtil {
      *
      * @param filePath Script path and file name.
      * @param functionName Optional function or method to invoke.
+     * @param context Script execution context.
+     * @param args Function/method arguments.
+     * @return The script result.
+     * @throws IllegalArgumentException
+     */
+    public static Object executeScript(String filePath, String functionName, Map<String, Object> context, Object[] args) {
+        Assert.notNull("filePath", filePath, "context", context);
+        try {
+            return executeScript(filePath, functionName, createScriptContext(context), args);
+        } catch (Exception e) {
+            String errMsg = "Error running script at location [" + filePath + "]: " + e.toString();
+            Debug.logWarning(e, errMsg, module);
+            throw new IllegalArgumentException(errMsg);
+        }
+    }
+
+    /**
+     * Executes the script at the specified location and returns the result.
+     *
+     * @param filePath Script path and file name.
+     * @param functionName Optional function or method to invoke.
      * @param scriptContext Script execution context.
      * @param args Function/method arguments.
      * @return The script result.
@@ -294,27 +342,6 @@ public final class ScriptUtil {
         return result;
     }
 
-    /**
-     * Executes the script at the specified location and returns the result.
-     *
-     * @param filePath Script path and file name.
-     * @param functionName Optional function or method to invoke.
-     * @param context Script execution context.
-     * @param args Function/method arguments.
-     * @return The script result.
-     * @throws IllegalArgumentException
-     */
-    public static Object executeScript(String filePath, String functionName, Map<String, ? extends Object> context, Object[] args) {
-        Assert.notNull("filePath", filePath, "context", context);
-        try {
-            return executeScript(filePath, functionName, createScriptContext(context), args);
-        } catch (Exception e) {
-            String errMsg = "Error running script at location [" + filePath + "]: " + e.toString();
-            Debug.logWarning(e, errMsg, module);
-            throw new IllegalArgumentException(errMsg);
-        }
-    }
-
     private static String getFileExtension(String filePath) {
         int pos = filePath.lastIndexOf(".");
         if (pos == -1) {
@@ -332,4 +359,71 @@ public final class ScriptUtil {
     }
 
     private ScriptUtil() {}
+
+    private static final class ProtectedBindings implements Bindings {
+        private final Map<String, Object> bindings;
+        private final Set<String> protectedKeys;
+        private ProtectedBindings(Map<String, Object> bindings, Set<String> protectedKeys) {
+            this.bindings = bindings;
+            this.protectedKeys = protectedKeys;
+        }
+        public void clear() {
+            for (String key : bindings.keySet()) {
+                if (!protectedKeys.contains(key)) {
+                    bindings.remove(key);
+                }
+            }
+        }
+        public boolean containsKey(Object key) {
+            return bindings.containsKey(key);
+        }
+        public boolean containsValue(Object value) {
+            return bindings.containsValue(value);
+        }
+        public Set<java.util.Map.Entry<String, Object>> entrySet() {
+            return bindings.entrySet();
+        }
+        public boolean equals(Object o) {
+            return bindings.equals(o);
+        }
+        public Object get(Object key) {
+            return bindings.get(key);
+        }
+        public int hashCode() {
+            return bindings.hashCode();
+        }
+        public boolean isEmpty() {
+            return bindings.isEmpty();
+        }
+        public Set<String> keySet() {
+            return bindings.keySet();
+        }
+        public Object put(String key, Object value) {
+            Assert.notNull("key", key);
+            if (protectedKeys.contains(key)) {
+                throw new UnsupportedOperationException();
+            }
+            return bindings.put(key, value);
+        }
+        public void putAll(Map<? extends String, ? extends Object> map) {
+            for (Map.Entry<? extends String, ? extends Object> entry : map.entrySet()) {
+                Assert.notNull("key", entry.getKey());
+                if (!protectedKeys.contains(entry.getKey())) {
+                    bindings.put(entry.getKey(), entry.getValue());
+                }
+            }
+        }
+        public Object remove(Object key) {
+            if (protectedKeys.contains(key)) {
+                throw new UnsupportedOperationException();
+            }
+            return bindings.remove(key);
+        }
+        public int size() {
+            return bindings.size();
+        }
+        public Collection<Object> values() {
+            return bindings.values();
+        }
+    }
 }

Modified: ofbiz/trunk/framework/base/src/org/ofbiz/base/util/string/FlexibleStringExpander.java
URL: http://svn.apache.org/viewvc/ofbiz/trunk/framework/base/src/org/ofbiz/base/util/string/FlexibleStringExpander.java?rev=1299040&r1=1299039&r2=1299040&view=diff
==============================================================================
--- ofbiz/trunk/framework/base/src/org/ofbiz/base/util/string/FlexibleStringExpander.java (original)
+++ ofbiz/trunk/framework/base/src/org/ofbiz/base/util/string/FlexibleStringExpander.java Fri Mar  9 20:41:18 2012
@@ -21,6 +21,7 @@ package org.ofbiz.base.util.string;
 import java.io.Serializable;
 import java.math.BigDecimal;
 import java.util.ArrayList;
+import java.util.HashMap;
 import java.util.Locale;
 import java.util.Map;
 import java.util.TimeZone;
@@ -593,7 +594,8 @@ public abstract class FlexibleStringExpa
         @Override
         protected Object get(Map<String, ? extends Object> context, TimeZone timeZone, Locale locale) {
             try {
-                Object obj = ScriptUtil.evaluate(this.language, this.script, this.parsedScript, context);
+                Map <String, Object> contextCopy = new HashMap<String, Object>(context);
+                Object obj = ScriptUtil.evaluate(this.language, this.script, this.parsedScript, contextCopy);
                 if (obj != null) {
                     return obj;
                 } else {

Modified: ofbiz/trunk/framework/service/src/org/ofbiz/service/engine/ScriptEngine.java
URL: http://svn.apache.org/viewvc/ofbiz/trunk/framework/service/src/org/ofbiz/service/engine/ScriptEngine.java?rev=1299040&r1=1299039&r2=1299040&view=diff
==============================================================================
--- ofbiz/trunk/framework/service/src/org/ofbiz/service/engine/ScriptEngine.java (original)
+++ ofbiz/trunk/framework/service/src/org/ofbiz/service/engine/ScriptEngine.java Fri Mar  9 20:41:18 2012
@@ -20,7 +20,10 @@ package org.ofbiz.service.engine;
 
 import static org.ofbiz.base.util.UtilGenerics.cast;
 
+import java.util.Collections;
+import java.util.HashSet;
 import java.util.Map;
+import java.util.Set;
 
 import javax.script.ScriptContext;
 
@@ -50,14 +53,19 @@ import org.ofbiz.service.ServiceUtil;
 public final class ScriptEngine extends GenericAsyncEngine {
 
     public static final String module = ScriptEngine.class.getName();
+    private static final Set<String> protectedKeys = createProtectedKeys();
 
-    public ScriptEngine(ServiceDispatcher dispatcher) {
-        super(dispatcher);
+    private static Set<String> createProtectedKeys() {
+        Set<String> newSet = new HashSet<String>();
+        newSet.add("parameters");
+        newSet.add("dctx");
+        newSet.add("dispatcher");
+        newSet.add("delegator");
+        return Collections.unmodifiableSet(newSet);
     }
 
-    @Override
-    public void runSyncIgnore(String localName, ModelService modelService, Map<String, Object> context) throws GenericServiceException {
-        runSync(localName, modelService, context);
+    public ScriptEngine(ServiceDispatcher dispatcher) {
+        super(dispatcher);
     }
 
     @Override
@@ -71,7 +79,7 @@ public final class ScriptEngine extends
         context.put("dispatcher", dctx.getDispatcher());
         context.put("delegator", dispatcher.getDelegator());
         try {
-            ScriptContext scriptContext = ScriptUtil.createScriptContext(context);
+            ScriptContext scriptContext = ScriptUtil.createScriptContext(context, protectedKeys);
             Object resultObj = ScriptUtil.executeScript(getLocation(modelService), modelService.invoke, scriptContext, new Object[] { context });
             if (resultObj == null) {
                 resultObj = scriptContext.getAttribute("result");
@@ -88,4 +96,8 @@ public final class ScriptEngine extends
         }
     }
 
+    @Override
+    public void runSyncIgnore(String localName, ModelService modelService, Map<String, Object> context) throws GenericServiceException {
+        runSync(localName, modelService, context);
+    }
 }