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.
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:
Add the report template to the component that will schedule the job (usually on the class path)
Access the embedded
ReportManager
Define the report by calling the
ReportManager.registerReport
method
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);
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.
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);
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.