package org.docbag.expression.evaluator; import java.util.regex.Matcher; import java.util.regex.Pattern; import org.docbag.Context; import org.docbag.chart.jfree.ChartToSVGConverter; import org.docbag.expression.Expression; import org.docbag.expression.evaluator.json.JSONContentResolver; import org.docbag.table.TableToFOConverter; import org.docbag.template.TemplatePatterns; /** * {@link TemplatePatterns} aware implementation of a {@link ExpressionEvaluator} interface. * * <p>The {@link Expression} evaluation depends on the pattern used in the template:</p> * <pre> * 1. If the {@link TemplatePatterns#CONTEXT_PATTERN} was used then evaluation results in a * forward call to the {@link JSONContentResolver#context(String)} operation. * The returned object is then converted to it's String representation by simply calling toString() method. * 2. In case of {@link TemplatePatterns#CHART_PATTERN} the evaluator forwards execution to * {@link JSONContentResolver#chart(String)} operation. * In addition it also uses the {@link ChartToSVGConverter} to convert the {@link org.docbag.chart.Chart} into * it's String representation. * 3. If {@link TemplatePatterns#TABLE_PATTERN} is the matching pattern then the evaluator forwards call to * {@link JSONContentResolver#table(String)} operation. * In addition it also uses the {@link TableToFOConverter} to convert the {@link org.docbag.table.Table} into * it's String representation. * </pre> * * <p>Example:</p> * * <pre> * #{context('name')} * </pre> * * <p>The above expression will result in a single call to the {@link JSONContentResolver#context(String)} * operation with "name" as a parameter value.</p> * * <p>If the associated object is found it'll be converted to a String by invoking toString() method, otherwise * an {@link EvaluatorException} will be thrown.</p> * * <p>It is not possible to evaluate more complex expressions with this evaluator, for instance:</p> * <pre> * #{'Dynamic value follows: ' + context('name')} * </pre> * <p>will throw an {@link EvaluatorException}</p> * <p>If you require more complex functionality use {@link SpELExpressionEvaluator} instead.</p> * <p>It is, however, possible to achieve the above effect with the following expression:</p> * <pre> * Dynamic value follows: #{context('name')} * </pre> * * @author Jakub Torbicki */ public class PatternsAwareExpressionEvaluator implements ExpressionEvaluator<String, String> { private static final Pattern contextPattern = Pattern.compile(TemplatePatterns.CONTEXT_PATTERN); private static final Pattern chartPattern = Pattern.compile(TemplatePatterns.CHART_PATTERN); private static final Pattern tablePattern = Pattern.compile(TemplatePatterns.TABLE_PATTERN); private static final ChartToSVGConverter CHART_CONVERTER = new ChartToSVGConverter(); private static final TableToFOConverter TABLE_CONVERTER = new TableToFOConverter(); public String evaluate(Context context, Expression<String, String> expression) { if (expression.evaluated()) { return expression.getValue(); } Object o = evaluateExpression(new JSONContentResolver(context), expression.getSource()); if (o == null) { throw new EvaluatorException( new StringBuilder("Could not evaluate Expression. No Object found. Expression: '").append(expression) .append("' ").append(context).toString()); } return o.toString(); } public String evaluate(Expression<String, String> expression) { if (expression.evaluated()) { return expression.getValue(); } throw new EvaluatorException("Could not evaluate Expression without valid Context!"); } private Object evaluateExpression(JSONContentResolver content, String source) { Matcher matcher = contextPattern.matcher(source); if (matcher.find()) { return content.context(matcher.group(1)); } else { matcher = chartPattern.matcher(source); if (matcher.find()) { return CHART_CONVERTER.convert(content.chart(matcher.group(1))); } else { matcher = tablePattern.matcher(source); if (matcher.find()) { return TABLE_CONVERTER.convert(content.table(matcher.group(1))); } } } throw new EvaluatorException("No matching pattern found for expression: " + source); } }