You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@commons.apache.org by he...@apache.org on 2009/09/14 15:38:48 UTC

svn commit: r814637 - in /commons/proper/jexl/trunk/src/main/java/org/apache/commons/jexl: ExpressionFactory.java Interpreter.java JexlEngine.java ScriptFactory.java

Author: henrib
Date: Mon Sep 14 13:38:47 2009
New Revision: 814637

URL: http://svn.apache.org/viewvc?rev=814637&view=rev
Log:
Made {Expression,Script}Factory use a specialized 'legacy' interpreter that more strictly mimicks JEXL 1.1 behavior, at least according to Jelly expectations (Jelly tests pass locally now).
Introduced undefinedVariable and invocationError methods in Interpreter.java to allow easier derivation.
Enhanced error reporting in JexlEngine#parse to go down further in stack seeking caller.

Modified:
    commons/proper/jexl/trunk/src/main/java/org/apache/commons/jexl/ExpressionFactory.java
    commons/proper/jexl/trunk/src/main/java/org/apache/commons/jexl/Interpreter.java
    commons/proper/jexl/trunk/src/main/java/org/apache/commons/jexl/JexlEngine.java
    commons/proper/jexl/trunk/src/main/java/org/apache/commons/jexl/ScriptFactory.java

Modified: commons/proper/jexl/trunk/src/main/java/org/apache/commons/jexl/ExpressionFactory.java
URL: http://svn.apache.org/viewvc/commons/proper/jexl/trunk/src/main/java/org/apache/commons/jexl/ExpressionFactory.java?rev=814637&r1=814636&r2=814637&view=diff
==============================================================================
--- commons/proper/jexl/trunk/src/main/java/org/apache/commons/jexl/ExpressionFactory.java (original)
+++ commons/proper/jexl/trunk/src/main/java/org/apache/commons/jexl/ExpressionFactory.java Mon Sep 14 13:38:47 2009
@@ -66,7 +66,7 @@
     @Deprecated
     public static Expression createExpression(String expression)
         throws ParseException {
-        return new JexlEngine().createExpression(expression);
+        return ScriptFactory.getInstance().createExpression(expression);
     }
 
 }

Modified: commons/proper/jexl/trunk/src/main/java/org/apache/commons/jexl/Interpreter.java
URL: http://svn.apache.org/viewvc/commons/proper/jexl/trunk/src/main/java/org/apache/commons/jexl/Interpreter.java?rev=814637&r1=814636&r2=814637&view=diff
==============================================================================
--- commons/proper/jexl/trunk/src/main/java/org/apache/commons/jexl/Interpreter.java (original)
+++ commons/proper/jexl/trunk/src/main/java/org/apache/commons/jexl/Interpreter.java Mon Sep 14 13:38:47 2009
@@ -202,7 +202,37 @@
         return node;
     }
 
