/* * eXist Open Source Native XML Database * Copyright (C) 2001-2015 The eXist Project * http://exist-db.org * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */ package org.exist.xslt; import java.util.Enumeration; import java.util.Hashtable; import javax.xml.transform.TransformerFactory; import javax.xml.transform.sax.SAXTransformerFactory; import org.apache.logging.log4j.LogManager; import org.apache.logging.log4j.Logger; import org.exist.storage.BrokerPool; /** * Allows the TransformerFactory that is used for XSLT to be * chosen through configuration settings in conf.xml * * Within eXist this class should be used instead of * directly calling SAXTransformerFactory.newInstance() directly * * @author Adam Retter <adam.retter@googlemail.com> * @author Andrzej Taramina <andrzej@chaeron.com> */ public class TransformerFactoryAllocator { private final static Logger LOG = LogManager.getLogger(TransformerFactoryAllocator.class); public static final String CONFIGURATION_ELEMENT_NAME = "transformer"; public final static String TRANSFORMER_CLASS_ATTRIBUTE = "class"; public final static String PROPERTY_TRANSFORMER_CLASS = "transformer.class"; public final static String CONFIGURATION_TRANSFORMER_ATTRIBUTE_ELEMENT_NAME = "attribute"; public final static String PROPERTY_TRANSFORMER_ATTRIBUTES = "transformer.attributes"; public final static String TRANSFORMER_CACHING_ATTRIBUTE = "caching"; public final static String PROPERTY_CACHING_ATTRIBUTE = "transformer.caching"; public final static String PROPERTY_BROKER_POOL = "transformer.brokerPool"; private static volatile SAXTransformerFactory saxTransformerFactory = null; //private constructor private TransformerFactoryAllocator() { } /** * Get the TransformerFactory defined in conf.xml * If the class can't be found or the given class doesn't implement * the required interface, the default factory is returned. * * @param pool A database broker pool, used for reading the conf.xml configuration * @return A SAXTransformerFactory, for which newInstance() can then be called * * Typical usage: * * Instead of SAXTransformerFactory.newInstance() use * TransformerFactoryAllocator.getTransformerFactory(broker).newInstance() */ public static SAXTransformerFactory getTransformerFactory(final BrokerPool pool) { if(saxTransformerFactory == null) { synchronized (TransformerFactoryAllocator.class) { // Check again, after having acquired the lock to make sure // the instance was not created meanwhile by another thread if (saxTransformerFactory == null) { // Lazy initialisation saxTransformerFactory = initTransformerFactory(pool); } } } return saxTransformerFactory; } private static SAXTransformerFactory initTransformerFactory(final BrokerPool pool) { //Get the transformer class name from conf.xml final String transformerFactoryClassName = (String) pool.getConfiguration().getProperty(PROPERTY_TRANSFORMER_CLASS); //Was a TransformerFactory class specified? SAXTransformerFactory factory; if (transformerFactoryClassName == null) { //No, use the system default factory = (SAXTransformerFactory) TransformerFactory.newInstance(); } else { //Try and load the specified TransformerFactory class try { factory = (SAXTransformerFactory) Class.forName(transformerFactoryClassName).newInstance(); if (LOG.isDebugEnabled()) { LOG.debug("Set transformer factory: " + transformerFactoryClassName); } final Hashtable<String, Object> attributes = (Hashtable<String, Object>) pool.getConfiguration().getProperty(PROPERTY_TRANSFORMER_ATTRIBUTES); final Enumeration<String> attrNames = attributes.keys(); while (attrNames.hasMoreElements()) { final String name = attrNames.nextElement(); final Object value = attributes.get(name); try { factory.setAttribute(name, value); if (LOG.isDebugEnabled()) { LOG.debug("Set transformer attribute: " + ", " + "name: " + name + ", value: " + value); } } catch (final IllegalArgumentException iae) { LOG.warn("Unable to set attribute for TransformerFactory: '" + transformerFactoryClassName + "', name: " + name + ", value: " + value + ", exception: " + iae.getMessage()); } } try { factory.setAttribute(PROPERTY_BROKER_POOL, pool); } catch (final Exception e) { //some transformers do not support "setAttribute" } } catch (final ClassNotFoundException | InstantiationException | IllegalAccessException e) { if (LOG.isDebugEnabled()) { LOG.debug("Error found loading the requested TrAX Transformer Factory '" + transformerFactoryClassName + "'. Using default TrAX Transformer Factory instead: " + e); } //Fallback to system default factory = (SAXTransformerFactory) TransformerFactory.newInstance(); } } return factory; } }