Running Jasper Reports from Java

As a follow-up to my previous post about using iReport, I wanted to write some code that would run the report.  My goal is something that I can launch from PeopleTools.

Below is some Java that will execute the report and build a PDF output.  This class takes the XML data file and the report designed by iReport and produces a PDF out of it.

package net.digitaleagle.psst0101;

import java.io.File;
import java.util.HashMap;
import java.util.Locale;

import net.sf.jasperreports.engine.JRException;
import net.sf.jasperreports.engine.JRParameter;
import net.sf.jasperreports.engine.JasperCompileManager;
import net.sf.jasperreports.engine.JasperExportManager;
import net.sf.jasperreports.engine.JasperFillManager;
import net.sf.jasperreports.engine.JasperPrint;
import net.sf.jasperreports.engine.JasperReport;
import net.sf.jasperreports.engine.query.JRXPathQueryExecuterFactory;
import net.sf.jasperreports.engine.util.FileResolver;
import net.sf.jasperreports.engine.util.JRXmlUtils;

import org.w3c.dom.Document;

public class JasperInterface {
	private String dataPath;
	private String basePath;
	private String reportName;
	private String reportOutput;

	public JasperInterface(String dataPath, String basePath, String reportName, String reportOutput) {
		this.dataPath = dataPath;
		this.basePath = basePath;
		this.reportName = reportName;
		this.reportOutput = reportOutput;
	}

	public void run() throws JRException {
		Document data = JRXmlUtils.parse(dataPath);

		HashMap parms = new HashMap();
		parms.put(JRXPathQueryExecuterFactory.PARAMETER_XML_DATA_DOCUMENT, data);
		parms.put(JRXPathQueryExecuterFactory.XML_DATE_PATTERN, "yyyy-MM-dd");
		parms.put(JRXPathQueryExecuterFactory.XML_LOCALE, Locale.ENGLISH);
		parms.put(JRParameter.REPORT_LOCALE, Locale.US);

		FileResolver fileResolver = new FileResolver() {
			 @Override
			 public File resolveFile(String fileName) {
			  return new File(basePath, fileName);
			 }
			};
		parms.put(JRParameter.REPORT_FILE_RESOLVER, fileResolver);

		JasperReport jr = JasperCompileManager.compileReport(basePath + reportName);
		JasperPrint pr = JasperFillManager.fillReport(jr, parms);
		JasperExportManager.exportReportToPdfFile(pr, reportOutput);
	}
}

Here’s some code that can launch the report without needing the JasperReports classes in the classpath.  I originally thought about just putting the jar files into the class directory in the PeopleSoft Home, but Jasper Reports has a number of Jar files.  So, I created a class that had no dependencies on JasperReports.  I tell it the location of the JasperReports installation, and it builds the necessary class path.

package net.digitaleagle.psst0101;

import java.io.File;
import java.lang.reflect.Constructor;
import java.lang.reflect.Method;
import java.net.MalformedURLException;
import java.net.URL;
import java.net.URLClassLoader;
import java.util.ArrayList;

public class JasperReportRunner {
	private String jasperPath;
	private String dataPath;
	private String basePath;
	private String reportName;
	private String reportOutput;

	/**
	 * @param args
	 */
	public static void main(String[] args) {
		String jasperPath = args[0];
		String dataPath = args[1];
		String basePath = args[2];
		String reportName = args[3];
		String reportOutput = args[4];

		JasperReportRunner jrr = new JasperReportRunner(jasperPath, dataPath, basePath, reportName, reportOutput);
		jrr.run();
	}

	public JasperReportRunner(String jasperPath, String dataPath, String basePath, String reportName, String reportOutput) {
		this.jasperPath = jasperPath;
		this.dataPath = dataPath;
		this.basePath = basePath;
		this.reportName = reportName;
		this.reportOutput = reportOutput;
	}

	public void run() {
		ArrayList urls = new ArrayList();
		File jasperDir = new File(jasperPath);
		addJars(urls, new File(jasperDir, "dist"));
		addJars(urls, new File(jasperDir, "lib"));
		URLClassLoader ucl = new URLClassLoader(urls.toArray(new URL[0]));
		Class jic;
		try {
			jic = ucl.loadClass(this.getClass().getPackage().getName() + ".JasperInterface");
		} catch (ClassNotFoundException e) {
			System.err.println("Could not access JasperInterface class");
			e.printStackTrace();
			return;
		}
		Constructor c = jic.getConstructors()[0];
		Object ji;
		try {
			ji = c.newInstance(dataPath, basePath, reportName, reportOutput);
		} catch (Exception e) {
			System.err.println("Error creating new instance of JasperInterface");
			e.printStackTrace();
			return;
		}
		Method method;
		try {
			method = jic.getMethod("run");
		} catch (Exception e) {
			System.err.println("Could not get run method");
			e.printStackTrace();
			return;
		}
		try {
			method.invoke(ji);
		} catch (Exception e) {
			System.err.println("Could not get execute run method");
			e.printStackTrace();
			return;
		}
	}

	private void addJars(ArrayList urls, File jarDir) {
		if(!jarDir.exists()) {
			System.err.println("Could not find Jasper Jar files in directory: " + jarDir.getAbsolutePath());
			System.err.println("Check installation directory");
			return;
		}
		for(File jarFile : jarDir.listFiles()) {
			if(jarFile.isFile() && jarFile.getName().toLowerCase().endsWith(".jar")) {
				try {
					urls.add(jarFile.toURI().toURL());
				} catch (MalformedURLException e) {
					System.err.println("Error loading jar for class path: " + jarFile.getAbsolutePath());
					e.printStackTrace();
				}
			}
		}
	}

}

Resources

One thought on “Running Jasper Reports from Java

Leave a Comment

Your email address will not be published. Required fields are marked *

This site uses Akismet to reduce spam. Learn how your comment data is processed.