This is an automated email from the ASF dual-hosted git repository.
acosentino pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/camel.git
commit 1565c94164230e8a95b1c266d147c552cf797a41
Author: Marc Giger <giger@apache.org>
AuthorDate: Wed Aug 21 18:15:39 2019 +0200
CAMEL-13851: Refactoring to reuse as much code as possible from the xslt component
---
.../camel/component/xj/JsonFileResultHandler.java | 22 +-
.../component/xj/JsonFileResultHandlerFactory.java | 14 +-
.../component/xj/JsonSourceHandlerFactoryImpl.java | 33 +-
.../component/xj/JsonStreamResultHandler.java | 22 +-
.../xj/JsonStreamResultHandlerFactory.java | 10 +
.../component/xj/JsonStringResultHandler.java | 22 +-
.../xj/JsonStringResultHandlerFactory.java | 11 +
.../camel/component/xj/JsonXmlStreamReader.java | 15 +-
.../camel/component/xj/TransformDirection.java | 3 +
.../org/apache/camel/component/xj/XJComponent.java | 178 +-------
.../org/apache/camel/component/xj/XJConstants.java | 33 +-
.../org/apache/camel/component/xj/XJEndpoint.java | 496 ++-------------------
.../camel/component/xj/XmlJsonStreamWriter.java | 18 +-
.../org/apache/camel/component/xj/XsltBuilder.java | 482 --------------------
.../org/apache/camel/component/xj/XsltHelper.java | 104 -----
.../component/xslt}/SourceHandlerFactory.java | 15 +-
.../xslt}/XmlSourceHandlerFactoryImpl.java | 62 ++-
.../apache/camel/component/xslt/XsltBuilder.java | 137 ++----
.../apache/camel/component/xslt/XsltComponent.java | 19 +-
.../apache/camel/component/xslt/XsltEndpoint.java | 19 +-
.../endpoint/dsl/XJEndpointBuilderFactory.java | 96 ++--
21 files changed, 391 insertions(+), 1420 deletions(-)
diff --git a/components/camel-xj/src/main/java/org/apache/camel/component/xj/JsonFileResultHandler.java b/components/camel-xj/src/main/java/org/apache/camel/component/xj/JsonFileResultHandler.java
index 5d6f2c1..538976f 100644
--- a/components/camel-xj/src/main/java/org/apache/camel/component/xj/JsonFileResultHandler.java
+++ b/components/camel-xj/src/main/java/org/apache/camel/component/xj/JsonFileResultHandler.java
@@ -16,32 +16,46 @@
*/
package org.apache.camel.component.xj;
+import java.io.File;
+
+import javax.xml.transform.Result;
+import javax.xml.transform.stax.StAXResult;
+
import com.fasterxml.jackson.core.JsonEncoding;
import com.fasterxml.jackson.core.JsonFactory;
import com.fasterxml.jackson.core.JsonGenerator;
import org.apache.camel.Message;
import org.apache.camel.component.xslt.ResultHandler;
-import javax.xml.transform.Result;
-import javax.xml.transform.stax.StAXResult;
-import java.io.File;
-
+/**
+ * Result handler impl. to write a json document into a {@link File}
+ */
public class JsonFileResultHandler implements ResultHandler {
private final File file;
private final Result result;
+ /**
+ * Creates a new json to file result handler instance
+ * @param jsonFactory the {@link JsonFactory} to use to write the json.
+ */
public JsonFileResultHandler(JsonFactory jsonFactory, File file) throws Exception {
this.file = file;
final JsonGenerator jsonGenerator = jsonFactory.createGenerator(this.file, JsonEncoding.UTF8);
this.result = new StAXResult(new XmlJsonStreamWriter(jsonGenerator));
}
+ /**
+ * {@inheritDoc}
+ */
@Override
public Result getResult() {
return this.result;
}
+ /**
+ * {@inheritDoc}
+ */
@Override
public void setBody(Message in) {
in.setBody(this.file);
diff --git a/components/camel-xj/src/main/java/org/apache/camel/component/xj/JsonFileResultHandlerFactory.java b/components/camel-xj/src/main/java/org/apache/camel/component/xj/JsonFileResultHandlerFactory.java
index 0b065ac..d56a320 100644
--- a/components/camel-xj/src/main/java/org/apache/camel/component/xj/JsonFileResultHandlerFactory.java
+++ b/components/camel-xj/src/main/java/org/apache/camel/component/xj/JsonFileResultHandlerFactory.java
@@ -16,21 +16,31 @@
*/
package org.apache.camel.component.xj;
+import java.io.File;
+
import com.fasterxml.jackson.core.JsonFactory;
import org.apache.camel.Exchange;
import org.apache.camel.component.xslt.ResultHandler;
import org.apache.camel.component.xslt.ResultHandlerFactory;
import org.apache.camel.support.ExchangeHelper;
-import java.io.File;
-
+/**
+ * {@JsonFileResultHandler} factory
+ */
public class JsonFileResultHandlerFactory implements ResultHandlerFactory {
private final JsonFactory jsonFactory;
+ /**
+ * Creates a new json to file result handler factory
+ * @param jsonFactory the {@link JsonFactory} to use to write the json.
+ */
public JsonFileResultHandlerFactory(JsonFactory jsonFactory) {
this.jsonFactory = jsonFactory;
}
+ /**
+ * {@inheritDoc}
+ */
@Override
public ResultHandler createResult(Exchange exchange) throws Exception {
final String fileName = ExchangeHelper.getMandatoryHeader(exchange, Exchange.XSLT_FILE_NAME, String.class);
diff --git a/components/camel-xj/src/main/java/org/apache/camel/component/xj/JsonSourceHandlerFactoryImpl.java b/components/camel-xj/src/main/java/org/apache/camel/component/xj/JsonSourceHandlerFactoryImpl.java
index 5959c86..9ba17a8 100644
--- a/components/camel-xj/src/main/java/org/apache/camel/component/xj/JsonSourceHandlerFactoryImpl.java
+++ b/components/camel-xj/src/main/java/org/apache/camel/component/xj/JsonSourceHandlerFactoryImpl.java
@@ -16,35 +16,54 @@
*/
package org.apache.camel.component.xj;
-import com.fasterxml.jackson.core.JsonFactory;
-import com.fasterxml.jackson.core.JsonParser;
-import org.apache.camel.Exchange;
-import org.apache.camel.ExpectedBodyTypeException;
+import java.io.File;
+import java.io.InputStream;
+import java.io.Reader;
import javax.xml.stream.XMLStreamReader;
import javax.xml.transform.Source;
import javax.xml.transform.stax.StAXSource;
-import java.io.File;
-import java.io.InputStream;
-import java.io.Reader;
+import com.fasterxml.jackson.core.JsonFactory;
+import com.fasterxml.jackson.core.JsonParser;
+import org.apache.camel.Exchange;
+import org.apache.camel.ExpectedBodyTypeException;
+import org.apache.camel.component.xslt.SourceHandlerFactory;
+
+/**
+ * Handler for json sources
+ */
public class JsonSourceHandlerFactoryImpl implements SourceHandlerFactory {
private JsonFactory jsonFactory;
private boolean isFailOnNullBody = true;
+ /**
+ * Creates a new instance
+ * @param jsonFactory the jsonFactory to use to read the json document
+ */
public JsonSourceHandlerFactoryImpl(JsonFactory jsonFactory) {
this.jsonFactory = jsonFactory;
}
+ /**
+ * Returns if we fail when the body is null
+ */
public boolean isFailOnNullBody() {
return isFailOnNullBody;
}
+ /**
+ * Set if we should fail when the body is null
+ * @param failOnNullBody
+ */
public void setFailOnNullBody(boolean failOnNullBody) {
isFailOnNullBody = failOnNullBody;
}
+ /**
+ * {@inheritDoc}
+ */
@Override
public Source getSource(Exchange exchange) throws Exception {
Object body = exchange.getIn().getBody();
diff --git a/components/camel-xj/src/main/java/org/apache/camel/component/xj/JsonStreamResultHandler.java b/components/camel-xj/src/main/java/org/apache/camel/component/xj/JsonStreamResultHandler.java
index 809e710..4bf71f1 100644
--- a/components/camel-xj/src/main/java/org/apache/camel/component/xj/JsonStreamResultHandler.java
+++ b/components/camel-xj/src/main/java/org/apache/camel/component/xj/JsonStreamResultHandler.java
@@ -16,32 +16,46 @@
*/
package org.apache.camel.component.xj;
+import java.io.ByteArrayOutputStream;
+
+import javax.xml.transform.Result;
+import javax.xml.transform.stax.StAXResult;
+
import com.fasterxml.jackson.core.JsonEncoding;
import com.fasterxml.jackson.core.JsonFactory;
import com.fasterxml.jackson.core.JsonGenerator;
import org.apache.camel.Message;
import org.apache.camel.component.xslt.ResultHandler;
-import javax.xml.transform.Result;
-import javax.xml.transform.stax.StAXResult;
-import java.io.ByteArrayOutputStream;
-
+/**
+ * Result handler impl. to write a json document into a {@ByteArrayOutputStream}
+ */
public class JsonStreamResultHandler implements ResultHandler {
private final ByteArrayOutputStream byteArrayOutputStream;
private final Result result;
+ /**
+ * Creates a new json to stream result handler instance
+ * @param jsonFactory the {@link JsonFactory} to use to write the json.
+ */
public JsonStreamResultHandler(JsonFactory jsonFactory) throws Exception {
this.byteArrayOutputStream = new ByteArrayOutputStream();
final JsonGenerator jsonGenerator = jsonFactory.createGenerator(this.byteArrayOutputStream, JsonEncoding.UTF8);
this.result = new StAXResult(new XmlJsonStreamWriter(jsonGenerator));
}
+ /**
+ * {@inheritDoc}
+ */
@Override
public Result getResult() {
return this.result;
}
+ /**
+ * {@inheritDoc}
+ */
@Override
public void setBody(Message in) {
in.setBody(this.byteArrayOutputStream.toByteArray());
diff --git a/components/camel-xj/src/main/java/org/apache/camel/component/xj/JsonStreamResultHandlerFactory.java b/components/camel-xj/src/main/java/org/apache/camel/component/xj/JsonStreamResultHandlerFactory.java
index f639086..f9034fe 100644
--- a/components/camel-xj/src/main/java/org/apache/camel/component/xj/JsonStreamResultHandlerFactory.java
+++ b/components/camel-xj/src/main/java/org/apache/camel/component/xj/JsonStreamResultHandlerFactory.java
@@ -21,13 +21,23 @@ import org.apache.camel.Exchange;
import org.apache.camel.component.xslt.ResultHandler;
import org.apache.camel.component.xslt.ResultHandlerFactory;
+/**
+ * {@JsonStreamResultHandler} factory
+ */
public class JsonStreamResultHandlerFactory implements ResultHandlerFactory {
private final JsonFactory jsonFactory;
+ /**
+ * Creates a new json to stream result handler factory
+ * @param jsonFactory the {@link JsonFactory} to use to write the json.
+ */
public JsonStreamResultHandlerFactory(JsonFactory jsonFactory) {
this.jsonFactory = jsonFactory;
}
+ /**
+ * {@inheritDoc}
+ */
@Override
public ResultHandler createResult(Exchange exchange) throws Exception {
return new JsonStreamResultHandler(jsonFactory);
diff --git a/components/camel-xj/src/main/java/org/apache/camel/component/xj/JsonStringResultHandler.java b/components/camel-xj/src/main/java/org/apache/camel/component/xj/JsonStringResultHandler.java
index 61e12ea..7abf4e0 100644
--- a/components/camel-xj/src/main/java/org/apache/camel/component/xj/JsonStringResultHandler.java
+++ b/components/camel-xj/src/main/java/org/apache/camel/component/xj/JsonStringResultHandler.java
@@ -16,31 +16,45 @@
*/
package org.apache.camel.component.xj;
+import java.io.StringWriter;
+
+import javax.xml.transform.Result;
+import javax.xml.transform.stax.StAXResult;
+
import com.fasterxml.jackson.core.JsonFactory;
import com.fasterxml.jackson.core.JsonGenerator;
import org.apache.camel.Message;
import org.apache.camel.component.xslt.ResultHandler;
-import javax.xml.transform.Result;
-import javax.xml.transform.stax.StAXResult;
-import java.io.StringWriter;
-
+/**
+ * Result handler impl. to write a json document into a {@link String}
+ */
public class JsonStringResultHandler implements ResultHandler {
private final StringWriter stringWriter;
private final Result result;
+ /**
+ * Creates a new json to string result handler instance
+ * @param jsonFactory the {@link JsonFactory} to use to write the json.
+ */
public JsonStringResultHandler(JsonFactory jsonFactory) throws Exception {
this.stringWriter = new StringWriter();
final JsonGenerator jsonGenerator = jsonFactory.createGenerator(this.stringWriter);
this.result = new StAXResult(new XmlJsonStreamWriter(jsonGenerator));
}
+ /**
+ * {@inheritDoc}
+ */
@Override
public Result getResult() {
return this.result;
}
+ /**
+ * {@inheritDoc}
+ */
@Override
public void setBody(Message in) {
in.setBody(this.stringWriter.toString());
diff --git a/components/camel-xj/src/main/java/org/apache/camel/component/xj/JsonStringResultHandlerFactory.java b/components/camel-xj/src/main/java/org/apache/camel/component/xj/JsonStringResultHandlerFactory.java
index e2991fc..c534c68 100644
--- a/components/camel-xj/src/main/java/org/apache/camel/component/xj/JsonStringResultHandlerFactory.java
+++ b/components/camel-xj/src/main/java/org/apache/camel/component/xj/JsonStringResultHandlerFactory.java
@@ -21,13 +21,24 @@ import org.apache.camel.Exchange;
import org.apache.camel.component.xslt.ResultHandler;
import org.apache.camel.component.xslt.ResultHandlerFactory;
+/**
+ * {@JsonStringResultHandler} factory
+ */
public class JsonStringResultHandlerFactory implements ResultHandlerFactory {
+
private final JsonFactory jsonFactory;
+ /**
+ * Creates a new json to string result handler factory
+ * @param jsonFactory the {@link JsonFactory} to use to write the json.
+ */
public JsonStringResultHandlerFactory(JsonFactory jsonFactory) {
this.jsonFactory = jsonFactory;
}
+ /**
+ * {@inheritDoc}
+ */
@Override
public ResultHandler createResult(Exchange exchange) throws Exception {
return new JsonStringResultHandler(jsonFactory);
diff --git a/components/camel-xj/src/main/java/org/apache/camel/component/xj/JsonXmlStreamReader.java b/components/camel-xj/src/main/java/org/apache/camel/component/xj/JsonXmlStreamReader.java
index 06106b5..b1d9e1a 100644
--- a/components/camel-xj/src/main/java/org/apache/camel/component/xj/JsonXmlStreamReader.java
+++ b/components/camel-xj/src/main/java/org/apache/camel/component/xj/JsonXmlStreamReader.java
@@ -17,8 +17,13 @@
package org.apache.camel.component.xj;
-import com.fasterxml.jackson.core.JsonParser;
-import com.fasterxml.jackson.core.JsonToken;
+import java.io.IOException;
+import java.util.ArrayDeque;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Deque;
+import java.util.List;
+import java.util.stream.Collectors;
import javax.xml.namespace.NamespaceContext;
import javax.xml.namespace.QName;
@@ -26,9 +31,9 @@ import javax.xml.stream.Location;
import javax.xml.stream.XMLStreamException;
import javax.xml.stream.XMLStreamReader;
import javax.xml.stream.events.XMLEvent;
-import java.io.IOException;
-import java.util.*;
-import java.util.stream.Collectors;
+
+import com.fasterxml.jackson.core.JsonParser;
+import com.fasterxml.jackson.core.JsonToken;
/**
* XML Json bridge. Explicitly using XMLStreamReader and not XMLEventReader because saxon wants that.
diff --git a/components/camel-xj/src/main/java/org/apache/camel/component/xj/TransformDirection.java b/components/camel-xj/src/main/java/org/apache/camel/component/xj/TransformDirection.java
index 73b0f2f..0cbf898 100644
--- a/components/camel-xj/src/main/java/org/apache/camel/component/xj/TransformDirection.java
+++ b/components/camel-xj/src/main/java/org/apache/camel/component/xj/TransformDirection.java
@@ -16,6 +16,9 @@
*/
package org.apache.camel.component.xj;
+/**
+ * Enum with the possible transform directions.
+ */
public enum TransformDirection {
XML2JSON,
JSON2XML
diff --git a/components/camel-xj/src/main/java/org/apache/camel/component/xj/XJComponent.java b/components/camel-xj/src/main/java/org/apache/camel/component/xj/XJComponent.java
index 030d560..18bd9d7 100644
--- a/components/camel-xj/src/main/java/org/apache/camel/component/xj/XJComponent.java
+++ b/components/camel-xj/src/main/java/org/apache/camel/component/xj/XJComponent.java
@@ -16,188 +16,20 @@
*/
package org.apache.camel.component.xj;
-import org.apache.camel.Endpoint;
-import org.apache.camel.component.xslt.DefaultXsltUriResolverFactory;
-import org.apache.camel.component.xslt.XsltUriResolverFactory;
-import org.apache.camel.spi.Metadata;
+import org.apache.camel.component.xslt.XsltComponent;
+import org.apache.camel.component.xslt.XsltEndpoint;
import org.apache.camel.spi.annotations.Component;
-import org.apache.camel.support.DefaultComponent;
-import org.apache.camel.support.EndpointHelper;
-import org.apache.camel.support.ResourceHelper;
-
-import javax.xml.transform.URIResolver;
-import java.util.HashMap;
-import java.util.List;
-import java.util.Map;
-
-// todo?: This class is just a copy of XsltComponent because of minor but important different requirements. Refactoring of XsltComponent so that we can extend it?
/**
* The <a href="http://camel.apache.org/xj.html">XJ Component</a> is for performing xml to json and back transformations of messages
*/
@Component("xj")
-public class XJComponent extends DefaultComponent {
-
- @Metadata(label = "advanced")
- private URIResolver uriResolver;
- @Metadata(label = "advanced")
- private XsltUriResolverFactory uriResolverFactory;
- @Metadata(label = "advanced")
- private Object saxonConfiguration;
- @Metadata(label = "advanced")
- private Map<String, Object> saxonConfigurationProperties = new HashMap<>();
- @Metadata(label = "advanced", javaType = "java.lang.String")
- private List<Object> saxonExtensionFunctions;
- @Metadata(defaultValue = "true")
- private boolean contentCache = true;
- @Metadata
- private boolean saxon;
+public class XJComponent extends XsltComponent {
public XJComponent() {
}
- public XsltUriResolverFactory getUriResolverFactory() {
- return uriResolverFactory;
- }
-
- /**
- * To use a custom UriResolver which depends on a dynamic endpoint resource URI. Should not be used together with the option 'uriResolver'.
- */
- public void setUriResolverFactory(XsltUriResolverFactory uriResolverFactory) {
- this.uriResolverFactory = uriResolverFactory;
- }
-
- public URIResolver getUriResolver() {
- return uriResolver;
- }
-
- /**
- * To use a custom UriResolver. Should not be used together with the option 'uriResolverFactory'.
- */
- public void setUriResolver(URIResolver uriResolver) {
- this.uriResolver = uriResolver;
- }
-
- public boolean isContentCache() {
- return contentCache;
- }
-
- /**
- * Cache for the resource content (the stylesheet file) when it is loaded.
- * If set to false Camel will reload the stylesheet file on each message processing. This is good for development.
- * A cached stylesheet can be forced to reload at runtime via JMX using the clearCachedStylesheet operation.
- */
- public void setContentCache(boolean contentCache) {
- this.contentCache = contentCache;
- }
-
- public boolean isSaxon() {
- return saxon;
- }
-
- /**
- * Whether to use Saxon as the transformerFactoryClass.
- * If enabled then the class net.sf.saxon.TransformerFactoryImpl. You would need to add Saxon to the classpath.
- */
- public void setSaxon(boolean saxon) {
- this.saxon = saxon;
- }
-
- public List<Object> getSaxonExtensionFunctions() {
- return saxonExtensionFunctions;
- }
-
- /**
- * Allows you to use a custom net.sf.saxon.lib.ExtensionFunctionDefinition.
- * You would need to add camel-saxon to the classpath.
- * The function is looked up in the registry, where you can comma to separate multiple values to lookup.
- */
- public void setSaxonExtensionFunctions(List<Object> extensionFunctions) {
- this.saxonExtensionFunctions = extensionFunctions;
- }
-
- /**
- * Allows you to use a custom net.sf.saxon.lib.ExtensionFunctionDefinition.
- * You would need to add camel-saxon to the classpath.
- * The function is looked up in the registry, where you can comma to separate multiple values to lookup.
- */
- public void setSaxonExtensionFunctions(String extensionFunctions) {
- this.saxonExtensionFunctions = EndpointHelper.resolveReferenceListParameter(
- getCamelContext(),
- extensionFunctions,
- Object.class
- );
- }
-
- public Object getSaxonConfiguration() {
- return saxonConfiguration;
- }
-
- /**
- * To use a custom Saxon configuration
- */
- public void setSaxonConfiguration(Object saxonConfiguration) {
- this.saxonConfiguration = saxonConfiguration;
- }
-
- public Map<String, Object> getSaxonConfigurationProperties() {
- return saxonConfigurationProperties;
- }
-
- /**
- * To set custom Saxon configuration properties
- */
- public void setSaxonConfigurationProperties(Map<String, Object> configurationProperties) {
- this.saxonConfigurationProperties = configurationProperties;
- }
-
- @Override
- protected Endpoint createEndpoint(String uri, final String remaining, Map<String, Object> parameters) throws Exception {
- XJEndpoint endpoint = new XJEndpoint(uri, this);
- endpoint.setContentCache(isContentCache());
- endpoint.setSaxon(isSaxon());
- endpoint.setSaxonConfiguration(saxonConfiguration);
- endpoint.setSaxonConfigurationProperties(saxonConfigurationProperties);
- endpoint.setSaxonExtensionFunctions(saxonExtensionFunctions);
-
- // lookup custom resolver to use
- URIResolver resolver = resolveAndRemoveReferenceParameter(parameters, "uriResolver", URIResolver.class);
- if (resolver == null) {
- // not in endpoint then use component specific resolver
- resolver = getUriResolver();
- }
- if (resolver == null) {
- // lookup custom resolver factory to use
- XsltUriResolverFactory resolverFactory = resolveAndRemoveReferenceParameter(parameters, "uriResolverFactory", XsltUriResolverFactory.class);
- if (resolverFactory == null) {
- // not in endpoint then use component specific resolver factory
- resolverFactory = getUriResolverFactory();
- }
- if (resolverFactory == null) {
- // fallback to use the Default URI resolver factory
- resolverFactory = new DefaultXsltUriResolverFactory();
- }
-
- resolver = resolverFactory.createUriResolver(getCamelContext(), remaining);
- }
- endpoint.setUriResolver(resolver);
-
- setProperties(endpoint, parameters);
-
- String resourceUri = remaining;
- if (ResourceHelper.isHttpUri(resourceUri)) {
- // if its a http uri, then append additional parameters as they are part of the uri
- resourceUri = ResourceHelper.appendParameters(resourceUri, parameters);
- }
- log.debug("{} using schema resource: {}", this, resourceUri);
- endpoint.setResourceUri(resourceUri);
-
- if (!parameters.isEmpty()) {
- // additional parameters need to be stored on endpoint as they can be used to configure xslt builder additionally
- endpoint.setParameters(parameters);
- }
-
- return endpoint;
+ protected XsltEndpoint createXsltEndpoint(String uri) {
+ return new XJEndpoint(uri, this);
}
-
}
diff --git a/components/camel-xj/src/main/java/org/apache/camel/component/xj/XJConstants.java b/components/camel-xj/src/main/java/org/apache/camel/component/xj/XJConstants.java
index 932a335..82ee635 100644
--- a/components/camel-xj/src/main/java/org/apache/camel/component/xj/XJConstants.java
+++ b/components/camel-xj/src/main/java/org/apache/camel/component/xj/XJConstants.java
@@ -17,24 +17,47 @@
package org.apache.camel.component.xj;
-import com.fasterxml.jackson.core.JsonToken;
-
import java.util.Collections;
import java.util.HashMap;
import java.util.Map;
+import com.fasterxml.jackson.core.JsonToken;
+
public class XJConstants {
+ /**
+ * The namespace used by xj for typehints
+ */
public static final String NS_XJ = "http://camel.apache.org/component/xj";
+
+ /**
+ * The namespace prefix used by xj for typehints
+ */
public static final String NS_PREFIX_XJ = "xj";
+ /**
+ * Name typehint. Used to instruct xj to write a field with that name when converting to json. On the otherhand
+ * when converting to xml xj writes the json field name in that attribute.
+ */
public static final String TYPE_HINT_NAME = "name";
+
+ /**
+ * JSON-Type hint. Used to instruct xj of which type the output is when converting to json. Otherwise when converting
+ * to xml the attribute holds the type that was in the original json document.
+ */
public static final String TYPE_HINT_TYPE = "type";
- public static final Map<JsonToken, String> JSONTYPE_TYPE_MAP;
- public static final Map<String, JsonToken> TYPE_JSONTYPE_MAP;
+ /**
+ * Mapping from json-types to typehint names
+ */
+ static final Map<JsonToken, String> JSONTYPE_TYPE_MAP;
+
+ /**
+ * Mapping from typehint names to json-types
+ */
+ static final Map<String, JsonToken> TYPE_JSONTYPE_MAP;
- public static final String UNSUPPORTED_OPERATION_EXCEPTION_MESSAGE = "unsupported / not yet implemented";
+ static final String UNSUPPORTED_OPERATION_EXCEPTION_MESSAGE = "unsupported / not yet implemented";
static {
final Map<JsonToken, String> jsonTypeTypeMap = new HashMap<>();
diff --git a/components/camel-xj/src/main/java/org/apache/camel/component/xj/XJEndpoint.java b/components/camel-xj/src/main/java/org/apache/camel/component/xj/XJEndpoint.java
index 59de196..9c80dd9 100644
--- a/components/camel-xj/src/main/java/org/apache/camel/component/xj/XJEndpoint.java
+++ b/components/camel-xj/src/main/java/org/apache/camel/component/xj/XJEndpoint.java
@@ -17,511 +17,105 @@
package org.apache.camel.component.xj;
import com.fasterxml.jackson.core.JsonFactory;
-import org.apache.camel.CamelContext;
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.component.xslt.ResultHandlerFactory;
-import org.apache.camel.component.xslt.XsltOutput;
-import org.apache.camel.spi.*;
-import org.apache.camel.support.EndpointHelper;
-import org.apache.camel.support.ProcessorEndpoint;
-import org.apache.camel.support.service.ServiceHelper;
+import org.apache.camel.component.xslt.XsltBuilder;
+import org.apache.camel.component.xslt.XsltEndpoint;
+import org.apache.camel.spi.Metadata;
+import org.apache.camel.spi.UriEndpoint;
+import org.apache.camel.spi.UriParam;
import org.apache.camel.util.ObjectHelper;
-import org.xml.sax.EntityResolver;
-
-import javax.xml.transform.*;
-import java.io.IOException;
-import java.util.HashMap;
-import java.util.List;
-import java.util.Map;
-
-// todo?: This class is just a copy of XsltEndpoint because of minor but important different requirements. Refactoring of XsltComponent so that we can extend it?
/**
* Transforms json/xml message back and forth using a XSLT.
*/
@ManagedResource(description = "Managed XJEndpoint")
-@UriEndpoint(firstVersion = "2.25.0", scheme = "xj", title = "XJ", syntax = "xj:resourceUri", producerOnly = true, label = "transformation")
-public class XJEndpoint extends ProcessorEndpoint {
-
- public static final String SAXON_TRANSFORMER_FACTORY_CLASS_NAME = "net.sf.saxon.TransformerFactoryImpl";
-
- private volatile boolean cacheCleared;
- private volatile XsltBuilder xslt;
- private Map<String, Object> parameters;
+@UriEndpoint(firstVersion = "3.0.0", scheme = "xj", title = "XJ", syntax = "xj:resourceUri", producerOnly = true, label = "transformation")
+public class XJEndpoint extends XsltEndpoint {
private JsonFactory jsonFactory = new JsonFactory();
@UriParam
- @Metadata(required = true)
+ @Metadata(required = true, description = "Transform direction. Either XML2JSON or JSON2XML")
private TransformDirection transformDirection;
- @UriPath
- @Metadata(required = true)
- private String resourceUri;
- @UriParam(defaultValue = "true")
- private boolean contentCache = true;
- @UriParam(label = "advanced")
- private String transformerFactoryClass;
- @UriParam(label = "advanced")
- private TransformerFactory transformerFactory;
- @UriParam
- private boolean saxon;
- @UriParam(label = "advanced")
- private Object saxonConfiguration;
- @Metadata(label = "advanced")
- private Map<String, Object> saxonConfigurationProperties = new HashMap<>();
- @UriParam(label = "advanced", javaType = "java.lang.String")
- private List<Object> saxonExtensionFunctions;
- @UriParam(label = "advanced")
- 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(label = "advanced")
- private ErrorListener errorListener;
- @UriParam(label = "advanced")
- private URIResolver uriResolver;
- @UriParam
- private boolean deleteOutputFile;
- @UriParam(label = "advanced")
- private EntityResolver entityResolver;
public XJEndpoint(String endpointUri, Component component) {
super(endpointUri, component);
}
- @ManagedOperation(description = "Clears the cached XSLT stylesheet, forcing to re-load the stylesheet on next request")
- public void clearCachedStylesheet() {
- this.cacheCleared = true;
- }
-
- @ManagedAttribute(description = "Whether the XSLT stylesheet is cached")
- public boolean isCacheStylesheet() {
- return contentCache;
- }
-
- public XJEndpoint findOrCreateEndpoint(String uri, String newResourceUri) {
- String newUri = uri.replace(resourceUri, newResourceUri);
- log.trace("Getting endpoint with URI: {}", newUri);
- return getCamelContext().getEndpoint(newUri, XJEndpoint.class);
- }
-
- @Override
- protected void onExchange(Exchange exchange) throws Exception {
- if (!contentCache || cacheCleared) {
- loadResource(resourceUri);
- }
- super.onExchange(exchange);
- }
-
@ManagedAttribute(description = "Transform direction")
public TransformDirection getTransformDirection() {
return transformDirection;
}
/**
- * The transform direction. Either XML2JSON or JSON2XML
+ * Sets the transform direction.
*/
public void setTransformDirection(TransformDirection transformDirection) {
this.transformDirection = transformDirection;
}
- 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;
- }
-
- @ManagedAttribute(description = "Path to the template")
- public String getResourceUri() {
- return resourceUri;
- }
-
- /**
- * Path to the template.
- * <p/>
- * The following is supported by the default URIResolver.
- * You can prefix with: classpath, file, http, ref, or bean.
- * classpath, file and http loads the resource using these protocols (classpath is default).
- * ref will lookup the resource in the registry.
- * bean will call a method on a bean to be used as the resource.
- * For bean you can specify the method name after dot, eg bean:myBean.myMethod
- *
- * @param resourceUri the resource path
- */
- public void setResourceUri(String resourceUri) {
- this.resourceUri = resourceUri;
- }
-
- public String getTransformerFactoryClass() {
- return transformerFactoryClass;
- }
-
- /**
- * To use a custom XSLT transformer factory, specified as a FQN class name
- */
- public void setTransformerFactoryClass(String transformerFactoryClass) {
- this.transformerFactoryClass = transformerFactoryClass;
- }
-
- public TransformerFactory getTransformerFactory() {
- return transformerFactory;
- }
-
- /**
- * To use a custom XSLT transformer factory
- */
- public void setTransformerFactory(TransformerFactory transformerFactory) {
- this.transformerFactory = transformerFactory;
- }
-
- @ManagedAttribute(description = "Whether to use Saxon as the transformerFactoryClass")
- public boolean isSaxon() {
- return saxon;
- }
-
- /**
- * Whether to use Saxon as the transformerFactoryClass.
- * If enabled then the class net.sf.saxon.TransformerFactoryImpl. You would need to add Saxon to the classpath.
- */
- public void setSaxon(boolean saxon) {
- this.saxon = saxon;
- }
-
- public List<Object> getSaxonExtensionFunctions() {
- return saxonExtensionFunctions;
- }
-
- /**
- * Allows you to use a custom net.sf.saxon.lib.ExtensionFunctionDefinition.
- * You would need to add camel-saxon to the classpath.
- * The function is looked up in the registry, where you can comma to separate multiple values to lookup.
- */
- public void setSaxonExtensionFunctions(List<Object> extensionFunctions) {
- this.saxonExtensionFunctions = extensionFunctions;
- }
-
- /**
- * Allows you to use a custom net.sf.saxon.lib.ExtensionFunctionDefinition.
- * You would need to add camel-saxon to the classpath.
- * The function is looked up in the registry, where you can comma to separate multiple values to lookup.
- */
- public void setSaxonExtensionFunctions(String extensionFunctions) {
- this.saxonExtensionFunctions = EndpointHelper.resolveReferenceListParameter(
- getCamelContext(),
- extensionFunctions,
- Object.class
- );
- }
-
- public Object getSaxonConfiguration() {
- return saxonConfiguration;
- }
-
- /**
- * To use a custom Saxon configuration
- */
- public void setSaxonConfiguration(Object saxonConfiguration) {
- this.saxonConfiguration = saxonConfiguration;
- }
-
- public Map<String, Object> getSaxonConfigurationProperties() {
- return saxonConfigurationProperties;
- }
-
- /**
- * To set custom Saxon configuration properties
- */
- public void setSaxonConfigurationProperties(Map<String, Object> configurationProperties) {
- this.saxonConfigurationProperties = configurationProperties;
- }
-
- public ResultHandlerFactory getResultHandlerFactory() {
- return resultHandlerFactory;
- }
-
- /**
- * Allows you to use a custom org.apache.camel.builder.xml.ResultHandlerFactory which is capable of
- * using custom org.apache.camel.builder.xml.ResultHandler types.
- */
- public void setResultHandlerFactory(ResultHandlerFactory resultHandlerFactory) {
- this.resultHandlerFactory = resultHandlerFactory;
- }
-
- @ManagedAttribute(description = "Whether or not to throw an exception if the input body is null")
- public boolean isFailOnNullBody() {
- return failOnNullBody;
- }
-
- /**
- * Whether or not to throw an exception if the input body is null.
- */
- public void setFailOnNullBody(boolean failOnNullBody) {
- this.failOnNullBody = failOnNullBody;
- }
-
- @ManagedAttribute(description = "What kind of option to use.")
- public XsltOutput getOutput() {
- return output;
- }
-
- /**
- * Option to specify which output type to use.
- * Possible values are: string, bytes, DOM, file. The first three options are all in memory based, where as file is streamed directly to a java.io.File.
- * For file you must specify the filename in the IN header with the key Exchange.XSLT_FILE_NAME which is also CamelXsltFileName.
- * Also any paths leading to the filename must be created beforehand, otherwise an exception is thrown at runtime.
- */
- public void setOutput(XsltOutput output) {
- this.output = output;
- }
-
- public int getTransformerCacheSize() {
- return transformerCacheSize;
- }
-
- /**
- * The number of javax.xml.transform.Transformer object that are cached for reuse to avoid calls to Template.newTransformer().
- */
- public void setTransformerCacheSize(int transformerCacheSize) {
- this.transformerCacheSize = transformerCacheSize;
- }
-
- public ErrorListener getErrorListener() {
- return errorListener;
- }
-
- /**
- * Allows to configure to use a custom javax.xml.transform.ErrorListener. Beware when doing this then the default error
- * listener which captures any errors or fatal errors and store information on the Exchange as properties is not in use.
- * So only use this option for special use-cases.
- */
- public void setErrorListener(ErrorListener errorListener) {
- this.errorListener = errorListener;
- }
-
- @ManagedAttribute(description = "Cache for the resource content (the stylesheet file) when it is loaded.")
- public boolean isContentCache() {
- return contentCache;
- }
-
- /**
- * Cache for the resource content (the stylesheet file) when it is loaded.
- * If set to false Camel will reload the stylesheet file on each message processing. This is good for development.
- * A cached stylesheet can be forced to reload at runtime via JMX using the clearCachedStylesheet operation.
- */
- public void setContentCache(boolean contentCache) {
- this.contentCache = contentCache;
- }
-
- public URIResolver getUriResolver() {
- return uriResolver;
- }
-
- /**
- * To use a custom javax.xml.transform.URIResolver
- */
- public void setUriResolver(URIResolver uriResolver) {
- this.uriResolver = uriResolver;
- }
-
- public boolean isDeleteOutputFile() {
- return deleteOutputFile;
- }
-
- /**
- * If you have output=file then this option dictates whether or not the output file should be deleted when the Exchange
- * is done processing. For example suppose the output file is a temporary file, then it can be a good idea to delete it after use.
- */
- public void setDeleteOutputFile(boolean deleteOutputFile) {
- this.deleteOutputFile = deleteOutputFile;
- }
-
- public EntityResolver getEntityResolver() {
- return entityResolver;
- }
-
- /**
- * To use a custom org.xml.sax.EntityResolver with javax.xml.transform.sax.SAXSource.
- */
- public void setEntityResolver(EntityResolver entityResolver) {
- this.entityResolver = entityResolver;
- }
-
- public Map<String, Object> getParameters() {
- return parameters;
- }
-
- /**
- * Additional parameters to configure on the javax.xml.transform.Transformer.
- */
- public void setParameters(Map<String, Object> parameters) {
- this.parameters = parameters;
- }
-
- /**
- * Loads the resource.
- *
- * @param resourceUri the resource to load
- * @throws TransformerException is thrown if error loading resource
- * @throws IOException is thrown if error loading resource
- */
- protected void loadResource(String resourceUri) throws TransformerException, IOException {
- log.trace("{} loading schema resource: {}", this, resourceUri);
- Source source = xslt.getUriResolver().resolve(resourceUri, null);
- if (source == null) {
- throw new IOException("Cannot load xsl resource " + resourceUri);
- } else {
- xslt.setTransformerSource(source);
- }
- // now loaded so clear flag
- cacheCleared = false;
- }
-
@Override
protected void doStart() throws Exception {
- super.doStart();
-
if (ObjectHelper.isEmpty(getResourceUri())) {
// todo using a stylesheet for "identity" transform is slow. But with transformerFactory we can't get an identity transformer...
setResourceUri("org/apache/camel/component/xj/identity.xsl");
}
- final CamelContext ctx = getCamelContext();
- final ClassResolver resolver = ctx.getClassResolver();
- final Injector injector = ctx.getInjector();
-
- log.debug("{} using schema resource: {}", this, resourceUri);
-
- this.xslt = new XsltBuilder();
-
- boolean useSaxon = false;
- if (transformerFactoryClass == null && (saxon || saxonExtensionFunctions != null)) {
- useSaxon = true;
- 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<TransformerFactory> factoryClass = resolver.resolveMandatoryClass(transformerFactoryClass, TransformerFactory.class, XJEndpoint.class.getClassLoader());
- log.debug("Using TransformerFactoryClass {}", factoryClass);
- factory = injector.newInstance(factoryClass);
+ super.doStart();
+ }
- if (useSaxon) {
- XsltHelper.registerSaxonConfiguration(ctx, factoryClass, factory, saxonConfiguration);
- XsltHelper.registerSaxonConfigurationProperties(ctx, factoryClass, factory, saxonConfigurationProperties);
- XsltHelper.registerSaxonExtensionFunctions(ctx, factoryClass, factory, saxonExtensionFunctions);
- }
- }
+ @Override
+ protected XsltBuilder createXsltBuilder() throws Exception {
+ final XsltBuilder xsltBuilder = super.createXsltBuilder();
+ xsltBuilder.setAllowStAX(true); // we rely on stax so always to true.
- if (factory != null) {
- log.debug("Using TransformerFactory {}", factory);
- xslt.setTransformerFactory(factory);
- }
- if (resultHandlerFactory != null) {
- xslt.setResultHandlerFactory(resultHandlerFactory);
- }
- if (this.transformDirection == TransformDirection.XML2JSON) {
- xslt.setSourceHandlerFactory(new XmlSourceHandlerFactoryImpl());
- } else {
- xslt.setSourceHandlerFactory(new JsonSourceHandlerFactoryImpl(jsonFactory));
- }
- if (errorListener != null) {
- xslt.errorListener(errorListener);
- }
- xslt.setFailOnNullBody(failOnNullBody);
- xslt.transformerCacheSize(transformerCacheSize);
- xslt.setUriResolver(uriResolver);
- xslt.setEntityResolver(entityResolver);
- xslt.setAllowStAX(true); // we rely on stax so always to true. No issues so far with jdk 1.8 and saxon xslt.
- xslt.setDeleteOutputFile(deleteOutputFile);
+ configureInput(xsltBuilder);
- configureOutput(xslt, output.name());
+ return xsltBuilder;
+ }
- // 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);
+ /**
+ * Configures the source input depending on the {@link XJEndpoint#transformDirection}
+ */
+ protected void configureInput(XsltBuilder xsltBuilder) {
+ if (TransformDirection.JSON2XML == this.transformDirection) {
+ final JsonSourceHandlerFactoryImpl sourceHandlerFactory = new JsonSourceHandlerFactoryImpl(jsonFactory);
+ sourceHandlerFactory.setFailOnNullBody(isFailOnNullBody());
+ xsltBuilder.setSourceHandlerFactory(sourceHandlerFactory);
}
-
- // must load resource first which sets a template and do a stylesheet compilation to catch errors early
- loadResource(resourceUri);
-
- // the processor is the xslt builder
- setProcessor(xslt);
+ // in the other direction, XML2JSON, the default org.apache.camel.component.xslt.XmlSourceHandlerFactoryImpl will be used
}
- protected void configureOutput(XsltBuilder xslt, String output) throws Exception {
+ /**
+ * Configures the result output depending on the {@link XJEndpoint#transformDirection}
+ */
+ protected void configureOutput(XsltBuilder xsltBuilder, String output) throws Exception {
switch (this.transformDirection) {
case JSON2XML:
- configureXmlOutput(xslt, output);
+ super.configureOutput(xsltBuilder, output);
break;
case XML2JSON:
- configureJsonOutput(xslt, output);
+ configureJsonOutput(xsltBuilder, output);
break;
default:
throw new IllegalArgumentException("Unknown transformation direction: " + this.transformDirection);
}
}
- protected void configureXmlOutput(XsltBuilder xslt, String output) throws Exception {
- if (ObjectHelper.isEmpty(output)) {
- return;
- }
-
- switch (output) {
- case "string":
- xslt.outputString();
- break;
- case "bytes":
- xslt.outputBytes();
- break;
- case "DOM":
- xslt.outputDOM();
- break;
- case "file":
- xslt.outputFile();
- break;
- default:
- throw new IllegalArgumentException("Unknown output type: " + output);
- }
- }
-
- protected void configureJsonOutput(XsltBuilder xslt, String output) throws Exception {
- switch (output) {
- case "bytes":
- xslt.setResultHandlerFactory(new JsonStreamResultHandlerFactory(jsonFactory));
- break;
- case "DOM":
- throw new UnsupportedOperationException("DOM output not supported when transforming to json");
- case "file":
- xslt.setResultHandlerFactory(new JsonFileResultHandlerFactory(jsonFactory));
- break;
- default:
- xslt.setResultHandlerFactory(new JsonStringResultHandlerFactory(jsonFactory));
- break;
+ /**
+ * Configures the result output when transforming to JSON
+ */
+ protected void configureJsonOutput(XsltBuilder xsltBuilder, String output) {
+ if ("DOM".equals(output)) {
+ throw new UnsupportedOperationException("DOM output not supported when transforming to json");
+ } else if ("bytes".equals(output)) {
+ xsltBuilder.setResultHandlerFactory(new JsonStreamResultHandlerFactory(jsonFactory));
+ } else if ("file".equals(output)) {
+ xsltBuilder.setResultHandlerFactory(new JsonFileResultHandlerFactory(jsonFactory));
+ } else {
+ xsltBuilder.setResultHandlerFactory(new JsonStringResultHandlerFactory(jsonFactory));
}
}
-
- @Override
- protected void doStop() throws Exception {
- super.doStop();
- ServiceHelper.stopService(xslt);
- }
}
diff --git a/components/camel-xj/src/main/java/org/apache/camel/component/xj/XmlJsonStreamWriter.java b/components/camel-xj/src/main/java/org/apache/camel/component/xj/XmlJsonStreamWriter.java
index ab64538..a9ef928 100644
--- a/components/camel-xj/src/main/java/org/apache/camel/component/xj/XmlJsonStreamWriter.java
+++ b/components/camel-xj/src/main/java/org/apache/camel/component/xj/XmlJsonStreamWriter.java
@@ -17,16 +17,24 @@
package org.apache.camel.component.xj;
-import com.fasterxml.jackson.core.JsonGenerator;
-import com.fasterxml.jackson.core.JsonToken;
+import java.io.IOException;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.Iterator;
+import java.util.LinkedHashSet;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+import java.util.stream.Collectors;
import javax.xml.namespace.NamespaceContext;
import javax.xml.stream.XMLStreamException;
import javax.xml.stream.XMLStreamWriter;
import javax.xml.stream.events.XMLEvent;
-import java.io.IOException;
-import java.util.*;
-import java.util.stream.Collectors;
+
+import com.fasterxml.jackson.core.JsonGenerator;
+import com.fasterxml.jackson.core.JsonToken;
/**
* XML Json bridge. Explicitly using StreamWriter and not XMLEventWriter because saxon wants that.
diff --git a/components/camel-xj/src/main/java/org/apache/camel/component/xj/XsltBuilder.java b/components/camel-xj/src/main/java/org/apache/camel/component/xj/XsltBuilder.java
deleted file mode 100644
index ea69c86..0000000
--- a/components/camel-xj/src/main/java/org/apache/camel/component/xj/XsltBuilder.java
+++ /dev/null
@@ -1,482 +0,0 @@
-/*
- * 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.xj;
-
-import org.apache.camel.Exchange;
-import org.apache.camel.Message;
-import org.apache.camel.Processor;
-import org.apache.camel.component.xslt.*;
-import org.apache.camel.support.ExchangeHelper;
-import org.apache.camel.support.SynchronizationAdapter;
-import org.apache.camel.support.builder.xml.XMLConverterHelper;
-import org.apache.camel.util.FileUtil;
-import org.apache.camel.util.IOHelper;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-import org.xml.sax.EntityResolver;
-
-import javax.xml.transform.*;
-import javax.xml.transform.sax.SAXSource;
-import javax.xml.transform.stream.StreamSource;
-import java.io.File;
-import java.io.IOException;
-import java.io.InputStream;
-import java.net.URL;
-import java.util.HashMap;
-import java.util.Map;
-import java.util.Set;
-import java.util.concurrent.ArrayBlockingQueue;
-import java.util.concurrent.BlockingQueue;
-
-import static org.apache.camel.util.ObjectHelper.notNull;
-
-// todo?: This class is just a copy from the XsltComponent because of minor but important different requirements. Refactoring of XsltComponent so that we can extend it?
-
-/**
- * Creates a <a href="http://camel.apache.org/processor.html">Processor</a>
- * which performs an XSLT transformation of the IN message body.
- * <p/>
- * Will by default output the result as a String. You can chose which kind of output
- * you want using the <tt>outputXXX</tt> methods.
- */
-public class XsltBuilder implements Processor {
-
- private static final Logger LOG = LoggerFactory.getLogger(XsltBuilder.class);
- private Map<String, Object> parameters = new HashMap<>();
- private XMLConverterHelper converter = new XMLConverterHelper();
- private Templates template;
- private volatile BlockingQueue<Transformer> transformers;
- private SourceHandlerFactory sourceHandlerFactory;
- private ResultHandlerFactory resultHandlerFactory = new StringResultHandlerFactory();
- private boolean failOnNullBody = true;
- private URIResolver uriResolver;
- private boolean deleteOutputFile;
- private ErrorListener errorListener;
- private boolean allowStAX = true;
- private EntityResolver entityResolver;
-
- public XsltBuilder() {
- }
-
- public XsltBuilder(Templates templates) {
- this.template = templates;
- }
-
- @Override
- public String toString() {
- return "XSLT[" + template + "]";
- }
-
- @Override
- public void process(Exchange exchange) throws Exception {
- notNull(getTemplate(), "template");
-
- if (isDeleteOutputFile()) {
- // add on completion so we can delete the file when the Exchange is done
- String fileName = ExchangeHelper.getMandatoryHeader(exchange, Exchange.XSLT_FILE_NAME, String.class);
- exchange.addOnCompletion(new XsltBuilderOnCompletion(fileName));
- }
-
- Transformer transformer = getTransformer();
- configureTransformer(transformer, exchange);
-
- ResultHandler resultHandler = resultHandlerFactory.createResult(exchange);
- Result result = resultHandler.getResult();
- // let's copy the headers before we invoke the transform in case they modify them
- Message out = exchange.getOut();
- out.copyFrom(exchange.getIn());
-
- // the underlying input stream, which we need to close to avoid locking files or other resources
- InputStream is = null;
- try {
- Source source = sourceHandlerFactory.getSource(exchange);
- if (source instanceof SAXSource) {
- tryAddEntityResolver((SAXSource) source);
- }
-
- LOG.trace("Using {} as source", source);
- transformer.transform(source, result);
- LOG.trace("Transform complete with result {}", result);
- resultHandler.setBody(out);
- } finally {
- releaseTransformer(transformer);
- // IOHelper can handle if is is null
- IOHelper.close(is);
- }
- }
-
- // Builder methods
- // -------------------------------------------------------------------------
-
- /**
- * Creates an XSLT processor using the given templates instance
- */
- public static XsltBuilder xslt(Templates templates) {
- return new XsltBuilder(templates);
- }
-
- /**
- * Creates an XSLT processor using the given XSLT source
- */
- public static XsltBuilder xslt(Source xslt) throws TransformerConfigurationException {
- notNull(xslt, "xslt");
- XsltBuilder answer = new XsltBuilder();
- answer.setTransformerSource(xslt);
- return answer;
- }
-
- /**
- * Creates an XSLT processor using the given XSLT source
- */
- public static XsltBuilder xslt(File xslt) throws TransformerConfigurationException {
- notNull(xslt, "xslt");
- return xslt(new StreamSource(xslt));
- }
-
- /**
- * Creates an XSLT processor using the given XSLT source
- */
- public static XsltBuilder xslt(URL xslt) throws TransformerConfigurationException, IOException {
- notNull(xslt, "xslt");
- return xslt(xslt.openStream());
- }
-
- /**
- * Creates an XSLT processor using the given XSLT source
- */
- public static XsltBuilder xslt(InputStream xslt) throws TransformerConfigurationException, IOException {
- notNull(xslt, "xslt");
- return xslt(new StreamSource(xslt));
- }
-
- /**
- * Sets the output as being a byte[]
- */
- public XsltBuilder outputBytes() {
- setResultHandlerFactory(new StreamResultHandlerFactory());
- return this;
- }
-
- /**
- * Sets the output as being a String
- */
- public XsltBuilder outputString() {
- setResultHandlerFactory(new StringResultHandlerFactory());
- return this;
- }
-
- /**
- * Sets the output as being a DOM
- */
- public XsltBuilder outputDOM() {
- setResultHandlerFactory(new DomResultHandlerFactory());
- return this;
- }
-
- /**
- * Sets the output as being a File where the filename
- * must be provided in the {@link Exchange#XSLT_FILE_NAME} header.
- */
- public XsltBuilder outputFile() {
- setResultHandlerFactory(new FileResultHandlerFactory());
- return this;
- }
-
- /**
- * Should the output file be deleted when the {@link Exchange} is done.
- * <p/>
- * This option should only be used if you use {@link #outputFile()} as well.
- */
- public XsltBuilder deleteOutputFile() {
- this.deleteOutputFile = true;
- return this;
- }
-
- public XsltBuilder parameter(String name, Object value) {
- parameters.put(name, value);
- return this;
- }
-
- /**
- * Sets a custom URI resolver to be used
- */
- public XsltBuilder uriResolver(URIResolver uriResolver) {
- setUriResolver(uriResolver);
- return this;
- }
-
- /**
- * Enables to allow using StAX.
- * <p/>
- * When enabled StAX is preferred as the first choice as {@link Source}.
- */
- public XsltBuilder allowStAX() {
- setAllowStAX(true);
- return this;
- }
-
- /**
- * Used for caching {@link Transformer}s.
- * <p/>
- * By default no caching is in use.
- *
- * @param numberToCache the maximum number of transformers to cache
- */
- public XsltBuilder transformerCacheSize(int numberToCache) {
- if (numberToCache > 0) {
- transformers = new ArrayBlockingQueue<>(numberToCache);
- } else {
- transformers = null;
- }
- return this;
- }
-
- /**
- * Uses a custom {@link ErrorListener}.
- */
- public XsltBuilder errorListener(ErrorListener errorListener) {
- setErrorListener(errorListener);
- return this;
- }
-
- // Properties
- // -------------------------------------------------------------------------
-
- public Map<String, Object> getParameters() {
- return parameters;
- }
-
- public void setParameters(Map<String, Object> parameters) {
- this.parameters = parameters;
- }
-
- public void setTemplate(Templates template) {
- this.template = template;
- if (transformers != null) {
- transformers.clear();
- }
- }
-
- public Templates getTemplate() {
- return template;
- }
-
- public boolean isFailOnNullBody() {
- return failOnNullBody;
- }
-
- public void setFailOnNullBody(boolean failOnNullBody) {
- this.failOnNullBody = failOnNullBody;
- }
-
- public SourceHandlerFactory getSourceHandlerFactory() {
- return sourceHandlerFactory;
- }
-
- public void setSourceHandlerFactory(SourceHandlerFactory sourceHandlerFactory) {
- this.sourceHandlerFactory = sourceHandlerFactory;
- }
-
- public ResultHandlerFactory getResultHandlerFactory() {
- return resultHandlerFactory;
- }
-
- public void setResultHandlerFactory(ResultHandlerFactory resultHandlerFactory) {
- this.resultHandlerFactory = resultHandlerFactory;
- }
-
- public boolean isAllowStAX() {
- return allowStAX;
- }
-
- public void setAllowStAX(boolean allowStAX) {
- this.allowStAX = allowStAX;
- }
-
- /**
- * Sets the XSLT transformer from a Source
- *
- * @param source the source
- * @throws TransformerConfigurationException is thrown if creating a XSLT transformer failed.
- */
- public void setTransformerSource(Source source) throws TransformerConfigurationException {
- TransformerFactory factory = converter.getTransformerFactory();
- if (errorListener != null) {
- factory.setErrorListener(errorListener);
- } else {
- // use a logger error listener so users can see from the logs what the error may be
- factory.setErrorListener(new XsltErrorListener());
- }
- if (getUriResolver() != null) {
- factory.setURIResolver(getUriResolver());
- }
-
- // Check that the call to newTemplates() returns a valid template instance.
- // In case of an xslt parse error, it will return null and we should stop the
- // deployment and raise an exception as the route will not be setup properly.
- Templates templates = factory.newTemplates(source);
- if (templates != null) {
- setTemplate(templates);
- } else {
- throw new TransformerConfigurationException("Error creating XSLT template. "
- + "This is most likely be caused by a XML parse error. "
- + "Please verify your XSLT file configured.");
- }
- }
-
- /**
- * Sets the XSLT transformer from a File
- */
- public void setTransformerFile(File xslt) throws TransformerConfigurationException {
- setTransformerSource(new StreamSource(xslt));
- }
-
- /**
- * Sets the XSLT transformer from a URL
- */
- public void setTransformerURL(URL url) throws TransformerConfigurationException, IOException {
- notNull(url, "url");
- setTransformerInputStream(url.openStream());
- }
-
- /**
- * Sets the XSLT transformer from the given input stream
- */
- public void setTransformerInputStream(InputStream in) throws TransformerConfigurationException, IOException {
- notNull(in, "InputStream");
- setTransformerSource(new StreamSource(in));
- }
-
- public URIResolver getUriResolver() {
- return uriResolver;
- }
-
- public void setUriResolver(URIResolver uriResolver) {
- this.uriResolver = uriResolver;
- }
-
- public void setEntityResolver(EntityResolver entityResolver) {
- this.entityResolver = entityResolver;
- }
-
- public boolean isDeleteOutputFile() {
- return deleteOutputFile;
- }
-
- public void setDeleteOutputFile(boolean deleteOutputFile) {
- this.deleteOutputFile = deleteOutputFile;
- }
-
- public ErrorListener getErrorListener() {
- return errorListener;
- }
-
- public void setErrorListener(ErrorListener errorListener) {
- this.errorListener = errorListener;
- }
-
- // Implementation methods
- // -------------------------------------------------------------------------
- public void setTransformerFactory(TransformerFactory transformerFactory) {
- this.converter.setTransformerFactory(transformerFactory);
- }
-
- private void releaseTransformer(Transformer transformer) {
- if (transformers != null) {
- transformer.reset();
- transformers.offer(transformer);
- }
- }
-
- private Transformer getTransformer() throws Exception {
- Transformer t = null;
- if (transformers != null) {
- t = transformers.poll();
- }
- if (t == null) {
- t = createTransformer();
- }
- return t;
- }
-
- protected Transformer createTransformer() throws Exception {
- return getTemplate().newTransformer();
- }
-
- private void tryAddEntityResolver(SAXSource source) {
- //expecting source to have not null XMLReader
- if (this.entityResolver != null && source != null) {
- source.getXMLReader().setEntityResolver(this.entityResolver);
- }
- }
-
- /**
- * Configures the transformer with exchange specific parameters
- */
- protected void configureTransformer(Transformer transformer, Exchange exchange) throws Exception {
- if (uriResolver == null) {
- uriResolver = new XsltUriResolver(exchange.getContext(), null);
- }
- transformer.setURIResolver(uriResolver);
- if (errorListener == null) {
- // set our error listener so we can capture errors and report them back on the exchange
- transformer.setErrorListener(new DefaultTransformErrorHandler(exchange));
- } else {
- // use custom error listener
- transformer.setErrorListener(errorListener);
- }
-
- transformer.clearParameters();
- addParameters(transformer, exchange.getProperties());
- addParameters(transformer, exchange.getIn().getHeaders());
- addParameters(transformer, getParameters());
- transformer.setParameter("exchange", exchange);
- transformer.setParameter("in", exchange.getIn());
- transformer.setParameter("out", exchange.getOut());
- }
-
- protected void addParameters(Transformer transformer, Map<String, Object> map) {
- Set<Map.Entry<String, Object>> propertyEntries = map.entrySet();
- for (Map.Entry<String, Object> entry : propertyEntries) {
- String key = entry.getKey();
- Object value = entry.getValue();
- if (value != null) {
- LOG.trace("Transformer set parameter {} -> {}", key, value);
- transformer.setParameter(key, value);
- }
- }
- }
-
- private static final class XsltBuilderOnCompletion extends SynchronizationAdapter {
- private final String fileName;
-
- private XsltBuilderOnCompletion(String fileName) {
- this.fileName = fileName;
- }
-
- @Override
- public void onDone(Exchange exchange) {
- FileUtil.deleteFile(new File(fileName));
- }
-
- @Override
- public String toString() {
- return "XsltBuilderOnCompletion";
- }
- }
-
-}
diff --git a/components/camel-xj/src/main/java/org/apache/camel/component/xj/XsltHelper.java b/components/camel-xj/src/main/java/org/apache/camel/component/xj/XsltHelper.java
deleted file mode 100644
index 1034aef..0000000
--- a/components/camel-xj/src/main/java/org/apache/camel/component/xj/XsltHelper.java
+++ /dev/null
@@ -1,104 +0,0 @@
-/*
- * 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.xj;
-
-import org.apache.camel.CamelContext;
-import org.apache.camel.component.xslt.XsltComponent;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-
-import javax.xml.XMLConstants;
-import javax.xml.transform.TransformerFactory;
-import java.lang.reflect.Method;
-import java.util.List;
-import java.util.Map;
-
-// todo 1:1 copy from XsltComponent
-
-final class XsltHelper {
- private static final Logger LOG = LoggerFactory.getLogger(XsltHelper.class);
-
- private static final String SAXON_CONFIGURATION_CLASS_NAME = "net.sf.saxon.Configuration";
- private static final String SAXON_EXTENDED_FUNCTION_DEFINITION_CLASS_NAME = "net.sf.saxon.lib.ExtensionFunctionDefinition";
-
- private XsltHelper() {
- }
-
- public static void registerSaxonConfiguration(
- CamelContext camelContext, Class<?> factoryClass, TransformerFactory factory, Object saxonConfiguration) throws Exception {
-
- if (saxonConfiguration != null) {
- Class<?> configurationClass = camelContext.getClassResolver().resolveClass(SAXON_CONFIGURATION_CLASS_NAME);
- if (configurationClass != null) {
- Method method = factoryClass.getMethod("setConfiguration", configurationClass);
- if (method != null) {
- method.invoke(factory, configurationClass.cast(saxonConfiguration));
- }
- }
- }
- }
-
- public static void registerSaxonConfigurationProperties(
- CamelContext camelContext, Class<?> factoryClass, TransformerFactory factory, Map<String, Object> saxonConfigurationProperties) throws Exception {
-
- if (saxonConfigurationProperties != null && !saxonConfigurationProperties.isEmpty()) {
- Method method = factoryClass.getMethod("getConfiguration");
- if (method != null) {
- Object configuration = method.invoke(factory);
- if (configuration != null) {
- method = configuration.getClass().getMethod("setConfigurationProperty", String.class, Object.class);
- for (Map.Entry<String, Object> entry : saxonConfigurationProperties.entrySet()) {
- method.invoke(configuration, entry.getKey(), entry.getValue());
- }
- }
- }
- }
- }
-
- public static void registerSaxonExtensionFunctions(
- CamelContext camelContext, Class<?> factoryClass, TransformerFactory factory, List<Object> saxonExtensionFunctions) throws Exception {
-
- if (saxonExtensionFunctions != null && !saxonExtensionFunctions.isEmpty()) {
- Method method = factoryClass.getMethod("getConfiguration");
- if (method != null) {
- Object configuration = method.invoke(factory);
- if (configuration != null) {
- Class<?> extensionClass = camelContext.getClassResolver().resolveMandatoryClass(
- SAXON_EXTENDED_FUNCTION_DEFINITION_CLASS_NAME, XsltComponent.class.getClassLoader()
- );
-
- method = configuration.getClass().getMethod("registerExtensionFunction", extensionClass);
- if (method != null) {
- factory.setFeature(XMLConstants.FEATURE_SECURE_PROCESSING, true);
- for (Object extensionFunction : saxonExtensionFunctions) {
- if (extensionClass.isInstance(extensionFunction)) {
- LOG.debug("Saxon.registerExtensionFunction {}", extensionFunction);
- method.invoke(configuration, extensionFunction);
- }
- }
- } else {
- LOG.warn("Unable to get reference to method registerExtensionFunction on {}", configuration.getClass().getName());
- }
- } else {
- LOG.warn("Unable to get Saxon configuration ({}) on {}", SAXON_CONFIGURATION_CLASS_NAME, factory.getClass().getName());
- }
- } else {
- LOG.warn("Unable to get reference to method getConfiguration on {}", factoryClass.getName());
- }
- }
- }
-}
diff --git a/components/camel-xj/src/main/java/org/apache/camel/component/xj/SourceHandlerFactory.java b/components/camel-xslt/src/main/java/org/apache/camel/component/xslt/SourceHandlerFactory.java
similarity index 72%
rename from components/camel-xj/src/main/java/org/apache/camel/component/xj/SourceHandlerFactory.java
rename to components/camel-xslt/src/main/java/org/apache/camel/component/xslt/SourceHandlerFactory.java
index 76898c1..7808a07 100644
--- a/components/camel-xj/src/main/java/org/apache/camel/component/xj/SourceHandlerFactory.java
+++ b/components/camel-xslt/src/main/java/org/apache/camel/component/xslt/SourceHandlerFactory.java
@@ -14,13 +14,22 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
-package org.apache.camel.component.xj;
-
-import org.apache.camel.Exchange;
+package org.apache.camel.component.xslt;
import javax.xml.transform.Source;
+import org.apache.camel.Exchange;
+
+/**
+ * Interface to be implemented by concrete source handlers/converters
+ */
public interface SourceHandlerFactory {
+ /**
+ * Creates a specific {@link Source} depending on the current message exchanged
+ * @param exchange the exchange
+ * @return the source created from the message
+ * @throws Exception if the source couldn't be created
+ */
Source getSource(Exchange exchange) throws Exception;
}
diff --git a/components/camel-xj/src/main/java/org/apache/camel/component/xj/XmlSourceHandlerFactoryImpl.java b/components/camel-xslt/src/main/java/org/apache/camel/component/xslt/XmlSourceHandlerFactoryImpl.java
similarity index 86%
rename from components/camel-xj/src/main/java/org/apache/camel/component/xj/XmlSourceHandlerFactoryImpl.java
rename to components/camel-xslt/src/main/java/org/apache/camel/component/xslt/XmlSourceHandlerFactoryImpl.java
index 230459d..eead2c1 100644
--- a/components/camel-xj/src/main/java/org/apache/camel/component/xj/XmlSourceHandlerFactoryImpl.java
+++ b/components/camel-xslt/src/main/java/org/apache/camel/component/xslt/XmlSourceHandlerFactoryImpl.java
@@ -14,14 +14,9 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
-package org.apache.camel.component.xj;
+package org.apache.camel.component.xslt;
-import org.apache.camel.Exchange;
-import org.apache.camel.ExpectedBodyTypeException;
-import org.apache.camel.RuntimeTransformException;
-import org.apache.camel.TypeConverter;
-import org.apache.camel.support.builder.xml.XMLConverterHelper;
-import org.w3c.dom.Node;
+import java.io.InputStream;
import javax.xml.parsers.ParserConfigurationException;
import javax.xml.transform.Source;
@@ -30,21 +25,61 @@ import javax.xml.transform.dom.DOMSource;
import javax.xml.transform.sax.SAXSource;
import javax.xml.transform.stax.StAXSource;
import javax.xml.transform.stream.StreamSource;
-import java.io.InputStream;
+import org.w3c.dom.Node;
+
+import org.apache.camel.Exchange;
+import org.apache.camel.ExpectedBodyTypeException;
+import org.apache.camel.RuntimeTransformException;
+import org.apache.camel.TypeConverter;
+import org.apache.camel.support.builder.xml.XMLConverterHelper;
+
+/**
+ * Handler for xml sources
+ */
public class XmlSourceHandlerFactoryImpl implements SourceHandlerFactory {
private XMLConverterHelper converter = new XMLConverterHelper();
private boolean isFailOnNullBody = true;
+ private boolean allowStax = true;
+
+ /**
+ * Returns true if we fail when the body is null.
+ */
+ public boolean isFailOnNullBody() {
+ return isFailOnNullBody;
+ }
+ /**
+ * Set if we should fail when the body is null
+ *
+ * @param failOnNullBody
+ */
public void setFailOnNullBody(boolean failOnNullBody) {
isFailOnNullBody = failOnNullBody;
}
- public boolean isFailOnNullBody() {
- return isFailOnNullBody;
+ /**
+ * Returns true if Stax is allowed
+ *
+ * @return
+ */
+ public boolean isAllowStax() {
+ return allowStax;
+ }
+
+ /**
+ * Sets if a {@link StAXSource} is allowed to read the document
+ *
+ * @param allowStax
+ */
+ public void setAllowStax(boolean allowStax) {
+ this.allowStax = allowStax;
}
+ /**
+ * {@inheritDoc}
+ */
@Override
public Source getSource(Exchange exchange) throws Exception {
// only convert to input stream if really needed
@@ -108,9 +143,10 @@ public class XmlSourceHandlerFactoryImpl implements SourceHandlerFactory {
}
Source source = null;
if (body != null) {
- // try StAX if enabled
- source = exchange.getContext().getTypeConverter().tryConvertTo(StAXSource.class, exchange, body);
-
+ if (isAllowStax()) {
+ // try StAX if enabled
+ source = exchange.getContext().getTypeConverter().tryConvertTo(StAXSource.class, exchange, body);
+ }
if (source == null) {
// then try SAX
source = exchange.getContext().getTypeConverter().tryConvertTo(SAXSource.class, exchange, body);
diff --git a/components/camel-xslt/src/main/java/org/apache/camel/component/xslt/XsltBuilder.java b/components/camel-xslt/src/main/java/org/apache/camel/component/xslt/XsltBuilder.java
index 95b6311..83a3c61 100644
--- a/components/camel-xslt/src/main/java/org/apache/camel/component/xslt/XsltBuilder.java
+++ b/components/camel-xslt/src/main/java/org/apache/camel/component/xslt/XsltBuilder.java
@@ -25,30 +25,23 @@ import java.util.Map;
import java.util.Set;
import java.util.concurrent.ArrayBlockingQueue;
import java.util.concurrent.BlockingQueue;
-import javax.xml.parsers.ParserConfigurationException;
import javax.xml.transform.ErrorListener;
import javax.xml.transform.Result;
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.URIResolver;
-import javax.xml.transform.dom.DOMSource;
import javax.xml.transform.sax.SAXSource;
import javax.xml.transform.stax.StAXSource;
import javax.xml.transform.stream.StreamSource;
-import org.w3c.dom.Node;
import org.xml.sax.EntityResolver;
import org.apache.camel.Exchange;
-import org.apache.camel.ExpectedBodyTypeException;
import org.apache.camel.Message;
import org.apache.camel.Processor;
-import org.apache.camel.RuntimeTransformException;
-import org.apache.camel.TypeConverter;
import org.apache.camel.support.ExchangeHelper;
import org.apache.camel.support.SynchronizationAdapter;
import org.apache.camel.support.builder.xml.StAX2SAXSource;
@@ -74,6 +67,7 @@ public class XsltBuilder implements Processor {
private XMLConverterHelper converter = new XMLConverterHelper();
private Templates template;
private volatile BlockingQueue<Transformer> transformers;
+ private SourceHandlerFactory sourceHandlerFactory;
private ResultHandlerFactory resultHandlerFactory = new StringResultHandlerFactory();
private boolean failOnNullBody = true;
private URIResolver uriResolver;
@@ -82,6 +76,8 @@ public class XsltBuilder implements Processor {
private boolean allowStAX = true;
private EntityResolver entityResolver;
+ private volatile Object sourceHandlerFactoryLock = new Object();
+
public XsltBuilder() {
}
@@ -116,17 +112,9 @@ public class XsltBuilder implements Processor {
// the underlying input stream, which we need to close to avoid locking files or other resources
InputStream is = null;
try {
- Source source;
- // only convert to input stream if really needed
- if (isInputStreamNeeded(exchange)) {
- is = exchange.getIn().getBody(InputStream.class);
- source = getSource(exchange, is);
- } else {
- Object body = exchange.getIn().getBody();
- source = getSource(exchange, body);
- }
+ Source source = getSourceHandlerFactory().getSource(exchange);
- if (source instanceof StAXSource) {
+ if (!isAllowStAX() && source instanceof StAXSource) {
// Always convert StAXSource to SAXSource.
// * Xalan and Saxon-B don't support StAXSource.
// * The JDK default implementation (XSLTC) doesn't handle CDATA events
@@ -136,6 +124,10 @@ public class XsltBuilder implements Processor {
source = new StAX2SAXSource(((StAXSource) source).getXMLStreamReader());
}
+ if (source instanceof SAXSource) {
+ tryAddEntityResolver((SAXSource) source);
+ }
+
LOG.trace("Using {} as source", source);
transformer.transform(source, result);
LOG.trace("Transform complete with result {}", result);
@@ -311,6 +303,26 @@ public class XsltBuilder implements Processor {
this.failOnNullBody = failOnNullBody;
}
+ public SourceHandlerFactory getSourceHandlerFactory() {
+ if (this.sourceHandlerFactory == null) {
+ synchronized (this.sourceHandlerFactoryLock) {
+ if (this.sourceHandlerFactory == null) {
+ final XmlSourceHandlerFactoryImpl xmlSourceHandlerFactory = new XmlSourceHandlerFactoryImpl();
+ xmlSourceHandlerFactory.setFailOnNullBody(isFailOnNullBody());
+ xmlSourceHandlerFactory.setAllowStax(isAllowStAX());
+
+ this.sourceHandlerFactory = xmlSourceHandlerFactory;
+ }
+ }
+ }
+
+ return this.sourceHandlerFactory;
+ }
+
+ public void setSourceHandlerFactory(SourceHandlerFactory sourceHandlerFactory) {
+ this.sourceHandlerFactory = sourceHandlerFactory;
+ }
+
public ResultHandlerFactory getResultHandlerFactory() {
return resultHandlerFactory;
}
@@ -437,97 +449,6 @@ public class XsltBuilder implements Processor {
return getTemplate().newTransformer();
}
- /**
- * Checks whether we need an {@link InputStream} to access the message body.
- * <p/>
- * Depending on the content in the message body, we may not need to convert
- * to {@link InputStream}.
- *
- * @param exchange the current exchange
- * @return <tt>true</tt> to convert to {@link InputStream} beforehand converting to {@link Source} afterwards.
- */
- protected boolean isInputStreamNeeded(Exchange exchange) {
- Object body = exchange.getIn().getBody();
- if (body == null) {
- return false;
- }
-
- if (body instanceof InputStream) {
- return true;
- } else if (body instanceof Source) {
- return false;
- } else if (body instanceof String) {
- return false;
- } else if (body instanceof byte[]) {
- return false;
- } else if (body instanceof Node) {
- return false;
- } else if (exchange.getContext().getTypeConverterRegistry().lookup(Source.class, body.getClass()) != null) {
- //there is a direct and hopefully optimized converter to Source
- return false;
- }
- // yes an input stream is needed
- return true;
- }
-
- /**
- * Converts the inbound body to a {@link Source}, if the body is <b>not</b> already a {@link Source}.
- * <p/>
- * This implementation will prefer to source in the following order:
- * <ul>
- * <li>StAX - If StAX is allowed</li>
- * <li>SAX - SAX as 2nd choice</li>
- * <li>Stream - Stream as 3rd choice</li>
- * <li>DOM - DOM as 4th choice</li>
- * </ul>
- */
- protected Source getSource(Exchange exchange, Object body) {
- // body may already be a source
- if (body instanceof Source) {
- return (Source) body;
- }
- Source source = null;
- if (body != null) {
- if (isAllowStAX()) {
- // try StAX if enabled
- source = exchange.getContext().getTypeConverter().tryConvertTo(StAXSource.class, exchange, body);
- }
- if (source == null) {
- // then try SAX
- source = exchange.getContext().getTypeConverter().tryConvertTo(SAXSource.class, exchange, body);
- tryAddEntityResolver((SAXSource)source);
- }
- if (source == null) {
- // then try stream
- source = exchange.getContext().getTypeConverter().tryConvertTo(StreamSource.class, exchange, body);
- }
- if (source == null) {
- // and fallback to DOM
- source = exchange.getContext().getTypeConverter().tryConvertTo(DOMSource.class, exchange, body);
- }
- // as the TypeConverterRegistry will look up source the converter differently if the type converter is loaded different
- // now we just put the call of source converter at last
- if (source == null) {
- TypeConverter tc = exchange.getContext().getTypeConverterRegistry().lookup(Source.class, body.getClass());
- if (tc != null) {
- source = tc.convertTo(Source.class, exchange, body);
- }
- }
- }
- if (source == null) {
- if (isFailOnNullBody()) {
- throw new ExpectedBodyTypeException(exchange, Source.class);
- } else {
- try {
- source = converter.toDOMSource(converter.createDocument());
- } catch (ParserConfigurationException | TransformerException e) {
- throw new RuntimeTransformException(e);
- }
- }
- }
- return source;
- }
-
private void tryAddEntityResolver(SAXSource source) {
//expecting source to have not null XMLReader
if (this.entityResolver != null && source != null) {
diff --git a/components/camel-xslt/src/main/java/org/apache/camel/component/xslt/XsltComponent.java b/components/camel-xslt/src/main/java/org/apache/camel/component/xslt/XsltComponent.java
index 88147d6..eab98e7 100644
--- a/components/camel-xslt/src/main/java/org/apache/camel/component/xslt/XsltComponent.java
+++ b/components/camel-xslt/src/main/java/org/apache/camel/component/xslt/XsltComponent.java
@@ -150,7 +150,17 @@ public class XsltComponent extends DefaultComponent {
@Override
protected Endpoint createEndpoint(String uri, final String remaining, Map<String, Object> parameters) throws Exception {
- XsltEndpoint endpoint = new XsltEndpoint(uri, this);
+ XsltEndpoint endpoint = createXsltEndpoint(uri);
+ configureEndpoint(endpoint, remaining, parameters);
+
+ return endpoint;
+ }
+
+ protected XsltEndpoint createXsltEndpoint(String uri) {
+ return new XsltEndpoint(uri, this);
+ }
+
+ protected void configureEndpoint(XsltEndpoint endpoint, final String remaining, Map<String, Object> parameters) throws Exception {
endpoint.setContentCache(isContentCache());
endpoint.setSaxon(isSaxon());
endpoint.setSaxonConfiguration(saxonConfiguration);
@@ -162,7 +172,7 @@ public class XsltComponent extends DefaultComponent {
if (resolver == null) {
// not in endpoint then use component specific resolver
resolver = getUriResolver();
- }
+ }
if (resolver == null) {
// lookup custom resolver factory to use
XsltUriResolverFactory resolverFactory = resolveAndRemoveReferenceParameter(parameters, "uriResolverFactory", XsltUriResolverFactory.class);
@@ -174,7 +184,7 @@ public class XsltComponent extends DefaultComponent {
// fallback to use the Default URI resolver factory
resolverFactory = new DefaultXsltUriResolverFactory();
}
-
+
resolver = resolverFactory.createUriResolver(getCamelContext(), remaining);
}
endpoint.setUriResolver(resolver);
@@ -193,8 +203,5 @@ public class XsltComponent extends DefaultComponent {
// additional parameters need to be stored on endpoint as they can be used to configure xslt builder additionally
endpoint.setParameters(parameters);
}
-
- return endpoint;
}
-
}
diff --git a/components/camel-xslt/src/main/java/org/apache/camel/component/xslt/XsltEndpoint.java b/components/camel-xslt/src/main/java/org/apache/camel/component/xslt/XsltEndpoint.java
index bfcac07..888770a 100644
--- a/components/camel-xslt/src/main/java/org/apache/camel/component/xslt/XsltEndpoint.java
+++ b/components/camel-xslt/src/main/java/org/apache/camel/component/xslt/XsltEndpoint.java
@@ -116,7 +116,7 @@ public class XsltEndpoint extends ProcessorEndpoint {
@Override
protected void onExchange(Exchange exchange) throws Exception {
if (!contentCache || cacheCleared) {
- loadResource(resourceUri);
+ loadResource(resourceUri, xslt);
}
super.onExchange(exchange);
}
@@ -382,7 +382,7 @@ public class XsltEndpoint extends ProcessorEndpoint {
* @throws TransformerException is thrown if error loading resource
* @throws IOException is thrown if error loading resource
*/
- protected void loadResource(String resourceUri) throws TransformerException, IOException {
+ protected void loadResource(String resourceUri, XsltBuilder xslt) throws TransformerException, IOException {
log.trace("{} loading schema resource: {}", this, resourceUri);
Source source = xslt.getUriResolver().resolve(resourceUri, null);
if (source == null) {
@@ -398,13 +398,19 @@ public class XsltEndpoint extends ProcessorEndpoint {
protected void doStart() throws Exception {
super.doStart();
+ // the processor is the xslt builder
+ setXslt(createXsltBuilder());
+ setProcessor(getXslt());
+ }
+
+ protected XsltBuilder createXsltBuilder() throws Exception {
final CamelContext ctx = getCamelContext();
final ClassResolver resolver = ctx.getClassResolver();
final Injector injector = ctx.getInjector();
log.debug("{} using schema resource: {}", this, resourceUri);
- this.xslt = injector.newInstance(XsltBuilder.class);
+ final XsltBuilder xslt = injector.newInstance(XsltBuilder.class);
boolean useSaxon = false;
if (transformerFactoryClass == null && (saxon || saxonExtensionFunctions != null)) {
@@ -452,10 +458,9 @@ public class XsltEndpoint extends ProcessorEndpoint {
}
// must load resource first which sets a template and do a stylesheet compilation to catch errors early
- loadResource(resourceUri);
+ loadResource(resourceUri, xslt);
- // the processor is the xslt builder
- setProcessor(xslt);
+ return xslt;
}
protected void configureOutput(XsltBuilder xslt, String output) throws Exception {
@@ -479,6 +484,6 @@ public class XsltEndpoint extends ProcessorEndpoint {
@Override
protected void doStop() throws Exception {
super.doStop();
- ServiceHelper.stopService(xslt);
+ ServiceHelper.stopService(getXslt());
}
}
diff --git a/core/camel-endpointdsl/src/main/java/org/apache/camel/builder/endpoint/dsl/XJEndpointBuilderFactory.java b/core/camel-endpointdsl/src/main/java/org/apache/camel/builder/endpoint/dsl/XJEndpointBuilderFactory.java
index 1f978fa..f597047 100644
--- a/core/camel-endpointdsl/src/main/java/org/apache/camel/builder/endpoint/dsl/XJEndpointBuilderFactory.java
+++ b/core/camel-endpointdsl/src/main/java/org/apache/camel/builder/endpoint/dsl/XJEndpointBuilderFactory.java
@@ -39,6 +39,55 @@ public interface XJEndpointBuilderFactory {
return (AdvancedXJEndpointBuilder) this;
}
/**
+ * Sets the transform direction.
+ *
+ * The option is a:
+ * <code>org.apache.camel.component.xj.TransformDirection</code> type.
+ *
+ * Required: true
+ * Group: producer
+ */
+ default XJEndpointBuilder transformDirection(
+ TransformDirection transformDirection) {
+ setProperty("transformDirection", transformDirection);
+ return this;
+ }
+ /**
+ * Sets the transform direction.
+ *
+ * The option will be converted to a
+ * <code>org.apache.camel.component.xj.TransformDirection</code> type.
+ *
+ * Required: true
+ * Group: producer
+ */
+ default XJEndpointBuilder transformDirection(String transformDirection) {
+ setProperty("transformDirection", transformDirection);
+ return this;
+ }
+ /**
+ * Whether to allow using StAX as the javax.xml.transform.Source.
+ *
+ * The option is a: <code>boolean</code> type.
+ *
+ * Group: producer
+ */
+ default XJEndpointBuilder allowStAX(boolean allowStAX) {
+ setProperty("allowStAX", allowStAX);
+ return this;
+ }
+ /**
+ * Whether to allow using StAX as the javax.xml.transform.Source.
+ *
+ * The option will be converted to a <code>boolean</code> type.
+ *
+ * Group: producer
+ */
+ default XJEndpointBuilder allowStAX(String allowStAX) {
+ setProperty("allowStAX", allowStAX);
+ return this;
+ }
+ /**
* Cache for the resource content (the stylesheet file) when it is
* loaded. If set to false Camel will reload the stylesheet file on each
* message processing. This is good for development. A cached stylesheet
@@ -181,33 +230,6 @@ public interface XJEndpointBuilderFactory {
return this;
}
/**
- * The transform direction. Either XML2JSON or JSON2XML.
- *
- * The option is a:
- * <code>org.apache.camel.component.xj.TransformDirection</code> type.
- *
- * Required: true
- * Group: producer
- */
- default XJEndpointBuilder transformDirection(
- TransformDirection transformDirection) {
- setProperty("transformDirection", transformDirection);
- return this;
- }
- /**
- * The transform direction. Either XML2JSON or JSON2XML.
- *
- * The option will be converted to a
- * <code>org.apache.camel.component.xj.TransformDirection</code> type.
- *
- * Required: true
- * Group: producer
- */
- default XJEndpointBuilder transformDirection(String transformDirection) {
- setProperty("transformDirection", transformDirection);
- return this;
- }
- /**
* The number of javax.xml.transform.Transformer object that are cached
* for reuse to avoid calls to Template.newTransformer().
*
@@ -502,6 +524,15 @@ public interface XJEndpointBuilderFactory {
}
/**
+ * Proxy enum for
+ * <code>org.apache.camel.component.xj.TransformDirection</code> enum.
+ */
+ enum TransformDirection {
+ XML2JSON,
+ JSON2XML;
+ }
+
+ /**
* Proxy enum for <code>org.apache.camel.component.xslt.XsltOutput</code>
* enum.
*/
@@ -511,21 +542,12 @@ public interface XJEndpointBuilderFactory {
DOM,
file;
}
-
- /**
- * Proxy enum for
- * <code>org.apache.camel.component.xj.TransformDirection</code> enum.
- */
- enum TransformDirection {
- XML2JSON,
- JSON2XML;
- }
/**
* XJ (camel-xj)
* Transforms json/xml message back and forth using a XSLT.
*
* Category: transformation
- * Available as of version: 2.25
+ * Available as of version: 3.0
* Maven coordinates: org.apache.camel:camel-xj
*
* Syntax: <code>xj:resourceUri</code>
|