-/** {@inheritDoc} */
+    /**
+     * Triggered when variable can not be resolved.
+     * @param xjexl the JexlException ("undefined variable " + variable)
+     * @return throws JexlException if strict, null otherwise
+     */
+    protected Object unknownVariable(JexlException xjexl) {
+        if (strict) {
+            throw xjexl;
+        }
+        if (!silent) {
+            logger.warn(xjexl.getMessage());
+        }
+        return null;
+    }
+
+    /**
+     * Triggered when method, function or constructor invocation fails.
+     * @param xjexl the JexlException wrapping the original error
+     * @return throws JexlException if strict, null otherwise
+     */
+    protected Object invocationFailed(JexlException xjexl) {
+        if (strict) {
+            throw xjexl;
+        }
+        if (!silent) {
+            logger.warn(xjexl.getMessage(), xjexl.getCause());
+        }
+        return null;
+    }
+
+    /** {@inheritDoc} */
     public Object visit(ASTAdditiveNode node, Object data) {
         /**
          * The pattern for exception mgmt is to let the child*.jjtAccept
@@ -600,13 +630,8 @@
             if (value == null
                 && !(node.jjtGetParent() instanceof ASTReference)
                 && !context.getVars().containsKey(name)) {
-                JexlException xjexl = new JexlException(node, "undefined variable " + name);
-                if (strict) {
-                    throw xjexl;
-                }
-                if (!silent) {
-                    logger.warn(xjexl.getMessage());
-                }
+                JexlException xjexl = new JexlException(node, "undefined variable " + node.image);
+                return unknownVariable(xjexl);
             }
             return value;
         } else {
@@ -777,20 +802,11 @@
                 return eval;
             }
         } catch (InvocationTargetException e) {
-            Throwable t = e.getTargetException();
-            if (!(t instanceof Exception)) {
-                t = e;
-            }
-            xjexl = new JexlException(node, "method invocation error", t);
+            xjexl = new JexlException(node, "method invocation error", e.getCause());
         } catch (Exception e) {
             xjexl = new JexlException(node, "method error", e);
         }
-        // xjexl cannot be null here
-        if (strict) {
-            throw xjexl;
-        }
-        logger.warn(xjexl.getMessage(), xjexl.getCause());
-        return null;
+        return invocationFailed(xjexl);
     }
 
     /** {@inheritDoc} */
@@ -821,20 +837,11 @@
                 return ctor.newInstance(argv);
             }
         } catch (InvocationTargetException e) {
-            Throwable t = e.getTargetException();
-            if (!(t instanceof Exception)) {
-                t = e;
-            }
-            xjexl = new JexlException(node, "constructor invocation error", t);
+            xjexl = new JexlException(node, "constructor invocation error", e.getCause());
         } catch (Exception e) {
             xjexl = new JexlException(node, "constructor error", e);
         }
-        // xjexl cannot be null here
-        if (strict) {
-            throw xjexl;
-        }
-        logger.warn(xjexl.getMessage(), xjexl.getCause());
-        return null;
+        return invocationFailed(xjexl);
     }
 
     /** {@inheritDoc} */
@@ -888,20 +895,11 @@
                 return eval;
             }
         } catch (InvocationTargetException e) {
-            Throwable t = e.getTargetException();
-            if (!(t instanceof Exception)) {
-                t = e;
-            }
-            xjexl = new JexlException(node, "function invocation error", t);
+            xjexl = new JexlException(node, "function invocation error", e.getCause());
         } catch (Exception e) {
             xjexl = new JexlException(node, "function error", e);
         }
-        // xjexl cannot be null here
-        if (strict) {
-            throw xjexl;
-        }
-        logger.warn(xjexl.getMessage(), xjexl.getCause());
-        return null;
+        return invocationFailed(xjexl);
     }
 
     /** {@inheritDoc} */

Modified: commons/proper/jexl/trunk/src/main/java/org/apache/commons/jexl/JexlEngine.java
URL: http://svn.apache.org/viewvc/commons/proper/jexl/trunk/src/main/java/org/apache/commons/jexl/JexlEngine.java?rev=814637&r1=814636&r2=814637&view=diff
==============================================================================
--- commons/proper/jexl/trunk/src/main/java/org/apache/commons/jexl/JexlEngine.java (original)
+++ commons/proper/jexl/trunk/src/main/java/org/apache/commons/jexl/JexlEngine.java Mon Sep 14 13:38:47 2009
@@ -586,12 +586,19 @@
                     StackTraceElement[] stack = xinfo.getStackTrace();
                     StackTraceElement se = null;
                     Class<?> clazz = getClass();
