/*
 * Licensed to the Apache Software Foundation (ASF) under one or more
 * contributor license agreements.  See the NOTICE file distributed with
 * this work for additional information regarding copyright ownership.
 * The ASF licenses this file to You under the Apache License, Version 2.0
 * (the "License"); you may not use this file except in compliance with
 * the License.  You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

/* $Id: FopServlet.java 1805173 2017-08-16 10:50:04Z ssteiner $ */

package org.apache.fop.servlet;

import java.io.File;
import java.io.IOException;
import java.io.OutputStream;
import java.io.PrintWriter;
import java.net.URI;
import java.net.URL;

import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.xml.transform.Result;
import javax.xml.transform.Source;
import javax.xml.transform.Transformer;
import javax.xml.transform.TransformerException;
import javax.xml.transform.TransformerFactory;
import javax.xml.transform.URIResolver;
import javax.xml.transform.sax.SAXResult;
import javax.xml.transform.stream.StreamSource;

import org.apache.commons.io.output.ByteArrayOutputStream;

import org.apache.xmlgraphics.io.Resource;
import org.apache.xmlgraphics.io.ResourceResolver;

import org.apache.fop.apps.FOPException;
import org.apache.fop.apps.FOUserAgent;
import org.apache.fop.apps.Fop;
import org.apache.fop.apps.FopFactory;
import org.apache.fop.apps.FopFactoryBuilder;
import org.apache.fop.apps.MimeConstants;

Example servlet to generate a PDF from a servlet.
Servlet param is:
  • fo: the path to a XSL-FO file to render
or
  • xml: the path to an XML file to render
  • xslt: the path to an XSLT file that can transform the above XML to XSL-FO

