net.sf.jasperreports.engine.fill.JRBaseFiller Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of jasperreports Show documentation
Show all versions of jasperreports Show documentation
Free Java Reporting Library
/*
* 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 .
*/
/*
* Contributors:
* John Bindel - [email protected]
*/
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 ([email protected])
*/
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;
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 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;
protected int printPageContentsWidth;
/**
* List of {@link JRFillBand JRFillBand} objects containing all bands of the
* report.
*/
protected List bands;
/**
* Collection of subfillers
*/
protected Map subfillers;
private boolean bandOverFlowAllowed;
/**
*
*/
protected Map dateFormatCache = new HashMap();
protected Map numberFormatCache = new HashMap();
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);
groups = mainDataset.groups;
createReportTemplates(factory);
String reportName = getBandReportParent() == null ? null : getBandReportParent().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();
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 getFieldsMap()
{
return mainDataset.fieldsMap;
}
/**
* Returns the report variables indexed by name.
*
* @return the report variables map
*/
protected Map 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(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 BandReportFillerParent getBandReportParent()
{
return (BandReportFillerParent)parent;
}
protected List 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 getBandReportParent() != null && getBandReportParent().isRunToBottom();
}
/**
*
*/
public JRPrintPage getCurrentPage()
{
return printPage;
}
protected int getCurrentPageContentsWidth()
{
return printPageContentsWidth;
}
/**
*
*/
protected abstract void setPageHeight(int pageHeight);
@Override
@continuable
public JasperPrint fill(Map parameterValues) throws JRException
{
if (parameterValues == null)
{
parameterValues = new HashMap();
}
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)
{
getBandReportParent().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)
{
getBandReportParent().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 defaultStyleListeners;
protected void addDefaultStyleListener(DefaultStyleListener listener)
{
defaultStyleListeners.add(listener);
}
protected void setDefaultStyle(JRStyle style)
{
defaultStyle = style;
for (Iterator it = defaultStyleListeners.iterator(); it.hasNext();)
{
DefaultStyleListener listener = it.next();
listener.defaultStyleSet(style);
}
}
protected void loadStyles() throws JRException
{
List styleList = collectStyles();
JRStyle reportDefaultStyle = jasperReport.getDefaultStyle();
if (reportDefaultStyle == null)
{
lookupExternalDefaultStyle(styleList);
}
List includedStyles = factory.setStyles(styleList);
if (getBandReportParent() != null)
{
getBandReportParent().registerReportStyles(includedStyles);
}
styles = includedStyles.toArray(new JRStyle[includedStyles.size()]);
if (reportDefaultStyle != null)
{
setDefaultStyle(factory.getStyle(reportDefaultStyle));
}
}
public void registerReportStyles(UUID id, List styles)
{
if (getBandReportParent() == null)
{
fillContext.registerReportStyles(jasperReport, id, styles);
}
else
{
String reportLocation = getBandReportParent().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 collectStyles() throws JRException
{
List 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 paramTemplates = (Collection) mainDataset.getParameterValue(
JRParameter.REPORT_TEMPLATES, true);
if (paramTemplates != null)
{
for (JRTemplate template : paramTemplates)
{
templates.add(ReportTemplateSource.of(template));
}
}
}
public List getTemplates()
{
return templates.stream().map(source -> source.getTemplate()).collect(Collectors.toList());
}
protected List collectTemplateStyles() throws JRException
{
collectTemplates();
List externalStyles = new ArrayList();
HashSet loadedLocations = new HashSet();
for (ReportTemplateSource template : templates)
{
collectStyles(template, externalStyles, loadedLocations);
}
return externalStyles;
}
protected void collectStyles(ReportTemplateSource template, List externalStyles, Set loadedLocations) throws JRException
{
HashSet parentLocations = new HashSet();
collectStyles(template, externalStyles, loadedLocations, parentLocations);
}
protected void collectStyles(ReportTemplateSource templateSource, List externalStyles,
Set loadedLocations, Set 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 externalStyles,
Set loadedLocations, Set 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 styleList)
{
JRStyle defStyle = null;
for (Iterator 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 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.getBandReportParent() != null)
{
if (log.isDebugEnabled())
{
log.debug("Fill " + fillerId + ": Aborting subfiller " + subfiller.fillerId);
}
subfiller.getBandReportParent().abortSubfiller(subfiller);
}
}
}
}
/**
*
*/
@continuable
protected abstract void fillReport() throws JRException;
@Override
protected void ignorePaginationSet(Map 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() || !getBandReportParent().isParentPagination())//subreport page height is already set by band master
{
int maxPageHeight = getMaxPageHeight(parameterValues);
setPageHeight(maxPageHeight);
}
}
maxPageWidth = getMaxPageWidth(parameterValues);
}
protected int getMaxPageHeight(Map 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 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(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 elements = new ArrayList();
for(Iterator 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 it = band.iterateElements(); it.hasNext();)
{
JRPrintElement element = it.next();
element.setX(element.getX() + offsetX);
element.setY(element.getY() + offsetY);
printPage.addElement(element);
recordUsedWidth(element);
}
}
int contentsWidth = band.getContentsWidth();
if (offsetX + contentsWidth + rightMargin > printPageContentsWidth)
{
printPageContentsWidth = offsetX + contentsWidth + rightMargin;
}
}
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));
}
addLastPageBookmarks();
// notify that the previous page was generated
int pageCount = jasperPrint.getPages().size();
if (pageCount > 0 && fillListener != null)
{
fillListener.pageGenerated(jasperPrint, pageCount - 1);
}
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?
getBandReportParent().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;
}
}