diff --git a/spring-integration-xml/src/main/java/org/springframework/integration/xml/config/XsltPayloadTransformerParser.java b/spring-integration-xml/src/main/java/org/springframework/integration/xml/config/XsltPayloadTransformerParser.java index 34ec33df53..b5c3a87bfa 100644 --- a/spring-integration-xml/src/main/java/org/springframework/integration/xml/config/XsltPayloadTransformerParser.java +++ b/spring-integration-xml/src/main/java/org/springframework/integration/xml/config/XsltPayloadTransformerParser.java @@ -1,5 +1,5 @@ /* - * Copyright 2002-2012 the original author or authors. + * Copyright 2002-2013 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -36,6 +36,7 @@ import org.springframework.util.xml.DomUtils; * @author Jonas Partner * @author Mark Fisher * @author Oleg Zhurakousky + * @author Mike Bazos */ public class XsltPayloadTransformerParser extends AbstractTransformerParser { @@ -51,6 +52,7 @@ public class XsltPayloadTransformerParser extends AbstractTransformerParser { String resultTransformer = element.getAttribute("result-transformer"); String resultFactory = element.getAttribute("result-factory"); String resultType = element.getAttribute("result-type"); + String transformerFactoryClass = element.getAttribute("transformer-factory-class"); IntegrationNamespaceUtils.setValueIfAttributeDefined(builder, element, "xslt-param-headers"); Assert.isTrue(StringUtils.hasText(xslResource) ^ StringUtils.hasText(xslTemplates), "Exactly one of 'xsl-resource' or 'xsl-templates' is required."); @@ -68,6 +70,9 @@ public class XsltPayloadTransformerParser extends AbstractTransformerParser { if (StringUtils.hasText(resultTransformer)) { builder.addConstructorArgReference(resultTransformer); } + if (StringUtils.hasText(transformerFactoryClass)) { + builder.addConstructorArgValue(transformerFactoryClass); + } List xslParameterElements = DomUtils.getChildElementsByTagName(element, "xslt-param"); if (!CollectionUtils.isEmpty(xslParameterElements)) { Map xslParameterMappings = new ManagedMap(); diff --git a/spring-integration-xml/src/main/java/org/springframework/integration/xml/transformer/XsltPayloadTransformer.java b/spring-integration-xml/src/main/java/org/springframework/integration/xml/transformer/XsltPayloadTransformer.java index d586c858a6..e79a01c2e2 100644 --- a/spring-integration-xml/src/main/java/org/springframework/integration/xml/transformer/XsltPayloadTransformer.java +++ b/spring-integration-xml/src/main/java/org/springframework/integration/xml/transformer/XsltPayloadTransformer.java @@ -19,7 +19,6 @@ package org.springframework.integration.xml.transformer; import java.io.IOException; import java.util.Map; -import javax.xml.parsers.ParserConfigurationException; import javax.xml.transform.Result; import javax.xml.transform.Source; import javax.xml.transform.Templates; @@ -30,10 +29,9 @@ import javax.xml.transform.dom.DOMResult; import javax.xml.transform.dom.DOMSource; import javax.xml.transform.stream.StreamSource; -import org.apache.commons.logging.Log; -import org.apache.commons.logging.LogFactory; import org.w3c.dom.Document; +import org.springframework.beans.factory.BeanClassLoaderAware; import org.springframework.core.io.Resource; import org.springframework.expression.Expression; import org.springframework.expression.spel.support.StandardEvaluationContext; @@ -76,19 +74,23 @@ import org.springframework.xml.transform.StringSource; * @author Mark Fisher * @author Oleg Zhurakousky * @author Artem Bilan + * @author Mike Bazos + * @author Gary Russell */ -public class XsltPayloadTransformer extends AbstractTransformer { +public class XsltPayloadTransformer extends AbstractTransformer implements BeanClassLoaderAware { - private final Log logger = LogFactory.getLog(this.getClass()); + private final ResultTransformer resultTransformer; - private final Templates templates; + private volatile Resource xslResource; + + private volatile Templates templates; + + private String transformerFactoryClassName; private volatile StandardEvaluationContext evaluationContext; private Map xslParameterMappings; - private final ResultTransformer resultTransformer; - private volatile SourceFactory sourceFactory = new DomSourceFactory(); private volatile ResultFactory resultFactory = new DomResultFactory(); @@ -101,27 +103,42 @@ public class XsltPayloadTransformer extends AbstractTransformer { private volatile String[] xsltParamHeaders; + private ClassLoader classLoader; - public XsltPayloadTransformer(Templates templates) throws ParserConfigurationException { + + public XsltPayloadTransformer(Templates templates) { this(templates, null); } - public XsltPayloadTransformer(Resource xslResource) throws Exception { - this(TransformerFactory.newInstance().newTemplates( - createStreamSourceOnResource(xslResource)), null); + public XsltPayloadTransformer(Resource xslResource) { + this(xslResource, null, null); } - public XsltPayloadTransformer(Resource xslResource, ResultTransformer resultTransformer) throws Exception { - this(TransformerFactory.newInstance().newTemplates( - createStreamSourceOnResource(xslResource)), resultTransformer); + public XsltPayloadTransformer(Resource xslResource, ResultTransformer resultTransformer) { + this(xslResource, resultTransformer, null); } - public XsltPayloadTransformer(Templates templates, ResultTransformer resultTransformer) throws ParserConfigurationException { + public XsltPayloadTransformer(Resource xslResource, String transformerFactoryClassName) { + Assert.notNull(xslResource, "'xslResource' must not be null."); + Assert.hasText(transformerFactoryClassName, "'transformerFactoryClassName' must not be empty String."); + this.xslResource = xslResource; + this.transformerFactoryClassName = transformerFactoryClassName; + this.resultTransformer = null; + } + + public XsltPayloadTransformer(Resource xslResource, ResultTransformer resultTransformer, String transformerFactoryClassName) { + Assert.notNull(xslResource, "'xslResource' must not be null."); + this.xslResource = xslResource; + this.resultTransformer = resultTransformer; + this.transformerFactoryClassName = transformerFactoryClassName; + } + + public XsltPayloadTransformer(Templates templates, ResultTransformer resultTransformer) { + Assert.notNull(templates, "'templates' must not be null."); this.templates = templates; this.resultTransformer = resultTransformer; } - /** * Sets the SourceFactory. */ @@ -161,16 +178,32 @@ public class XsltPayloadTransformer extends AbstractTransformer { this.xsltParamHeaders = xsltParamHeaders; } + @Override + public void setBeanClassLoader(ClassLoader classLoader) { + Assert.notNull(classLoader, "'beanClassLoader' must not be null."); + this.classLoader = classLoader; + } + + @Override public String getComponentType() { return "xml:xslt-transformer"; } - @Override protected void onInit() throws Exception { super.onInit(); this.evaluationContext = ExpressionUtils.createStandardEvaluationContext(this.getBeanFactory()); + if (this.templates == null) { + TransformerFactory transformerFactory; + if (this.transformerFactoryClassName != null) { + transformerFactory = TransformerFactory.newInstance(this.transformerFactoryClassName, this.classLoader); + } + else { + transformerFactory = TransformerFactory.newInstance(); + } + this.templates = transformerFactory.newTemplates(createStreamSourceOnResource(this.xslResource)); + } } @Override @@ -269,6 +302,7 @@ public class XsltPayloadTransformer extends AbstractTransformer { return (Document) domResult.getNode(); } + private Transformer buildTransformer(Message message) throws TransformerException { // process individual mappings Transformer transformer = this.templates.newTransformer(); @@ -301,7 +335,6 @@ public class XsltPayloadTransformer extends AbstractTransformer { return transformer; } - /** * Compensate for the fact that a Resource may not be a File or even * addressable through a URI. If it is, we want the created StreamSource to diff --git a/spring-integration-xml/src/main/resources/org/springframework/integration/xml/config/spring-integration-xml-3.0.xsd b/spring-integration-xml/src/main/resources/org/springframework/integration/xml/config/spring-integration-xml-3.0.xsd index ae605e70ca..3ccf9a8344 100644 --- a/spring-integration-xml/src/main/resources/org/springframework/integration/xml/config/spring-integration-xml-3.0.xsd +++ b/spring-integration-xml/src/main/resources/org/springframework/integration/xml/config/spring-integration-xml-3.0.xsd @@ -237,6 +237,21 @@ + + + + + + + + + + + + diff --git a/spring-integration-xml/src/test/java/org/springframework/integration/xml/transformer/XsltPayloadTransformerTests.java b/spring-integration-xml/src/test/java/org/springframework/integration/xml/transformer/XsltPayloadTransformerTests.java index 937b1564fe..7bee4335b5 100644 --- a/spring-integration-xml/src/test/java/org/springframework/integration/xml/transformer/XsltPayloadTransformerTests.java +++ b/spring-integration-xml/src/test/java/org/springframework/integration/xml/transformer/XsltPayloadTransformerTests.java @@ -5,7 +5,7 @@ * 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 + * 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, @@ -16,12 +16,19 @@ package org.springframework.integration.xml.transformer; +import static org.custommonkey.xmlunit.XMLAssert.assertXMLEqual; +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertTrue; + import javax.xml.transform.Result; import javax.xml.transform.TransformerException; +import javax.xml.transform.TransformerFactoryConfigurationError; import javax.xml.transform.dom.DOMResult; import org.junit.Before; import org.junit.Test; +import org.w3c.dom.Document; + import org.springframework.core.io.ByteArrayResource; import org.springframework.core.io.ClassPathResource; import org.springframework.core.io.Resource; @@ -32,165 +39,186 @@ import org.springframework.integration.xml.result.StringResultFactory; import org.springframework.integration.xml.util.XmlTestUtil; import org.springframework.xml.transform.StringResult; import org.springframework.xml.transform.StringSource; -import org.w3c.dom.Document; - -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertTrue; -import static org.custommonkey.xmlunit.XMLAssert.assertXMLEqual; /** * @author Jonas Partner * @author Oleg Zhurakousky * @author Gunnar Hillert + * @author Mike Bazos */ public class XsltPayloadTransformerTests { - private XsltPayloadTransformer transformer; + private XsltPayloadTransformer transformer; - private String docAsString = "test"; + private final String docAsString = "test"; - private String outputAsString = "test"; + private final String outputAsString = "test"; - @Before - public void setUp() throws Exception { - transformer = new XsltPayloadTransformer(getXslResource()); - } + @Before + public void setUp() throws Exception { + transformer = new XsltPayloadTransformer(getXslResource()); + transformer.afterPropertiesSet(); + } - @Test - public void testDocumentAsPayload() throws Exception { - Object transformed = transformer.doTransform(buildMessage(XmlTestUtil - .getDocumentForString(docAsString))); - assertTrue("Wrong return type for document payload", Document.class - .isAssignableFrom(transformed.getClass())); - Document transformedDocument = (Document) transformed; - assertXMLEqual(outputAsString, XmlTestUtil - .docToString(transformedDocument)); - } + @Test + public void testDocumentAsPayload() throws Exception { + Object transformed = transformer.doTransform(buildMessage(XmlTestUtil + .getDocumentForString(docAsString))); + assertTrue("Wrong return type for document payload", Document.class + .isAssignableFrom(transformed.getClass())); + Document transformedDocument = (Document) transformed; + assertXMLEqual(outputAsString, XmlTestUtil + .docToString(transformedDocument)); + } - @Test - public void testSourceAsPayload() throws Exception { - Object transformed = transformer - .doTransform(buildMessage(new StringSource(docAsString))); - assertEquals("Wrong return type for source payload", DOMResult.class, - transformed.getClass()); - DOMResult result = (DOMResult) transformed; - assertXMLEqual("Document incorrect after transformation", XmlTestUtil - .getDocumentForString(outputAsString), (Document) result - .getNode()); - } + @Test + public void testSourceAsPayload() throws Exception { + Object transformed = transformer + .doTransform(buildMessage(new StringSource(docAsString))); + assertEquals("Wrong return type for source payload", DOMResult.class, + transformed.getClass()); + DOMResult result = (DOMResult) transformed; + assertXMLEqual("Document incorrect after transformation", XmlTestUtil + .getDocumentForString(outputAsString), (Document) result + .getNode()); + } - @Test - public void testStringAsPayload() throws Exception { - Object transformed = transformer.doTransform(buildMessage(docAsString)); - assertEquals("Wrong return type for string payload", String.class, - transformed.getClass()); - String transformedString = (String) transformed; - assertXMLEqual("String incorrect after transform", outputAsString, - transformedString); - } + @Test + public void testStringAsPayload() throws Exception { + Object transformed = transformer.doTransform(buildMessage(docAsString)); + assertEquals("Wrong return type for string payload", String.class, + transformed.getClass()); + String transformedString = (String) transformed; + assertXMLEqual("String incorrect after transform", outputAsString, + transformedString); + } - @Test - public void testStringAsPayloadUseResultFactoryTrue() throws Exception { - transformer.setAlwaysUseResultFactory(true); - Object transformed = transformer.doTransform(buildMessage(docAsString)); - assertEquals("Wrong return type for useFactories true", - DOMResult.class, transformed.getClass()); - DOMResult result = (DOMResult) transformed; - assertXMLEqual("Document incorrect after transformation", XmlTestUtil - .getDocumentForString(outputAsString), (Document) result - .getNode()); - } + @Test + public void testStringAsPayloadUseResultFactoryTrue() throws Exception { + transformer.setAlwaysUseResultFactory(true); + Object transformed = transformer.doTransform(buildMessage(docAsString)); + assertEquals("Wrong return type for useFactories true", + DOMResult.class, transformed.getClass()); + DOMResult result = (DOMResult) transformed; + assertXMLEqual("Document incorrect after transformation", XmlTestUtil + .getDocumentForString(outputAsString), (Document) result + .getNode()); + } - @Test - public void testSourceWithResultTransformer() throws Exception { - Integer returnValue = new Integer(13); - transformer = new XsltPayloadTransformer(getXslResource(), - new StubResultTransformer(returnValue)); - Object transformed = transformer - .doTransform(buildMessage(new StringSource(docAsString))); - assertEquals("Wrong value from result conversion", returnValue, - transformed); - } + @Test + public void testSourceWithResultTransformer() throws Exception { + Integer returnValue = new Integer(13); + transformer = new XsltPayloadTransformer(getXslResource(), + new StubResultTransformer(returnValue)); + transformer.afterPropertiesSet(); + Object transformed = transformer + .doTransform(buildMessage(new StringSource(docAsString))); + assertEquals("Wrong value from result conversion", returnValue, + transformed); + } - @Test(expected = TransformerException.class) - public void testNonXmlString() throws Exception { - transformer.doTransform(buildMessage("test")); - } + @Test + public void testXsltPayloadWithTransformerFactoryClassname() throws Exception { + Integer returnValue = new Integer(13); + transformer = new XsltPayloadTransformer(getXslResource(), new StubResultTransformer(returnValue), + "com.sun.org.apache.xalan.internal.xsltc.trax.TransformerFactoryImpl"); + transformer.afterPropertiesSet(); + Object transformed = transformer + .doTransform(buildMessage(new StringSource(docAsString))); + assertEquals("Wrong value from result conversion", returnValue, + transformed); + } - @Test(expected = MessagingException.class) - public void testUnsupportedPayloadType() throws Exception { - transformer.doTransform(buildMessage(new Long(12))); - } + @Test(expected = TransformerFactoryConfigurationError.class) + public void testXsltPayloadWithBadTransformerFactoryClassname() throws Exception { + transformer = new XsltPayloadTransformer(getXslResource(), "foo.bar.Baz"); + transformer.afterPropertiesSet(); + transformer.doTransform(buildMessage(new StringSource(docAsString))); + } - @Test - public void testXsltWithImports() throws Exception { - Resource resource = new ClassPathResource("transform-with-import.xsl", - this.getClass()); - transformer = new XsltPayloadTransformer(resource); - assertEquals(transformer.doTransform(buildMessage(docAsString)), - outputAsString); - } + @Test(expected = TransformerException.class) + public void testNonXmlString() throws Exception { + transformer.doTransform(buildMessage("test")); + } + + @Test(expected = MessagingException.class) + public void testUnsupportedPayloadType() throws Exception { + transformer.doTransform(buildMessage(new Long(12))); + } + + @Test + public void testXsltWithImports() throws Exception { + Resource resource = new ClassPathResource("transform-with-import.xsl", + this.getClass()); + transformer = new XsltPayloadTransformer(resource); + transformer.afterPropertiesSet(); + assertEquals(transformer.doTransform(buildMessage(docAsString)), + outputAsString); + } - @Test - public void documentInStringResultOut() throws Exception { - Resource resource = new ClassPathResource("transform-with-import.xsl", - this.getClass()); - transformer = new XsltPayloadTransformer(resource); - transformer.setResultFactory(new StringResultFactory()); - transformer.setAlwaysUseResultFactory(true); - Object returned = transformer.doTransform(buildMessage(XmlTestUtil.getDocumentForString(docAsString))); - assertEquals("Wrong type of return ", StringResult.class, returned.getClass()); - } + @Test + public void documentInStringResultOut() throws Exception { + Resource resource = new ClassPathResource("transform-with-import.xsl", + this.getClass()); + transformer = new XsltPayloadTransformer(resource); + transformer.setResultFactory(new StringResultFactory()); + transformer.setAlwaysUseResultFactory(true); + transformer.afterPropertiesSet(); + Object returned = transformer.doTransform(buildMessage(XmlTestUtil.getDocumentForString(docAsString))); + assertEquals("Wrong type of return ", StringResult.class, returned.getClass()); + } - @Test - public void stringInDomResultOut() throws Exception { - Resource resource = new ClassPathResource("transform-with-import.xsl", - this.getClass()); - transformer = new XsltPayloadTransformer(resource); - transformer.setResultFactory(new StringResultFactory()); - transformer.setAlwaysUseResultFactory(true); - Object returned = transformer.doTransform(buildMessage(XmlTestUtil.getDocumentForString(docAsString))); - assertEquals("Wrong type of return ", StringResult.class, returned.getClass()); - } + @Test + public void stringInDomResultOut() throws Exception { + Resource resource = new ClassPathResource("transform-with-import.xsl", + this.getClass()); + transformer = new XsltPayloadTransformer(resource); + transformer.setResultFactory(new StringResultFactory()); + transformer.setAlwaysUseResultFactory(true); + transformer.afterPropertiesSet(); + Object returned = transformer.doTransform(buildMessage(XmlTestUtil.getDocumentForString(docAsString))); + assertEquals("Wrong type of return ", StringResult.class, returned.getClass()); + } - @Test - public void docInStringOut() throws Exception { - transformer = new XsltPayloadTransformer(getXslResourceThatOutputsText()); - transformer.setResultFactory(new StringResultFactory()); - transformer.setAlwaysUseResultFactory(true); - Object returned = transformer.doTransform(buildMessage(XmlTestUtil.getDocumentForString(docAsString))); - assertEquals("Wrong type of return ", StringResult.class, returned.getClass()); - assertEquals("Wrong content in string", "hello world", returned.toString()); - } + @Test + public void docInStringOut() throws Exception { + transformer = new XsltPayloadTransformer(getXslResourceThatOutputsText()); + transformer.setResultFactory(new StringResultFactory()); + transformer.setAlwaysUseResultFactory(true); + transformer.afterPropertiesSet(); + Object returned = transformer.doTransform(buildMessage(XmlTestUtil.getDocumentForString(docAsString))); + assertEquals("Wrong type of return ", StringResult.class, returned.getClass()); + assertEquals("Wrong content in string", "hello world", returned.toString()); + } - protected Message buildMessage(Object payload) { - return MessageBuilder.withPayload(payload).build(); - } + protected Message buildMessage(Object payload) { + return MessageBuilder.withPayload(payload).build(); + } - private Resource getXslResource() throws Exception { - String xsl = "test"; - return new ByteArrayResource(xsl.getBytes("UTF-8")); - } + private Resource getXslResource() throws Exception { + String xsl = "test"; + return new ByteArrayResource(xsl.getBytes("UTF-8")); + } - private Resource getXslResourceThatOutputsText() throws Exception { - String xsl = "hello world"; - return new ByteArrayResource(xsl.getBytes("UTF-8")); - } + private Resource getXslResourceThatOutputsText() throws Exception { + String xsl = "hello world"; + return new ByteArrayResource(xsl.getBytes("UTF-8")); + } - public static class StubResultTransformer implements ResultTransformer { + public static class StubResultTransformer implements ResultTransformer { - private Object objectToReturn; + private final Object objectToReturn; - public StubResultTransformer(Object objectToReturn) { - this.objectToReturn = objectToReturn; - } + public StubResultTransformer(Object objectToReturn) { + this.objectToReturn = objectToReturn; + } - public Object transformResult(Result result) { - return objectToReturn; - } - } + public Object transformResult(Result result) { + return objectToReturn; + } + } } diff --git a/spring-integration-xml/src/test/java/org/springframework/integration/xml/transformer/XsltTransformerTests-context.xml b/spring-integration-xml/src/test/java/org/springframework/integration/xml/transformer/XsltTransformerTests-context.xml index e9b189370d..c76f7e5aea 100644 --- a/spring-integration-xml/src/test/java/org/springframework/integration/xml/transformer/XsltTransformerTests-context.xml +++ b/spring-integration-xml/src/test/java/org/springframework/integration/xml/transformer/XsltTransformerTests-context.xml @@ -17,7 +17,8 @@ input-channel="paramHeadersWithStartWildCharacterChannel" output-channel="output" xsl-resource="classpath:org/springframework/integration/xml/transformer/transformer.xslt" - xslt-param-headers="*Param, foo"> + xslt-param-headers="*Param, foo" + transformer-factory-class="com.sun.org.apache.xalan.internal.xsltc.trax.TransformerFactoryImpl"> . +
+ XsltPayloadTransformer + + You can now specify the transformer factory class name using the + transformer-factory-class attribute. See + +
Message Headers and TCP diff --git a/src/reference/docbook/xml.xml b/src/reference/docbook/xml.xml index 813e86ac18..427d4c0723 100644 --- a/src/reference/docbook/xml.xml +++ b/src/reference/docbook/xml.xml @@ -463,6 +463,11 @@ ]]> + + Starting with Spring Integration 3.0, you can now specify the transformer factory class name using + a constructor argument. This is configured using the transformer-factory-class + attribute when using the namespace. +
ResultTransformers @@ -640,6 +645,10 @@ Xslt parameters could now be mapped to any accessible part of the Message as well as any literal value. + + Starting with Spring Integration 3.0, you can now specify the transformer factory class name using + the transformer-factory-class attribute. +
Namespace Configuration and ResultTransformers