Author: henrib
Date: Mon Sep 14 10:41:18 2015
New Revision: 1702901
URL: http://svn.apache.org/r1702901
Log:
JEXL:
Use derived interpreter instead of wrapping context in Jxlt engine so
operator/method overloads (user defined) can be called
Added:
commons/proper/jexl/trunk/src/main/java/org/apache/commons/jexl3/internal/TemplateInterpreter.java
(with props)
Modified:
commons/proper/jexl/trunk/src/main/java/org/apache/commons/jexl3/internal/Engine.java
commons/proper/jexl/trunk/src/main/java/org/apache/commons/jexl3/internal/TemplateEngine.java
commons/proper/jexl/trunk/src/main/java/org/apache/commons/jexl3/internal/TemplateScript.java
commons/proper/jexl/trunk/src/test/java/org/apache/commons/jexl3/ArithmeticOperatorTest.java
commons/proper/jexl/trunk/src/test/java/org/apache/commons/jexl3/IssuesTest.java
Modified:
commons/proper/jexl/trunk/src/main/java/org/apache/commons/jexl3/internal/Engine.java
URL:
http://svn.apache.org/viewvc/commons/proper/jexl/trunk/src/main/java/org/apache/commons/jexl3/internal/Engine.java?rev=1702901&r1=1702900&r2=1702901&view=diff
==============================================================================
---
commons/proper/jexl/trunk/src/main/java/org/apache/commons/jexl3/internal/Engine.java
(original)
+++
commons/proper/jexl/trunk/src/main/java/org/apache/commons/jexl3/internal/Engine.java
Mon Sep 14 10:41:18 2015
@@ -342,7 +342,7 @@ public class Engine extends JexlEngine {
* @return an Interpreter
*/
protected Interpreter createInterpreter(JexlContext context, Scope.Frame
frame) {
- return new Interpreter(this, context == null ? EMPTY_CONTEXT :
context, frame);
+ return new Interpreter(this, context, frame);
}
@Override
Modified:
commons/proper/jexl/trunk/src/main/java/org/apache/commons/jexl3/internal/TemplateEngine.java
URL:
http://svn.apache.org/viewvc/commons/proper/jexl/trunk/src/main/java/org/apache/commons/jexl3/internal/TemplateEngine.java?rev=1702901&r1=1702900&r2=1702901&view=diff
==============================================================================
---
commons/proper/jexl/trunk/src/main/java/org/apache/commons/jexl3/internal/TemplateEngine.java
(original)
+++
commons/proper/jexl/trunk/src/main/java/org/apache/commons/jexl3/internal/TemplateEngine.java
Mon Sep 14 10:41:18 2015
@@ -20,8 +20,6 @@ import org.apache.commons.jexl3.JexlCont
import org.apache.commons.jexl3.JexlException;
import org.apache.commons.jexl3.JexlInfo;
import org.apache.commons.jexl3.JxltEngine;
-import org.apache.commons.jexl3.introspection.JexlMethod;
-import org.apache.commons.jexl3.introspection.JexlUberspect;
import org.apache.commons.jexl3.parser.ASTJexlScript;
import org.apache.commons.jexl3.parser.JexlNode;
import org.apache.commons.jexl3.parser.StringParser;
@@ -30,7 +28,6 @@ import java.io.BufferedReader;
import java.io.IOException;
import java.io.Reader;
import java.io.StringReader;
-import java.io.Writer;
import java.util.ArrayList;
import java.util.Collections;
@@ -282,10 +279,7 @@ public final class TemplateEngine extend
@Override
public final TemplateExpression prepare(JexlContext context) {
- Scope.Frame frame = context instanceof TemplateContext
- ? ((TemplateContext) context).getFrame()
- : null;
- return prepare(frame, context);
+ return prepare(null, context);
}
/**
@@ -297,7 +291,7 @@ public final class TemplateEngine extend
*/
protected final TemplateExpression prepare(Scope.Frame frame,
JexlContext context) {
try {
- Interpreter interpreter = jexl.createInterpreter(context,
frame);
+ Interpreter interpreter = new TemplateInterpreter(jexl,
context, frame, null, null);
return prepare(interpreter);
} catch (JexlException xjexl) {
JexlException xuel = createException(xjexl.getInfo(),
"prepare", this, xjexl);
@@ -321,10 +315,7 @@ public final class TemplateEngine extend
@Override
public final Object evaluate(JexlContext context) {
- Scope.Frame frame = context instanceof TemplateContext
- ? ((TemplateContext) context).getFrame()
- : null;
- return evaluate(frame, context);
+ return evaluate(null, context);
}
/**
@@ -336,10 +327,10 @@ public final class TemplateEngine extend
*/
protected final Object evaluate(Scope.Frame frame, JexlContext
context) {
try {
- Interpreter interpreter = jexl.createInterpreter(context,
frame);
+ Interpreter interpreter = new TemplateInterpreter(jexl,
context, frame, null, null);
return evaluate(interpreter);
} catch (JexlException xjexl) {
- JexlException xuel = createException(xjexl.getInfo(),
"prepare", this, xjexl);
+ JexlException xuel = createException(xjexl.getInfo(),
"evaluate", this, xjexl);
if (jexl.isSilent()) {
jexl.logger.warn(xuel.getMessage(), xuel.getCause());
return null;
@@ -701,7 +692,7 @@ public final class TemplateEngine extend
* @param xany the exception
* @return an exception containing an explicit error message
*/
- private Exception createException(JexlInfo info, String action,
TemplateExpression expr, java.lang.Exception xany) {
+ static Exception createException(JexlInfo info, String action,
TemplateExpression expr, java.lang.Exception xany) {
StringBuilder strb = new StringBuilder("failed to ");
strb.append(action);
if (expr != null) {
@@ -994,146 +985,6 @@ public final class TemplateEngine extend
}
- /**
- * The type of context to use during evaluation of templates.
- * <p>This context exposes its writer as '$jexl' to the scripts.</p>
- * <p>public for introspection purpose.</p>
- */
- public final class TemplateContext implements JexlContext,
JexlContext.NamespaceResolver {
- /** The wrapped context. */
- private final JexlContext wrap;
- /** The array of TemplateEngine expressions. */
- private final TemplateExpression[] exprs;
- /** The writer used to output. */
- private final Writer writer;
- /** The call frame. */
- private final Scope.Frame frame;
-
- /**
- * Creates a TemplateScript context instance.
- * @param jcontext the base context
- * @param jframe the calling frame
- * @param expressions the list of TemplateExpression from the
TemplateScript to evaluate
- * @param out the output writer
- */
- protected TemplateContext(JexlContext jcontext, Scope.Frame jframe,
- TemplateExpression[] expressions, Writer out) {
- wrap = jcontext;
- frame = jframe;
- exprs = expressions;
- writer = out;
- }
-
- /**
- * Gets this context calling frame.
- * @return the engine frame
- */
- public Scope.Frame getFrame() {
- return frame;
- }
-
- @Override
- public Object get(String name) {
- if ("$jexl".equals(name)) {
- return writer;
- } else {
- return wrap.get(name);
- }
- }
-
- @Override
- public void set(String name, Object value) {
- wrap.set(name, value);
- }
-
- @Override
- public boolean has(String name) {
- return wrap.has(name);
- }
-
- @Override
- public Object resolveNamespace(String ns) {
- if ("jexl".equals(ns)) {
- return this;
- } else if (wrap instanceof JexlContext.NamespaceResolver) {
- return ((JexlContext.NamespaceResolver)
wrap).resolveNamespace(ns);
- } else {
- return null;
- }
- }
-
- /**
- * Includes a call to another template.
- * <p>Includes another template using this template initial context
and writer.</p>
- * @param script the TemplateScript to evaluate
- * @param args the arguments
- */
- public void include(TemplateScript script, Object... args) {
- script.evaluate(wrap, writer, args);
- }
-
- /**
- * Prints a unified expression evaluation result.
- * @param e the expression number
- */
- public void print(int e) {
- if (e < 0 || e >= exprs.length) {
- return;
- }
- TemplateExpression expr = exprs[e];
- if (expr.isDeferred()) {
- expr = expr.prepare(frame, wrap);
- }
- if (expr instanceof CompositeExpression) {
- printComposite((CompositeExpression) expr);
- } else {
- doPrint(expr.getInfo(), expr.evaluate(frame, this));
- }
- }
-
- /**
- * Prints a composite expression.
- * @param composite the composite expression
- */
- protected void printComposite(CompositeExpression composite) {
- TemplateExpression[] cexprs = composite.exprs;
- final int size = cexprs.length;
- Object value;
- for (int e = 0; e < size; ++e) {
- value = cexprs[e].evaluate(frame, this);
- doPrint(cexprs[e].getInfo(), value);
- }
- }
-
- /**
- * Prints to output.
- * <p>This will dynamically try to find the best suitable method in
the writer through uberspection.
- * Subclassing Writer by adding 'print' methods should be the
preferred way to specialize output.
- * </p>
- * @param info the source info
- * @param arg the argument to print out
- */
- private void doPrint(JexlInfo info, Object arg) {
- try {
- if (arg instanceof CharSequence) {
- writer.write(arg.toString());
- } else if (arg != null) {
- Object[] value = {arg};
- JexlUberspect uber = getEngine().getUberspect();
- JexlMethod method = uber.getMethod(writer, "print", value);
- if (method != null) {
- method.invoke(writer, value);
- } else {
- writer.write(arg.toString());
- }
- }
- } catch (java.io.IOException xio) {
- throw createException(info, "call print", null, xio);
- } catch (java.lang.Exception xany) {
- throw createException(info, "invoke print", null, xany);
- }
- }
- }
/**
* Whether a sequence starts with a given set of characters (following
spaces).
Added:
commons/proper/jexl/trunk/src/main/java/org/apache/commons/jexl3/internal/TemplateInterpreter.java
URL:
http://svn.apache.org/viewvc/commons/proper/jexl/trunk/src/main/java/org/apache/commons/jexl3/internal/TemplateInterpreter.java?rev=1702901&view=auto
==============================================================================
---
commons/proper/jexl/trunk/src/main/java/org/apache/commons/jexl3/internal/TemplateInterpreter.java
(added)
+++
commons/proper/jexl/trunk/src/main/java/org/apache/commons/jexl3/internal/TemplateInterpreter.java
Mon Sep 14 10:41:18 2015
@@ -0,0 +1,187 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.commons.jexl3.internal;
+
+import org.apache.commons.jexl3.JexlContext;
+import org.apache.commons.jexl3.JexlInfo;
+import org.apache.commons.jexl3.JxltEngine;
+import org.apache.commons.jexl3.internal.TemplateEngine.TemplateExpression;
+import org.apache.commons.jexl3.introspection.JexlMethod;
+import org.apache.commons.jexl3.introspection.JexlUberspect;
+import org.apache.commons.jexl3.parser.ASTArguments;
+import org.apache.commons.jexl3.parser.ASTFunctionNode;
+import org.apache.commons.jexl3.parser.ASTIdentifier;
+import org.apache.commons.jexl3.parser.JexlNode;
+import java.io.Writer;
+import java.util.Arrays;
+
+/**
+ * The type of interpreter to use during evaluation of templates.
+ * <p>This context exposes its writer as '$jexl' to the scripts.</p>
+ * <p>public for introspection purpose.</p>
+ */
+public class TemplateInterpreter extends Interpreter {
+ /** The array of template expressions. */
+ private final TemplateExpression[] exprs;
+ /** The writer used to output. */
+ private final Writer writer;
+
+ /**
+ * Creates a template interpreter instance.
+ * @param jexl the engine instance
+ * @param jcontext the base context
+ * @param jframe the calling frame
+ * @param expressions the list of TemplateExpression from the
TemplateScript to evaluate
+ * @param out the output writer
+ */
+ TemplateInterpreter(Engine jexl,
+ JexlContext jcontext, Scope.Frame jframe, TemplateExpression[]
expressions, Writer out) {
+ super(jexl, jcontext, jframe);
+ exprs = expressions;
+ writer = out;
+ }
+
+ /**
+ * Includes a call to another template.
+ * <p>
+ * Includes another template using this template initial context and
writer.</p>
+ * @param script the TemplateScript to evaluate
+ * @param args the arguments
+ */
+ public void include(TemplateScript script, Object... args) {
+ script.evaluate(context, writer, args);
+ }
+
+ /**
+ * Prints a unified expression evaluation result.
+ * @param e the expression number
+ */
+ public void print(int e) {
+ if (e < 0 || e >= exprs.length) {
+ return;
+ }
+ TemplateEngine.TemplateExpression expr = exprs[e];
+ if (expr.isDeferred()) {
+ expr = expr.prepare(frame, context);
+ }
+ if (expr instanceof TemplateEngine.CompositeExpression) {
+ printComposite((TemplateEngine.CompositeExpression) expr);
+ } else {
+ doPrint(expr.getInfo(), expr.evaluate(this));
+ }
+ }
+
+ /**
+ * Prints a composite expression.
+ * @param composite the composite expression
+ */
+ private void printComposite(TemplateEngine.CompositeExpression composite) {
+ TemplateEngine.TemplateExpression[] cexprs = composite.exprs;
+ final int size = cexprs.length;
+ Object value;
+ for (int e = 0; e < size; ++e) {
+ value = cexprs[e].evaluate(this);
+ doPrint(cexprs[e].getInfo(), value);
+ }
+ }
+
+ /**
+ * Prints to output.
+ * <p>
+ * This will dynamically try to find the best suitable method in the
writer through uberspection.
+ * Subclassing Writer by adding 'print' methods should be the preferred
way to specialize output.
+ * </p>
+ * @param info the source info
+ * @param arg the argument to print out
+ */
+ private void doPrint(JexlInfo info, Object arg) {
+ try {
+ if (writer != null) {
+ if (arg instanceof CharSequence) {
+ writer.write(arg.toString());
+ } else if (arg != null) {
+ Object[] value = {arg};
+ JexlUberspect uber = jexl.getUberspect();
+ JexlMethod method = uber.getMethod(writer, "print", value);
+ if (method != null) {
+ method.invoke(writer, value);
+ } else {
+ writer.write(arg.toString());
+ }
+ }
+ }
+ } catch (java.io.IOException xio) {
+ throw TemplateEngine.createException(info, "call print", null,
xio);
+ } catch (java.lang.Exception xany) {
+ throw TemplateEngine.createException(info, "invoke print", null,
xany);
+ }
+ }
+
+ @Override
+ protected Object resolveNamespace(String prefix, JexlNode node) {
+ return "jexl".equals(prefix)? this : super.resolveNamespace(prefix,
node);
+ }
+
+ @Override
+ protected Object visit(ASTFunctionNode node, Object data) {
+ int argc = node.jjtGetNumChildren();
+ if (argc > 2) {
+ // objectNode 0 is the prefix
+ String prefix = ((ASTIdentifier) node.jjtGetChild(0)).getName();
+ if ("jexl".equals(prefix)) {
+ ASTIdentifier functionNode = (ASTIdentifier)
node.jjtGetChild(1);
+ ASTArguments argNode = (ASTArguments) node.jjtGetChild(2);
+ String fname = functionNode.getName();
+ if ("print".equals(fname)) {
+ // evaluate the arguments
+ Object[] argv = visit(argNode, null);
+ print((Integer) argv[0]);
+ return null;
+ }
+ if ("include".equals(fname)) {
+ // evaluate the arguments
+ Object[] argv = visit(argNode, null);
+ if (argv != null && argv.length > 0) {
+ if (argv[0] instanceof TemplateScript) {
+ TemplateScript script = (TemplateScript) argv[0];
+ if (argv.length > 1) {
+ argv = Arrays.copyOfRange(argv, 1,
argv.length);
+ } else {
+ argv = null;
+ }
+ include(script, argv);
+ return null;
+ }
+ }
+ }
+ // fail safe
+ throw new JxltEngine.Exception(node.jexlInfo(), "no callable
template function " + fname, null);
+ }
+ }
+ return super.visit(node, data);
+ }
+
+ @Override
+ protected Object visit(ASTIdentifier node, Object data) {
+ String name = node.getName();
+ if ("$jexl".equals(name)) {
+ return writer;
+ }
+ return super.visit(node, data);
+ }
+
+}
Propchange:
commons/proper/jexl/trunk/src/main/java/org/apache/commons/jexl3/internal/TemplateInterpreter.java
------------------------------------------------------------------------------
svn:eol-style = native
Modified:
commons/proper/jexl/trunk/src/main/java/org/apache/commons/jexl3/internal/TemplateScript.java
URL:
http://svn.apache.org/viewvc/commons/proper/jexl/trunk/src/main/java/org/apache/commons/jexl3/internal/TemplateScript.java?rev=1702901&r1=1702900&r2=1702901&view=diff
==============================================================================
---
commons/proper/jexl/trunk/src/main/java/org/apache/commons/jexl3/internal/TemplateScript.java
(original)
+++
commons/proper/jexl/trunk/src/main/java/org/apache/commons/jexl3/internal/TemplateScript.java
Mon Sep 14 10:41:18 2015
@@ -21,7 +21,6 @@ import org.apache.commons.jexl3.JexlInfo
import org.apache.commons.jexl3.JxltEngine;
import org.apache.commons.jexl3.internal.TemplateEngine.Block;
import org.apache.commons.jexl3.internal.TemplateEngine.BlockType;
-import org.apache.commons.jexl3.internal.TemplateEngine.TemplateContext;
import org.apache.commons.jexl3.internal.TemplateEngine.TemplateExpression;
import org.apache.commons.jexl3.parser.ASTJexlScript;
import java.io.Reader;
@@ -175,10 +174,9 @@ public final class TemplateScript implem
@Override
public TemplateScript prepare(JexlContext context) {
Scope.Frame frame = script.createFrame((Object[]) null);
- TemplateContext tcontext = jxlt.new TemplateContext(context, frame,
exprs, null);
TemplateExpression[] immediates = new TemplateExpression[exprs.length];
for (int e = 0; e < exprs.length; ++e) {
- immediates[e] = exprs[e].prepare(frame, tcontext);
+ immediates[e] = exprs[e].prepare(frame, context);
}
return new TemplateScript(jxlt, prefix, source, script, immediates);
}
@@ -191,8 +189,7 @@ public final class TemplateScript implem
@Override
public void evaluate(JexlContext context, Writer writer, Object... args) {
Scope.Frame frame = script.createFrame(args);
- TemplateContext tcontext = jxlt.new TemplateContext(context, frame,
exprs, writer);
- Interpreter interpreter = jxlt.getEngine().createInterpreter(tcontext,
frame);
+ Interpreter interpreter = new TemplateInterpreter(jxlt.getEngine(),
context, frame, exprs, writer);
interpreter.interpret(script);
}
Modified:
commons/proper/jexl/trunk/src/test/java/org/apache/commons/jexl3/ArithmeticOperatorTest.java
URL:
http://svn.apache.org/viewvc/commons/proper/jexl/trunk/src/test/java/org/apache/commons/jexl3/ArithmeticOperatorTest.java?rev=1702901&r1=1702900&r2=1702901&view=diff
==============================================================================
---
commons/proper/jexl/trunk/src/test/java/org/apache/commons/jexl3/ArithmeticOperatorTest.java
(original)
+++
commons/proper/jexl/trunk/src/test/java/org/apache/commons/jexl3/ArithmeticOperatorTest.java
Mon Sep 14 10:41:18 2015
@@ -26,6 +26,7 @@ import java.util.Set;
import java.util.SortedSet;
import java.util.TreeSet;
import org.apache.commons.jexl3.junit.Asserter;
+import java.io.StringWriter;
import java.text.DecimalFormat;
import java.text.SimpleDateFormat;
import java.util.Arrays;
@@ -315,7 +316,6 @@ public class ArithmeticOperatorTest exte
}
}
-
protected Object setDateValue(Date date, String key, Object value)
throws Exception {
Calendar cal = Calendar.getInstance();
cal.setTime(date);
@@ -345,10 +345,6 @@ public class ArithmeticOperatorTest exte
public Object arraySet(Date date, String identifier, Object value)
throws Exception {
return setDateValue(date, identifier, value);
}
-
- public String format(Number number, String fmt) {
- return new DecimalFormat(fmt).format(number);
- }
}
public static class DateContext extends MapContext {
@@ -362,6 +358,10 @@ public class ArithmeticOperatorTest exte
SimpleDateFormat sdf = new SimpleDateFormat(fmt, locale);
return sdf.format(date);
}
+
+ public String format(Number number, String fmt) {
+ return new DecimalFormat(fmt).format(number);
+ }
}
@Test
@@ -412,6 +412,37 @@ public class ArithmeticOperatorTest exte
Assert.assertEquals("Wed 20 Aug 1969", s0);
jc.setLocale(Locale.FRANCE);
s0 = expr1.execute(jc, x0, "EEE dd MMM yyyy");
- Assert.assertEquals("mer. 20 août 1969", s0);
+ Assert.assertEquals("mer. 20 ao\u00fbt 1969", s0);
+ }
+
+ @Test
+ public void testFormatArithmeticJxlt() throws Exception {
+ Map<String, Object> ns = new HashMap<String, Object>();
+ ns.put("calc", Aggregate.class);
+ Calendar cal = Calendar.getInstance();
+ cal.set(1969, 7, 20);
+ Date x0 = cal.getTime();
+ String y0 = "yyy-MM-dd";
+ DateContext jc = new DateContext();
+ JexlEngine jexl = new
JexlBuilder().cache(32).namespaces(ns).arithmetic(new
DateArithmetic(true)).create();
+ JxltEngine jxlt = jexl.createJxltEngine();
+
+ JxltEngine.Template expr0 = jxlt.createTemplate("${x.format(y)}", "x",
"y");
+ StringWriter strw = new StringWriter();
+ expr0.evaluate(jc, strw, x0, y0);
+ String strws = strw.toString();
+ Assert.assertEquals("1969-08-20", strws);
+
+ expr0 = jxlt.createTemplate("${calc:sum(x .. y)}", "x", "y");
+ strw = new StringWriter();
+ expr0.evaluate(jc, strw, 1, 3);
+ strws = strw.toString();
+ Assert.assertEquals("6", strws);
+
+ JxltEngine.Template expr1 = jxlt.createTemplate("${jexl:include(s, x,
y)}", "s", "x", "y");
+ strw = new StringWriter();
+ expr1.evaluate(jc, strw, expr0, 1, 3);
+ strws = strw.toString();
+ Assert.assertEquals("6", strws);
}
}
Modified:
commons/proper/jexl/trunk/src/test/java/org/apache/commons/jexl3/IssuesTest.java
URL:
http://svn.apache.org/viewvc/commons/proper/jexl/trunk/src/test/java/org/apache/commons/jexl3/IssuesTest.java?rev=1702901&r1=1702900&r2=1702901&view=diff
==============================================================================
---
commons/proper/jexl/trunk/src/test/java/org/apache/commons/jexl3/IssuesTest.java
(original)
+++
commons/proper/jexl/trunk/src/test/java/org/apache/commons/jexl3/IssuesTest.java
Mon Sep 14 10:41:18 2015
@@ -24,12 +24,8 @@ import java.util.Map;
import org.apache.commons.jexl3.internal.introspection.Uberspect;
import java.io.File;
import java.net.URL;
-import java.text.DecimalFormat;
-import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Arrays;
-import java.util.Calendar;
-import java.util.Date;
import java.util.List;
import java.util.Set;
import org.junit.Assert;