org.apache.commons.jexl3.internal.TemplateInterpreter Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of commons-jexl3 Show documentation
Show all versions of commons-jexl3 Show documentation
The Apache Commons JEXL library is an implementation of the JSTL Expression Language with extensions.
/*
* 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.
* This context exposes its writer as '$jexl' to the scripts.
* public for introspection purpose.
*/
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.
*
* Includes another template using this template initial context and writer.
* @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.
*
* 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.
*
* @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);
}
}
© 2015 - 2024 Weber Informatics LLC | Privacy Policy