/*
* Copyright (C) 2006 Erik Swenson - erik@oreports.com
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the Free
* Software Foundation; either version 2 of the License, or (at your option)
* any later version.
*
* This program 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 General Public License for
* more details.
*
* You should have received a copy of the GNU General Public License along with
* this program; if not, write to the Free Software Foundation, Inc., 59 Temple
* Place - Suite 330, Boston, MA 02111-1307, USA.
*
*/
package org.efs.openreports.engine;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import net.sf.jasperreports.engine.JRAbstractExporter;
import net.sf.jasperreports.engine.JREmptyDataSource;
import net.sf.jasperreports.engine.JRException;
import net.sf.jasperreports.engine.JRExporterParameter;
import net.sf.jasperreports.engine.JRField;
import net.sf.jasperreports.engine.JRParameter;
import net.sf.jasperreports.engine.JRReport;
import net.sf.jasperreports.engine.JasperCompileManager;
import net.sf.jasperreports.engine.JasperFillManager;
import net.sf.jasperreports.engine.JasperPrint;
import net.sf.jasperreports.engine.JasperReport;
import net.sf.jasperreports.engine.data.JRBeanCollectionDataSource;
import net.sf.jasperreports.engine.design.JRDesignBand;
import net.sf.jasperreports.engine.design.JRDesignExpression;
import net.sf.jasperreports.engine.design.JRDesignField;
import net.sf.jasperreports.engine.design.JRDesignParameter;
import net.sf.jasperreports.engine.design.JRDesignQuery;
import net.sf.jasperreports.engine.design.JRDesignStaticText;
import net.sf.jasperreports.engine.design.JRDesignTextField;
import net.sf.jasperreports.engine.design.JasperDesign;
import net.sf.jasperreports.engine.export.JExcelApiExporter;
import net.sf.jasperreports.engine.export.JRCsvExporter;
import net.sf.jasperreports.engine.export.JRHtmlExporter;
import net.sf.jasperreports.engine.export.JRHtmlExporterParameter;
import net.sf.jasperreports.engine.export.JRPdfExporter;
import net.sf.jasperreports.engine.export.JRRtfExporter;
import net.sf.jasperreports.engine.export.JRTextExporter;
import net.sf.jasperreports.engine.export.JRTextExporterParameter;
import net.sf.jasperreports.engine.export.JRXlsAbstractExporterParameter;
import net.sf.jasperreports.engine.export.JRXlsExporter;
import net.sf.jasperreports.engine.query.JRXPathQueryExecuterFactory;
import net.sf.jasperreports.engine.util.JRLoader;
import net.sf.jasperreports.engine.util.JRQueryExecuter;
import net.sf.jasperreports.engine.util.JRXmlUtils;
import org.apache.commons.beanutils.DynaProperty;
import org.apache.commons.beanutils.RowSetDynaClass;
import org.apache.log4j.Logger;
import org.efs.openreports.ReportConstants.ExportType;
import org.efs.openreports.engine.input.ReportEngineInput;
import org.efs.openreports.engine.output.JasperReportEngineOutput;
import org.efs.openreports.engine.output.ReportEngineOutput;
import org.efs.openreports.objects.Report;
import org.efs.openreports.objects.ReportDataSource;
import org.efs.openreports.objects.ReportExportOption;
import org.efs.openreports.objects.ReportParameter;
import org.efs.openreports.objects.ReportParameterMap;
import org.efs.openreports.providers.DataSourceProvider;
import org.efs.openreports.providers.DirectoryProvider;
import org.efs.openreports.providers.PropertiesProvider;
import org.efs.openreports.providers.ProviderException;
import org.efs.openreports.util.LocalStrings;
import org.efs.openreports.util.ORUtil;
import org.w3c.dom.Document;
/**
* JasperReports ReportEngine implementation. Report generation is separated
* into fillReport and exportReport methods in order to provide direct access
* to the JasperPrint object when required.
*
* @author Erik Swenson
*
*/
public class JasperReportEngine extends ReportEngine
{
protected static Logger log = Logger.getLogger(JasperReportEngine.class.getName());
public JasperReportEngine(DataSourceProvider dataSourceProvider,
DirectoryProvider directoryProvider, PropertiesProvider propertiesProvider)
{
super(dataSourceProvider,directoryProvider, propertiesProvider);
}
@Override
public ReportEngineOutput generateReport(ReportEngineInput input)
throws ProviderException
{
JasperPrint jasperPrint = fillReport(input);
ReportEngineOutput engineOutput = exportReport(jasperPrint,
input.getExportType(), input.getReport().getReportExportOption(), input
.getImagesMap(), input.isInlineImages());
return engineOutput;
}
public JasperPrint fillReport(ReportEngineInput input) throws ProviderException
{
Connection conn = null;
Report report = input.getReport();
Map<String,Object> parameters = input.getParameters();
ReportDataSource dataSource = report.getDataSource();
try
{
JasperReport jr = null;
if (report.isQueryReport()) return fillQueryReport(report, parameters, input.getExportType());
jr = (JasperReport) JRLoader
.loadObject(directoryProvider.getReportDirectory() + report.getFile());
List<ReportParameterMap> subReports = report.getSubReportParameters();
if (subReports != null && subReports.size() > 0)
{
Iterator<ReportParameterMap> iterator = report.getSubReportParameters().iterator();
while (iterator.hasNext())
{
ReportParameterMap rpMap = iterator.next();
JasperReport subReport = (JasperReport) JRLoader.loadObject(directoryProvider
.getReportDirectory()
+ rpMap.getReportParameter().getData());
parameters.put(rpMap.getReportParameter().getName(), subReport);
}
}
JasperPrint jp = null;
// create new HashMap to send to JasperReports in order to
// fix serialization problems
Map<String,Object> jasperReportMap = new HashMap<String,Object>(parameters);
if (input.getXmlInput() != null)
{
ByteArrayInputStream stream = new ByteArrayInputStream(input.getXmlInput().getBytes());
Document document = JRXmlUtils.parse(stream);
jasperReportMap.put(JRXPathQueryExecuterFactory.PARAMETER_XML_DATA_DOCUMENT, document);
jp = JasperFillManager.fillReport(jr, jasperReportMap);
}
else if (dataSource == null)
{
jp = JasperFillManager.fillReport(jr, jasperReportMap, new JREmptyDataSource());
}
else
{
conn = dataSourceProvider.getConnection(dataSource.getId());
jp = JasperFillManager.fillReport(jr, jasperReportMap, conn);
}
if (jp == null || jp.getPages().size() < 1) throw new ProviderException(LocalStrings.ERROR_REPORT_EMPTY);
return jp;
}
catch (Exception e)
{
if (!e.getMessage().equals(LocalStrings.ERROR_REPORT_EMPTY)) log.error("JasperReportEngine.fillReport", e);
throw new ProviderException(e.getMessage());
}
finally
{
try
{
if (conn != null) conn.close();
}
catch (Exception ex)
{
log.error("Error closing connection: " + ex.getMessage());
}
}
}
public ReportEngineOutput exportReport(JasperPrint jasperPrint, ExportType exportType,
ReportExportOption exportOptions, Map<?,?> imagesMap, boolean inlineImages) throws ProviderException
{
JasperReportEngineOutput engineOutput = new JasperReportEngineOutput();
ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
JRAbstractExporter exporter = null;
try
{
if (exportType == ExportType.PDF)
{
engineOutput.setContentType(ReportEngineOutput.CONTENT_TYPE_PDF);
exporter = new JRPdfExporter();
}
else if (exportType == ExportType.XLS
|| exportType == ExportType.EXCEL)
{
engineOutput.setContentType(ReportEngineOutput.CONTENT_TYPE_XLS);
if (exportType == ExportType.XLS)
{
exporter = new JRXlsExporter();
}
else if (exportType == ExportType.EXCEL)
{
exporter = new JExcelApiExporter();
}
exporter.setParameter(
JRXlsAbstractExporterParameter.IS_REMOVE_EMPTY_SPACE_BETWEEN_ROWS,
new Boolean(exportOptions.isXlsRemoveEmptySpaceBetweenRows()));
exporter.setParameter(JRXlsAbstractExporterParameter.IS_ONE_PAGE_PER_SHEET,
new Boolean(exportOptions.isXlsOnePagePerSheet()));
exporter.setParameter(JRXlsAbstractExporterParameter.IS_DETECT_CELL_TYPE,
new Boolean(exportOptions.isXlsAutoDetectCellType()));
exporter.setParameter(JRXlsAbstractExporterParameter.IS_WHITE_PAGE_BACKGROUND,
new Boolean(exportOptions.isXlsWhitePageBackground()));
}
else if (exportType == ExportType.CSV)
{
engineOutput.setContentType(ReportEngineOutput.CONTENT_TYPE_CSV);
exporter = new JRCsvExporter();
}
else if (exportType == ExportType.TEXT)
{
engineOutput.setContentType(ReportEngineOutput.CONTENT_TYPE_TEXT);
exporter = new JRTextExporter();
exporter.setParameter(JRTextExporterParameter.CHARACTER_WIDTH,
new Integer(10));
exporter.setParameter(JRTextExporterParameter.CHARACTER_HEIGHT,
new Integer(10));
}
else if (exportType == ExportType.RTF)
{
engineOutput.setContentType(ReportEngineOutput.CONTENT_TYPE_RTF);
exporter = new JRRtfExporter();
}
else
{
engineOutput.setContentType(ReportEngineOutput.CONTENT_TYPE_HTML);
exporter = new JRHtmlExporter();
exporter.setParameter(
JRHtmlExporterParameter.IS_REMOVE_EMPTY_SPACE_BETWEEN_ROWS,
new Boolean(exportOptions.isHtmlRemoveEmptySpaceBetweenRows()));
exporter.setParameter(JRHtmlExporterParameter.IS_USING_IMAGES_TO_ALIGN,
new Boolean(exportOptions.isHtmlUsingImagesToAlign()));
exporter.setParameter(JRHtmlExporterParameter.IS_WHITE_PAGE_BACKGROUND,
new Boolean(exportOptions.isHtmlWhitePageBackground()));
exporter.setParameter(JRHtmlExporterParameter.IS_WRAP_BREAK_WORD,
new Boolean(exportOptions.isHtmlWrapBreakWord()));
if (imagesMap == null) imagesMap = new HashMap<Object,Object>();
exporter.setParameter(JRHtmlExporterParameter.IMAGES_MAP, imagesMap);
if (inlineImages)
{
exporter.setParameter(JRHtmlExporterParameter.IMAGES_URI, "cid:");
}
else
{
//see ImageLoaderAction for more information
exporter.setParameter(JRHtmlExporterParameter.IMAGES_URI,
"imageLoader.action?imageName=");
}
//if embedded html, just include <div> tags instead of <html>,<header>, <body>, etc.
if (exportType == ExportType.HTML_EMBEDDED)
{
exporter.setParameter(JRHtmlExporterParameter.HTML_HEADER, "<div>");
exporter.setParameter(JRHtmlExporterParameter.HTML_FOOTER, "</div>");
}
}
exporter.setParameter(JRExporterParameter.JASPER_PRINT, jasperPrint);
exporter.setParameter(JRExporterParameter.OUTPUT_STREAM, outputStream);
exporter.exportReport();
}
catch (Exception e)
{
throw new ProviderException(e.toString());
}
engineOutput.setImagesMap(imagesMap);
engineOutput.setContent(outputStream.toByteArray());
return engineOutput;
}
/*
* Creates a default JasperPrint from a QueryReport. This method is used when
* a scheduled QueryReport is executed.
*/
private JasperPrint fillQueryReport(Report report, Map<String,Object> map, ExportType exportType) throws Exception
{
Connection conn = null;
PreparedStatement pStmt = null;
ResultSet rs = null;
// create new HashMap to send to JasperReports in order to
// fix serialization problems
Map<String,Object> parameters = new HashMap<String,Object>(map);
List<?> results = null;
DynaProperty[] properties = null;
try
{
ReportDataSource dataSource = report.getDataSource();
conn = dataSourceProvider.getConnection(dataSource.getId());
if (parameters == null || parameters.isEmpty())
{
pStmt = conn.prepareStatement(report.getQuery());
}
else
{
// Use JasperReports Query logic to parse parameters in chart
// queries
JRDesignQuery query = new JRDesignQuery();
query.setText(report.getQuery());
// convert parameters to JRDesignParameters so they can be
// parsed
Map<String, JRDesignParameter> jrParameters = ORUtil.buildJRDesignParameters(parameters);
pStmt = JRQueryExecuter.getStatement(query, jrParameters, parameters, conn);
}
rs = pStmt.executeQuery();
RowSetDynaClass rowSetDynaClass = new RowSetDynaClass(rs);
results = rowSetDynaClass.getRows();
properties = rowSetDynaClass.getDynaProperties();
rs.close();
}
catch (Exception e)
{
throw new ProviderException("Error executing report query: " + e.getMessage());
}
finally
{
try
{
if (pStmt != null) pStmt.close();
if (conn != null) conn.close();
}
catch (Exception c)
{
log.error("Error closing");
}
}
JasperDesign jasperDesign = new JasperDesign();
jasperDesign.setName(report.getName().replaceAll(" ", "_"));
int width = jasperDesign.getPageWidth();
int height = jasperDesign.getPageHeight();
jasperDesign.setOrientation(JRReport.ORIENTATION_LANDSCAPE);
jasperDesign.setPageHeight(width);
jasperDesign.setPageWidth(height);
for (int i = 0; i < properties.length; i++)
{
JRDesignField field = new JRDesignField();
field.setName(properties[i].getName());
field.setValueClass(properties[i].getType());
try
{
jasperDesign.addField(field);
}
catch (Exception e)
{
log.warn(e);
}
}
if (exportType == ExportType.PDF)
{
// add title
JRDesignStaticText sText = new JRDesignStaticText();
sText.setX(0);
sText.setY(0);
sText.setWidth(jasperDesign.getPageHeight());
sText.setHeight(50);
sText.setText(jasperDesign.getName());
sText.setFontSize(16);
sText.setBold(true);
JRDesignBand band = new JRDesignBand();
band.setHeight(50);
band.addElement(sText);
jasperDesign.setTitle(band);
// add page footer for page numbers
band = new JRDesignBand();
band.setHeight(15);
sText = new JRDesignStaticText();
sText.setX(0);
sText.setY(0);
sText.setHeight(15);
sText.setWidth(40);
sText.setText("Page:");
band.addElement(sText);
JRDesignExpression exp = new JRDesignExpression();
exp.addVariableChunk("PAGE_NUMBER");
exp.setValueClass(Integer.class);
JRDesignTextField txt = new JRDesignTextField();
txt.setExpression(exp);
txt.setX(40);
txt.setY(0);
txt.setHeight(15);
txt.setWidth(100);
band.addElement(txt);
jasperDesign.setPageFooter(band);
}
JRDesignBand emptyBand = new JRDesignBand();
emptyBand.setHeight(0);
jasperDesign.setPageHeader(emptyBand);
jasperDesign.setColumnFooter(emptyBand);
jasperDesign.setSummary(emptyBand);
JRField[] fields = jasperDesign.getFields();
// add column header and detail bands
JRDesignBand bandDetail = new JRDesignBand();
bandDetail.setHeight(20);
JRDesignBand bandHeader = new JRDesignBand();
bandHeader.setHeight(20);
int fieldWidth = (jasperDesign.getPageWidth() - jasperDesign.getLeftMargin()
- jasperDesign.getRightMargin() - (fields.length - 1) * jasperDesign.getColumnSpacing())
/ fields.length;
for (int i = 0; i < fields.length; i++)
{
try
{
JRField field = fields[i];
JRDesignExpression exp = new JRDesignExpression();
exp.addFieldChunk(field.getName());
if (field.getValueClassName().equals("java.sql.Date"))
{
// JasperReports does not support java.sql.Date in text field expression
exp.setValueClass(java.util.Date.class);
}
else
{
exp.setValueClass(field.getValueClass());
}
JRDesignTextField txt = new JRDesignTextField();
txt.setExpression(exp);
txt.setX(i * fieldWidth);
txt.setY(0);
txt.setHeight(20);
txt.setWidth(fieldWidth);
if (field.getValueClass().equals(Double.class))
{
txt.setPattern("0.00");
}
bandDetail.addElement(txt);
JRDesignStaticText sText = new JRDesignStaticText();
sText.setX(i * fieldWidth);
sText.setY(0);
sText.setHeight(20);
sText.setWidth(fieldWidth);
sText.setText(field.getName());
sText.setUnderline(true);
bandHeader.addElement(sText);
}
catch (Exception e)
{
log.warn(e);
}
}
if (exportType == ExportType.PDF) jasperDesign.setColumnHeader(bandHeader);
jasperDesign.setDetail(bandDetail);
JasperReport jasperReport = JasperCompileManager.compileReport(jasperDesign);
JasperPrint jasperPrint = JasperFillManager.fillReport(jasperReport, parameters,
new JRBeanCollectionDataSource(results));
return jasperPrint;
}
@Override
public List<ReportParameter> buildParameterList(Report report) throws ProviderException
{
try
{
JasperReport jasperReport = (JasperReport) JRLoader
.loadObject(directoryProvider.getReportDirectory() + report.getFile());
ArrayList<ReportParameter> parameters = new ArrayList<ReportParameter>();
JRParameter[] jrParameters = jasperReport.getParameters();
for (int i=0; i < jrParameters.length; i++)
{
if (!jrParameters[i].isSystemDefined())
{
ReportParameter rp = new ReportParameter();
rp.setClassName(jrParameters[i].getValueClassName());
rp.setDescription(jrParameters[i].getName());
rp.setName(jrParameters[i].getName());
rp.setType(ReportParameter.TEXT_PARAM);
parameters.add(rp);
}
}
return parameters;
}
catch(JRException e)
{
throw new ProviderException(e);
}
}
}