Eclipse BIRT in Spring web applications

Many applications we built have to provide reporting to allow end users to monitor results, progress, etc. In most cases a simple query and an Excel export is more than sufficient. In cases where more advanced reports are required we often look at projects like JasperReports or if that doesn't suffice maybe even Crystal Reports. As I'll try to explain in this blog, it might be worth your time to take a look at Eclipse BIRT.

The Eclipse “Business Intelligence and Reporting Tools” is one of those Eclipse projects I've been tracking for some time now. Its current release features a report designer based on our favorite IDE (also available as standalone download) which allows non-technical users to create reports with charts, tables, etc. It includes a web based report viewer application. It can of course execute the report designs, but also provides export capabilities (with AJAX column selection) and a range of other features.

For a more thorough overview of the features of BIRT, take a look at their website at http://eclipse.org/birt/phoenix. Features I found interesting:

  • Standalone designer (based on the Eclipse IDE)
  • Support for various datasources (including XML)
  • Different output formats (with similiar layout)
    Currently it supports PDF and HTML, but there is also an (experimental) XLS emitter available. Look for "tribix" here: http://qauck.blogspot.com

In most cases we want to include the reporting directly in our applications (to be able to provide security, caching, etc.). Since most of our applications are built using the Spring framework it would be convenient if we could use BIRT by instantiating a few beans. As it turns out we can, but it took me some time reading (sometimes) badly documented source code and googling a lot. The remainder of this blog describes the steps I took to integrate BIRT in a sample Spring web application.

