blob: a1ff1715bf66639bc61309360679f46123e575b3 [file] [log] [blame]
/*
* 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$ */
package org.apache.fop.cli;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.InputStream;
import java.io.OutputStream;
import java.util.Vector;
import javax.xml.parsers.ParserConfigurationException;
import javax.xml.parsers.SAXParserFactory;
import javax.xml.transform.ErrorListener;
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.sax.SAXSource;
import javax.xml.transform.stream.StreamResult;
import javax.xml.transform.stream.StreamSource;
import org.xml.sax.EntityResolver;
import org.xml.sax.InputSource;
import org.xml.sax.SAXException;
import org.xml.sax.XMLReader;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
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.render.awt.viewer.Renderable;
/**
* Class for handling files input from command line
* either with XML and XSLT files (and optionally xsl
* parameters) or FO File input alone.
*/
public class InputHandler implements ErrorListener, Renderable {
/** original source file */
protected File sourcefile;
private File stylesheet; // for XML/XSLT usage
private Vector xsltParams; // for XML/XSLT usage
private EntityResolver entityResolver;
private URIResolver uriResolver;
/** the logger */
protected Log log = LogFactory.getLog(InputHandler.class);
/**
* Constructor for XML->XSLT->FO input
*
* @param xmlfile XML file
* @param xsltfile XSLT file
* @param params Vector of command-line parameters (name, value,
* name, value, ...) for XSL stylesheet, null if none
*/
public InputHandler(File xmlfile, File xsltfile, Vector params) {
sourcefile = xmlfile;
stylesheet = xsltfile;
xsltParams = params;
}
/**
* Constructor for XML->XSLT->FO input
*
* @param xmlfile XML file
* @param xsltfile XSLT file
* @param params Vector of command-line parameters (name, value,
* name, value, ...) for XSL stylesheet, null if none
* @param useCatalogResolver if true, use a catalog resolver
* for XML parsing and XSLT URI resolution
*/
public InputHandler(File xmlfile, File xsltfile, Vector params, boolean useCatalogResolver) {
this(xmlfile, xsltfile, params);
if (useCatalogResolver) {
createCatalogResolver();
}
}
/**
* Constructor for FO input
* @param fofile the file to read the FO document.
*/
public InputHandler(File fofile) {
sourcefile = fofile;
}
/**
* Generate a document, given an initialized Fop object
* @param userAgent the user agent
* @param outputFormat the output format to generate (MIME type, see MimeConstants)
* @param out the output stream to write the generated output to (may be null if not applicable)
* @throws FOPException in case of an error during processing
*/
public void renderTo(FOUserAgent userAgent, String outputFormat, OutputStream out)
throws FOPException {
FopFactory factory = userAgent.getFactory();
Fop fop;
if (out != null) {
fop = factory.newFop(outputFormat, userAgent, out);
} else {
fop = factory.newFop(outputFormat, userAgent);
}
// if base URL was not explicitly set in FOUserAgent, obtain here
if (fop.getUserAgent().getBaseURL() == null && sourcefile != null) {
String baseURL = null;
try {
baseURL = new File(sourcefile.getAbsolutePath()).
getParentFile().toURI().toURL().toExternalForm();
} catch (Exception e) {
baseURL = "";
}
fop.getUserAgent().setBaseURL(baseURL);
}
// Resulting SAX events (the generated FO) must be piped through to FOP
Result res = new SAXResult(fop.getDefaultHandler());
transformTo(res);
}
/** {@inheritDoc} */
public void renderTo(FOUserAgent userAgent, String outputFormat) throws FOPException {
renderTo(userAgent, outputFormat, null);
}
/**
* In contrast to render(Fop) this method only performs the XSLT stage and saves the
* intermediate XSL-FO file to the output file.
* @param out OutputStream to write the transformation result to.
* @throws FOPException in case of an error during processing
*/
public void transformTo(OutputStream out) throws FOPException {
Result res = new StreamResult(out);
transformTo(res);
}
/**
* Creates a Source for the main input file. Processes XInclude if
* available in the XML parser.
*
* @return the Source for the main input file
*/
protected Source createMainSource() {
Source source;
InputStream in;
String uri;
if (this.sourcefile != null) {
try {
in = new java.io.FileInputStream(this.sourcefile);
uri = this.sourcefile.toURI().toASCIIString();
} catch (FileNotFoundException e) {
//handled elsewhere
return new StreamSource(this.sourcefile);
}
} else {
in = System.in;
uri = null;
}
try {
InputSource is = new InputSource(in);
is.setSystemId(uri);
XMLReader xr = getXMLReader();
if (entityResolver != null) {
xr.setEntityResolver(entityResolver);
}
source = new SAXSource(xr, is);
} catch (SAXException e) {
if (this.sourcefile != null) {
source = new StreamSource(this.sourcefile);
} else {
source = new StreamSource(in, uri);
}
} catch (ParserConfigurationException e) {
if (this.sourcefile != null) {
source = new StreamSource(this.sourcefile);
} else {
source = new StreamSource(in, uri);
}
}
return source;
}
/**
* Creates a catalog resolver and uses it for XML parsing and XSLT URI resolution.
* Tries the Apache Commons Resolver, and if unsuccessful,
* tries the same built into Java 6.
*/
private void createCatalogResolver() {
String[] classNames = new String[] {
"org.apache.xml.resolver.tools.CatalogResolver",
"com.sun.org.apache.xml.internal.resolver.tools.CatalogResolver"};
Class resolverClass = null;
for (int i = 0; i < classNames.length && resolverClass == null; ++i) {
try {
resolverClass = Class.forName(classNames[i]);
} catch (ClassNotFoundException e) {
// No worries
}
}
if (resolverClass == null) {
log.error("Could not find catalog resolver in class path");
return;
}
try {
entityResolver = (EntityResolver) resolverClass.newInstance();
uriResolver = (URIResolver) resolverClass.newInstance();
} catch (InstantiationException e) {
log.error("Error creating the catalog resolver: " + e.getMessage());
} catch (IllegalAccessException e) {
log.error("Error creating the catalog resolver: " + e.getMessage());
}
}
/**
* Creates a Source for the selected stylesheet.
*
* @return the Source for the selected stylesheet or null if there's no stylesheet
*/
protected Source createXSLTSource() {
Source xslt = null;
if (this.stylesheet != null) {
if (entityResolver != null) {
try {
InputSource is = new InputSource(this.stylesheet.getPath());
XMLReader xr = getXMLReader();
xr.setEntityResolver(entityResolver);
xslt = new SAXSource(xr, is);
} catch (SAXException e) {
// return StreamSource
} catch (ParserConfigurationException e) {
// return StreamSource
}
}
if (xslt == null) {
xslt = new StreamSource(this.stylesheet);
}
}
return xslt;
}
private XMLReader getXMLReader() throws ParserConfigurationException, SAXException {
SAXParserFactory spf = SAXParserFactory.newInstance();
spf.setFeature("http://xml.org/sax/features/namespaces", true);
spf.setFeature("http://apache.org/xml/features/xinclude", true);
XMLReader xr = spf.newSAXParser().getXMLReader();
return xr;
}
/**
* Transforms the input document to the input format expected by FOP using XSLT.
* @param result the Result object where the result of the XSL transformation is sent to
* @throws FOPException in case of an error during processing
*/
protected void transformTo(Result result) throws FOPException {
try {
// Setup XSLT
TransformerFactory factory = TransformerFactory.newInstance();
Transformer transformer;
Source xsltSource = createXSLTSource();
if (xsltSource == null) { // FO Input
transformer = factory.newTransformer();
} else { // XML/XSLT input
transformer = factory.newTransformer(xsltSource);
// Set the value of parameters, if any, defined for stylesheet
if (xsltParams != null) {
for (int i = 0; i < xsltParams.size(); i += 2) {
transformer.setParameter((String) xsltParams.elementAt(i),
(String) xsltParams.elementAt(i + 1));
}
}
if (uriResolver != null) {
transformer.setURIResolver(uriResolver);
}
}
transformer.setErrorListener(this);
// Create a SAXSource from the input Source file
Source src = createMainSource();
// Start XSLT transformation and FOP processing
transformer.transform(src, result);
} catch (Exception e) {
throw new FOPException(e);
}
}
// --- Implementation of the ErrorListener interface ---
/**
* {@inheritDoc}
*/
public void warning(TransformerException exc) {
log.warn(exc.getLocalizedMessage());
}
/**
* {@inheritDoc}
*/
public void error(TransformerException exc) {
log.error(exc.toString());
}
/**
* {@inheritDoc}
*/
public void fatalError(TransformerException exc)
throws TransformerException {
throw exc;
}
}