/* * JasperReports - Free Java Reporting Library. * Copyright (C) 2001 - 2009 Jaspersoft Corporation. All rights reserved. * http://www.jaspersoft.com * * Unless you have purchased a commercial license agreement from Jaspersoft, * the following license terms apply: * * This program is part of JasperReports. * * JasperReports is free software: you can redistribute it and/or modify * it under the terms of the GNU Lesser General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * JasperReports is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with JasperReports. If not, see <http://www.gnu.org/licenses/>. */ package net.sf.jasperreports.compilers; import java.util.HashMap; import java.util.Iterator; import java.util.Map; import net.sf.jasperreports.engine.JRException; import net.sf.jasperreports.engine.JRExpression; import net.sf.jasperreports.engine.JRExpressionChunk; import net.sf.jasperreports.engine.JRRuntimeException; import net.sf.jasperreports.engine.fill.JREvaluator; import net.sf.jasperreports.engine.fill.JRFillField; import net.sf.jasperreports.engine.fill.JRFillParameter; import net.sf.jasperreports.engine.fill.JRFillVariable; import net.sf.jasperreports.engine.util.JRClassLoader; import net.sf.jasperreports.engine.util.JRStringUtil; import org.mozilla.javascript.Context; import org.mozilla.javascript.ContextFactory; import org.mozilla.javascript.EvaluatorException; import org.mozilla.javascript.Script; import org.mozilla.javascript.ScriptableObject; /** * JavaScript expression evaluator. * * @author Lucian Chirita (lucianc@users.sourceforge.net) * @version $Id: JavaScriptEvaluator.java 3717 2010-04-09 10:01:33Z teodord $ */ public class JavaScriptEvaluator extends JREvaluator { /** * Base JavaScript value class. */ public abstract static class JSValue { private final ScriptableObject scope; protected JSValue(ScriptableObject scope) { this.scope = scope; } protected final Object toJSValue(Object value) { return Context.javaToJS(value, scope); } } /** * Parameter class used in JavaScript expressions. */ public static class JSParameter extends JSValue { private final JRFillParameter parameter; public JSParameter(JRFillParameter parameter, ScriptableObject scope) { super(scope); this.parameter = parameter; } public Object getValue() { return toJSValue(parameter.getValue()); } } /** * Field class used in JavaScript expressions. */ public static class JSField extends JSValue { private final JRFillField field; public JSField(JRFillField field, ScriptableObject scope) { super(scope); this.field = field; } public Object getValue() { return toJSValue(field.getValue()); } public Object getOldValue() { return toJSValue(field.getOldValue()); } } /** * Variable class used in JavaScript expressions. */ public static class JSVariable extends JSValue { private final JRFillVariable variable; public JSVariable(JRFillVariable variable, ScriptableObject scope) { super(scope); this.variable = variable; } public Object getValue() { return toJSValue(variable.getValue()); } public Object getOldValue() { return toJSValue(variable.getOldValue()); } public Object getEstimatedValue() { return toJSValue(variable.getEstimatedValue()); } } protected static JavaScriptCompileData.Expression createJSExpression(JRExpression expression) { StringBuffer defaultExpr = new StringBuffer(); StringBuffer oldExpr = new StringBuffer(); StringBuffer estimatedExpr = new StringBuffer(); JRExpressionChunk[] chunks = expression.getChunks(); if (chunks == null) { defaultExpr.append("null"); oldExpr.append("null"); estimatedExpr.append("null"); } else { for (int i = 0; i < chunks.length; i++) { JRExpressionChunk chunk = chunks[i]; switch (chunk.getType()) { case JRExpressionChunk.TYPE_TEXT: defaultExpr.append(chunk.getText()); oldExpr.append(chunk.getText()); estimatedExpr.append(chunk.getText()); break; case JRExpressionChunk.TYPE_PARAMETER: String paramName = getParameterVar(chunk.getText()); defaultExpr.append(paramName); defaultExpr.append(".getValue()"); oldExpr.append(paramName); oldExpr.append(".getValue()"); estimatedExpr.append(paramName); estimatedExpr.append(".getValue()"); break; case JRExpressionChunk.TYPE_VARIABLE: String varName = getVariableVar(chunk.getText()); defaultExpr.append(varName); defaultExpr.append(".getValue()"); oldExpr.append(varName); oldExpr.append(".getOldValue()"); estimatedExpr.append(varName); estimatedExpr.append(".getEstimatedValue()"); break; case JRExpressionChunk.TYPE_FIELD: String fieldName = getFieldVar(chunk.getText()); defaultExpr.append(fieldName); defaultExpr.append(".getValue()"); oldExpr.append(fieldName); oldExpr.append(".getOldValue()"); estimatedExpr.append(fieldName); estimatedExpr.append(".getValue()"); break; } } } return new JavaScriptCompileData.Expression(expression.getValueClassName(), defaultExpr.toString(), estimatedExpr.toString(), oldExpr.toString()); } protected static String getParameterVar(String name) { return "param_" + JRStringUtil.getJavaIdentifier(name); } protected static String getVariableVar(String name) { return "var_" + JRStringUtil.getJavaIdentifier(name); } protected static String getFieldVar(String name) { return "field_" + JRStringUtil.getJavaIdentifier(name); } private final JavaScriptCompileData compileData; private Context context; private ScriptableObject scope; private Map loadedTypes = new HashMap(); private Map compiledExpressions = new HashMap(); /** * Create a JavaScript expression evaluator. * * @param compileData the report compile data */ public JavaScriptEvaluator(JavaScriptCompileData compileData) { this.compileData = compileData; } protected void customizedInit(Map parametersMap, Map fieldsMap, Map variablesMap) throws JRException { context = ContextFactory.getGlobal().enterContext();//TODO exit context context.getWrapFactory().setJavaPrimitiveWrap(false); scope = context.initStandardObjects(); for (Iterator it = parametersMap.entrySet().iterator(); it.hasNext();) { Map.Entry entry = (Map.Entry) it.next(); String name = (String) entry.getKey(); JRFillParameter param = (JRFillParameter) entry.getValue(); JSParameter jsParam = new JSParameter(param, scope); scope.put(getParameterVar(name), scope, jsParam); } for (Iterator it = variablesMap.entrySet().iterator(); it.hasNext();) { Map.Entry entry = (Map.Entry) it.next(); String name = (String) entry.getKey(); JRFillVariable var = (JRFillVariable) entry.getValue(); JSVariable jsVar = new JSVariable(var, scope); scope.put(getVariableVar(name), scope, jsVar); } if (fieldsMap != null) { for (Iterator it = fieldsMap.entrySet().iterator(); it.hasNext();) { Map.Entry entry = (Map.Entry) it.next(); String name = (String) entry.getKey(); JRFillField field = (JRFillField) entry.getValue(); JSField jsField = new JSField(field, scope); scope.put(getFieldVar(name), scope, jsField); } } } protected Object evaluate(int id) throws Throwable //NOSONAR { JavaScriptCompileData.Expression expression = getExpression(id); return evaluateExpression(expression.getJavaType(), expression.getDefaultExpression()); } protected Object evaluateEstimated(int id) throws Throwable //NOSONAR { JavaScriptCompileData.Expression expression = getExpression(id); return evaluateExpression(expression.getJavaType(), expression.getEstimatedExpression()); } protected Object evaluateOld(int id) throws Throwable //NOSONAR { JavaScriptCompileData.Expression expression = getExpression(id); return evaluateExpression(expression.getJavaType(), expression.getOldExpression()); } protected JavaScriptCompileData.Expression getExpression(int id) { return compileData.getExpression(id); } protected Object evaluateExpression(String type, String expression) { Script compiledExpression = getCompiledExpression(expression); Object value = compiledExpression.exec(context, scope); Class typeClass = getTypeClass(type); Object javaValue; try { javaValue = Context.jsToJava(value, typeClass); } catch (EvaluatorException e) { throw new JRRuntimeException(e); } return javaValue; } protected Script getCompiledExpression(String expression) { Script compiledExpression = (Script) compiledExpressions.get(expression); if (compiledExpression == null) { compiledExpression = context.compileString(expression, "expression", 0, null); compiledExpressions.put(expression, compiledExpression); } return compiledExpression; } protected Class getTypeClass(String type) { Class typeClass = (Class) loadedTypes.get(type); if (typeClass == null) { try { typeClass = JRClassLoader.loadClassForName(type); } catch (ClassNotFoundException e) { throw new JRRuntimeException("Unable to load class " + type, e); } loadedTypes.put(type, typeClass); } return typeClass; } }