001: /*
002: * ============================================================================
003: * GNU Lesser General Public License
004: * ============================================================================
005: *
006: * JasperReports - Free Java report-generating library.
007: * Copyright (C) 2001-2006 JasperSoft Corporation http://www.jaspersoft.com
008: *
009: * This library is free software; you can redistribute it and/or
010: * modify it under the terms of the GNU Lesser General Public
011: * License as published by the Free Software Foundation; either
012: * version 2.1 of the License, or (at your option) any later version.
013: *
014: * This library is distributed in the hope that it will be useful,
015: * but WITHOUT ANY WARRANTY; without even the implied warranty of
016: * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
017: * Lesser General Public License for more details.
018: *
019: * You should have received a copy of the GNU Lesser General Public
020: * License along with this library; if not, write to the Free Software
021: * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307, USA.
022: *
023: * JasperSoft Corporation
024: * 303 Second Street, Suite 450 North
025: * San Francisco, CA 94107
026: * http://www.jaspersoft.com
027: */
028:
029: /*
030: * Contributors:
031: * Gaganis Giorgos - gaganis@users.sourceforge.net
032: * Peter Severin - peter_p_s@users.sourceforge.net
033: */
034: package net.sf.jasperreports.engine.design;
035:
036: import java.text.SimpleDateFormat;
037: import java.util.ArrayList;
038: import java.util.Arrays;
039: import java.util.Collection;
040: import java.util.Collections;
041: import java.util.HashMap;
042: import java.util.Iterator;
043: import java.util.List;
044: import java.util.Map;
045: import java.util.StringTokenizer;
046:
047: import net.sf.jasperreports.engine.JRException;
048: import net.sf.jasperreports.engine.JRExpression;
049: import net.sf.jasperreports.engine.JRExpressionChunk;
050: import net.sf.jasperreports.engine.JRField;
051: import net.sf.jasperreports.engine.JRParameter;
052: import net.sf.jasperreports.engine.JRVariable;
053: import net.sf.jasperreports.engine.util.JRStringUtil;
054:
055: /**
056: * @author Teodor Danciu (teodord@users.sourceforge.net)
057: * @version $Id: JRClassGenerator.java 1731 2007-05-30 15:04:23Z lucianc $
058: */
059: public class JRClassGenerator {
060:
061: /**
062: *
063: */
064: private static final int EXPR_MAX_COUNT_PER_METHOD = 100;
065:
066: protected static final String SOURCE_EXPRESSION_ID_START = "$JR_EXPR_ID=";
067: protected static final int sOURCE_EXPRESSION_ID_START_LENGTH = SOURCE_EXPRESSION_ID_START
068: .length();
069: protected static final String SOURCE_EXPRESSION_ID_END = "$";
070:
071: private static Map fieldPrefixMap = null;
072: private static Map variablePrefixMap = null;
073: private static Map methodSuffixMap = null;
074:
075: static {
076: fieldPrefixMap = new HashMap();
077: fieldPrefixMap
078: .put(new Byte(JRExpression.EVALUATION_OLD), "Old");
079: fieldPrefixMap.put(new Byte(JRExpression.EVALUATION_ESTIMATED),
080: "");
081: fieldPrefixMap.put(new Byte(JRExpression.EVALUATION_DEFAULT),
082: "");
083:
084: variablePrefixMap = new HashMap();
085: variablePrefixMap.put(new Byte(JRExpression.EVALUATION_OLD),
086: "Old");
087: variablePrefixMap.put(new Byte(
088: JRExpression.EVALUATION_ESTIMATED), "Estimated");
089: variablePrefixMap.put(
090: new Byte(JRExpression.EVALUATION_DEFAULT), "");
091:
092: methodSuffixMap = new HashMap();
093: methodSuffixMap.put(new Byte(JRExpression.EVALUATION_OLD),
094: "Old");
095: methodSuffixMap.put(
096: new Byte(JRExpression.EVALUATION_ESTIMATED),
097: "Estimated");
098: methodSuffixMap.put(new Byte(JRExpression.EVALUATION_DEFAULT),
099: "");
100: }
101:
102: protected final JRSourceCompileTask sourceTask;
103:
104: protected Map parametersMap;
105: protected Map fieldsMap;
106: protected Map variablesMap;
107: protected JRVariable[] variables;
108:
109: protected JRClassGenerator(JRSourceCompileTask sourceTask) {
110: this .sourceTask = sourceTask;
111:
112: parametersMap = sourceTask.getParametersMap();
113: fieldsMap = sourceTask.getFieldsMap();
114: variablesMap = sourceTask.getVariablesMap();
115: variables = sourceTask.getVariables();
116: }
117:
118: /**
119: * Generates Java source code for evaluating the expressions of a report/dataset/crosstab.
120: *
121: * @param sourceTask the source task containing data required to generate the source file
122: * @return the source code
123: * @throws JRException
124: */
125: public static JRCompilationSourceCode generateClass(
126: JRSourceCompileTask sourceTask) throws JRException {
127: JRClassGenerator generator = new JRClassGenerator(sourceTask);
128: return generator.generateClass();
129: }
130:
131: protected JRCompilationSourceCode generateClass()
132: throws JRException {
133: StringBuffer sb = new StringBuffer();
134:
135: generateClassStart(sb);
136:
137: generateDeclarations(sb);
138:
139: generateInitMethod(sb);
140: generateInitParamsMethod(sb);
141: if (fieldsMap != null) {
142: generateInitFieldsMethod(sb);
143: }
144: generateInitVarsMethod(sb);
145:
146: List expressions = sourceTask.getExpressions();
147: sb.append(generateMethod(JRExpression.EVALUATION_DEFAULT,
148: expressions));
149: if (sourceTask.isOnlyDefaultEvaluation()) {
150: List empty = new ArrayList();
151: sb
152: .append(generateMethod(JRExpression.EVALUATION_OLD,
153: empty));
154: sb.append(generateMethod(JRExpression.EVALUATION_ESTIMATED,
155: empty));
156: } else {
157: sb.append(generateMethod(JRExpression.EVALUATION_OLD,
158: expressions));
159: sb.append(generateMethod(JRExpression.EVALUATION_ESTIMATED,
160: expressions));
161: }
162:
163: sb.append("}\n");
164:
165: String code = sb.toString();
166: JRExpression[] lineExpressions = parseSourceLines(code);
167: return new JRDefaultCompilationSourceCode(code, lineExpressions);
168: }
169:
170: private void generateInitMethod(StringBuffer sb) {
171: sb.append("\n");
172: sb.append("\n");
173: sb.append(" /**\n");
174: sb.append(" *\n");
175: sb.append(" */\n");
176: sb.append(" public void customizedInit(\n");
177: sb.append(" Map pm,\n");
178: sb.append(" Map fm,\n");
179: sb.append(" Map vm\n");
180: sb.append(" )\n");
181: sb.append(" {\n");
182: sb.append(" initParams(pm);\n");
183: if (fieldsMap != null) {
184: sb.append(" initFields(fm);\n");
185: }
186: sb.append(" initVars(vm);\n");
187: sb.append(" }\n");
188: sb.append("\n");
189: sb.append("\n");
190: }
191:
192: protected final void generateClassStart(StringBuffer sb) {
193: sb.append("/*\n");
194: sb.append(" * Generated by JasperReports - ");
195: sb
196: .append((new SimpleDateFormat())
197: .format(new java.util.Date()));
198: sb.append("\n");
199: sb.append(" */\n");
200: sb.append("import net.sf.jasperreports.engine.*;\n");
201: sb.append("import net.sf.jasperreports.engine.fill.*;\n");
202: sb.append("\n");
203: sb.append("import java.util.*;\n");
204: sb.append("import java.math.*;\n");
205: sb.append("import java.text.*;\n");
206: sb.append("import java.io.*;\n");
207: sb.append("import java.net.*;\n");
208: sb.append("\n");
209:
210: /* */
211: String[] imports = sourceTask.getImports();
212: if (imports != null && imports.length > 0) {
213: for (int i = 0; i < imports.length; i++) {
214: sb.append("import ");
215: sb.append(imports[i]);
216: sb.append(";\n");
217: }
218: }
219:
220: /* */
221: sb.append("\n");
222: sb.append("\n");
223: sb.append("/**\n");
224: sb.append(" *\n");
225: sb.append(" */\n");
226: sb.append("public class ");
227: sb.append(sourceTask.getUnitName());
228: sb.append(" extends JREvaluator\n");
229: sb.append("{\n");
230: sb.append("\n");
231: sb.append("\n");
232: sb.append(" /**\n");
233: sb.append(" *\n");
234: sb.append(" */\n");
235: }
236:
237: protected final void generateDeclarations(StringBuffer sb) {
238: if (parametersMap != null && parametersMap.size() > 0) {
239: Collection parameterNames = parametersMap.keySet();
240: for (Iterator it = parameterNames.iterator(); it.hasNext();) {
241: sb.append(" private JRFillParameter parameter_");
242: sb.append(JRStringUtil.getLiteral((String) it.next()));
243: sb.append(" = null;\n");
244: }
245: }
246:
247: if (fieldsMap != null && fieldsMap.size() > 0) {
248: Collection fieldNames = fieldsMap.keySet();
249: for (Iterator it = fieldNames.iterator(); it.hasNext();) {
250: sb.append(" private JRFillField field_");
251: sb.append(JRStringUtil.getLiteral((String) it.next()));
252: sb.append(" = null;\n");
253: }
254: }
255:
256: if (variables != null && variables.length > 0) {
257: for (int i = 0; i < variables.length; i++) {
258: sb.append(" private JRFillVariable variable_");
259: sb.append(JRStringUtil.getLiteral(variables[i]
260: .getName()));
261: sb.append(" = null;\n");
262: }
263: }
264: }
265:
266: protected final void generateInitParamsMethod(StringBuffer sb)
267: throws JRException {
268: Iterator parIt = null;
269: if (parametersMap != null && parametersMap.size() > 0) {
270: parIt = parametersMap.keySet().iterator();
271: } else {
272: parIt = Collections.EMPTY_SET.iterator();
273: }
274: generateInitParamsMethod(sb, parIt, 0);
275: }
276:
277: protected final void generateInitFieldsMethod(StringBuffer sb)
278: throws JRException {
279: Iterator fieldIt = null;
280: if (fieldsMap != null && fieldsMap.size() > 0) {
281: fieldIt = fieldsMap.keySet().iterator();
282: } else {
283: fieldIt = Collections.EMPTY_SET.iterator();
284: }
285: generateInitFieldsMethod(sb, fieldIt, 0);
286: }
287:
288: protected final void generateInitVarsMethod(StringBuffer sb)
289: throws JRException {
290: Iterator varIt = null;
291: if (variables != null && variables.length > 0) {
292: varIt = Arrays.asList(variables).iterator();
293: } else {
294: varIt = Collections.EMPTY_LIST.iterator();
295: }
296: generateInitVarsMethod(sb, varIt, 0);
297: }
298:
299: /**
300: *
301: */
302: private void generateInitParamsMethod(StringBuffer sb, Iterator it,
303: int index) throws JRException {
304: sb.append(" /**\n");
305: sb.append(" *\n");
306: sb.append(" */\n");
307: sb.append(" private void initParams");
308: if (index > 0) {
309: sb.append(index);
310: }
311: sb.append("(Map pm)\n");
312: sb.append(" {\n");
313: for (int i = 0; i < EXPR_MAX_COUNT_PER_METHOD && it.hasNext(); i++) {
314: String parameterName = (String) it.next();
315: sb.append(" parameter_");
316: sb.append(JRStringUtil.getLiteral(parameterName));
317: sb.append(" = (JRFillParameter)pm.get(\"");
318: sb.append(parameterName);
319: sb.append("\");\n");
320: }
321: if (it.hasNext()) {
322: sb.append(" initParams");
323: sb.append(index + 1);
324: sb.append("(pm);\n");
325: }
326: sb.append(" }\n");
327: sb.append("\n");
328: sb.append("\n");
329:
330: if (it.hasNext()) {
331: generateInitParamsMethod(sb, it, index + 1);
332: }
333: }
334:
335: /**
336: *
337: */
338: private void generateInitFieldsMethod(StringBuffer sb, Iterator it,
339: int index) throws JRException {
340: sb.append(" /**\n");
341: sb.append(" *\n");
342: sb.append(" */\n");
343: sb.append(" private void initFields");
344: if (index > 0) {
345: sb.append(index);
346: }
347: sb.append("(Map fm)\n");
348: sb.append(" {\n");
349: for (int i = 0; i < EXPR_MAX_COUNT_PER_METHOD && it.hasNext(); i++) {
350: String fieldName = (String) it.next();
351: sb.append(" field_");
352: sb.append(JRStringUtil.getLiteral(fieldName));
353: sb.append(" = (JRFillField)fm.get(\"");
354: sb.append(fieldName);
355: sb.append("\");\n");
356: }
357: if (it.hasNext()) {
358: sb.append(" initFields");
359: sb.append(index + 1);
360: sb.append("(fm);\n");
361: }
362: sb.append(" }\n");
363: sb.append("\n");
364: sb.append("\n");
365:
366: if (it.hasNext()) {
367: generateInitFieldsMethod(sb, it, index + 1);
368: }
369: }
370:
371: /**
372: *
373: */
374: private void generateInitVarsMethod(StringBuffer sb, Iterator it,
375: int index) throws JRException {
376: sb.append(" /**\n");
377: sb.append(" *\n");
378: sb.append(" */\n");
379: sb.append(" private void initVars");
380: if (index > 0) {
381: sb.append(index);
382: }
383: sb.append("(Map vm)\n");
384: sb.append(" {\n");
385: for (int i = 0; i < EXPR_MAX_COUNT_PER_METHOD && it.hasNext(); i++) {
386: String variableName = ((JRVariable) it.next()).getName();
387: sb.append(" variable_");
388: sb.append(JRStringUtil.getLiteral(variableName));
389: sb.append(" = (JRFillVariable)vm.get(\"");
390: sb.append(variableName);
391: sb.append("\");\n");
392: }
393: if (it.hasNext()) {
394: sb.append(" initVars");
395: sb.append(index + 1);
396: sb.append("(vm);\n");
397: }
398: sb.append(" }\n");
399: sb.append("\n");
400: sb.append("\n");
401:
402: if (it.hasNext()) {
403: generateInitVarsMethod(sb, it, index + 1);
404: }
405: }
406:
407: protected final String generateMethod(byte evaluationType,
408: List expressionsList) throws JRException {
409: StringBuffer sb = new StringBuffer();
410:
411: if (expressionsList.size() > 0) {
412: sb.append(generateMethod(expressionsList.listIterator(), 0,
413: evaluationType));
414: } else {
415: /* */
416: sb.append(" /**\n");
417: sb.append(" *\n");
418: sb.append(" */\n");
419: sb.append(" public Object evaluate");
420: sb.append((String) methodSuffixMap.get(new Byte(
421: evaluationType)));
422: sb.append("(int id) throws Throwable\n");
423: sb.append(" {\n");
424: sb.append(" return null;\n");
425: sb.append(" }\n");
426: sb.append("\n");
427: sb.append("\n");
428: }
429:
430: return sb.toString();
431: }
432:
433: /**
434: *
435: */
436: private String generateMethod(Iterator it, int index,
437: byte evaluationType) throws JRException {
438: StringBuffer sb = new StringBuffer();
439:
440: /* */
441: sb.append(" /**\n");
442: sb.append(" *\n");
443: sb.append(" */\n");
444: if (index > 0) {
445: sb.append(" private Object evaluate");
446: sb.append((String) methodSuffixMap.get(new Byte(
447: evaluationType)));
448: sb.append(index);
449: } else {
450: sb.append(" public Object evaluate");
451: sb.append((String) methodSuffixMap.get(new Byte(
452: evaluationType)));
453: }
454: sb.append("(int id) throws Throwable\n");
455: sb.append(" {\n");
456: sb.append(" Object value = null;\n");
457: sb.append("\n");
458: sb.append(" switch (id)\n");
459: sb.append(" {\n");
460:
461: for (int i = 0; it.hasNext() && i < EXPR_MAX_COUNT_PER_METHOD; i++) {
462: JRExpression expression = (JRExpression) it.next();
463:
464: sb.append(" case ");
465: sb.append(sourceTask.getExpressionId(expression));
466: sb.append(" : \n");
467: sb.append(" {\n");
468: sb.append(" value = (");
469: sb.append(expression.getValueClassName());
470: sb.append(")(");
471: sb.append(this .generateExpression(expression,
472: evaluationType));
473: sb.append(");");
474: sb.append(expressionComment(expression));
475: sb.append("\n");
476: sb.append(" break;\n");
477: sb.append(" }\n");
478: }
479:
480: /* */
481: sb.append(" default :\n");
482: sb.append(" {\n");
483: if (it.hasNext()) {
484: sb.append(" value = evaluate");
485: sb.append((String) methodSuffixMap.get(new Byte(
486: evaluationType)));
487: sb.append(index + 1);
488: sb.append("(id);\n");
489: }
490: sb.append(" }\n");
491: sb.append(" }\n");
492: sb.append(" \n");
493: sb.append(" return value;\n");
494: sb.append(" }\n");
495: sb.append("\n");
496: sb.append("\n");
497:
498: if (it.hasNext()) {
499: sb.append(generateMethod(it, index + 1, evaluationType));
500: }
501:
502: return sb.toString();
503: }
504:
505: /**
506: *
507: */
508: private String generateExpression(JRExpression expression,
509: byte evaluationType) {
510: JRParameter jrParameter = null;
511: JRField jrField = null;
512: JRVariable jrVariable = null;
513:
514: StringBuffer sb = new StringBuffer();
515:
516: JRExpressionChunk[] chunks = expression.getChunks();
517: JRExpressionChunk chunk = null;
518: String chunkText = null;
519: if (chunks != null && chunks.length > 0) {
520: for (int i = 0; i < chunks.length; i++) {
521: chunk = chunks[i];
522:
523: chunkText = chunk.getText();
524: if (chunkText == null) {
525: chunkText = "";
526: }
527:
528: switch (chunk.getType()) {
529: case JRExpressionChunk.TYPE_TEXT: {
530: appendExpressionText(expression, sb, chunkText);
531: break;
532: }
533: case JRExpressionChunk.TYPE_PARAMETER: {
534: jrParameter = (JRParameter) parametersMap
535: .get(chunkText);
536:
537: sb.append("((");
538: sb.append(jrParameter.getValueClassName());
539: sb.append(")parameter_");
540: sb.append(JRStringUtil.getLiteral(chunkText));
541: sb.append(".getValue())");
542:
543: break;
544: }
545: case JRExpressionChunk.TYPE_FIELD: {
546: jrField = (JRField) fieldsMap.get(chunkText);
547:
548: sb.append("((");
549: sb.append(jrField.getValueClassName());
550: sb.append(")field_");
551: sb.append(JRStringUtil.getLiteral(chunkText));
552: sb.append(".get");
553: sb.append((String) fieldPrefixMap.get(new Byte(
554: evaluationType)));
555: sb.append("Value())");
556:
557: break;
558: }
559: case JRExpressionChunk.TYPE_VARIABLE: {
560: jrVariable = (JRVariable) variablesMap
561: .get(chunkText);
562:
563: sb.append("((");
564: sb.append(jrVariable.getValueClassName());
565: sb.append(")variable_");
566: sb.append(JRStringUtil.getLiteral(chunkText));
567: sb.append(".get");
568: sb.append((String) variablePrefixMap.get(new Byte(
569: evaluationType)));
570: sb.append("Value())");
571:
572: break;
573: }
574: case JRExpressionChunk.TYPE_RESOURCE: {
575: sb.append("str(\"");
576: sb.append(chunkText);
577: sb.append("\")");
578:
579: break;
580: }
581: }
582: }
583: }
584:
585: if (sb.length() == 0) {
586: sb.append("null");
587: }
588:
589: return sb.toString();
590: }
591:
592: protected void appendExpressionText(JRExpression expression,
593: StringBuffer sb, String chunkText) {
594: StringTokenizer tokenizer = new StringTokenizer(chunkText, "\n");
595: if (tokenizer.hasMoreTokens()) {
596: sb.append(tokenizer.nextToken());
597: while (tokenizer.hasMoreTokens()) {
598: sb.append(expressionComment(expression));
599: sb.append("\n");
600: sb.append(tokenizer.nextToken());
601: }
602: }
603: }
604:
605: protected String expressionComment(JRExpression expression) {
606: StringBuffer sb = new StringBuffer(24);
607: sb.append("//");
608: sb.append(SOURCE_EXPRESSION_ID_START);
609: sb.append(sourceTask.getExpressionId(expression));
610: sb.append(SOURCE_EXPRESSION_ID_END);
611: return sb.toString();
612: }
613:
614: protected JRExpression[] parseSourceLines(String sourceCode) {
615: List expressions = new ArrayList();
616: int start = 0;
617: int end = sourceCode.indexOf('\n');
618: while (end >= 0) {
619: JRExpression expression = null;
620: if (start < end) {
621: String line = sourceCode.substring(start, end);
622: expression = getLineExpression(line);
623: }
624: expressions.add(expression);
625:
626: start = end + 1;
627: end = sourceCode.indexOf('\n', start);
628: }
629: return (JRExpression[]) expressions
630: .toArray(new JRExpression[expressions.size()]);
631: }
632:
633: protected JRExpression getLineExpression(String line) {
634: JRExpression expression = null;
635: int exprIdStart = line.indexOf(SOURCE_EXPRESSION_ID_START);
636: if (exprIdStart >= 0) {
637: exprIdStart += sOURCE_EXPRESSION_ID_START_LENGTH;
638: int exprIdEnd = line.indexOf("$", exprIdStart);
639: if (exprIdEnd >= 0) {
640: try {
641: int exprId = Integer.parseInt(line.substring(
642: exprIdStart, exprIdEnd));
643: expression = sourceTask.getExpression(exprId);
644: } catch (NumberFormatException e) {
645: // ignore
646: }
647: }
648: }
649: return expression;
650: }
651:
652: }
|