package net.sf.jasperreports.engine.design; import java.text.SimpleDateFormat; import java.util.ArrayList; import java.util.Arrays; import java.util.Collection; import java.util.Collections; import java.util.Date; import java.util.HashMap; import java.util.Iterator; import java.util.List; import java.util.Map; import java.util.StringTokenizer; import net.sf.jasperreports.engine.JRException; import net.sf.jasperreports.engine.JRExpression; import net.sf.jasperreports.engine.JRExpressionChunk; import net.sf.jasperreports.engine.JRField; import net.sf.jasperreports.engine.JRParameter; import net.sf.jasperreports.engine.JRVariable; import net.sf.jasperreports.engine.util.JRStringUtil; public class JRClassGenerator { private static final int EXPR_MAX_COUNT_PER_METHOD = 100; protected static final String SOURCE_EXPRESSION_ID_START = "$JR_EXPR_ID="; protected static final int sOURCE_EXPRESSION_ID_START_LENGTH = "$JR_EXPR_ID=".length(); protected static final String SOURCE_EXPRESSION_ID_END = "$"; private static Map fieldPrefixMap = null; private static Map variablePrefixMap = null; private static Map methodSuffixMap = null; protected final JRSourceCompileTask sourceTask; protected Map parametersMap; protected Map fieldsMap; protected Map variablesMap; protected JRVariable[] variables; static { fieldPrefixMap = new HashMap(); fieldPrefixMap.put(new Byte((byte)1), "Old"); fieldPrefixMap.put(new Byte((byte)2), ""); fieldPrefixMap.put(new Byte((byte)3), ""); variablePrefixMap = new HashMap(); variablePrefixMap.put(new Byte((byte)1), "Old"); variablePrefixMap.put(new Byte((byte)2), "Estimated"); variablePrefixMap.put(new Byte((byte)3), ""); methodSuffixMap = new HashMap(); methodSuffixMap.put(new Byte((byte)1), "Old"); methodSuffixMap.put(new Byte((byte)2), "Estimated"); methodSuffixMap.put(new Byte((byte)3), ""); } protected JRClassGenerator(JRSourceCompileTask sourceTask) { this.sourceTask = sourceTask; this.parametersMap = sourceTask.getParametersMap(); this.fieldsMap = sourceTask.getFieldsMap(); this.variablesMap = sourceTask.getVariablesMap(); this.variables = sourceTask.getVariables(); } public static JRCompilationSourceCode generateClass(JRSourceCompileTask sourceTask) throws JRException { JRClassGenerator generator = new JRClassGenerator(sourceTask); return generator.generateClass(); } protected JRCompilationSourceCode generateClass() throws JRException { StringBuffer sb = new StringBuffer(); generateClassStart(sb); generateDeclarations(sb); generateInitMethod(sb); generateInitParamsMethod(sb); if (this.fieldsMap != null) generateInitFieldsMethod(sb); generateInitVarsMethod(sb); List expressions = this.sourceTask.getExpressions(); sb.append(generateMethod((byte)3, expressions)); if (this.sourceTask.isOnlyDefaultEvaluation()) { List empty = new ArrayList(); sb.append(generateMethod((byte)1, empty)); sb.append(generateMethod((byte)2, empty)); } else { sb.append(generateMethod((byte)1, expressions)); sb.append(generateMethod((byte)2, expressions)); } sb.append("}\n"); String code = sb.toString(); JRExpression[] lineExpressions = parseSourceLines(code); return new JRDefaultCompilationSourceCode(code, lineExpressions); } private void generateInitMethod(StringBuffer sb) { sb.append("\n"); sb.append("\n"); sb.append(" /**\n"); sb.append(" *\n"); sb.append(" */\n"); sb.append(" public void customizedInit(\n"); sb.append(" Map pm,\n"); sb.append(" Map fm,\n"); sb.append(" Map vm\n"); sb.append(" )\n"); sb.append(" {\n"); sb.append(" initParams(pm);\n"); if (this.fieldsMap != null) sb.append(" initFields(fm);\n"); sb.append(" initVars(vm);\n"); sb.append(" }\n"); sb.append("\n"); sb.append("\n"); } protected final void generateClassStart(StringBuffer sb) { sb.append("/*\n"); sb.append(" * Generated by JasperReports - "); sb.append((new SimpleDateFormat()).format(new Date())); sb.append("\n"); sb.append(" */\n"); sb.append("import net.sf.jasperreports.engine.*;\n"); sb.append("import net.sf.jasperreports.engine.fill.*;\n"); sb.append("\n"); sb.append("import java.util.*;\n"); sb.append("import java.math.*;\n"); sb.append("import java.text.*;\n"); sb.append("import java.io.*;\n"); sb.append("import java.net.*;\n"); sb.append("\n"); String[] imports = this.sourceTask.getImports(); if (imports != null && imports.length > 0) for (int i = 0; i < imports.length; i++) { sb.append("import "); sb.append(imports[i]); sb.append(";\n"); } sb.append("\n"); sb.append("\n"); sb.append("/**\n"); sb.append(" *\n"); sb.append(" */\n"); sb.append("public class "); sb.append(this.sourceTask.getUnitName()); sb.append(" extends JREvaluator\n"); sb.append("{\n"); sb.append("\n"); sb.append("\n"); sb.append(" /**\n"); sb.append(" *\n"); sb.append(" */\n"); } protected final void generateDeclarations(StringBuffer sb) { if (this.parametersMap != null && this.parametersMap.size() > 0) { Collection parameterNames = this.parametersMap.keySet(); for (Iterator it = parameterNames.iterator(); it.hasNext(); ) { sb.append(" private JRFillParameter parameter_"); sb.append(JRStringUtil.getLiteral(it.next())); sb.append(" = null;\n"); } } if (this.fieldsMap != null && this.fieldsMap.size() > 0) { Collection fieldNames = this.fieldsMap.keySet(); for (Iterator it = fieldNames.iterator(); it.hasNext(); ) { sb.append(" private JRFillField field_"); sb.append(JRStringUtil.getLiteral(it.next())); sb.append(" = null;\n"); } } if (this.variables != null && this.variables.length > 0) for (int i = 0; i < this.variables.length; i++) { sb.append(" private JRFillVariable variable_"); sb.append(JRStringUtil.getLiteral(this.variables[i].getName())); sb.append(" = null;\n"); } } protected final void generateInitParamsMethod(StringBuffer sb) throws JRException { Iterator parIt = null; if (this.parametersMap != null && this.parametersMap.size() > 0) { parIt = this.parametersMap.keySet().iterator(); } else { parIt = Collections.EMPTY_SET.iterator(); } generateInitParamsMethod(sb, parIt, 0); } protected final void generateInitFieldsMethod(StringBuffer sb) throws JRException { Iterator fieldIt = null; if (this.fieldsMap != null && this.fieldsMap.size() > 0) { fieldIt = this.fieldsMap.keySet().iterator(); } else { fieldIt = Collections.EMPTY_SET.iterator(); } generateInitFieldsMethod(sb, fieldIt, 0); } protected final void generateInitVarsMethod(StringBuffer sb) throws JRException { Iterator varIt = null; if (this.variables != null && this.variables.length > 0) { varIt = Arrays.asList(this.variables).iterator(); } else { varIt = Collections.EMPTY_LIST.iterator(); } generateInitVarsMethod(sb, varIt, 0); } private void generateInitParamsMethod(StringBuffer sb, Iterator it, int index) throws JRException { sb.append(" /**\n"); sb.append(" *\n"); sb.append(" */\n"); sb.append(" private void initParams"); if (index > 0) sb.append(index); sb.append("(Map pm)\n"); sb.append(" {\n"); for (int i = 0; i < 100 && it.hasNext(); i++) { String parameterName = it.next(); sb.append(" parameter_"); sb.append(JRStringUtil.getLiteral(parameterName)); sb.append(" = (JRFillParameter)pm.get(\""); sb.append(parameterName); sb.append("\");\n"); } if (it.hasNext()) { sb.append(" initParams"); sb.append(index + 1); sb.append("(pm);\n"); } sb.append(" }\n"); sb.append("\n"); sb.append("\n"); if (it.hasNext()) generateInitParamsMethod(sb, it, index + 1); } private void generateInitFieldsMethod(StringBuffer sb, Iterator it, int index) throws JRException { sb.append(" /**\n"); sb.append(" *\n"); sb.append(" */\n"); sb.append(" private void initFields"); if (index > 0) sb.append(index); sb.append("(Map fm)\n"); sb.append(" {\n"); for (int i = 0; i < 100 && it.hasNext(); i++) { String fieldName = it.next(); sb.append(" field_"); sb.append(JRStringUtil.getLiteral(fieldName)); sb.append(" = (JRFillField)fm.get(\""); sb.append(fieldName); sb.append("\");\n"); } if (it.hasNext()) { sb.append(" initFields"); sb.append(index + 1); sb.append("(fm);\n"); } sb.append(" }\n"); sb.append("\n"); sb.append("\n"); if (it.hasNext()) generateInitFieldsMethod(sb, it, index + 1); } private void generateInitVarsMethod(StringBuffer sb, Iterator it, int index) throws JRException { sb.append(" /**\n"); sb.append(" *\n"); sb.append(" */\n"); sb.append(" private void initVars"); if (index > 0) sb.append(index); sb.append("(Map vm)\n"); sb.append(" {\n"); for (int i = 0; i < 100 && it.hasNext(); i++) { String variableName = ((JRVariable)it.next()).getName(); sb.append(" variable_"); sb.append(JRStringUtil.getLiteral(variableName)); sb.append(" = (JRFillVariable)vm.get(\""); sb.append(variableName); sb.append("\");\n"); } if (it.hasNext()) { sb.append(" initVars"); sb.append(index + 1); sb.append("(vm);\n"); } sb.append(" }\n"); sb.append("\n"); sb.append("\n"); if (it.hasNext()) generateInitVarsMethod(sb, it, index + 1); } protected final String generateMethod(byte evaluationType, List expressionsList) throws JRException { StringBuffer sb = new StringBuffer(); if (expressionsList.size() > 0) { sb.append(generateMethod(expressionsList.listIterator(), 0, evaluationType)); } else { sb.append(" /**\n"); sb.append(" *\n"); sb.append(" */\n"); sb.append(" public Object evaluate"); sb.append((String)methodSuffixMap.get(new Byte(evaluationType))); sb.append("(int id) throws Throwable\n"); sb.append(" {\n"); sb.append(" return null;\n"); sb.append(" }\n"); sb.append("\n"); sb.append("\n"); } return sb.toString(); } private String generateMethod(Iterator it, int index, byte evaluationType) throws JRException { StringBuffer sb = new StringBuffer(); sb.append(" /**\n"); sb.append(" *\n"); sb.append(" */\n"); if (index > 0) { sb.append(" private Object evaluate"); sb.append((String)methodSuffixMap.get(new Byte(evaluationType))); sb.append(index); } else { sb.append(" public Object evaluate"); sb.append((String)methodSuffixMap.get(new Byte(evaluationType))); } sb.append("(int id) throws Throwable\n"); sb.append(" {\n"); sb.append(" Object value = null;\n"); sb.append("\n"); sb.append(" switch (id)\n"); sb.append(" {\n"); for (int i = 0; it.hasNext() && i < 100; i++) { JRExpression expression = it.next(); sb.append(" case "); sb.append(this.sourceTask.getExpressionId(expression)); sb.append(" : \n"); sb.append(" {\n"); sb.append(" value = ("); sb.append(expression.getValueClassName()); sb.append(")("); sb.append(generateExpression(expression, evaluationType)); sb.append(");"); appendExpressionComment(sb, expression); sb.append("\n"); sb.append(" break;\n"); sb.append(" }\n"); } sb.append(" default :\n"); sb.append(" {\n"); if (it.hasNext()) { sb.append(" value = evaluate"); sb.append((String)methodSuffixMap.get(new Byte(evaluationType))); sb.append(index + 1); sb.append("(id);\n"); } sb.append(" }\n"); sb.append(" }\n"); sb.append(" \n"); sb.append(" return value;\n"); sb.append(" }\n"); sb.append("\n"); sb.append("\n"); if (it.hasNext()) sb.append(generateMethod(it, index + 1, evaluationType)); return sb.toString(); } private String generateExpression(JRExpression expression, byte evaluationType) { JRParameter jrParameter = null; JRField jrField = null; JRVariable jrVariable = null; StringBuffer sb = new StringBuffer(); JRExpressionChunk[] chunks = expression.getChunks(); JRExpressionChunk chunk = null; String chunkText = null; if (chunks != null && chunks.length > 0) for (int i = 0; i < chunks.length; i++) { chunk = chunks[i]; chunkText = chunk.getText(); if (chunkText == null) chunkText = ""; switch (chunk.getType()) { case 1: appendExpressionText(expression, sb, chunkText); break; case 2: jrParameter = (JRParameter)this.parametersMap.get(chunkText); sb.append("(("); sb.append(jrParameter.getValueClassName()); sb.append(")parameter_"); sb.append(JRStringUtil.getLiteral(chunkText)); sb.append(".getValue())"); break; case 3: jrField = (JRField)this.fieldsMap.get(chunkText); sb.append("(("); sb.append(jrField.getValueClassName()); sb.append(")field_"); sb.append(JRStringUtil.getLiteral(chunkText)); sb.append(".get"); sb.append((String)fieldPrefixMap.get(new Byte(evaluationType))); sb.append("Value())"); break; case 4: jrVariable = (JRVariable)this.variablesMap.get(chunkText); sb.append("(("); sb.append(jrVariable.getValueClassName()); sb.append(")variable_"); sb.append(JRStringUtil.getLiteral(chunkText)); sb.append(".get"); sb.append((String)variablePrefixMap.get(new Byte(evaluationType))); sb.append("Value())"); break; case 5: sb.append("str(\""); sb.append(chunkText); sb.append("\")"); break; } } if (sb.length() == 0) sb.append("null"); return sb.toString(); } protected void appendExpressionText(JRExpression expression, StringBuffer sb, String chunkText) { StringTokenizer tokenizer = new StringTokenizer(chunkText, "\n", true); while (tokenizer.hasMoreTokens()) { String token = tokenizer.nextToken(); if (token.equals("\n")) appendExpressionComment(sb, expression); sb.append(token); } } protected void appendExpressionComment(StringBuffer sb, JRExpression expression) { sb.append("//"); sb.append("$JR_EXPR_ID="); sb.append(this.sourceTask.getExpressionId(expression)); sb.append("$"); } protected JRExpression[] parseSourceLines(String sourceCode) { List expressions = new ArrayList(); int start = 0; int end = sourceCode.indexOf('\n'); while (end >= 0) { JRExpression expression = null; if (start < end) { String line = sourceCode.substring(start, end); expression = getLineExpression(line); } expressions.add(expression); start = end + 1; end = sourceCode.indexOf('\n', start); } return expressions.toArray(new JRExpression[expressions.size()]); } protected JRExpression getLineExpression(String line) { JRExpression expression = null; int exprIdStart = line.indexOf("$JR_EXPR_ID="); if (exprIdStart >= 0) { exprIdStart += sOURCE_EXPRESSION_ID_START_LENGTH; int exprIdEnd = line.indexOf("$", exprIdStart); if (exprIdEnd >= 0) try { int exprId = Integer.parseInt(line.substring(exprIdStart, exprIdEnd)); expression = this.sourceTask.getExpression(exprId); } catch (NumberFormatException e) {} } return expression; } }