Skip to main content
Blog

Using the Pojo BIRT Runtime

By 31 mei 2013januari 30th, 2017No Comments

BIRT is an excellent reporting toolkit for Java. However, the documentation is sometimes hard to find or outdated.

If you want to add reporting capabilities to your existing Java application you have a new options since BIRT 3.7: using the Pojo BIRT Runtime integration. This article is about how you can execute the reports from within your web application with full control over the reporting engine. We will use BIRT 4.2.1 in this example.

As has always been possible, you can install the Eclipse BIRT Web Viewer next to your application. Integrating BIRT in this way is quick and easy: you create an iframe wrapping the Viewer. By specifying parameters in the url you can generate any report.
However, if you need access controls (e.g. specific users can only few specific reports with specific data), or you need to manage resource usage of BIRT, or want to run reports automatically at specific times it can become quite tricky to do.

In these cases you can use the Pojo BIRT Runtime. Basically, you can use BIRT as a jar file, accessing its Report Engine API via Java calls. In doing so, you need to implement all the viewer functionality yourself which is a big disadvantage.

So, how does it work? Assuming you have a maven project, you can add a dependency to your pom.xml:


	org.eclipse.birt.runtime
	org.eclipse.birt.runtime
	4.2.1a
	compile

Unfortunately, the packaging is quite horrible. Also note that the 4.2.1 release is broken, so use 4.2.1a. I guess due to the OSGi nature of Eclipse, all dependencies are renamed and packaged as well. If you run into conflicts, you might want to exclude some of the dependencies, for example xerces or batik:


	org.eclipse.birt.runtime
	org.eclipse.birt.runtime
	4.2.1a
	compile
	
		
			org.eclipse.birt.runtime.3_7_1
			org.apache.xerces
		
		
		
			org.eclipse.birt.runtime.3_7_1
			org.apache.batik.pdf
		
	

We can now use the Report Engine API. We have to do a couple of things to render a report:

  1. Start the Platform
  2. Create an Engine
  3. Open the Report Design (.rptdesign)
  4. Create a RunAndRender task

As a starting point, I define the following class which hides most of steps from the end user. In following posts, I will build on this class to add more features. On class load we start the Platform. Assuming generation of reports is a core feature of the application I am developing I simply want starting the application to fail if BIRT does not work.
The report design is assumed to be on the class path. In this way, it is deployed along with the rest of the application, making it easier to do versioning on it. The actual output is done to an OutputStream, so an end user can use it to stream it through a servlet or store it in the database or on disk. For now, it renders HTML content.

public class ReportUtil {

    private static final EngineConfig CONFIG = new EngineConfig();
    static {
        try {
            CONFIG.setLogConfig("/home/arjanl/birt.log", Level.FINEST);
            Platform.startup(CONFIG);
        } catch (BirtException e) {
            throw new IllegalArgumentException(e);
        }
    }

    private HTMLRenderOption getRenderOptions(OutputStream outs) {
        // set render options including output type
        HTMLRenderOption options = new HTMLRenderOption();
        options.setOutputStream(outs);
        options.setSupportedImageFormats("PNG");
        options.setEmbeddable(true);
        options.setOutputFormat("html");
        return options;
    }

    public void runReport(final String reportResourceName, final Map reportParameters, OutputStream outs)
            throws EngineException {
        IReportEngineFactory factory =
                (IReportEngineFactory) Platform
                        .createFactoryObject(IReportEngineFactory.EXTENSION_REPORT_ENGINE_FACTORY);
        IReportEngine engine = factory.createReportEngine(CONFIG);
        final IReportRunnable design =
                engine.openReportDesign(ReportEngineFactory.class.getResourceAsStream(reportResourceName));
        IRunAndRenderTask task = engine.createRunAndRenderTask(design);
        task.setRenderOption(getRenderOptions(outs));
        task.setParameterValues(reportParameters);
        // pass necessary parameters
        if (!task.validateParameters()) {
            throw new IllegalArgumentException("Parameters do not validate");
        }
        task.run();
    }
}

One thing is still missing: where does this report get its data from? The class defined above will use the Data Source as defined in the rptdesign. Since data sources might be different between the different OTAP environments, we want the report to use the data source as defined by the container. Luckily, we can inject it:

task.getAppContext().put("OdaJDBCDriverPassInConnection", getConnection());

You will probably want to close() that connection when you are done with it.
With this, we have a skeleton implementation which generates HTML pages based on a rptdesign. Next time, we’ll discuss how to embed images.

Some references: