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 FO!UserAgent.
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 FO!UserAgent 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 |
FO!UserAgent receives a constructor that has as its sole parameter an instance of FopFactory. (for use by FopFactory. User should instantiate FOUserAgent through FopFactory.) |
D4 |
FO!UserAgent's default constructor automatically instantiates a new FopFactory class. (deprecated, for backwards temporary backwards compatibility) |
D5 |
The FO!UserAgent can return the FopFactory instance. (needed internally by FOP) |
D6 |
FopFactory receives a newFO!UserAgent() method that creates a new FO!UserAgent 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, FO!UserAgent userAgent) and newFop(FO!UserAgent). The last method is an addition for the case where a custom FO!EventHandler or Renderer is set on the FO!UserAgent 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 FO!EventHandler/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 |
FO!UserAgent instances can be reused for multiple rendering runs if the future facilities for rendering run feedback are not used. Reusing FO!UserAgent instances will be discouraged, however. |
D11 |
For temporary backwards-compatibility, FO!UserAgent will be rewritten to retrieve the values formerly held in FO!UserAgent from FopFactory. The methods involved will be deprecated. |
D12 |
The XML configuration will primarily contain settings for FopFactory but also provide defaults for the FO!UserAgent. |
D13 |
The splitting of settings between FopFactory and FO!UserAgent 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 FO!UserAgent should not contain any renderer-specific values (like the PDF encryption parameters). Instead the existing renderer options Map (see get!RendererOptions()) should be used, i.e. setPDF!EncryptionParams() will be deprecated. |
Addendum A
Remaining in FOUserAgent
RendererOverride
- Metadata such as:
- Producer
- Creator
CreationDate
- Author
- Title
- Keywords
- BaseURL
- URIResolver
PDF!EncryptionParams
OutputFile
TargetResolution
Moved from FOUserAgent to FopFactory
AdditionalElementMappings
StrictValidation
BreakIndentInheritanceOnReferenceAreaBoundary
LayoutManagerMakerOverride
- XML configuration
- Font Base URL
SourceResolution
- Default Page Width/Height
RendererFactory
XML!HandlerFactory
Addendum B
ElementMappings moved from FO!TreeBuilder
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 FO!UserAgent.
As part of adding support for PDF/A-1, support for XMP Metadata will be added. This will be located in FO!UserAgent.