Author: henrib
Date: Thu Jan  7 17:16:09 2010
New Revision: 896931

URL: http://svn.apache.org/viewvc?rev=896931&view=rev
Log:
Moved JexlScriptObject into JexlScriptEngine;
JEXL variable is 'reserved', does not appear in binding and shields user value; 
ie user value of that name must be accessed through 'context.JEXL'
Made JEXL.err, JEXL.out, JEXL.in point to defaut engine scope objects 
writer/errwriter/reader;
All JexlScripEngine instances share a unique JEXL engine instance and 
expression cache;

Removed:
    
commons/proper/jexl/trunk/src/main/java/org/apache/commons/jexl2/scripting/JexlScriptObject.java
Modified:
    
commons/proper/jexl/trunk/src/main/java/org/apache/commons/jexl2/scripting/JexlScriptEngine.java
    
commons/proper/jexl/trunk/src/main/java/org/apache/commons/jexl2/scripting/JexlScriptEngineFactory.java
    
commons/proper/jexl/trunk/src/test/java/org/apache/commons/jexl2/scripting/JexlScriptEngineOptionalTest.java
    
commons/proper/jexl/trunk/src/test/java/org/apache/commons/jexl2/scripting/JexlScriptEngineTest.java

Modified: 
commons/proper/jexl/trunk/src/main/java/org/apache/commons/jexl2/scripting/JexlScriptEngine.java
URL: 
http://svn.apache.org/viewvc/commons/proper/jexl/trunk/src/main/java/org/apache/commons/jexl2/scripting/JexlScriptEngine.java?rev=896931&r1=896930&r2=896931&view=diff
==============================================================================
--- 
commons/proper/jexl/trunk/src/main/java/org/apache/commons/jexl2/scripting/JexlScriptEngine.java
 (original)
+++ 
commons/proper/jexl/trunk/src/main/java/org/apache/commons/jexl2/scripting/JexlScriptEngine.java
 Thu Jan  7 17:16:09 2010
@@ -18,9 +18,9 @@
 package org.apache.commons.jexl2.scripting;
 
 import java.io.IOException;
+import java.io.PrintWriter;
 import java.io.Reader;
-import java.util.HashMap;
-import java.util.Map;
+import java.io.Writer;
 
 import javax.script.AbstractScriptEngine;
 import javax.script.Bindings;
@@ -36,6 +36,9 @@
 import org.apache.commons.jexl2.JexlEngine;
 import org.apache.commons.jexl2.Script;
 
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+
 /**
  * Implements the Jexl ScriptEngine for JSF-223.
  * <p>
@@ -56,19 +59,27 @@
  * @since 2.0
  */
 public class JexlScriptEngine extends AbstractScriptEngine implements 
Compilable {
+    /** The logger. */
+    private static final Log LOG = LogFactory.getLog(JexlScriptEngine.class);
 
-    /** Reserved key for JexlScriptObject. */
-    public static final String JEXL_OBJECT_KEY = "JEXL";
+    /** The shared expression cache size. */
+    private static final int CACHE_SIZE = 512;
 
     /** Reserved key for context (mandated by JSR-223). */
     public static final String CONTEXT_KEY = "context";
 
+    /** Reserved key for JexlScriptObject. */
+    public static final String JEXL_OBJECT_KEY = "JEXL";
+
+    /** The JexlScriptObject instance. */
+    private final JexlScriptObject jexlObject;
+
     /** The factory which created this instance. */
     private final ScriptEngineFactory parentFactory;
     
     /** The JEXL EL engine. */
     private final JexlEngine jexlEngine;
-   
+    
     /**
      * Default constructor.
      * <p>
@@ -76,22 +87,92 @@
      * Sets the factory to {...@link JexlScriptEngineFactory}.
      */
     public JexlScriptEngine() {
-        this(SingletonHolder.DEFAULT_FACTORY);
+        this(FactorySingletonHolder.DEFAULT_FACTORY);
     }
 
     /**
-     * The set of functions exposed in the default namespace.
+     * Implements engine and engine context properties for use by JEXL scripts.
+     * Those properties are allways bound to the default engine scope context.
+     * <p>
+     * The following properties are defined:
+     * <ul>
+     * <li>in - refers to the engine scope reader that defaults to reading 
System.err</li>
+     * <li>out - refers the engine scope writer that defaults to writing in 
System.out</li>
+     * <li>err - refers to the engine scope writer that defaults to writing in 
System.err</li>
+     * <li>logger - the JexlScriptEngine logger</li>
+     * <li>System - the System.class</li>
+     * </ul>
+     * </p>
+     * @since 2.0
      */
-    public static final class JexlFunctions {
+    public class JexlScriptObject {
+        /**
+         * Gives access to the underlying JEXL engine shared between all 
ScriptEngine instances.
+         * <p>Although this allows to manipulate various engine flags 
(lenient, debug, cache...)
+         * for <strong>all</strong> JexlScriptEngine instances, you probably 
should only do so
+         * if you are in strict control and sole user of the Jexl scripting 
feature.</p>
+         * @return the shared underlying JEXL engine
+         */
+        public JexlEngine getEngine() {
+            return jexlEngine;
+        }
+
         /**
-         * Calls System.out.println.
-         * @param arg the argument
+         * Gives access to the engine scope output writer (defaults to 
System.out).
+         * @return the engine output writer
          */
-        public void print(String arg) {
-            System.out.println(arg);
+        public PrintWriter getOut() {
+            final Writer out = context.getWriter();
+            if (out instanceof PrintWriter) {
+                return (PrintWriter) out;
+            } else if (out != null) {
+                return new PrintWriter(out, true);
+            } else {
+                return null;
+            }
+        }
+
+        /**
+         * Gives access to the engine scope error writer (defaults to 
System.err).
+         * @return the engine error writer
+         */
+        public PrintWriter getErr() {
+            final Writer error = context.getErrorWriter();
+            if (error instanceof PrintWriter) {
+                return (PrintWriter) error;
+            } else if (error != null) {
+                return new PrintWriter(error, true);
+            } else {
+                return null;
+            }
+        }
+
+        /**
+         * Gives access to the engine scope input reader (defaults to 
System.in).
+         * @return the engine input reader
+         */
+        public Reader getIn() {
+            return context.getReader();
+        }
+
+        /**
+         * Gives access to System class.
+         * @return System.class
+         */
+        public Class<System> getSystem() {
+            return System.class;
+        }
+
+        /**
+         * Gives access to the engine logger.
+         * @return the JexlScriptEngine logger
+         */
+        public Log getLogger() {
+            return LOG;
         }
     }
-    
+
+
     /**
      * Create a scripting engine using the supplied factory.
      * 
@@ -103,13 +184,8 @@
             throw new NullPointerException("ScriptEngineFactory must not be 
null");
         }
         parentFactory = factory;
-        jexlEngine = new JexlEngine();
-        // Add the jexl functions, ie print and escape
-        Map<String,Object> funcs = new HashMap<String,Object>();
-        funcs.put(null, new JexlFunctions());
-        jexlEngine.setFunctions(funcs);
-        // Add utility object
-        put(JEXL_OBJECT_KEY, new JexlScriptObject());
+        jexlEngine = EngineSingletonHolder.DEFAULT_ENGINE;
+        jexlObject = new JexlScriptObject();
     }
 
     /** {...@inheritdoc} */
@@ -118,24 +194,22 @@
     }
 
     /** {...@inheritdoc} */
-    public Object eval(Reader reader, ScriptContext context) throws 
ScriptException {
+    public Object eval(final Reader reader, final ScriptContext context) 
throws ScriptException {
         // This is mandated by JSR-223 (see SCR.5.5.2   Methods)
         if (reader == null || context == null) {
             throw new NullPointerException("script and context must be 
non-null");
         }
-
         return eval(readerToString(reader), context);
     }
 
     /** {...@inheritdoc} */
-    public Object eval(String script, final ScriptContext context) throws 
ScriptException {
+    public Object eval(final String script, final ScriptContext context) 
throws ScriptException {
         // This is mandated by JSR-223 (see SCR.5.5.2   Methods)
         if (script == null || context == null) {
             throw new NullPointerException("script and context must be 
non-null");
         }
         // This is mandated by JSR-223 (end of section SCR.4.3.4.1.2 - Script 
Execution)
         context.setAttribute(CONTEXT_KEY, context, ScriptContext.ENGINE_SCOPE);
-        
         try {
             Script jexlScript = jexlEngine.createScript(script);
             JexlContext ctxt = new JexlContextWrapper(context);
@@ -151,7 +225,7 @@
     }
 
     /** {...@inheritdoc} */
-    public CompiledScript compile(String script) throws ScriptException {
+    public CompiledScript compile(final String script) throws ScriptException {
         // This is mandated by JSR-223
         if (script == null) {
             throw new NullPointerException("script must be non-null");
@@ -165,7 +239,7 @@
     }
 
     /** {...@inheritdoc} */
-    public CompiledScript compile(Reader script) throws ScriptException {
+    public CompiledScript compile(final Reader script) throws ScriptException {
         // This is mandated by JSR-223
         if (script == null) {
             throw new NullPointerException("script must be non-null");
@@ -179,7 +253,7 @@
      * @return the script as a string
      * @throws ScriptException if an exception occurs during read
      */
-    private String readerToString(Reader script) throws ScriptException {
+    private String readerToString(final Reader script) throws ScriptException {
         try {
            return JexlEngine.readerToString(script);
         } catch (IOException e) {
@@ -190,47 +264,68 @@
     /**
      * Holds singleton JexlScriptEngineFactory (IODH). 
      */
-    private static class SingletonHolder {
+    private static class FactorySingletonHolder {
         /** non instantiable. */
-        private SingletonHolder() {}
-        /** The singleton instance. */
+        private FactorySingletonHolder() {}
+        /** The engine factory singleton instance. */
         private static final JexlScriptEngineFactory DEFAULT_FACTORY = new 
JexlScriptEngineFactory();
     }
 
     /**
+     * Holds singleton JexlScriptEngine (IODH).
+     * <p>A single JEXL engine and Uberspect is shared by all instances of 
JexlScriptEngine.</p>
+     */
+    private static class EngineSingletonHolder {
+        /** non instantiable. */
+        private EngineSingletonHolder() {}
+        /** The JEXL engine singleton instance. */
+        private static final JexlEngine DEFAULT_ENGINE = new JexlEngine(null, 
null, null, LOG) {
+            {
+                this.setCache(CACHE_SIZE);
+            }
+        };
+    }
+
+    /**
      * Wrapper to help convert a JSR-223 ScriptContext into a JexlContext.
      *
      * Current implementation only gives access to ENGINE_SCOPE binding.
      */
-    private static final class JexlContextWrapper implements JexlContext {
-        /** The engine context. */
-        private final ScriptContext engineContext;
+    private final class JexlContextWrapper implements JexlContext {
+        /** The wrapped script context. */
+        private final ScriptContext scriptContext;
         /**
-         * Create the class.
-         *
-         * @param context the engine context.
+         * Creates a context wrapper.
+         * @param theContext the engine context.
          */
-        private JexlContextWrapper (final ScriptContext  context){
-            engineContext = context;
+        private JexlContextWrapper (final ScriptContext theContext){
+            scriptContext = theContext;
         }
 
         /** {...@inheritdoc} */
-        public Object get(String name) {
-            return engineContext.getAttribute(name);
+        public Object get(final String name) {
+            final Object o = scriptContext.getAttribute(name);
+            if (JEXL_OBJECT_KEY.equals(name)) {
+                if (o != null) {
+                    LOG.warn("JEXL is a reserved variable name, user defined 
value is ignored");
+                }
+                return jexlObject;
+            }
+            return o;
         }
 
         /** {...@inheritdoc} */
-        public void set(String name, Object value) {
-            int scope = engineContext.getAttributesScope(name);
+        public void set(final String name, final Object value) {
+            int scope = scriptContext.getAttributesScope(name);
             if (scope == -1) { // not found, default to engine
                 scope = ScriptContext.ENGINE_SCOPE;
             }
-            engineContext.getBindings(scope).put(name , value);
+            scriptContext.getBindings(scope).put(name , value);
         }
 
         /** {...@inheritdoc} */
-        public boolean has(String name) {
-            Bindings bnd = 
engineContext.getBindings(ScriptContext.ENGINE_SCOPE);
+        public boolean has(final String name) {
+            Bindings bnd = 
scriptContext.getBindings(ScriptContext.ENGINE_SCOPE);
             return bnd.containsKey(name);
         }
 
@@ -247,7 +342,7 @@
          * Creates an instance.
          * @param theScript to wrap
          */
-        private JexlCompiledScript(Script theScript) {
+        private JexlCompiledScript(final Script theScript) {
             script = theScript;
         }
 
@@ -259,7 +354,7 @@
         
         /** {...@inheritdoc} */
         @Override
-        public Object eval(ScriptContext context) throws ScriptException {
+        public Object eval(final ScriptContext context) throws ScriptException 
{
             // This is mandated by JSR-223 (end of section SCR.4.3.4.1.2 - 
Script Execution)
             context.setAttribute(CONTEXT_KEY, context, 
ScriptContext.ENGINE_SCOPE);
             try {

Modified: 
commons/proper/jexl/trunk/src/main/java/org/apache/commons/jexl2/scripting/JexlScriptEngineFactory.java
URL: 
http://svn.apache.org/viewvc/commons/proper/jexl/trunk/src/main/java/org/apache/commons/jexl2/scripting/JexlScriptEngineFactory.java?rev=896931&r1=896930&r2=896931&view=diff
==============================================================================
--- 
commons/proper/jexl/trunk/src/main/java/org/apache/commons/jexl2/scripting/JexlScriptEngineFactory.java
 (original)
+++ 
commons/proper/jexl/trunk/src/main/java/org/apache/commons/jexl2/scripting/JexlScriptEngineFactory.java
 Thu Jan  7 17:16:09 2010
@@ -98,9 +98,9 @@
     /** {...@inheritdoc} */
     public String getOutputStatement(String toDisplay) {
         if (toDisplay == null) {
-            return "print(null)";
+            return "JEXL.out.print(null)";
         } else {
-            return "print("+StringParser.escapeString(toDisplay)+")";
+            return "JEXL.out.print("+StringParser.escapeString(toDisplay)+")";
         }
     }
 
@@ -117,8 +117,14 @@
         } else if(key.equals(ScriptEngine.LANGUAGE_VERSION)) {
             return getLanguageVersion();
         } else if (key.equals("THREADING")) {
-            return null;//"MULTITHREADED"; // TODO what is the correct value 
here?
-        } 
+            /*
+             * To implement multithreading, the scripting engine context 
(inherited from AbstractScriptEngine)
+             * would need to be made thread-safe; so would the 
setContext/getContext methods.
+             * It is easier to share the underlying Uberspect and JEXL engine 
instance, especially
+             * with an expression cache.
+             */
+            return null;
+        }
         return null;
     }
 

Modified: 
commons/proper/jexl/trunk/src/test/java/org/apache/commons/jexl2/scripting/JexlScriptEngineOptionalTest.java
URL: 
http://svn.apache.org/viewvc/commons/proper/jexl/trunk/src/test/java/org/apache/commons/jexl2/scripting/JexlScriptEngineOptionalTest.java?rev=896931&r1=896930&r2=896931&view=diff
==============================================================================
--- 
commons/proper/jexl/trunk/src/test/java/org/apache/commons/jexl2/scripting/JexlScriptEngineOptionalTest.java
 (original)
+++ 
commons/proper/jexl/trunk/src/test/java/org/apache/commons/jexl2/scripting/JexlScriptEngineOptionalTest.java
 Thu Jan  7 17:16:09 2010
@@ -18,8 +18,8 @@
 
 package org.apache.commons.jexl2.scripting;
 
-import java.io.ByteArrayOutputStream;
-import java.io.PrintStream;
+import java.io.PrintWriter;
+import java.io.StringWriter;
 import javax.script.Compilable;
 import javax.script.CompiledScript;
 
@@ -32,18 +32,23 @@
     private final ScriptEngineManager manager = new ScriptEngineManager();
     private final ScriptEngine engine = manager.getEngineByName("jexl");
 
-    public void testScriptEngineOutput() throws Exception {
+    public void testOutput() throws Exception {
         String output = factory.getOutputStatement("foo\u00a9bar");
-        assertEquals(output, "print('foo\\u00a9bar')");
+        assertEquals("JEXL.out.print('foo\\u00a9bar')", output);
         // redirect output to capture evaluation result
-        final ByteArrayOutputStream outContent = new ByteArrayOutputStream();
-        System.setOut(new PrintStream(outContent));
-        try {
-            engine.eval(output);
-        } finally {
-            System.setOut(null);
-        }
-        assertEquals("foo\u00a9bar\n", outContent.toString());
+        final StringWriter outContent = new StringWriter();
+        engine.getContext().setWriter(outContent);
+        engine.eval(output);
+        assertEquals("foo\u00a9bar", outContent.toString());
+    }
+
+    public void testError() throws Exception {
+        String error = "JEXL.err.print('ERROR')";
+        // redirect error to capture evaluation result
+        final StringWriter outContent = new StringWriter();
+        engine.getContext().setErrorWriter(outContent);
+        engine.eval(error);
+        assertEquals("ERROR", outContent.toString());
     }
 
     public void testCompilable() throws Exception {
@@ -53,5 +58,4 @@
         assertEquals(Integer.valueOf(42), script.eval());
         assertEquals(Integer.valueOf(42), script.eval());
     }
-
 }

Modified: 
commons/proper/jexl/trunk/src/test/java/org/apache/commons/jexl2/scripting/JexlScriptEngineTest.java
URL: 
http://svn.apache.org/viewvc/commons/proper/jexl/trunk/src/test/java/org/apache/commons/jexl2/scripting/JexlScriptEngineTest.java?rev=896931&r1=896930&r2=896931&view=diff
==============================================================================
--- 
commons/proper/jexl/trunk/src/test/java/org/apache/commons/jexl2/scripting/JexlScriptEngineTest.java
 (original)
+++ 
commons/proper/jexl/trunk/src/test/java/org/apache/commons/jexl2/scripting/JexlScriptEngineTest.java
 Thu Jan  7 17:16:09 2010
@@ -18,13 +18,9 @@
 
 package org.apache.commons.jexl2.scripting;
 
-import java.io.ByteArrayOutputStream;
-import java.io.PrintStream;
 import java.io.Reader;
 import java.util.Arrays;
 import java.util.Map;
-import javax.script.Compilable;
-import javax.script.CompiledScript;
 
 import javax.script.ScriptEngine;
 import javax.script.ScriptEngineManager;
@@ -72,9 +68,9 @@
         assertEquals(newValue,engine.get("value"));
         
assertEquals(engine.getContext(),engine.get(JexlScriptEngine.CONTEXT_KEY));
         // Check behaviour of JEXL object
-        assertNotNull(engine.get("JEXL"));
-        assertEquals(System.out,engine.eval("JEXL.out"));
-        assertEquals(System.err,engine.eval("JEXL.err"));
+        assertEquals(engine.getContext().getReader(),engine.eval("JEXL.in"));
+        assertEquals(engine.getContext().getWriter(),engine.eval("JEXL.out"));
+        
assertEquals(engine.getContext().getErrorWriter(),engine.eval("JEXL.err"));
         assertEquals(System.class,engine.eval("JEXL.System"));
     }
     
@@ -98,10 +94,9 @@
     }
 
     public void testEngineNames() throws Exception {
-        ScriptEngine engine;
         ScriptEngineManager manager = new ScriptEngineManager();
         assertNotNull("Manager should not be null", manager);
-        engine = manager.getEngineByName("JEXL");
+        ScriptEngine engine = manager.getEngineByName("JEXL");
         assertNotNull("Engine should not be null (JEXL)", engine);        
         engine = manager.getEngineByName("Jexl");
         assertNotNull("Engine should not be null (Jexl)", engine);        
@@ -110,10 +105,9 @@
     }
 
     public void testScopes() throws Exception {
-        ScriptEngine engine;
         ScriptEngineManager manager = new ScriptEngineManager();
         assertNotNull("Manager should not be null", manager);
-        engine = manager.getEngineByName("JEXL");
+        ScriptEngine engine = manager.getEngineByName("JEXL");
         assertNotNull("Engine should not be null (JEXL)", engine);
         manager.put("global",Integer.valueOf(1));
         engine.put("local", Integer.valueOf(10));
@@ -132,10 +126,9 @@
     }
 
     public void testDottedNames() throws Exception {
-        ScriptEngine engine;
         ScriptEngineManager manager = new ScriptEngineManager();
         assertNotNull("Manager should not be null", manager);
-        engine = manager.getEngineByName("JEXL");
+        ScriptEngine engine = manager.getEngineByName("JEXL");
         assertNotNull("Engine should not be null (JEXL)", engine);
         engine.eval("this.is.a.test=null");
         assertNull(engine.get("this.is.a.test"));


Reply via email to