Installation of the BIRT runtime
The BIRT project provides a download of just the components needed to execute and render reports in JEE environments named appropriately the "BIRT Runtime". For the example application I used the 2.1RC6 version. You can download it from Eclipse.org and extract it to ${eclipse.birt.home} (we're using this property later on).

Example project
I've attached a Maven 1.x example project to this page which includes all the code and necessary configuration. Since the BIRT libraries are not (yet) available on any public repository, you will need to copy the required libraries from the BIRT runtime (see ${eclipse.birt.home}/WebViewExample/WEB-INF/lib) and rename them according to the project.xml.

Firing up BIRT
Before we can start calling the BIRT API to execute and render reports, the BIRT platform itself must first be started using the appropriate configuration objects. Doing this from inside a Spring application context using just the BIRT classes turned out be difficult, so I've created two utility classes:

BirtConfiguration
Besides the getters and setters for properties this class provides the getEngineConfig() method, which creates an instance of EngineConfig used to configure BIRT upon startup. The "birtInstallation" property by itself is enough to start it and render reports, but the HTML export will use file:// uri's to reference any images you've included. We can solve this by telling BIRT to use the HTMLServerImageHandler and set the appropriate configuration (see BIRT spring configuration). In addition we can also specify the loglevel here.

public EngineConfig getEngineConfig() {
    if (engineConfig == null) {
      if (log.isDebugEnabled()) {
        log.debug("Creating new instance of EngineConfig");
      }

      engineConfig = new EngineConfig();
      engineConfig.setEngineHome(birtRuntimeLocation);
      engineConfig.setLogConfig(logLocation, logLevel);

      HTMLEmitterConfig htmlConfig = new HTMLEmitterConfig();
      htmlConfig.setActionHandler(new HTMLActionHandler());
      
      // This allows images to be referenced by url
      htmlConfig.setImageHandler(new HTMLServerImageHandler());

      engineConfig.getEmitterConfigs().put("html", htmlConfig);
    }

    return engineConfig;
  }

BirtPlatformListener
This class uses the EngineConfig (as created by the BirtConfiguration class) to start and initalize the platform, and allows the creation of an IReportEngine which in turn can be used to execute and render reports.

  public void start() {
    try {
      Platform.startup(engineConfig);
    } catch (BirtException be) {
      throw new IllegalArgumentException("Failure starting BIRT platform", be);
    }
  }

  public void shutdown() {
    if (reportEngine != null) {
      reportEngine.shutdown();
    }

    // Just call shutdown
    Platform.shutdown();
  }

  public IReportEngine getReportEngine() {
    if (reportEngine == null) {
      IReportEngineFactory factory = (IReportEngineFactory)
      Platform.createFactoryObject(IReportEngineFactory.EXTENSION_REPORT_ENGINE_FACTORY);

      reportEngine = factory.createReportEngine(engineConfig);
    }

    return reportEngine;
  }

Bean definitions
Once we have these two classes, it's simply a matter of configuring beans to be able to use BIRT whenever we want to. The following snippet from the spring context shows all the required definitions to start and stop the platform along with the application and create an IReportEngine instance.

	<!-- BIRT configuration -->
	<bean id="birtConfig"
		class="com.xebia.springbirt.util.BirtConfiguration">
		<property name="birtRuntimeLocation"
			value="${eclipse.birt.home}/ReportEngine" />
		<property name="logLocation" value="${eclipse.birt.logdir}" />
	</bean>

	<bean id="platformListener"
		class="com.xebia.springbirt.util.BirtPlatformListener"
		init-method="start" destroy-method="shutdown">
		<property name="engineConfig">
			<bean factory-bean="birtConfig"
				factory-method="getEngineConfig" />
		</property>
	</bean>

	<bean id="reportEngine" factory-bean="platformListener"
		factory-method="getReportEngine" />

	<!-- Render context beans -->
	<bean id="pdfRenderContext"
		class="org.eclipse.birt.report.engine.api.PDFRenderContext">
		<property name="supportedImageFormats" value="JPG;PNG;BMP;SVG" />
	</bean>

	<bean id="htmlRenderContext"
		class="org.eclipse.birt.report.engine.api.HTMLRenderContext">
		<property name="supportedImageFormats" value="JPG;PNG;BMP" />
		<property name="baseImageURL" value="${springbirt.url}/reportImage.html?id="/>
		<property name="imageDirectory" value="${eclipse.images.dir}"/>
	</bean>

Adding some controllers
I've created two Spring MVC controllers for the sample application. The ReportImageController is responsible for receiving requests for images included in the reports. It simply tries to open the file and writes back the contents (and deletes the files afterwards).

The ReportController is responsible for calling BIRT and executing our example report. The sample application includes a report design that uses the Slashdot RSS feed as datasource. The following code shows how to execute and render this report:

protected ModelAndView handleRequestInternal(HttpServletRequest request, HttpServletResponse response) throws Exception {
    String format = RequestUtils.getStringParameter(request, "format", "html");

    IReportRunnable runnable = reportEngine.openReportDesign(new ClassPathResource("BirtExample.rptdesign").getInputStream());
    IRunAndRenderTask runAndRenderTask = reportEngine.createRunAndRenderTask(runnable);

    // Although it's called HtmlRenderOption, it is used for all formats
    HTMLRenderOption htmlRenderOption = new HTMLRenderOption();
    htmlRenderOption.setOutputFormat(format);
    htmlRenderOption.setOutputStream(response.getOutputStream());

    runAndRenderTask.setAppContext(renderOptions);
    runAndRenderTask.setRenderOption(htmlRenderOption);
    runAndRenderTask.run();

    return null;
  }

Accessing the application (by default http://localhost:8080/springbirt/) should result in a HTML page which looks similar to this (altough probably with new entries :-)):
Screenshot of Slashdot Birt report

If you'd rather take a look at the PDF version, just append ?format=pdf to the URL. You should now get a nice PDF in the same format as the HTML version.

The example application is simple. It only allows viewing an entire report without any interaction (which in most cases is enough), but it could be extended to provide similar features to the web applicatation that BIRT provides...

Conclusion
Although BIRT still has some flaws (e.g. the designer that keeps mixing up formatting of my charts), it's a powerful platform that I'm certainly going to be using for reporting more often.

Comments (13)

  1. Michael Franken - Reply

    September 1, 2006 at 11:32 am

    Great work, Silvester. Are you considering donating the com.xebia.springbirt stuff to Spring or make it available as Open Source?

  2. Silvester Van der Bijl - Reply

    September 1, 2006 at 3:52 pm

    Thanks! I\'ve been looking at the support for JasperReports in Spring, and I\'m considering creating View classes (like AbstractJasperReportsView). If the people add Spring are interested I\'ll be happy to donate it...

    Update: seems more people are interested in seeing Spring support for BIRT: http://opensource.atlassian.com/projects/spring/browse/SPR-1220

  3. Jason Weathersby - Reply

    November 9, 2006 at 9:43 pm

    Silvester,

    Nicely done. It would be great if you could add this example to the BIRT wiki. If you are interested send me an email at jasonweathersby at alltel.net.

    Thanks

    Jason

  4. M Chisty - Reply

    March 7, 2007 at 5:30 am

    Can u show us how is it possible to integrate BIRT with Struts 2 with an example?

  5. Leonard - Reply

    November 23, 2007 at 7:46 pm

    Is there any example of integreting BIRT with struts 2 ?
    M Chisty, did you find something ?

  6. David Apimerika - Reply

    March 5, 2008 at 10:26 am

    Cool stuff. I would like to see a tutorial that takes the jpetstore and extend it to produce reports using BIRT. As jpetstore supports either Spring or Struts, one of the questions above may be covered in the process. The jpetstore is a great learning aid (for me), especially couple with that book "Better, Faster, Lighter Java".

  7. kishore maddipoti - Reply

    April 28, 2008 at 6:43 am

    This is very informative for the beginners and very excellent to refer

  8. Prakash Palanisamy - Reply

    July 4, 2008 at 12:50 pm

    thanks dude. Found superb information about the integration of BIRT with Spring. thank you so much. Keep post.

  9. Burt - Reply

    August 24, 2009 at 8:07 pm

    I got bir exception while display the rptdesign. invalid javascript dataSetRow[...]
    I use birt 2.5, Jboss4.2, Eclipse 3.2, spring

  10. BIRT: start to use - Reply

    June 21, 2010 at 11:32 am

    [...] – POJO+BIRT: a kind of (imho) stupid (but popular) situation of using (or exampling) it. Eclipse BIRT in Spring web applications + more. Deploying BIRT. Tagged with: birt • Environment • report  0 Comments [...]

  11. Rajesh - Reply

    July 15, 2010 at 6:39 am

    2010-07-15 10:34:17 IST - WARN [main] PropertyPlaceholderConfigurer - Could not load properties from class path resource [springbirt.properties]: class path resource [springbirt.properties] cannot be opened because it does not exist
    2010-07-15 10:34:17 IST - INFO [main] XmlWebApplicationContext - Unable to locate MessageSource with name 'messageSource': using default [org.springframework.context.support.DelegatingMessageSource@102679a]
    2010-07-15 10:34:17 IST - INFO [main] XmlWebApplicationContext - Unable to locate ApplicationEventMulticaster with name 'applicationEventMulticaster': using default [org.springframework.context.event.SimpleApplicationEventMulticaster@11e1bbf]
    2010-07-15 10:34:17 IST - INFO [main] UiApplicationContextUtils - Unable to locate ThemeSource with name 'themeSource': using default [org.springframework.ui.context.support.ResourceBundleThemeSource@175b7f9]
    2010-07-15 10:34:17 IST - INFO [main] DefaultListableBeanFactory - Pre-instantiating singletons in factory [org.springframework.beans.factory.support.DefaultListableBeanFactory defining beans [org.springframework.beans.factory.config.PropertyPlaceholderConfigurer,handlerMapping,viewResolver,reportController,reportImageController,birtConfig,platformListener,reportEngine,pdfRenderContext,htmlRenderContext]; root of BeanFactory hierarchy]
    2010-07-15 10:34:18 IST - INFO [main] DefaultListableBeanFactory - Destroying singletons in factory {org.springframework.beans.factory.support.DefaultListableBeanFactory defining beans [org.springframework.beans.factory.config.PropertyPlaceholderConfigurer,handlerMapping,viewResolver,reportController,reportImageController,birtConfig,platformListener,reportEngine,pdfRenderContext,htmlRenderContext]; root of BeanFactory hierarchy}
    2010-07-15 10:34:18 IST - ERROR [main] DispatcherServlet - Context initialization failed
    org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'reportController' defined in ServletContext resource [/WEB-INF/webContext.xml]: Cannot resolve reference to bean 'reportEngine' while setting bean property 'reportEngine'; nested exception is org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'platformListener' defined in ServletContext resource [/WEB-INF/webContext.xml]: Initialization of bean failed; nested exception is java.lang.IllegalArgumentException: Failure starting BIRT platform
    org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'platformListener' defined in ServletContext resource [/WEB-INF/webContext.xml]: Initialization of bean failed; nested exception is java.lang.IllegalArgumentException: Failure starting BIRT platform
    java.lang.IllegalArgumentException: Failure starting BIRT platform

    Getting error while application startup...
    springbirt.properties file not found. pls attach file

  12. Shivayan mukherjee - Reply

    April 25, 2012 at 12:54 pm

    you will need to copy the required libraries from the BIRT runtime (see ${eclipse.birt.home}/WebViewExample/WEB-INF/lib) and rename them according to the project.xml.

    can any1 please elaborate this line?? what jars are required and where to find the project.xml file??

  13. Abdul sukhaini - Reply

    December 11, 2013 at 2:16 pm

    this is the best example in the world., thank you very much

Add a Comment