]> source.dussan.org Git - xmlgraphics-fop.git/commitdiff
Split Embedding page to Embedding and Servlets.
authorJeremias Maerki <jeremias@apache.org>
Wed, 21 May 2003 16:48:19 +0000 (16:48 +0000)
committerJeremias Maerki <jeremias@apache.org>
Wed, 21 May 2003 16:48:19 +0000 (16:48 +0000)
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

src/documentation/content/xdocs/book.xml
src/documentation/content/xdocs/embedding.xml
src/documentation/content/xdocs/faq.xml
src/documentation/content/xdocs/servlets.xml [new file with mode: 0644]

index afd087834c412de325944fe217b608d1bdd3a25c..37fd320681df36215218c493150d34101a29104b 100644 (file)
@@ -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>
 
index a71431e0c94ac244cdea1567181c61655b2aded7..035b37d70bafe68737c6f61163c6459e96df7f09 100644 (file)
   <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&amp;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>
index 5559dda05611ff643fa4435d362b9152e1cffc92..7664a763dd4b9b8d92aa9523e9f0bd0ecedfd07e 100644 (file)
@@ -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&amp;par2=b&amp;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 (file)
index 0000000..c3bbdf9
--- /dev/null
@@ -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&amp;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&amp;par2=b&amp;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$ -->