Deploying BIRT in Your Existing Web Application


The Business Intelligence and Reporting Tools (BIRT) project is an open source, Eclipse-based reporting framework that enables the creation and deployment of enterprise reports. Development with BIRT can usually be thought of as a two-step process:

  1. The creation of the report designs within the Eclipse BIRT Report Designer
  2. Deployment of the designs and framework to an application for dissemination.

BIRT also offers three public APIs and a J2EE servlet-based viewer that can be used outside of Eclipse.

  1. Design Engine API (DE API) – The DE API is responsible for creating and modifying the XML report design format. This API is what the Eclipse BIRT Report Designer uses to create the report design
  2. Report Engine API (RE API) – The RE API is responsible for consuming the report design files and producing the report output.
  3. Chart Engine API (CE API) – The CE API can be used to create and render charts standalone or through the DE and RE APIs.

There are 2 major deployment formats that are used for web applications

  1. Deploy the BIRT Viewer to a J2EE application server.
  2. Create a servlet that wraps the RE API and deploy it to a J2EE application server.

Assuming that you already have a pre-existing web application and would like to introduce the BIRT component for reporting, the recommended format would be the latter i.e. “Create a servlet that wraps the RE API and deploy it to a J2EE application server.”

Existing Web Application with embedded BIRT RE

Advantages of this approach are that you can embed the runtime engine in the existing web application and use the RE for generating reports. There is no need to copy the design report files to a separate war for rendering. It is a clean approach to integrate with your existing web application.

The major drawback to deploying BIRT in this fashion is that native functions supplied by the BIRT Viewer are not available without the developer coding them into the servlet. These functions include TOC, paginated HTML, and export to CSV. This approach is generally used when the developer has a specific need, such as direct generation to PDF, and does not want the other functions available in the viewer. This approach is as good as writing a custom viewer for report rendering.

How to embed the Runtime Engine into the existing Web App? Assuming that you are using the eclipse platform, you would need the RE and related jars in your project so that you can use them at compile time. Unfortunately, the BIRT jars are not present on the maven repository. There are BIRT 2.3.2 jars which are present on JBoss but for the latest release we would have to manually install these jars in the local repository. If you have nexus, then you could install there jars there too. Use the following script to install the BIRT jars into the mvn repository

#!/bin/sh
BV=2.6 #Birt version
PK=jar   #package type

# For linux export BIRT_HOME=/path/to/birt

if  [ "x" = "x$BIRT_HOME" ]; then
echo "variable BIRT_HOME , containing lib/ and plugins/ must be set"
exit;
fi;

BASEDIR=$BIRT_HOME/ReportEngine/lib
BIRT_GROUP=org.eclipse.birt
EMF_GROUP=org.eclipse.emf.ecore
ACTUAL_DIR=`pwd`
cd $BASEDIR
#We Assume thar the 3 emf jars have the same version number , and take org.eclipse.emf.common for reference
# For 2.6 i changed the emf ecore xmi jar to have the same version as the common
EMFV=`ls org.eclipse.emf.common*.jar | sed -e 's/.jar$//' | sed -e 's/.*_//'`

#BIRT APIs
for i in `ls *api.jar | sed -e 's/.jar$//'` ;
do mvn install:install-file -DgroupId=$BIRT_GROUP -DartifactId=${i} -Dversion=$BV -Dpackaging=$PK -Dfile="$BASEDIR/${i}.$PK" -DgeneratePom=true ;
done;

#EMF ( Eclipse Modeling Framework ) . Assuming the 3 emf jars have the same version number!
for i in `ls org.eclipse.emf.*.jar | sed -e 's/.jar$//' | sed -e 's/_.*//'` ;
do mvn install:install-file -DgroupId=${i} -DartifactId=${i} -Dversion=$EMFV -Dpackaging=$PK -Dfile="$BASEDIR/${i}_$EMFV.$PK" -DgeneratePom=true ;
done;

