edu.ualberta.med.biobank.reporting.DynamicJasperHelper.java Source code

Java tutorial

Introduction

Here is the source code for edu.ualberta.med.biobank.reporting.DynamicJasperHelper.java

Source

package edu.ualberta.med.biobank.reporting;

/*
 * 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
 *
 *
 */

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.JRDesignQuery;
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.CoreException;
import ar.com.fdvs.dj.core.DJDefaultScriptlet;
import ar.com.fdvs.dj.core.DJException;
import ar.com.fdvs.dj.core.DJJRDesignHelper;
import ar.com.fdvs.dj.core.layout.LayoutManager;
import ar.com.fdvs.dj.core.registration.ColumnRegistrationManager;
import ar.com.fdvs.dj.core.registration.DJGroupRegistrationManager;
import ar.com.fdvs.dj.core.registration.DJGroupVariableDefRegistrationManager;
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.DynamicReportOptions;
import ar.com.fdvs.dj.domain.constants.Page;
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
 * 
 * DD: this class and 2 or 3 others methods has been copied from the
 * DynamicJasper library. It is expecting a url searched into the same
 * classloader than dynamicjasper. But dynamicjasper is in another plugin so it
 * can't find the url for the jasper file that is in this plugin. Since this
 * class is in biobank2 plugin then the url is found. (see issue #1239)
 */
@SuppressWarnings({ "unchecked", "rawtypes", "unused" })
public class DynamicJasperHelper {

    private static final Log log = LogFactory.getLog(DynamicJasperHelper.class);
    public static final String DEFAULT_XML_ENCODING = "UTF-8"; //$NON-NLS-1$
    private static final String DJ_RESOURCE_BUNDLE = DynamicJasperHelper.class.getPackage().getName()
            + ".dj-messages"; //$NON-NLS-1$

    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() //$NON-NLS-1$
                    + ", Locale to use: " + locale); //$NON-NLS-1$
        }
        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)"); //$NON-NLS-1$
            }
        }

        if (messages == null) {
            try {
                messages = ResourceBundle.getBundle(DJ_RESOURCE_BUNDLE, locale);
            } catch (MissingResourceException e) {
                log.warn(e.getMessage() + ", usign default (dj-messages)"); //$NON-NLS-1$
                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: " //$NON-NLS-1$
                            + DJ_RESOURCE_BUNDLE + ", " + e2.getMessage(), e2); //$NON-NLS-1$
                    throw new DJException("Default messajes file not found: " //$NON-NLS-1$
                            + DJ_RESOURCE_BUNDLE + "en.properties", e2); //$NON-NLS-1$
                }
            }
        }
        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: " //$NON-NLS-1$
                        + dr.getTemplateFileName() + ", Attemping to find the file directly in the file system."); //$NON-NLS-1$
                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..."); //$NON-NLS-1$
                    URL url = DynamicJasperHelper.class.getClassLoader().getResource(dr.getTemplateFileName());
                    JasperDesign jdesign = JRXmlLoader.load(url.openStream());
                    jd = DJJRDesignHelper.downCast(jdesign, dr);
                }
                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;
    }

    /**
     * Because all the layout calculations are made from the Domain Model of
     * DynamicJasper, when loading a template file, we have to populate the
     * "ReportOptions" with the settings from the template file (ie: margins,
     * etc)
     * 
     * @param jd
     * @param dr
     */
    protected static void populateReportOptionsFromDesign(DynamicJasperDesign jd, DynamicReport dr) {
        DynamicReportOptions options = dr.getOptions();

        options.setBottomMargin(new Integer(jd.getBottomMargin()));
        options.setTopMargin(new Integer(jd.getTopMargin()));
        options.setLeftMargin(new Integer(jd.getLeftMargin()));
        options.setRightMargin(new Integer(jd.getRightMargin()));

        options.setColumnSpace(new Integer(jd.getColumnSpacing()));
        options.setColumnsPerPage(new Integer(jd.getColumnCount()));

        options.setPage(new Page(jd.getPageHeight(), jd.getPageWidth()));

        if (dr.getQuery() != null) {
            JRDesignQuery query = getJRDesignQuery(dr);
            jd.setQuery(query);
        }

        if (dr.getReportName() != null) {
            jd.setName(dr.getReportName());
        }

    }

    protected static JRDesignQuery getJRDesignQuery(DynamicReport dr) {
        JRDesignQuery query = new JRDesignQuery();
        query.setText(dr.getQuery().getText());
        query.setLanguage(dr.getQuery().getLanguage());
        return query;
    }

    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"); //$NON-NLS-1$
        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"); //$NON-NLS-1$
        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"); //$NON-NLS-1$
        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 //$NON-NLS-1$
                                + "\" already registered, skipping this one: " //$NON-NLS-1$
                                + 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"); //$NON-NLS-1$
        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"); //$NON-NLS-1$
        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());
        }
    }

}