001: /*
002: * Copyright (C) 2006 Erik Swenson - erik@oreports.com
003: *
004: * This program is free software; you can redistribute it and/or modify it
005: * under the terms of the GNU General Public License as published by the Free
006: * Software Foundation; either version 2 of the License, or (at your option)
007: * any later version.
008: *
009: * This program is distributed in the hope that it will be useful, but WITHOUT
010: * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
011: * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
012: * more details.
013: *
014: * You should have received a copy of the GNU General Public License along with
015: * this program; if not, write to the Free Software Foundation, Inc., 59 Temple
016: * Place - Suite 330, Boston, MA 02111-1307, USA.
017: *
018: */
019:
020: package org.efs.openreports.engine;
021:
022: import java.io.ByteArrayInputStream;
023: import java.io.ByteArrayOutputStream;
024: import java.sql.Connection;
025: import java.sql.PreparedStatement;
026: import java.sql.ResultSet;
027: import java.util.ArrayList;
028: import java.util.HashMap;
029: import java.util.Iterator;
030: import java.util.List;
031: import java.util.Map;
032:
033: import net.sf.jasperreports.engine.JRAbstractExporter;
034: import net.sf.jasperreports.engine.JREmptyDataSource;
035: import net.sf.jasperreports.engine.JRException;
036: import net.sf.jasperreports.engine.JRExporterParameter;
037: import net.sf.jasperreports.engine.JRField;
038: import net.sf.jasperreports.engine.JRParameter;
039: import net.sf.jasperreports.engine.JasperCompileManager;
040: import net.sf.jasperreports.engine.JasperFillManager;
041: import net.sf.jasperreports.engine.JasperPrint;
042: import net.sf.jasperreports.engine.JasperReport;
043: import net.sf.jasperreports.engine.data.JRBeanCollectionDataSource;
044: import net.sf.jasperreports.engine.design.JRDesignBand;
045: import net.sf.jasperreports.engine.design.JRDesignExpression;
046: import net.sf.jasperreports.engine.design.JRDesignField;
047: import net.sf.jasperreports.engine.design.JRDesignQuery;
048: import net.sf.jasperreports.engine.design.JRDesignStaticText;
049: import net.sf.jasperreports.engine.design.JRDesignTextField;
050: import net.sf.jasperreports.engine.design.JasperDesign;
051: import net.sf.jasperreports.engine.export.JExcelApiExporter;
052: import net.sf.jasperreports.engine.export.JRCsvExporter;
053: import net.sf.jasperreports.engine.export.JRHtmlExporter;
054: import net.sf.jasperreports.engine.export.JRHtmlExporterParameter;
055: import net.sf.jasperreports.engine.export.JRPdfExporter;
056: import net.sf.jasperreports.engine.export.JRRtfExporter;
057: import net.sf.jasperreports.engine.export.JRTextExporter;
058: import net.sf.jasperreports.engine.export.JRTextExporterParameter;
059: import net.sf.jasperreports.engine.export.JRXlsExporter;
060: import net.sf.jasperreports.engine.export.JRXlsExporterParameter;
061: import net.sf.jasperreports.engine.query.JRXPathQueryExecuterFactory;
062: import net.sf.jasperreports.engine.util.JRLoader;
063: import net.sf.jasperreports.engine.util.JRQueryExecuter;
064: import net.sf.jasperreports.engine.util.JRXmlUtils;
065:
066: import org.apache.commons.beanutils.DynaProperty;
067: import org.apache.commons.beanutils.RowSetDynaClass;
068: import org.apache.log4j.Logger;
069: import org.efs.openreports.ReportConstants.ExportType;
070: import org.efs.openreports.engine.input.ReportEngineInput;
071: import org.efs.openreports.engine.output.JasperReportEngineOutput;
072: import org.efs.openreports.engine.output.ReportEngineOutput;
073: import org.efs.openreports.objects.Report;
074: import org.efs.openreports.objects.ReportDataSource;
075: import org.efs.openreports.objects.ReportExportOption;
076: import org.efs.openreports.objects.ReportParameter;
077: import org.efs.openreports.objects.ReportParameterMap;
078: import org.efs.openreports.providers.DataSourceProvider;
079: import org.efs.openreports.providers.DirectoryProvider;
080: import org.efs.openreports.providers.PropertiesProvider;
081: import org.efs.openreports.providers.ProviderException;
082: import org.efs.openreports.util.LocalStrings;
083: import org.efs.openreports.util.ORUtil;
084: import org.w3c.dom.Document;
085:
086: /**
087: * JasperReports ReportEngine implementation. Report generation is separated
088: * into fillReport and exportReport methods in order to provide direct access
089: * to the JasperPrint object when required.
090: *
091: * @author Erik Swenson
092: *
093: */
094: public class JasperReportEngine extends ReportEngine {
095: protected static Logger log = Logger
096: .getLogger(JasperReportEngine.class.getName());
097:
098: public JasperReportEngine(DataSourceProvider dataSourceProvider,
099: DirectoryProvider directoryProvider,
100: PropertiesProvider propertiesProvider) {
101: super (dataSourceProvider, directoryProvider, propertiesProvider);
102: }
103:
104: public ReportEngineOutput generateReport(ReportEngineInput input)
105: throws ProviderException {
106: JasperPrint jasperPrint = fillReport(input);
107:
108: ReportEngineOutput engineOutput = exportReport(jasperPrint,
109: input.getExportType(), input.getReport()
110: .getReportExportOption(), input.getImagesMap(),
111: input.isInlineImages());
112:
113: return engineOutput;
114: }
115:
116: public JasperPrint fillReport(ReportEngineInput input)
117: throws ProviderException {
118: Connection conn = null;
119:
120: Report report = input.getReport();
121: Map<String, Object> parameters = input.getParameters();
122:
123: ReportDataSource dataSource = report.getDataSource();
124:
125: try {
126: JasperReport jr = null;
127:
128: if (report.isQueryReport())
129: return fillQueryReport(report, parameters, input
130: .getExportType());
131:
132: jr = (JasperReport) JRLoader.loadObject(directoryProvider
133: .getReportDirectory()
134: + report.getFile());
135:
136: List subReports = report.getSubReportParameters();
137: if (subReports != null && subReports.size() > 0) {
138: Iterator iterator = report.getSubReportParameters()
139: .iterator();
140: while (iterator.hasNext()) {
141: ReportParameterMap rpMap = (ReportParameterMap) iterator
142: .next();
143:
144: JasperReport subReport = (JasperReport) JRLoader
145: .loadObject(directoryProvider
146: .getReportDirectory()
147: + rpMap.getReportParameter()
148: .getData());
149:
150: parameters.put(
151: rpMap.getReportParameter().getName(),
152: subReport);
153: }
154: }
155:
156: JasperPrint jp = null;
157:
158: // create new HashMap to send to JasperReports in order to
159: // fix serialization problems
160: Map<String, Object> jasperReportMap = new HashMap<String, Object>(
161: parameters);
162:
163: if (input.getXmlInput() != null) {
164: ByteArrayInputStream stream = new ByteArrayInputStream(
165: input.getXmlInput().getBytes());
166: Document document = JRXmlUtils.parse(stream);
167:
168: jasperReportMap
169: .put(
170: JRXPathQueryExecuterFactory.PARAMETER_XML_DATA_DOCUMENT,
171: document);
172:
173: jp = JasperFillManager.fillReport(jr, jasperReportMap);
174: } else if (dataSource == null) {
175: jp = JasperFillManager.fillReport(jr, jasperReportMap,
176: new JREmptyDataSource());
177: } else {
178: conn = dataSourceProvider.getConnection(dataSource
179: .getId());
180: jp = JasperFillManager.fillReport(jr, jasperReportMap,
181: conn);
182: }
183:
184: if (jp == null || jp.getPages().size() < 1)
185: throw new ProviderException(
186: LocalStrings.ERROR_REPORT_EMPTY);
187:
188: return jp;
189: } catch (Exception e) {
190: if (!e.getMessage().equals(LocalStrings.ERROR_REPORT_EMPTY))
191: log.error("JasperReportEngine.fillReport", e);
192: throw new ProviderException(e.getMessage());
193: } finally {
194: try {
195: if (conn != null)
196: conn.close();
197: } catch (Exception ex) {
198: log.error("Error closing connection: "
199: + ex.getMessage());
200: }
201: }
202: }
203:
204: public ReportEngineOutput exportReport(JasperPrint jasperPrint,
205: ExportType exportType, ReportExportOption exportOptions,
206: Map imagesMap, boolean inlineImages)
207: throws ProviderException {
208: JasperReportEngineOutput engineOutput = new JasperReportEngineOutput();
209: ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
210:
211: JRAbstractExporter exporter = null;
212:
213: try {
214: if (exportType == ExportType.PDF) {
215: engineOutput
216: .setContentType(ReportEngineOutput.CONTENT_TYPE_PDF);
217:
218: exporter = new JRPdfExporter();
219: } else if (exportType == ExportType.XLS
220: || exportType == ExportType.EXCEL) {
221: engineOutput
222: .setContentType(ReportEngineOutput.CONTENT_TYPE_XLS);
223:
224: if (exportType == ExportType.XLS) {
225: exporter = new JRXlsExporter();
226: } else if (exportType == ExportType.EXCEL) {
227: exporter = new JExcelApiExporter();
228: }
229:
230: exporter
231: .setParameter(
232: JRXlsExporterParameter.IS_REMOVE_EMPTY_SPACE_BETWEEN_ROWS,
233: new Boolean(
234: exportOptions
235: .isXlsRemoveEmptySpaceBetweenRows()));
236:
237: exporter.setParameter(
238: JRXlsExporterParameter.IS_ONE_PAGE_PER_SHEET,
239: new Boolean(exportOptions
240: .isXlsOnePagePerSheet()));
241:
242: exporter.setParameter(
243: JRXlsExporterParameter.IS_DETECT_CELL_TYPE,
244: new Boolean(exportOptions
245: .isXlsAutoDetectCellType()));
246:
247: exporter
248: .setParameter(
249: JRXlsExporterParameter.IS_WHITE_PAGE_BACKGROUND,
250: new Boolean(exportOptions
251: .isXlsWhitePageBackground()));
252: } else if (exportType == ExportType.CSV) {
253: engineOutput
254: .setContentType(ReportEngineOutput.CONTENT_TYPE_CSV);
255:
256: exporter = new JRCsvExporter();
257: } else if (exportType == ExportType.TEXT) {
258: engineOutput
259: .setContentType(ReportEngineOutput.CONTENT_TYPE_TEXT);
260:
261: exporter = new JRTextExporter();
262: exporter.setParameter(
263: JRTextExporterParameter.CHARACTER_WIDTH,
264: new Integer(10));
265: exporter.setParameter(
266: JRTextExporterParameter.CHARACTER_HEIGHT,
267: new Integer(10));
268: } else if (exportType == ExportType.RTF) {
269: engineOutput
270: .setContentType(ReportEngineOutput.CONTENT_TYPE_RTF);
271:
272: exporter = new JRRtfExporter();
273: } else {
274: engineOutput
275: .setContentType(ReportEngineOutput.CONTENT_TYPE_HTML);
276:
277: exporter = new JRHtmlExporter();
278:
279: exporter
280: .setParameter(
281: JRHtmlExporterParameter.IS_REMOVE_EMPTY_SPACE_BETWEEN_ROWS,
282: new Boolean(
283: exportOptions
284: .isHtmlRemoveEmptySpaceBetweenRows()));
285:
286: exporter
287: .setParameter(
288: JRHtmlExporterParameter.IS_USING_IMAGES_TO_ALIGN,
289: new Boolean(exportOptions
290: .isHtmlUsingImagesToAlign()));
291:
292: exporter
293: .setParameter(
294: JRHtmlExporterParameter.IS_WHITE_PAGE_BACKGROUND,
295: new Boolean(exportOptions
296: .isHtmlWhitePageBackground()));
297:
298: exporter
299: .setParameter(
300: JRHtmlExporterParameter.IS_WRAP_BREAK_WORD,
301: new Boolean(exportOptions
302: .isHtmlWrapBreakWord()));
303:
304: if (imagesMap == null)
305: imagesMap = new HashMap();
306: exporter.setParameter(
307: JRHtmlExporterParameter.IMAGES_MAP, imagesMap);
308:
309: if (inlineImages) {
310: exporter.setParameter(
311: JRHtmlExporterParameter.IMAGES_URI, "cid:");
312: } else {
313: //see ImageLoaderAction for more information
314: exporter.setParameter(
315: JRHtmlExporterParameter.IMAGES_URI,
316: "imageLoader.action?imageName=");
317: }
318: }
319:
320: exporter.setParameter(JRExporterParameter.JASPER_PRINT,
321: jasperPrint);
322: exporter.setParameter(JRExporterParameter.OUTPUT_STREAM,
323: outputStream);
324: exporter.exportReport();
325: } catch (Exception e) {
326: throw new ProviderException(e.toString());
327: }
328:
329: engineOutput.setImagesMap(imagesMap);
330: engineOutput.setContent(outputStream.toByteArray());
331:
332: return engineOutput;
333: }
334:
335: /*
336: * Creates a default JasperPrint from a QueryReport. This method is used when
337: * a scheduled QueryReport is executed.
338: */
339: private JasperPrint fillQueryReport(Report report,
340: Map<String, Object> map, ExportType exportType)
341: throws Exception {
342: Connection conn = null;
343: PreparedStatement pStmt = null;
344: ResultSet rs = null;
345:
346: // create new HashMap to send to JasperReports in order to
347: // fix serialization problems
348: Map<String, Object> parameters = new HashMap<String, Object>(
349: map);
350:
351: List results = null;
352: DynaProperty[] properties = null;
353:
354: try {
355: ReportDataSource dataSource = report.getDataSource();
356: conn = dataSourceProvider.getConnection(dataSource.getId());
357:
358: if (parameters == null || parameters.isEmpty()) {
359: pStmt = conn.prepareStatement(report.getQuery());
360: } else {
361: // Use JasperReports Query logic to parse parameters in chart
362: // queries
363:
364: JRDesignQuery query = new JRDesignQuery();
365: query.setText(report.getQuery());
366:
367: // convert parameters to JRDesignParameters so they can be
368: // parsed
369: Map jrParameters = ORUtil
370: .buildJRDesignParameters(parameters);
371:
372: pStmt = JRQueryExecuter.getStatement(query,
373: jrParameters, parameters, conn);
374: }
375:
376: rs = pStmt.executeQuery();
377:
378: RowSetDynaClass rowSetDynaClass = new RowSetDynaClass(rs);
379:
380: results = rowSetDynaClass.getRows();
381: properties = rowSetDynaClass.getDynaProperties();
382:
383: rs.close();
384: } catch (Exception e) {
385: throw new ProviderException(
386: "Error executing report query: " + e.getMessage());
387: } finally {
388: try {
389: if (pStmt != null)
390: pStmt.close();
391: if (conn != null)
392: conn.close();
393: } catch (Exception c) {
394: log.error("Error closing");
395: }
396: }
397:
398: JasperDesign jasperDesign = new JasperDesign();
399: jasperDesign.setName(report.getName().replaceAll(" ", "_"));
400:
401: int width = jasperDesign.getPageWidth();
402: int height = jasperDesign.getPageHeight();
403:
404: jasperDesign.setOrientation(JasperDesign.ORIENTATION_LANDSCAPE);
405: jasperDesign.setPageHeight(width);
406: jasperDesign.setPageWidth(height);
407:
408: for (int i = 0; i < properties.length; i++) {
409:
410: JRDesignField field = new JRDesignField();
411: field.setName((String) properties[i].getName());
412: field.setValueClass((Class) properties[i].getType());
413:
414: try {
415: jasperDesign.addField(field);
416: } catch (Exception e) {
417: log.warn(e);
418: }
419: }
420:
421: if (exportType == ExportType.PDF) {
422: // add title
423: JRDesignStaticText sText = new JRDesignStaticText();
424: sText.setX(0);
425: sText.setY(0);
426: sText.setWidth(jasperDesign.getPageHeight());
427: sText.setHeight(50);
428: sText.setText(jasperDesign.getName());
429: sText.setFontSize(16);
430: sText.setBold(true);
431:
432: JRDesignBand band = new JRDesignBand();
433: band.setHeight(50);
434: band.addElement(sText);
435:
436: jasperDesign.setTitle(band);
437:
438: // add page footer for page numbers
439: band = new JRDesignBand();
440: band.setHeight(15);
441:
442: sText = new JRDesignStaticText();
443: sText.setX(0);
444: sText.setY(0);
445: sText.setHeight(15);
446: sText.setWidth(40);
447: sText.setText("Page:");
448:
449: band.addElement(sText);
450:
451: JRDesignExpression exp = new JRDesignExpression();
452: exp.addVariableChunk("PAGE_NUMBER");
453: exp.setValueClass(Integer.class);
454:
455: JRDesignTextField txt = new JRDesignTextField();
456: txt.setExpression(exp);
457: txt.setX(40);
458: txt.setY(0);
459: txt.setHeight(15);
460: txt.setWidth(100);
461:
462: band.addElement(txt);
463:
464: jasperDesign.setPageFooter(band);
465: }
466:
467: JRDesignBand emptyBand = new JRDesignBand();
468: emptyBand.setHeight(0);
469: jasperDesign.setPageHeader(emptyBand);
470: jasperDesign.setColumnFooter(emptyBand);
471: jasperDesign.setSummary(emptyBand);
472:
473: JRField[] fields = jasperDesign.getFields();
474:
475: // add column header and detail bands
476: JRDesignBand bandDetail = new JRDesignBand();
477: bandDetail.setHeight(20);
478:
479: JRDesignBand bandHeader = new JRDesignBand();
480: bandHeader.setHeight(20);
481:
482: int fieldWidth = (jasperDesign.getPageWidth()
483: - jasperDesign.getLeftMargin()
484: - jasperDesign.getRightMargin() - (fields.length - 1)
485: * jasperDesign.getColumnSpacing())
486: / fields.length;
487:
488: for (int i = 0; i < fields.length; i++) {
489: try {
490: JRField field = fields[i];
491:
492: JRDesignExpression exp = new JRDesignExpression();
493: exp.addFieldChunk(field.getName());
494:
495: if (field.getValueClassName().equals("java.sql.Date")) {
496: // JasperReports does not support java.sql.Date in text field expression
497: exp.setValueClass(java.util.Date.class);
498: } else {
499: exp.setValueClass(field.getValueClass());
500: }
501:
502: JRDesignTextField txt = new JRDesignTextField();
503: txt.setExpression(exp);
504: txt.setX(i * fieldWidth);
505: txt.setY(0);
506: txt.setHeight(20);
507: txt.setWidth(fieldWidth);
508:
509: if (field.getValueClass().equals(Double.class)) {
510: txt.setPattern("0.00");
511: }
512:
513: bandDetail.addElement(txt);
514:
515: JRDesignStaticText sText = new JRDesignStaticText();
516: sText.setX(i * fieldWidth);
517: sText.setY(0);
518: sText.setHeight(20);
519: sText.setWidth(fieldWidth);
520: sText.setText(field.getName());
521: sText.setUnderline(true);
522:
523: bandHeader.addElement(sText);
524: } catch (Exception e) {
525: log.warn(e);
526: }
527: }
528:
529: if (exportType == ExportType.PDF)
530: jasperDesign.setColumnHeader(bandHeader);
531: jasperDesign.setDetail(bandDetail);
532:
533: JasperReport jasperReport = JasperCompileManager
534: .compileReport(jasperDesign);
535: JasperPrint jasperPrint = JasperFillManager.fillReport(
536: jasperReport, parameters,
537: new JRBeanCollectionDataSource(results));
538:
539: return jasperPrint;
540: }
541:
542: public List buildParameterList(Report report)
543: throws ProviderException {
544: try {
545: JasperReport jasperReport = (JasperReport) JRLoader
546: .loadObject(directoryProvider.getReportDirectory()
547: + report.getFile());
548:
549: ArrayList<ReportParameter> parameters = new ArrayList<ReportParameter>();
550:
551: JRParameter[] jrParameters = jasperReport.getParameters();
552: for (int i = 0; i < jrParameters.length; i++) {
553: if (!jrParameters[i].isSystemDefined()) {
554: ReportParameter rp = new ReportParameter();
555: rp
556: .setClassName(jrParameters[i]
557: .getValueClassName());
558: rp.setDescription(jrParameters[i].getName());
559: rp.setName(jrParameters[i].getName());
560: rp.setType(ReportParameter.TEXT_PARAM);
561:
562: parameters.add(rp);
563: }
564: }
565:
566: return parameters;
567: } catch (JRException e) {
568: throw new ProviderException(e);
569: }
570: }
571: }
|