Example URL: http://servername/fop/servlet/FopServlet?fo=readme.fo
Example URL: http://servername/fop/servlet/FopServlet?xml=data.xml
For this to work with Internet Explorer, you might need to append "ext=.pdf" to the URL. (todo) Ev. add caching mechanism for Templates objects
/** * Example servlet to generate a PDF from a servlet. * <br> * Servlet param is: * <ul> * <li>fo: the path to a XSL-FO file to render * </ul> * or * <ul> * <li>xml: the path to an XML file to render</li> * <li>xslt: the path to an XSLT file that can transform the above XML to XSL-FO</li> * </ul> * <br> * Example URL: http://servername/fop/servlet/FopServlet?fo=readme.fo * <br> * Example URL: http://servername/fop/servlet/FopServlet?xml=data.xml * <br> * For this to work with Internet Explorer, you might need to append "ext=.pdf" * to the URL. * (todo) Ev. add caching mechanism for Templates objects */
public class FopServlet extends HttpServlet { private static final long serialVersionUID = -908918093488215264L;
Name of the parameter used for the XSL-FO file
/** Name of the parameter used for the XSL-FO file */
protected static final String FO_REQUEST_PARAM = "fo";
Name of the parameter used for the XML file
/** Name of the parameter used for the XML file */
protected static final String XML_REQUEST_PARAM = "xml";
Name of the parameter used for the XSLT file
/** Name of the parameter used for the XSLT file */
protected static final String XSLT_REQUEST_PARAM = "xslt";
The TransformerFactory used to create Transformer instances
/** The TransformerFactory used to create Transformer instances */
protected TransformerFactory transFactory;
The FopFactory used to create Fop instances
/** The FopFactory used to create Fop instances */
protected FopFactory fopFactory;
URIResolver for use by this servlet
/** URIResolver for use by this servlet */
protected transient URIResolver uriResolver;
{@inheritDoc}
/** * {@inheritDoc} */
public void init() throws ServletException { this.uriResolver = new ServletContextURIResolver(getServletContext()); this.transFactory = TransformerFactory.newInstance(); transFactory.setAttribute("http://javax.xml.XMLConstants/property/accessExternalDTD", ""); transFactory.setAttribute("http://javax.xml.XMLConstants/property/accessExternalStylesheet", ""); this.transFactory.setURIResolver(this.uriResolver); //Configure FopFactory as desired // TODO: Double check this behaves properly!! ResourceResolver resolver = new ResourceResolver() { public OutputStream getOutputStream(URI uri) throws IOException { URL url = getServletContext().getResource(uri.toASCIIString()); return url.openConnection().getOutputStream(); } public Resource getResource(URI uri) throws IOException { return new Resource(getServletContext().getResourceAsStream(uri.toASCIIString())); } }; FopFactoryBuilder builder = new FopFactoryBuilder(new File(".").toURI(), resolver); configureFopFactory(builder); fopFactory = builder.build(); }
This method is called right after the FopFactory is instantiated and can be overridden by subclasses to perform additional configuration.
/** * This method is called right after the FopFactory is instantiated and can be overridden * by subclasses to perform additional configuration. */
protected void configureFopFactory(FopFactoryBuilder builder) { //Subclass and override this method to perform additional configuration }
{@inheritDoc}
/** * {@inheritDoc} */
public void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException { try { //Get parameters String foParam = request.getParameter(FO_REQUEST_PARAM); String xmlParam = request.getParameter(XML_REQUEST_PARAM); String xsltParam = request.getParameter(XSLT_REQUEST_PARAM); //Analyze parameters and decide with method to use if (foParam != null) { renderFO(foParam, response); } else if ((xmlParam != null) && (xsltParam != null)) { renderXML(xmlParam, xsltParam, response); } else { response.setContentType("text/html"); PrintWriter out = response.getWriter(); out.println("<html><head><title>Error</title></head>\n" + "<body><h1>FopServlet Error</h1><h3>No 'fo' " + "request param given.</body></html>"); } } catch (Exception ex) { throw new ServletException(ex); } }
Converts a String parameter to a JAXP Source object.
Params:
  • param – a String parameter
Returns:Source the generated Source object
/** * Converts a String parameter to a JAXP Source object. * @param param a String parameter * @return Source the generated Source object */
protected Source convertString2Source(String param) { Source src; try { src = uriResolver.resolve(param, null); } catch (TransformerException e) { src = null; } if (src == null) { src = new StreamSource(new File(param)); } return src; } private void sendPDF(byte[] content, HttpServletResponse response) throws IOException { //Send the result back to the client response.setContentType("application/pdf"); response.setContentLength(content.length); response.getOutputStream().write(content); response.getOutputStream().flush(); }
Renders an XSL-FO file into a PDF file. The PDF is written to a byte array that is returned as the method's result.
Params:
  • fo – the XSL-FO file
  • response – HTTP response object
Throws:
/** * Renders an XSL-FO file into a PDF file. The PDF is written to a byte * array that is returned as the method's result. * @param fo the XSL-FO file * @param response HTTP response object * @throws FOPException If an error occurs during the rendering of the * XSL-FO * @throws TransformerException If an error occurs while parsing the input * file * @throws IOException In case of an I/O problem */
protected void renderFO(String fo, HttpServletResponse response) throws FOPException, TransformerException, IOException { //Setup source Source foSrc = convertString2Source(fo); //Setup the identity transformation Transformer transformer = this.transFactory.newTransformer(); transformer.setURIResolver(this.uriResolver); //Start transformation and rendering process render(foSrc, transformer, response); }
Renders an XML file into a PDF file by applying a stylesheet that converts the XML to XSL-FO. The PDF is written to a byte array that is returned as the method's result.
Params:
  • xml – the XML file
  • xslt – the XSLT file
  • response – HTTP response object
Throws:
/** * Renders an XML file into a PDF file by applying a stylesheet * that converts the XML to XSL-FO. The PDF is written to a byte array * that is returned as the method's result. * @param xml the XML file * @param xslt the XSLT file * @param response HTTP response object * @throws FOPException If an error occurs during the rendering of the * XSL-FO * @throws TransformerException If an error occurs during XSL * transformation * @throws IOException In case of an I/O problem */
protected void renderXML(String xml, String xslt, HttpServletResponse response) throws FOPException, TransformerException, IOException { //Setup sources Source xmlSrc = convertString2Source(xml); Source xsltSrc = convertString2Source(xslt); //Setup the XSL transformation Transformer transformer = this.transFactory.newTransformer(xsltSrc); transformer.setURIResolver(this.uriResolver); //Start transformation and rendering process render(xmlSrc, transformer, response); }
Renders an input file (XML or XSL-FO) into a PDF file. It uses the JAXP transformer given to optionally transform the input document to XSL-FO. The transformer may be an identity transformer in which case the input must already be XSL-FO. The PDF is written to a byte array that is returned as the method's result.
Params:
  • src – Input XML or XSL-FO
  • transformer – Transformer to use for optional transformation
  • response – HTTP response object
Throws:
/** * Renders an input file (XML or XSL-FO) into a PDF file. It uses the JAXP * transformer given to optionally transform the input document to XSL-FO. * The transformer may be an identity transformer in which case the input * must already be XSL-FO. The PDF is written to a byte array that is * returned as the method's result. * @param src Input XML or XSL-FO * @param transformer Transformer to use for optional transformation * @param response HTTP response object * @throws FOPException If an error occurs during the rendering of the * XSL-FO * @throws TransformerException If an error occurs during XSL * transformation * @throws IOException In case of an I/O problem */
protected void render(Source src, Transformer transformer, HttpServletResponse response) throws FOPException, TransformerException, IOException { FOUserAgent foUserAgent = getFOUserAgent(); //Setup output ByteArrayOutputStream out = new ByteArrayOutputStream(); //Setup FOP Fop fop = fopFactory.newFop(MimeConstants.MIME_PDF, foUserAgent, out); //Make sure the XSL transformation's result is piped through to FOP Result res = new SAXResult(fop.getDefaultHandler()); //Start the transformation and rendering process transformer.transform(src, res); //Return the result sendPDF(out.toByteArray(), response); }
Returns:a new FOUserAgent for FOP
/** @return a new FOUserAgent for FOP */
protected FOUserAgent getFOUserAgent() { FOUserAgent userAgent = fopFactory.newFOUserAgent(); //Configure foUserAgent as desired return userAgent; } }