diff options
Diffstat (limited to 'framework/src/ant/apache-ant-1.9.6/src/main/org/apache/tools/ant/taskdefs/optional/TraXLiaison.java')
-rw-r--r-- | framework/src/ant/apache-ant-1.9.6/src/main/org/apache/tools/ant/taskdefs/optional/TraXLiaison.java | 650 |
1 files changed, 650 insertions, 0 deletions
diff --git a/framework/src/ant/apache-ant-1.9.6/src/main/org/apache/tools/ant/taskdefs/optional/TraXLiaison.java b/framework/src/ant/apache-ant-1.9.6/src/main/org/apache/tools/ant/taskdefs/optional/TraXLiaison.java new file mode 100644 index 00000000..8d9a44a6 --- /dev/null +++ b/framework/src/ant/apache-ant-1.9.6/src/main/org/apache/tools/ant/taskdefs/optional/TraXLiaison.java @@ -0,0 +1,650 @@ +/* + * 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. + * + */ + +package org.apache.tools.ant.taskdefs.optional; + +import java.io.BufferedInputStream; +import java.io.BufferedOutputStream; +import java.io.File; +import java.io.FileInputStream; +import java.io.FileOutputStream; +import java.io.IOException; +import java.io.InputStream; +import java.io.OutputStream; +import java.lang.reflect.Field; +import java.net.URL; +import java.util.Enumeration; +import java.util.Hashtable; +import java.util.Vector; + +import javax.xml.parsers.ParserConfigurationException; +import javax.xml.parsers.SAXParserFactory; +import javax.xml.transform.ErrorListener; +import javax.xml.transform.Source; +import javax.xml.transform.SourceLocator; +import javax.xml.transform.Templates; +import javax.xml.transform.Transformer; +import javax.xml.transform.TransformerConfigurationException; +import javax.xml.transform.TransformerException; +import javax.xml.transform.TransformerFactory; +import javax.xml.transform.URIResolver; +import javax.xml.transform.sax.SAXSource; +import javax.xml.transform.stream.StreamResult; +import javax.xml.transform.stream.StreamSource; + +import org.apache.tools.ant.BuildException; +import org.apache.tools.ant.Project; +import org.apache.tools.ant.taskdefs.XSLTLiaison4; +import org.apache.tools.ant.taskdefs.XSLTLogger; +import org.apache.tools.ant.taskdefs.XSLTLoggerAware; +import org.apache.tools.ant.taskdefs.XSLTProcess; +import org.apache.tools.ant.types.Resource; +import org.apache.tools.ant.types.XMLCatalog; +import org.apache.tools.ant.types.resources.FileProvider; +import org.apache.tools.ant.types.resources.FileResource; +import org.apache.tools.ant.types.resources.URLProvider; +import org.apache.tools.ant.util.FileUtils; +import org.apache.tools.ant.util.JAXPUtils; +import org.xml.sax.EntityResolver; +import org.xml.sax.InputSource; +import org.xml.sax.SAXException; +import org.xml.sax.XMLReader; + +/** + * Concrete liaison for XSLT processor implementing TraX. (ie JAXP 1.1) + * + * @since Ant 1.3 + */ +public class TraXLiaison implements XSLTLiaison4, ErrorListener, XSLTLoggerAware { + + /** + * Helper for transforming filenames to URIs. + * + * @since Ant 1.7 + */ + private static final FileUtils FILE_UTILS = FileUtils.getFileUtils(); + + /** + * The current <code>Project</code> + */ + private Project project; + + /** + * the name of the factory implementation class to use + * or null for default JAXP lookup. + */ + private String factoryName = null; + + /** The trax TransformerFactory */ + private TransformerFactory tfactory = null; + + /** stylesheet to use for transformation */ + private Resource stylesheet; + + private XSLTLogger logger; + + /** possible resolver for publicIds */ + private EntityResolver entityResolver; + + /** transformer to use for processing files */ + private Transformer transformer; + + /** The In memory version of the stylesheet */ + private Templates templates; + + /** + * The modification time of the stylesheet from which the templates + * are read + */ + private long templatesModTime; + + /** possible resolver for URIs */ + private URIResolver uriResolver; + + /** transformer output properties */ + private final Vector outputProperties = new Vector(); + + /** stylesheet parameters */ + private final Hashtable<String, Object> params = new Hashtable<String, Object>(); + + /** factory attributes */ + private final Vector attributes = new Vector(); + + /** whether to suppress warnings */ + private boolean suppressWarnings = false; + + /** optional trace configuration. */ + private XSLTProcess.TraceConfiguration traceConfiguration = null; + + /** + * Constructor for TraXLiaison. + * @throws Exception never + */ + public TraXLiaison() throws Exception { + } + + /** + * Set the stylesheet file. + * @param stylesheet a <code>File</code> value + * @throws Exception on error + */ + public void setStylesheet(final File stylesheet) throws Exception { + final FileResource fr = new FileResource(); + fr.setProject(project); + fr.setFile(stylesheet); + setStylesheet(fr); + } + + /** + * Set the stylesheet file. + * @param stylesheet a {@link org.apache.tools.ant.types.Resource} value + * @throws Exception on error + */ + public void setStylesheet(final Resource stylesheet) throws Exception { + if (this.stylesheet != null) { + // resetting the stylesheet - reset transformer + transformer = null; + + // do we need to reset templates as well + if (!this.stylesheet.equals(stylesheet) + || (stylesheet.getLastModified() != templatesModTime)) { + templates = null; + } + } + this.stylesheet = stylesheet; + } + + /** + * Transform an input file. + * @param infile the file to transform + * @param outfile the result file + * @throws Exception on error + */ + public void transform(final File infile, final File outfile) throws Exception { + if (transformer == null) { + createTransformer(); + } + + InputStream fis = null; + OutputStream fos = null; + try { + fis = new BufferedInputStream(new FileInputStream(infile)); + fos = new BufferedOutputStream(new FileOutputStream(outfile)); + final StreamResult res = new StreamResult(fos); + // not sure what could be the need of this... + res.setSystemId(JAXPUtils.getSystemId(outfile)); + final Source src = getSource(fis, infile); + + // set parameters on each transformation, maybe something has changed + //(e.g. value of file name parameter) + setTransformationParameters(); + + transformer.transform(src, res); + } finally { + // make sure to close all handles, otherwise the garbage + // collector will close them...whenever possible and + // Windows may complain about not being able to delete files. + FileUtils.close(fis); + FileUtils.close(fos); + } + } + + /** + * Get the source instance from the stream and id of the file. + * @param is the stream containing the stylesheet data. + * @param infile the file that will be used for the systemid. + * @return the configured source instance matching the stylesheet. + * @throws ParserConfigurationException if a parser cannot be created which + * satisfies the requested configuration. + * @throws SAXException in case of problem detected by the SAX parser. + */ + private Source getSource(final InputStream is, final File infile) + throws ParserConfigurationException, SAXException { + // todo: is this comment still relevant ?? + // FIXME: need to use a SAXSource as the source for the transform + // so we can plug in our own entity resolver + Source src = null; + if (entityResolver != null) { + if (getFactory().getFeature(SAXSource.FEATURE)) { + final SAXParserFactory spFactory = SAXParserFactory.newInstance(); + spFactory.setNamespaceAware(true); + final XMLReader reader = spFactory.newSAXParser().getXMLReader(); + reader.setEntityResolver(entityResolver); + src = new SAXSource(reader, new InputSource(is)); + } else { + throw new IllegalStateException("xcatalog specified, but " + + "parser doesn't support SAX"); + } + } else { + // WARN: Don't use the StreamSource(File) ctor. It won't work with + // xalan prior to 2.2 because of systemid bugs. + src = new StreamSource(is); + } + src.setSystemId(JAXPUtils.getSystemId(infile)); + return src; + } + + private Source getSource(final InputStream is, final Resource resource) + throws ParserConfigurationException, SAXException { + // todo: is this comment still relevant ?? + // FIXME: need to use a SAXSource as the source for the transform + // so we can plug in our own entity resolver + Source src = null; + if (entityResolver != null) { + if (getFactory().getFeature(SAXSource.FEATURE)) { + final SAXParserFactory spFactory = SAXParserFactory.newInstance(); + spFactory.setNamespaceAware(true); + final XMLReader reader = spFactory.newSAXParser().getXMLReader(); + reader.setEntityResolver(entityResolver); + src = new SAXSource(reader, new InputSource(is)); + } else { + throw new IllegalStateException("xcatalog specified, but " + + "parser doesn't support SAX"); + } + } else { + // WARN: Don't use the StreamSource(File) ctor. It won't work with + // xalan prior to 2.2 because of systemid bugs. + src = new StreamSource(is); + } + // The line below is a hack: the system id must an URI, but it is not + // cleat to get the URI of an resource, so just set the name of the + // resource as a system id + src.setSystemId(resourceToURI(resource)); + return src; + } + + private String resourceToURI(final Resource resource) { + final FileProvider fp = resource.as(FileProvider.class); + if (fp != null) { + return FILE_UTILS.toURI(fp.getFile().getAbsolutePath()); + } + final URLProvider up = resource.as(URLProvider.class); + if (up != null) { + final URL u = up.getURL(); + return String.valueOf(u); + } else { + return resource.getName(); + } + } + + /** + * Read in templates from the stylesheet + */ + private void readTemplates() + throws IOException, TransformerConfigurationException, + ParserConfigurationException, SAXException { + + // Use a stream so that you can close it yourself quickly + // and avoid keeping the handle until the object is garbaged. + // (always keep control), otherwise you won't be able to delete + // the file quickly on windows. + InputStream xslStream = null; + try { + xslStream + = new BufferedInputStream(stylesheet.getInputStream()); + templatesModTime = stylesheet.getLastModified(); + final Source src = getSource(xslStream, stylesheet); + templates = getFactory().newTemplates(src); + } finally { + if (xslStream != null) { + xslStream.close(); + } + } + } + + /** + * Create a new transformer based on the liaison settings + * @throws Exception thrown if there is an error during creation. + * @see #setStylesheet(java.io.File) + * @see #addParam(java.lang.String, java.lang.String) + * @see #setOutputProperty(java.lang.String, java.lang.String) + */ + private void createTransformer() throws Exception { + if (templates == null) { + readTemplates(); + } + + transformer = templates.newTransformer(); + + // configure the transformer... + transformer.setErrorListener(this); + if (uriResolver != null) { + transformer.setURIResolver(uriResolver); + } + final int size = outputProperties.size(); + for (int i = 0; i < size; i++) { + final String[] pair = (String[]) outputProperties.elementAt(i); + transformer.setOutputProperty(pair[0], pair[1]); + } + + if (traceConfiguration != null) { + if ("org.apache.xalan.transformer.TransformerImpl" + .equals(transformer.getClass().getName())) { + try { + final Class traceSupport = + Class.forName("org.apache.tools.ant.taskdefs.optional." + + "Xalan2TraceSupport", true, + Thread.currentThread() + .getContextClassLoader()); + final XSLTTraceSupport ts = + (XSLTTraceSupport) traceSupport.newInstance(); + ts.configureTrace(transformer, traceConfiguration); + } catch (final Exception e) { + final String msg = "Failed to enable tracing because of " + e; + if (project != null) { + project.log(msg, Project.MSG_WARN); + } else { + System.err.println(msg); + } + } + } else { + final String msg = "Not enabling trace support for transformer" + + " implementation" + transformer.getClass().getName(); + if (project != null) { + project.log(msg, Project.MSG_WARN); + } else { + System.err.println(msg); + } + } + } + } + + /** + * Sets the parameters for the transformer. + */ + private void setTransformationParameters() { + for (final Enumeration enumeration = params.keys(); + enumeration.hasMoreElements();) { + final String name = (String) enumeration.nextElement(); + final Object value = params.get(name); + transformer.setParameter(name, value); + } + } + + /** + * return the Transformer factory associated to this liaison. + * @return the Transformer factory associated to this liaison. + * @throws BuildException thrown if there is a problem creating + * the factory. + * @see #setFactory(String) + * @since Ant 1.5.2 + */ + private TransformerFactory getFactory() throws BuildException { + if (tfactory != null) { + return tfactory; + } + // not initialized yet, so create the factory + if (factoryName == null) { + tfactory = TransformerFactory.newInstance(); + } else { + try { + Class clazz = null; + try { + clazz = + Class.forName(factoryName, true, + Thread.currentThread() + .getContextClassLoader()); + } catch (final ClassNotFoundException cnfe) { + final String msg = "Failed to load " + factoryName + + " via the configured classpath, will try" + + " Ant's classpath instead."; + if (logger != null) { + logger.log(msg); + } else if (project != null) { + project.log(msg, Project.MSG_WARN); + } else { + System.err.println(msg); + } + } + + if (clazz == null) { + clazz = Class.forName(factoryName); + } + tfactory = (TransformerFactory) clazz.newInstance(); + } catch (final Exception e) { + throw new BuildException(e); + } + } + + try { // #51668, #52382 + final Field _isNotSecureProcessing = tfactory.getClass().getDeclaredField("_isNotSecureProcessing"); + _isNotSecureProcessing.setAccessible(true); + _isNotSecureProcessing.set(tfactory, Boolean.TRUE); + } catch (final Exception x) { + if (project != null) { + project.log(x.toString(), Project.MSG_DEBUG); + } + } + + tfactory.setErrorListener(this); + + // specific attributes for the transformer + final int size = attributes.size(); + for (int i = 0; i < size; i++) { + final Object[] pair = (Object[]) attributes.elementAt(i); + tfactory.setAttribute((String) pair[0], pair[1]); + } + + if (uriResolver != null) { + tfactory.setURIResolver(uriResolver); + } + return tfactory; + } + + + /** + * Set the factory name to use instead of JAXP default lookup. + * @param name the fully qualified class name of the factory to use + * or null for the default JAXP look up mechanism. + * @since Ant 1.6 + */ + public void setFactory(final String name) { + factoryName = name; + } + + /** + * Set a custom attribute for the JAXP factory implementation. + * @param name the attribute name. + * @param value the value of the attribute, usually a boolean + * string or object. + * @since Ant 1.6 + */ + public void setAttribute(final String name, final Object value) { + final Object[] pair = new Object[]{name, value}; + attributes.addElement(pair); + } + + /** + * Set the output property for the current transformer. + * Note that the stylesheet must be set prior to calling + * this method. + * @param name the output property name. + * @param value the output property value. + * @since Ant 1.5 + * @since Ant 1.5 + */ + public void setOutputProperty(final String name, final String value) { + final String[] pair = new String[]{name, value}; + outputProperties.addElement(pair); + } + + /** + * Set the class to resolve entities during the transformation. + * @param aResolver the resolver class. + */ + public void setEntityResolver(final EntityResolver aResolver) { + entityResolver = aResolver; + } + + /** + * Set the class to resolve URIs during the transformation + * @param aResolver a <code>EntityResolver</code> value + */ + public void setURIResolver(final URIResolver aResolver) { + uriResolver = aResolver; + } + + /** + * Add a parameter. + * @param name the name of the parameter + * @param value the value of the parameter + */ + public void addParam(final String name, final String value) { + params.put(name, value); + } + + /** + * Add a parameter. + * @param name the name of the parameter + * @param value the value of the parameter + * @since Ant 1.9.3 + */ + public void addParam(final String name, final Object value) { + params.put(name, value); + } + + /** + * Set a logger. + * @param l a logger. + */ + public void setLogger(final XSLTLogger l) { + logger = l; + } + + /** + * Log an error. + * @param e the exception to log. + */ + public void error(final TransformerException e) { + logError(e, "Error"); + } + + /** + * Log a fatal error. + * @param e the exception to log. + */ + public void fatalError(final TransformerException e) { + logError(e, "Fatal Error"); + throw new BuildException("Fatal error during transformation using " + stylesheet + ": " + e.getMessageAndLocation(), e); + } + + /** + * Log a warning. + * @param e the exception to log. + */ + public void warning(final TransformerException e) { + if (!suppressWarnings) { + logError(e, "Warning"); + } + } + + private void logError(final TransformerException e, final String type) { + if (logger == null) { + return; + } + + final StringBuffer msg = new StringBuffer(); + final SourceLocator locator = e.getLocator(); + if (locator != null) { + final String systemid = locator.getSystemId(); + if (systemid != null) { + String url = systemid; + if (url.startsWith("file:")) { + url = FileUtils.getFileUtils().fromURI(url); + } + msg.append(url); + } else { + msg.append("Unknown file"); + } + final int line = locator.getLineNumber(); + if (line != -1) { + msg.append(":"); + msg.append(line); + final int column = locator.getColumnNumber(); + if (column != -1) { + msg.append(":"); + msg.append(column); + } + } + } + msg.append(": "); + msg.append(type); + msg.append("! "); + msg.append(e.getMessage()); + if (e.getCause() != null) { + msg.append(" Cause: "); + msg.append(e.getCause()); + } + + logger.log(msg.toString()); + } + + // kept for backwards compatibility + /** + * @param file the filename to use for the systemid + * @return the systemid + * @deprecated since 1.5.x. + * Use org.apache.tools.ant.util.JAXPUtils#getSystemId instead. + */ + @Deprecated + protected String getSystemId(final File file) { + return JAXPUtils.getSystemId(file); + } + + + /** + * Specific configuration for the TRaX liaison. + * @param xsltTask the XSLTProcess task instance from which this liaison + * is to be configured. + */ + public void configure(final XSLTProcess xsltTask) { + project = xsltTask.getProject(); + final XSLTProcess.Factory factory = xsltTask.getFactory(); + if (factory != null) { + setFactory(factory.getName()); + + // configure factory attributes + for (final Enumeration attrs = factory.getAttributes(); + attrs.hasMoreElements();) { + final XSLTProcess.Factory.Attribute attr = + (XSLTProcess.Factory.Attribute) attrs.nextElement(); + setAttribute(attr.getName(), attr.getValue()); + } + } + + final XMLCatalog xmlCatalog = xsltTask.getXMLCatalog(); + // use XMLCatalog as the entity resolver and URI resolver + if (xmlCatalog != null) { + setEntityResolver(xmlCatalog); + setURIResolver(xmlCatalog); + } + + + // configure output properties + for (final Enumeration props = xsltTask.getOutputProperties(); + props.hasMoreElements();) { + final XSLTProcess.OutputProperty prop + = (XSLTProcess.OutputProperty) props.nextElement(); + setOutputProperty(prop.getName(), prop.getValue()); + } + + suppressWarnings = xsltTask.getSuppressWarnings(); + + traceConfiguration = xsltTask.getTraceConfiguration(); + } +} |