net.sf.jasperreports.engine.xml.JRXmlLoader 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 - 2023 Cloud Software Group, 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:
* Artur Biesiadowski - [email protected]
*/
package net.sf.jasperreports.engine.xml;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Iterator;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import java.util.Set;
import javax.xml.parsers.ParserConfigurationException;
import org.apache.commons.digester.Digester;
import org.xml.sax.InputSource;
import org.xml.sax.SAXException;
import net.sf.jasperreports.engine.DefaultJasperReportsContext;
import net.sf.jasperreports.engine.JRDataset;
import net.sf.jasperreports.engine.JRDatasetRun;
import net.sf.jasperreports.engine.JRElementDataset;
import net.sf.jasperreports.engine.JRException;
import net.sf.jasperreports.engine.JRGroup;
import net.sf.jasperreports.engine.JRRuntimeException;
import net.sf.jasperreports.engine.JRVariable;
import net.sf.jasperreports.engine.JasperReportsContext;
import net.sf.jasperreports.engine.design.JRDesignChart;
import net.sf.jasperreports.engine.design.JRDesignDataset;
import net.sf.jasperreports.engine.design.JRDesignElement;
import net.sf.jasperreports.engine.design.JRDesignElementDataset;
import net.sf.jasperreports.engine.design.JRDesignImage;
import net.sf.jasperreports.engine.design.JRDesignTextField;
import net.sf.jasperreports.engine.design.JRDesignVariable;
import net.sf.jasperreports.engine.design.JRValidationException;
import net.sf.jasperreports.engine.design.JasperDesign;
import net.sf.jasperreports.engine.type.DatasetResetTypeEnum;
import net.sf.jasperreports.engine.type.IncrementTypeEnum;
import net.sf.jasperreports.engine.type.ResetTypeEnum;
/**
* Utility class that helps parsing a JRXML file into a
* {@link net.sf.jasperreports.engine.design.JasperDesign} object.
*
* This can be done using one of the load(...)
or loadXml
* methods published by this class. Applications might need to do this in cases where report
* templates kept in their source form (JRXML) must be modified at runtime based on
* some user input and then compiled on the fly for filling with data.
*
* @author Teodor Danciu ([email protected])
*/
public class JRXmlLoader
{
public static final String EXCEPTION_MESSAGE_KEY_UNKNOWN_SUBDATASET = "xml.loader.unknown.subdataset";
public static final String EXCEPTION_MESSAGE_KEY_SUBDATASET_NOT_FOUND = "xml.loader.subdataset.not.found";
/**
*
*/
private final JasperReportsContext jasperReportsContext;
private JasperDesign jasperDesign;
private LinkedList contextStack = new LinkedList<>();
private Map groupReferences = new HashMap<>();
//TODO use XmlGroupReference for datasets
private Set groupBoundDatasets = new HashSet<>();
private List errors = new ArrayList<>();
private Digester digester;
private boolean ignoreConsistencyProblems;
/**
*
*/
public JRXmlLoader(JasperReportsContext jasperReportsContext, Digester digester)
{
this.jasperReportsContext = jasperReportsContext;
this.digester = digester;
}
/**
*
*/
public JasperReportsContext getJasperReportsContext()
{
return jasperReportsContext;
}
/**
*
*/
public void setJasperDesign(JasperDesign jasperDesign)
{
this.jasperDesign = jasperDesign;
}
public void addGroupReference(XmlGroupReference reference)
{
XmlLoaderReportContext reportContext = getReportContext();
groupReferences.put(reference, reportContext);
}
/**
* @deprecated To be removed.
*/
public void addGroupReprintedElement(JRDesignElement element)
{
addGroupReference(
new ElementReprintGroupReference(element));
}
/**
* @deprecated To be removed.
*/
public void addGroupEvaluatedImage(JRDesignImage image)
{
addGroupReference(
new ImageEvaluationGroupReference(image));
}
/**
* @deprecated To be removed.
*/
public void addGroupEvaluatedTextField(JRDesignTextField textField)
{
addGroupReference(
new TextFieldEvaluationGroupReference(textField));
}
/**
* @deprecated To be removed.
*/
public void addGroupEvaluatedChart(JRDesignChart chart)
{
addGroupReference(
new ChartEvaluationGroupReference(chart));
}
/**
*
*/
public Set getGroupBoundDatasets()
{
return groupBoundDatasets;
}
/**
* @see #load(JasperReportsContext, String)
*/
public static JasperDesign load(String sourceFileName) throws JRException//FIXMEREPO consider renaming
{
return load(DefaultJasperReportsContext.getInstance(), sourceFileName);
}
/**
*
*/
public static JasperDesign load(JasperReportsContext jasperReportsContext, String sourceFileName) throws JRException//FIXMEREPO consider renaming
{
return load(jasperReportsContext, new File(sourceFileName));
}
/**
* @see #load(JasperReportsContext, File)
*/
public static JasperDesign load(File file) throws JRException
{
return load(DefaultJasperReportsContext.getInstance(), file);
}
/**
*
*/
public static JasperDesign load(JasperReportsContext jasperReportsContext, File file) throws JRException
{
JasperDesign jasperDesign = null;
try (FileInputStream fis = new FileInputStream(file))
{
jasperDesign = JRXmlLoader.load(jasperReportsContext, fis);
}
catch (IOException e)
{
throw new JRException(e);
}
return jasperDesign;
}
/**
* @see #load(JasperReportsContext, InputStream)
*/
public static JasperDesign load(InputStream is) throws JRException
{
return load(DefaultJasperReportsContext.getInstance(), is);
}
/**
*
*/
public static JasperDesign load(JasperReportsContext jasperReportsContext, InputStream is) throws JRException
{
JasperDesign jasperDesign = null;
JRXmlLoader xmlLoader = null;
try
{
xmlLoader = new JRXmlLoader(jasperReportsContext, JRXmlDigesterFactory.createDigester(jasperReportsContext));
}
catch (ParserConfigurationException | SAXException e)
{
throw new JRException(e);
}
jasperDesign = xmlLoader.loadXML(is);
return jasperDesign;
}
/**
*
*/
public JasperDesign loadXML(InputStream is) throws JRException
{
return loadXML(new InputSource(is));
}
/**
*
*/
public JasperDesign loadXML(InputSource is) throws JRException
{
try
{
digester.push(this);
/* */
digester.parse(is);
}
catch (SAXException | IOException e)
{
throw new JRException(e);
}
finally
{
digester.clear();
}
if (errors.size() > 0)
{
Exception e = errors.get(0);
if (e instanceof JRException)
{
throw (JRException)e;
}
throw new JRException(e);
}
/* */
assignGroupsToVariables(jasperDesign.getMainDesignDataset());
for (Iterator it = jasperDesign.getDatasetsList().iterator(); it.hasNext();)
{
JRDesignDataset dataset = (JRDesignDataset) it.next();
assignGroupsToVariables(dataset);
}
assignGroupReferences();
this.assignGroupsToDatasets();
return jasperDesign;
}
/**
*
*/
private void assignGroupsToVariables(JRDesignDataset dataset) throws JRException
{
JRVariable[] variables = dataset.getVariables();
if (variables != null && variables.length > 0)
{
Map groupsMap = dataset.getGroupsMap();
for(int i = 0; i < variables.length; i++)
{
JRDesignVariable variable = (JRDesignVariable)variables[i];
if (variable.getResetTypeValue() == ResetTypeEnum.GROUP)
{
String groupName = null;
JRGroup group = variable.getResetGroup();
if (group != null)
{
groupName = group.getName();
group = groupsMap.get(groupName);
}
if (!ignoreConsistencyProblems && group == null)
{
throw
new JRValidationException(
"Unknown reset group '" + groupName
+ "' for variable : " + variable.getName(),
variable
);
}
variable.setResetGroup(group);
}
else
{
variable.setResetGroup(null);
}
if (variable.getIncrementTypeValue() == IncrementTypeEnum.GROUP)
{
String groupName = null;
JRGroup group = variable.getIncrementGroup();
if (group != null)
{
groupName = group.getName();
group = groupsMap.get(groupName);
}
if (!ignoreConsistencyProblems && group == null)
{
throw
new JRValidationException(
"Unknown increment group '" + groupName
+ "' for variable : " + variable.getName(),
variable
);
}
variable.setIncrementGroup(group);
}
else
{
variable.setIncrementGroup(null);
}
}
}
}
/**
*
*/
private void assignGroupReferences() throws JRException
{
for (Map.Entry entry :
groupReferences.entrySet())
{
XmlGroupReference reference = entry.getKey();
XmlLoaderReportContext context = entry.getValue();
String groupName = null;
JRGroup group = reference.getGroupReference();
if (group != null)
{
groupName = group.getName();
group = resolveGroup(groupName, context);
}
if (!ignoreConsistencyProblems && group == null)
{
reference.groupNotFound(groupName);
}
else
{
reference.assignGroup(group);
}
}
}
protected JRGroup resolveGroup(String groupName, XmlLoaderReportContext context)
{
JRGroup group;
if (context == null)
{
// main dataset groups
Map groupsMap = jasperDesign.getGroupsMap();
group = groupsMap.get(groupName);
}
else
{
String datasetName = context.getSubdatesetName();
JRDesignDataset dataset = (JRDesignDataset) jasperDesign.getDatasetMap().get(datasetName);
if (dataset == null)
{
throw
new JRRuntimeException(
EXCEPTION_MESSAGE_KEY_SUBDATASET_NOT_FOUND,
new Object[]{datasetName});
}
group = dataset.getGroupsMap().get(groupName);
}
return group;
}
/**
*
*/
private void assignGroupsToDatasets() throws JRException
{
for(Iterator it = groupBoundDatasets.iterator(); it.hasNext();)
{
JRDesignElementDataset dataset = (JRDesignElementDataset) it.next();
JRDatasetRun datasetRun = dataset.getDatasetRun();
Map groupsMap;
if (datasetRun == null)
{
groupsMap = jasperDesign.getGroupsMap();
}
else
{
Map datasetMap = jasperDesign.getDatasetMap();
String datasetName = datasetRun.getDatasetName();
JRDesignDataset subDataset = (JRDesignDataset) datasetMap.get(datasetName);
if (subDataset == null)
{
throw
new JRException(
EXCEPTION_MESSAGE_KEY_UNKNOWN_SUBDATASET,
new Object[]{datasetName});
}
groupsMap = subDataset.getGroupsMap();
}
if (dataset.getIncrementTypeValue() == IncrementTypeEnum.GROUP)
{
String groupName = null;
JRGroup group = dataset.getIncrementGroup();
if (group != null)
{
groupName = group.getName();
group = groupsMap.get(group.getName());
}
if (!ignoreConsistencyProblems && group == null)
{
throw new JRValidationException("Unknown increment group '" + groupName + "' for element dataset.", dataset);
}
dataset.setIncrementGroup(group);
}
else
{
dataset.setIncrementGroup(null);
}
if (dataset.getDatasetResetType() == DatasetResetTypeEnum.GROUP)
{
String groupName = null;
JRGroup group = dataset.getResetGroup();
if (group != null)
{
groupName = group.getName();
group = groupsMap.get(group.getName());
}
if (!ignoreConsistencyProblems && group == null)
{
throw new JRValidationException("Unknown reset group '" + groupName + "' for element dataset.", dataset);
}
dataset.setResetGroup(group);
}
else
{
dataset.setResetGroup(null);
}
}
}
/**
*
*/
public void addError(Exception e)
{
if(!ignoreConsistencyProblems)
{
this.errors.add(e);
}
}
/**
* Returns true if the loader is set to ignore consistency problems
* @return the ignoreConsistencyProblems flag.
*/
public boolean isIgnoreConsistencyProblems() {
return ignoreConsistencyProblems;
}
/**
* Allows to enable or disable the reporting of consistency problems. Consistency
* problems are problems in the logical structure of the report such as references
* to missing groups and fonts.
*
* @param ignoreConsistencyProblems The ignoreConsistencyProblems value to set.
*/
public void setIgnoreConsistencyProblems(boolean ignoreConsistencyProblems) {
this.ignoreConsistencyProblems = ignoreConsistencyProblems;
}
public void pushReportContext(XmlLoaderReportContext context)
{
contextStack.addFirst(context);
}
public XmlLoaderReportContext popReportContext()
{
return contextStack.removeFirst();
}
public XmlLoaderReportContext getReportContext()
{
return contextStack.isEmpty() ? null : contextStack.getFirst();
}
}