All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.apache.fulcrum.xslt.DefaultXSLTService Maven / Gradle / Ivy

The newest version!
package org.apache.fulcrum.xslt;

/*
 * 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.
 */

import java.io.Reader;
import java.io.StringWriter;
import java.io.Writer;
import java.net.MalformedURLException;
import java.net.URL;
import java.util.Hashtable;
import java.util.Map;
import java.util.Map.Entry;

import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.transform.Result;
import javax.xml.transform.Source;
import javax.xml.transform.Templates;
import javax.xml.transform.Transformer;
import javax.xml.transform.TransformerFactory;
import javax.xml.transform.dom.DOMSource;
import javax.xml.transform.stream.StreamResult;
import javax.xml.transform.stream.StreamSource;

import org.apache.avalon.framework.activity.Initializable;
import org.apache.avalon.framework.configuration.Configurable;
import org.apache.avalon.framework.configuration.Configuration;
import org.apache.avalon.framework.configuration.ConfigurationException;
import org.apache.avalon.framework.context.Context;
import org.apache.avalon.framework.context.ContextException;
import org.apache.avalon.framework.context.Contextualizable;
import org.apache.avalon.framework.logger.AbstractLogEnabled;
import org.apache.avalon.framework.service.ServiceManager;
import org.apache.avalon.framework.service.Serviceable;
import org.w3c.dom.Document;
import org.w3c.dom.Node;

/**
 * Implementation of the Turbine XSLT Service. It transforms xml with a given
 * xsl file. XSL stylesheets are compiled and cached (if the service property is
 * set) to improve speeds.
 *
 * @author Leon Messerschmidt
 * @author Sam Ruby
 * @author Eric Pugh
 * @author Thomas Vandahl
 */
