Hope to see you there!
Hope to see you there!
This page discusses topic all around using Apache™ FOP in a servlet environment.
In the directory {fop-dir}/fop-core/src/main/java/org/apache/fop/servlet, you'll find a working example of a FOP-enabled servlet.
The servlet is automatically built when you build Apache FOP using the supplied Ant script. After building the servlet, drop fop.war into the webapps directory of Apache Tomcat (or any other web container). Then, you can use URLs like the following to generate PDF files:
http://localhost:8080/fop/fop?fo=/home/path/to/fofile.fo
http://localhost:8080/fop/fop?xml=/home/path/to/xmlfile.xml&xsl=/home/path/to/xslfile.xsl
The source code for the servlet can be found under {fop-dir}/fop-core/src/main/java/org/apache/fop/servlet/FopServlet.java.
Here is a minimal code snippet to demonstrate the basics:
privateTransformerFactorytFactory=TransformerFactory.newInstance();publicvoiddoGet(HttpServletRequestrequest,HttpServletResponseresponse)throwsServletException{try{response.setContentType("application/pdf");FopFactoryfopFactory=FopFactory.newInstance(newFile(".").toURI());Fopfop=fopFactory.newFop(MimeConstants.MIME_PDF,response.getOutputStream());Transformertransformer=tFactory.newTransformer();Sourcesrc=newStreamSource("foo.fo");Resultres=newSAXResult(fop.getDefaultHandler());transformer.transform(src,res);}catch(Exceptionex){thrownewServletException(ex);}}A common requirement is to transform an XML source to XSL-FO using an XSL transformation. It is recommended to use JAXP for this task. The following snippet shows the basic code:
privateTransformerFactorytFactory=TransformerFactory.newInstance();publicvoidinit()throwsServletException{//Optionally customize the FopFactory and TransformerFactory here}[..]FopFactoryfopFactory=FopFactory.newInstance(newFile(".").toURI());//Setup a buffer to obtain the content lengthByteArrayOutputStreamout=newByteArrayOutputStream();//Setup FOPFopfop=fopFactory.newFop(MimeConstants.MIME_PDF,out);//Setup TransformerSourcexsltSrc=newStreamSource(newFile("foo-xml2fo.xsl"));Transformertransformer=tFactory.newTransformer(xsltSrc);//Make sure the XSL transformation's result is piped through to FOPResultres=newSAXResult(fop.getDefaultHandler());//Setup inputSourcesrc=newStreamSource(newFile("foo.xml"));//Start the transformation and rendering processtransformer.transform(src,res);//Prepare responseresponse.setContentType("application/pdf");response.setContentLength(out.size());//Send content to Browserresponse.getOutputStream().write(out.toByteArray());response.getOutputStream().flush();TheSource instance used above is simply an example. If you have to read the XML from a string, supply anew StreamSource(new StringReader(xmlstring)). 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.
Because you have an explicitTransformer object, you can also use it to explicitely set parameters for the transformation run.
You can easily set up your own FOUserAgent as demonstrated on theEmbedding page.
There are several options to consider:
Instead of java.io.ByteArrayOutputStream consider using the ByteArrayOutputStream implementation from theJakarta Commons IO project which allocates less memory. The full class name is:org.apache.commons.io.output.ByteArrayOutputStream
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.
Of course, theperformance hints from the Embedding page apply here, too.
Often, you will want to use resources (stylesheets, images etc.) which are bundled with your web application. FOP provides a URIResolver implementation that lets you access files via the Servlet's ServletContext. The class is calledorg.apache.fop.servlet.ServletContextURIResolver.
Here's how to set it up in your servlet. Instantiate a new instance in the servlet's init() method:
/** URIResolver for use by this servlet */protectedURIResolveruriResolver;publicvoidinit()throwsServletException{this.uriResolver=newServletContextURIResolver(getServletContext());[..]}The ServletContextURIResolver reacts on URIs beginning with "servlet-context:". If you want to access an image in a subdirectory of your web application, you could, for example, use: "servlet-context:/images/myimage.png". Don't forget the leading slash after the colon!
Further down, you can use the URIResolver for various things:
With the Transformer (JAXP/XSLT) so things like document() functions can resolver "servlet-context:" URIs.
With the FopFactory so every resource FOP loads can be loaded using a "servlet-context:" URI.
You can the ServletContextURIResolver yourself in your servlet code to access stylesheets or XML files bundled with your web application.
Here are some example snippets:
//Setting up the JAXP TransformerFactorythis.transFactory=TransformerFactory.newInstance();this.transFactory.setURIResolver(this.uriResolver);[..]ResourceResolverresolver=newResourceResolver(){publicOutputStreamgetOutputStream(URIuri)throwsIOException{URLurl=getServletContext().getResource(uri.toASCIIString());returnurl.openConnection().getOutputStream();}publicResourcegetResource(URIuri)throwsIOException{returnnewResource(getServletContext().getResourceAsStream(uri.toASCIIString()));}};//Setting up the FOP factoryFopFactoryBuilderbuilder=newFopFactoryBuilder(newFile(".").toURI(),resolver);fopFactory=builder.build();[..]//The stylesheet for the JAXP TransfomerSourcexsltSrc=this.uriResolver.resolve("servlet-context:/xslt/mystylesheet.xsl",null);Transformertransformer=this.transFactory.newTransformer(xsltSrc);transformer.setURIResolver(this.uriResolver);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:
Use an URL ending in.pdf, likehttp://myserver/servlet/stuff.pdf. Yes, the servlet can be configured to handle this. If the URL has to contain parameters, try to haveboth the base URL as well as the last parameter end in.pdf, if necessary append a dummy parameter, likehttp://myserver/servlet/stuff.pdf?par1=a&par2=b&d=.pdf. The effect may depend on IEx version.
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, because most IEx installations will by defaultnot cache any content retrieved over HTTPS. Setting theExpires header entry may help in this case:
response.setDateHeader("Expires",System.currentTimeMillis()+cacheExpiringDuration*1000);Consult your server manual and the relevant RFCs for further details on HTTP headers and caching.
Cache in the server. It may help to include a parameter in the URL which has a timestamp as the value min order to decide whether a request is repeated. IEx is reported to retrieve a document up to three times, but never more often.
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.
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.
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.
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 usingApache Cocoon instead of a custom servlet to accomplish your goal.
Copyright © 2025 The Apache Software Foundation, Licensed undertheApache License, Version 2.0.
Apache, Apache XML Graphics, Apache FOP, Apache Batik, the Apache logo, and theApache XML Graphics logos are trademarks ofThe ApacheSoftware Foundation. All other marks mentioned may be trademarks or registeredtrademarks of their respective owners.