diff options
Diffstat (limited to 'src/documentation/content/xdocs/embedding.xml')
-rw-r--r-- | src/documentation/content/xdocs/embedding.xml | 467 |
1 files changed, 240 insertions, 227 deletions
diff --git a/src/documentation/content/xdocs/embedding.xml b/src/documentation/content/xdocs/embedding.xml index a71431e0c..035b37d70 100644 --- a/src/documentation/content/xdocs/embedding.xml +++ b/src/documentation/content/xdocs/embedding.xml @@ -36,231 +36,178 @@ <p>Here is an example use of Driver which outputs PDF: </p> <source><![CDATA[ - import org.apache.fop.apps.Driver; +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> +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> - <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> + <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; - - /*..*/ - - Logger logger = new ConsoleLogger(ConsoleLogger.LEVEL_INFO); - MessageHandler.setScreenLogger(logger); - driver.setLogger(logger);]]></source> +import org.apache.avalon.framework.logger.Logger; +import org.apache.avalon.framework.logger.ConsoleLogger; - <p>To setup the user config file you can do the following - </p> +/*..*/ + +Driver driver = new Driver(); +Logger logger = new ConsoleLogger(ConsoleLogger.LEVEL_INFO); +MessageHandler.setScreenLogger(logger); +driver.setLogger(logger);]]></source> + </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[ - 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> +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> - <p>Once the Driver is set up, the render method - is called. Depending on whether DOM or SAX 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> - </p> - <p>Once the FO Tree is built, the format() and render() methods may be - called in that order. - </p> - <p>Here is an example use of Driver:</p> - <source><![CDATA[ - Driver driver = new Driver(); - driver.setRenderer(Driver.RENDER_PDF); - driver.setInputSource(new FileInputSource(args[0])); - driver.setOutputStream(new FileOutputStream(args[1])); - driver.run();]]></source> - <p>You can also specify an xml and xsl file for the input. - </p> - <p>Here is an example use of Driver with the XSLTInputHandler:</p> - <source><![CDATA[ - Driver driver = new Driver(); - driver.setRenderer(Driver.RENDER_PDF); - InputHandler inputHandler = new XSLTInputHandler(xmlFile, xslFile); - XMLReader parser = inputHandler.getParser(); - driver.setOutputStream(new FileOutputStream(outFile)); - driver.render(parser, inputHandler.getInputSource());]]></source> - <p>Have a look at the classes CommandLineStarter or FopServlet for complete - examples. Also, have a look at the examples at the bottom of this page. - </p> + <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); -<note>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. -The thread means that the Java application will 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</note> +//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>FOP uses Jakarta Avalon's - <fork href="http://jakarta.apache.org/avalon/api/org/apache/avalon/framework/logger/Logger.html">Logger</fork> - interface to do logging. See the <fork href="http://jakarta.apache.org/avalon/">Jakarta Avalon project</fork> for more information.</p> - <p>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:</p> + <p> + FOP 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 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: + </p> <source><![CDATA[ - Hierarchy hierarchy = Hierarchy.getDefaultHierarchy(); - PatternFormatter formatter = new PatternFormatter( - "[%{priority}]: %{message}\n%{throwable}" ); +Hierarchy hierarchy = Hierarchy.getDefaultHierarchy(); +PatternFormatter formatter = new PatternFormatter( + "[%{priority}]: %{message}\n%{throwable}" ); - LogTarget target = null; - target = new StreamTarget(System.out, formatter); +LogTarget target = null; +target = new StreamTarget(System.out, formatter); - hierarchy.setDefaultLogTarget(target); - log = hierarchy.getLoggerFor("fop"); - log.setPriority(Priority.INFO); +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="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="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 reset method is called. -You will need to setup the driver again with a new OutputStream, -IntputStream and renderer. - </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="servlet"> - <title>Using FOP in a Servlet</title> - <p> - Here is a minimal code snippet to demonstrate the basics: - </p> - <source>response.setContentType("application/pdf"); -Driver driver=new Driver( new InputSource("foo.fo"), - response.getOutputStream()); -driver.setRenderer(Driver.RENDER_PDF); -driver.run();</source> - <p> -There are numerous problems with the code snippet above. -Its purpose is only to demonstrate the basic concepts. -See xml-fop/examples/servlet for a working example of FOP used in a servlet. -After building the servlet, drop the fop.war into the webapps directory of Tomcat. -Then access a URL as follows: - </p> - <p>http://localhost:8080/fop/fop?fo=/home/path/to/fofile.fo</p> - <p>http://localhost:8080/fop/fop?xml=/home/path/to/xmlfile.xml&xsl=/home/path/to/xslfile.xsl</p> - <p>The source code for the servlet can be found under xml-fop/examples/servlet/src/FopServlet.java.</p> - <note> - Some versions of Internet Explorer will not automatically show the PDF. -This is well-known to be a limitation of Internet Explorer, and is not a problem with the servlet. -However, Internet Explorer can still be used to download the PDF so that it can be viewed later. Also, appending ".pdf" to the end of the URL may help. - </note> - </section> - <section id="servlet-transform"> - <title>Using FOP in a Servlet with an XSLT Transformation</title> +driver.setLogger(new org.apache.avalon.framework.logger.LogKitLogger(log));]]></source> <p> - If both the source XML and XSL are read from files, use the TraxInputHandler: + 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> - <source>response.setContentType("application/pdf"); -XSLTInputHandler input - =new XSLTInputHandler(new File("foo.xml"), new File("foo.xsl")); -Driver driver=new Driver(); -driver.setOutputStream(response.getOutputStream()); -driver.setRenderer(Driver.RENDER_PDF); -driver.render(input.getParser(), input.getInputSource());</source> <p> - This code snippet has the same problems as the one from the <link href="#servlet">section above</link>. + 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 your source XML is generated on the fly (for example from a database, a web service, or another servlet), create a transformer object explicitly, and use a SAX event stream to feed the transformation result into FOP: + If you want FOP to be totally silent you can also set an org.apache.avalon.framework.logger.NullLogger instance. </p> - <source>response.setContentType("application/pdf"); -Driver driver =new Driver(); -driver.setOutputStream(response.getOutputStream()); -driver.setRenderer(Driver.RENDER_PDF); -Transformer transformer=TransformerFactory.newInstance() - .newTransformer(new StreamSource("foo.xsl")); -transformer.transform(xmlsource, new SAXResult(driver.getContentHandler()));</source> <p> - You don't have to call run() or render() on the driver object. + 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 <code>xmlsource</code> is a placeholder for your actual XML source. -If you have to read the XML from a string, supply a <code>new StreamSource(new StringReader(xmlstring))</code>. -Constructing and reparsing an XML string is generally less desirable than using a SAXSource if you generate your XML. -You can alternatively supply a DOMSource as well. -You may also use dynamically generated XSL if you like. + The input XSL-FO document is always handled internally as SAX (see the + <link href="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> - Because you have an explicit transformer object, you can also use it to explicitly set parameters for the transformation run. + 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"> @@ -268,9 +215,19 @@ You may also use dynamically generated XSL if you like. <p> To access an external configuration: </p> - <source>org.apache.fop.apps.Options options = new Options(new File("userconfig.xml"));</source> + <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. @@ -290,6 +247,82 @@ You may also use dynamically generated XSL if you like. 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. + </li> + <li> + Use an XSLT compiler like XSLTC that comes with Xalan-J. + </li> + </ul> + </section> <section id="multithreading"> <title>Multithreading FOP</title> <p> @@ -299,44 +332,24 @@ 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> + To avoid having your threads blocked, create a Driver object for each thread. </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> + 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> </section> - <section id="servlet-engine"> - <title>Servlet Engines</title> - <p> - When using a servlet engine, there are potential CLASSPATH issues, and potential conflicts with existing XML/XSLT libraries. -Servlet containers also often use their own classloaders for loading webapps, which can cause bugs and security problems. - </p> - <section id="tomcat"> - <title>Tomcat</title> - <p> - Check Tomcat's documentation for detailed instructions about installing FOP and Cocoon. -There are known bugs that must be addressed, particularly for Tomcat 4.0.3. - </p> - </section> - <section id="websphere"> - <title>WebSphere 3.5</title> - <p> - Put a copy of a working parser in some directory where WebSphere can access it. -For example, if /usr/webapps/yourapp/servlets is the CLASSPATH for your servlets, copy the Xerces jar into it (any other directory would also be fine). -Do not add the jar to the servlet CLASSPATH, but add it to the CLASSPATH of the application server which contains your web application. -In the WebSphere administration console, click on the "environment" button in the "general" tab. -In the "variable name" box, enter "CLASSPATH". -In the "value" box, enter the correct path to the parser jar file (/usr/webapps/yourapp/servlets/Xerces.jar in our example here). -Press "OK", then apply the change and restart the application server. - </p> - </section> - </section> <section id="examples"> <title>Examples</title> <p> -The directory "xml-fop/examples/embedding" contains several working examples. +The directory "{fop-fir}/examples/embedding" contains several working examples. In contrast of the examples above the examples here primarily use JAXP for XML access. This may be easier to understand for people familiar with JAXP. </p> |