package org.caudexorigo.jpt; import java.io.IOException; import java.io.Serializable; import java.io.Writer; import java.util.Map; import java.util.Map.Entry; import java.util.Set; import org.apache.commons.lang3.StringEscapeUtils; import org.apache.commons.lang3.StringUtils; import org.caudexorigo.ErrorAnalyser; import org.mvel2.MVEL; import org.mvel2.ParserContext; public class JptOutputExpressionNode extends JptNode { private static final String TEXT = "text "; // DEFAULT - "angle-brackets and ampersands with their HTML entity equivalents" private static final String STRUCTURE = "structure "; // "passes the replacement text through unchanged"; private boolean _isInSlot; private Serializable _compiled_exp; private final boolean escape; private String _evaluation_exp; JptOutputExpressionNode(String jpt_exp, boolean isInSlot) { _isInSlot = isInSlot; if (StringUtils.isBlank(jpt_exp)) { throw new IllegalArgumentException("tal expression can not be blank"); } _evaluation_exp = jpt_exp; if (jpt_exp.startsWith(TEXT)) { escape = true; _evaluation_exp = jpt_exp.substring(TEXT.length()); } else if (jpt_exp.startsWith(STRUCTURE)) { escape = false; _evaluation_exp = jpt_exp.substring(STRUCTURE.length()); } else { escape = true; } } public int getChildCount() { return 0; } public JptNode getChild(int i) { throw new IndexOutOfBoundsException("Output Expressions do not have children"); } public void render(Map<String, Object> context, Writer out) throws IOException { if (context == null) { throw new IllegalArgumentException("render context can not be null"); } String result = null; try { if (_compiled_exp == null) { ParserContext parser_context = ParserContext.create(); Set<Entry<String, Object>> ctx_entries = context.entrySet(); for (Entry<String, Object> entry : ctx_entries) { parser_context.addInput(entry.getKey(), entry.getValue().getClass()); } // Compile the expression. _compiled_exp = MVEL.compileExpression(_evaluation_exp, parser_context); } result = String.valueOf(MVEL.executeExpression(_compiled_exp, context)); String sout = escape ? StringEscapeUtils.escapeXml(result) : result; out.write(sout); } catch (Throwable t) { Throwable r = ErrorAnalyser.findRootCause(t); throw new RuntimeException(String.format("Error processing JptOutputExpressionNode:%nexpression: '%s';%ncontext: %s;%nmessage: '%s'", _evaluation_exp, context, r.getMessage())); } } public boolean isInSlot() { return _isInSlot; } }