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

org.ow2.petals.se.xslt.model.XsltConfigurationHandler Maven / Gradle / Ivy

There is a newer version: 2.10.0
Show newest version
/**
 * Copyright (c) 2010-2012 EBM WebSourcing, 2012-2016 Linagora
 * 
 * This program/library 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.1 of the License, or (at your
 * option) any later version.
 * 
 * This program/library 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 program/library; If not, see http://www.gnu.org/licenses/
 * for the GNU Lesser General Public License version 2.1.
 */
package org.ow2.petals.se.xslt.model;

import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.util.Enumeration;
import java.util.Map;
import java.util.jar.JarEntry;
import java.util.jar.JarFile;
import java.util.logging.Level;
import java.util.logging.Logger;

import javax.jbi.messaging.MessagingException;
import javax.xml.transform.Source;
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.stream.StreamSource;

import org.ow2.petals.component.framework.api.exception.PEtALSCDKException;
import org.ow2.petals.component.framework.api.message.Exchange;
import org.ow2.petals.component.framework.util.ClassLoaderUtil;
import org.ow2.petals.se.xslt.utils.LogErrorListener;
import org.ow2.petals.se.xslt.utils.ServiceUnitURIResolver;

import com.ebmwebsourcing.easycommons.pooling.GenericResourcePool;
import com.ebmwebsourcing.easycommons.pooling.PoolPolicy;