# Misc
mvn install:install-file -DgroupId=org.w3c -DartifactId=flute -Dversion=1.3 -Dpackaging=jar -Dfile="flute.$PK" -DgeneratePom=true
mvn install:install-file -DgroupId=org.w3c -DartifactId=sac -Dversion=1.3.0.v200805290154 -Dpackaging=jar -Dfile="org.w3c.css.sac_1.3.0.v200805290154.$PK" -DgeneratePom=true
mvn install:install-file -DgroupId=com.ibm -DartifactId=icu -Dversion=4.2.1.v20100412 -Dpackaging=jar -Dfile="com.ibm.icu_4.2.1.v20100412.$PK" -DgeneratePom=true
mvn install:install-file -DgroupId=com.lowagie -DartifactId=itext -Dversion=1.3 -Dpackaging=jar -Dfile="itext-1.3.$PK" -DgeneratePom=true
mvn install:install-file -DgroupId=org.mozilla.rhino -DartifactId=js -Dversion=1.6R7 -Dpackaging=jar -Dfile="js.$PK" -DgeneratePom=true
#
cd $ACTUAL_DIR

Once the jars are installed in the maven repository, you could include them in your pom.xml as

	<properties>
		<birt.version>2.6</birt.version>
	</properties>

	<dependencies>
		<dependency>
			<groupId>junit</groupId>
			<artifactId>junit</artifactId>
			<version>4.8.1</version>
			<scope>test</scope>
		</dependency>
		<dependency>
			<groupId>javax.servlet</groupId>
			<artifactId>servlet-api</artifactId>
			<version>2.5</version>
		</dependency>

		<dependency>
			<groupId>org.eclipse.birt</groupId>
			<artifactId>chartengineapi</artifactId>
			<version>${birt.version}</version>
		</dependency>

		<dependency>
			<groupId>org.eclipse.birt</groupId>
			<artifactId>coreapi</artifactId>
			<version>${birt.version}</version>
		</dependency>

		<dependency>
			<groupId>org.eclipse.birt</groupId>
			<artifactId>dataadapterapi</artifactId>
			<version>${birt.version}</version>
		</dependency>

		<dependency>
			<groupId>org.eclipse.birt</groupId>
			<artifactId>engineapi</artifactId>
			<version>${birt.version}</version>
		</dependency>

		<dependency>
			<groupId>org.eclipse.birt</groupId>
			<artifactId>modelapi</artifactId>
			<version>${birt.version}</version>
		</dependency>

		<dependency>
			<groupId>org.eclipse.birt</groupId>
			<artifactId>scriptapi</artifactId>
			<version>${birt.version}</version>
		</dependency>

		<dependency>
			<groupId>org.eclipse.birt</groupId>
			<artifactId>dteapi</artifactId>
			<version>${birt.version}</version>
		</dependency>

		<dependency>
			<groupId>com.ibm</groupId>
			<artifactId>icu</artifactId>
			<version>4.2.1.v20100412</version>
		</dependency>

		<dependency>
			<groupId>org.mozilla.rhino</groupId>
			<artifactId>js</artifactId>
			<version>1.6R7</version>
		</dependency>

		<dependency>
			<groupId>commons-codec</groupId>
			<artifactId>commons-codec</artifactId>
			<version>1.4</version>
		</dependency>
		<!-- Added the extra w3c jars that we had included -->
		<dependency>
			<groupId>org.w3c</groupId>
			<artifactId>flute</artifactId>
			<version>1.3</version>
		</dependency>
		
		<dependency>
			<groupId>org.w3c</groupId>
			<artifactId>sac</artifactId>
			<version>1.3.0.v200805290154</version>
		</dependency>
		
	</dependencies>
		

Next step is create a platform directory under src/main/webapp/WEB-INF of your maven structure.  Copy the birt-runtime-2_6_0/Report Engine/plugins and birt-runtime-2_6_0/Report Engine/configuration directories to the platform directory you just created. These 3 steps complete the embed part of the BIRT RE into your web application.

How to call the RE for a report request?

There are three main components required to generate the report for an incoming request
  1. A servlet to handle the request and pass the details to the Report Engine

  2. Report Engine Manager to set up the report engine and start a BIRT Engine instance

  3. A configuration file for BIRT RE

