4. Usage Examples

This section includes sample code and configuration files for using the Geronimo JasperReports plugins.

The example report discussed in this section lists records from a simple table in the database.

4.1. ReportManager Example

Using the embedded scheduler, you can write a standard JasperReports report template like this.

JasperReports Report Template

<?xml version="1.0" encoding="UTF-8"  ?>
<!-- Created with iReport - A designer for JasperReports -->
<!DOCTYPE jasperReport PUBLIC "//JasperReports//DTD Report Design//EN"
          "http://jasperreports.sourceforge.net/dtds/jasperreport.dtd">
<jasperReport
     name="Untitled_report_1"
     columnCount="1"
     printOrder="Vertical"
     orientation="Portrait"
     pageWidth="612"
     pageHeight="792"
     columnWidth="552"
     columnSpacing="0"
     leftMargin="30"
     rightMargin="30"
     topMargin="20"
     bottomMargin="20"
     whenNoDataType="NoPages"
     isTitleNewPage="false"
     isSummaryNewPage="false">
  <property name="ireport.scriptlethandling" value="2" />
  <property name="ireport.encoding" value="UTF-8" />
  <import value="java.util.*" />
  <import value="net.sf.jasperreports.engine.*" />
  <import value="net.sf.jasperreports.engine.data.*" />

  <queryString><![CDATA[select product_no, product_desc from product]]></queryString>

  <field name="product_no" class="java.lang.Integer"/>
  <field name="product_desc" class="java.lang.String"/>

  <background>
    <band height="0"  isSplitAllowed="true" >
    </band>
  </background>
  <title>
    <band height="50"  isSplitAllowed="true" >
    </band>
  </title>
  <pageHeader>
    <band height="50"  isSplitAllowed="true" >
    </band>
  </pageHeader>
  <columnHeader>
    <band height="30"  isSplitAllowed="true" >
    </band>
  </columnHeader>
  <detail>
    <band height="44"  isSplitAllowed="true" >
      <textField isStretchWithOverflow="false" isBlankWhenNull="false"
                 evaluationTime="Now" hyperlinkType="None"
                 hyperlinkTarget="Self" >
        <reportElement
                x="48"
                y="20"
                width="100"
                height="18"
                key="textField"/>
        <box topBorder="None" topBorderColor="#000000" leftBorder="None"
             leftBorderColor="#000000" rightBorder="None"
             rightBorderColor="#000000" bottomBorder="None"
             bottomBorderColor="#000000"/>
        <textElement>
          <font/>
        </textElement>
        <textFieldExpression
         class="java.lang.Integer"><![CDATA[$F{product_no}]]></textFieldExpression>
      </textField>
      <textField isStretchWithOverflow="false" isBlankWhenNull="false" 
                 evaluationTime="Now" hyperlinkType="None"
                 hyperlinkTarget="Self" >
        <reportElement
                x="162"
                y="19"
                width="270"
                height="18"
                key="textField"/>
        <box topBorder="None" topBorderColor="#000000"
             leftBorder="None" leftBorderColor="#000000"
             rightBorder="None" rightBorderColor="#000000"
             bottomBorder="None" bottomBorderColor="#000000"/>
        <textElement>
          <font/>
        </textElement>
        <textFieldExpression
         class="java.lang.String"><![CDATA[$F{product_desc}]]></textFieldExpression>
      </textField>
    </band>
  </detail>
  <columnFooter>
    <band height="30"  isSplitAllowed="true" >
    </band>
  </columnFooter>
  <pageFooter>
    <band height="50"  isSplitAllowed="true" >
    </band>
  </pageFooter>
  <lastPageFooter>
    <band height="50"  isSplitAllowed="true" >
    </band>
  </lastPageFooter>
  <summary>
    <band height="50"  isSplitAllowed="true" >
    </band>
  </summary>
</jasperReport>

To deploy the report, you need to:

  1. Add the report template to the component that will schedule the job (usually on the class path)

  2. Access the embedded ReportManager

  3. Define the report by calling the ReportManager.registerReport method

  4. Run a report by calling the ReportManager.generateReport (or ReportManager.generateAndSave) method

The code to do the report registration looks like this. It could be executed in a startup servlet, or on demand by a web or EJB component, etc.

Component that Schedules a Job

Context ctx = new InitialContext();
ReportManager manager = (ReportManager)ctx.lookup("java:comp/env/ReportManager");
DataSource ds = (DataSource)ctx.lookup("java:comp/env/ReportDatabase");
ReportDefinition report = new ReportDefinition();
report.setName("TestReport");
report.setDataSource(ds);
URL template = getClass().getClassLoader().getResource("test-report.jrxml");
report.setReportTemplate(template);
manager.registerReport(report);

In order for the JNDI lookup to access the scheduler GBean, the component should include a gbean-ref element in its deployment plan (e.g. geronimo-web.xml or openejb-jar.xml):

GBean Reference in Geronimo Plan

<gbean-ref>
  <ref-name>ReportManager</ref-name>
  <ref-type>org.gplugins.jasper.ReportManager</ref-type>
  <pattern>
    <name>ReportManager</name>
  </pattern>
</gbean-ref>

Note that the ref-name defines the JNDI location where the ReportManager GBean will be bound (java:comp/env/ plus the ref-name value -- or java:comp/env/ReportManager in this case, which is where the sample code above looks it up).

Finally, in order to generate a report, a component can use code like this (assuming the same GBean reference is configured):

Generating a Report

Context ctx = new InitialContext();
ReportManager manager = (ReportManager)ctx.lookup("java:comp/env/ReportManager");
Map criteria = ... // Supply some report criteria, if necessary
InputStream reportStream = manager.generateReport("TestReport", criteria,
                                                  ReportManager.FORMAT_PDF);

