diff options
author | Jeremias Maerki <jeremias@apache.org> | 2003-05-21 16:48:19 +0000 |
---|---|---|
committer | Jeremias Maerki <jeremias@apache.org> | 2003-05-21 16:48:19 +0000 |
commit | 6ce33e28f4ba7097e38cafcf408cb9a84657d0c5 (patch) | |
tree | f9a56a039c04f01a7024f9abdbb48da0081f39a5 /src/documentation/content | |
parent | 86b519bd7479f42e138a0b6b93ee2bcf688b644e (diff) | |
download | xmlgraphics-fop-6ce33e28f4ba7097e38cafcf408cb9a84657d0c5.tar.gz xmlgraphics-fop-6ce33e28f4ba7097e38cafcf408cb9a84657d0c5.zip |
Split Embedding page to Embedding and Servlets.
Added some more content gathered from fop-user.
Replaced InputHandler usage with JAXP patterns.
git-svn-id: https://svn.apache.org/repos/asf/xmlgraphics/fop/trunk@196444 13f79535-47bb-0310-9956-ffa450edef68
Diffstat (limited to 'src/documentation/content')
-rw-r--r-- | src/documentation/content/xdocs/book.xml | 1 | ||||
-rw-r--r-- | src/documentation/content/xdocs/embedding.xml | 467 | ||||
-rw-r--r-- | src/documentation/content/xdocs/faq.xml | 26 | ||||
-rw-r--r-- | src/documentation/content/xdocs/servlets.xml | 240 |
4 files changed, 483 insertions, 251 deletions
diff --git a/src/documentation/content/xdocs/book.xml b/src/documentation/content/xdocs/book.xml index afd087834..37fd32068 100644 --- a/src/documentation/content/xdocs/book.xml +++ b/src/documentation/content/xdocs/book.xml @@ -19,6 +19,7 @@ <menu-item label="Configure" href="configuration.html"/> <menu-item label="Run" href="running.html"/> <menu-item label="Embed" href="embedding.html"/> + <menu-item label="Servlets" href="servlets.html"/> <menu-item label="Ant task" href="anttask.html"/> </menu> 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> diff --git a/src/documentation/content/xdocs/faq.xml b/src/documentation/content/xdocs/faq.xml index 5559dda05..7664a763d 100644 --- a/src/documentation/content/xdocs/faq.xml +++ b/src/documentation/content/xdocs/faq.xml @@ -758,31 +758,9 @@ Can I control this?</question> <answer> <p> This is a problem of Internet Explorer requesting the content several - times. Some suggestions: + times. Please see the <link href="servlets.html#ie">notes on Internet Explorer</link> + for more information. </p> - <ul> - <li> - Use an URL ending in <code>.pdf</code>, like - <code>http://myserver/servlet/stuff.pdf</code>. Yes, the servlet can - be configured to handle this. If the URL has to contain parameters, - try to have both the base URL as well as the last parameter end in - <code>.pdf</code>, if necessary append a dummy parameter, like - <code>http://myserver/servlet/stuff.pdf?par1=a&par2=b&d=.pdf</code>. The - effect may depend on IEx version. - </li> - <li> - Give IEx the opportunity to cache. In particular, ensure the server - does not set any headers causing IEx not to cache the content. This - may be a real problem if the document is sent over HTTPS. Consult - your server manual. - </li> - <li> - Cache in the server. Including a parameter in the URL which has a - timestamp as the value may help you to decide whether a request is - repeated. IEx is reported to retrieve a document up to three times, - but never more often. - </li> - </ul> </answer> </faq> <faq id="iex-pdf-print-from-browser"> diff --git a/src/documentation/content/xdocs/servlets.xml b/src/documentation/content/xdocs/servlets.xml new file mode 100644 index 000000000..c3bbdf9d5 --- /dev/null +++ b/src/documentation/content/xdocs/servlets.xml @@ -0,0 +1,240 @@ +<?xml version="1.0" standalone="no"?> +<!DOCTYPE document PUBLIC "-//APACHE//DTD Documentation V1.1//EN" + "http://cvs.apache.org/viewcvs.cgi/*checkout*/xml-forrest/src/resources/schema/dtd/document-v11.dtd"> +<document> + <header> + <title>Servlets</title> + <subtitle>How to use FOP in a Servlet</subtitle> + </header> + <body> + <section id="overview"> + <title>Overview</title> + <p> + This page discusses topic all around using FOP in a servlet environment. + </p> + </section> + <section id="example-servlets"> + <title>Example Servlets in the FOP distribution</title> + <p> + In the directory {fop-dir}/examples/servlet, you'll find a working example + of a FOP-enabled servlet. + </p> + <p> + You can build the servlet easily by using the supplied Ant script. After building + the servlet, drop fop.war into the webapps directory of Tomcat. Then, you can use + URLs like the following to generate PDF files: + </p> + <ul> + <li>http://localhost:8080/fop/fop?fo=/home/path/to/fofile.fo</li> + <li>http://localhost:8080/fop/fop?xml=/home/path/to/xmlfile.xml&xsl=/home/path/to/xslfile.xsl</li> + </ul> + <p/> + <p>The source code for the servlet can be found under xml-fop/examples/servlet/src/FopServlet.java.</p> + </section> + <section id="servlet"> + <title>Create your own Servlet</title> + <note> + This section assumes you are familiar with <link href="embedding.html">embedding FOP</link>. + </note> + <section id="minimal-servlet"> + <title>A minimal Servlet</title> + <p> + Here is a minimal code snippet to demonstrate the basics: + </p> + <source>public void doGet(HttpServletRequest request, + HttpServletResponse response) throws ServletException { + try { + response.setContentType("application/pdf"); + Driver driver = new Driver(new InputSource("foo.fo"), + response.getOutputStream()); + driver.setRenderer(Driver.RENDER_PDF); + driver.run(); + } catch (Exception ex) { + throw new ServletException(ex); + } +}</source> + <note> + There are numerous problems with the code snippet above. + Its purpose is only to demonstrate the basic concepts. + See below for details. + </note> + </section> + <section id="xslt"> + <title>Adding XSL tranformation (XSLT)</title> + <p> + A common requirement is the ability to do an XSL transformation to transform some + XML source to XSL-FO. It is recommended that JAXP be used for this task. The following + snippet shows the basic code for doing this: + </p> + <source> +protected Logger log; +protected TransformerFactory transformerFactory; + +public void init() throws ServletException { + this.log = new ConsoleLogger(ConsoleLogger.LEVEL_WARN); + this.transformerFactory = TransformerFactory.newInstance(); +} + +[..] + + //Setup FOP + Driver driver = new Driver(); + driver.setLogger(this.log); + driver.setRenderer(Driver.RENDER_PDF); + + //Setup a buffer to obtain the content length + ByteArrayOutputStream out = new ByteArrayOutputStream(); + driver.setOutputStream(out); + + //Setup Transformer + Source xsltSrc = new StreamSource(new File("foo-xml2fo.xsl")); + Transformer transformer = this.transformerFactory.newTransformer(xsltSrc); + + //Make sure the XSL transformation's result is piped through to FOP + Result res = new SAXResult(driver.getContentHandler()); + + //Setup input + Source src = new StreamSource(new File("foo.xml")); + + //Start the transformation and rendering process + transformer.transform(src, res); + + //Prepare response + response.setContentType("application/pdf"); + response.setContentLength(out.size()); + + //Send content to Browser + response.getOutputStream().write(out.toByteArray()); + response.getOutputStream().flush();</source> + <note> + Buffering the generated PDF in a ByteArrayOutputStream is done to avoid potential + problems with the Acrobat Reader Plug-in. + </note> + <p> + The <code>Source</code> instance used above is simply an example. + 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. + </p> + <p> + Because you have an explicit <code>Transformer</code> object, you can also use it to + explicitly set parameters for the transformation run. + </p> + </section> + <section id="cfg"> + <title>Custom configuration</title> + <p> + If you need to supply a special configuration do this in the <code>init()</code> + method so it will only be done once and to avoid multithreading problems. + </p> + <source>public void init() throws ServletException { + [..] + new Options(new File("userconfig.xml")); + //or + Configuration.put("baseDir", "/my/base/dir"); +}</source> + </section> + <section id="performance"> + <title>Improving performance</title> + <p> + There are several options to consider: + </p> + <ul> + <li> + Instead of java.io.ByteArrayOutputStream consider using the ByteArrayOutputStream + implementation from the Jakarta Commons IO project which allocates less memory. + </li> + <li> + In certain cases it can help to write the generated PDF to a temporary file so + you can quickly reuse the file. This is especially useful, if Internet Explorer + calls the servlet multiple times with the same request or if you often generate + equal PDFs. + </li> + </ul> + <p> + Of course, the + <link href="embedding.html#performance">performance hints from the Embedding page</link> + apply here, too. + </p> + </section> + </section> + <section id="ie"> + <title>Notes on Microsoft Internet Explorer</title> + <p> + Some versions of Internet Explorer will not automatically show the PDF or call the servlet multiple times. + These are well-known limitations of Internet Explorer and are not a problem of the servlet. + However, Internet Explorer can still be used to download the PDF so that it can be viewed later. + Here are some suggestions in this context: + </p> + <ul> + <li> + Use an URL ending in <code>.pdf</code>, like + <code>http://myserver/servlet/stuff.pdf</code>. Yes, the servlet can + be configured to handle this. If the URL has to contain parameters, + try to have <strong>both</strong> the base URL as well as the last parameter end in + <code>.pdf</code>, if necessary append a dummy parameter, like + <code>http://myserver/servlet/stuff.pdf?par1=a&par2=b&d=.pdf</code>. The + effect may depend on IEx version. + </li> + <li> + Give IEx the opportunity to cache. In particular, ensure the server + does not set any headers causing IEx not to cache the content. This + may be a real problem if the document is sent over HTTPS. Consult + your server manual. + </li> + <li> + Setting the <code>Expires</code> header entry may help: + <code>response.setDateHeader("Expires", System.currentTimeMillis() + cacheExpiringDuration * 1000);</code> + </li> + <li> + Cache in the server. Including a parameter in the URL which has a + timestamp as the value may help you to decide whether a request is + repeated. IEx is reported to retrieve a document up to three times, + but never more often. + </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="complex-usecases"> + <title>Handling complex use cases</title> + <p> + Sometimes the requirements for a servlet get quite sophisticated: SQL data sources, + multiple XSL transformations, merging of several datasources etc. In such a case + consider using <fork href="http://cocoon.apache.org">Apache Cocoon</fork> instead + of a custom servlet to accomplish your goal. + </p> + </section> + </body> +</document> +<!-- Last Line of $RCSFile$ --> |