CAMEL-8034: xslt component like the others.
Project: http://git-wip-us.apache.org/repos/asf/camel/repo Commit: http://git-wip-us.apache.org/repos/asf/camel/commit/438700a1 Tree: http://git-wip-us.apache.org/repos/asf/camel/tree/438700a1 Diff: http://git-wip-us.apache.org/repos/asf/camel/diff/438700a1 Branch: refs/heads/master Commit: 438700a1e8f1a7cf8c170155a2d709b70931e84a Parents: c79aaa1 Author: Claus Ibsen <davscl...@apache.org> Authored: Wed Nov 12 08:30:20 2014 +0100 Committer: Claus Ibsen <davscl...@apache.org> Committed: Wed Nov 12 08:30:20 2014 +0100 ---------------------------------------------------------------------- .../camel/component/xslt/XsltComponent.java | 102 ++------ .../camel/component/xslt/XsltEndpoint.java | 251 ++++++++++++++++++- .../apache/camel/component/xslt/XsltOutput.java | 24 ++ ...ponentConfigurationAndDocumentationTest.java | 2 +- .../xslt/XsltReferenceParameterTest.java | 8 - camel-core/src/test/resources/log4j.properties | 2 +- 6 files changed, 286 insertions(+), 103 deletions(-) ---------------------------------------------------------------------- http://git-wip-us.apache.org/repos/asf/camel/blob/438700a1/camel-core/src/main/java/org/apache/camel/component/xslt/XsltComponent.java ---------------------------------------------------------------------- diff --git a/camel-core/src/main/java/org/apache/camel/component/xslt/XsltComponent.java b/camel-core/src/main/java/org/apache/camel/component/xslt/XsltComponent.java index 7f4b0ad..999c8a8 100644 --- a/camel-core/src/main/java/org/apache/camel/component/xslt/XsltComponent.java +++ b/camel-core/src/main/java/org/apache/camel/component/xslt/XsltComponent.java @@ -17,17 +17,12 @@ package org.apache.camel.component.xslt; import java.util.Map; -import javax.xml.transform.ErrorListener; -import javax.xml.transform.TransformerFactory; import javax.xml.transform.URIResolver; import org.apache.camel.Endpoint; -import org.apache.camel.builder.xml.ResultHandlerFactory; -import org.apache.camel.builder.xml.XsltBuilder; import org.apache.camel.builder.xml.XsltUriResolver; import org.apache.camel.converter.jaxp.XmlConverter; import org.apache.camel.impl.UriEndpointComponent; -import org.apache.camel.util.ObjectHelper; import org.apache.camel.util.ResourceHelper; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -38,8 +33,8 @@ import org.slf4j.LoggerFactory; */ public class XsltComponent extends UriEndpointComponent { - private static final String SAXON_TRANSFORMER_FACTORY_CLASS_NAME = "net.sf.saxon.TransformerFactoryImpl"; private static final Logger LOG = LoggerFactory.getLogger(XsltComponent.class); + private XmlConverter xmlConverter; private URIResolver uriResolver; private boolean contentCache = true; @@ -82,69 +77,19 @@ public class XsltComponent extends UriEndpointComponent { } protected Endpoint createEndpoint(String uri, final String remaining, Map<String, Object> parameters) throws Exception { - String resourceUri = remaining; - LOG.debug("{} using schema resource: {}", this, resourceUri); - final XsltBuilder xslt = getCamelContext().getInjector().newInstance(XsltBuilder.class); - - // lets allow the converter to be configured - XmlConverter converter = resolveAndRemoveReferenceParameter(parameters, "converter", XmlConverter.class); - if (converter == null) { - converter = getXmlConverter(); - } - if (converter != null) { - xslt.setConverter(converter); - } - - String transformerFactoryClassName = getAndRemoveParameter(parameters, "transformerFactoryClass", String.class); - Boolean saxon = getAndRemoveParameter(parameters, "saxon", Boolean.class, isSaxon()); - if (transformerFactoryClassName == null && saxon) { - transformerFactoryClassName = SAXON_TRANSFORMER_FACTORY_CLASS_NAME; - } - - TransformerFactory factory = null; - if (transformerFactoryClassName != null) { - // provide the class loader of this component to work in OSGi environments - Class<?> factoryClass = getCamelContext().getClassResolver().resolveMandatoryClass(transformerFactoryClassName, XsltComponent.class.getClassLoader()); - LOG.debug("Using TransformerFactoryClass {}", factoryClass); - factory = (TransformerFactory) getCamelContext().getInjector().newInstance(factoryClass); - } - - if (parameters.get("transformerFactory") != null) { - factory = resolveAndRemoveReferenceParameter(parameters, "transformerFactory", TransformerFactory.class); - } - - if (factory != null) { - LOG.debug("Using TransformerFactory {}", factory); - xslt.getConverter().setTransformerFactory(factory); - } - - ResultHandlerFactory resultHandlerFactory = resolveAndRemoveReferenceParameter(parameters, "resultHandlerFactory", ResultHandlerFactory.class); - if (resultHandlerFactory != null) { - xslt.setResultHandlerFactory(resultHandlerFactory); - } + XsltEndpoint endpoint = new XsltEndpoint(uri, this); + endpoint.setConverter(getXmlConverter()); + endpoint.setContentCache(isContentCache()); + endpoint.setSaxon(isSaxon()); - Boolean failOnNullBody = getAndRemoveParameter(parameters, "failOnNullBody", Boolean.class); - if (failOnNullBody != null) { - xslt.setFailOnNullBody(failOnNullBody); - } - String output = getAndRemoveParameter(parameters, "output", String.class); - configureOutput(xslt, output); - - Integer cs = getAndRemoveParameter(parameters, "transformerCacheSize", Integer.class, 0); - xslt.transformerCacheSize(cs); - - ErrorListener errorListener = resolveAndRemoveReferenceParameter(parameters, "errorListener", ErrorListener.class); - if (errorListener != null) { - xslt.errorListener(errorListener); - } - - // default to use the cache option from the component if the endpoint did not have the contentCache parameter - boolean cache = getAndRemoveParameter(parameters, "contentCache", Boolean.class, contentCache); + String resourceUri = remaining; // if its a http uri, then append additional parameters as they are part of the uri if (ResourceHelper.isHttpUri(resourceUri)) { resourceUri = ResourceHelper.appendParameters(resourceUri, parameters); } + LOG.debug("{} using schema resource: {}", this, resourceUri); + endpoint.setResourceUri(resourceUri); // lookup custom resolver to use URIResolver resolver = resolveAndRemoveReferenceParameter(parameters, "uriResolver", URIResolver.class); @@ -156,34 +101,15 @@ public class XsltComponent extends UriEndpointComponent { // fallback to use a Camel specific resolver resolver = new XsltUriResolver(getCamelContext().getClassResolver(), remaining); } - // set resolver before input stream as resolver is used when loading the input stream - xslt.setUriResolver(resolver); - - configureXslt(xslt, uri, remaining, parameters); - - return new XsltEndpoint(uri, this, xslt, resourceUri, cache); - } + endpoint.setUriResolver(resolver); - protected void configureXslt(XsltBuilder xslt, String uri, String remaining, Map<String, Object> parameters) throws Exception { - setProperties(xslt, parameters); - } - - protected void configureOutput(XsltBuilder xslt, String output) throws Exception { - if (ObjectHelper.isEmpty(output)) { - return; + setProperties(endpoint, parameters); + if (!parameters.isEmpty()) { + // additional parameters need to be stored on endpoint as they can be used to configure xslt builder additionally + endpoint.setParameters(parameters); } - if ("string".equalsIgnoreCase(output)) { - xslt.outputString(); - } else if ("bytes".equalsIgnoreCase(output)) { - xslt.outputBytes(); - } else if ("DOM".equalsIgnoreCase(output)) { - xslt.outputDOM(); - } else if ("file".equalsIgnoreCase(output)) { - xslt.outputFile(); - } else { - throw new IllegalArgumentException("Unknown output type: " + output); - } + return endpoint; } } http://git-wip-us.apache.org/repos/asf/camel/blob/438700a1/camel-core/src/main/java/org/apache/camel/component/xslt/XsltEndpoint.java ---------------------------------------------------------------------- diff --git a/camel-core/src/main/java/org/apache/camel/component/xslt/XsltEndpoint.java b/camel-core/src/main/java/org/apache/camel/component/xslt/XsltEndpoint.java index a7075ee..0e6b92b 100644 --- a/camel-core/src/main/java/org/apache/camel/component/xslt/XsltEndpoint.java +++ b/camel-core/src/main/java/org/apache/camel/component/xslt/XsltEndpoint.java @@ -17,19 +17,27 @@ package org.apache.camel.component.xslt; import java.io.IOException; +import java.util.HashMap; +import java.util.Map; +import javax.xml.transform.ErrorListener; import javax.xml.transform.Source; import javax.xml.transform.TransformerException; +import javax.xml.transform.TransformerFactory; +import javax.xml.transform.URIResolver; import org.apache.camel.Component; import org.apache.camel.Exchange; import org.apache.camel.api.management.ManagedAttribute; import org.apache.camel.api.management.ManagedOperation; import org.apache.camel.api.management.ManagedResource; +import org.apache.camel.builder.xml.ResultHandlerFactory; import org.apache.camel.builder.xml.XsltBuilder; +import org.apache.camel.converter.jaxp.XmlConverter; import org.apache.camel.impl.ProcessorEndpoint; import org.apache.camel.spi.UriEndpoint; import org.apache.camel.spi.UriParam; import org.apache.camel.spi.UriPath; +import org.apache.camel.util.ObjectHelper; import org.apache.camel.util.ServiceHelper; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -39,20 +47,52 @@ import org.slf4j.LoggerFactory; public class XsltEndpoint extends ProcessorEndpoint { private static final Logger LOG = LoggerFactory.getLogger(XsltEndpoint.class); + private static final String SAXON_TRANSFORMER_FACTORY_CLASS_NAME = "net.sf.saxon.TransformerFactoryImpl"; private volatile boolean cacheCleared; - private XsltBuilder xslt; + private volatile XsltBuilder xslt; + private Map<String, Object> parameters; + @UriPath private String resourceUri; + @UriParam(defaultValue = "true") + private boolean contentCache = true; + @UriParam + private XmlConverter converter; + @UriParam + private String transformerFactoryClass; + @UriParam + private TransformerFactory transformerFactory; + @UriParam(defaultValue = "false") + private boolean saxon; + @UriParam + private ResultHandlerFactory resultHandlerFactory; + @UriParam(defaultValue = "true") + private boolean failOnNullBody = true; + @UriParam(defaultValue = "string") + private XsltOutput output = XsltOutput.string; + @UriParam(defaultValue = "0") + private int transformerCacheSize; + @UriParam + private ErrorListener errorListener; + @UriParam + private URIResolver uriResolver; + @UriParam(defaultValue = "true") + private boolean allowStAX = true; @UriParam(defaultValue = "false") - private boolean cacheStylesheet; + private boolean deleteOutputFile; + @Deprecated public XsltEndpoint(String endpointUri, Component component, XsltBuilder xslt, String resourceUri, boolean cacheStylesheet) throws Exception { super(endpointUri, component, xslt); this.xslt = xslt; this.resourceUri = resourceUri; - this.cacheStylesheet = cacheStylesheet; + this.contentCache = cacheStylesheet; + } + + public XsltEndpoint(String endpointUri, Component component) { + super(endpointUri, component); } @ManagedOperation(description = "Clears the cached XSLT stylesheet, forcing to re-load the stylesheet on next request") @@ -62,7 +102,7 @@ public class XsltEndpoint extends ProcessorEndpoint { @ManagedAttribute(description = "Whether the XSLT stylesheet is cached") public boolean isCacheStylesheet() { - return cacheStylesheet; + return contentCache; } @ManagedAttribute(description = "Endpoint State") @@ -88,12 +128,148 @@ public class XsltEndpoint extends ProcessorEndpoint { @Override protected void onExchange(Exchange exchange) throws Exception { - if (!cacheStylesheet || cacheCleared) { + if (!contentCache || cacheCleared) { loadResource(resourceUri); } super.onExchange(exchange); } + public boolean isCacheCleared() { + return cacheCleared; + } + + public void setCacheCleared(boolean cacheCleared) { + this.cacheCleared = cacheCleared; + } + + public XsltBuilder getXslt() { + return xslt; + } + + public void setXslt(XsltBuilder xslt) { + this.xslt = xslt; + } + + public String getResourceUri() { + return resourceUri; + } + + public void setResourceUri(String resourceUri) { + this.resourceUri = resourceUri; + } + + public XmlConverter getConverter() { + return converter; + } + + public void setConverter(XmlConverter converter) { + this.converter = converter; + } + + public String getTransformerFactoryClass() { + return transformerFactoryClass; + } + + public void setTransformerFactoryClass(String transformerFactoryClass) { + this.transformerFactoryClass = transformerFactoryClass; + } + + public TransformerFactory getTransformerFactory() { + return transformerFactory; + } + + public void setTransformerFactory(TransformerFactory transformerFactory) { + this.transformerFactory = transformerFactory; + } + + public boolean isSaxon() { + return saxon; + } + + public void setSaxon(boolean saxon) { + this.saxon = saxon; + } + + public ResultHandlerFactory getResultHandlerFactory() { + return resultHandlerFactory; + } + + public void setResultHandlerFactory(ResultHandlerFactory resultHandlerFactory) { + this.resultHandlerFactory = resultHandlerFactory; + } + + public boolean isFailOnNullBody() { + return failOnNullBody; + } + + public void setFailOnNullBody(boolean failOnNullBody) { + this.failOnNullBody = failOnNullBody; + } + + public XsltOutput getOutput() { + return output; + } + + public void setOutput(XsltOutput output) { + this.output = output; + } + + public int getTransformerCacheSize() { + return transformerCacheSize; + } + + public void setTransformerCacheSize(int transformerCacheSize) { + this.transformerCacheSize = transformerCacheSize; + } + + public ErrorListener getErrorListener() { + return errorListener; + } + + public void setErrorListener(ErrorListener errorListener) { + this.errorListener = errorListener; + } + + public boolean isContentCache() { + return contentCache; + } + + public void setContentCache(boolean contentCache) { + this.contentCache = contentCache; + } + + public URIResolver getUriResolver() { + return uriResolver; + } + + public void setUriResolver(URIResolver uriResolver) { + this.uriResolver = uriResolver; + } + + public boolean isAllowStAX() { + return allowStAX; + } + + public void setAllowStAX(boolean allowStAX) { + this.allowStAX = allowStAX; + } + + public boolean isDeleteOutputFile() { + return deleteOutputFile; + } + + public void setDeleteOutputFile(boolean deleteOutputFile) { + this.deleteOutputFile = deleteOutputFile; + } + + public Map<String, Object> getParameters() { + return parameters; + } + + public void setParameters(Map<String, Object> parameters) { + this.parameters = parameters; + } + /** * Loads the resource. * @@ -117,14 +293,79 @@ public class XsltEndpoint extends ProcessorEndpoint { protected void doStart() throws Exception { super.doStart(); + LOG.debug("{} using schema resource: {}", this, resourceUri); + + this.xslt = getCamelContext().getInjector().newInstance(XsltBuilder.class); + if (converter != null) { + xslt.setConverter(converter); + } + + if (transformerFactoryClass == null && saxon) { + transformerFactoryClass = SAXON_TRANSFORMER_FACTORY_CLASS_NAME; + } + + TransformerFactory factory = transformerFactory; + if (factory == null && transformerFactoryClass != null) { + // provide the class loader of this component to work in OSGi environments + Class<?> factoryClass = getCamelContext().getClassResolver().resolveMandatoryClass(transformerFactoryClass, XsltComponent.class.getClassLoader()); + LOG.debug("Using TransformerFactoryClass {}", factoryClass); + factory = (TransformerFactory) getCamelContext().getInjector().newInstance(factoryClass); + } + + if (factory != null) { + LOG.debug("Using TransformerFactory {}", factory); + xslt.getConverter().setTransformerFactory(factory); + } + if (resultHandlerFactory != null) { + xslt.setResultHandlerFactory(resultHandlerFactory); + } + if (errorListener != null) { + xslt.errorListener(errorListener); + } + xslt.setFailOnNullBody(failOnNullBody); + xslt.transformerCacheSize(transformerCacheSize); + xslt.setUriResolver(uriResolver); + xslt.setAllowStAX(allowStAX); + xslt.setDeleteOutputFile(deleteOutputFile); + + configureOutput(xslt, output.name()); + + // any additional transformer parameters then make a copy to avoid side-effects + if (parameters != null) { + Map<String, Object> copy = new HashMap<>(parameters); + xslt.setParameters(copy); + } + // must load resource first which sets a template and do a stylesheet compilation to catch errors early loadResource(resourceUri); // and then inject camel context and start service xslt.setCamelContext(getCamelContext()); + + // the processor is the xslt builder + setProcessor(xslt); + ServiceHelper.startService(xslt); } + protected void configureOutput(XsltBuilder xslt, String output) throws Exception { + if (ObjectHelper.isEmpty(output)) { + return; + } + + if ("string".equalsIgnoreCase(output)) { + xslt.outputString(); + } else if ("bytes".equalsIgnoreCase(output)) { + xslt.outputBytes(); + } else if ("DOM".equalsIgnoreCase(output)) { + xslt.outputDOM(); + } else if ("file".equalsIgnoreCase(output)) { + xslt.outputFile(); + } else { + throw new IllegalArgumentException("Unknown output type: " + output); + } + } + @Override protected void doStop() throws Exception { super.doStop(); http://git-wip-us.apache.org/repos/asf/camel/blob/438700a1/camel-core/src/main/java/org/apache/camel/component/xslt/XsltOutput.java ---------------------------------------------------------------------- diff --git a/camel-core/src/main/java/org/apache/camel/component/xslt/XsltOutput.java b/camel-core/src/main/java/org/apache/camel/component/xslt/XsltOutput.java new file mode 100644 index 0000000..5b846aa --- /dev/null +++ b/camel-core/src/main/java/org/apache/camel/component/xslt/XsltOutput.java @@ -0,0 +1,24 @@ +/** + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You 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.apache.camel.component.xslt; + +public enum XsltOutput { + + string, bytes, DOM, file + +} + http://git-wip-us.apache.org/repos/asf/camel/blob/438700a1/camel-core/src/test/java/org/apache/camel/component/xslt/XsltComponentConfigurationAndDocumentationTest.java ---------------------------------------------------------------------- diff --git a/camel-core/src/test/java/org/apache/camel/component/xslt/XsltComponentConfigurationAndDocumentationTest.java b/camel-core/src/test/java/org/apache/camel/component/xslt/XsltComponentConfigurationAndDocumentationTest.java index 4de8f63..aaaf8e2 100644 --- a/camel-core/src/test/java/org/apache/camel/component/xslt/XsltComponentConfigurationAndDocumentationTest.java +++ b/camel-core/src/test/java/org/apache/camel/component/xslt/XsltComponentConfigurationAndDocumentationTest.java @@ -41,7 +41,7 @@ public class XsltComponentConfigurationAndDocumentationTest extends ContextTestS String json = compConf.createParameterJsonSchema(); assertNotNull(json); - assertTrue(json.contains("\"resourceUri\": { \"type\": \"string\"")); + assertTrue(json.contains("\"contentCache\": { \"type\": \"boolean\", \"javaType\": \"boolean\" }")); assertTrue(json.contains("\"synchronous\": { \"type\": \"boolean\"")); } http://git-wip-us.apache.org/repos/asf/camel/blob/438700a1/camel-core/src/test/java/org/apache/camel/component/xslt/XsltReferenceParameterTest.java ---------------------------------------------------------------------- diff --git a/camel-core/src/test/java/org/apache/camel/component/xslt/XsltReferenceParameterTest.java b/camel-core/src/test/java/org/apache/camel/component/xslt/XsltReferenceParameterTest.java index 4e4d469..fd7b7f8 100644 --- a/camel-core/src/test/java/org/apache/camel/component/xslt/XsltReferenceParameterTest.java +++ b/camel-core/src/test/java/org/apache/camel/component/xslt/XsltReferenceParameterTest.java @@ -35,14 +35,11 @@ public class XsltReferenceParameterTest extends TestSupport { private static final String TEST_URI_1 = "xslt:org/apache/camel/component/xslt/transform.xsl?converter=#testConverter&transformerFactory=#testTransformerFactory"; - private static final String TEST_URI_2 = - "xslt:org/apache/camel/component/xslt/transform.xsl?converter=testConverter&transformerFactory=testTransformerFactory"; private TestConverter testConverter; private TransformerFactory testTransformerFactory; private XsltBuilder builder1; - private XsltBuilder builder2; public void setUp() throws Exception { JndiRegistry registry = new JndiRegistry(new JndiContext()); @@ -56,10 +53,8 @@ public class XsltReferenceParameterTest extends TestSupport { registry.bind("testTransformerFactory", testTransformerFactory); ProcessorEndpoint pep1 = context.getEndpoint(TEST_URI_1, ProcessorEndpoint.class); - ProcessorEndpoint pep2 = context.getEndpoint(TEST_URI_2, ProcessorEndpoint.class); builder1 = (XsltBuilder)pep1.getProcessor(); - builder2 = (XsltBuilder)pep2.getProcessor(); context.addRoutes(builder); context.start(); @@ -67,19 +62,16 @@ public class XsltReferenceParameterTest extends TestSupport { public void testConverterReference() { assertSame(testConverter, builder1.getConverter()); - assertSame(testConverter, builder2.getConverter()); } public void testTransformerFactoryReference() { assertSame(testTransformerFactory, builder1.getConverter().getTransformerFactory()); - assertSame(testTransformerFactory, builder2.getConverter().getTransformerFactory()); } protected RouteBuilder createRouteBuilder() throws Exception { return new RouteBuilder() { public void configure() throws Exception { from("direct:a").to(TEST_URI_1); - from("direct:b").to(TEST_URI_2); } }; } http://git-wip-us.apache.org/repos/asf/camel/blob/438700a1/camel-core/src/test/resources/log4j.properties ---------------------------------------------------------------------- diff --git a/camel-core/src/test/resources/log4j.properties b/camel-core/src/test/resources/log4j.properties index c3eb9f7..66c0278 100644 --- a/camel-core/src/test/resources/log4j.properties +++ b/camel-core/src/test/resources/log4j.properties @@ -22,7 +22,7 @@ log4j.rootLogger=INFO, file log4j.logger.org.apache.camel.customlogger=TRACE, file2 #log4j.logger.org.apache.camel.impl.converter=WARN -#log4j.logger.org.apache.camel.management=WARN +#log4j.logger.org.apache.camel.management=DEBUG log4j.logger.org.apache.camel.impl.DefaultPackageScanClassResolver=WARN #log4j.logger.org.apache.camel.impl.converter.DefaultTypeConverter=TRACE #log4j.logger.org.apache.camel.impl.converter=DEBUG