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 18 /* $Id: InputHandler.java 1805173 2017-08-16 10:50:04Z ssteiner $ */ 19 20 package org.apache.fop.cli; 21 22 import java.io.File; 23 import java.io.FileNotFoundException; 24 import java.io.InputStream; 25 import java.io.OutputStream; 26 import java.lang.reflect.InvocationTargetException; 27 import java.util.Vector; 28 29 import javax.xml.parsers.ParserConfigurationException; 30 import javax.xml.parsers.SAXParserFactory; 31 import javax.xml.transform.ErrorListener; 32 import javax.xml.transform.Result; 33 import javax.xml.transform.Source; 34 import javax.xml.transform.Transformer; 35 import javax.xml.transform.TransformerException; 36 import javax.xml.transform.TransformerFactory; 37 import javax.xml.transform.URIResolver; 38 import javax.xml.transform.sax.SAXResult; 39 import javax.xml.transform.sax.SAXSource; 40 import javax.xml.transform.stream.StreamResult; 41 import javax.xml.transform.stream.StreamSource; 42 43 import org.xml.sax.EntityResolver; 44 import org.xml.sax.InputSource; 45 import org.xml.sax.SAXException; 46 import org.xml.sax.XMLReader; 47 48 import org.apache.commons.logging.Log; 49 import org.apache.commons.logging.LogFactory; 50 51 import org.apache.fop.ResourceEventProducer; 52 import org.apache.fop.apps.FOPException; 53 import org.apache.fop.apps.FOUserAgent; 54 import org.apache.fop.apps.Fop; 55 import org.apache.fop.render.awt.viewer.Renderable; 56 57 /** 58 * Class for handling files input from command line 59 * either with XML and XSLT files (and optionally xsl 60 * parameters) or FO File input alone. 61 */ 62 public class InputHandler implements ErrorListener, Renderable { 63 64 /** original source file */ 65 protected File sourcefile; 66 private File stylesheet; // for XML/XSLT usage 67 private Vector xsltParams; // for XML/XSLT usage 68 private EntityResolver entityResolver; 69 private URIResolver uriResolver; 70 71 /** the logger */ 72 protected Log log = LogFactory.getLog(InputHandler.class); 73 74 /** 75 * Constructor for XML->XSLT->FO input 76 * 77 * @param xmlfile XML file 78 * @param xsltfile XSLT file 79 * @param params Vector of command-line parameters (name, value, 80 * name, value, ...) for XSL stylesheet, null if none 81 */ InputHandler(File xmlfile, File xsltfile, Vector params)82 public InputHandler(File xmlfile, File xsltfile, Vector params) { 83 sourcefile = xmlfile; 84 stylesheet = xsltfile; 85 xsltParams = params; 86 } 87 88 /** 89 * Constructor for FO input 90 * @param fofile the file to read the FO document. 91 */ InputHandler(File fofile)92 public InputHandler(File fofile) { 93 sourcefile = fofile; 94 } 95 96 /** 97 * Generate a document, given an initialized Fop object 98 * @param userAgent the user agent 99 * @param outputFormat the output format to generate (MIME type, see MimeConstants) 100 * @param out the output stream to write the generated output to (may be null if not applicable) 101 * @throws FOPException in case of an error during processing 102 */ renderTo(FOUserAgent userAgent, String outputFormat, OutputStream out)103 public void renderTo(FOUserAgent userAgent, String outputFormat, OutputStream out) 104 throws FOPException { 105 106 Fop fop; 107 if (out != null) { 108 fop = userAgent.newFop(outputFormat, out); 109 } else { 110 fop = userAgent.newFop(outputFormat); 111 } 112 113 // Resulting SAX events (the generated FO) must be piped through to FOP 114 Result res = new SAXResult(fop.getDefaultHandler()); 115 116 transformTo(res); 117 } 118 119 /** {@inheritDoc} */ renderTo(FOUserAgent userAgent, String outputFormat)120 public void renderTo(FOUserAgent userAgent, String outputFormat) throws FOPException { 121 renderTo(userAgent, outputFormat, null); 122 } 123 124 /** 125 * In contrast to render(Fop) this method only performs the XSLT stage and saves the 126 * intermediate XSL-FO file to the output file. 127 * @param out OutputStream to write the transformation result to. 128 * @throws FOPException in case of an error during processing 129 */ transformTo(OutputStream out)130 public void transformTo(OutputStream out) throws FOPException { 131 Result res = new StreamResult(out); 132 transformTo(res); 133 } 134 135 /** 136 * Creates a Source for the main input file. Processes XInclude if 137 * available in the XML parser. 138 * 139 * @return the Source for the main input file 140 */ createMainSource()141 protected Source createMainSource() { 142 Source source; 143 InputStream in; 144 String uri; 145 if (this.sourcefile != null) { 146 try { 147 in = new java.io.FileInputStream(this.sourcefile); 148 uri = this.sourcefile.toURI().toASCIIString(); 149 } catch (FileNotFoundException e) { 150 //handled elsewhere 151 return new StreamSource(this.sourcefile); 152 } 153 } else { 154 in = System.in; 155 uri = null; 156 } 157 try { 158 InputSource is = new InputSource(in); 159 is.setSystemId(uri); 160 XMLReader xr = getXMLReader(); 161 if (entityResolver != null) { 162 xr.setEntityResolver(entityResolver); 163 } 164 source = new SAXSource(xr, is); 165 } catch (SAXException e) { 166 if (this.sourcefile != null) { 167 source = new StreamSource(this.sourcefile); 168 } else { 169 source = new StreamSource(in, uri); 170 } 171 } catch (ParserConfigurationException e) { 172 if (this.sourcefile != null) { 173 source = new StreamSource(this.sourcefile); 174 } else { 175 source = new StreamSource(in, uri); 176 } 177 } 178 return source; 179 } 180 181 /** 182 * Creates a catalog resolver and uses it for XML parsing and XSLT URI resolution. 183 * Tries the Apache Commons Resolver, and if unsuccessful, 184 * tries the same built into Java 6. 185 * @param userAgent the user agent instance 186 */ createCatalogResolver(FOUserAgent userAgent)187 public void createCatalogResolver(FOUserAgent userAgent) { 188 String[] classNames = new String[] { 189 "org.apache.xml.resolver.tools.CatalogResolver", 190 "com.sun.org.apache.xml.internal.resolver.tools.CatalogResolver"}; 191 ResourceEventProducer eventProducer 192 = ResourceEventProducer.Provider.get(userAgent.getEventBroadcaster()); 193 Class resolverClass = null; 194 for (int i = 0; i < classNames.length && resolverClass == null; ++i) { 195 try { 196 resolverClass = Class.forName(classNames[i]); 197 } catch (ClassNotFoundException e) { 198 // No worries 199 } 200 } 201 if (resolverClass == null) { 202 eventProducer.catalogResolverNotFound(this); 203 return; 204 } 205 try { 206 entityResolver = (EntityResolver) resolverClass.getDeclaredConstructor().newInstance(); 207 uriResolver = (URIResolver) resolverClass.getDeclaredConstructor().newInstance(); 208 } catch (InstantiationException e) { 209 log.error("Error creating the catalog resolver: " + e.getMessage()); 210 eventProducer.catalogResolverNotCreated(this, e.getMessage()); 211 } catch (IllegalAccessException e) { 212 log.error("Error creating the catalog resolver: " + e.getMessage()); 213 eventProducer.catalogResolverNotCreated(this, e.getMessage()); 214 } catch (NoSuchMethodException e) { 215 log.error("Error creating the catalog resolver: " + e.getMessage()); 216 eventProducer.catalogResolverNotCreated(this, e.getMessage()); 217 } catch (InvocationTargetException e) { 218 log.error("Error creating the catalog resolver: " + e.getMessage()); 219 eventProducer.catalogResolverNotCreated(this, e.getMessage()); 220 } 221 } 222 223 /** 224 * Creates a Source for the selected stylesheet. 225 * 226 * @return the Source for the selected stylesheet or null if there's no stylesheet 227 */ createXSLTSource()228 protected Source createXSLTSource() { 229 Source xslt = null; 230 if (this.stylesheet != null) { 231 if (entityResolver != null) { 232 try { 233 InputSource is = new InputSource(this.stylesheet.getPath()); 234 XMLReader xr = getXMLReader(); 235 xr.setEntityResolver(entityResolver); 236 xslt = new SAXSource(xr, is); 237 } catch (SAXException e) { 238 // return StreamSource 239 } catch (ParserConfigurationException e) { 240 // return StreamSource 241 } 242 } 243 if (xslt == null) { 244 xslt = new StreamSource(this.stylesheet); 245 } 246 } 247 return xslt; 248 } 249 getXMLReader()250 private XMLReader getXMLReader() throws ParserConfigurationException, SAXException { 251 SAXParserFactory spf = SAXParserFactory.newInstance(); 252 spf.setFeature("http://xml.org/sax/features/namespaces", true); 253 spf.setFeature("http://apache.org/xml/features/xinclude", true); 254 spf.setFeature("http://apache.org/xml/features/disallow-doctype-decl", true); 255 XMLReader xr = spf.newSAXParser().getXMLReader(); 256 return xr; 257 } 258 259 /** 260 * Transforms the input document to the input format expected by FOP using XSLT. 261 * @param result the Result object where the result of the XSL transformation is sent to 262 * @throws FOPException in case of an error during processing 263 */ transformTo(Result result)264 protected void transformTo(Result result) throws FOPException { 265 try { 266 // Setup XSLT 267 TransformerFactory factory = TransformerFactory.newInstance(); 268 Transformer transformer; 269 270 Source xsltSource = createXSLTSource(); 271 if (xsltSource == null) { // FO Input 272 transformer = factory.newTransformer(); 273 } else { // XML/XSLT input 274 transformer = factory.newTransformer(xsltSource); 275 276 // Set the value of parameters, if any, defined for stylesheet 277 if (xsltParams != null) { 278 for (int i = 0; i < xsltParams.size(); i += 2) { 279 transformer.setParameter((String) xsltParams.elementAt(i), 280 (String) xsltParams.elementAt(i + 1)); 281 } 282 } 283 if (uriResolver != null) { 284 transformer.setURIResolver(uriResolver); 285 } 286 } 287 transformer.setErrorListener(this); 288 289 // Create a SAXSource from the input Source file 290 Source src = createMainSource(); 291 292 // Start XSLT transformation and FOP processing 293 transformer.transform(src, result); 294 295 } catch (Exception e) { 296 throw new FOPException(e); 297 } 298 } 299 300 // --- Implementation of the ErrorListener interface --- 301 302 /** 303 * {@inheritDoc} 304 */ warning(TransformerException exc)305 public void warning(TransformerException exc) { 306 log.warn(exc.getLocalizedMessage()); 307 } 308 309 /** 310 * {@inheritDoc} 311 */ error(TransformerException exc)312 public void error(TransformerException exc) { 313 log.error(exc.toString()); 314 } 315 316 /** 317 * {@inheritDoc} 318 */ fatalError(TransformerException exc)319 public void fatalError(TransformerException exc) 320 throws TransformerException { 321 throw exc; 322 } 323 324 } 325