diff --git a/xml/src/main/java/org/springframework/xml/transform/TransformerHelper.java b/xml/src/main/java/org/springframework/xml/transform/TransformerHelper.java new file mode 100644 index 00000000..7fe8bf1c --- /dev/null +++ b/xml/src/main/java/org/springframework/xml/transform/TransformerHelper.java @@ -0,0 +1,141 @@ +/* + * Copyright 2005-2010 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. + * You may obtain a copy of the License at + * + * 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, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.xml.transform; + +import javax.xml.transform.Result; +import javax.xml.transform.Source; +import javax.xml.transform.Transformer; +import javax.xml.transform.TransformerConfigurationException; +import javax.xml.transform.TransformerException; +import javax.xml.transform.TransformerFactory; +import javax.xml.transform.TransformerFactoryConfigurationError; + +import org.springframework.util.Assert; + +/** + * Helper class for {@link Transformer} usage. Provides {@link #createTransformer()} and {@link #transform(Source, + * Result)}. + * + * @author Arjen Poutsma + * @since 3.0 + */ +public class TransformerHelper { + + private volatile TransformerFactory transformerFactory; + + private Class transformerFactoryClass; + + /** + * Initializes a new instance of the {@code TransformerHelper}. + */ + public TransformerHelper() { + } + + /** + * Initializes a new instance of the {@code TransformerHelper} with the specified {@link TransformerFactory}. + */ + public TransformerHelper(TransformerFactory transformerFactory) { + this.transformerFactory = transformerFactory; + } + + /** + * Initializes a new instance of the {@code TransformerHelper} with the specified {@link TransformerFactory} class. + */ + public TransformerHelper(Class transformerFactoryClass) { + setTransformerFactoryClass(transformerFactoryClass); + } + + /** + * Specify the {@code TransformerFactory} class to use. + */ + public void setTransformerFactoryClass(Class transformerFactoryClass) { + Assert.isAssignable(TransformerFactory.class, transformerFactoryClass); + this.transformerFactoryClass = transformerFactoryClass; + } + + /** + * Instantiate a new TransformerFactory. + *

+ * The default implementation simply calls {@link TransformerFactory#newInstance()}. If a {@link + * #setTransformerFactoryClass transformerFactoryClass} has been specified explicitly, the default constructor of + * the specified class will be called instead. + *

+ * Can be overridden in subclasses. + * + * @param transformerFactoryClass the specified factory class (if any) + * @return the new TransactionFactory instance + * @see #setTransformerFactoryClass + * @see #getTransformerFactory() + */ + protected TransformerFactory newTransformerFactory(Class transformerFactoryClass) { + if (transformerFactoryClass != null) { + try { + return transformerFactoryClass.newInstance(); + } + catch (Exception ex) { + throw new TransformerFactoryConfigurationError(ex, + "Could not instantiate TransformerFactory [" + transformerFactoryClass + "]"); + } + } + else { + return TransformerFactory.newInstance(); + } + } + + /** + * Returns the {@code TransformerFactory}. + * + * @return the transformer factory + */ + public TransformerFactory getTransformerFactory() { + TransformerFactory result = transformerFactory; + if (result == null) { + synchronized (this) { + result = transformerFactory; + if (result == null) { + transformerFactory = result = newTransformerFactory(transformerFactoryClass); + } + } + } + return result; + } + + /** + * Creates a new {@code Transformer}. Must be called per thread, as transformers are not thread-safe. + * + * @return the created transformer + * @throws TransformerConfigurationException + * if thrown by JAXP methods + */ + public Transformer createTransformer() throws TransformerConfigurationException { + return getTransformerFactory().newTransformer(); + } + + /** + * Transforms the given {@link Source} to the given {@link Result}. Creates a new {@link Transformer} for every + * call, as transformers are not thread-safe. + * + * @param source the source to transform from + * @param result the result to transform to + * @throws TransformerException if thrown by JAXP methods + */ + public void transform(Source source, Result result) throws TransformerException { + Transformer transformer = createTransformer(); + transformer.transform(source, result); + } + +} diff --git a/xml/src/main/java/org/springframework/xml/transform/TransformerObjectSupport.java b/xml/src/main/java/org/springframework/xml/transform/TransformerObjectSupport.java index e2b2e9db..3f827430 100644 --- a/xml/src/main/java/org/springframework/xml/transform/TransformerObjectSupport.java +++ b/xml/src/main/java/org/springframework/xml/transform/TransformerObjectSupport.java @@ -22,9 +22,6 @@ import javax.xml.transform.Transformer; import javax.xml.transform.TransformerConfigurationException; import javax.xml.transform.TransformerException; import javax.xml.transform.TransformerFactory; -import javax.xml.transform.TransformerFactoryConfigurationError; - -import org.springframework.util.Assert; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; @@ -40,52 +37,40 @@ import org.apache.commons.logging.LogFactory; */ public abstract class TransformerObjectSupport { - /** Logger available to subclasses. */ + /** + * Logger available to subclasses. + */ protected final Log logger = LogFactory.getLog(getClass()); - private TransformerFactory transformerFactory; - - private Class transformerFactoryClass; + private TransformerHelper transformerHelper = new TransformerHelper(); /** * Specify the {@code TransformerFactory} class to use. */ public void setTransformerFactoryClass(Class transformerFactoryClass) { - Assert.isAssignable(TransformerFactory.class, transformerFactoryClass); - this.transformerFactoryClass = transformerFactoryClass; + transformerHelper.setTransformerFactoryClass(transformerFactoryClass); } /** - * Instantiate a new TransformerFactory. - *

The default implementation simply calls {@link TransformerFactory#newInstance()}. - * If a {@link #setTransformerFactoryClass "transformerFactoryClass"} has been specified explicitly, - * the default constructor of the specified class will be called instead. - *

Can be overridden in subclasses. + * Instantiate a new TransformerFactory.

The default implementation simply calls {@link + * TransformerFactory#newInstance()}. If a {@link #setTransformerFactoryClass "transformerFactoryClass"} has been + * specified explicitly, the default constructor of the specified class will be called instead.

Can be overridden + * in subclasses. + * * @param transformerFactoryClass the specified factory class (if any) * @return the new TransactionFactory instance * @see #setTransformerFactoryClass * @see #getTransformerFactory() */ protected TransformerFactory newTransformerFactory(Class transformerFactoryClass) { - if (transformerFactoryClass != null) { - try { - return transformerFactoryClass.newInstance(); - } - catch (Exception ex) { - throw new TransformerFactoryConfigurationError(ex, "Could not instantiate TransformerFactory"); - } - } - else { - return TransformerFactory.newInstance(); - } + return transformerHelper.newTransformerFactory(transformerFactoryClass); } - /** Returns the TransformerFactory. */ + /** + * Returns the TransformerFactory. + */ protected TransformerFactory getTransformerFactory() { - if (transformerFactory == null) { - transformerFactory = newTransformerFactory(transformerFactoryClass); - } - return transformerFactory; + return transformerHelper.getTransformerFactory(); } /** @@ -96,7 +81,7 @@ public abstract class TransformerObjectSupport { * if thrown by JAXP methods */ protected final Transformer createTransformer() throws TransformerConfigurationException { - return getTransformerFactory().newTransformer(); + return transformerHelper.createTransformer(); } /** @@ -108,8 +93,7 @@ public abstract class TransformerObjectSupport { * @throws TransformerException if thrown by JAXP methods */ protected final void transform(Source source, Result result) throws TransformerException { - Transformer transformer = createTransformer(); - transformer.transform(source, result); + transformerHelper.transform(source, result); } } diff --git a/xml/src/test/java/org/springframework/xml/transform/TransformerHelperTest.java b/xml/src/test/java/org/springframework/xml/transform/TransformerHelperTest.java new file mode 100644 index 00000000..273622cf --- /dev/null +++ b/xml/src/test/java/org/springframework/xml/transform/TransformerHelperTest.java @@ -0,0 +1,60 @@ +/* + * Copyright 2005-2010 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. + * You may obtain a copy of the License at + * + * 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, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.xml.transform; + +import java.io.IOException; +import javax.xml.transform.Result; +import javax.xml.transform.Source; +import javax.xml.transform.TransformerException; + +import com.sun.org.apache.xalan.internal.xsltc.trax.TransformerFactoryImpl; +import org.junit.Before; +import org.junit.Test; +import org.xml.sax.SAXException; + +import static org.custommonkey.xmlunit.XMLAssert.assertXMLEqual; + +public class TransformerHelperTest { + + private TransformerHelper helper; + + @Before + public void setUp() throws Exception { + helper = new TransformerHelper(); + } + + @Test + public void defaultTransformerFactory() throws TransformerException, IOException, SAXException { + doTest(); + } + + @Test + public void customTransformerFactory() throws TransformerException, IOException, SAXException { + helper.setTransformerFactoryClass(TransformerFactoryImpl.class); + doTest(); + } + + private void doTest() throws TransformerException, SAXException, IOException { + String xml = "text"; + Source source = new StringSource(xml); + Result result = new StringResult(); + + helper.transform(source, result); + + assertXMLEqual(xml, result.toString()); + } +}