package au.com.vaadinutils.jasper;
import java.io.File;
import java.util.HashSet;
import java.util.Set;
import java.util.StringTokenizer;
import net.sf.jasperreports.crosstabs.JRCrosstab;
import net.sf.jasperreports.engine.JRBreak;
import net.sf.jasperreports.engine.JRChart;
import net.sf.jasperreports.engine.JRComponentElement;
import net.sf.jasperreports.engine.JRElementGroup;
import net.sf.jasperreports.engine.JREllipse;
import net.sf.jasperreports.engine.JRFrame;
import net.sf.jasperreports.engine.JRGenericElement;
import net.sf.jasperreports.engine.JRImage;
import net.sf.jasperreports.engine.JRLine;
import net.sf.jasperreports.engine.JRRectangle;
import net.sf.jasperreports.engine.JRStaticText;
import net.sf.jasperreports.engine.JRSubreport;
import net.sf.jasperreports.engine.JRTextField;
import net.sf.jasperreports.engine.JRVisitor;
import net.sf.jasperreports.engine.JasperCompileManager;
import net.sf.jasperreports.engine.JasperReport;
import net.sf.jasperreports.engine.design.JasperDesign;
import net.sf.jasperreports.engine.util.JRElementsVisitor;
import net.sf.jasperreports.engine.util.JRLoader;
import net.sf.jasperreports.engine.util.JRSaver;
import net.sf.jasperreports.engine.xml.JRXmlLoader;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
public class JasperReportCompiler
{
Logger logger = LogManager.getLogger();
protected Throwable subReportException;
public JasperReport compileReportIfNeeded(JasperDesign jasperDesign, final File sourcePath, final File outputPath,
String reportName) throws Throwable
{
JasperReport report;
if (checkIfReportNeedsCompile(sourcePath, outputPath, reportName))
{
report = compileReport(jasperDesign, sourcePath, outputPath, reportName);
}
else
{
File outputReport = new File(outputPath.getAbsolutePath() + "/" + reportName + ".jasper");
logger.warn("Report " + outputReport.getName() + " is up to date");
report = (JasperReport) JRLoader.loadObject(outputReport);
}
return report;
}
public JasperDesign getDesignFile(final File sourcePath, String reportName) throws Throwable
{
String name = reportName;
if (!name.contains(".jrxml"))
{
name = name+".jrxml";
}
File sourceReport = new File(sourcePath.getAbsoluteFile() + "/" + name);
return JRXmlLoader.load(sourceReport);
}
public JasperReport compileReport( final File sourcePath, final File outputPath,
String reportName) throws Throwable
{
String name = reportName;
if (!name.contains(".jasper"))
{
name = name+".jasper";
}
JasperReport jasperReport = null;
JasperDesign jasperDesign = getDesignFile(sourcePath, reportName);
File outputReport = new File(outputPath.getAbsolutePath() + "/" + name);
jasperReport = JasperCompileManager.compileReport(jasperDesign);
JRSaver.saveObject(jasperReport, outputReport);
logger.warn("Saving compiled report : " + outputReport.getName());
// Compile sub reports
JRElementsVisitor.visitReport(jasperReport, createVisitor(sourcePath, outputPath));
if (subReportException != null)
throw new RuntimeException(subReportException);
return jasperReport;
}
public JasperReport compileReport(JasperDesign jasperDesign, final File sourcePath, final File outputPath,
String reportName) throws Throwable
{
JasperReport jasperReport = null;
File outputReport = new File(outputPath.getAbsolutePath() + "/" + reportName + ".jasper");
jasperReport = JasperCompileManager.compileReport(jasperDesign);
JRSaver.saveObject(jasperReport, outputReport);
logger.warn("Saving compiled report : " + outputReport.getAbsolutePath());
// Compile sub reports
JRElementsVisitor.visitReport(jasperReport, createVisitor(sourcePath, outputPath));
if (subReportException != null)
throw new RuntimeException(subReportException);
return jasperReport;
}
public boolean checkIfReportNeedsCompile(final File sourcePath, final File outputPath, String reportName)
{
File sourceReport = new File(sourcePath.getAbsoluteFile() + "/" + reportName + ".jrxml");
File outputReport = new File(outputPath.getAbsolutePath() + "/" + reportName + ".jasper");
return !outputReport.exists() || sourceReport.lastModified() > outputReport.lastModified();
}
private JRVisitor createVisitor(final File sourcePath, final File outputPath)
{
return new JRVisitor()
{
private Set<String> completedSubReports = new HashSet<String>();
@Override
public void visitBreak(JRBreak breakElement)
{
}
@Override
public void visitChart(JRChart chart)
{
}
@Override
public void visitCrosstab(JRCrosstab crosstab)
{
}
@Override
public void visitElementGroup(JRElementGroup elementGroup)
{
}
@Override
public void visitEllipse(JREllipse ellipse)
{
}
@Override
public void visitFrame(JRFrame frame)
{
}
@Override
public void visitImage(JRImage image)
{
}
@Override
public void visitLine(JRLine line)
{
}
@Override
public void visitRectangle(JRRectangle rectangle)
{
}
@Override
public void visitStaticText(JRStaticText staticText)
{
}
@Override
public void visitSubreport(JRSubreport subreport)
{
try
{
String expression = subreport.getExpression().getText().replace(".jasper", "");
StringTokenizer st = new StringTokenizer(expression, "\"/");
String subReportName = null;
while (st.hasMoreTokens())
subReportName = st.nextToken();
// Sometimes the same subreport can be used multiple times,
// but
// there is no need to compile multiple times
if (completedSubReports.contains(subReportName))
return;
completedSubReports.add(subReportName);
compileReport( sourcePath, outputPath, subReportName);
}
catch (Throwable e)
{
subReportException = e;
}
}
@Override
public void visitTextField(JRTextField textField)
{
}
@Override
public void visitComponentElement(JRComponentElement componentElement)
{
}
@Override
public void visitGenericElement(JRGenericElement element)
{
}
};
}
}