Cloud Foundry logo in white on a blue background
blog single gear
Engineering

Java Reporting Engine is Now Available on Cloud Foundry via JasperReports

The popular Java reporting engine from JasperSoft is now available as a Cloud Foundry package. With two simple commands developers can make JasperReports Server available on Cloud Foundry and build powerful reports querying  Cloud Foundry data services.  Deploying  JasperReport server using the Cloud Foundry command line tool (‘VMC’) is as simple as ‘vmc push’ and  ‘vmc bind-service’.

Cloud Foundry is a strategic platform for many users . As more applications get deployed to Cloud Foundry open PaaS, more developers will find the need to perform reporting and analysis (Business Intelligence) on the data that they are gathering. You could write your own reporting features… but that’s a lot of work, and it’s generally not your core strength. It makes sense to focus on improving your own application, and then embed analysis and reporting features.

With that in mind, we wanted to make JasperReports Server available on Cloud Foundry. It’s a logical extension for the most widely used Business Intelligence solution to move into the PaaS world.

The accompanying video shows how to configure and install JasperReports Server on Cloud Foundry.  We will review the steps in the details of the sections below.

By default, JasperReports Server (JRS) requires a JNDI connection to a database to hold its metadata repository. Normally it’s defined like this in applicationContext-webapp.xml:

[code 1="xml" language=""]
<bean id="dataSource">
  <property name="jndiName" value="java:comp/env/${metadata.hibernate.dataSource.jndiName}"/>
</bean>
[/code]

While JNDI is not supported on Cloud Foundry, the standard Spring DataSource is available. So the change was relatively simple:

[code 1="xml" language=""]
<cloud:properties id="cloudProperties"/>
<bean id="dataSource" destroy-method="close">
  <property name="driverClassName" value="${db.driverClassName}" />
  <property name="url" value="${db.url}" />
  <property name="username" value="${db.username}" />
  <property name="password" value="${db.password}" />
</bean>
[/code]

There are a few additional details around creating and referencing a new file called data-services.properties which contains the values for connecting to the repository database. We had to reference this file in applicationContext-webapp.xml:

[code 1="xml" language=""]
<bean id="propertyConfigurer">
 <property name="locations">
  <list>
   <value>/WEB-INF/hibernate.properties&lt; /value>
   <value>/WEB-INF/data-services.properties&lt; /value>
  </list>
 </property>
 <property name="properties" ref="cloudProperties"/>
 <property name="localOverride" value="true"/>
</bean>
[/code]

The file data-services.properties contains a mix of static default values and values that are populated dynamically by Cloud Foundry. For example, a developer is free to modify the name of the JasperReports Server repository database, but by default we assume it will be called “jrs-repo”. On the other hand, the connection information is dynamically generated when the application is deployed. Here are a few lines from the file:

serviceName=jrs-repo
db.name=${cloud.services.${serviceName}.connection.name}
db.url=jdbc:${serviceType}://${db.host}:${db.port}/${db.name}
db.username=${cloud.services.${serviceName}.connection.username}

After making this modification to get connected to the database, we needed to populate it. When using JasperReports Server in a standard on-premises situation, we would run a script that creates and populates the database. When deploying to Cloud Foundry we don’t have quite the same options. “Caldecott”, a new feature that allows developers to open a tunnel to any Cloud Foundry data service via a local port, is beginning to change this. But to fit into the PaaS world seamlessly, it makes more sense to have our application “bootstrap” the repository. Rather than assuming that the repository is already appropriately populated, we instead test on startup. If the required repository tables don’t exist, then we create them. This was the most significant change we made to our application, but it’s a feature that would make life easier for customers deploying on-premises as well. We plan to migrate this feature into our core product.

With these two changes in place, we were able to push the application up to Cloud Foundry and have it automatically configure itself and start working. But there was still one important piece to add.

The most common data source that a user needs for BI is a SQL data source. A connection to the database is normally created either by adding a JNDI data source or by defining a JDBC data source directly in the JasperReports Server user interface. But JNDI is not available, and you cannot define a JDBC data source if you don’t know your username and password. (It’s possible to determine your username and password for a database on Cloud Foundry… but part of the benefit is that you shouldn’t need to worry about it.)

We needed a custom SQL data source that is Cloud Foundry-aware. This required a new class that extends the JasperReports class BaseJdbcDataSource which adds support for Cloud Foundry’s RdbmsServiceInfo to get database connection information.

Likewise, Jaspersoft already has a connector for MongoDB, but this needed to be extended to include Cloud Foundry’s MongoServiceInfo class and provide for a Cloud Foundry-aware MongoDB data source. With these two additional .jar files and corresponding applicationContext files, we were then ready to deploy JasperReports Server to Cloud Foundry.

The following excerpt is from deploying JasperReports server to the Cloud Foundry and then binding an existing database to it so that we can begin creating reports and performing analysis. Typically an application will use either MySQL or PostgreSQL or MongoDB, but for our tests we used all three at once.

>vmc push
Would you like to deploy from the current directory? [Yn]: Y
...
Would you like to bind any services to 'jrs-community-421'? [yN]: y
The following system services are available:
1. mongodb
2. mysql
3. postgresql
4. rabbitmq
5. redis
Please select one you wish to provision: 2
Specify the name of the service [mysql-a8ec3]: jrs-repo
Creating Service: OK
...
Push Status: OK

vmc bind-service postgresql-data jaspersoft-421
vmc bind-service mongodb-data jaspersoft-421

By taking advantage of the ‘bind-service’ command end users avoid any additional configuration when attaching data sources for reporting e.g.: manually entering the IP address of the datastore, entering the name of the database, managing credentials, selecting a port number, constructing the target URL, or defining the JNDI source. Cloud Foundry’s simple ‘bind-service’ semantics transforms the eight step process above into one simple command. Additional Information:

We are excited about the power of the Cloud Foundry ecosystem and the ease with which one can now use BI in the cloud. We are eager to hear feedback from the Cloud Foundry community as folks start using Jaspersoft to analyze and report on data.

A Guest Blog Post by Matthew Dahlman, Jaspersoft *

Don’t have a Cloud Foundry account yet? Sign up for free today