Java tutorial
/* * JasperReports - Free Java Reporting Library. * Copyright (C) 2001 - 2019 TIBCO Software Inc. All rights reserved. * http://www.jaspersoft.com * * Unless you have purchased a commercial license agreement from Jaspersoft, * the following license terms apply: * * This program is part of JasperReports. * * JasperReports 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 3 of the License, or * (at your option) any later version. * * JasperReports 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 JasperReports. If not, see <http://www.gnu.org/licenses/>. */ /* * Contributors: * John Bindel - jbindel@users.sourceforge.net */ package net.sf.jasperreports.engine.fill; import java.text.Format; import java.util.ArrayList; import java.util.Arrays; import java.util.Collection; import java.util.Collections; import java.util.HashMap; import java.util.HashSet; import java.util.Iterator; import java.util.List; import java.util.Locale; import java.util.Map; import java.util.ResourceBundle; import java.util.Set; import java.util.TimeZone; import java.util.UUID; import java.util.concurrent.ConcurrentHashMap; import java.util.stream.Collectors; import org.apache.commons.javaflow.api.continuable; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; import net.sf.jasperreports.engine.JRBand; import net.sf.jasperreports.engine.JRDefaultStyleProvider; import net.sf.jasperreports.engine.JRException; import net.sf.jasperreports.engine.JRExpression; import net.sf.jasperreports.engine.JRGroup; import net.sf.jasperreports.engine.JROrigin; import net.sf.jasperreports.engine.JRParameter; import net.sf.jasperreports.engine.JRPrintElement; import net.sf.jasperreports.engine.JRPrintPage; import net.sf.jasperreports.engine.JRReport; import net.sf.jasperreports.engine.JRReportTemplate; import net.sf.jasperreports.engine.JRRuntimeException; import net.sf.jasperreports.engine.JRStyle; import net.sf.jasperreports.engine.JRStyleSetter; import net.sf.jasperreports.engine.JRTemplate; import net.sf.jasperreports.engine.JRTemplateReference; import net.sf.jasperreports.engine.JRVariable; import net.sf.jasperreports.engine.JasperPrint; import net.sf.jasperreports.engine.JasperReportsContext; import net.sf.jasperreports.engine.base.JRBasePrintPage; import net.sf.jasperreports.engine.base.JRVirtualPrintPage; import net.sf.jasperreports.engine.type.BandTypeEnum; import net.sf.jasperreports.engine.type.EvaluationTimeEnum; import net.sf.jasperreports.engine.type.OrientationEnum; import net.sf.jasperreports.engine.type.PrintOrderEnum; import net.sf.jasperreports.engine.type.PropertyEvaluationTimeEnum; import net.sf.jasperreports.engine.type.RunDirectionEnum; import net.sf.jasperreports.engine.type.SectionTypeEnum; import net.sf.jasperreports.engine.type.WhenNoDataTypeEnum; import net.sf.jasperreports.engine.type.WhenResourceMissingTypeEnum; import net.sf.jasperreports.engine.util.JRDataUtils; import net.sf.jasperreports.engine.util.JRStyledTextParser; import net.sf.jasperreports.engine.util.JRStyledTextUtil; import net.sf.jasperreports.engine.util.StyleResolver; import net.sf.jasperreports.repo.RepositoryContext; import net.sf.jasperreports.repo.RepositoryResourceContext; import net.sf.jasperreports.repo.SimpleRepositoryContext; import net.sf.jasperreports.repo.SimpleRepositoryResourceContext; /** * @author Teodor Danciu (teodord@users.sourceforge.net) */ public abstract class JRBaseFiller extends BaseReportFiller implements JRDefaultStyleProvider { private static final Log log = LogFactory.getLog(JRBaseFiller.class); public static final String EXCEPTION_MESSAGE_KEY_INFINITE_LOOP_CREATING_NEW_PAGE = "fill.common.filler.infinite.loop.creating.new.page"; public static final String EXCEPTION_MESSAGE_KEY_COLUMN_HEADER_OVERFLOW_INFINITE_LOOP = "fill.common.filler.column.header.overflow.infinite.loop"; public static final String EXCEPTION_MESSAGE_KEY_CIRCULAR_DEPENDENCY_FOUND = "fill.base.filler.circular.dependency.found"; public static final String EXCEPTION_MESSAGE_KEY_EXTERNAL_STYLE_NAME_NOT_SET = "fill.base.filler.external.style.name.not.set"; public static final String EXCEPTION_MESSAGE_KEY_NO_SUCH_GROUP = "fill.base.filler.no.such.group"; public static final String EXCEPTION_MESSAGE_KEY_PAGE_HEADER_OVERFLOW_INFINITE_LOOP = "fill.common.filler.page.header.overflow.infinite.loop"; public static final String EXCEPTION_MESSAGE_KEY_UNSUPPORTED_REPORT_SECTION_TYPE = "fill.base.filler.unsupported.report.section.type"; public static final String EXCEPTION_MESSAGE_KEY_KEEP_TOGETHER_CONTENT_DOES_NOT_FIT = "fill.common.filler.keep.together.content.does.not.fit"; private static final int PAGE_HEIGHT_PAGINATION_IGNORED = 0x7d000000;//less than Integer.MAX_VALUE to avoid private static final int PAGE_WIDTH_IGNORED = 0x7d000000; protected BandReportFillerParent bandReportParent; private JRStyledTextParser styledTextParser = JRStyledTextParser.getInstance(); /** * */ protected String name; protected int columnCount; protected PrintOrderEnum printOrder; protected RunDirectionEnum columnDirection; protected int pageWidth; protected int maxPageWidth; protected int pageHeight; protected OrientationEnum orientation; private WhenNoDataTypeEnum whenNoDataType; protected int columnWidth; protected int columnSpacing; protected int leftMargin; protected int rightMargin; protected int topMargin; protected int bottomMargin; protected boolean isTitleNewPage; protected boolean isSummaryNewPage; protected boolean isSummaryWithPageHeaderAndFooter; protected boolean isFloatColumnFooter; /** * the resource missing handling type */ protected WhenResourceMissingTypeEnum whenResourceMissingType; protected JRFillReportTemplate[] reportTemplates; protected List<ReportTemplateSource> templates; protected JRStyle defaultStyle; protected StyleResolver styleResolver; protected JRStyle[] styles; protected JRFillGroup[] groups; protected JRFillSection missingFillSection; protected JRFillBand missingFillBand; protected JRFillBand background; protected JRFillBand title; protected JRFillBand pageHeader; protected JRFillBand columnHeader; protected JRFillSection detailSection; protected JRFillBand columnFooter; protected JRFillBand pageFooter; protected JRFillBand lastPageFooter; protected JRFillBand summary; protected JRFillBand noData; protected JRPrintPage printPage; /** * List of {@link JRFillBand JRFillBand} objects containing all bands of the * report. */ protected List<JRBand> bands; /** * Collection of subfillers */ protected Map<Integer, JRBaseFiller> subfillers; private boolean bandOverFlowAllowed; /** * */ protected Map<String, Format> dateFormatCache = new HashMap<String, Format>(); protected Map<String, Format> numberFormatCache = new HashMap<String, Format>(); protected GroupFooterElementRange groupFooterPositionElementRange; // we need to keep detail element range separate from orphan group footer element range // because it is created in advance, as by the time we need to create the element range // for the current detail, we do not know if any group will break and footers would be filled protected ElementRange detailElementRange; // we use this element range to keep the detail element range once orphan footers start to render; // this is more like a flag to signal that we are currently dealing with orphan group footers protected ElementRange orphanGroupFooterDetailElementRange; // we keep the content of orphan group footers bands in separate element range because in horizontal // filler, the detail element range can have a different columnIndex and thus be moved with a different X offset protected ElementRange orphanGroupFooterElementRange; // keep the content of floating column footer so that it can be moved up in case content is moved // from one page/column to the next due to keep together, min details or orphan footer groups protected ElementRange floatColumnFooterElementRange; /** * */ protected boolean isCreatingNewPage; protected boolean isNewPage; protected boolean isNewColumn; protected boolean isFirstPageBand; protected boolean isFirstColumnBand; // indicates if values from current record have already appeared on current page through a band being evaluated with JRExpression.EVALUATION_DEFAULT protected boolean isCrtRecordOnPage; protected boolean isCrtRecordOnColumn; // we call it min level because footers print in reverse order and lower level means outer footer protected Integer preventOrphanFootersMinLevel; protected int crtGroupFootersLevel; protected int columnIndex; protected int offsetX; protected int offsetY; protected int columnHeaderOffsetY; protected int columnFooterOffsetY; protected int lastPageColumnFooterOffsetY; protected boolean isLastPageFooter; protected boolean isReorderBandElements; protected int usedPageHeight = 0; /** * */ protected JRBaseFiller(JasperReportsContext jasperReportsContext, JasperReportSource reportSource, BandReportFillerParent parent) throws JRException { super(jasperReportsContext, reportSource, parent); this.bandReportParent = parent; groups = mainDataset.groups; createReportTemplates(factory); String reportName = this.bandReportParent == null ? null : this.bandReportParent.getReportName(); background = createFillBand(jasperReport.getBackground(), reportName, BandTypeEnum.BACKGROUND); title = createFillBand(jasperReport.getTitle(), reportName, BandTypeEnum.TITLE); pageHeader = createFillBand(jasperReport.getPageHeader(), reportName, BandTypeEnum.PAGE_HEADER); columnHeader = createFillBand(jasperReport.getColumnHeader(), reportName, BandTypeEnum.COLUMN_HEADER); detailSection = factory.getSection(jasperReport.getDetailSection()); if (detailSection != missingFillSection) { detailSection.setOrigin(new JROrigin(reportName, BandTypeEnum.DETAIL)); } columnFooter = createFillBand(jasperReport.getColumnFooter(), reportName, BandTypeEnum.COLUMN_FOOTER); pageFooter = createFillBand(jasperReport.getPageFooter(), reportName, BandTypeEnum.PAGE_FOOTER); lastPageFooter = createFillBand(jasperReport.getLastPageFooter(), reportName, BandTypeEnum.LAST_PAGE_FOOTER); summary = createFillBand(jasperReport.getSummary(), reportName, BandTypeEnum.SUMMARY); if (summary != missingFillBand && summary.isEmpty()) { summary = missingFillBand; } noData = createFillBand(jasperReport.getNoData(), reportName, BandTypeEnum.NO_DATA); initDatasets(); initBands(); } @Override protected void jasperReportSet() { SectionTypeEnum sectionType = jasperReport.getSectionType(); if (sectionType != null && sectionType != SectionTypeEnum.BAND) { throw new JRRuntimeException(EXCEPTION_MESSAGE_KEY_UNSUPPORTED_REPORT_SECTION_TYPE, new Object[] { jasperReport.getSectionType() }); } /* */ name = jasperReport.getName(); columnCount = jasperReport.getColumnCount(); printOrder = jasperReport.getPrintOrderValue(); columnDirection = jasperReport.getColumnDirection(); pageWidth = jasperReport.getPageWidth(); pageHeight = jasperReport.getPageHeight(); orientation = jasperReport.getOrientationValue(); whenNoDataType = jasperReport.getWhenNoDataTypeValue(); columnWidth = jasperReport.getColumnWidth(); columnSpacing = jasperReport.getColumnSpacing(); leftMargin = jasperReport.getLeftMargin(); rightMargin = jasperReport.getRightMargin(); topMargin = jasperReport.getTopMargin(); bottomMargin = jasperReport.getBottomMargin(); isTitleNewPage = jasperReport.isTitleNewPage(); isSummaryNewPage = jasperReport.isSummaryNewPage(); isSummaryWithPageHeaderAndFooter = jasperReport.isSummaryWithPageHeaderAndFooter(); isFloatColumnFooter = jasperReport.isFloatColumnFooter(); whenResourceMissingType = jasperReport.getWhenResourceMissingTypeValue(); } @Override protected JRFillObjectFactory initFillFactory() { JRFillObjectFactory fillFactory = new JRFillObjectFactory(this); // needed when creating group bands defaultStyleListeners = new ArrayList<DefaultStyleListener>(); missingFillBand = new JRFillBand(this, null, fillFactory); missingFillSection = new JRFillSection(this, null, fillFactory); return fillFactory; } private JRFillBand createFillBand(JRBand reportBand, String reportName, BandTypeEnum bandType) { JRFillBand fillBand = factory.getBand(reportBand); if (fillBand != missingFillBand) { JROrigin origin = new JROrigin(reportName, bandType); fillBand.setOrigin(origin); } return fillBand; } @Override protected void setJasperReportsContext(JasperReportsContext jasperReportsContext) { super.setJasperReportsContext(jasperReportsContext); this.styleResolver = new StyleResolver(jasperReportsContext); } /** * Returns the report fields indexed by name. * * @return the report fields map */ protected Map<String, JRFillField> getFieldsMap() { return mainDataset.fieldsMap; } /** * Returns the report variables indexed by name. * * @return the report variables map */ protected Map<String, JRFillVariable> getVariablesMap() { return mainDataset.variablesMap; } /** * Returns a report field. * * @param fieldName the field name * @return the field */ protected JRFillField getField(String fieldName) { return mainDataset.getFillField(fieldName); } private void initBands() { bands = new ArrayList<JRBand>(8 + (groups == null ? 0 : (2 * groups.length))); bands.add(title); bands.add(summary); bands.add(pageHeader); bands.add(pageFooter); bands.add(lastPageFooter); bands.add(columnHeader); bands.add(columnFooter); if (detailSection.getBands() != null) { bands.addAll(Arrays.asList(detailSection.getBands())); } bands.add(noData); if (groups != null && groups.length > 0) { for (int i = 0; i < groups.length; i++) { JRFillGroup group = groups[i]; if (group.getGroupHeaderSection().getBands() != null) { bands.addAll(Arrays.asList(group.getGroupHeaderSection().getBands())); } if (group.getGroupFooterSection().getBands() != null) { bands.addAll(Arrays.asList(group.getGroupFooterSection().getBands())); } } } initBandsNowEvaluationTimes(); } private void initBandsNowEvaluationTimes() { JREvaluationTime[] groupEvaluationTimes; if (groups == null) { groupEvaluationTimes = new JREvaluationTime[0]; } else { groupEvaluationTimes = new JREvaluationTime[groups.length]; for (int i = 0; i < groups.length; i++) { groupEvaluationTimes[i] = JREvaluationTime.getGroupEvaluationTime(groups[i].getName()); } for (int i = 0; i < groups.length; i++) { JRGroup group = groups[i]; JRFillSection footer = (JRFillSection) group.getGroupFooterSection(); for (int j = i; j < groupEvaluationTimes.length; ++j) { footer.addNowEvaluationTime(groupEvaluationTimes[j]); } } } columnFooter.addNowEvaluationTime(JREvaluationTime.EVALUATION_TIME_COLUMN); pageFooter.addNowEvaluationTime(JREvaluationTime.EVALUATION_TIME_COLUMN); pageFooter.addNowEvaluationTime(JREvaluationTime.EVALUATION_TIME_PAGE); summary.addNowEvaluationTimes(groupEvaluationTimes); noData.addNowEvaluationTimes(groupEvaluationTimes); } protected List<String> getPrintTransferPropertyPrefixes() { return printTransferPropertyPrefixes; } /** * */ public JRStyledTextParser getStyledTextParser() { return styledTextParser; } protected JRStyledTextUtil getStyledTextUtil() { return fillContext.getStyledTextUtil(); } /** * Returns the number of generated master print pages. * * @return the number of generated master print pages */ public int getCurrentPageCount() { return getMasterFiller().jasperPrint.getPages().size(); } @Override public JRStyle getDefaultStyle() { return defaultStyle; } @Override public StyleResolver getStyleResolver() { return styleResolver; } protected boolean isSubreportRunToBottom() { return bandReportParent != null && bandReportParent.isRunToBottom(); } /** * */ protected JRPrintPage getCurrentPage() { return printPage; } /** * */ protected abstract void setPageHeight(int pageHeight); @Override @continuable public JasperPrint fill(Map<String, Object> parameterValues) throws JRException { if (parameterValues == null) { parameterValues = new HashMap<String, Object>(); } if (log.isDebugEnabled()) { log.debug("Fill " + fillerId + ": filling report"); } setParametersToContext(parameterValues); fillingThread = Thread.currentThread(); JRResourcesFillUtil.ResourcesFillContext resourcesContext = JRResourcesFillUtil .setResourcesFillContext(parameterValues); boolean success = false; try { createBoundElemementMaps(); if (parent != null) { bandReportParent.registerSubfiller(this); } setParameters(parameterValues); setBookmarkHelper(); loadStyles(); jasperPrint.setName(name); jasperPrint.setPageWidth(pageWidth); jasperPrint.setPageHeight(pageHeight); jasperPrint.setTopMargin(topMargin); jasperPrint.setLeftMargin(leftMargin); jasperPrint.setBottomMargin(bottomMargin); jasperPrint.setRightMargin(rightMargin); jasperPrint.setOrientation(orientation); jasperPrint.setFormatFactoryClass(jasperReport.getFormatFactoryClass()); jasperPrint.setLocaleCode(JRDataUtils.getLocaleCode(getLocale())); jasperPrint.setTimeZoneId(JRDataUtils.getTimeZoneId(getTimeZone())); propertiesUtil.transferProperties(mainDataset, jasperPrint, JasperPrint.PROPERTIES_PRINT_TRANSFER_PREFIX); jasperPrint.setDefaultStyle(defaultStyle); /* */ if (styles != null && styles.length > 0) { for (int i = 0; i < styles.length; i++) { addPrintStyle(styles[i]); } } /* */ mainDataset.start(); /* */ fillReport(); mainDataset.evaluateProperties(PropertyEvaluationTimeEnum.REPORT); propertiesUtil.transferProperties(mainDataset, jasperPrint, JasperPrint.PROPERTIES_PRINT_TRANSFER_PREFIX); // add consolidates styles as normal styles in the print object // for (Iterator it = consolidatedStyles.values().iterator(); it.hasNext();) // { // jasperPrint.addStyle((JRStyle) it.next()); // } if (log.isDebugEnabled()) { log.debug("Fill " + fillerId + ": ended"); } success = true; return jasperPrint; } finally { mainDataset.closeDatasource(); mainDataset.disposeParameterContributors(); if (success && parent == null) { // commit the cached data fillContext.cacheDone(); } if (parent != null) { bandReportParent.unregisterSubfiller(this); } delayedActions.dispose(); fillingThread = null; //kill the subreport filler threads abortSubfillers(); if (parent == null) { fillContext.dispose(); } JRResourcesFillUtil.revertResourcesFillContext(resourcesContext); } } public void addPrintStyle(JRStyle style) throws JRException { jasperPrint.addStyle(style, true); } protected static interface DefaultStyleListener { void defaultStyleSet(JRStyle style); } private List<DefaultStyleListener> defaultStyleListeners; protected void addDefaultStyleListener(DefaultStyleListener listener) { defaultStyleListeners.add(listener); } protected void setDefaultStyle(JRStyle style) { defaultStyle = style; for (Iterator<DefaultStyleListener> it = defaultStyleListeners.iterator(); it.hasNext();) { DefaultStyleListener listener = it.next(); listener.defaultStyleSet(style); } } protected void loadStyles() throws JRException { List<JRStyle> styleList = collectStyles(); JRStyle reportDefaultStyle = jasperReport.getDefaultStyle(); if (reportDefaultStyle == null) { lookupExternalDefaultStyle(styleList); } List<JRStyle> includedStyles = factory.setStyles(styleList); if (bandReportParent != null) { bandReportParent.registerReportStyles(includedStyles); } styles = includedStyles.toArray(new JRStyle[includedStyles.size()]); if (reportDefaultStyle != null) { setDefaultStyle(factory.getStyle(reportDefaultStyle)); } } public void registerReportStyles(UUID id, List<JRStyle> styles) { if (bandReportParent == null) { fillContext.registerReportStyles(jasperReport, id, styles); } else { String reportLocation = bandReportParent.getReportLocation(); if (reportLocation != null) { fillContext.registerReportStyles(reportLocation, id, styles); } } } private static final JRStyleSetter DUMMY_STYLE_SETTER = new JRStyleSetter() { @Override public void setStyle(JRStyle style) { } @Override public void setStyleNameReference(String name) { } }; protected List<JRStyle> collectStyles() throws JRException { List<JRStyle> styleList = collectTemplateStyles(); JRStyle[] reportStyles = jasperReport.getStyles(); if (reportStyles != null) { styles = new JRStyle[reportStyles.length];//FIXME remove this for (int i = 0; i < reportStyles.length; i++) { JRStyle style = reportStyles[i]; styleList.add(style); //add dummy style requester so that report styles are always included //in the final list factory.registerDelayedStyleSetter(DUMMY_STYLE_SETTER, style.getName()); } } return styleList; } protected void collectTemplates() throws JRException { templates = new ArrayList<>(); if (reportTemplates != null) { for (JRFillReportTemplate reportTemplate : reportTemplates) { ReportTemplateSource template = reportTemplate.evaluate(); if (template != null) { templates.add(template); } } } Collection<JRTemplate> paramTemplates = (Collection<JRTemplate>) mainDataset .getParameterValue(JRParameter.REPORT_TEMPLATES, true); if (paramTemplates != null) { for (JRTemplate template : paramTemplates) { templates.add(ReportTemplateSource.of(template)); } } } public List<JRTemplate> getTemplates() { return templates.stream().map(source -> source.getTemplate()).collect(Collectors.toList()); } protected List<JRStyle> collectTemplateStyles() throws JRException { collectTemplates(); List<JRStyle> externalStyles = new ArrayList<JRStyle>(); HashSet<String> loadedLocations = new HashSet<String>(); for (ReportTemplateSource template : templates) { collectStyles(template, externalStyles, loadedLocations); } return externalStyles; } protected void collectStyles(ReportTemplateSource template, List<JRStyle> externalStyles, Set<String> loadedLocations) throws JRException { HashSet<String> parentLocations = new HashSet<String>(); collectStyles(template, externalStyles, loadedLocations, parentLocations); } protected void collectStyles(ReportTemplateSource templateSource, List<JRStyle> externalStyles, Set<String> loadedLocations, Set<String> templateParentLocations) throws JRException { String templateLocation = templateSource.getTemplateResourceInfo() == null ? null : templateSource.getTemplateResourceInfo().getRepositoryResourceLocation(); if (templateLocation != null && !templateParentLocations.add(templateLocation)) { throw new JRRuntimeException(EXCEPTION_MESSAGE_KEY_CIRCULAR_DEPENDENCY_FOUND, new Object[] { templateLocation }); } if (templateLocation != null && !loadedLocations.add(templateLocation)) { //already loaded return; } collectIncludedTemplates(templateSource, externalStyles, loadedLocations, templateParentLocations); JRStyle[] templateStyles = templateSource.getTemplate().getStyles(); if (templateStyles != null) { for (int i = 0; i < templateStyles.length; i++) { JRStyle style = templateStyles[i]; String styleName = style.getName(); if (styleName == null) { throw new JRRuntimeException(EXCEPTION_MESSAGE_KEY_EXTERNAL_STYLE_NAME_NOT_SET, (Object[]) null); } externalStyles.add(style); } } } protected void collectIncludedTemplates(ReportTemplateSource templateSource, List<JRStyle> externalStyles, Set<String> loadedLocations, Set<String> templateParentLocations) throws JRException { JRTemplateReference[] includedTemplates = templateSource.getTemplate().getIncludedTemplates(); if (includedTemplates != null && includedTemplates.length > 0) { RepositoryResourceContext currentContext = repositoryContext.getResourceContext(); String contextLocation = templateSource.getTemplateResourceInfo() == null ? null : templateSource.getTemplateResourceInfo().getRepositoryContextLocation(); RepositoryResourceContext templateResourceContext = SimpleRepositoryResourceContext.of(contextLocation, currentContext == null ? null : currentContext.getDerivedContextFallback()); RepositoryContext templateRepositoryContext = SimpleRepositoryContext .of(repositoryContext.getJasperReportsContext(), templateResourceContext); for (int i = 0; i < includedTemplates.length; i++) { JRTemplateReference reference = includedTemplates[i]; String location = reference.getLocation(); ReportTemplateSource includedTemplate = JRFillReportTemplate.loadTemplate(location, this, templateRepositoryContext); collectStyles(includedTemplate, externalStyles, loadedLocations, templateParentLocations); } } } protected void lookupExternalDefaultStyle(Collection<JRStyle> styleList) { JRStyle defStyle = null; for (Iterator<JRStyle> it = styleList.iterator(); it.hasNext();) { JRStyle style = it.next(); if (style.isDefault()) { defStyle = style; } } if (defStyle != null) { factory.registerDelayedStyleSetter(new JRStyleSetter() { @Override public void setStyle(JRStyle style) { if (style.isDefault()) { setDefaultStyle(style); } } @Override public void setStyleNameReference(String name) { } }, defStyle.getName()); } } private void createBoundElemementMaps() { createBoundElementMaps(JREvaluationTime.EVALUATION_TIME_MASTER); createBoundElementMaps(JREvaluationTime.EVALUATION_TIME_REPORT); createBoundElementMaps(JREvaluationTime.EVALUATION_TIME_PAGE); createBoundElementMaps(JREvaluationTime.EVALUATION_TIME_COLUMN); if (groups != null) { for (int i = 0; i < groups.length; i++) { createBoundElementMaps(JREvaluationTime.getGroupEvaluationTime(groups[i].getName())); } } for (Iterator<JRBand> i = bands.iterator(); i.hasNext();) { JRFillBand band = (JRFillBand) i.next(); createBoundElementMaps(JREvaluationTime.getBandEvaluationTime(band)); } } private void abortSubfillers() { if (subfillers != null && !subfillers.isEmpty()) { for (JRBaseFiller subfiller : subfillers.values()) { if (subfiller.bandReportParent != null) { if (log.isDebugEnabled()) { log.debug("Fill " + fillerId + ": Aborting subfiller " + subfiller.fillerId); } subfiller.bandReportParent.abortSubfiller(subfiller); } } } } /** * */ @continuable protected abstract void fillReport() throws JRException; @Override protected void ignorePaginationSet(Map<String, Object> parameterValues) { if (ignorePagination) { isTitleNewPage = false; isSummaryNewPage = false; if (groups != null) { for (int i = 0; i < groups.length; i++) { groups[i].setStartNewPage(false); groups[i].setResetPageNumber(false); groups[i].setStartNewColumn(false); } } if (isMasterReport() || !bandReportParent.isParentPagination())//subreport page height is already set by band master { int maxPageHeight = getMaxPageHeight(parameterValues); setPageHeight(maxPageHeight); } } maxPageWidth = getMaxPageWidth(parameterValues); } protected int getMaxPageHeight(Map<String, Object> parameterValues) { Integer maxPageHeightParam = (Integer) parameterValues.get(JRParameter.MAX_PAGE_HEIGHT); int maxPageHeight = maxPageHeightParam != null ? maxPageHeightParam : PAGE_HEIGHT_PAGINATION_IGNORED; if (maxPageHeight < pageHeight) { if (log.isDebugEnabled()) { log.debug("max page height " + maxPageHeight + " smaller than report page height " + pageHeight); } //use the report page height maxPageHeight = pageHeight; } if (log.isDebugEnabled()) { log.debug("max page height is " + maxPageHeight); } return maxPageHeight; } protected int getMaxPageWidth(Map<String, Object> parameterValues) { Integer maxPageWidthParam = (Integer) parameterValues.get(JRParameter.MAX_PAGE_WIDTH); int maxPageWidth = maxPageWidthParam != null ? maxPageWidthParam : PAGE_WIDTH_IGNORED; if (maxPageWidth < pageWidth) { if (log.isDebugEnabled()) { log.debug("max page width " + maxPageWidth + " smaller than report page width " + pageWidth); } //use the report page width maxPageWidth = pageWidth; } if (log.isDebugEnabled()) { log.debug("max page width is " + maxPageWidth); } return maxPageWidth; } protected void recordUsedPageHeight(int pageHeight) { if (pageHeight > usedPageHeight) { usedPageHeight = pageHeight; } } /** * Returns the report resource bundle. * * @return the report resource bundle */ protected ResourceBundle getResourceBundle() { return mainDataset.resourceBundle; } /** * */ protected WhenNoDataTypeEnum getWhenNoDataType() { WhenNoDataTypeEnum result = whenNoDataType; if (result == null) { result = WhenNoDataTypeEnum .getByName(propertiesUtil.getProperty(mainDataset, JRReport.CONFIG_PROPERTY_WHEN_NO_DATA_TYPE)); } return result; } /** * */ public Format getDateFormat(String pattern) { return getDateFormat(pattern, null); } protected Format getDateFormat(String pattern, TimeZone timeZone) { Locale lc = getLocale(); TimeZone tz = timeZone == null ? getTimeZone() : timeZone;// default to filler timezone String key = pattern + "|" + JRDataUtils.getLocaleCode(lc) + "|" + JRDataUtils.getTimeZoneId(tz); Format format = dateFormatCache.get(key); if (format == null) { format = getFormatFactory().createDateFormat(pattern, lc, tz); if (format != null) { dateFormatCache.put(key, format); } } return format; } /** * */ public Format getNumberFormat(String pattern) { Locale lc = getLocale(); String key = pattern + "|" + JRDataUtils.getLocaleCode(lc); Format format = numberFormatCache.get(key); if (format == null) { format = getFormatFactory().createNumberFormat(pattern, lc); if (format != null) { numberFormatCache.put(key, format); } } return format; } protected boolean hasMasterFormatFactory() { return !isSubreport() || getFormatFactory().getClass().getName() .equals(fillContext.getMasterFormatFactory().getClass().getName()); } protected boolean hasMasterLocale() { return !isSubreport() || getLocale().equals(fillContext.getMasterLocale()); } protected boolean hasMasterTimeZone() { return !isSubreport() || getTimeZone().equals(fillContext.getMasterTimeZone()); } /** * Sets a parameter's value. * * @param parameterName the parameter name * @param value the value * @throws JRException */ protected void setParameter(String parameterName, Object value) throws JRException { mainDataset.setParameter(parameterName, value); } /** * Sets a parameter's value. * * @param parameter the parameter * @param value the value * @throws JRException */ protected void setParameter(JRFillParameter parameter, Object value) throws JRException { mainDataset.setParameter(parameter, value); } /** * */ protected boolean next() throws JRException { isCrtRecordOnPage = false; isCrtRecordOnColumn = false; return mainDataset.next(); } /** * Resolves elements which are to be evaluated at report level. */ protected void resolveReportBoundElements() throws JRException { resolveBoundElements(JREvaluationTime.EVALUATION_TIME_REPORT, JRExpression.EVALUATION_DEFAULT); } /** * Resolves elements which are to be evaluated at page level. * * @param evaluation * the evaluation type */ protected void resolvePageBoundElements(byte evaluation) throws JRException { resolveBoundElements(JREvaluationTime.EVALUATION_TIME_PAGE, evaluation); } /** * Resolves elements which are to be evaluated at column level. * * @param evaluation * the evaluation type */ protected void resolveColumnBoundElements(byte evaluation) throws JRException { resolveBoundElements(JREvaluationTime.EVALUATION_TIME_COLUMN, evaluation); } /** * Resolves elements which are to be evaluated at group level. * * @param evaluation * the evaluation type * @param isFinal */ protected void resolveGroupBoundElements(byte evaluation, boolean isFinal) throws JRException { if (groups != null && groups.length > 0) { for (int i = 0; i < groups.length; i++) { JRFillGroup group = groups[i]; if ((group.hasChanged() && group.isFooterPrinted()) || isFinal) { String groupName = group.getName(); resolveBoundElements(JREvaluationTime.getGroupEvaluationTime(groupName), evaluation); } } } } protected JRPrintPage newPage() { JRPrintPage page; if (fillContext.isUsingVirtualizer()) { JRVirtualPrintPage virtualPage = new JRVirtualPrintPage(virtualizationContext); page = virtualPage; } else { page = new JRBasePrintPage(); } return page; } /** * Resloves elements which are to be evaluated at band level. * * @param band * the band * @param evaluation * the evaluation type * @throws JRException */ protected void resolveBandBoundElements(JRFillBand band, byte evaluation) throws JRException { resolveBoundElements(JREvaluationTime.getBandEvaluationTime(band), evaluation); } protected void registerSubfiller(JRBaseFiller subfiller) { if (subfillers == null) { subfillers = new ConcurrentHashMap<Integer, JRBaseFiller>(16, 0.75f, 1); } subfillers.put(subfiller.fillerId, subfiller); } protected void unregisterSubfiller(JRBaseFiller subfiller) { if (subfillers != null) { subfillers.remove(subfiller.fillerId); } } /** * */ protected void fillBand(JRPrintBand band) { if (isReorderBandElements()) { List<JRPrintElement> elements = new ArrayList<JRPrintElement>(); for (Iterator<JRPrintElement> it = band.iterateElements(); it.hasNext();) { JRPrintElement element = it.next(); element.setX(element.getX() + offsetX); element.setY(element.getY() + offsetY); elements.add(element); } Collections.sort(elements, new JRYXComparator());//FIXME make singleton comparator; same for older comparator for (JRPrintElement element : elements) { printPage.addElement(element); recordUsedWidth(element); } } else { for (Iterator<JRPrintElement> it = band.iterateElements(); it.hasNext();) { JRPrintElement element = it.next(); element.setX(element.getX() + offsetX); element.setY(element.getY() + offsetY); printPage.addElement(element); recordUsedWidth(element); } } } protected void recordUsedWidth(JRPrintElement element) { recordUsedPageWidth(element.getX() + element.getWidth() + rightMargin); } protected void addPage(JRPrintPage page) { if (!isSubreport()) { if (log.isDebugEnabled()) { log.debug("Fill " + fillerId + ": adding page " + (jasperPrint.getPages().size() + 1)); } // notify that the previous page was generated int pageCount = jasperPrint.getPages().size(); if (pageCount > 0 && fillListener != null) { fillListener.pageGenerated(jasperPrint, pageCount - 1); } addLastPageBookmarks(); jasperPrint.addPage(page); fillContext.setPrintPage(page); } } @continuable protected void addPageToParent(final boolean ended) throws JRException { if (printPage == null) { return; } FillerPageAddedEvent pageAdded = new FillerPageAddedEvent() { @Override public JasperPrint getJasperPrint() { return jasperPrint; } @Override public JRPrintPage getPage() { return printPage; } @Override public boolean hasReportEnded() { return ended; } @Override public int getPageStretchHeight() { return offsetY + bottomMargin; } @Override public int getPageIndex() { Number pageNumber = (Number) calculator.getPageNumber().getValue(); if (pageNumber == null)//this happens when whenNoDataType="BlankPage" //FIXMEBOOK maybe we should set the variable? { return 0; } return pageNumber.intValue() - 1; } @Override public JRBaseFiller getFiller() { return JRBaseFiller.this; } @Override public DelayedFillActions getDelayedActions() { return delayedActions; } }; //FIXMEBOOK use a fill listener instead of this? bandReportParent.addPage(pageAdded); } protected void setMasterPageVariables(int currentPageIndex, int totalPages) { JRFillVariable masterCurrentPage = getVariable(JRVariable.MASTER_CURRENT_PAGE); if (masterCurrentPage != null) { masterCurrentPage.setValue(currentPageIndex + 1); } JRFillVariable masterTotalPages = getVariable(JRVariable.MASTER_TOTAL_PAGES); if (masterTotalPages != null) { masterTotalPages.setValue(totalPages); } } protected WhenResourceMissingTypeEnum getWhenResourceMissingType() { return mainDataset.whenResourceMissingType; } protected boolean isBandOverFlowAllowed() { return bandOverFlowAllowed; } protected void setBandOverFlowAllowed(boolean splittableBand) { this.bandOverFlowAllowed = splittableBand; } protected boolean isReorderBandElements() { return isReorderBandElements; } protected void setReorderBandElements(boolean isReorderBandElements) { this.isReorderBandElements = isReorderBandElements; } protected int getMasterColumnCount() { FillerParent fillerParent = parent; int colCount = 1; while (fillerParent != null) { BaseReportFiller filler = fillerParent.getFiller(); if (filler instanceof JRBaseFiller)//FIXMEBOOK { colCount *= ((JRBaseFiller) filler).columnCount; } fillerParent = filler.parent; } return colCount; } /** * Returns the top-level (master) filler object. * * @return the master filler object */ public BaseReportFiller getMasterFiller() { BaseReportFiller filler = this; while (filler.parent != null) { filler = filler.parent.getFiller(); } return filler; } protected void addBoundElement(JRFillElement element, JRPrintElement printElement, EvaluationTimeEnum evaluationType, String groupName, JRFillBand band) { JRFillGroup group = groupName == null ? null : getGroup(groupName); addBoundElement(element, printElement, evaluationType, group, band); } protected void addBoundElement(JRFillElement element, JRPrintElement printElement, EvaluationTimeEnum evaluationType, JRGroup group, JRFillBand band) { JREvaluationTime evaluationTime = JREvaluationTime.getEvaluationTime(evaluationType, group, band); addBoundElement(element, printElement, evaluationTime); } protected void addBoundElement(JRFillElement element, JRPrintElement printElement, JREvaluationTime evaluationTime) { // the key contains the page and its index; the index is only stored so that we have it in resolveBoundElements int pageIndex = currentPageIndex(); FillPageKey pageKey = new FillPageKey(printPage, pageIndex); addBoundElement(element, printElement, evaluationTime, pageKey); } protected int currentPageIndex() { int pageIndex = ((Number) calculator.getPageNumber().getValue()).intValue() - 1; return pageIndex; } protected void subreportPageFilled(JRPrintPage subreportPage) { FillPageKey subreportKey = new FillPageKey(subreportPage); // this method is only called when the parent is a band report JRBaseFiller parentFiller = (JRBaseFiller) parent.getFiller(); //FIXMEBOOK the index is only correct when the parent is the master, see fillListener.pageUpdated int parentPageIndex = parentFiller.getJasperPrint().getPages().size() - 1; FillPageKey parentKey = new FillPageKey(parentFiller.printPage, parentPageIndex); // move all delayed elements from the subreport page to the master page moveBoundActions(subreportKey, parentKey); // move all master evaluations to the parent parent.getFiller().delayedActions.moveMasterEvaluations(delayedActions, parentKey); } protected void moveBoundActions(FillPageKey subreportKey, FillPageKey parentKey) { delayedActions.moveActions(subreportKey, parentKey); if (subfillers != null)//recursive { for (JRBaseFiller subfiller : subfillers.values()) { subfiller.moveBoundActions(subreportKey, parentKey); } } } @Override public boolean isPageFinal(int pageIdx) { JRPrintPage page = jasperPrint.getPages().get(pageIdx); return !hasBoundActions(page); } public boolean isPageFinal(JRPrintPage page) { return !hasBoundActions(page); } protected boolean hasBoundActions(JRPrintPage page) { boolean hasActions = delayedActions.hasDelayedActions(page); if (hasActions) { return true; } if (subfillers != null) { for (JRBaseFiller subfiller : subfillers.values()) { // recursive if (subfiller.hasBoundActions(page)) { return true; } } } return false; } protected JRFillGroup getGroup(String groupName) { JRFillGroup group = null; if (groups != null) { for (int i = 0; i < groups.length; i++) { if (groups[i].getName().equals(groupName)) { group = groups[i]; break; } } } if (group == null) { throw new JRRuntimeException(EXCEPTION_MESSAGE_KEY_NO_SUCH_GROUP, new Object[] { groupName }); } return group; } /** * */ protected JRFillGroup getKeepTogetherGroup() { Integer keepTogetherGroupLevel = null; if (groups != null) { // check to see if there is any group that needs to be kept together or does not have the required min details for (int i = 0; i < groups.length; i++) { JRFillGroup group = groups[i]; if (group.getKeepTogetherElementRange() != null && (group.isKeepTogether() || !group.hasMinDetails())) { keepTogetherGroupLevel = i; break; } } } if (keepTogetherGroupLevel != null || orphanGroupFooterDetailElementRange != null) { // if there was a group that was going to be moved, either because it had keepTogether or less than required min details, // or if there is an orphan to be moved, we need to check if the outer groups still meet their required min details or need // to be moved themselves, possibly instead of the inner group int detailsToMove = Math.max( keepTogetherGroupLevel == null ? 0 : groups[keepTogetherGroupLevel].getDetailsCount(), orphanGroupFooterDetailElementRange == null ? 0 : 1); int lcMaxGrpIdx = keepTogetherGroupLevel == null ? groups.length : keepTogetherGroupLevel; for (int i = 0; i < lcMaxGrpIdx; i++) { JRFillGroup group = groups[i]; if (group.getKeepTogetherElementRange() != null && !group.hasMinDetails(detailsToMove)) { keepTogetherGroupLevel = i; break; } } } return keepTogetherGroupLevel == null ? null : groups[keepTogetherGroupLevel]; } // protected JRStyle getConsolidatedStyle(String consolidatedStyleName) // { // return (JRStyle) consolidatedStyles.get(consolidatedStyleName); // } // // // protected void putConsolidatedStyle(JRStyle consolidatedStyle) // { // consolidatedStyles.put(consolidatedStyle.getName(), consolidatedStyle); // } protected void createReportTemplates(JRFillObjectFactory factory) { JRReportTemplate[] templates = jasperReport.getTemplates(); if (templates != null) { reportTemplates = new JRFillReportTemplate[templates.length]; for (int i = 0; i < templates.length; i++) { JRReportTemplate template = templates[i]; reportTemplates[i] = factory.getReportTemplate(template); } } } protected int getFillerId() { return fillerId; } protected PrintElementOriginator assignElementId(JRFillElement fillElement) { int id = getFillContext().generateFillElementId(); DefaultPrintElementOriginator originator = new DefaultPrintElementOriginator(id); return originator; } }