The BirtConfig.properties file contains only two entries.logDirectory=c:/temp logLevel=FINEST The logDirectory specifies where the Report Engine will log entries. The logLevel sets the level for logging. As stated earlier, we would have to create a Report. java servlet which serves the requests for reports. The doGet() method of the servlet could be something like this

	public void doGet(HttpServletRequest req, HttpServletResponse resp)
			throws ServletException, IOException {

		resp.setContentType("application/pdf");

		// fetch the report name to be generated
		String reportName = req.getParameter("ReportName");
		ServletContext sc = req.getSession().getServletContext();
		this.birtReportEngine = BirtEngine.getBirtEngine(sc);

		// setup image directory
		HTMLRenderContext renderContext = new HTMLRenderContext();
		renderContext.setBaseImageURL(req.getContextPath() + "/images");
		renderContext.setImageDirectory(sc.getRealPath("/images"));

		HashMap contextMap = new HashMap();
		contextMap.put(EngineConstants.APPCONTEXT_HTML_RENDER_CONTEXT,
				renderContext);

		IReportRunnable design;
		try {
			// Open report design
			design = birtReportEngine.openReportDesign(sc
					.getRealPath("/Reports") + "/" + reportName);
			// create task to run and render report
			IRunAndRenderTask task = birtReportEngine
					.createRunAndRenderTask(design);
			task.setAppContext(contextMap);

			// set output options
			HTMLRenderOption options = new HTMLRenderOption();
			options.setOutputFormat(HTMLRenderOption.OUTPUT_FORMAT_PDF);
			options.setOutputStream(resp.getOutputStream());
			task.setRenderOption(options);

			task.run();
			task.close();
		} catch (Exception e) {

			e.printStackTrace();
			throw new ServletException(e);
		}
	}

The BirtEngine.java class is a singleton and is used to create one instance of the Report Engine for the servlet. It has a synchronized method for retrieving the instance, or creating and configuring it if it doesn’t exist. The BIRT Report Engine uses OSGi to load Eclipse plugins. These plugins provide functions for connecting to data sources and emitting PDF/HTML. The following lines instruct the Report Engine to look in the src/main/webapp/WEB-INF/platform directory when starting Eclipse plugins using OSGi.

config.setEngineHome("");
IPlatformContext context =
               new PlatformServletContext( sc );
config.setPlatformContext( context );

The rest of the code within this class is responsible for starting the platform and creating the report engine.

public static synchronized IReportEngine getBirtEngine(ServletContext sc) {
  if (birtEngine == null)
  {
                .
                .
        try
        {
                //Start up the OSGi framework
                Platform.startup( config );
        }
        catch ( BirtException e )
        {
                e.printStackTrace( );
        }

        IReportEngineFactory factory =
                (IReportEngineFactory) Platform.
                 createFactoryObject(
                 IReportEngineFactory.
                 EXTENSION_REPORT_ENGINE_FACTORY
                 );

        birtEngine =
                  factory.createReportEngine( config );
        }
        return birtEngine;
  }
}

Other Useful References:

About Vikas Hazrati

Vikas is the Founding Partner @ Knoldus which is a group of software industry veterans who have joined hands to add value to the art of software development. Knoldus does niche Reactive and Big Data product development on Scala, Spark and Functional Java. Knoldus has a strong focus on software craftsmanship which ensures high-quality software development. It partners with the best in the industry like Lightbend (Scala Ecosystem), Databricks (Spark Ecosystem), Confluent (Kafka) and Datastax (Cassandra). To know more, send a mail to hello@knoldus.com or visit www.knoldus.com
This entry was posted in Architecture, Java. Bookmark the permalink.

7 Responses to Deploying BIRT in Your Existing Web Application

  1. Pingback: Using Scripted Data-Sources in BIRT and Deploying in Application Server « Inphina Thoughts

  2. Meetu Maltiar says:

    Hi Vikas,
    you can get rid of the deprecated BIRT Api’s by directly setting base image url and image directory in HTMLRenderOption. You will have to remove HTMLRenderContext and contextMap followed by adding following lines in the servlet code
    options.setBaseImageURL(req.getContextPath()+”/report/images”);
    options.setImageDirectory(sc.getRealPath(“/report/images”));

  3. Virgil Dodson says:

    Hi Vikas, This is a great article and would be a valuable resource for the users who roll through BIRT Exchange. You can just add a link to your post in the DevShare area at BIRT Exchange. Let me know if you need help.

    Virgil Dodson
    Evangelist
    Actuate/BIRT Exchange

  4. Pramod says:

    Hi, your article was wonderful. could you please share the code with me. i am working on a project based on birt. i need to know one complete cycle of request coming from browser and hitting birt and generating report. even a simple hello world would be a great help. i am not able to crack this. if you could help on this?

  5. Luis says:

    Hi Vikas, Is possible integrate birt reports in angularJs?

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s