JFreeReportDevHowTo

JFreeReport Classic - Getting Started Developer's Guide

This document will help the new JFreeReport developer get started working with the JFreeReport Classic engine. It will outline how to setup a development environment, how to run through some sample reports, and describe (some of) the architecture of the classic engine.

NOTE: I am creating this document as I learn this myself ... so some of the information may be incorrect until I am corrected or I learn my lessons (big grin)

Setting Up the Development Environment

When I setup my development environment, I used the Eclipse IDE and connected to the JFreeReport repository to get the classic engine code. The step-by-step instructions have already been documented elsewhere in the Wiki.

Running the Reporting Demo Application 

Using the already documented procedures for getting a project out of the "classic" branch of the source code repository, you should check out the project jfreereport-demo and set it up in the development environment and make sure it compiles cleanly. Once that is completed, run (as a Java Application) the org.jfree.report.ancient.demo.DemoFrontend class.

A window will be displayed that has a list of reports on the left side (organized in folders) and a description of the report on the right side. Below the report description is the dataset that the report will use.

Select the "Color and Letter Group Demo" ... then (after reading the description and reviewing the source data), clock the "Print Preview" button on the bottom of the window. After a few seconds, the report will be displayed in a new window. Page through the report and notice the report heading, page headings, details.

After being amazed at the crispness of the report, open the report description XML document ( .../source/org/jfree/report/ancient/demo/groups/data-groups.xml ) and see how this report is defined.

To help reading the XML document, review the document: Pentaho Advanced Reporting Guide - Understanding the Pentaho File Report Definition

Exe-Wrappers and Jar-File-Optimizers

Pentaho Reporting's architecture relies heavily on dynamic classloading. Tools which try to find unused classes to remove them from the final deployment jar-file cannot handle such cases and will not generate runnable applications with their efforts.

If you want to use such tools, make sure that all such size-optimizations are disabled for the Pentaho Reporting classes.

How and where to start with the engine

Right now the documentation we have can be considered ... improvable. So usually it is a good idea to get started by looking at the demos. (In the pentaho-reporting-classic-demo package.)

For the Java side of the reporting, I now assume that there is a a report definition file somewhere. To parse a report, you first need the URL to the report-definition (or a file-object, whatever you prefer), and then you feed that into the parser.

// from http://wiki.pentaho.org/display/Reporting/Pentaho+Reporting+XML+Definition+formats
private JFreeReport parseReport(URL in) throws ReportDefinitionException
{
    if (in == null)
    {
      throw new ReportDefinitionException("ReportDefinition Source is invalid");
    }

    try
    {
      ResourceManager manager = new ResourceManager();
      manager.registerDefaults();
      Resource res = manager.createDirectly(in, JFreeReport.class);
      return (JFreeReport) res.getResource();
    }
    catch(Exception e)
    {
      throw new ReportDefinitionException("Parsing failed", e);
    }
}

If your report-definition contained a data-source definition as well, this JFreeReport object can now be used for reporting.

To show the swing-preview-dialog:

      JFreeReport report; // created elsewhere ..

      final PreviewDialog frame = new PreviewDialog(report);
      frame.pack();
      RefineryUtilities.positionFrameRandomly(frame);
      frame.setVisible(true);

or (you mentioned PDF) you can use this object to generate the desired content directly, for instance:

      PdfReportUtl.createPdf(report, "/tmp/report.pdf");

*ReportUtil classes are available for all export types; if they do not provide enough flexibility, you can instantiate and configure the report processors manually as well. To send the data directly to the HttpResponse, simply use the createPdf(..) method that accepts an output-stream. Cleaning temporary files is just ugly, so we better dont create them in the first place.

How the data comes to the report

Since version 0.8.9, we provide several data-source-factory implementations to allow the reports to query the data for the reporting by themself. The two most interesting options are the "SQLDataFactory" and the "NamedStaticDataFactory". The SQL-datafactory uses JDBC to query a database, while the NamedStaticDataFactory uses Java-reflection to call a method in your code to return a dataset. For both data-factories you have the choice of whether you define them in XML or with Java-code.

Each report and sub-report has a "query" property that contains the name of a query defined in the data-source. Queries can be parametrized by simply inlining the parameter-name into the SQL-query.

Examples for XML-Definitions that use XML to define a SQL-DataSource can be found in the demo (package org.jfree.report.demo.features.datasource and org.jfree.report.demo.features.subreport).

(More on the format of SQL-DataSources: http://wiki.pentaho.org/display/Reporting/JFR9DataProcessing
Although this is part of the flow-engine documentation, the data-sources are the same on both systems. Why reinvent the wheel?)

Data-Source definitions can either be embedded in the report-definition xml file or can be stored in a separate file (which is referenced by the report-definition).

Examples:

Extended-XML with embedded data-source

<?xml version="1.0" encoding="ISO-8859-1"?>
<report-definition xmlns="http://jfreereport.sourceforge.net/namespaces/reports/legacy/ext" name="Quadrant For Region" query="default">
..
   <report-config>
..
    <data:sql-datasource xmlns:data="http://jfreereport.sourceforge.net/namespaces/datasources/sql">
      <data:config label-mapping="true"/>
      <data:connection>
        <data:driver>org.hsqldb.jdbcDriver</data:driver>
        <data:url>jdbc:hsqldb:./sql/sampledata</data:url>
        <data:properties>
          <data:property name="user">sa</data:property>
          <data:property name="pass"></data:property>
        </data:properties>
      </data:connection>
      <data:query name="actuals-by-region">
      SELECT
           QUADRANT_ACTUALS.REGION,
           QUADRANT_ACTUALS.DEPARTMENT,
           QUADRANT_ACTUALS.POSITIONTITLE,
           QUADRANT_ACTUALS.ACTUAL,
           QUADRANT_ACTUALS.BUDGET,
           QUADRANT_ACTUALS.VARIANCE
      FROM
           QUADRANT_ACTUALS
      WHERE
          REGION = ${REGION}
      ORDER BY
          REGION, DEPARTMENT, POSITIONTITLE
  </data:query>
      <data:query name="default">
      SELECT DISTINCT
           QUADRANT_ACTUALS.REGION
      FROM
           QUADRANT_ACTUALS
      ORDER BY
          REGION
  </data:query>
    </data:sql-datasource>
..
  </report-config>
..
</report-definition>

Extended-XML with external data-source:

<?xml version="1.0" encoding="ISO-8859-1"?>
<report-definition xmlns="http://jfreereport.sourceforge.net/namespaces/reports/legacy/ext" name="Quadrant For Region" query="default">
..
   <report-config>
    <data-factory href="sql-subreport.sqlds"/>
..
  </report-config>
..
</report-definition>

How to approach your reporting case

For your case, I would use a master-details report. A master-detail report uses sub-queries to retrieve additional information from the database based on parameter values given in the master report.

The master-report would simply query the employee-table. The employee-id is then passed as parameter to all detail reports, which query the employees education and children and so on.

For the picture, you could use a Image-URL-Field. This one accepts an URL and tries to load the image from there. The URL most likely comes from your database or you can use a expression to compute a suitable URL based on the data given in the employee-record.

How to get the report-definition

You can use the report-designer for that task. Design the report as usual, and when finished, publish the report into a directory. The publish generates a .xaction (which you can ignore) and a .xml file (which is the report-definition that can be used by our parser). As the report-designer still cant write a decent data-source definition, you have to add one manually afterwards.