/* Milyn - Copyright (C) 2006 - 2010 This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License (version 2.1) as published by the Free Software Foundation. This 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: http://www.gnu.org/licenses/lgpl.txt */ package org.milyn.templating.xslt; import org.milyn.cdr.SmooksConfigurationException; import org.milyn.cdr.SmooksResourceConfiguration; import org.milyn.cdr.annotation.AppContext; import org.milyn.cdr.annotation.Configurator; import org.milyn.container.ApplicationContext; import org.milyn.delivery.ContentHandler; import org.milyn.delivery.ContentHandlerFactory; import org.milyn.delivery.annotation.Resource; import org.milyn.javabean.context.BeanContext; /** * XSL {@link org.milyn.delivery.dom.DOMElementVisitor} Creator class. * <p/> * Creates {@link org.milyn.delivery.dom.DOMElementVisitor} instances for performing node/element level * <a href="http://www.w3.org/Style/XSL/">XSL</a> templating (aka XSLT). * <p/> * Template application can be done in a synchronized or unsynchronized fashion by setting * the system property "org.milyn.templating.xslt.synchronized". According to the spec, * this should not be necessary. However, Xalan 2.7.0 (for one) has a bug which results in * unsynchronized template application causing invalid transforms. * <p/> * <h2>Targeting "xsl" Templates</h2> * The following is the basic configuration specification for XSL resources: * <pre> * <resource-config selector="<i>target-element</i>"> * <resource><b>XSL Resource - Inline or {@link org.milyn.resource.URIResourceLocator URI}</b></resource> * * <!-- (Optional) The action to be applied on the template content. Should the content * generated by the template: * 1. replace ("replace") the target element, or * 2. be added to ("addto") the target element, or * 3. be inserted before ("insertbefore") the target element, or * 4. be inserted after ("insertafter") the target element. * 5. be bound to ("bindto") a {@link BeanContext} variable named by the "bindId" param. * Default "replace".--> * <param name="<b>action</b>"><i>replace/addto/insertbefore/insertafter/bindto</i></param> * * <!-- (Optional) Is this XSL template resource a complete XSL template, or just a <a href="#templatelets">"Template<u>let</u></a>". * Only relevant for inlined XSL resources. URI based resource are always assumed to NOT be templatelets. * Default "false" (for inline resources).--> * <param name="<b>is-xslt-templatelet</b>"><i>true/false</i></param> * * <!-- (Optional) Should the template be applied before (true) or * after (false) Smooks visits the child elements of the target element. * Default "false".--> * <param name="<b>applyTemplateBefore</b>"><i>true/false</i></param> * * <!-- (Optional) The name of the {@link org.milyn.io.AbstractOutputStreamResource OutputStreamResource} * to which the result should be written. If set, the "action" param is ignored. --> * <param name="<b>outputStreamResource</b>"><i>xyzResource</i></param> * * <!-- (Optional) Template encoding. * Default "UTF-8".--> * <param name="<b>encoding</b>"><i>encoding</i></param> * * <!-- (Optional) bindId when "action" is "bindto". * <param name="<b>bindId</b>"><i>xxxx</i></param> * * <!-- (Optional) Fail on XSL Transformer Warning. * Default "true".--> * <param name="<b>failOnWarning</b>">false</param></b> <!-- Default "true" --> * * </resource-config> * </pre> * <p/> * <i><u>Example - URI based XSLT spec</u></i>: * <pre> * <resource-config selector="<i>target-element</i>"> * <!-- 1. See {@link org.milyn.resource.URIResourceLocator} --> * <resource>/com/acme/order-transform.xsl</resource> * </resource-config> * </pre> * <p/> * <i><u>Example - Inlined XSLT spec</u></i>: * <pre> * <resource-config selector="<i>target-element</i>"> * <!-- 1. Note how we have to specify the resource type when it's inlined. --> * <!-- 2. Note how the inlined XSLT is wrapped as an XML Comment. CDATA Section wrapping also works. --> * <!-- 3. Note if the inlined XSLT is a <a href="#templatelets">templatelet</a>, is-xslt-templatelet=true must be specified. --> * <resource <b color="red">type="xsl"</b>> * <!-- * <i>Inline XSLT....</i> * --> * </resource> * <b color="red"><param name="is-xslt-templatelet">true</param></b> * </resource-config> * </pre> * <p/> * <h3 id="templatelets">Templatelets</h3> * Templatelets are a convenient way of specifying an XSL Stylesheet. When using "Templatelets", you simply specify the * body of an XSL template. This creator then wraps that body to make a complete XSL Stylesheet with a single template matched to the * element targeted by the Smooks resource configuration in question. This feature only applies * to inlined XSL resources and in this case, it's <u>OFF</u> by default. To use this feature, * you must specify the "is-xslt-templatelet" parameter with a value of "true". * <p/> * This feature will not work in all situations since you'll often need to specify a full stylesheet in order to * specify namespaces etc. It's just here for convenience. * <p/> * <a href="doc-files/templatelet.xsl" type="text/plain">See the template used to wrap the templatelet</a>. * <p/> * <h3>JavaBean Support</h3> * Support for injection of JavaBean values populated by the * <a href="http://milyn.codehaus.org/downloads">Smooks JavaBean Cartridge</a> is supported through the * <a href="http://xml.apache.org/xalan-j/">Xalan</a> extension {@link org.milyn.templating.xslt.XalanJavabeanExtension}. * * @author <a href="mailto:tom.fennelly@gmail.com">tom.fennelly@gmail.com</a> */ @Resource(type = "xsl") public class XslContentHandlerFactory implements ContentHandlerFactory { /** * Parameter name for templating feature. */ public static final String IS_XSLT_TEMPLATELET = "is-xslt-templatelet"; /** * Synchonized template application system property key. */ public static final String ORG_MILYN_TEMPLATING_XSLT_SYNCHRONIZED = "org.milyn.templating.xslt.synchronized"; @AppContext private ApplicationContext applicationContext; /** * Create an XSL based ContentHandler instance ie from an XSL byte streamResult. * * @param resourceConfig The SmooksResourceConfiguration for the XSL {@link org.milyn.delivery.ContentHandler} * to be created. * @return XSL {@link org.milyn.delivery.ContentHandler} instance. * @see org.milyn.delivery.JavaContentHandlerFactory */ public synchronized ContentHandler create(SmooksResourceConfiguration resourceConfig) throws SmooksConfigurationException, InstantiationException { try { return Configurator.configure(new XslTemplateProcessor(), resourceConfig, applicationContext); } catch(SmooksConfigurationException e) { throw e; } catch (Exception e) { InstantiationException instanceException = new InstantiationException("XSL ProcessingUnit resource [" + resourceConfig.getResource() + "] not loadable."); instanceException.initCause(e); throw instanceException; } } }