Author: henrib Date: Sun Aug 30 11:29:27 2009 New Revision: 809315 URL: http://svn.apache.org/viewvc?rev=809315&view=rev Log: Made ExpressionImpl implement both Script and Expression (will delete ScripImpl.java). Use ASTJexlScript as root of Expression; implies it's also used as cached object by JexlEngine cache (thus the modifications in JexlEngine and JexlTestCase)
Modified: commons/proper/jexl/branches/2.0/src/main/java/org/apache/commons/jexl/ExpressionImpl.java commons/proper/jexl/branches/2.0/src/main/java/org/apache/commons/jexl/JexlEngine.java commons/proper/jexl/branches/2.0/src/test/java/org/apache/commons/jexl/JexlTestCase.java Modified: commons/proper/jexl/branches/2.0/src/main/java/org/apache/commons/jexl/ExpressionImpl.java URL: http://svn.apache.org/viewvc/commons/proper/jexl/branches/2.0/src/main/java/org/apache/commons/jexl/ExpressionImpl.java?rev=809315&r1=809314&r2=809315&view=diff ============================================================================== --- commons/proper/jexl/branches/2.0/src/main/java/org/apache/commons/jexl/ExpressionImpl.java (original) +++ commons/proper/jexl/branches/2.0/src/main/java/org/apache/commons/jexl/ExpressionImpl.java Sun Aug 30 11:29:27 2009 @@ -17,29 +17,28 @@ package org.apache.commons.jexl; -import org.apache.commons.jexl.parser.JexlNode; +import org.apache.commons.jexl.parser.ASTJexlScript; /** * Instances of ExpressionImpl are created by the {...@link JexlEngine}, - * and this is the default implementation of the {...@link Expression} interface. + * and this is the default implementation of the {...@link Expression} and + * {...@link Script} interface. * * @since 1.0 * @author <a href="mailto:ge...@apache.org">Geir Magnusson Jr.</a> * @version $Id$ */ -class ExpressionImpl implements Expression { +class ExpressionImpl implements Expression, Script { /** The engine for this expression. */ protected final JexlEngine jexl; /** - * Original expression. This is just a 'snippet', not a valid statement - * (i.e. foo.bar() vs foo.bar(); + * Original expression stripped from leading & trailing spaces. */ protected final String expression; - /** * The resulting AST we can interpret. */ - protected final JexlNode node; + protected final ASTJexlScript script; /** @@ -49,9 +48,9 @@ * @param expr the expression. * @param ref the parsed expression. */ - ExpressionImpl(JexlEngine engine, String expr, JexlNode ref) { + ExpressionImpl(JexlEngine engine, String expr, ASTJexlScript ref) { expression = expr; - node = ref; + script = ref; jexl = engine; } @@ -59,8 +58,11 @@ * {...@inheritdoc} */ public Object evaluate(JexlContext context) { + if (script.jjtGetNumChildren() < 1) { + return null; + } Interpreter interpreter = jexl.createInterpreter(context); - return interpreter.interpret(node); + return interpreter.interpret(script.jjtGetChild(0)); } /** @@ -68,7 +70,7 @@ */ public String dump() { Debugger debug = new Debugger(); - return debug.debug(node)? debug.toString() : "/*?*/"; + return debug.debug(script)? debug.toString() : "/*?*/"; } /** @@ -89,4 +91,19 @@ return expr == null ? "" : expr; } + /** + * {...@inheritdoc} + */ + public String getText() { + return toString(); + } + + /** + * {...@inheritdoc} + */ + public Object execute(JexlContext context) throws Exception { + Interpreter interpreter = jexl.createInterpreter(context); + return interpreter.interpret(script); + } + } \ No newline at end of file Modified: commons/proper/jexl/branches/2.0/src/main/java/org/apache/commons/jexl/JexlEngine.java URL: http://svn.apache.org/viewvc/commons/proper/jexl/branches/2.0/src/main/java/org/apache/commons/jexl/JexlEngine.java?rev=809315&r1=809314&r2=809315&view=diff ============================================================================== --- commons/proper/jexl/branches/2.0/src/main/java/org/apache/commons/jexl/JexlEngine.java (original) +++ commons/proper/jexl/branches/2.0/src/main/java/org/apache/commons/jexl/JexlEngine.java Sun Aug 30 11:29:27 2009 @@ -117,7 +117,7 @@ /** * The expression cache. */ - protected Map<String, JexlNode> cache = null; + protected Map<String, ASTJexlScript> cache = null; /** * An empty/static/non-mutable JexlContext used instead of null context. */ @@ -298,13 +298,12 @@ public Expression createExpression(String expression, Info info) throws ParseException { // Parse the expression - JexlNode tree = parse(expression, info); + ASTJexlScript tree = parse(expression, info); if (tree.jjtGetNumChildren() > 1) { logger.warn("The JEXL Expression created will be a reference" + " to the first expression from the supplied script: \"" + expression + "\" "); } - JexlNode node = tree.jjtGetChild(0); - return new ExpressionImpl(this, expression, node); + return new ExpressionImpl(this, expression, tree); } /** @@ -332,12 +331,9 @@ if (scriptText == null) { throw new NullPointerException("scriptText is null"); } - JexlNode script = parse(scriptText, info); - if (script instanceof ASTJexlScript) { - return new ScriptImpl(this, scriptText, (ASTJexlScript) script); - } else { - throw new IllegalStateException("Parsed script is not an ASTJexlScript"); - } + // Parse the expression + ASTJexlScript tree = parse(scriptText, info); + return new ExpressionImpl(this, scriptText, tree); } /** @@ -540,12 +536,12 @@ * @param cacheSize the cache size, must be > 0 * @return a Map usable as a cache bounded to the given size */ - protected Map<String, JexlNode> createCache(final int cacheSize) { - return new java.util.LinkedHashMap<String, JexlNode>(cacheSize, LOAD_FACTOR, true) { + protected Map<String, ASTJexlScript> createCache(final int cacheSize) { + return new java.util.LinkedHashMap<String, ASTJexlScript>(cacheSize, LOAD_FACTOR, true) { /** Serial version UID. */ private static final long serialVersionUID = 3801124242820219131L; @Override - protected boolean removeEldestEntry(Map.Entry<String, JexlNode> eldest) { + protected boolean removeEldestEntry(Map.Entry<String, ASTJexlScript> eldest) { return size() > cacheSize; } }; @@ -558,9 +554,9 @@ * @return the parsed tree * @throws ParseException if any error occured during parsing */ - protected JexlNode parse(CharSequence expression, Info info) throws ParseException { + protected ASTJexlScript parse(CharSequence expression, Info info) throws ParseException { String expr = cleanExpression(expression); - JexlNode tree = null; + ASTJexlScript tree = null; synchronized (parser) { logger.debug("Parsing expression: " + expression); if (cache != null) { Modified: commons/proper/jexl/branches/2.0/src/test/java/org/apache/commons/jexl/JexlTestCase.java URL: http://svn.apache.org/viewvc/commons/proper/jexl/branches/2.0/src/test/java/org/apache/commons/jexl/JexlTestCase.java?rev=809315&r1=809314&r2=809315&view=diff ============================================================================== --- commons/proper/jexl/branches/2.0/src/test/java/org/apache/commons/jexl/JexlTestCase.java (original) +++ commons/proper/jexl/branches/2.0/src/test/java/org/apache/commons/jexl/JexlTestCase.java Sun Aug 30 11:29:27 2009 @@ -17,6 +17,7 @@ package org.apache.commons.jexl; +import java.lang.reflect.Constructor; import java.lang.reflect.Method; import java.util.Iterator; import java.util.Map; @@ -24,17 +25,21 @@ import java.util.ArrayList; import org.apache.commons.jexl.parser.JexlNode; +import org.apache.commons.jexl.parser.ASTJexlScript; import org.apache.commons.jexl.parser.ParseException; import junit.framework.TestCase; + /** - * Implements a runTest method to dynamically invoke a test, + * Implements runTest methods to dynamically instantiate and invoke a test, * wrapping the call with setUp(), tearDown() calls. * Eases the implementation of main methods to debug. */ public class JexlTestCase extends TestCase { /** No parameters signature for test run. */ private static final Class<?>[] noParms = {}; + /** String parameter signature for test run. */ + private static final Class<?>[] stringParm = {String.class}; /** A default Jexl engine instance. */ protected final JexlEngine JEXL = new JexlEngine(); @@ -67,9 +72,9 @@ JexlEngine jdbg = new JexlEngine(); Debugger dbg = new Debugger(); // iterate over all expression in cache - Iterator<Map.Entry<String,JexlNode>> inodes = jexl.cache.entrySet().iterator(); + Iterator<Map.Entry<String,ASTJexlScript>> inodes = jexl.cache.entrySet().iterator(); while (inodes.hasNext()) { - Map.Entry<String,JexlNode> entry = inodes.next(); + Map.Entry<String,ASTJexlScript> entry = inodes.next(); JexlNode node = entry.getValue(); // recreate expr string from AST dbg.debug(node); @@ -78,7 +83,7 @@ // recreate expr from string Expression exprdbg = jdbg.createExpression(expressiondbg); // make arg cause become the root cause - JexlNode root = ((ExpressionImpl) exprdbg).node; + JexlNode root = ((ExpressionImpl) exprdbg).script; while (root.jjtGetParent() != null) { root = root.jjtGetParent(); } @@ -101,8 +106,8 @@ } /** - * Creates a list of all descendants of a node including itself. - * @param node the node to flatten + * Creates a list of all descendants of a script including itself. + * @param script the script to flatten * @return the descendants-and-self list */ private static ArrayList<JexlNode> flatten(JexlNode node) { @@ -112,9 +117,9 @@ } /** - * Recursively adds all children of a node to the list of descendants. + * Recursively adds all children of a script to the list of descendants. * @param list the list of descendants to add to - * @param node the node & descendants to add + * @param script the script & descendants to add */ private static void flatten(List<JexlNode> list, JexlNode node) { int nc = node.jjtGetNumChildren(); @@ -127,8 +132,8 @@ /** * Checks the equality of 2 nodes by comparing all their descendants. * Descendants must have the same class and same image if non null. - * @param lhs the left node - * @param rhs the right node + * @param lhs the left script + * @param rhs the right script * @return null if true, a reason otherwise */ private static String checkEquals(JexlNode lhs, JexlNode rhs) { @@ -156,6 +161,11 @@ return null; } + /** + * Dynamically runs a test method. + * @param name the test method to run + * @throws Exception if anything goes wrong + */ public void runTest(String name) throws Exception { if ("runTest".equals(name)) { return; @@ -176,8 +186,52 @@ } } - /*public void testRunTest() throws Exception { - new JexlTestCase().runTest("runTest"); - }*/ + /** + * Instantiate and runs a test method; useful for debugging purpose. + * For instance: + * <code> + * public static void main(String[] args) throws Exception { + * runTest("BitwiseOperatorTest","testAndVariableNumberCoercion"); + * } + * </code> + * @param tname the test class name + * @param mname the test class method + * @throws Exception + */ + public static void runTest(String tname, String mname) throws Exception { + String testClassName = "org.apache.commons.jexl."+tname; + Class<JexlTestCase> clazz = null; + JexlTestCase test = null; + // find the class + try { + clazz = (Class<JexlTestCase>) Class.forName(testClassName); + } + catch(ClassNotFoundException xclass) { + fail("no such class: " + testClassName); + return; + } + // find ctor & instantiate + Constructor<JexlTestCase> ctor = null; + try { + ctor = clazz.getConstructor(stringParm); + test = ctor.newInstance("debug"); + } + catch(NoSuchMethodException xctor) { + // instantiate default class ctor + try { + test = clazz.newInstance(); + } + catch(Exception xany) { + fail("cant instantiate test: " + xany); + return; + } + } + catch(Exception xany) { + fail("cant instantiate test: " + xany); + return; + } + // Run the test + test.runTest(mname); + } }