You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

FopServlet.java 10KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275
  1. /*
  2. * Licensed to the Apache Software Foundation (ASF) under one or more
  3. * contributor license agreements. See the NOTICE file distributed with
  4. * this work for additional information regarding copyright ownership.
  5. * The ASF licenses this file to You under the Apache License, Version 2.0
  6. * (the "License"); you may not use this file except in compliance with
  7. * the License. You may obtain a copy of the License at
  8. *
  9. * http://www.apache.org/licenses/LICENSE-2.0
  10. *
  11. * Unless required by applicable law or agreed to in writing, software
  12. * distributed under the License is distributed on an "AS IS" BASIS,
  13. * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  14. * See the License for the specific language governing permissions and
  15. * limitations under the License.
  16. */
  17. /* $Id$ */
  18. package org.apache.fop.servlet;
  19. import java.io.File;
  20. import java.io.IOException;
  21. import java.io.OutputStream;
  22. import java.io.PrintWriter;
  23. import java.net.URI;
  24. import java.net.URL;
  25. import javax.servlet.ServletException;
  26. import javax.servlet.http.HttpServlet;
  27. import javax.servlet.http.HttpServletRequest;
  28. import javax.servlet.http.HttpServletResponse;
  29. import javax.xml.transform.Result;
  30. import javax.xml.transform.Source;
  31. import javax.xml.transform.Transformer;
  32. import javax.xml.transform.TransformerException;
  33. import javax.xml.transform.TransformerFactory;
  34. import javax.xml.transform.URIResolver;
  35. import javax.xml.transform.sax.SAXResult;
  36. import javax.xml.transform.stream.StreamSource;
  37. import org.apache.commons.io.output.ByteArrayOutputStream;
  38. import org.apache.xmlgraphics.io.Resource;
  39. import org.apache.xmlgraphics.io.ResourceResolver;
  40. import org.apache.fop.apps.FOPException;
  41. import org.apache.fop.apps.FOUserAgent;
  42. import org.apache.fop.apps.Fop;
  43. import org.apache.fop.apps.FopFactory;
  44. import org.apache.fop.apps.FopFactoryBuilder;
  45. import org.apache.fop.apps.MimeConstants;
  46. /**
  47. * Example servlet to generate a PDF from a servlet.
  48. * <br/>
  49. * Servlet param is:
  50. * <ul>
  51. * <li>fo: the path to a XSL-FO file to render
  52. * </ul>
  53. * or
  54. * <ul>
  55. * <li>xml: the path to an XML file to render</li>
  56. * <li>xslt: the path to an XSLT file that can transform the above XML to XSL-FO</li>
  57. * </ul>
  58. * <br/>
  59. * Example URL: http://servername/fop/servlet/FopServlet?fo=readme.fo
  60. * <br/>
  61. * Example URL: http://servername/fop/servlet/FopServlet?xml=data.xml&xslt=format.xsl
  62. * <br/>
  63. * For this to work with Internet Explorer, you might need to append "&ext=.pdf"
  64. * to the URL.
  65. * (todo) Ev. add caching mechanism for Templates objects
  66. */
  67. public class FopServlet extends HttpServlet {
  68. private static final long serialVersionUID = -908918093488215264L;
  69. /** Name of the parameter used for the XSL-FO file */
  70. protected static final String FO_REQUEST_PARAM = "fo";
  71. /** Name of the parameter used for the XML file */
  72. protected static final String XML_REQUEST_PARAM = "xml";
  73. /** Name of the parameter used for the XSLT file */
  74. protected static final String XSLT_REQUEST_PARAM = "xslt";
  75. /** The TransformerFactory used to create Transformer instances */
  76. protected TransformerFactory transFactory = null;
  77. /** The FopFactory used to create Fop instances */
  78. protected FopFactory fopFactory = null;
  79. /** URIResolver for use by this servlet */
  80. protected URIResolver uriResolver;
  81. /**
  82. * {@inheritDoc}
  83. */
  84. public void init() throws ServletException {
  85. this.uriResolver = new ServletContextURIResolver(getServletContext());
  86. this.transFactory = TransformerFactory.newInstance();
  87. this.transFactory.setURIResolver(this.uriResolver);
  88. //Configure FopFactory as desired
  89. // TODO: Double check this behaves properly!!
  90. ResourceResolver resolver = new ResourceResolver() {
  91. public OutputStream getOutputStream(URI uri) throws IOException {
  92. URL url = getServletContext().getResource(uri.toASCIIString());
  93. return url.openConnection().getOutputStream();
  94. }
  95. public Resource getResource(URI uri) throws IOException {
  96. return new Resource(getServletContext().getResourceAsStream(uri.toASCIIString()));
  97. }
  98. };
  99. FopFactoryBuilder builder = new FopFactoryBuilder(new File(".").toURI(), resolver);
  100. configureFopFactory(builder);
  101. fopFactory = builder.build();
  102. }
  103. /**
  104. * This method is called right after the FopFactory is instantiated and can be overridden
  105. * by subclasses to perform additional configuration.
  106. */
  107. protected void configureFopFactory(FopFactoryBuilder builder) {
  108. //Subclass and override this method to perform additional configuration
  109. }
  110. /**
  111. * {@inheritDoc}
  112. */
  113. public void doGet(HttpServletRequest request,
  114. HttpServletResponse response) throws ServletException {
  115. try {
  116. //Get parameters
  117. String foParam = request.getParameter(FO_REQUEST_PARAM);
  118. String xmlParam = request.getParameter(XML_REQUEST_PARAM);
  119. String xsltParam = request.getParameter(XSLT_REQUEST_PARAM);
  120. //Analyze parameters and decide with method to use
  121. if (foParam != null) {
  122. renderFO(foParam, response);
  123. } else if ((xmlParam != null) && (xsltParam != null)) {
  124. renderXML(xmlParam, xsltParam, response);
  125. } else {
  126. response.setContentType("text/html");
  127. PrintWriter out = response.getWriter();
  128. out.println("<html><head><title>Error</title></head>\n"
  129. + "<body><h1>FopServlet Error</h1><h3>No 'fo' "
  130. + "request param given.</body></html>");
  131. }
  132. } catch (Exception ex) {
  133. throw new ServletException(ex);
  134. }
  135. }
  136. /**
  137. * Converts a String parameter to a JAXP Source object.
  138. * @param param a String parameter
  139. * @return Source the generated Source object
  140. */
  141. protected Source convertString2Source(String param) {
  142. Source src;
  143. try {
  144. src = uriResolver.resolve(param, null);
  145. } catch (TransformerException e) {
  146. src = null;
  147. }
  148. if (src == null) {
  149. src = new StreamSource(new File(param));
  150. }
  151. return src;
  152. }
  153. private void sendPDF(byte[] content, HttpServletResponse response) throws IOException {
  154. //Send the result back to the client
  155. response.setContentType("application/pdf");
  156. response.setContentLength(content.length);
  157. response.getOutputStream().write(content);
  158. response.getOutputStream().flush();
  159. }
  160. /**
  161. * Renders an XSL-FO file into a PDF file. The PDF is written to a byte
  162. * array that is returned as the method's result.
  163. * @param fo the XSL-FO file
  164. * @param response HTTP response object
  165. * @throws FOPException If an error occurs during the rendering of the
  166. * XSL-FO
  167. * @throws TransformerException If an error occurs while parsing the input
  168. * file
  169. * @throws IOException In case of an I/O problem
  170. */
  171. protected void renderFO(String fo, HttpServletResponse response)
  172. throws FOPException, TransformerException, IOException {
  173. //Setup source
  174. Source foSrc = convertString2Source(fo);
  175. //Setup the identity transformation
  176. Transformer transformer = this.transFactory.newTransformer();
  177. transformer.setURIResolver(this.uriResolver);
  178. //Start transformation and rendering process
  179. render(foSrc, transformer, response);
  180. }
  181. /**
  182. * Renders an XML file into a PDF file by applying a stylesheet
  183. * that converts the XML to XSL-FO. The PDF is written to a byte array
  184. * that is returned as the method's result.
  185. * @param xml the XML file
  186. * @param xslt the XSLT file
  187. * @param response HTTP response object
  188. * @throws FOPException If an error occurs during the rendering of the
  189. * XSL-FO
  190. * @throws TransformerException If an error occurs during XSL
  191. * transformation
  192. * @throws IOException In case of an I/O problem
  193. */
  194. protected void renderXML(String xml, String xslt, HttpServletResponse response)
  195. throws FOPException, TransformerException, IOException {
  196. //Setup sources
  197. Source xmlSrc = convertString2Source(xml);
  198. Source xsltSrc = convertString2Source(xslt);
  199. //Setup the XSL transformation
  200. Transformer transformer = this.transFactory.newTransformer(xsltSrc);
  201. transformer.setURIResolver(this.uriResolver);
  202. //Start transformation and rendering process
  203. render(xmlSrc, transformer, response);
  204. }
  205. /**
  206. * Renders an input file (XML or XSL-FO) into a PDF file. It uses the JAXP
  207. * transformer given to optionally transform the input document to XSL-FO.
  208. * The transformer may be an identity transformer in which case the input
  209. * must already be XSL-FO. The PDF is written to a byte array that is
  210. * returned as the method's result.
  211. * @param src Input XML or XSL-FO
  212. * @param transformer Transformer to use for optional transformation
  213. * @param response HTTP response object
  214. * @throws FOPException If an error occurs during the rendering of the
  215. * XSL-FO
  216. * @throws TransformerException If an error occurs during XSL
  217. * transformation
  218. * @throws IOException In case of an I/O problem
  219. */
  220. protected void render(Source src, Transformer transformer, HttpServletResponse response)
  221. throws FOPException, TransformerException, IOException {
  222. FOUserAgent foUserAgent = getFOUserAgent();
  223. //Setup output
  224. ByteArrayOutputStream out = new ByteArrayOutputStream();
  225. //Setup FOP
  226. Fop fop = fopFactory.newFop(MimeConstants.MIME_PDF, foUserAgent, out);
  227. //Make sure the XSL transformation's result is piped through to FOP
  228. Result res = new SAXResult(fop.getDefaultHandler());
  229. //Start the transformation and rendering process
  230. transformer.transform(src, res);
  231. //Return the result
  232. sendPDF(out.toByteArray(), response);
  233. }
  234. /** @return a new FOUserAgent for FOP */
  235. protected FOUserAgent getFOUserAgent() {
  236. FOUserAgent userAgent = fopFactory.newFOUserAgent();
  237. //Configure foUserAgent as desired
  238. return userAgent;
  239. }
  240. }