-                    for(int s = 0; s < stack.length; ++s, se = null) {
+                    for(int s = 1; s < stack.length; ++s, se = null) {
                         se = stack[s];
-                        if (!se.getClassName().equals(clazz.getName())) {
-                            // go deeper if called from UnifiedJEXL
-                            if (se.getClassName().equals(UnifiedJEXL.class.getName())) {
+                        String className = se.getClassName();
+                        if (!className.equals(clazz.getName())) {
+                            // go deeper if called from JexlEngine, UnifiedJEXL or a Factory
+                            if (className.equals(JexlEngine.class.getName())) {
+                                clazz = JexlEngine.class;
+                            } else if (className.equals(UnifiedJEXL.class.getName())) {
                                 clazz = UnifiedJEXL.class;
+                            } else if (className.equals(ScriptFactory.class.getName())) {
+                                clazz = ScriptFactory.class;
+                            } else if (className.equals(ExpressionFactory.class.getName())) {
+                                clazz = ExpressionFactory.class;
                             } else {
                                 break;
                             }

Modified: commons/proper/jexl/trunk/src/main/java/org/apache/commons/jexl/ScriptFactory.java
URL: http://svn.apache.org/viewvc/commons/proper/jexl/trunk/src/main/java/org/apache/commons/jexl/ScriptFactory.java?rev=814637&r1=814636&r2=814637&view=diff
==============================================================================
--- commons/proper/jexl/trunk/src/main/java/org/apache/commons/jexl/ScriptFactory.java (original)
+++ commons/proper/jexl/trunk/src/main/java/org/apache/commons/jexl/ScriptFactory.java Mon Sep 14 13:38:47 2009
@@ -18,7 +18,7 @@
 
 import java.io.File;
 import java.net.URL;
-
+import org.apache.commons.jexl.parser.JexlNode;
 /**
  * <p>
  * Creates {@link Script}s.  To create a JEXL Script, pass
@@ -46,6 +46,76 @@
 @Deprecated
 public final class ScriptFactory {
     /**
+     * Lazy JexlEngine singleton; since this class is deprecated, let's not create the shared
+     * engine if it's not gonna be used.
+     */
+    private static volatile JexlEngine INSTANCE = null;
+    
+    /**
+     * An interpreter made compatible with v1.1 behavior (at least Jelly's expectations).
+     */
+    private static class LegacyInterpreter extends Interpreter {
+        public LegacyInterpreter(JexlEngine jexl, JexlContext aContext) {
+            super(jexl, aContext);
+        }
+
+        @Override
+        public Object interpret(JexlNode node) {
+            try {
+                return node.jjtAccept(this, null);
+            } catch (JexlException xjexl) {
+                Throwable e = xjexl.getCause();
+                if (e instanceof RuntimeException)
+                        throw (RuntimeException)e;
+                if (e instanceof IllegalStateException)
+                        throw (IllegalStateException )e;
+                throw new IllegalStateException(e.getMessage(), e);
+            }
+        }
+
+        @Override
+        protected Object invocationFailed(JexlException xjexl) {
+            throw xjexl;
+        }
+
+        @Override
+        protected Object unknownVariable(JexlException xjexl) {
+            return null;
+        }
+    }
+    
+    /**
+     * An engine that uses a LegacyInterpreter.
+     */
+    private static class LegacyEngine extends JexlEngine {
+        @Override
+        protected Interpreter createInterpreter(JexlContext context) {
+            if (context == null) {
+                context = EMPTY_CONTEXT;
+            }
+            return new ScriptFactory.LegacyInterpreter(this, context);
+        }
+    }
+    
+    /**
+     * Retrieves the static shared JexlEngine instance.
+     */
+    static JexlEngine getInstance() {
+        // Java5 memory model allows double-lock pattern
+        if (INSTANCE == null) {
+            synchronized(ScriptFactory.class){
+                if (INSTANCE == null) {
+                    JexlEngine jexl = new LegacyEngine();
+                    jexl.setCache(256);
+                    jexl.setSilent(false);
+                    INSTANCE = jexl;
+                }
+            }
+        }
+        return INSTANCE;
+    }
+
+    /**
      * Private constructor, ensure no instance.
      */
     private ScriptFactory() {}
@@ -63,7 +133,7 @@
      */
     @Deprecated
     public static Script createScript(String scriptText) throws Exception {
-        return new JexlEngine().createScript(scriptText);
+        return getInstance().createScript(scriptText);
     }
 
     /**
@@ -80,7 +150,7 @@
      */
     @Deprecated
     public static Script createScript(File scriptFile) throws Exception {
-        return new JexlEngine().createScript(scriptFile);
+        return getInstance().createScript(scriptFile);
     }
 
     /**
@@ -97,7 +167,7 @@
      */
     @Deprecated
     public static Script createScript(URL scriptUrl) throws Exception {
-        return new JexlEngine().createScript(scriptUrl);
+        return getInstance().createScript(scriptUrl);
     }
 
 }
\ No newline at end of file