4.1.1. Report Manager FAQ

Q: Is running JasperReports in Geronimo this way any different from packaging JasperReports and the report definition inside the application?

A: Not terribly. The main differences are that reports can be shared across several applications, and the JasperReports environment with all necessary JARs are pre-configured in Geronimo. It makes the application modules a little lighter and saves any trouble figuring out exactly what needs to be packed in there.

Q: Can reports be printed?

A: Presently there are no printing-specific features, and in particular, reports are always generated to a file and not e.g. to a printer device directly. You'll have to use some software that understands the file format to render the report and send it to the printer.

4.2. Deployable Reports Example

With the deployable reports approach, the sample report can be packaged in a JAR on its own, with its report template and parameters, and can be configured to access a database pool already deployed in Geronimo (rather than manually configuring connectivity in code like the previous example). The report template is the same as above (and a totally standard JasperReports template).

To configure the report paremeters and select a database pool, an XML deployment plan must be included with the JAR containing the report template(s). It can be packaged into the JAR at the location META-INF/geronimo-jasper.xml, or provided as a separate argument in addition to the JAR when deploying the job.

geronimo-jasper.xml

<?xml version="1.0" encoding="UTF-8"?>

<jobs xmlns="http://geronimo.apache.org/xml/ns/plugins/jasper-1.0">
    <environment xmlns="http://geronimo.apache.org/xml/ns/deployment-1.1">
        <moduleId>
            <artifactId>ProductReport</artifactId>
        </moduleId>
        <dependencies>
            <dependency>
                 <groupId>geronimo</groupId>
                 <artifactId>system-database</artifactId>
             </dependency>
        </dependencies>
    </environment>
    <report>
        <name>TestReport</name>
        <template-file>test-report.jrxml</template-file>
        <data-source>SystemDatasource</data-source>
        <available-output-formats>
            <output-format>PDF</output-format>
        </available-output-formats>
        <archiving />
    </report>
</jobs>

This looks similar to other Geronimo deployment plans, except the meaty part defines one or more JasperReports repoprts instead of servlets or EJBs. Some important parts to note include:

  • The moduleId element defines the unique identifier for the deployed report. This name will be used as an argument to the deploy tool to start, stop, or undeploy the job, for example. In this case it is set to ProductReport.

  • The dependencies element lists other modules that the job depends on. In this case, it depends on the module containing the database pool that the report will use.

  • Within a report definition, the name sets the name that will be used to identify this job to the ReportManager when running the report. In this case, it is TestReport.

  • The template-file defines the path to the report template. This JasperReports XML template file should be included in the report JAR. In this case it is test-report.jrxml.

  • The data-source links the report to a specific database connection pool in Geronimo. In this case, the name of the database pool is SystemDatasource (the default pool configured in Geronimo).

  • A report may list preferred output formats (here PDF), and also indicate that the output report file should be saved for future reference (using the archiving element).

If both the report template and deployment plan are packaged into a JAR, the JAR contents might look like this:

> jar -tf product-report.jar
META-INF/
META-INF/MANIFEST.MF
META-INF/geronimo-jasper.xml
test-report.jrxml

To deploy this report definition, use any of the usual Geronimo deployment tools. The syntax for the command-line deploy tool would look like this:

java -jar bin/deployer.jar deploy product-report.jar

Then, the syntax used to generate a report is the same as in the previous example:

Generating a Report

Context ctx = new InitialContext();
ReportManager manager = (ReportManager)ctx.lookup("java:comp/env/ReportManager");
Map criteria = ... // Supply some report criteria, if necessary
InputStream reportStream = manager.generateReport("TestReport", criteria,
                                                  ReportManager.FORMAT_PDF);

4.2.1. Deployable Reports FAQ

Q: What's wrong with just accessing the Report Manager directly to deploy jobs?

A: Nothing's "wrong" with that, but there are some advantages to the deployable reports approach. If you manually deploy the reports, for example, with a startup servlet, then the report templates needs to be bundled with your application and the application needs to be redeployed in order to update the reports. Also, the code that configures the report would need to manually look up or create the database connection pool to use for the report, whereas with deployable reports that can be conveniently configured in the XML plan.

Q: Does the report need to have any special code or configuration?

A: The report uses the same report template format as any JasperReports report. The plan that configures the database pool and output format is custom to this integration package, but that doesn't prevent you from reusing the report template elsewhere.

Q: Isn't this an awful lot of XML?

A: It is more than we'd prefer. We'll look at how to reduce it in the future.

Q: Do I need a separate JAR and XML for every report?

A: No, you can list one or many reports in each module you deploy. However, it's only possible to redeploy the module as a whole. So the benefit of deploying the reports individually is you can update them individually, but it requires more JARs (or at least more XML plans). Each report can be started and stopped individually in any case; the only difference is redeployment.

Q: I got the error "Error: Unable to distribute my-reports.jar: Cannot deploy the requested application module because no deployer is able to handle it..."

A: That means Geronimo didn't link up the JAR you deployed with the JasperReports deployer module. First, check that the namespace is correct in your XML plan. The jobs element should have xmlns="http://geronimo.apache.org/xml/ns/plugins/jasper-1.0" (make sure that is exact, though it may change for future releases of the plugin). If that's correct, make sure the jasper-deployer module is running. Try java -jar bin/deployer.jar list-modules and make sure that you see gplugins/jasper-dpeloyer/.../car in the list and that it has a + next to it. If not, you can run java -jar bin/deployer.jar start jasper-deployer to start it.