/**
 * A handler for XSLT configurations.
 * 

* Every element derived from the SU configuration and required at runtime is * hold by such a handler. *

* * @author Vincent Zurczak - EBM WebSourcing */ public class XsltConfigurationHandler { /** * The XSLT configuration. */ private final XsltConfiguration xsltConfiguration; /** * The URI resolver for this service-unit. */ private final ServiceUnitURIResolver uriResolver; /** * The error listener, used to resolve and log line numbers when errors are * found. */ private final LogErrorListener logErrorListener; /** * The class loader associated with this transformer. *

* This class loader may be specific to the SU if it embeds custom Java * functions used in the XSL transformation. *

*/ private ClassLoader classLoader; /** * An object that will be used as a lock in the management of the instance's * state. */ private final Object lock = new Object(); /** * The SU transformer resource pool */ private GenericResourcePool suTransformerResourcePool; /** * Constructor. * * @param xsltConfiguration * an XSLT configuration * @param logger * the component's logger * @throws PEtALSCDKException */ public XsltConfigurationHandler(XsltConfiguration xsltConfiguration, Logger logger) { this.xsltConfiguration = xsltConfiguration; this.logErrorListener = new LogErrorListener(logger, xsltConfiguration.getServiceUnitName()); this.uriResolver = new ServiceUnitURIResolver(xsltConfiguration.getSuInstallRoot(), logger, xsltConfiguration.getServiceUnitName()); } /** * Checks the handler. *

* It tries to create the XSL template which is not cached (deployment)
* If the SU embeds JAR files, they are loaded in the class loader of the * handler, so that they can be used by the XSL transformation. *

* * @param logger * the logger of the component * @throws PEtALSCDKException * if the check fails */ public void check(Logger logger) throws PEtALSCDKException { createTemplate(logger, true); } /** * Starts the handler. *

* The XSL style sheet is cached and a pool of transformer is created
* If the SU embeds JAR files, they are loaded in the class loader of the * handler, so that they can be used by the XSL transformation. *

* * @param logger * the logger of the component * @throws PEtALSCDKException * if the handler could not be started */ public void start(Logger logger) throws PEtALSCDKException { Templates template = createTemplate(logger, false); XsltTransformerResourceHandler transformerResourceHandler = new XsltTransformerResourceHandler( template, uriResolver, logErrorListener, xsltConfiguration); int transformerPoolSizeMin = this.xsltConfiguration.getTransformerPoolSizeMin(); int transformerPoolSizeMax = this.xsltConfiguration.getTransformerPoolSizeMax(); ClassLoader customClassLoader = getClassLoader(); try { // this is needed because the pool is susceptible of pre-creating resources // which are susceptible to precompiling XSLT (for example the default XSLT engine of Java 7 does that) // and they will need the context classloader in case there is custom functions used in the XSLT if (customClassLoader != null) { Thread.currentThread().setContextClassLoader(customClassLoader); } this.suTransformerResourcePool = new GenericResourcePool(transformerResourceHandler, transformerPoolSizeMin, transformerPoolSizeMax, PoolPolicy.WAIT); } finally { if (customClassLoader != null) { Thread.currentThread().setContextClassLoader(this.getClass().getClassLoader()); } } } /** * Creates the XSL template * * @param logger * the logger of the component * @param logEnabled * a flag to indicate to log or not * * @return the XSL template * * @throws PEtALSCDKException * if the template could not be created */ private Templates createTemplate(Logger logger, boolean logEnabled) throws PEtALSCDKException { Templates template = null; synchronized (this.lock) { String suRoot = this.xsltConfiguration.getSuInstallRoot(); String logPrefix = this.xsltConfiguration.getServiceUnitName(); // Try to get the XSL from the file system InputStream xslStream = null; try { // Check if Java classes are provided // These classes should contain custom XSL functions boolean clazzProvided = false; bigLoop: for (File file : new File(suRoot).listFiles()) { // Skip non-JAR files if (!file.getName().toLowerCase().endsWith(".jar")) continue; // Check that the jar doesn't contain only a META-INF // directory JarFile jar = new JarFile(file); Enumeration entryEnum = jar.entries(); while (entryEnum.hasMoreElements()) { JarEntry jarEntry = entryEnum.nextElement(); if (jarEntry.getName().toLowerCase().endsWith(".class")) { clazzProvided = true; break bigLoop; } } jar.close(); } // PETALSSEXSLT-9: try to get the input stream as a resource // (class loader). // If it fails, try to get it from a file. ClassLoader tempClassLoader = ClassLoaderUtil.createClassLoader(suRoot, getClass() .getClassLoader()); xslStream = tempClassLoader .getResourceAsStream(this.xsltConfiguration.getXslPath()); if (xslStream == null) { File xslStyleSheet = new File(suRoot, this.xsltConfiguration.getXslPath()); xslStream = new FileInputStream(xslStyleSheet); } // PETALSSEXSLT-9 // Instantiate the XSL style sheet Source source = new StreamSource(xslStream); String transformerFactoryClassName = this.xsltConfiguration .getTransformerFactoryClassName(); TransformerFactory transformerFactory = createTransformerFactory(logger, logPrefix, transformerFactoryClassName, logEnabled); transformerFactory.setURIResolver(this.uriResolver); transformerFactory.setErrorListener(this.logErrorListener); if (clazzProvided) { this.classLoader = tempClassLoader; Thread.currentThread().setContextClassLoader(this.classLoader); } else { // Do not use it anymore - and speed up the garbage // collector tempClassLoader = null; } // Register the XSL style sheet, and its class loader template = transformerFactory.newTemplates(source); if (this.classLoader != null) { Thread.currentThread().setContextClassLoader(this.getClass().getClassLoader()); if (logger.isLoggable(Level.FINE)) logger.fine(logPrefix + ": the XSL style sheet was stored with a custom class loader."); } } catch (IOException e) { throw new PEtALSCDKException(logPrefix + ": failed to retrieve the XSL resources.", e); } catch (TransformerConfigurationException e) { throw new PEtALSCDKException(logPrefix + ": Error when creating the XSLT template.", e); } finally { // Close the loaded input stream if (xslStream != null) { try { xslStream.close(); } catch (IOException e) { if (logger.isLoggable(Level.FINE)) logger.fine(logPrefix + ": the XSL input stream could not be closed."); } } } } return template; } /** * Create the transformer factory * * @param logger * the logger * @param logPrefix * the log prefix * @param transformerFactoryClassName * the transformer factory class name * @param logEnabled * a flag to indicate to log or not * @return the transformer factory * * @throws PEtALSCDKException * if the transformer factory can not be created */ static final TransformerFactory createTransformerFactory(Logger logger, String logPrefix, String transformerFactoryClassName, boolean logEnabled) throws PEtALSCDKException { final TransformerFactory transformerFactory; if (transformerFactoryClassName == null) { transformerFactory = TransformerFactory.newInstance(); if(logger.isLoggable(Level.CONFIG)) { logger.log(Level.CONFIG, "Transformer used: " + transformerFactory.getClass().getName() + " provided by the component"); } } else { try { if (logger.isLoggable(Level.FINE)) { logger.log(Level.FINE, "Trying to load the specific XSLT engine factory class " + transformerFactoryClassName + " in the following classloader\n" + Thread.currentThread().getContextClassLoader()); } Class transformerFactoryClass = Class.forName(transformerFactoryClassName); Object transformerFactoryObj = transformerFactoryClass.newInstance(); if (transformerFactoryObj instanceof TransformerFactory) { transformerFactory = (TransformerFactory) transformerFactoryObj; if(logger.isLoggable(Level.CONFIG)) { logger .log(Level.CONFIG, "Transformer used: " + transformerFactory.getClass().getName() + " provided by the SL"); } } else { throw new PEtALSCDKException( logPrefix + ": failed to create the pool of transformer. The class defined as XSLT engine factory does not implement TransformerFactory"); } } catch (ClassNotFoundException e) { throw new PEtALSCDKException(logPrefix + ": failed to create the pool of transformer.", e); } catch (InstantiationException e) { throw new PEtALSCDKException(logPrefix + ": failed to create the pool of transformer.", e); } catch (IllegalAccessException e) { throw new PEtALSCDKException(logPrefix + ": failed to create the pool of transformer.", e); } } return transformerFactory; } /** * Stops the handler. *

* The transformer is deleted and the class loader is freed. *

*/ public void stop() { synchronized (this.lock) { // FIXME: are we sure an exception won't be thrown at the uninstall // phase? // Sun's URL class loaders lock JAR files... this.classLoader = null; } } /** * @return the associated end-point name * @see org.ow2.petals.se.xslt.model.XsltConfiguration #getEndpointName() */ public String getEndpointName() { return this.xsltConfiguration.getEndpointName(); } /** * @return the classLoader */ public ClassLoader getClassLoader() { return this.classLoader; } /** * @return an output attachment-name */ public String getOutputAttachmentName() { return this.xsltConfiguration.getOutputAttachmentName(); } /** * Takes a transformer (with the right properties) in the transformer pool. * * @param exchange * the exchange, to get its properties * @param logger * the component logger * * @return a new transformer * @throws TransformerException * if the transformer could not be created or if a XSL parameter * could not be overridden */ public Transformer takeTransformer(Exchange exchange, Logger logger) throws TransformerException { Transformer transformer = this.suTransformerResourcePool.take(); // Prepare the log prefix String logHint = "Exchange " + exchange.getExchangeId(); // Then, pass the XSL parameters from the exchange try { Map suXslParameters = this.xsltConfiguration .getParamNameToParamBean(); for (String propertyName : exchange.getInMessagePropertyNames()) { XslParameterBean suXslParamBean = suXslParameters.get(propertyName); if (suXslParamBean != null && !suXslParamBean.isOverridable()) throw new TransformerException(logHint + ": the XSL parameter " + propertyName + " was already set by the configuration and cannot be overridden."); Object value = exchange.getInMessageProperty(propertyName); transformer.setParameter(propertyName, value); } } catch (MessagingException e) { if (logger.isLoggable(Level.WARNING)) { String msg = logHint + ": IN message properties could not be read and passed as parameters to the transformer."; logger.warning(msg); } } return transformer; } /** * Releases a transformer (for the transformer pool). * * @param transformer * the transformer to release */ public void releaseTransformer(Transformer transformer) { this.suTransformerResourcePool.release(transformer); } }




© 2015 - 2024 Weber Informatics LLC | Privacy Policy