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

[sourcecode language=”bash”]
#!/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

[/sourcecode]

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

[sourcecode language=”xml”]
<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>

[/sourcecode]

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

[sourcecode language=”java”]
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);
}
}
[/sourcecode]

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.

[sourcecode language=”java”]
config.setEngineHome("");
IPlatformContext context =
new PlatformServletContext( sc );
config.setPlatformContext( context );
[/sourcecode]

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

[sourcecode language=”java”]
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;
}
}
[/sourcecode]

Other Useful References:

Written by 

Vikas is the CEO and Co-Founder of Knoldus Inc. 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). Vikas has been working in the cutting edge tech industry for 20+ years. He was an ardent fan of Java with multiple high load enterprise systems to boast of till he met Scala. His current passions include utilizing the power of Scala, Akka and Play to make Reactive and Big Data systems for niche startups and enterprises who would like to change the way software is developed. To know more, send a mail to hello@knoldus.com or visit www.knoldus.com

7 thoughts on “Deploying BIRT in Your Existing Web Application

  1. 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”));

  2. 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

  3. 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?

Leave a Reply

%d bloggers like this: