/* * This program is free software; you can redistribute it and/or modify it under the * terms of the GNU Lesser General Public License, version 2.1 as published by the Free Software * Foundation. * * You should have received a copy of the GNU Lesser General Public License along with this * program; if not, you can obtain a copy at http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html * or from the Free Software Foundation, Inc., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. * * 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 Lesser General Public License for more details. * * Copyright 2006 - 2009 Pentaho Corporation. All rights reserved. * */ package org.pentaho.platform.plugin.action.jasperreports; import java.io.File; import java.io.IOException; import java.io.OutputStream; import java.sql.Connection; import java.sql.DriverManager; import java.sql.SQLException; import java.util.ArrayList; import java.util.Arrays; import java.util.Collection; import java.util.HashMap; import java.util.HashSet; import java.util.List; import java.util.Map; import javax.sql.DataSource; import net.sf.jasperreports.engine.JRException; import net.sf.jasperreports.engine.JRExporter; import net.sf.jasperreports.engine.JRExporterParameter; import net.sf.jasperreports.engine.JRParameter; 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.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.JRXlsExporter; import net.sf.jasperreports.engine.export.JRXlsExporterParameter; import net.sf.jasperreports.engine.export.JRXmlExporter; import net.sf.jasperreports.engine.util.JRLoader; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; import org.pentaho.actionsequence.dom.ActionInput; import org.pentaho.actionsequence.dom.ActionInputConstant; import org.pentaho.actionsequence.dom.IActionInput; import org.pentaho.actionsequence.dom.IActionResource; import org.pentaho.actionsequence.dom.actions.JasperReportAction; import org.pentaho.platform.api.data.DatasourceServiceException; import org.pentaho.platform.api.data.IDatasourceService; import org.pentaho.platform.api.engine.IActionParameter; import org.pentaho.platform.api.engine.IActionSequenceResource; import org.pentaho.platform.api.engine.ObjectFactoryException; import org.pentaho.platform.api.repository.IContentItem; import org.pentaho.platform.engine.core.system.PentahoSystem; import org.pentaho.platform.engine.services.solution.ComponentBase; import org.pentaho.platform.plugin.action.messages.Messages; /** * @author James Dixon and Barry Klawans * * JasperReports runner for Pentaho. * * This class implements a Pentaho Component that runs JasperReports. It * includes full support for parameterization and output in PDF and HTML. * * This is a Beta version, with a number of open issues. 1) Data sources must be * specified in the config file for EACH report. There should be a default * source in the jasper reports configuration. 2) Support for JNDI defined data * source has not been added yet. 3) Images are written to the Pentaho temp * directory and never cleaned up. They should probably be moved into Session * related storage. 4) Support should be added so a Filled report can be * persisited into the Pentaho repository and exported repeatedly. * * @author Radek Maciaszek <radek@m3.net> * * Added handling multiple reports in batch mode which allow to create excel reports with * multiple worksheets */ public class JasperReportsComponent extends ComponentBase { private static final String REMOVE_EMPTY_ROWS = "remove-empty-rows"; //$NON-NLS-1$ private static final String IMAGE_URL = "image-url"; //$NON-NLS-1$ private static final String IMAGE_DIR = "image-dir"; //$NON-NLS-1$ private static final String TEXT_HTML = "text/html"; //$NON-NLS-1$ private static final String CONFIG_XML = "jasperreports/jasperreports-conf.xml"; //$NON-NLS-1$ private static final String HTML = "html"; //$NON-NLS-1$ private static final String PDF = "pdf"; //$NON-NLS-1$ private static final String XML = "xml"; //$NON-NLS-1$ private static final String XLS = "xls"; //$NON-NLS-1$ private static final String CSV = "csv"; //$NON-NLS-1$ private static final String TXT = "txt"; //$NON-NLS-1$ private static final String RTF = "rtf"; //$NON-NLS-1$ private static final String NEED_TO_PROMPT = "NeedToPrompt"; //$NON-NLS-1$ private static final String RETURN_IMMEDIATELY = "ReturnImmediately"; //$NON-NLS-1$ private static final long serialVersionUID = -4422766007912720969L; /** * The extension of the JasperReports reports to run. Currently only designs * saved as an XML file are supported, not searilized JasperDesign objects. */ public static final String JASPER_REPORTS_DESIGN_EXTENSION = ".jrxml"; //$NON-NLS-1$ private static Log logger = LogFactory.getLog(JasperReportsComponent.class); /** * The extension of a compiled JasperReports file. */ public static final String COMPILED_JASPER_REPORTS_EXTENSION = ".jasper"; //$NON-NLS-1$ /** * The parametername of the report directory (to support subreports) */ public static final String REPORT_FOLDER_PARAMETER = "REPORT_FOLDER"; //$NON-NLS-1$ public Log getLogger() { return logger; } /** * Validates the settings in the jasper reports configuration file. * <p> * Currently the mandatory settings are imageHandling/imageUrl and * imageHandling/imageDir, which specify where to store images generated by * the report (ie charts) and how to access the images inside an HTML page. * @return true if the validation was successful */ protected boolean validateSystemSettings() { // make sure that the system settings are valid. // In production this will only be called when they have changed, for // development purposes we are calling it every time // get and validate system settings String imageUrl = PentahoSystem.getSystemSetting(CONFIG_XML, "jasperreports/imageHandling/imageUrl", null); //$NON-NLS-1$ String imageDir = PentahoSystem.getSystemSetting(CONFIG_XML, "jasperreports/imageHandling/imageDir", null); //$NON-NLS-1$ String removeEmptyRows = PentahoSystem.getSystemSetting(CONFIG_XML, "jasperreports/htmlExportOptions/removeEmptySpaceBetweenRows", "false"); //$NON-NLS-1$ //$NON-NLS-2$ if (debug) { debug(Messages.getInstance().getString("JasperReport.DEBUG_IMAGE_URL") + imageUrl); //$NON-NLS-1$ debug(Messages.getInstance().getString("JasperReport.DEBUG_IMAGE_DIRECTORY") + imageDir); //$NON-NLS-1$ debug(Messages.getInstance().getString("JasperReport.DEBUG_REMOVE_EMPTRY_ROWS") + removeEmptyRows); //$NON-NLS-1$ } if (imageUrl == null) { error(Messages.getInstance().getErrorString("JasperReport.ERROR_0001_IMAGE_URL_NOT_DEFINED")); //$NON-NLS-1$ return false; } if (imageDir == null) { error(Messages.getInstance().getErrorString("JasperReport.ERROR_0002_IMAGE_DIRECTORY_INVALID")); //$NON-NLS-1$ return false; } saveSetting(IMAGE_URL, imageUrl); saveSetting(IMAGE_DIR, imageDir); saveSetting(REMOVE_EMPTY_ROWS, removeEmptyRows); // set a property for these, they will be cached and be available at // execution time return true; } /** * NOTE: The comments from Pentaho state that in production this will not be * called during execution. If so, this info needs to be moved into the * execute path as well. * * @return true if the validation was successful */ public boolean validateAction() { // In production this will only be called during validation and publish, // it will not be called before report executions // for now it is called before every execution boolean actionValidated = true; JasperReportAction reportAction = (JasperReportAction) getActionDefinition(); // get report connection setting if (getActionDefinition() instanceof JasperReportAction) { // Validate settings are passed. Treat the password as optional. if (reportAction.getJndi() == ActionInputConstant.NULL_INPUT) { if (reportAction.getDriver() != ActionInputConstant.NULL_INPUT) { error(Messages.getInstance().getErrorString("JasperReport.ERROR_0003_JDBC_DRIVER_NOT_SPECIFIED")); //$NON-NLS-1$ actionValidated = false; } if (actionValidated && reportAction.getConnection() == ActionInputConstant.NULL_INPUT) { error(Messages.getInstance().getErrorString("JasperReport.ERROR_0004_JDBC_CONNECTION_NOT_SPECIFIED")); //$NON-NLS-1$ actionValidated = false; } if (actionValidated && reportAction.getUserId() == ActionInputConstant.NULL_INPUT) { error(Messages.getInstance().getErrorString("JasperReport.ERROR_0005_JDBC_USER_NOT_SPECIFIED")); //$NON-NLS-1$ actionValidated = false; } } // check the inputs, we cannot reply on input values during validation if (actionValidated && reportAction.getOutputType() == ActionInputConstant.NULL_INPUT) { error(Messages.getInstance().getErrorString("JasperReport.ERROR_0006_OUTPUT_TYPE_NOT_SPECIFIED")); //$NON-NLS-1$ actionValidated = false; } // check the resources if (actionValidated && reportAction.getReportDefinition() == null) { error(Messages.getInstance().getErrorString("JasperReport.ERROR_0007_REPORT_DEFINITION_NOT_SPECIFIED")); //$NON-NLS-1$ actionValidated = false; } } else { actionValidated = false; error(Messages.getInstance().getErrorString( "ComponentBase.ERROR_0001_UNKNOWN_ACTION_TYPE", getActionDefinition().getElement().asXML())); //$NON-NLS-1$ } return actionValidated; } /** * Creates and initializes the appropriate exporter for producing output. * All channel specific export options will be set for the exporter. * * @param outputType * the channel (pdf or html) to use when exporting * @param reportName * used to create a unique name for the directory to store images * in. Should be something unique to the invocation, such as the * session id, but I don't know how to get that from the Pentaho * API yet. * * @return the exporter to use, or <code>null</code> if the output type is * not valid. * * TODO: replace reportName with something unique, like session id. */ private JRExporter getExporter(String outputType, String reportName) { JRExporter exporter = null; if (HTML.equals(outputType)) { String removeEmptyRows = getStringSetting("removeEmptyRows"); //$NON-NLS-1$ exporter = new JRHtmlExporter(); exporter.setParameter(JRHtmlExporterParameter.IS_USING_IMAGES_TO_ALIGN, Boolean.FALSE); if (removeEmptyRows != null && "true".equalsIgnoreCase(removeEmptyRows)) { //$NON-NLS-1$ exporter.setParameter(JRHtmlExporterParameter.IS_REMOVE_EMPTY_SPACE_BETWEEN_ROWS, Boolean.TRUE); } String imageUrl = PentahoSystem.getApplicationContext().getBaseUrl() + getStringSetting(IMAGE_URL); StringBuffer tempImgPath = new StringBuffer().append(PentahoSystem.getApplicationContext().getSolutionPath(getStringSetting(IMAGE_DIR))); if (! (tempImgPath.charAt(tempImgPath.length() - 1) == File.separatorChar)) { tempImgPath.append(File.separator); } tempImgPath.append(reportName).append(File.separator); String imagePath = tempImgPath.toString(); File imageDir = new File(imagePath); imageDir.mkdirs(); exporter.setParameter(JRHtmlExporterParameter.IMAGES_DIR, imageDir); // exporter.setParameter(JRHtmlExporter.IMAGES_URI, imageUrl + // reportName ); //$NON-NLS-1$ exporter.setParameter(JRHtmlExporterParameter.IMAGES_URI, imageUrl + reportName + "/"); //$NON-NLS-1$ exporter.setParameter(JRHtmlExporterParameter.IS_OUTPUT_IMAGES_TO_DIR, Boolean.TRUE); if (debug) { debug(Messages.getInstance().getString("JasperReport.DEBUG_IMAGE_DIRECTORY", imagePath)); //$NON-NLS-1$ } } else if (PDF.equals(outputType)) { exporter = new JRPdfExporter(); } else if (XLS.equals(outputType)) { exporter = new JRXlsExporter(); // Some cleaning in order to make excel reports look better exporter.setParameter(JRXlsExporterParameter.IS_DETECT_CELL_TYPE, Boolean.TRUE); exporter.setParameter(JRXlsExporterParameter.IS_REMOVE_EMPTY_SPACE_BETWEEN_ROWS, Boolean.TRUE); exporter.setParameter(JRXlsExporterParameter.IS_WHITE_PAGE_BACKGROUND, Boolean.TRUE); exporter.setParameter(JRXlsExporterParameter.IS_ONE_PAGE_PER_SHEET, Boolean.FALSE); } else if (CSV.equals(outputType)) { exporter = new JRCsvExporter(); } else if (XML.equals(outputType)) { exporter = new JRXmlExporter(); } else if (TXT.equals(outputType)) { exporter = new JRTextExporter(); // Add required parameters exporter.setParameter(JRTextExporterParameter.PAGE_HEIGHT, new Integer("120")); //$NON-NLS-1$ exporter.setParameter(JRTextExporterParameter.PAGE_WIDTH, new Integer("120")); //$NON-NLS-1$ } else if (RTF.equals(outputType)) { exporter = new JRRtfExporter(); } return exporter; } /** * Runs a report. * * @return true if action was successful */ public boolean executeAction() { JasperReportAction reportAction = (JasperReportAction) getActionDefinition(); // perform runtime validation of the output type String reportOutputType = reportAction.getOutputType().getStringValue(); if (debug) { debug(Messages.getInstance().getString("JasperReport.DEBUG_OUTPUT_TYPE", reportOutputType)); //$NON-NLS-1$ } String mimeType = getMimeType(reportOutputType); if (mimeType == null) { error(Messages.getInstance().getErrorString("JasperReport.ERROR_0011_OUTPUT_TYPE_INVALID")); //$NON-NLS-1$ return false; } String extension = "." + reportOutputType; //$NON-NLS-1$ HashSet<String> compiledReportPaths = new HashSet<String>(); JasperReport jrreport = null; // Store parameters for all reports HashMap allReportParameters = new HashMap(); IActionResource reportDefinition = reportAction.getReportDefinition(); if (reportDefinition != null) { IActionSequenceResource resource = getResource(reportDefinition.getName()); HashMap returnImmediately = new HashMap(); processCurrentReport(resource, compiledReportPaths, jrreport, allReportParameters, returnImmediately, reportOutputType); if (!returnImmediately.isEmpty() && returnImmediately.containsKey(RETURN_IMMEDIATELY)) { return true; } } else { // This else statement is here to support old action sequence functionality. org.pentaho.actionsequence.dom.IActionSequenceResource[] actionSequenceResources = reportAction.getDocument() .getResources(); for (org.pentaho.actionsequence.dom.IActionSequenceResource element : actionSequenceResources) { IActionSequenceResource resource = getResource(element.getName()); HashMap returnImmediately = new HashMap(); // Compile every report processCurrentReport(resource, compiledReportPaths, jrreport, allReportParameters, returnImmediately, reportOutputType); if (!returnImmediately.isEmpty() && returnImmediately.containsKey(RETURN_IMMEDIATELY)) { return true; } } } // Try to get the output from the action-sequence document. // execute the report here... IContentItem contentItem = null; OutputStream outputStream = getOutputStream(mimeType, extension, contentItem); if (outputStream == null) { error(Messages.getInstance().getErrorString("JasperReport.ERROR_0013_OUTPUT_STREAM_INVALID")); //$NON-NLS-1$ return false; } return exportReport(compiledReportPaths, allReportParameters, reportOutputType, outputStream, contentItem); } /* * This function does the actual meat work. This method was created to reduce redundancy * in code, that was a part of supporting the new way and old way. * NOTE: The input params compiledReportPaths, jrreport and allReportParameters are being updated in the given method. * They are in essence being used as inout variables / referene vars. * * @return boolean if processing should continue */ private boolean processCurrentReport(IActionSequenceResource resource, HashSet<String> compiledReportPaths, JasperReport jrreport, HashMap allReportParameters, HashMap returnImmediately, String reportOutputType) { boolean continueProcessing = true; String reportDefinitionPath = getReportDefinitionPath(resource); String compiledReportPath = ""; //$NON-NLS-1$ if (reportDefinitionPath == null) { error(Messages.getInstance().getErrorString("JasperReport.ERROR_0008_REPORT_DEFINITION_UNREADABLE")); //$NON-NLS-1$ continueProcessing = false; } if (continueProcessing) { compiledReportPath = getCompiledReportPath(reportDefinitionPath); if (null == compiledReportPath) { continueProcessing = false; } } if (continueProcessing) { compiledReportPaths.add(compiledReportPath); continueProcessing = didReportCompile(reportDefinitionPath, compiledReportPath); } if (continueProcessing) { jrreport = loadJasperReport(compiledReportPath); if (null == jrreport) { continueProcessing = false; } } if (continueProcessing && (jrreport != null) ) { // We have a compiled reports, ready to run. JRParameter[] jrparams = jrreport.getParameters(); if (debug) { debug(Messages.getInstance().getString("JasperReport.DEBUG_LOADED_DESIGN", Integer.toString(jrparams.length))); //$NON-NLS-1$ } HashMap needToPrompt = new HashMap(); Map reportParameters = getReportParameters(jrparams, needToPrompt); // We're adding a parameter with the report's location. Useful for // subreports reportParameters.put(REPORT_FOLDER_PARAMETER, (new java.io.File(reportDefinitionPath)).getParent()); // Add a ignore pagination parameter for xls, html and csv if (XLS.equals(reportOutputType) || HTML.equals(reportOutputType) || CSV.equals(reportOutputType)) { reportParameters.put(JRParameter.IS_IGNORE_PAGINATION, Boolean.TRUE); } allReportParameters.put(compiledReportPath, reportParameters); // If we have parameters to prompt for, have Pentaho create the // parameter // page for us. if (!needToPrompt.isEmpty() && needToPrompt.containsKey(NEED_TO_PROMPT)) { // make sure the type parameter comes back to us... // context.createFeedbackParameter( "type", "type", // reportOutputType, false ); //$NON-NLS-1$ //$NON-NLS-1$ // //$NON-NLS-2$ // Isn't the parameter page always HTML? setFeedbackMimeType("text/html"); //$NON-NLS-1$ /* * Creation of the key RETURN IMMEDIATELY is important here. * We would like to return because we need to prompt the * user for input at this point. */ returnImmediately.put(RETURN_IMMEDIATELY, null); } else if (getRuntimeContext().isPromptPending()) { returnImmediately.put(RETURN_IMMEDIATELY, null); } } return continueProcessing; } /* * Simply exports the report once we have all the report parameters, the location * of the compiled report. */ private boolean exportReport(HashSet<String> compiledReportPaths, Map allReportParameters, String reportOutputType, OutputStream outputStream, IContentItem contentItem) { Connection conn = getConnection(); if (conn == null) { return false; } try { String reportBaseName = ""; //$NON-NLS-1$ List jasperPrintList = new ArrayList(); for (String compiledReportPath : compiledReportPaths) { // Fill reports // TODO: Read reportParameters from HashMap Map reportParameters = (Map) allReportParameters.get(compiledReportPath); JasperPrint jrprint = JasperFillManager.fillReport(compiledReportPath, reportParameters, conn); //jasperPrintList.add(JRLoader.loadObject(compiledReportPath)); jasperPrintList.add(jrprint); // Get a configure exporter for the desired output format. File compiledReportFile = new File(compiledReportPath); String lastReportBaseName = compiledReportFile.getName(); int extensionIdx = lastReportBaseName.lastIndexOf("."); //$NON-NLS-1$ if (extensionIdx > 0) { lastReportBaseName = lastReportBaseName.substring(0, extensionIdx); } reportBaseName = reportBaseName.concat(lastReportBaseName); } JRExporter exporter = getExporter(reportOutputType, reportBaseName); // Reverse jasperPrintList order so first resource will appear as first report List jasperPrintListReversed = new ArrayList(); for (int i = jasperPrintList.size() - 1; i >= 0; i--) { jasperPrintListReversed.add(jasperPrintList.get(i)); } // Set the filled report and output stream. exporter.setParameter(JRExporterParameter.JASPER_PRINT_LIST, jasperPrintListReversed); exporter.setParameter(JRExporterParameter.OUTPUT_STREAM, outputStream); // Go! exporter.exportReport(); } catch (JRException jre) { error(Messages.getInstance().getErrorString("JasperReport.ERROR_0014_REPORT_EXECUTION_FAILED"), jre); //$NON-NLS-1$ return false; } finally { try { conn.close(); if (contentItem != null) { contentItem.closeOutputStream(); } } catch (SQLException ignored) { } } return true; } /* * Gets all the report parameters required for the report. */ private Map getReportParameters(JRParameter[] jrparams, HashMap needToPrompt) { Map reportParameters = new HashMap(); for (JRParameter param : jrparams) { if (param.isSystemDefined()) { continue; } String parameterName = param.getName(); // We use Object type so that we can handle String and non-String type params Object parameterValue = null; IActionInput actionInput = getActionDefinition().getInput(parameterName); if (actionInput != null) { if ((actionInput instanceof ActionInput) && ((ActionInput) actionInput).getType().equals("string-list")) { //$NON-NLS-1$ Object parameterObject = getInputValue(parameterName); parameterValue = sqlQuote(parameterObject); } else { parameterValue = getInputStringValue(parameterName); } } if (parameterValue != null && parameterValue.toString().length() != 0) { // give the parameter value to the report engine... if (debug) { debug(Messages.getInstance().getString("JasperReport.DEBUG_ADDING_PARAMETER", parameterName, parameterValue.toString())); //$NON-NLS-1$ } reportParameters.put(parameterName, parameterValue); } // Check for unspecified parameters that need to be specified else if (param.isForPrompting()) { if (debug) { debug(Messages.getInstance().getString("JasperReport.DEBUG_PARAMETER_NEEDED", parameterName)); //$NON-NLS-1$ } // see if we can prompt for this... if (feedbackAllowed()) { IActionParameter paramParameter = getInputParameter(parameterName); if (paramParameter.getPromptStatus() != IActionParameter.PROMPT_PENDING) { String displayName = param.getDescription(); if (displayName == null || displayName.trim().length() == 0) { displayName = parameterName; } String defaultValue = ""; //$NON-NLS-1$ createFeedbackParameter(parameterName, displayName, "", defaultValue, true); //$NON-NLS-1$ } needToPrompt.put(NEED_TO_PROMPT, Boolean.TRUE); } } } return reportParameters; } /* * Load the current jasper report defined by the compiled report path. */ private JasperReport loadJasperReport(String compiledReportPath) { if (debug) { debug(Messages.getInstance().getString("JasperReport.DEBUG_LOADING_REPORT_DESIGN")); //$NON-NLS-1$ } JasperReport jrreport = null; try { jrreport = (JasperReport) JRLoader.loadObject(compiledReportPath); } catch (JRException jre) { jrreport = null; error(Messages.getInstance().getErrorString("JasperReport.ERROR_0012_REPORT_DESIGN_NO_LOADABLE", compiledReportPath), jre); //$NON-NLS-1$ } return jrreport; } /* * Get the location of the compiled report. */ private String getCompiledReportPath(String reportDefinitionPath) { String compiledReportPath = null; if (debug) { debug(Messages.getInstance().getString("JasperReport.GETTING_REPORT_PATH", reportDefinitionPath)); //$NON-NLS-1$ } // See if we have a compiled report or a report definition. If its a // definition, see if a compiled version exists, and if not, compile it. // get the base name of the report. // Parse the path and get the name of the report. File sourceFile = new File(reportDefinitionPath); String reportBaseName = sourceFile.getName(); int extensionIdx = reportBaseName.lastIndexOf("."); //$NON-NLS-1$ if (extensionIdx > 0) reportBaseName = reportBaseName.substring(0, extensionIdx); // If we are handed a .jasper file, just use it as the compiled report // definition. if (reportDefinitionPath.endsWith(COMPILED_JASPER_REPORTS_EXTENSION)) { compiledReportPath = reportDefinitionPath; } else { // Assume its a .jrxml if (!sourceFile.exists()) { compiledReportPath = null; error(Messages.getInstance().getErrorString("JasperReport.ERROR_0009_REPORT_DEFINITION_MISSING", reportDefinitionPath)); //$NON-NLS-1$ } else { if (debug) { debug(Messages.getInstance().getString("JasperReport.DEBUG_REPORT_FILE_FOUND")); //$NON-NLS-1$ } StringBuffer sb = new StringBuffer(); sb.append(sourceFile.getParent()); if (!sourceFile.getParent().endsWith(File.separator)) { sb.append(File.separator); } // Get the directory where the report source is, and compile to // same directory sb.append(reportBaseName).append(COMPILED_JASPER_REPORTS_EXTENSION); compiledReportPath = sb.toString(); } } return compiledReportPath; } /* * Compile the report and see if the report compiles successfully. */ private boolean didReportCompile(String reportDefinitionPath, String compiledReportPath) { boolean reportCompiled = true; if (debug) { debug(Messages.getInstance().getString("JasperReport.DEBUG_RUNNING_REPORT", reportDefinitionPath)); //$NON-NLS-1$ debug(Messages.getInstance().getString("JasperReport.DEBUG_COMPILED_REPORT_LOCATION", compiledReportPath)); //$NON-NLS-1$ } // make sure the report is compiled File compiledReportFile = new File(compiledReportPath); File sourceFile = new File(reportDefinitionPath); // We compile if the compiled file doesn't exist, or the source is // newer if (!compiledReportFile.exists() || sourceFile.lastModified() > compiledReportFile.lastModified()) { if (debug) { debug(Messages.getInstance().getString("JasperReport.DEBUG_COMPILING_REPORT")); //$NON-NLS-1$ } // We are currently ignoring any error conditions with compiled // files // that exist but aren't readable. // Use the jdt compiler System.setProperty("jasper.reports.compiler.class", "net.sf.jasperreports.engine.design.JRJdtCompiler"); //$NON-NLS-1$ //$NON-NLS-2$ // Compile the report design try { JasperCompileManager.compileReportToFile(reportDefinitionPath, compiledReportPath); } catch (JRException jre) { error(Messages.getInstance().getErrorString( "JasperReport.ERROR_0010_UNABLE_TO_COMPILE", reportDefinitionPath, compiledReportPath), jre); //$NON-NLS-1$ reportCompiled = false; } if (debug && reportCompiled) { debug(Messages.getInstance().getString("JasperReport.DEBUG_COMPILED_OK")); //$NON-NLS-1$ } } return reportCompiled; } /* * */ private static String getReportDefinitionPath(IActionSequenceResource resource) { String reportDefinitionPath = null; if (resource.getSourceType() == IActionSequenceResource.SOLUTION_FILE_RESOURCE) { reportDefinitionPath = PentahoSystem.getApplicationContext().getSolutionPath(resource.getAddress()); } else { reportDefinitionPath = resource.getAddress(); } return reportDefinitionPath; } private static String getMimeType(String reportOutputType) { String mimeType = null; if (HTML.equals(reportOutputType)) { mimeType = TEXT_HTML; } else if (PDF.equals(reportOutputType)) { mimeType = "application/pdf"; //$NON-NLS-1$ } else if (XLS.equals(reportOutputType)) { mimeType = "application/vnd.ms-excel"; //$NON-NLS-1$ } else if (CSV.equals(reportOutputType)) { mimeType = "text/text"; //$NON-NLS-1$ } else if (XML.equals(reportOutputType)) { mimeType = "text/xml"; //$NON-NLS-1$ } else if (TXT.equals(reportOutputType)) { mimeType = "text/plain"; //$NON-NLS-1$ } else if (RTF.equals(reportOutputType)) { mimeType = "application/rtf"; //$NON-NLS-1$ } else { mimeType = "application/octet-stream"; //$NON-NLS-1$ } return mimeType; } @SuppressWarnings("deprecation") private OutputStream getOutputStream(String mimeType, String extension, IContentItem contentItem) { OutputStream outputStream = null; JasperReportAction reportAction = (JasperReportAction) getActionDefinition(); if (reportAction.getOutputReport() != null) { //contentItem = getOutputItem(JasperReportAction.REPORT_OUTPUT_ELEMENT, mimeType, extension); contentItem = getOutputItem(reportAction.getOutputReport().getName(), mimeType, extension); try { outputStream = contentItem.getOutputStream(getActionName()); } catch (IOException e) { outputStream = null; } } else if (getOutputNames().size() == 1) { String outputName = (String) getOutputNames().iterator().next(); contentItem = getOutputContentItem(outputName, mimeType); try { outputStream = contentItem.getOutputStream(getActionName()); } catch (IOException e) { outputStream = null; } } else { // There was no output in the action-sequence document, so make a // default // outputStream. warn(Messages.getInstance().getString("Base.WARN_NO_OUTPUT_STREAM")); //$NON-NLS-1$ outputStream = getDefaultOutputStream(mimeType); if (outputStream != null) { setOutputMimeType(mimeType); } } return outputStream; } public boolean init() { // TODO any initialization you need to do before execution return true; } public void done() { // perform any cleanup necessary } private Connection getConnection() { try { // get the report settings JasperReportAction reportAction = (JasperReportAction) getActionDefinition(); String jndiUrl = reportAction.getJndi().getStringValue(); Connection conn = null; if (jndiUrl != null) { IDatasourceService datasourceService = PentahoSystem.getObjectFactory().get(IDatasourceService.class ,null); DataSource ds = datasourceService.getDataSource(jndiUrl); return ds.getConnection(); } else { String driver = reportAction.getDriver().getStringValue(); String connectString = reportAction.getConnection().getStringValue(); String user = reportAction.getUserId().getStringValue(); String password = reportAction.getPassword().getStringValue(); Class.forName(driver); conn = DriverManager.getConnection(connectString, user, password); } return conn; } catch (ObjectFactoryException objface) { error(Messages.getInstance().getErrorString("JasperReport.ERROR_0017_UNABLE_TO_FACTORY_OBJECT")); //$NON-NLS-1$ } catch (ClassNotFoundException cnfe) { error(Messages.getInstance().getErrorString("JasperReport.ERROR_0015_JDBC_DRIVER_LOAD_FAILED")); //$NON-NLS-1$ } catch (SQLException se) { error(Messages.getInstance().getErrorString("JasperReport.ERROR_0016_DATABASE_CONNECTION_FAILED"), se); //$NON-NLS-1$ } catch (DatasourceServiceException dse) { error(Messages.getInstance().getErrorString("JasperReport.ERROR_0016_DATABASE_CONNECTION_FAILED"), dse); //$NON-NLS-1$ } return null; } private String sqlQuote(Object obj) { if (obj == null) { return (null); } String out = null; if (obj instanceof String[]) { // quote everything, and join with '' List c = Arrays.asList((String[]) obj); out = quoteMe(c); } else if (obj instanceof List) { out = quoteMe((Collection) obj); } else { if (!(obj instanceof String)) { warn("Unknown type " + obj.getClass() + " in object " + obj); //$NON-NLS-1$ //$NON-NLS-2$ } out = "'" + obj.toString().replaceAll("'", "'") + "'"; //$NON-NLS-1$//$NON-NLS-2$ //$NON-NLS-3$ //$NON-NLS-4$ } return out; } private static String quoteMe(Collection c) { if (c.size() == 0) { return ""; //$NON-NLS-1$ } StringBuffer sb = new StringBuffer(); for (Object value : c) { sb.append(",'"); //$NON-NLS-1$ sb.append(value.toString().replaceAll("'", "''")); //$NON-NLS-1$ //$NON-NLS-2$ sb.append("'"); //$NON-NLS-1$ } return sb.substring(1); } }