public class DefaultXSLTService extends AbstractLogEnabled implements
        XSLTService, Initializable, Configurable, Contextualizable, Serviceable
{
    /**
     * The application root
     */
    private String applicationRoot;

    /**
     * Property to control the caching of Templates.
     */
    protected boolean caching = false;

    /**
     * Path to style sheets used for transforming well-formed XML documents. The
     * path is relative to the webapp context.
     */
    protected String path;

    /**
     * Cache of compiled Templates.
     */
    protected Hashtable cache = new Hashtable();

    protected final static String STYLESHEET_PATH = "path";

    protected final static String STYLESHEET_CACHING = "cache";

    /**
     * Factory for producing templates and null transformers
     */
    private static TransformerFactory tfactory;

    /**
     * Try to create a valid url object from the style parameter.
     *
     * @param style
     *            the xsl-Style
     * @return a URL object or null if the style sheet could not
     *         be found
     */
    private URL getStyleURL(String style)
    {
        StringBuilder sb = new StringBuilder();

        sb.append(path);

        // we chop off the existing extension
        int colon = style.lastIndexOf(".");

        if (colon > 0)
        {
            sb.append(style.substring(0, colon));
        }
        else
        {
            sb.append(style);
        }

        sb.append(".xslt");

        URL url = null;

        try
        {
            url = new URL(sb.toString());
        }
        catch (MalformedURLException e)
        {
            getLogger().error("Malformed URL: " + sb, e);
        }

        return url;
    }

    /**
     * Compile Templates from an input file.
     *
     * @param source the source URL
     * @return the compiled template
     * @throws Exception the compilation failed
     */
    protected Templates compileTemplates(URL source) throws Exception
    {
        StreamSource xslin = new StreamSource(source.openStream());
        return tfactory.newTemplates(xslin);
    }

    /**
     * Retrieves Templates. If caching is switched on the first attempt is to
     * load Templates from the cache. If caching is switched of or if the
     * Stylesheet is not found in the cache new Templates are compiled from an
     * input file.
     * 

* This method is synchronized on the xsl cache so that a thread does not * attempt to load Templates from the cache while it is still being * compiled. * * @param xslName the name of the XSL file * @return the correspondint template or null if the XSL was not found * @throws Exception getting the template failed */ protected Templates getTemplates(String xslName) throws Exception { synchronized (cache) { URL fn = getStyleURL(xslName); if (fn == null) return null; if (caching && cache.containsKey(fn)) { return (Templates) cache.get(fn); } Templates sr = compileTemplates(fn); if (caching) { cache.put(fn, sr); } return sr; } } /** * Transform the XML file * * @param xslName the name of the XSL file * @param xmlin source xml * @param xmlout resulting xml * @param params A set of parameters that will be forwarded to the XSLT * @throws Exception if the transform fails */ protected void transform(String xslName, Source xmlin, Result xmlout, Map params) throws Exception { try { long startTime = System.currentTimeMillis(); Transformer transformer = getTransformer(xslName); if (params != null) { for ( Entry entry : params.entrySet() ) { transformer.setParameter(String.valueOf(entry.getKey()), entry.getValue()); } } transformer.transform(xmlin, xmlout); if(getLogger().isDebugEnabled()) { long duration = System.currentTimeMillis() - startTime; getLogger().debug("The transforamtion '" + xslName + "' took " + duration + " ms"); } } catch(Exception e) { getLogger().debug("The transformation '" + xslName + "' failed due to : " + e.getMessage()); throw e; } } /** * Uses an xsl file to transform xml input from a reader and writes the * output to a writer. * * @param xslName * The name of the file that contains the xsl stylesheet. * @param in * The reader that passes the xml to be transformed * @param out * The writer for the transformed output * * @throws Exception if the transform fails */ public void transform(String xslName, Reader in, Writer out) throws Exception { Source xmlin = new StreamSource(in); Result xmlout = new StreamResult(out); transform(xslName, xmlin, xmlout, null); } /** * Uses an xsl file to transform xml input from a reader and returns a * string containing the transformed output. * * @param xslName * The name of the file that contains the xsl stylesheet. * @param in * The reader that passes the xml to be transformed * * @throws Exception if the transform fails */ public String transform(String xslName, Reader in) throws Exception { StringWriter sw = new StringWriter(); transform(xslName, in, sw, null); return sw.toString(); } /** * Uses an xsl file to transform xml input from a DOM note and writes the * output to a writer. * * @see org.apache.fulcrum.xslt.XSLTService#transform(java.lang.String, org.w3c.dom.Node, java.io.Writer) * * @param xslName * The name of the file that contains the xsl stylesheet. * @param in * The DOM Node to be transformed * @param out * The writer for the transformed output * * @throws Exception if the transform fails */ public void transform(String xslName, Node in, Writer out) throws Exception { Source xmlin = new DOMSource(in); Result xmlout = new StreamResult(out); transform(xslName, xmlin, xmlout, null); } /** * Uses an xsl file to transform xml input from a DOM note and returns a * string containing the transformed output. * * @param xslName * The name of the file that contains the xsl stylesheet. * @param in * The DOM Node to be transformed * * @throws Exception if the transform fails */ public String transform(String xslName, Node in) throws Exception { StringWriter sw = new StringWriter(); transform(xslName, in, sw); return sw.toString(); } /** * Uses an xsl file to transform xml input from a reader and writes the * output to a writer. * * @param xslName * The name of the file that contains the xsl stylesheet. * @param in * The reader that passes the xml to be transformed * @param out * The writer for the transformed output * @param params * A set of parameters that will be forwarded to the XSLT * * @throws Exception if the transform fails */ public void transform(String xslName, Reader in, Writer out, Map params) throws Exception { Source xmlin = new StreamSource(in); Result xmlout = new StreamResult(out); transform(xslName, xmlin, xmlout, params); } /** * Uses an xsl file to transform xml input from a reader and returns a * string containing the transformed output. * * @param xslName * The name of the file that contains the xsl stylesheet. * @param in * The reader that passes the xml to be transformed * @param params * A set of parameters that will be forwarded to the XSLT * * @throws Exception if the transform fails */ public String transform(String xslName, Reader in, Map params) throws Exception { StringWriter sw = new StringWriter(); transform(xslName, in, sw, params); return sw.toString(); } /** * Uses an xsl file to transform xml input from a DOM note and writes the * output to a writer. * * @param xslName * The name of the file that contains the xsl stylesheet. * @param in * The DOM Node to be transformed * @param out * The writer for the transformed output * @param params * A set of parameters that will be forwarded to the XSLT * * @throws Exception if the transform fails */ public void transform(String xslName, Node in, Writer out, Map params) throws Exception { Source xmlin = new DOMSource(in); Result xmlout = new StreamResult(out); transform(xslName, xmlin, xmlout, params); } /** * Uses an xsl file to transform xml input from a DOM note and returns a * string containing the transformed output. * * @param xslName * The name of the file that contains the xsl stylesheet. * @param in * The DOM Node to be transformed * @param params * A set of parameters that will be forwarded to the XSLT * * @throws Exception if the transform fails */ public String transform(String xslName, Node in, Map params) throws Exception { StringWriter sw = new StringWriter(); transform(xslName, in, sw, params); return sw.toString(); } /** * Uses an xsl file without any input. * * @param xslName The name of the file that contains the xsl stylesheet. * @param params A set of parameters that will be forwarded to the XSLT * @return the transformed output * * @throws Exception if the transform fails */ public String transform(String xslName, Map params) throws Exception { StringWriter sw = new StringWriter(); transform(xslName, sw, params); return sw.toString(); } /** * Uses an xsl file without any xml input (simplified stylesheet) * * @param xslName The name of the file that contains the xsl stylesheet * @param out The writer for the transformed output. * @param params A set of parameters that will be forwarded to the XSLT * @throws Exception the transformation failed */ public void transform(String xslName, Writer out, Map params) throws Exception { DocumentBuilderFactory documentBuilderFactory = DocumentBuilderFactory.newInstance(); DocumentBuilder documentBuilder = documentBuilderFactory.newDocumentBuilder(); Document document = documentBuilder.newDocument(); transform(xslName, document.getDocumentElement(), out, params); } /** * Retrieve a transformer for the given stylesheet name. If no stylesheet is * available for the provided name, an identity transformer will be * returned. This allows clients of this service to perform more complex * transformations (for example, where parameters must be set). When * possible prefer using one of the forms of {@link #transform}. * * @param xslName * Identifies stylesheet to get transformer for * @return A transformer for that stylesheet * @throws Exception retrieving the transformer failed */ public Transformer getTransformer(String xslName) throws Exception { Templates sr = getTemplates(xslName); if (sr == null) { return tfactory.newTransformer(); } else { return sr.newTransformer(); } } // ---------------- Avalon Lifecycle Methods --------------------- /** * Avalon component lifecycle method * * This method processes the repository path, to make it relative to the web * application root, if neccessary. It supports URL-style repositories. */ public void configure(Configuration conf) throws ConfigurationException { StringBuilder sb = new StringBuilder(conf.getAttribute(STYLESHEET_PATH, "/")); // is URL? if (!sb.toString().matches("[a-zA-Z]{3,}://.*")) { // No if (sb.charAt(0) != '/') { sb.insert(0, '/'); } sb.insert(0, applicationRoot); sb.insert(0, "file:"); } if (sb.charAt(sb.length() - 1) != '/') { sb.append('/'); } path = sb.toString(); caching = conf.getAttributeAsBoolean(STYLESHEET_CACHING, false); } /** * Initializes the service. */ public void initialize() throws Exception { tfactory = TransformerFactory.newInstance(); } /* (non-Javadoc) * @see org.apache.avalon.framework.context.Contextualizable#contextualize(org.apache.avalon.framework.context.Context) */ public void contextualize(Context context) throws ContextException { this.applicationRoot = context.get("urn:avalon:home").toString(); } /** * Avalon component lifecycle method */ public void service(ServiceManager manager) { XSLTServiceFacade.setService(this); } }





© 2015 - 2025 Weber Informatics LLC | Privacy Policy