123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521 |
- <?xml version="1.0" standalone="no"?>
- <!--
- Licensed to the Apache Software Foundation (ASF) under one or more
- contributor license agreements. See the NOTICE file distributed with
- this work for additional information regarding copyright ownership.
- The ASF licenses this file to You under the Apache License, Version 2.0
- (the "License"); you may not use this file except in compliance with
- the License. You may obtain a copy of the License at
-
- http://www.apache.org/licenses/LICENSE-2.0
-
- Unless required by applicable law or agreed to in writing, software
- distributed under the License is distributed on an "AS IS" BASIS,
- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- See the License for the specific language governing permissions and
- limitations under the License.
- -->
- <!-- $Id$ -->
- <!DOCTYPE document PUBLIC "-//APACHE//DTD Documentation V1.1//EN"
- "http://cvs.apache.org/viewcvs.cgi/*checkout*/xml-forrest/src/core/context/resources/schema/dtd/document-v12.dtd">
-
-
- <!-- Embedding FOP -->
- <document>
- <header>
- <title>FOP: Embedding</title>
- <subtitle>How to Embed FOP in a Java application</subtitle>
- <version>$Revision$</version>
- </header>
-
- <body>
- <section id="overview">
- <title>Overview</title>
- <p>Review <link href="running.html">Running FOP</link> for important information that applies to embedded applications as well as command-line use, such as options and performance.
- </p>
- <p>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).
- </p>
- </section>
- <section id="basics">
- <title>Basics</title>
- <p>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.
- </p>
- <p>Here is an example use of Driver which outputs PDF:
- </p>
- <source><![CDATA[
- import org.apache.fop.apps.Driver;
-
- /*..*/
-
- Driver driver = new Driver(new InputSource(args[0]),
- new FileOutputStream(args[1]));
- driver.setRenderer(Driver.RENDER_PDF);
- driver.run();]]></source>
- <p>
- 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.
- </p>
- <section id="basic-logging">
- <title>Logging</title>
- <p>
- 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
- <jump href="#logging">below</jump> for more information.
- </p>
- <p>
- Call <code>setLogger(Logger)</code> always immediately after
- instantiating the Driver object. See here:
- </p>
- <source><![CDATA[
- import org.apache.avalon.framework.logger.Logger;
- import org.apache.avalon.framework.logger.ConsoleLogger;
-
- /*..*/
-
- Driver driver = new Driver();
- Logger logger = new ConsoleLogger(ConsoleLogger.LEVEL_INFO);
- MessageHandler.setScreenLogger(logger);
- driver.setLogger(logger);]]></source>
- </section>
-
- <section id="basic-logging-new-version">
- <title>Logging (Upcoming FOP 1.0 Version only)</title>
- <p>
- Logging is handled automatically via Jakarta Commons-Logging, which uses
- JDK logging by default. No special driver configuration is needed.
- For specialized configuration of Commons-Logging (e.g. to use a
- different logger or to change logging levels), please see the
- <fork href="http://jakarta.apache.org/commons/logging/">Jakarta Commons-Logging</fork>
- site.
- </p>
- </section>
-
- <section id="render">
- <title>Processing XSL-FO</title>
- <p>
- Once the Driver is set up, one of the <code>render()</code> methods
- is called. Depending on whether DOM or an InputSource is being used, the
- invocation of the method is either <code>render(Document)</code> or
- <code>render(Parser, InputSource)</code> respectively.
- </p>
- <p>
- <strong>Another possibility may be used to build the FO Tree: You can
- call <code>getContentHandler()</code> and fire the SAX events yourself.
- </strong>
- You don't have to call <code>run()</code> or <code>render()</code> on the
- Driver object if you use <code>getContentHandler()</code>.
- </p>
- <p>Here is an example use of Driver:</p>
- <source><![CDATA[
- Driver driver = new Driver();
- //Setup logging here: driver.setLogger(...
- driver.setRenderer(Driver.RENDER_PDF);
- driver.setInputSource(new FileInputSource(args[0]));
- driver.setOutputStream(new FileOutputStream(args[1]));
- driver.run();]]></source>
- </section>
-
- <section id="render-with-xslt">
- <title>Processing XSL-FO generated from XML+XSLT</title>
- <p>
- 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:
- </p>
- <source><![CDATA[
- Driver driver = new Driver();
- //Setup logging here: driver.setLogger(...
- driver.setRenderer(Driver.RENDER_PDF);
-
- //Setup the OutputStream for FOP
- driver.setOutputStream(new java.io.FileOutputStream(outFile));
-
- //Make sure the XSL transformation's result is piped through to FOP
- Result res = new SAXResult(driver.getContentHandler());
-
- //Setup XML input
- Source src = new StreamSource(xmlFile);
-
- //Setup Transformer
- Source xsltSrc = new StreamSource(xslFile);
- TransformerFactory transformerFactory = TransformerFactory.newInstance();
- Transformer transformer = transformerFactory.newTransformer(xsltSrc);
-
- //Start the transformation and rendering process
- transformer.transform(src, res);]]></source>
- <note>There's no need to call <code>run()</code> or <code>render()</code>.</note>
- <p>
- 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.
- </p>
- <p>
- For fully working examples of the above and hints to some interesting
- possibilities, see the <link href="#examples">examples section</link> below.
- </p>
- </section>
- </section>
- <section id="logging">
- <title>Controlling logging</title>
- <p>
- Current FOP 0.20.x production uses the
- <fork href="http://avalon.apache.org/framework/api/org/apache/avalon/framework/logger/package-summary.html">Logger package</fork>
- from Apache Avalon Framework to do logging. See the
- <fork href="http://avalon.apache.org/framework/">Apache Avalon Framework</fork>
- for more information.
- </p>
- <p>
- Per default FOP uses the SimpleLog 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:
- </p>
- <source><![CDATA[
- Hierarchy hierarchy = Hierarchy.getDefaultHierarchy();
- PatternFormatter formatter = new PatternFormatter(
- "[%{priority}]: %{message}\n%{throwable}" );
-
- LogTarget target = null;
- target = new StreamTarget(System.out, formatter);
-
- hierarchy.setDefaultLogTarget(target);
- log = hierarchy.getLoggerFor("fop");
- log.setPriority(Priority.INFO);
-
- driver.setLogger(new org.apache.avalon.framework.logger.LogKitLogger(log));]]></source>
- <p>
- The LogKitLogger class implements the Logger interface so all logging calls are being redirected to LogKit.
- More information on Jakarta LogKit can be found <fork href="http://jakarta.apache.org/avalon/logkit/index.html">here</fork>.
- </p>
- <p>
- Similar implementations exist for Log4J (org.apache.avalon.framework.logger.Log4JLogger) and
- JDK 1.4 logging (org.apache.avalon.framework.logger.Jdk14Logger).
- </p>
- <p>
- If you want FOP to be totally silent you can also set an org.apache.avalon.framework.logger.NullLogger instance.
- </p>
- <p>
- 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.
- </p>
- </section>
- <section id="input">
- <title>Input Sources</title>
- <p>
- The input XSL-FO document is always handled internally as SAX (see the
- <link href="../dev/design/parsing.html">Parsing Design Document</link> 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:
- </p>
- <ul>
- <li><strong>SAX Events through SAX Handler</strong>: <code>FOTreeBuilder</code> is the SAX Handler which is obtained through <code>getContentHandler</code> on <code>Driver</code>.</li>
- <li><strong>DOM (which is converted into SAX Events)</strong>: The conversion of a DOM tree is done via the <code>render(Document)</code> method on <code>Driver</code>.</li>
- <li><strong>Data Source (which is parsed and converted into SAX Events)</strong>: The <code>Driver</code> can take an <code>InputSource</code> as input.
- This can use a <code>Stream</code>, <code>String</code> etc.</li>
- <li><strong>XML+XSLT Transformation</strong> (which is transformed using an XSLT Processor and the result is fired as SAX Events: <code>XSLTInputHandler</code> is used as an <code>InputSource</code> in the render(<code>XMLReader</code>, <code>InputSource</code>) method on <code>Driver</code>.</li>
- </ul>
- <p>
- 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
- <fork href="http://xml.apache.org/xalan-j/usagepatterns.html">Xalan Basic Usage Patterns</fork>.
- </p>
- <p>
- See the <link href="#examples">Examples</link> for some variations on input.
- </p>
- </section>
- <section id="config-external">
- <title>Using a Configuration File</title>
- <p>
- To access an external configuration:
- </p>
- <source><![CDATA[
- import org.apache.fop.apps.Options;
-
- /*..*/
-
- userConfigFile = new File(userConfig);
- options = new Options(userConfigFile);]]></source>
- <note>
- This is all you need to do, it sets up a static configuration class.
- </note>
- <p>
- No further reference to the <code>options</code> variable is necessary.
- The "options = " is actually not even necessary.
- </p>
- <p>
- See <link href="#multithreading">Multithreading FOP</link> for issues related to changing configuration in a multithreaded environment.
- </p>
- </section>
- <section id="config-internal">
- <title>Setting the Configuration Programmatically</title>
- <p>
- If you wish to set configuration options from within your embedded application, use the <code>Configuration.put</code> method. Here is an example that sets the "baseDir" configuration in a Unix environment:
- </p>
- <source>org.apache.fop.configuration.Configuration.put("baseDir","/my/base/dir");</source>
- <p>
- Here is another that sets baseDir in a Windows environment:
- </p>
- <source>org.apache.fop.configuration.Configuration.put("baseDir","C:\my\base\dir");</source>
- <p>
- See <link href="#multithreading">Multithreading FOP</link> for issues related to changing configuration in a multithreaded environment.
- </p>
- </section>
- <section id="hints">
- <title>Hints</title>
- <section id="object-reuse">
- <title>Object reuse</title>
- <p>
- If FOP is going to be used multiple times within your application
- it may be useful to reuse certain objects to save time.
- </p>
- <p>
- 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 <code>reset()</code> method is called.
- You will need to setup the driver again with a new OutputStream,
- IntputStream and renderer.
- </p>
- </section>
- <section id="awt">
- <title>AWT issues</title>
- <p>
- If your XSL-FO files contain SVG then Batik will be used. When Batik is
- initialised it uses certain classes in <code>java.awt</code> 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.
- </p>
- <p>
- The thread means that the Java application may not automatically quit
- when finished, you will need to call <code>System.exit()</code>. These
- issues should be fixed in the upcoming JDK 1.4.
- </p>
- <p>
- If you run into trouble running FOP on a head-less server, please see the
- <link href="graphics.html#batik">notes on Batik</link>.
- </p>
- </section>
- <section id="render-info">
- <title>Getting information on the rendering process</title>
- <p>
- To get the number of pages that were rendered by FOP you can call
- <code>Driver.getResults()</code>. 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.
- </p>
- </section>
- </section>
- <section id="performance">
- <title>Improving performance</title>
- <p>
- There are several options to consider:
- </p>
- <ul>
- <li>
- Whenever possible, try to use SAX to couple the individual components involved
- (parser, XSL transformer, SQL datasource etc.).
- </li>
- <li>
- Depending on the target OutputStream (in case of an FileOutputStream, but not
- for a ByteArrayOutputStream, for example) it may improve performance considerably
- if you buffer the OutputStream using a BufferedOutputStream:
- <code>driver.setOutputStream(new java.io.BufferedOutputStream(out));</code>
- <br/>
- Make sure you properly close the OutputStream when FOP is finished.
- </li>
- <li>
- Cache the stylesheet. If you use the same stylesheet multiple times
- you can setup a JAXP <code>Templates</code> object and reuse it each time you do
- the XSL transformation. (More information can be found
- <fork href="http://www.javaworld.com/javaworld/jw-05-2003/jw-0502-xsl.html">here</fork>.)
- </li>
- <li>
- Use an XSLT compiler like <fork href="http://xml.apache.org/xalan-j/xsltc_usage.html">XSLTC</fork>
- that comes with Xalan-J.
- </li>
- </ul>
- </section>
- <section id="multithreading">
- <title>Multithreading FOP</title>
- <p>
- 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:
- </p>
- <ul>
- <li>
- To avoid having your threads blocked, create a Driver object for each thread.
- </li>
- <li>
- If possible, do not change the configuration data while there is a Driver object rendering.
- Setup the configuration only once, preferably in the <code>init()</code> method of the servlet.
- </li>
- <li>
- If you must change the configuration data more often, or if you have multiple
- servlets within the same webapp using FOP, consider implementing a singleton
- class to encapsulate the configuration settings and to run FOP in synchronized methods.
- </li>
- </ul>
- <p>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.</p>
- </section>
- <section id="examples">
- <title>Examples</title>
- <p>
- 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.
- </p>
- <section id="ExampleFO2PDF">
- <title>ExampleFO2PDF.java</title>
- <p>This example
- <fork href="http://svn.apache.org/viewcvs.cgi/xmlgraphics/fop/tags/fop-0_20_5/examples/embedding/java/embedding/ExampleFO2PDF.java?view=markup">
- (current 0.20.5)</fork>
- <fork href="http://svn.apache.org/viewcvs.cgi/xmlgraphics/fop/trunk/examples/embedding/java/embedding/ExampleFO2PDF.java?view=markup">
- (future 1.0dev)</fork>
- demonstrates the basic usage pattern to transform an XSL-FO
- file to PDF using FOP.
- </p>
- <figure src="images/EmbeddingExampleFO2PDF.png" alt="Example XSL-FO to PDF"/>
- </section>
- <section id="ExampleXML2FO">
- <title>ExampleXML2FO.java</title>
- <p>This example
- <fork href="http://svn.apache.org/viewcvs.cgi/xmlgraphics/fop/tags/fop-0_20_5/examples/embedding/java/embedding/ExampleXML2FO.java?view=markup">
- (current 0.20.5)</fork>
- <fork href="http://svn.apache.org/viewcvs.cgi/xmlgraphics/fop/trunk/examples/embedding/java/embedding/ExampleXML2FO.java?view=markup">
- (future 1.0dev)</fork>
- has nothing to do with FOP. It is there to show you how an XML
- file can be converted to XSL-FO using XSLT. The JAXP API is used to do the
- transformation. Make sure you've got a JAXP-compliant XSLT processor in your
- classpath (ex. <fork href="http://xml.apache.org/xalan-j">Xalan</fork>).
- </p>
- <figure src="images/EmbeddingExampleXML2FO.png" alt="Example XML to XSL-FO"/>
- </section>
- <section id="ExampleXML2PDF">
- <title>ExampleXML2PDF.java</title>
- <p>This example
- <fork href="http://svn.apache.org/viewcvs.cgi/xmlgraphics/fop/tags/fop-0_20_5/examples/embedding/java/embedding/ExampleXML2PDF.java?view=markup">
- (current 0.20.5)</fork>
- <fork href="http://svn.apache.org/viewcvs.cgi/xmlgraphics/fop/trunk/examples/embedding/java/embedding/ExampleXML2PDF.java?view=markup">
- (future 1.0dev)</fork>
- demonstrates how you can convert an arbitrary XML file to PDF
- using XSLT and XSL-FO/FOP. It is a combination of the first two examples
- above. The example uses JAXP to transform the XML file to XSL-FO and FOP to
- transform the XSL-FO to PDF.
- </p>
- <figure src="images/EmbeddingExampleXML2PDF.png" alt="Example XML to PDF (via XSL-FO)"/>
- <p>
- 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.
- </p>
- </section>
- <section id="ExampleObj2XML">
- <title>ExampleObj2XML.java</title>
- <p>This example
- <fork href="http://svn.apache.org/viewcvs.cgi/xmlgraphics/fop/tags/fop-0_20_5/examples/embedding/java/embedding/ExampleObj2XML.java?view=markup">
- (current 0.20.5)</fork>
- <fork href="http://svn.apache.org/viewcvs.cgi/xmlgraphics/fop/trunk/examples/embedding/java/embedding/ExampleObj2XML.java?view=markup">
- (future 1.0dev)</fork>
- is a preparatory example for the next one. It's an example that
- shows how an arbitrary Java object can be converted to XML. It's an often
- needed task to do this. Often people create a DOM tree from a Java object and
- use that. This is pretty straightforward. The example here however shows how
- to do this using SAX which will probably be faster and not even more
- complicated once you know how this works.
- </p>
- <figure src="images/EmbeddingExampleObj2XML.png" alt="Example Java object to XML"/>
- <p>
- 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).
- </p>
- <p>
- 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.
- </p>
- <p>
- 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.
- <fork href="http://java.sun.com/xml/jaxp/dist/1.1/docs/tutorial/xslt/3_generate.html">An older JAXP tutorial</fork>).
- </p>
- </section>
- <section id="ExampleObj2PDF">
- <title>ExampleObj2PDF.java</title>
- <p>This example
- <fork href="http://svn.apache.org/viewcvs.cgi/xmlgraphics/fop/tags/fop-0_20_5/examples/embedding/java/embedding/ExampleObj2PDF.java?view=markup">
- (current 0.20.5)</fork>
- <fork href="http://svn.apache.org/viewcvs.cgi/xmlgraphics/fop/trunk/examples/embedding/java/embedding/ExampleObj2PDF.java?view=markup">
- (future 1.0dev)</fork>
- combines the previous and the third to demonstrate
- how you can transform a Java object to a PDF directly in one smooth run
- by generating SAX events from the Java object that get fed to an XSL
- transformation. The result of the transformation is then converted to PDF
- using FOP as before.
- </p>
- <figure src="images/EmbeddingExampleObj2PDF.png" alt="Example Java object to PDF (via XML and XSL-FO)"/>
- </section>
- <section id="ExampleDOM2PDF">
- <title>ExampleDOM2PDF.java</title>
- <p>This example
- <fork href="http://svn.apache.org/viewcvs.cgi/xmlgraphics/fop/tags/fop-0_20_5/examples/embedding/java/embedding/ExampleDOM2PDF.java?view=markup">
- (current 0.20.5)</fork>
- <fork href="http://svn.apache.org/viewcvs.cgi/xmlgraphics/fop/trunk/examples/embedding/java/embedding/ExampleDOM2PDF.java?view=markup">
- (future 1.0dev)</fork>
- has FOP use a DOMSource instead of a StreamSource in order to
- use a DOM tree as input for an XSL transformation.
- </p>
- </section>
- <section id="ExampleSVG2PDF">
- <title>ExampleSVG2PDF.java (PDF Transcoder example)</title>
- <p>This example
- <fork href="http://svn.apache.org/viewcvs.cgi/xmlgraphics/fop/trunk/examples/embedding/java/embedding/ExampleSVG2PDF.java?view=markup">
- (applies to 0.20.5 and future 1.0dev)</fork>
- shows use of the PDF Transcoder, a sub-application within FOP.
- It is used to generate a PDF document from an SVG file.
- </p>
- </section>
- <section id="example-notes">
- <title>Final notes</title>
- <p>
- These examples should give you an idea of what's possible. It should be easy
- to adjust these examples to your needs. Also, if you have other examples that you
- think should be added here, please let us know via either the FOP-USER or FOP-DEV
- mailing lists. Finally, for more help please send your questions to the FOP-USER
- mailing list.
- </p>
- </section>
- </section>
- </body>
- </document>
|