This page describes the design of Apache FOP's API.

Requirements

API requirements are document elsewhere and referenced from this page.

Principles

  • Hard requirements are met
  • Nothing stands in the way to implement wishlist items
  • Static variables should not be used. Static initialization code should only be used to initialize constants.
  • Full backwards compatibility will be preserved for the next beta release but some methods will be deprecated. For the release after the next the deprecated methods will be removed.

Current Status

The Fop class is a one-use class which provides access to the receiving SAX DefaultHandler and the FormattingResults. Arguments to the constructor are the MIME type for the desired output format and an instance of FOUserAgent.

Main problem

Currently, a lot of initialization code is repeated for each rendering run. Furthermore, reusable objects are instantiated in every rendering run. This means that there is room for optimization. Another symptom is the fact the the image cache is bound to a static variable.

The other problem is that we finally need to finalize the API before the first production release. The current API does not meet all the ApiRequirements.

The idea

Separate an environment/factory class from the FOUserAgent that holds references to all information (cfg, caches) that should be reused over multiple rendering runs and is responsible for instantiating classes to handle individual rendering runs.

Design

D1

A new class FopFactory is created. It holds references to configuration items that usually don't change between rendering runs and to cached items that can be reused by multiple rendering runs.

D2

FopFactory has protected constructors and a public static newInstance() just like the JAXP TransformerFactory which might, in the future, enable replacing the factory class if desired. Primarily however, this is done to improve similarity to JAXP so people feel at home with the construct. People are free to construct a singleton instance of the FopFactory if they desire so.

D3

FOUserAgent receives a constructor that has as its sole parameter an instance of FopFactory. (for use by FopFactory. User should instantiate FOUserAgent through FopFactory.)

D4

FOUserAgent's default constructor automatically instantiates a new FopFactory class. (deprecated, for backwards temporary backwards compatibility)

D5

The FOUserAgent can return the FopFactory instance. (needed internally by FOP)

D6

FopFactory receives a newFOUserAgent() method that creates a new FOUserAgent instance with defaults set from the XML configuration if available.

D7

FopFactory receives the following methods to create Fop instances: newFop(String outputFormat), newFop(String outputFormat, FOUserAgent userAgent) and newFop(FOUserAgent). The last method is an addition for the case where a custom FOEventHandler or Renderer is set on the FOUserAgent and the specification of an outputFormat will be misleading as this value may not be used at all. It will be an error to omit the outputFormat and to forget setting an overriding FOEventHandler/Renderer.

D8

The Fop constructors will be deprecated. In a future release, Fop.java can be changed to an interface. (Optional. See here)

D9

Fop instances shall not be reused for multiple rendering runs.

D10

FOUserAgent instances can be reused for multiple rendering runs if the future facilities for rendering run feedback are not used. Reusing FOUserAgent instances will be discouraged, however.

D11

For temporary backwards-compatibility, FOUserAgent will be rewritten to retrieve the values formerly held in FOUserAgent from FopFactory. The methods involved will be deprecated.

D12

The XML configuration will primarily contain settings for FopFactory but also provide defaults for the FOUserAgent.

D13

The splitting of settings between FopFactory and FOUserAgent is listed below in addendum A.

D14

Items held by and moved to FopFactory in addition to D11 above are listed in addendum B.

D15

The FOUserAgent should not contain any renderer-specific values (like the PDF encryption parameters). Instead the existing renderer options Map (see getRendererOptions()) should be used, i.e. setPDFEncryptionParams() will be deprecated.

Addendum A

Remaining in FOUserAgent

  • RendererOverride
  • FOEventHandlerOverride
  • Metadata such as:
    • Producer
    • Creator
    • CreationDate
    • Author
    • Title
    • Keywords
  • BaseURL
  • URIResolver
  • PDFEncryptionParams
  • OutputFile
  • TargetResolution

Moved from FOUserAgent to FopFactory

  • AdditionalElementMappings
  • StrictValidation
  • BreakIndentInheritanceOnReferenceAreaBoundary
  • LayoutManagerMakerOverride
  • XML configuration
  • Font Base URL
  • SourceResolution
  • Default Page Width/Height
  • RendererFactory
  • XMLHandlerFactory

Addendum B

  • ElementMappings moved from FOTreeBuilder
  • Image cache from static variable in ImageFactory

Example of API Usage after the Changes

FopFactory fopFactory = FopFactory.newInstance();
fopFactory.setUserConfig(new File("C:/FOP/fop.xconf"));

FOUserAgent userAgent = fopFactory.newFOUserAgent();
userAgent.setTitle("My document");

// Setup output
OutputStream out = new java.io.FileOutputStream(pdffile);
out = new java.io.BufferedOutputStream(out);
try {

    // Construct fop with desired output format
    Fop fop = fopFactory.newFop(MimeConstants.MIME_PDF, userAgent, out);

    // Setup XSLT
    TransformerFactory factory = TransformerFactory.newInstance();
    Transformer transformer = factory.newTransformer(new StreamSource(xsltfile));
    
    // Set the value of a <param> in the stylesheet
    transformer.setParameter("versionParam", "2.0");

    // Setup input for XSLT transformation
    Source src = new StreamSource(xmlfile);

    // Resulting SAX events (the generated FO) must be piped through to FOP
    Result res = new SAXResult(fop.getDefaultHandler());

    // Start XSLT transformation and FOP processing
    transformer.transform(src, res);

    FormattingResults results = fop.getResults();
    System.out.println("Generated " + results.getPageCount() + " pages.");
} finally {
    out.close();
}

Open Items

  • The feedback mechanism described in HR8 (see ApiRequirements) is not specified, yet. This will be done separately. The feedback mechanism will be located in FOUserAgent.
  • As part of adding support for PDF/A-1, support for XMP Metadata will be added. This will be located in FOUserAgent.
  • No labels