Review Running FOP for important information that applies to embedded applications as well as command-line use, such as options and performance.
To embed FOP in your application, instantiate org.apache.fop.apps.Driver. Once this class is instantiated, methods are called to set the Renderer to use and the OutputStream to use to output the results of the rendering (where applicable). In the case of the Renderer and ElementMapping(s), the Driver may be supplied either with the object itself, or the name of the class, in which case Driver will instantiate the class itself. The advantage of the latter is it enables runtime determination of Renderer and ElementMapping(s).
The simplest way to use Driver is to instantiate it with the InputSource and OutputStream, then set the renderer desired and call the run method.
Here is an example use of Driver which outputs PDF:
In the example above, args[0] contains the path to an XSL-FO file, while args[1] contains a path for the target PDF file.
You also need to set up logging. Global logging for all FOP
processes is managed by MessageHandler. Per-instance logging
is handled by Driver. You want to set both using an implementation
of org.apache.avalon.framework.logger.Logger. See
Call setLogger(Logger)
always immediately after
instantiating the Driver object. See here:
Once the Driver is set up, one of the render()
methods
is called. Depending on whether DOM or an InputSource is being used, the
invocation of the method is either render(Document)
or
render(Parser, InputSource)
respectively.
Another possibility may be used to build the FO Tree: You can
call getContentHandler()
and fire the SAX events yourself.
You don't have to call run()
or render()
on the
Driver object if you use getContentHandler()
.
Here is an example use of Driver:
If you want to process XSL-FO generated from XML using XSLT we recommend using standard JAXP to do the XSLT part and piping the generated SAX events directly through to FOP. Here's how this would look like:
run()
or render()
.This may look complicated at first, but it's really just the combination of an XSL transformation and a FOP run. It's also easy to comment out the FOP part for debugging purposes, for example when you're tracking down a bug in your stylesheet. You can easily write the XSL-FO output from the XSL transformation to a file to check if that part generates the expected output.
For fully working examples of the above and hints to some interesting possibilities, see the examples section below.
FOP uses the
Per default FOP uses the ConsoleLogger which logs to System.out. If you want to do logging using a logging framework (such as LogKit, Log4J or JDK 1.4 Logging) you can set a different Logger implementation on the Driver object. Here's an example how you would use LogKit:
The LogKitLogger class implements the Logger interface so all logging calls are being redirected to LogKit.
More information on Jakarta LogKit can be found
Similar implementations exist for Log4J (org.apache.avalon.framework.logger.Log4JLogger) and JDK 1.4 logging (org.apache.avalon.framework.logger.Jdk14Logger).
If you want FOP to be totally silent you can also set an org.apache.avalon.framework.logger.NullLogger instance.
If you want to use yet another logging facility you simply have to create a class that implements org.apache.avalon.framework.logging.Logger and set it on the Driver object. See the existing implementations in Avalon Framework for examples.
The input XSL-FO document is always handled internally as SAX (see the Parsing Design Document for the rationale). However, the input itself can be provided in a variety of ways to FOP, which normalizes the input (if necessary) into SAX events:
FOTreeBuilder
is the SAX Handler which is obtained through getContentHandler
on Driver
.render(Document)
method on Driver
.Driver
can take an InputSource
as input.
This can use a Stream
, String
etc.XSLTInputHandler
is used as an InputSource
in the render(XMLReader
, InputSource
) method on Driver
.
There are a variety of upstream data manipulations possible.
For example, you may have a DOM and an XSL stylesheet; or you may want to
set variables in the stylesheet. Interface documentation and some cookbook
solutions to these situations are provided in
See the Examples for some variations on input.
To access an external configuration:
No further reference to the options
variable is necessary.
The "options = " is actually not even necessary.
See Multithreading FOP for issues related to changing configuration in a multithreaded environment.
If you wish to set configuration options from within your embedded application, use the Configuration.put
method. Here is an example that sets the "baseDir" configuration in a Unix environment:
Here is another that sets baseDir in a Windows environment:
See Multithreading FOP for issues related to changing configuration in a multithreaded environment.
If FOP is going to be used multiple times within your application it may be useful to reuse certain objects to save time.
The renderers and the driver can both be reused. A renderer is reusable
once the previous render has been completed. The driver is reuseable
after the rendering is complete and the reset()
method is called.
You will need to setup the driver again with a new OutputStream,
IntputStream and renderer.
If your XSL-FO files contain SVG then Batik will be used. When Batik is
initialised it uses certain classes in java.awt
that
intialises the java AWT classes. This means that a daemon thread
is created by the JVM and on Unix it will need to connect to a
DISPLAY.
The thread means that the Java application may not automatically quit
when finished, you will need to call System.exit()
. These
issues should be fixed in the upcoming JDK 1.4.
If you run into trouble running FOP on a head-less server, please see the notes on Batik.
To get the number of pages that were rendered by FOP you can call
Driver.getResults()
. This returns a FormattingResults object
where you can lookup the number of pages produced. It also gives you the
page-sequences that were produced along with their id attribute and their
number of pages. This is particularly useful if you render multiple
documents (each enclosed by a page-sequence) and have to know the number of
pages of each document.
There are several options to consider:
driver.setOutputStream(new java.io.BufferedOutputStream(out));
Templates
object and reuse it each time you do
the XSL transformation. (More information can be found
FOP is not currently completely thread safe. Although the relevant methods of the Driver object are synchronized, FOP uses static variables for configuration data and loading images. Here are some tips to mitigate these problems:
init()
method of the servlet.
There is also a known issue with fonts being jumbled between threads when using the AWT renderer (which is used by the -awt and -print output options). In general, you cannot safely run multiple threads through the AWT renderer.
The directory "{fop-dir}/examples/embedding" contains several working examples. In contrast to the examples above the examples here primarily use JAXP for XML access. This may be easier to understand for people familiar with JAXP.
The output (XSL-FO) from the XSL transformation is piped through to FOP using SAX events. This is the most efficient way to do this because the intermediate result doesn't have to be saved somewhere. Often, novice users save the intermediate result in a file, a byte array or a DOM tree. We strongly discourage you to do this if it isn't absolutely necessary. The performance is significantly higher with SAX.
For this example we've created two classes: ProjectTeam and ProjectMember (found in xml-fop/examples/embedding/java/embedding/model). They represent the same data structure found in xml-fop/examples/embedding/xml/xml/projectteam.xml. We want to serialize a project team with several members which exist as Java objects to XML. Therefore we created the two classes: ProjectTeamInputSource and ProjectTeamXMLReader (in the same place as ProjectTeam above).
The XMLReader implementation (regard it as a special kind of XML parser)is responsible for creating SAX events from the Java object. The InputSource class is only used to hold the ProjectTeam object to be used.
Have a look at the source of ExampleObj2XML.java to find out how this is
used. For more detailed information see other resources on JAXP (ex.
These examples should give you an idea of what's possible. It should be easy to adjust these examples to your needs. For examples, you can use a DOMSource instead of a StreamSource to feed a DOM tree as input for an XSL transformation.
If you think you have a decent example that should be here, contact us via one of the mailing lists and we'll see to it that it gets added. Also, if you can't find the solution to your particular problem drop us a message on the fop-user mailing list.