ONJava.com -- The Independent Source for Enterprise Java
oreilly.comSafari Books Online.Conferences.


AddThis Social Bookmark Button

Dynamic Creation of Reports with Apache Formatting Objects
Pages: 1, 2, 3, 4

Architecture Patterns

Destructive Design

During development of report generation solutions, various reporting tools and libraries may be selected for use to reduce development time and associated costs. Limiting the impact of changing or adding additional components, and supporting the different configurations that result, can be problematic in this context. Decomposing the system as much as possible into parts that can be removed as easily as they can be added or replaced alleviates some of the problem. Reducing the number of steps to remove or add parts reduces the number of potential errors and facilitates easier reconfiguration. This is the intent of the report-creation component, which defines a static interface whose underlying implementation can be handled by a variety of software product components.

Limited Dependency

Dependency among parts is the primary determinant of system complexity. Complexity exponentially correlates to increased difficulty in system maintenance, evolution, verifiability, and robustness. Too much dependency defeats the benefits achieved by decomposition. Using well-defined interfaces passing a limited set of parameters limits subsystem dependencies.


Encapsulation involves combining data and behavior behind an interface that exposes only abstracted behavior. Implementation of modules with crossdependencies or duplicate responsibilities increases system complexity and hinders evolution. Encapsulation of the reporting support tools' capabilities within the report content subsystem reduces system complexity.


The reporting system acts as a façade, decoupling the underlying report generation mechanisms completely from the client. It encapsulates the other report generation subsystems and defines an explicit interface defining available capabilities.

Design Description

Request Sequence

Figure 4 shows the basic sequence of events that take place when a report is requested. It is a high-level representation using packages defined in the architecture definition.

Click for larger view
Figure 4. Package Level Sequence Definition for Report Request. (You can click on the screen shot to open a full-size view.)

The main responsibilities and interfaces for the packages used in the sequence are as follows:

Reporting System


  1. Handle report requests
  2. Initiate report content creation
  3. Initiate report style application
  4. Initiate report output format rendering
  5. Return report to Requester
  6. Persist report to temporary or permanent storage
  7. Send notification of report completion to Requester


To access the reporting system, the following interfaces are defined:

  • For a synchronous request:

    public OutputStream requestReport(String reportType, String styleSheet, 
       int renderFormat, java.security.Principal principal)
  • For an asynchronous request:

    public void requestReport(String reportType, String styleSheet, 
       int notification, String notificationAddress, int renderFormat, 
       java.security.Principal principal)

Report Creation


  1. Get the report template for the requested report type
  2. Authorize request for report and authorize each section of data content
  3. Create data producers for each section defined in the template
  4. Assemble report data content using data returned by data producers
  5. Using FOP libraries, apply style to the report content
  6. Using FOP libraries, convert report to final output format


  • To assemble the data content of the report:

    mergeData(java.lang.Principal principal, 
       String template, String tempFile)

    The principal defines the user to be authorized. Template defines the report template that is used as the basis of the report. TempFile is the location of the report with data content only, in XML format.

  • To apply a style to the report and convert to requested output format:

    styleAndRender(String tempFile, String styleSheet, 
       int renderFormat, OutputStream output)

    TempFile is the location of the report data content created from the mergeData call. Stylesheet defines the XSL information used to apply the report style. RenderFormat is a constant value used to define the output format. Output is the OuputStream where the final formatted report is streamed.



  • Determine if the requesting Principal has rights to view the sections of data content that are to become part of the report.


  • The interfaces depend on the authorization engine to be integrated with this reporting framework. The design is such that access rights are defined for each named data producer. Access for a principal to use a data producer is determined before creation of the data producer.

Data Producer


  1. Access data sources containing data to be included in a report.
  2. Convert raw data requests to well-formed XML syntax that is used in the report.
  3. Return XML back to report creation subsystem.


  • To start the processing of the data producer that gets and returns the report data content as XML:

    StringBuffer process( )



  1. Maintain the data used in reports.
  2. Provide access to the report data.


  • Access is through JDBC or using third-party reporting tool APIs.

Separating Content, Style, and Output Format

The content of the report, the style applied to a report, and the rendered format are all distinct and separate operations. The same content can potentially have different styles applied to it and the styled report can be converted to a number of different formats (e.g., PDF or PostScript).

The first step in creating a report is to access and merge the dynamic content. Data content for a report is defined using XML and a custom defined set of tags and attributes that are relevant to the specific report type. A report template is used to define the type of content that will populate the report and data producers provide the dynamic content.

The second step in report creation is to apply a style to the report content generated in the first step. One or more stylesheets may be defined for a report. The requester of the reporting system may choose which style to apply. Stylesheets use the XSL:FO recommendations from the W3C. The XSL definitions are applied to the XML data using FOP classes. FOP includes a Driver class that starts the translation process, given an XML and XSL file.

InputHandler inputHandler = new XSLTInputHandler(XMLFile, XSLFile);
XMLReader parser = inputHandler.getParser();

The XSLTInputHandler reads in the data and style information, performs the transformation, and streams the new data to an XMLReader.

The data is then ready to be rendered by the FOP tools by defining the desired output format and the OutputStream to use. Using the Apache Formatting Object Processor makes these operations very simple.

driver.render(parser, inputHandler.getInputSource());

In the implementation that goes along with this article, the XML data file is generated and saved as a file. The file is useful for validating that the data is correct and for applying various styles during development. A production system would most likely stream the XML data content directly to the XSL transformation processing, eliminating the time it takes to write the data to a file.

FOP provides a number of different renderers as part of the distribution. Additional renderers are in the works or can be added to the libraries as explained on the xml.apache.org FOP Web site.

Pages: 1, 2, 3, 4

Next Pagearrow