Java tutorial
/* * DynamicJasper: A library for creating reports dynamically by specifying * columns, groups, styles, etc. at runtime. It also saves a lot of development * time in many cases! (http://sourceforge.net/projects/dynamicjasper) * * Copyright (C) 2008 FDV Solutions (http://www.fdvsolutions.com) * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * * License as published by the Free Software Foundation; either * * version 2.1 of the License, or (at your option) any later version. * * This library 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. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA * * */ package ar.com.fdvs.dj.core; import java.io.File; import java.io.IOException; import java.io.OutputStream; import java.net.URL; import java.sql.Connection; import java.sql.ResultSet; import java.util.ArrayList; import java.util.Collection; import java.util.HashMap; import java.util.Iterator; import java.util.List; import java.util.Locale; import java.util.Map; import java.util.MissingResourceException; import java.util.ResourceBundle; import net.sf.jasperreports.engine.JRDataSource; import net.sf.jasperreports.engine.JRException; import net.sf.jasperreports.engine.JRResultSetDataSource; 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.JRCompiler; import net.sf.jasperreports.engine.design.JRDesignField; import net.sf.jasperreports.engine.design.JRDesignGroup; import net.sf.jasperreports.engine.design.JRDesignParameter; import net.sf.jasperreports.engine.design.JasperDesign; import net.sf.jasperreports.engine.util.JRProperties; import net.sf.jasperreports.engine.xml.JRXmlLoader; import net.sf.jasperreports.engine.xml.JRXmlWriter; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; import ar.com.fdvs.dj.core.layout.LayoutManager; import ar.com.fdvs.dj.core.registration.ColumnRegistrationManager; import ar.com.fdvs.dj.core.registration.DJGroupVariableDefRegistrationManager; import ar.com.fdvs.dj.core.registration.DJGroupRegistrationManager; import ar.com.fdvs.dj.domain.ColumnProperty; import ar.com.fdvs.dj.domain.DJCalculation; import ar.com.fdvs.dj.domain.DynamicJasperDesign; import ar.com.fdvs.dj.domain.DynamicReport; import ar.com.fdvs.dj.domain.entities.DJGroup; import ar.com.fdvs.dj.domain.entities.DJGroupVariableDef; import ar.com.fdvs.dj.domain.entities.Parameter; import ar.com.fdvs.dj.domain.entities.Subreport; import ar.com.fdvs.dj.domain.entities.columns.AbstractColumn; import ar.com.fdvs.dj.domain.entities.columns.PercentageColumn; import ar.com.fdvs.dj.util.DJCompilerFactory; import ar.com.fdvs.dj.util.LayoutUtils; /** * Helper class for running a report and some other DJ related stuff */ public class DynamicJasperHelper { private static final Log log = LogFactory.getLog(DynamicJasperHelper.class); public static final String DEFAULT_XML_ENCODING = "UTF-8"; private static final String DJ_RESOURCE_BUNDLE = "dj-messages"; private final static void registerEntities(DynamicJasperDesign jd, DynamicReport dr, LayoutManager layoutManager) { ColumnRegistrationManager columnRegistrationManager = new ColumnRegistrationManager(jd, dr, layoutManager); columnRegistrationManager.registerEntities(dr.getColumns()); DJGroupRegistrationManager djGroupRegistrationManager = new DJGroupRegistrationManager(jd, dr, layoutManager); djGroupRegistrationManager.registerEntities(dr.getColumnsGroups()); registerPercentageColumnsVariables(jd, dr, layoutManager); registerOtherFields(jd, dr.getFields()); Locale locale = dr.getReportLocale() == null ? Locale.getDefault() : dr.getReportLocale(); if (log.isDebugEnabled()) { log.debug("Requested Locale = " + dr.getReportLocale() + ", Locale to use: " + locale); } ResourceBundle messages = null; if (dr.getResourceBundle() != null) { try { messages = ResourceBundle.getBundle(dr.getResourceBundle(), locale); } catch (MissingResourceException e) { log.warn(e.getMessage() + ", usign default (dj-messages)"); } } if (messages == null) { try { messages = ResourceBundle.getBundle(DJ_RESOURCE_BUNDLE, locale); } catch (MissingResourceException e) { log.warn(e.getMessage() + ", usign default (dj-messages)"); try { messages = ResourceBundle.getBundle(DJ_RESOURCE_BUNDLE, Locale.ENGLISH); //this cannot fail because is included in the DJ jar } catch (MissingResourceException e2) { log.error("Default messajes not found: " + DJ_RESOURCE_BUNDLE + ", " + e2.getMessage(), e2); throw new DJException( "Default messajes file not found: " + DJ_RESOURCE_BUNDLE + "en.properties", e2); } } } jd.getParametersWithValues().put(JRDesignParameter.REPORT_RESOURCE_BUNDLE, messages); jd.getParametersWithValues().put(JRDesignParameter.REPORT_LOCALE, locale); // JRDesignParameter.REPORT_RESOURCE_BUNDLE // report. } private static void registerPercentageColumnsVariables(DynamicJasperDesign jd, DynamicReport dr, LayoutManager layoutManager) { for (Iterator iterator = dr.getColumns().iterator(); iterator.hasNext();) { AbstractColumn column = (AbstractColumn) iterator.next(); // if (column instanceof PercentageColumn) { // PercentageColumn percentageColumn = ((PercentageColumn) column); // JRDesignGroup jrGroup = LayoutUtils.getJRDesignGroup(jd, layoutManager, percentageColumn.getGroup()); // ColumnsGroupTemporalVariablesRegistrationManager variablesRM = new ColumnsGroupTemporalVariablesRegistrationManager(jd,dr,layoutManager, jrGroup); // DJGroupTemporalVariable variable = new DJGroupTemporalVariable(percentageColumn.getGroupVariableName(), percentageColumn.getPercentageColumn(), DJCalculation.SUM); // Collection entities = new ArrayList(); // entities.add(variable); // variablesRM.registerEntities(entities); // } /** * Group should not be needed in the percentage column. There should be a variable for each group, using * parent group as "rest group" */ if (column instanceof PercentageColumn) { PercentageColumn percentageColumn = ((PercentageColumn) column); for (Iterator iterator2 = dr.getColumnsGroups().iterator(); iterator2.hasNext();) { DJGroup djGroup = (DJGroup) iterator2.next(); JRDesignGroup jrGroup = LayoutUtils.getJRDesignGroup(jd, layoutManager, djGroup); DJGroupVariableDefRegistrationManager variablesRM = new DJGroupVariableDefRegistrationManager( jd, dr, layoutManager, jrGroup); DJGroupVariableDef variable = new DJGroupVariableDef( percentageColumn.getGroupVariableName(djGroup), percentageColumn.getPercentageColumn(), DJCalculation.SUM); Collection entities = new ArrayList(); entities.add(variable); variablesRM.registerEntities(entities); } } } } private static void registerOtherFields(DynamicJasperDesign jd, List fields) { for (Iterator iter = fields.iterator(); iter.hasNext();) { ColumnProperty element = (ColumnProperty) iter.next(); JRDesignField field = new JRDesignField(); field.setValueClassName(element.getValueClassName()); field.setName(element.getProperty()); try { jd.addField(field); } catch (JRException e) { // e.printStackTrace(); //if the field is already registered, it's not a problem log.warn(e.getMessage()); } } } protected static DynamicJasperDesign generateJasperDesign(DynamicReport dr) throws CoreException { DynamicJasperDesign jd = null; try { if (dr.getTemplateFileName() != null) { log.info("about to load template file: " + dr.getTemplateFileName() + ", Attemping to find the file directly in the file system."); File file = new File(dr.getTemplateFileName()); if (file.exists()) { JasperDesign jdesign = JRXmlLoader.load(file); jd = DJJRDesignHelper.downCast(jdesign, dr); } else { log.info("Not found: Attemping to find the file in the classpath..."); URL url = DynamicJasperHelper.class.getClassLoader().getResource(dr.getTemplateFileName()); JasperDesign jdesign = JRXmlLoader.load(url.openStream()); jd = DJJRDesignHelper.downCast(jdesign, dr); } DJJRDesignHelper.populateReportOptionsFromDesign(jd, dr); } else { //Create new JasperDesign from the scratch jd = DJJRDesignHelper.getNewDesign(dr); } jd.setScriptletClass(DJDefaultScriptlet.class.getName()); //Set up scripttlet so that custom expressions can do their magic registerParameters(jd, dr); } catch (JRException e) { throw new CoreException(e.getMessage(), e); } catch (IOException e) { throw new CoreException(e.getMessage(), e); } return jd; } protected static void registerParameters(DynamicJasperDesign jd, DynamicReport dr) { for (Iterator iterator = dr.getParameters().iterator(); iterator.hasNext();) { Parameter param = (Parameter) iterator.next(); JRDesignParameter jrparam = new JRDesignParameter(); jrparam.setName(param.getName()); jrparam.setValueClassName(param.getClassName()); try { jd.addParameter(jrparam); } catch (JRException e) { throw new CoreException(e.getMessage(), e); } } } public static JasperPrint generateJasperPrint(DynamicReport dr, LayoutManager layoutManager, JRDataSource ds) throws JRException { return generateJasperPrint(dr, layoutManager, ds, new HashMap()); } public static JasperPrint generateJasperPrint(DynamicReport dr, LayoutManager layoutManager, Collection collection) throws JRException { JRDataSource ds = new JRBeanCollectionDataSource(collection); return generateJasperPrint(dr, layoutManager, ds, new HashMap()); } public static JasperPrint generateJasperPrint(DynamicReport dr, LayoutManager layoutManager, ResultSet resultSet) throws JRException { JRDataSource ds = new JRResultSetDataSource(resultSet); return generateJasperPrint(dr, layoutManager, ds, new HashMap()); } /** * Compiles and fills the reports design. * * @param dr the DynamicReport * @param layoutManager the object in charge of doing the layout * @param ds The datasource * @param _parameters Map with parameters that the report may need * @return * @throws JRException */ public static JasperPrint generateJasperPrint(DynamicReport dr, LayoutManager layoutManager, JRDataSource ds, Map _parameters) throws JRException { log.info("generating JasperPrint"); JasperPrint jp = null; // if (_parameters == null) // _parameters = new HashMap(); // // visitSubreports(dr, _parameters); // compileOrLoadSubreports(dr, _parameters); // // DynamicJasperDesign jd = generateJasperDesign(dr); // Map params = new HashMap(); // if (!_parameters.isEmpty()){ // registerParams(jd,_parameters); // params.putAll(_parameters); // } // // registerEntities(jd, dr); // layoutManager.applyLayout(jd, dr); // JRProperties.setProperty(JRProperties.COMPILER_CLASS, DJCompilerFactory.getCompilerClassName()); // // JasperReport jr = JasperCompileManager.compileReport(jd); // params.putAll(jd.getParametersWithValues()); JasperReport jr = DynamicJasperHelper.generateJasperReport(dr, layoutManager, _parameters); jp = JasperFillManager.fillReport(jr, _parameters, ds); return jp; } /** * For running queries embebed in the report design * @param dr * @param layoutManager * @param con * @param _parameters * @return * @throws JRException */ public static JasperPrint generateJasperPrint(DynamicReport dr, LayoutManager layoutManager, Connection con, Map _parameters) throws JRException { log.info("generating JasperPrint"); JasperPrint jp = null; if (_parameters == null) _parameters = new HashMap(); visitSubreports(dr, _parameters); compileOrLoadSubreports(dr, _parameters); DynamicJasperDesign jd = generateJasperDesign(dr); Map params = new HashMap(); if (!_parameters.isEmpty()) { registerParams(jd, _parameters); params.putAll(_parameters); } registerEntities(jd, dr, layoutManager); layoutManager.applyLayout(jd, dr); JRProperties.setProperty(JRCompiler.COMPILER_PREFIX, DJCompilerFactory.getCompilerClassName()); JasperReport jr = JasperCompileManager.compileReport(jd); params.putAll(jd.getParametersWithValues()); jp = JasperFillManager.fillReport(jr, params, con); return jp; } /** * For compiling and filling reports whose datasource is passed as parameter (e.g. Hibernate, Mondrean, etc.) * @param dr * @param layoutManager * @param _parameters * @return * @throws JRException */ public static JasperPrint generateJasperPrint(DynamicReport dr, LayoutManager layoutManager, Map _parameters) throws JRException { log.info("generating JasperPrint"); JasperPrint jp = null; if (_parameters == null) _parameters = new HashMap(); visitSubreports(dr, _parameters); compileOrLoadSubreports(dr, _parameters); DynamicJasperDesign jd = generateJasperDesign(dr); Map params = new HashMap(); if (!_parameters.isEmpty()) { registerParams(jd, _parameters); params.putAll(_parameters); } registerEntities(jd, dr, layoutManager); layoutManager.applyLayout(jd, dr); // JRProperties.setProperty(JRProperties.COMPILER_CLASS, DJCompilerFactory.getCompilerClassName()); JRProperties.setProperty(JRCompiler.COMPILER_PREFIX, DJCompilerFactory.getCompilerClassName()); JasperReport jr = JasperCompileManager.compileReport(jd); params.putAll(jd.getParametersWithValues()); jp = JasperFillManager.fillReport(jr, params); return jp; } /** * Creates a jrxml file * @param dr * @param layoutManager * @param _parameters * @param xmlEncoding (default is UTF-8 ) * @return * @throws JRException */ public static String generateJRXML(DynamicReport dr, LayoutManager layoutManager, Map _parameters, String xmlEncoding) throws JRException { JasperReport jr = generateJasperReport(dr, layoutManager, _parameters); if (xmlEncoding == null) xmlEncoding = DEFAULT_XML_ENCODING; return JRXmlWriter.writeReport(jr, xmlEncoding); } /** * Creates a jrxml file * @param dr * @param layoutManager * @param _parameters * @param xmlEncoding (default is UTF-8 ) * @param outputStream * @throws JRException */ public static void generateJRXML(DynamicReport dr, LayoutManager layoutManager, Map _parameters, String xmlEncoding, OutputStream outputStream) throws JRException { JasperReport jr = generateJasperReport(dr, layoutManager, _parameters); if (xmlEncoding == null) xmlEncoding = DEFAULT_XML_ENCODING; JRXmlWriter.writeReport(jr, outputStream, xmlEncoding); } /** * Creates a jrxml file * @param dr * @param layoutManager * @param _parameters * @param xmlEncoding (default is UTF-8 ) * @param filename the path to the destination file * @throws JRException */ public static void generateJRXML(DynamicReport dr, LayoutManager layoutManager, Map _parameters, String xmlEncoding, String filename) throws JRException { JasperReport jr = generateJasperReport(dr, layoutManager, _parameters); if (xmlEncoding == null) xmlEncoding = DEFAULT_XML_ENCODING; ensurePath(filename); JRXmlWriter.writeReport(jr, filename, xmlEncoding); } public static void generateJRXML(JasperReport jr, String xmlEncoding, String filename) throws JRException { if (xmlEncoding == null) xmlEncoding = DEFAULT_XML_ENCODING; ensurePath(filename); JRXmlWriter.writeReport(jr, filename, xmlEncoding); } private static void ensurePath(String filename) { File outputFile = new File(filename); File parentFile = outputFile.getParentFile(); if (parentFile != null) parentFile.mkdirs(); } protected static void compileOrLoadSubreports(DynamicReport dr, Map _parameters) throws JRException { for (Iterator iterator = dr.getColumnsGroups().iterator(); iterator.hasNext();) { DJGroup group = (DJGroup) iterator.next(); //Header Subreports for (Iterator iterator2 = group.getHeaderSubreports().iterator(); iterator2.hasNext();) { Subreport subreport = (Subreport) iterator2.next(); if (subreport.getDynamicReport() != null) { compileOrLoadSubreports(subreport.getDynamicReport(), _parameters); JasperReport jp = generateJasperReport(subreport.getDynamicReport(), subreport.getLayoutManager(), _parameters); _parameters.put(jp.toString(), jp); subreport.setReport(jp); } } //Footer Subreports for (Iterator iterator2 = group.getFooterSubreports().iterator(); iterator2.hasNext();) { Subreport subreport = (Subreport) iterator2.next(); if (subreport.getDynamicReport() != null) { compileOrLoadSubreports(subreport.getDynamicReport(), _parameters); JasperReport jp = generateJasperReport(subreport.getDynamicReport(), subreport.getLayoutManager(), _parameters); _parameters.put(jp.toString(), jp); subreport.setReport(jp); } } } } /** * For every String key, it registers the object as a parameter to make it available * in the report. * @param jd * @param _parameters */ public static void registerParams(DynamicJasperDesign jd, Map _parameters) { for (Iterator iterator = _parameters.keySet().iterator(); iterator.hasNext();) { Object key = iterator.next(); if (key instanceof String) { try { Object value = _parameters.get(key); if (jd.getParametersMap().get(key) != null) { log.warn("Parameter \"" + key + "\" already registered, skipping this one: " + value); continue; } JRDesignParameter parameter = new JRDesignParameter(); if (value == null) //There are some Map implementations that allows nulls values, just go on continue; // parameter.setValueClassName(value.getClass().getCanonicalName()); Class clazz = value.getClass().getComponentType(); if (clazz == null) clazz = value.getClass(); parameter.setValueClass(clazz); //NOTE this is very strange //when using an array as subreport-data-source, I must pass the parameter class name like this: value.getClass().getComponentType() parameter.setName((String) key); jd.addParameter(parameter); } catch (JRException e) { //nothing to do } } } } /** * Compiles the report and applies the layout. <b>generatedParams</b> MUST NOT BE NULL * All the key objects from the generatedParams map that are String, will be registered as parameters of the report. * @param dr * @param layoutManager * @param generatedParams * @return * @throws JRException */ public final static JasperReport generateJasperReport(DynamicReport dr, LayoutManager layoutManager, Map generatedParams) throws JRException { log.info("generating JasperReport"); JasperReport jr = null; if (generatedParams == null) generatedParams = new HashMap(); visitSubreports(dr, generatedParams); compileOrLoadSubreports(dr, generatedParams); DynamicJasperDesign jd = generateJasperDesign(dr); registerEntities(jd, dr, layoutManager); registerParams(jd, generatedParams); //if we have parameters from the outside, we register them layoutManager.applyLayout(jd, dr); JRProperties.setProperty(JRCompiler.COMPILER_PREFIX, "ar.com.fdvs.dj.util.DJJRJdtCompiler"); jr = JasperCompileManager.compileReport(jd); generatedParams.putAll(jd.getParametersWithValues()); return jr; } /** * Performs any needed operation on subreports after they are built like ensuring proper subreport with * if "fitToParentPrintableArea" flag is set to true * @param dr * @param _parameters * @throws JRException */ protected static void visitSubreports(DynamicReport dr, Map _parameters) throws JRException { for (Iterator iterator = dr.getColumnsGroups().iterator(); iterator.hasNext();) { DJGroup group = (DJGroup) iterator.next(); //Header Subreports for (Iterator iterator2 = group.getHeaderSubreports().iterator(); iterator2.hasNext();) { Subreport subreport = (Subreport) iterator2.next(); if (subreport.getDynamicReport() != null) { visitSubreport(dr, subreport, _parameters); visitSubreports(subreport.getDynamicReport(), _parameters); } } //Footer Subreports for (Iterator iterator2 = group.getFooterSubreports().iterator(); iterator2.hasNext();) { Subreport subreport = (Subreport) iterator2.next(); if (subreport.getDynamicReport() != null) { visitSubreport(dr, subreport, _parameters); visitSubreports(subreport.getDynamicReport(), _parameters); } } } } protected static void visitSubreport(DynamicReport parentDr, Subreport subreport, Map _parameters) { DynamicReport childDr = subreport.getDynamicReport(); if (subreport.isFitToParentPrintableArea()) { childDr.getOptions().setPage(parentDr.getOptions().getPage()); childDr.getOptions().setLeftMargin(parentDr.getOptions().getLeftMargin()); childDr.getOptions().setRightMargin(parentDr.getOptions().getRightMargin()); } } }