org.fcrepo.utilities.XmlTransformUtility.java Source code

Java tutorial

Introduction

Here is the source code for org.fcrepo.utilities.XmlTransformUtility.java

Source

/* The contents of this file are subject to the license and copyright terms
 * detailed in the license directory at the root of the source tree (also
 * available online at http://fedora-commons.org/license/).
 */
package org.fcrepo.utilities;

import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.util.HashMap;
import java.util.Map;

import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.SAXParser;
import javax.xml.transform.Source;
import javax.xml.transform.Templates;
import javax.xml.transform.Transformer;
import javax.xml.transform.TransformerException;
import javax.xml.transform.TransformerFactory;
import javax.xml.transform.stream.StreamSource;

import org.apache.commons.pool.impl.SoftReferenceObjectPool;
import org.fcrepo.utilities.xml.PoolableDocumentBuilderFactory;
import org.fcrepo.utilities.xml.PoolableSAXParserFactory;
import org.fcrepo.utilities.xml.PoolableTransformerFactoryFactory;
import org.w3c.dom.Document;
import org.xml.sax.InputSource;
import org.xml.sax.SAXException;
import org.xml.sax.helpers.DefaultHandler;

/**
 *
 * @author Edwin Shin
 * @version $Id$
 */
public class XmlTransformUtility {

    private static final Map<String, TimestampedCacheEntry<Templates>> TEMPLATES_CACHE = new HashMap<String, TimestampedCacheEntry<Templates>>();

    // A pool of namespace-aware DocumentBuilders
    // Using a Stack pool means that objectsare created on demand after the
    // pool is exhausted
    //TODO how should the default values be configured?
    private static final SoftReferenceObjectPool<DocumentBuilder> DOCUMENT_BUILDERS = new SoftReferenceObjectPool<DocumentBuilder>(
            new PoolableDocumentBuilderFactory(true, false));

    private static final SoftReferenceObjectPool<TransformerFactory> TRANSFORM_FACTORIES = new SoftReferenceObjectPool<TransformerFactory>(
            new PoolableTransformerFactoryFactory());

    private static final SoftReferenceObjectPool<SAXParser> SAX_PARSERS = new SoftReferenceObjectPool<SAXParser>(
            new PoolableSAXParserFactory(true, false));

    /**
     * Convenience method to get a new instance of a TransformerFactory.
     * If the {@link #TransformerFactory} is an instance of
     * net.sf.saxon.TransformerFactoryImpl, the attribute
     * {@link #FeatureKeys.VERSION_WARNING} will be set to false in order to
     * suppress the warning about using an XSLT1 stylesheet with an XSLT2
     * processor.
     *
     * @return a new instance of TransformerFactory
     * @throws Exception 
     */
    public static TransformerFactory borrowTransformerFactory() throws Exception {
        return (TransformerFactory) TRANSFORM_FACTORIES.borrowObject();
    }

    public static void returnTransformerFactory(TransformerFactory factory) {
        try {
            TRANSFORM_FACTORIES.returnObject(factory);
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    public static Transformer getTransformer() throws Exception {
        return getTransformer(null);
    }

    public static Transformer getTransformer(Source src) throws Exception {
        TransformerFactory factory = null;
        Transformer result = null;
        try {
            factory = TRANSFORM_FACTORIES.borrowObject();
            result = (src == null) ? factory.newTransformer() : factory.newTransformer(src);

        } finally {
            if (factory != null) {
                try {
                    TRANSFORM_FACTORIES.returnObject(factory);
                } catch (Exception e) {
                    e.printStackTrace();
                }
            }
        }
        return result;
    }

    /**
     * Try to cache parsed Templates, but check for changes on disk
     * @param src
     * @return
     */
    public static Templates getTemplates(File src) throws TransformerException {
        String key = src.getAbsolutePath();
        TimestampedCacheEntry<Templates> entry = TEMPLATES_CACHE.get(key);
        // check to see if it is null or has changed
        if (entry == null || entry.timestamp() < src.lastModified()) {
            TransformerFactory factory = null;
            try {
                factory = borrowTransformerFactory();
                Templates template = factory.newTemplates(new StreamSource(src));
                entry = new TimestampedCacheEntry<Templates>(src.lastModified(), template);
            } catch (Exception e) {
                throw new TransformerException(e.getMessage(), e);
            } finally {
                if (factory != null)
                    returnTransformerFactory(factory);
            }
            TEMPLATES_CACHE.put(key, entry);
        }
        return entry.value();
    }

    public static Templates getTemplates(StreamSource source) throws TransformerException {
        TransformerFactory tf = null;
        Templates result = null;
        try {
            tf = borrowTransformerFactory();
            result = tf.newTemplates(source);
        } catch (Exception e) {
            throw new TransformerException(e.getMessage(), e);
        } finally {
            if (tf != null)
                returnTransformerFactory(tf);
        }
        return result;
    }

    public static DocumentBuilder borrowDocumentBuilder() throws Exception {
        return (DocumentBuilder) DOCUMENT_BUILDERS.borrowObject();
    }

    public static void returnDocumentBuilder(DocumentBuilder object) {
        try {
            DOCUMENT_BUILDERS.returnObject(object);
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    public static Document parseNamespaceAware(File src) throws Exception {
        return parseNamespaceAware(new FileInputStream(src));
    }

    public static Document parseNamespaceAware(InputStream src) throws Exception {
        Document result = null;
        DocumentBuilder builder = (DocumentBuilder) DOCUMENT_BUILDERS.borrowObject();
        try {
            result = builder.parse(src);
        } finally {
            DOCUMENT_BUILDERS.returnObject(builder);
        }
        return result;
    }

    public static void parseWithoutValidating(InputStream in, DefaultHandler handler)
            throws SAXException, IOException {
        parseWithoutValidating(new InputSource(in), handler);
    }

    public static void parseWithoutValidating(InputSource in, DefaultHandler handler)
            throws SAXException, IOException {
        SAXParser parser = null;
        try {
            parser = (SAXParser) SAX_PARSERS.borrowObject();
        } catch (Exception e) {
            throw new RuntimeException("Error initializing SAX parser", e);
        }

        try {
            parser.parse(in, handler);
        } finally {
            if (parser != null) {
                try {
                    SAX_PARSERS.returnObject(parser);
                } catch (Exception e) {
                    e.printStackTrace();
                }
            }
        }
    }
}