You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@camel.apache.org by da...@apache.org on 2016/11/24 09:45:26 UTC
[4/4] camel git commit: CAMEL-10447 Add contract based type awareness
and transformer which leverages the type metadata
CAMEL-10447 Add contract based type awareness and transformer which leverages the type metadata
Project: http://git-wip-us.apache.org/repos/asf/camel/repo
Commit: http://git-wip-us.apache.org/repos/asf/camel/commit/7ba090f5
Tree: http://git-wip-us.apache.org/repos/asf/camel/tree/7ba090f5
Diff: http://git-wip-us.apache.org/repos/asf/camel/diff/7ba090f5
Branch: refs/heads/master
Commit: 7ba090f5ca58f2f4a040898e56db3e11ba24fcde
Parents: b650414
Author: Tomohisa Igarashi <tm...@gmail.com>
Authored: Fri Jul 15 22:41:04 2016 +0900
Committer: Claus Ibsen <da...@apache.org>
Committed: Thu Nov 24 10:45:13 2016 +0100
----------------------------------------------------------------------
.../java/org/apache/camel/CamelContext.java | 34 ++
.../main/java/org/apache/camel/Exchange.java | 3 +
.../apache/camel/impl/DefaultCamelContext.java | 61 ++++
.../apache/camel/impl/DefaultRouteContext.java | 11 +
.../impl/transformer/DataFormatTransformer.java | 154 ++++++++
.../impl/transformer/ProcessorTransformer.java | 122 +++++++
.../camel/impl/transformer/TransformerKey.java | 75 ++++
.../java/org/apache/camel/model/Constants.java | 3 +-
.../apache/camel/model/InputTypeDefinition.java | 79 +++++
.../camel/model/OutputTypeDefinition.java | 80 +++++
.../org/apache/camel/model/RouteDefinition.java | 80 ++++-
.../CustomTransformerDefinition.java | 106 ++++++
.../DataFormatTransformerDefinition.java | 161 +++++++++
.../EndpointTransformerDefinition.java | 88 +++++
.../transformer/TransformerDefinition.java | 133 +++++++
.../transformer/TransformersDefinition.java | 58 +++
.../camel/model/transformer/package-info.java | 24 ++
.../camel/processor/CamelInternalProcessor.java | 120 +++++++
.../java/org/apache/camel/spi/Contract.java | 112 ++++++
.../java/org/apache/camel/spi/DataType.java | 89 +++++
.../java/org/apache/camel/spi/RouteContext.java | 5 +
.../java/org/apache/camel/spi/Transformer.java | 128 +++++++
.../resources/org/apache/camel/model/jaxb.index | 2 +
.../apache/camel/model/transformer/jaxb.index | 21 ++
.../transformer/TransformerContractTest.java | 173 +++++++++
.../impl/transformer/TransformerRouteTest.java | 349 +++++++++++++++++++
.../blueprint/CamelContextFactoryBean.java | 11 +
.../camel/cdi/xml/CamelContextFactoryBean.java | 12 +
.../xml/AbstractCamelContextFactoryBean.java | 6 +
.../camel/spring/CamelContextFactoryBean.java | 14 +
.../spring/handler/CamelNamespaceHandler.java | 1 +
.../transformer/SpringTransformerRouteTest.java | 48 +++
.../transformer/SpringTransformerRouteTest.xml | 97 ++++++
examples/README.md | 5 +
.../README.md | 51 +++
.../camel-example-transformer-blueprint/pom.xml | 121 +++++++
.../OSGI-INF/blueprint/camel-context.xml | 53 +++
.../src/main/resources/features.xml | 29 ++
.../src/main/resources/log4j2.properties | 28 ++
.../src/main/resources/transform.xsl | 14 +
.../camel-example-transformer-cdi/README.md | 37 ++
examples/camel-example-transformer-cdi/pom.xml | 102 ++++++
.../camel/example/transformer/cdi/MyRoutes.java | 56 +++
.../src/main/resources/META-INF/LICENSE.txt | 203 +++++++++++
.../src/main/resources/META-INF/NOTICE.txt | 11 +
.../src/main/resources/META-INF/beans.xml | 18 +
.../src/main/resources/log4j2.properties | 28 ++
.../src/main/resources/transform.xsl | 14 +
.../camel-example-transformer-demo/README.md | 33 ++
examples/camel-example-transformer-demo/pom.xml | 141 ++++++++
.../camel/example/transformer/demo/Order.java | 82 +++++
.../transformer/demo/OrderProcessor.java | 41 +++
.../example/transformer/demo/OrderResponse.java | 76 ++++
.../transformer/demo/client/CamelClient.java | 106 ++++++
.../src/main/resources/META-INF/LICENSE.txt | 203 +++++++++++
.../src/main/resources/META-INF/NOTICE.txt | 11 +
.../resources/META-INF/spring/camel-context.xml | 100 ++++++
.../src/main/resources/features.xml | 30 ++
.../src/main/resources/log4j2.properties | 28 ++
.../camel/example/transformer/demo/jaxb.index | 2 +
.../transformer/OrderRouteSpringTest.java | 140 ++++++++
examples/pom.xml | 3 +
62 files changed, 4224 insertions(+), 2 deletions(-)
----------------------------------------------------------------------
http://git-wip-us.apache.org/repos/asf/camel/blob/7ba090f5/camel-core/src/main/java/org/apache/camel/CamelContext.java
----------------------------------------------------------------------
diff --git a/camel-core/src/main/java/org/apache/camel/CamelContext.java b/camel-core/src/main/java/org/apache/camel/CamelContext.java
index e3710d8..8c687b2 100644
--- a/camel-core/src/main/java/org/apache/camel/CamelContext.java
+++ b/camel-core/src/main/java/org/apache/camel/CamelContext.java
@@ -36,11 +36,13 @@ import org.apache.camel.model.RoutesDefinition;
import org.apache.camel.model.remote.ServiceCallConfigurationDefinition;
import org.apache.camel.model.rest.RestDefinition;
import org.apache.camel.model.rest.RestsDefinition;
+import org.apache.camel.model.transformer.TransformerDefinition;
import org.apache.camel.spi.AsyncProcessorAwaitManager;
import org.apache.camel.spi.CamelContextNameStrategy;
import org.apache.camel.spi.ClassResolver;
import org.apache.camel.spi.DataFormat;
import org.apache.camel.spi.DataFormatResolver;
+import org.apache.camel.spi.DataType;
import org.apache.camel.spi.Debugger;
import org.apache.camel.spi.EndpointRegistry;
import org.apache.camel.spi.EndpointStrategy;
@@ -69,6 +71,7 @@ import org.apache.camel.spi.RuntimeEndpointRegistry;
import org.apache.camel.spi.ServicePool;
import org.apache.camel.spi.ShutdownStrategy;
import org.apache.camel.spi.StreamCachingStrategy;
+import org.apache.camel.spi.Transformer;
import org.apache.camel.spi.TypeConverterRegistry;
import org.apache.camel.spi.UnitOfWorkFactory;
import org.apache.camel.spi.UuidGenerator;
@@ -1217,6 +1220,37 @@ public interface CamelContext extends SuspendableService, RuntimeConfiguration {
void setDataFormatResolver(DataFormatResolver dataFormatResolver);
/**
+ * Sets the transformers that can be referenced in the routes.
+ *
+ * @param transformers the transformers
+ */
+ void setTransformers(List<TransformerDefinition> transformers);
+
+ /**
+ * Gets the transformers that can be referenced in the routes.
+ *
+ * @return the transformers available
+ */
+ List<TransformerDefinition> getTransformers();
+
+ /**
+ * Resolve a transformer given a scheme
+ *
+ * @param model data model name.
+ * @return the resolved transformer, or <tt>null</tt> if not found
+ */
+ Transformer resolveTransformer(String model);
+
+ /**
+ * Resolve a transformer given from/to data type.
+ *
+ * @param from from data type
+ * @param to to data type
+ * @return the resolved data format, or <tt>null</tt> if not found
+ */
+ Transformer resolveTransformer(DataType from, DataType to);
+
+ /**
* Sets the properties that can be referenced in the camel context
* <p/>
* <b>Important:</b> This has nothing to do with property placeholders, and is just a plain set of key/value pairs
http://git-wip-us.apache.org/repos/asf/camel/blob/7ba090f5/camel-core/src/main/java/org/apache/camel/Exchange.java
----------------------------------------------------------------------
diff --git a/camel-core/src/main/java/org/apache/camel/Exchange.java b/camel-core/src/main/java/org/apache/camel/Exchange.java
index b23da1a..b6f6c37 100644
--- a/camel-core/src/main/java/org/apache/camel/Exchange.java
+++ b/camel-core/src/main/java/org/apache/camel/Exchange.java
@@ -231,6 +231,9 @@ public interface Exchange {
String XSLT_FATAL_ERROR = "CamelXsltFatalError";
String XSLT_WARNING = "CamelXsltWarning";
+ String INPUT_TYPE = "CamelInputType";
+ String OUTPUT_TYPE = "CamelOutputType";
+
/**
* Returns the {@link ExchangePattern} (MEP) of this exchange.
*
http://git-wip-us.apache.org/repos/asf/camel/blob/7ba090f5/camel-core/src/main/java/org/apache/camel/impl/DefaultCamelContext.java
----------------------------------------------------------------------
diff --git a/camel-core/src/main/java/org/apache/camel/impl/DefaultCamelContext.java b/camel-core/src/main/java/org/apache/camel/impl/DefaultCamelContext.java
index 12295bf..9cd8e83 100644
--- a/camel-core/src/main/java/org/apache/camel/impl/DefaultCamelContext.java
+++ b/camel-core/src/main/java/org/apache/camel/impl/DefaultCamelContext.java
@@ -90,6 +90,7 @@ import org.apache.camel.component.properties.PropertiesComponent;
import org.apache.camel.impl.converter.BaseTypeConverterRegistry;
import org.apache.camel.impl.converter.DefaultTypeConverter;
import org.apache.camel.impl.converter.LazyLoadingTypeConverter;
+import org.apache.camel.impl.transformer.TransformerKey;
import org.apache.camel.management.DefaultManagementMBeanAssembler;
import org.apache.camel.management.DefaultManagementStrategy;
import org.apache.camel.management.JmxSystemPropertyKeys;
@@ -105,6 +106,7 @@ import org.apache.camel.model.RoutesDefinition;
import org.apache.camel.model.remote.ServiceCallConfigurationDefinition;
import org.apache.camel.model.rest.RestDefinition;
import org.apache.camel.model.rest.RestsDefinition;
+import org.apache.camel.model.transformer.TransformerDefinition;
import org.apache.camel.processor.interceptor.BacklogDebugger;
import org.apache.camel.processor.interceptor.BacklogTracer;
import org.apache.camel.processor.interceptor.Debug;
@@ -119,6 +121,7 @@ import org.apache.camel.spi.ComponentResolver;
import org.apache.camel.spi.Container;
import org.apache.camel.spi.DataFormat;
import org.apache.camel.spi.DataFormatResolver;
+import org.apache.camel.spi.DataType;
import org.apache.camel.spi.Debugger;
import org.apache.camel.spi.EndpointRegistry;
import org.apache.camel.spi.EndpointStrategy;
@@ -150,6 +153,7 @@ import org.apache.camel.spi.RuntimeEndpointRegistry;
import org.apache.camel.spi.ServicePool;
import org.apache.camel.spi.ShutdownStrategy;
import org.apache.camel.spi.StreamCachingStrategy;
+import org.apache.camel.spi.Transformer;
import org.apache.camel.spi.TypeConverterRegistry;
import org.apache.camel.spi.UnitOfWorkFactory;
import org.apache.camel.spi.UuidGenerator;
@@ -276,6 +280,8 @@ public class DefaultCamelContext extends ServiceSupport implements ModelCamelCon
private final StopWatch stopWatch = new StopWatch(false);
private Date startDate;
private ModelJAXBContextFactory modelJAXBContextFactory;
+ private List<TransformerDefinition> transformers = new ArrayList<TransformerDefinition>();
+ private Map<TransformerKey, Transformer> transformerRegistry = new HashMap<TransformerKey, Transformer>();
/**
* Creates the {@link CamelContext} using {@link JndiRegistry} as registry,
@@ -4323,6 +4329,61 @@ public class DefaultCamelContext extends ServiceSupport implements ModelCamelCon
}
}
}
+ }
+
+ @Override
+ public void setTransformers(List<TransformerDefinition> transformers) {
+ this.transformers = transformers;
+ }
+
+ @Override
+ public List<TransformerDefinition> getTransformers() {
+ return transformers;
+ }
+
+ @Override
+ public Transformer resolveTransformer(String scheme) {
+ if (scheme == null) {
+ return null;
+ }
+ return resolveTransformer(getTransformerKey(scheme));
+ }
+
+ @Override
+ public Transformer resolveTransformer(DataType from, DataType to) {
+ if (from == null || to == null) {
+ return null;
+ }
+ return resolveTransformer(getTransformerKey(from, to));
+ }
+
+ protected Transformer resolveTransformer(TransformerKey key) {
+ Transformer transformer = transformerRegistry.get(key);
+ if (transformer != null) {
+ return transformer;
+ }
+ for (TransformerDefinition def : getTransformers()) {
+ if (key.match(def)) {
+ try {
+ transformer = def.createTransformer(this);
+ transformer.setCamelContext(this);
+ addService(transformer);
+ } catch (Exception e) {
+ throw new RuntimeCamelException(e);
+ }
+ log.debug("Registering Transformer '{}'", transformer);
+ transformerRegistry.put(key, transformer);
+ return transformer;
+ }
+ }
+ return null;
+ }
+
+ protected TransformerKey getTransformerKey(String scheme) {
+ return new TransformerKey(scheme);
+ }
+ protected TransformerKey getTransformerKey(DataType from, DataType to) {
+ return new TransformerKey(from, to);
}
}
http://git-wip-us.apache.org/repos/asf/camel/blob/7ba090f5/camel-core/src/main/java/org/apache/camel/impl/DefaultRouteContext.java
----------------------------------------------------------------------
diff --git a/camel-core/src/main/java/org/apache/camel/impl/DefaultRouteContext.java b/camel-core/src/main/java/org/apache/camel/impl/DefaultRouteContext.java
index d18ccb7..8a2e7c1 100644
--- a/camel-core/src/main/java/org/apache/camel/impl/DefaultRouteContext.java
+++ b/camel-core/src/main/java/org/apache/camel/impl/DefaultRouteContext.java
@@ -36,6 +36,7 @@ import org.apache.camel.model.ProcessorDefinition;
import org.apache.camel.model.RouteDefinition;
import org.apache.camel.processor.CamelInternalProcessor;
import org.apache.camel.processor.Pipeline;
+import org.apache.camel.spi.Contract;
import org.apache.camel.spi.InterceptStrategy;
import org.apache.camel.spi.RouteContext;
import org.apache.camel.spi.RoutePolicy;
@@ -68,6 +69,7 @@ public class DefaultRouteContext implements RouteContext {
private List<RoutePolicy> routePolicyList = new ArrayList<RoutePolicy>();
private ShutdownRoute shutdownRoute;
private ShutdownRunningTask shutdownRunningTask;
+ private Contract contract;
public DefaultRouteContext(CamelContext camelContext, RouteDefinition route, FromDefinition from, Collection<Route> routes) {
this.camelContext = camelContext;
@@ -191,6 +193,11 @@ public class DefaultRouteContext implements RouteContext {
// wrap in route lifecycle
internal.addAdvice(new CamelInternalProcessor.RouteLifecycleAdvice());
+ // wrap in contract
+ if (contract != null) {
+ internal.addAdvice(new CamelInternalProcessor.ContractAdvice(contract));
+ }
+
// and create the route that wraps the UoW
Route edcr = new EventDrivenConsumerRoute(this, getEndpoint(), internal);
edcr.getProperties().put(Route.ID_PROPERTY, routeId);
@@ -400,4 +407,8 @@ public class DefaultRouteContext implements RouteContext {
public List<RoutePolicy> getRoutePolicyList() {
return routePolicyList;
}
+
+ public void setContract(Contract contract) {
+ this.contract = contract;
+ }
}
http://git-wip-us.apache.org/repos/asf/camel/blob/7ba090f5/camel-core/src/main/java/org/apache/camel/impl/transformer/DataFormatTransformer.java
----------------------------------------------------------------------
diff --git a/camel-core/src/main/java/org/apache/camel/impl/transformer/DataFormatTransformer.java b/camel-core/src/main/java/org/apache/camel/impl/transformer/DataFormatTransformer.java
new file mode 100644
index 0000000..9993807
--- /dev/null
+++ b/camel-core/src/main/java/org/apache/camel/impl/transformer/DataFormatTransformer.java
@@ -0,0 +1,154 @@
+/**
+ * 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.impl.transformer;
+
+import java.io.InputStream;
+import java.io.OutputStream;
+
+import org.apache.camel.CamelContext;
+import org.apache.camel.Exchange;
+import org.apache.camel.Message;
+import org.apache.camel.converter.stream.OutputStreamBuilder;
+import org.apache.camel.model.DataFormatDefinition;
+import org.apache.camel.model.transformer.DataFormatTransformerDefinition;
+import org.apache.camel.spi.DataFormat;
+import org.apache.camel.spi.DataType;
+import org.apache.camel.spi.Transformer;
+import org.apache.camel.support.ServiceSupport;
+import org.apache.camel.util.ServiceHelper;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+/**
+ * A <a href="http://camel.apache.org/transformer.html">Transformer</a>
+ * leverages DataFormat to perform transformation.
+ */
+public class DataFormatTransformer extends Transformer {
+ private static final Logger LOG = LoggerFactory.getLogger(DataFormatTransformer.class);
+
+ private String dataFormatRef;
+ private DataFormatDefinition dataFormatType;
+ private DataFormat dataFormat;
+ private String transformerString;
+
+ public DataFormatTransformer(CamelContext context) {
+ setCamelContext(context);
+ }
+
+ /**
+ * Perform data transformation with specified from/to type using DataFormat.
+ * @param message message to apply transformation
+ * @param from 'from' data type
+ * @param to 'to' data type
+ */
+ @Override
+ public void transform(Message message, DataType from, DataType to) throws Exception {
+ Exchange exchange = message.getExchange();
+ CamelContext context = exchange.getContext();
+
+ // Unmarshaling into Java Object
+ if ((to == null || to.isJavaType()) && (from.equals(getFrom()) || from.getModel().equals(getModel()))) {
+ DataFormat dataFormat = getDataFormat(exchange);
+ LOG.debug("Unmarshaling with '{}'", dataFormat);
+ Object answer = dataFormat.unmarshal(exchange, message.getBody(InputStream.class));
+ if (to != null && to.getName() != null) {
+ Class<?> toClass = context.getClassResolver().resolveClass(to.getName());
+ if (!toClass.isAssignableFrom(answer.getClass())) {
+ LOG.debug("Converting to '{}'", toClass.getName());
+ answer = context.getTypeConverter().mandatoryConvertTo(toClass, answer);
+ }
+ }
+ message.setBody(answer);
+
+ // Marshaling from Java Object
+ } else if ((from == null || from.isJavaType()) && (to.equals(getTo()) || to.getModel().equals(getModel()))) {
+ Object input = message.getBody();
+ if (from != null && from.getName() != null) {
+ Class<?> fromClass = context.getClassResolver().resolveClass(from.getName());
+ if (!fromClass.isAssignableFrom(input.getClass())) {
+ LOG.debug("Converting to '{}'", fromClass.getName());
+ input = context.getTypeConverter().mandatoryConvertTo(fromClass, input);
+ }
+ }
+ OutputStreamBuilder osb = OutputStreamBuilder.withExchange(exchange);
+ DataFormat dataFormat = getDataFormat(exchange);
+ LOG.debug("Marshaling with '{}'", dataFormat);
+ dataFormat.marshal(exchange, message.getBody(), osb);
+ message.setBody(osb.build());
+
+ } else {
+ throw new IllegalArgumentException("Unsupported transformation: from='" + from + ", to='" + to + "'");
+ }
+ }
+
+ /**
+ * A bit dirty hack to create DataFormat instance, as it requires a RouteContext anyway.
+ */
+ private DataFormat getDataFormat(Exchange exchange) throws Exception {
+ if (this.dataFormat == null) {
+ this.dataFormat = DataFormatDefinition.getDataFormat(
+ exchange.getUnitOfWork().getRouteContext(), this.dataFormatType, this.dataFormatRef);
+ if (this.dataFormat != null && !getCamelContext().hasService(this.dataFormat)) {
+ getCamelContext().addService(this.dataFormat, false);
+ }
+ }
+ return this.dataFormat;
+ }
+
+ /**
+ * Set DataFormat ref.
+ * @param ref DataFormat ref
+ * @return this DataFormatTransformer instance
+ */
+ public DataFormatTransformer setDataFormatRef(String ref) {
+ this.dataFormatRef = ref;
+ this.transformerString = null;
+ return this;
+ }
+
+ /**
+ * Set DataFormatDefinition.
+ * @param dataFormatType DataFormatDefinition
+ * @return this DataFormatTransformer instance
+ */
+ public DataFormatTransformer setDataFormatType(DataFormatDefinition dataFormatType) {
+ this.dataFormatType = dataFormatType;
+ this.transformerString = null;
+ return this;
+ }
+
+ @Override
+ public String toString() {
+ if (transformerString == null) {
+ transformerString =
+ String.format("DataFormatTransformer[scheme='%s', from='%s', to='%s', ref='%s', type='%s']",
+ getModel(), getFrom(), getTo(), dataFormatRef, dataFormatType);
+ }
+ return transformerString;
+ }
+
+ @Override
+ public void doStart() throws Exception {
+ // no-op
+ }
+
+ @Override
+ public void doStop() throws Exception {
+ ServiceHelper.stopService(this.dataFormat);
+ getCamelContext().removeService(this.dataFormat);
+ }
+}
http://git-wip-us.apache.org/repos/asf/camel/blob/7ba090f5/camel-core/src/main/java/org/apache/camel/impl/transformer/ProcessorTransformer.java
----------------------------------------------------------------------
diff --git a/camel-core/src/main/java/org/apache/camel/impl/transformer/ProcessorTransformer.java b/camel-core/src/main/java/org/apache/camel/impl/transformer/ProcessorTransformer.java
new file mode 100644
index 0000000..f7bc2d4
--- /dev/null
+++ b/camel-core/src/main/java/org/apache/camel/impl/transformer/ProcessorTransformer.java
@@ -0,0 +1,122 @@
+/**
+ * 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.impl.transformer;
+
+import org.apache.camel.CamelContext;
+import org.apache.camel.Endpoint;
+import org.apache.camel.Exchange;
+import org.apache.camel.ExchangePattern;
+import org.apache.camel.Message;
+import org.apache.camel.Processor;
+import org.apache.camel.impl.DefaultExchange;
+import org.apache.camel.model.transformer.EndpointTransformerDefinition;
+import org.apache.camel.processor.SendProcessor;
+import org.apache.camel.spi.DataType;
+import org.apache.camel.spi.Transformer;
+import org.apache.camel.support.ServiceSupport;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+/**
+ * A <a href="http://camel.apache.org/transformer.html">Transformer</a>
+ * leverages Processor to perform transformation.
+ */
+public class ProcessorTransformer extends Transformer {
+ private static final Logger LOG = LoggerFactory.getLogger(ProcessorTransformer.class);
+
+ private Processor processor;
+ private String transformerString;
+
+ public ProcessorTransformer(CamelContext context) {
+ setCamelContext(context);
+ }
+
+ /**
+ * Perform data transformation with specified from/to type using Processor.
+ * @param message message to apply transformation
+ * @param from 'from' data type
+ * @param to 'to' data type
+ */
+ @Override
+ public void transform(Message message, DataType from, DataType to) throws Exception {
+ Exchange exchange = message.getExchange();
+ CamelContext context = exchange.getContext();
+ if (from.isJavaType()) {
+ Object input = message.getBody();
+ Class<?> fromClass = context.getClassResolver().resolveClass(from.getName());
+ if (!fromClass.isAssignableFrom(input.getClass())) {
+ LOG.debug("Converting to '{}'", fromClass.getName());
+ input = context.getTypeConverter().mandatoryConvertTo(fromClass, input);
+ message.setBody(input);
+ }
+ }
+
+ LOG.debug("Sending to transform processor '{}'", processor);
+ DefaultExchange transformExchange = new DefaultExchange(exchange);
+ transformExchange.setIn(message);
+ transformExchange.setProperties(exchange.getProperties());
+ processor.process(transformExchange);
+ Message answer = transformExchange.hasOut() ? transformExchange.getOut() : transformExchange.getIn();
+
+ if (to.isJavaType()) {
+ Object answerBody = answer.getBody();
+ Class<?> toClass = context.getClassResolver().resolveClass(to.getName());
+ if (!toClass.isAssignableFrom(answerBody.getClass())) {
+ LOG.debug("Converting to '{}'", toClass.getName());
+ answerBody = context.getTypeConverter().mandatoryConvertTo(toClass, answerBody);
+ answer.setBody(answerBody);
+ }
+ }
+
+ message.copyFrom(answer);
+ }
+
+ /**
+ * Set Processor.
+ * @param processor Processor
+ * @return this ProcessorTransformer instance
+ */
+ public ProcessorTransformer setProcessor(Processor processor) {
+ this.processor = processor;
+ this.transformerString = null;
+ return this;
+ }
+
+ @Override
+ public String toString() {
+ if (transformerString == null) {
+ transformerString =
+ String.format("ProcessorTransformer[scheme='%s', from='%s', to='%s', processor='%s']",
+ getModel(), getFrom(), getTo(), processor);
+ }
+ return transformerString;
+ }
+
+ @Override
+ protected void doStart() throws Exception {
+ if (this.processor instanceof ServiceSupport) {
+ ((ServiceSupport)this.processor).start();
+ }
+ }
+
+ @Override
+ protected void doStop() throws Exception {
+ if (this.processor instanceof ServiceSupport) {
+ ((ServiceSupport)this.processor).stop();
+ }
+ }
+}
http://git-wip-us.apache.org/repos/asf/camel/blob/7ba090f5/camel-core/src/main/java/org/apache/camel/impl/transformer/TransformerKey.java
----------------------------------------------------------------------
diff --git a/camel-core/src/main/java/org/apache/camel/impl/transformer/TransformerKey.java b/camel-core/src/main/java/org/apache/camel/impl/transformer/TransformerKey.java
new file mode 100644
index 0000000..c5680ea
--- /dev/null
+++ b/camel-core/src/main/java/org/apache/camel/impl/transformer/TransformerKey.java
@@ -0,0 +1,75 @@
+/**
+ * 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.impl.transformer;
+
+import org.apache.camel.impl.DefaultCamelContext;
+import org.apache.camel.impl.DefaultEndpointRegistry;
+import org.apache.camel.model.transformer.TransformerDefinition;
+import org.apache.camel.spi.DataType;
+import org.apache.camel.util.ObjectHelper;
+import org.apache.camel.util.ValueHolder;
+
+/**
+ * Key used in Transformer registry in {@link DefaultCamelContext},
+ * to ensure a consistent lookup.
+ */
+public final class TransformerKey extends ValueHolder<String> {
+
+ private String scheme;
+ private DataType from;
+ private DataType to;
+
+ public TransformerKey(String scheme) {
+ super(scheme);
+ this.scheme = scheme;
+ ObjectHelper.notEmpty(scheme, "scheme");
+ }
+
+ public TransformerKey(DataType from, DataType to) {
+ super(createKeyString(from, to));
+ this.from = from;
+ this.to = to;
+ }
+
+ private static String createKeyString(DataType from, DataType to) {
+ return from + "/" + to;
+ }
+
+ /**
+ * Test if specified TransformerDefinition matches with data type represented by this key.
+ * @param def TransformerDefinition
+ * @return true if it matches, otherwise false
+ */
+ public boolean match(TransformerDefinition def) {
+ if (scheme != null) {
+ return scheme.equals(def.getScheme());
+ }
+ if (from == null) {
+ return to.toString().equals(def.getTo());
+ }
+ if (to == null) {
+ return from.toString().equals(def.getFrom());
+ }
+ return from.toString().equals(def.getFrom()) && to.toString().equals(def.getTo());
+ }
+
+ @Override
+ public String toString() {
+ return get();
+ }
+
+}
http://git-wip-us.apache.org/repos/asf/camel/blob/7ba090f5/camel-core/src/main/java/org/apache/camel/model/Constants.java
----------------------------------------------------------------------
diff --git a/camel-core/src/main/java/org/apache/camel/model/Constants.java b/camel-core/src/main/java/org/apache/camel/model/Constants.java
index 9c72ac1..eaec06e 100644
--- a/camel-core/src/main/java/org/apache/camel/model/Constants.java
+++ b/camel-core/src/main/java/org/apache/camel/model/Constants.java
@@ -31,7 +31,8 @@ public final class Constants {
+ "org.apache.camel.model.language:"
+ "org.apache.camel.model.loadbalancer:"
+ "org.apache.camel.model.remote:"
- + "org.apache.camel.model.rest";
+ + "org.apache.camel.model.rest:"
+ + "org.apache.camel.model.transformer";
public static final String PLACEHOLDER_QNAME = "http://camel.apache.org/schema/placeholder";
http://git-wip-us.apache.org/repos/asf/camel/blob/7ba090f5/camel-core/src/main/java/org/apache/camel/model/InputTypeDefinition.java
----------------------------------------------------------------------
diff --git a/camel-core/src/main/java/org/apache/camel/model/InputTypeDefinition.java b/camel-core/src/main/java/org/apache/camel/model/InputTypeDefinition.java
new file mode 100644
index 0000000..782e041
--- /dev/null
+++ b/camel-core/src/main/java/org/apache/camel/model/InputTypeDefinition.java
@@ -0,0 +1,79 @@
+/**
+ * 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.model;
+
+import javax.xml.bind.annotation.XmlAccessType;
+import javax.xml.bind.annotation.XmlAccessorType;
+import javax.xml.bind.annotation.XmlAttribute;
+import javax.xml.bind.annotation.XmlRootElement;
+import javax.xml.bind.annotation.XmlTransient;
+
+import org.apache.camel.spi.Metadata;
+
+/**
+ * Set data type of the input message.
+ */
+@Metadata(label = "configuration")
+@XmlRootElement(name = "inputType")
+@XmlAccessorType(XmlAccessType.FIELD)
+public class InputTypeDefinition extends OptionalIdentifiedDefinition<InputTypeDefinition> {
+ @XmlAttribute(required = true)
+ private String urn;
+ @XmlTransient
+ private Class<?> clazz;
+
+ public InputTypeDefinition() {
+ }
+
+ /**
+ * Get input type URN.
+ * @return input type URN
+ */
+ public String getUrn() {
+ if (clazz != null) {
+ return "java:" + clazz.getName();
+ }
+ return urn;
+ }
+
+ /**
+ * Set input type URN.
+ * @param urn input type URN
+ */
+ public void setUrn(String urn) {
+ this.urn = urn;
+ }
+
+ /**
+ * Set input type via Java Class.
+ * @param clazz Java Class
+ */
+ public void setJavaClass(Class<?> clazz) {
+ this.clazz = clazz;
+ }
+
+ @Override
+ public String toString() {
+ return "inputType[" + urn + "]";
+ }
+
+ @Override
+ public String getLabel() {
+ return "inputType[" + urn + "]";
+ }
+
+}
http://git-wip-us.apache.org/repos/asf/camel/blob/7ba090f5/camel-core/src/main/java/org/apache/camel/model/OutputTypeDefinition.java
----------------------------------------------------------------------
diff --git a/camel-core/src/main/java/org/apache/camel/model/OutputTypeDefinition.java b/camel-core/src/main/java/org/apache/camel/model/OutputTypeDefinition.java
new file mode 100644
index 0000000..755874a
--- /dev/null
+++ b/camel-core/src/main/java/org/apache/camel/model/OutputTypeDefinition.java
@@ -0,0 +1,80 @@
+/**
+ * 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.model;
+
+import javax.xml.bind.annotation.XmlAccessType;
+import javax.xml.bind.annotation.XmlAccessorType;
+import javax.xml.bind.annotation.XmlAttribute;
+import javax.xml.bind.annotation.XmlRootElement;
+import javax.xml.bind.annotation.XmlTransient;
+
+import org.apache.camel.spi.Metadata;
+
+/**
+ * Sets data type of the output message.
+ */
+@Metadata(label = "configuration")
+@XmlRootElement(name = "outputType")
+@XmlAccessorType(XmlAccessType.FIELD)
+public class OutputTypeDefinition extends OptionalIdentifiedDefinition<OutputTypeDefinition> {
+ @XmlAttribute(required = true)
+ private String urn;
+ @XmlTransient
+ private Class<?> clazz;
+
+ public OutputTypeDefinition() {
+ }
+
+ /**
+ * Get output type URN.
+ * @return output type URN
+ */
+ public String getUrn() {
+ if (clazz != null) {
+ return "java:" + clazz.getName();
+ }
+ return urn;
+ }
+
+ /**
+ * Set output type URN.
+ * @param urn output type URN
+ * @return this OutputTypeDefinition instance
+ */
+ public void setUrn(String urn) {
+ this.urn = urn;
+ }
+
+ /**
+ * Set output type via Java Class.
+ * @param clazz Java Class
+ */
+ public void setJavaClass(Class<?> clazz) {
+ this.clazz = clazz;
+ }
+
+ @Override
+ public String toString() {
+ return "outputType[" + urn + "]";
+ }
+
+ @Override
+ public String getLabel() {
+ return "outputType[" + urn + "]";
+ }
+
+}
http://git-wip-us.apache.org/repos/asf/camel/blob/7ba090f5/camel-core/src/main/java/org/apache/camel/model/RouteDefinition.java
----------------------------------------------------------------------
diff --git a/camel-core/src/main/java/org/apache/camel/model/RouteDefinition.java b/camel-core/src/main/java/org/apache/camel/model/RouteDefinition.java
index 83f51ef..e140dc0 100644
--- a/camel-core/src/main/java/org/apache/camel/model/RouteDefinition.java
+++ b/camel-core/src/main/java/org/apache/camel/model/RouteDefinition.java
@@ -46,6 +46,7 @@ import org.apache.camel.builder.RouteBuilder;
import org.apache.camel.impl.DefaultRouteContext;
import org.apache.camel.model.rest.RestDefinition;
import org.apache.camel.processor.interceptor.HandleFault;
+import org.apache.camel.spi.Contract;
import org.apache.camel.spi.LifecycleStrategy;
import org.apache.camel.spi.Metadata;
import org.apache.camel.spi.RouteContext;
@@ -61,7 +62,7 @@ import org.apache.camel.util.ObjectHelper;
*/
@Metadata(label = "configuration")
@XmlRootElement(name = "route")
-@XmlType(propOrder = {"inputs", "outputs"})
+@XmlType(propOrder = {"inputs", "inputType", "outputType", "outputs"})
@XmlAccessorType(XmlAccessType.PROPERTY)
// must use XmlAccessType.PROPERTY as there is some custom logic needed to be executed in the setter methods
public class RouteDefinition extends ProcessorDefinition<RouteDefinition> {
@@ -87,6 +88,8 @@ public class RouteDefinition extends ProcessorDefinition<RouteDefinition> {
private boolean contextScopedErrorHandler = true;
private Boolean rest;
private RestDefinition restDefinition;
+ private InputTypeDefinition inputType;
+ private OutputTypeDefinition outputType;
public RouteDefinition() {
}
@@ -629,6 +632,50 @@ public class RouteDefinition extends ProcessorDefinition<RouteDefinition> {
return this;
}
+ /**
+ * Declare an input type.
+ * @param name input type URN
+ * @return the builder
+ */
+ public RouteDefinition inputType(String name) {
+ inputType = new InputTypeDefinition();
+ inputType.setUrn(name);
+ return this;
+ }
+
+ /**
+ * Declare an input type with Java class.
+ * @param clazz Class object of the input type
+ * @return the builder
+ */
+ public RouteDefinition inputType(Class clazz) {
+ inputType = new InputTypeDefinition();
+ inputType.setJavaClass(clazz);
+ return this;
+ }
+
+ /**
+ * Declare an output type.
+ * @param name output type URN
+ * @return the builder
+ */
+ public RouteDefinition outputType(String name) {
+ outputType = new OutputTypeDefinition();
+ outputType.setUrn(name);
+ return this;
+ }
+
+ /**
+ * Declare an output type.
+ * @param clazz Class object of the output type
+ * @return the builder
+ */
+ public RouteDefinition outputType(Class clazz) {
+ outputType = new OutputTypeDefinition();
+ outputType.setJavaClass(clazz);
+ return this;
+ }
+
// Properties
// -----------------------------------------------------------------------
@@ -935,6 +982,24 @@ public class RouteDefinition extends ProcessorDefinition<RouteDefinition> {
return true;
}
+ @XmlElementRef(required = false)
+ public void setInputType(InputTypeDefinition inputType) {
+ this.inputType = inputType;
+ }
+
+ public InputTypeDefinition getInputType() {
+ return this.inputType;
+ }
+
+ @XmlElementRef(required = false)
+ public void setOutputType(OutputTypeDefinition outputType) {
+ this.outputType = outputType;
+ }
+
+ public OutputTypeDefinition getOutputType() {
+ return this.outputType;
+ }
+
// Implementation methods
// -------------------------------------------------------------------------
protected RouteContext addRoutes(CamelContext camelContext, Collection<Route> routes, FromDefinition fromType) throws Exception {
@@ -1062,6 +1127,18 @@ public class RouteDefinition extends ProcessorDefinition<RouteDefinition> {
throw new FailedToCreateRouteException(route.getId(), route.toString(), at, cause);
}
+ // add data type contract
+ if (inputType != null || outputType != null) {
+ Contract contract = new Contract();
+ if (inputType != null) {
+ contract.setInputType(inputType.getUrn());
+ }
+ if (outputType != null) {
+ contract.setOutputType(outputType.getUrn());
+ }
+ routeContext.setContract(contract);
+ }
+
List<ProcessorDefinition<?>> list = new ArrayList<ProcessorDefinition<?>>(outputs);
for (ProcessorDefinition<?> output : list) {
try {
@@ -1075,4 +1152,5 @@ public class RouteDefinition extends ProcessorDefinition<RouteDefinition> {
routeContext.commit();
return routeContext;
}
+
}
http://git-wip-us.apache.org/repos/asf/camel/blob/7ba090f5/camel-core/src/main/java/org/apache/camel/model/transformer/CustomTransformerDefinition.java
----------------------------------------------------------------------
diff --git a/camel-core/src/main/java/org/apache/camel/model/transformer/CustomTransformerDefinition.java b/camel-core/src/main/java/org/apache/camel/model/transformer/CustomTransformerDefinition.java
new file mode 100644
index 0000000..3af804b
--- /dev/null
+++ b/camel-core/src/main/java/org/apache/camel/model/transformer/CustomTransformerDefinition.java
@@ -0,0 +1,106 @@
+/**
+ * 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.model.transformer;
+
+import java.util.Map;
+import javax.xml.bind.annotation.XmlAccessType;
+import javax.xml.bind.annotation.XmlAccessorType;
+import javax.xml.bind.annotation.XmlAnyAttribute;
+import javax.xml.bind.annotation.XmlAttribute;
+import javax.xml.bind.annotation.XmlTransient;
+import javax.xml.bind.annotation.XmlType;
+import javax.xml.namespace.QName;
+
+import org.apache.camel.CamelContext;
+import org.apache.camel.Endpoint;
+import org.apache.camel.component.bean.BeanHolder;
+import org.apache.camel.component.bean.BeanProcessor;
+import org.apache.camel.component.bean.ConstantStaticTypeBeanHolder;
+import org.apache.camel.component.bean.ConstantTypeBeanHolder;
+import org.apache.camel.impl.transformer.ProcessorTransformer;
+import org.apache.camel.spi.DataFormat;
+import org.apache.camel.spi.DataType;
+import org.apache.camel.spi.Metadata;
+import org.apache.camel.spi.RouteContext;
+import org.apache.camel.spi.Transformer;
+import org.apache.camel.util.ObjectHelper;
+
+/**
+ * Represents a BeanTransformer.
+ */
+@Metadata(label = "transformation")
+@XmlType(name = "customTransformer")
+@XmlAccessorType(XmlAccessType.FIELD)
+public class CustomTransformerDefinition extends TransformerDefinition {
+ @XmlAttribute
+ private String ref;
+ @XmlAttribute
+ private String type;
+
+ @Override
+ protected Transformer doCreateTransformer() throws Exception {
+ if (ref == null && type == null) {
+ throw new IllegalArgumentException("'ref' or 'type' must be specified for customTransformer");
+ }
+ Transformer transformer;
+ if (ref != null) {
+ transformer = getCamelContext().getRegistry().lookupByNameAndType(ref, Transformer.class);
+ if (transformer == null) {
+ throw new IllegalArgumentException("Cannot find transformer with ref:" + ref);
+ }
+ if (transformer.getModel() != null || transformer.getFrom() != null || transformer.getTo() != null) {
+ throw new IllegalArgumentException(String.format("Transformer '%s' is already in use. Please check if duplicate transformer exists.", ref));
+ }
+ } else {
+ Class<Transformer> transformerClass = getCamelContext().getClassResolver().resolveMandatoryClass(type, Transformer.class);
+ if (transformerClass == null) {
+ throw new IllegalArgumentException("Cannot find transformer class: " + type);
+ }
+ transformer = transformerClass.newInstance();
+ }
+ transformer.setCamelContext(getCamelContext());
+ return transformer.setModel(getScheme())
+ .setFrom(getFrom())
+ .setTo(getTo());
+ }
+
+ public String getRef() {
+ return ref;
+ }
+
+ /**
+ * Set a bean reference of the Transformer
+ * @param ref the bean reference of the Transformer
+ */
+ public void setRef(String ref) {
+ this.ref = ref;
+ }
+
+ public String getType() {
+ return type;
+ }
+
+ /**
+ * Set a class name of the Transformer
+ * @param ref the class name of the Transformer
+ */
+ public void setType(String type) {
+ this.type = type;
+ }
+
+}
+
http://git-wip-us.apache.org/repos/asf/camel/blob/7ba090f5/camel-core/src/main/java/org/apache/camel/model/transformer/DataFormatTransformerDefinition.java
----------------------------------------------------------------------
diff --git a/camel-core/src/main/java/org/apache/camel/model/transformer/DataFormatTransformerDefinition.java b/camel-core/src/main/java/org/apache/camel/model/transformer/DataFormatTransformerDefinition.java
new file mode 100644
index 0000000..6429b85
--- /dev/null
+++ b/camel-core/src/main/java/org/apache/camel/model/transformer/DataFormatTransformerDefinition.java
@@ -0,0 +1,161 @@
+/**
+ * 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.model.transformer;
+
+import java.util.Map;
+import javax.xml.bind.annotation.XmlAccessType;
+import javax.xml.bind.annotation.XmlAccessorType;
+import javax.xml.bind.annotation.XmlAnyAttribute;
+import javax.xml.bind.annotation.XmlAttribute;
+import javax.xml.bind.annotation.XmlElement;
+import javax.xml.bind.annotation.XmlElements;
+import javax.xml.bind.annotation.XmlTransient;
+import javax.xml.bind.annotation.XmlType;
+import javax.xml.namespace.QName;
+
+import org.apache.camel.CamelContext;
+import org.apache.camel.Endpoint;
+import org.apache.camel.Message;
+import org.apache.camel.impl.transformer.DataFormatTransformer;
+import org.apache.camel.model.DataFormatDefinition;
+import org.apache.camel.model.dataformat.AvroDataFormat;
+import org.apache.camel.model.dataformat.Base64DataFormat;
+import org.apache.camel.model.dataformat.BeanioDataFormat;
+import org.apache.camel.model.dataformat.BindyDataFormat;
+import org.apache.camel.model.dataformat.BoonDataFormat;
+import org.apache.camel.model.dataformat.CastorDataFormat;
+import org.apache.camel.model.dataformat.CryptoDataFormat;
+import org.apache.camel.model.dataformat.CsvDataFormat;
+import org.apache.camel.model.dataformat.CustomDataFormat;
+import org.apache.camel.model.dataformat.FlatpackDataFormat;
+import org.apache.camel.model.dataformat.GzipDataFormat;
+import org.apache.camel.model.dataformat.HL7DataFormat;
+import org.apache.camel.model.dataformat.IcalDataFormat;
+import org.apache.camel.model.dataformat.JacksonXMLDataFormat;
+import org.apache.camel.model.dataformat.JaxbDataFormat;
+import org.apache.camel.model.dataformat.JibxDataFormat;
+import org.apache.camel.model.dataformat.JsonDataFormat;
+import org.apache.camel.model.dataformat.PGPDataFormat;
+import org.apache.camel.model.dataformat.ProtobufDataFormat;
+import org.apache.camel.model.dataformat.RssDataFormat;
+import org.apache.camel.model.dataformat.SerializationDataFormat;
+import org.apache.camel.model.dataformat.SoapJaxbDataFormat;
+import org.apache.camel.model.dataformat.StringDataFormat;
+import org.apache.camel.model.dataformat.SyslogDataFormat;
+import org.apache.camel.model.dataformat.TarFileDataFormat;
+import org.apache.camel.model.dataformat.TidyMarkupDataFormat;
+import org.apache.camel.model.dataformat.UniVocityCsvDataFormat;
+import org.apache.camel.model.dataformat.UniVocityFixedWidthDataFormat;
+import org.apache.camel.model.dataformat.UniVocityTsvDataFormat;
+import org.apache.camel.model.dataformat.XMLBeansDataFormat;
+import org.apache.camel.model.dataformat.XMLSecurityDataFormat;
+import org.apache.camel.model.dataformat.XStreamDataFormat;
+import org.apache.camel.model.dataformat.XmlJsonDataFormat;
+import org.apache.camel.model.dataformat.XmlRpcDataFormat;
+import org.apache.camel.model.dataformat.ZipDataFormat;
+import org.apache.camel.model.dataformat.ZipFileDataFormat;
+import org.apache.camel.spi.DataFormat;
+import org.apache.camel.spi.Metadata;
+import org.apache.camel.spi.RouteContext;
+import org.apache.camel.spi.Transformer;
+
+/**
+ * Represents a DataFormatTransformer.
+ */
+@Metadata(label = "transformation")
+@XmlType(name = "dataFormatTransformer")
+@XmlAccessorType(XmlAccessType.FIELD)
+public class DataFormatTransformerDefinition extends TransformerDefinition {
+
+ @XmlElements({
+ @XmlElement(required = false, name = "avro", type = AvroDataFormat.class),
+ @XmlElement(required = false, name = "base64", type = Base64DataFormat.class),
+ @XmlElement(required = false, name = "beanio", type = BeanioDataFormat.class),
+ @XmlElement(required = false, name = "bindy", type = BindyDataFormat.class),
+ @XmlElement(required = false, name = "boon", type = BoonDataFormat.class),
+ @XmlElement(required = false, name = "castor", type = CastorDataFormat.class),
+ @XmlElement(required = false, name = "crypto", type = CryptoDataFormat.class),
+ @XmlElement(required = false, name = "csv", type = CsvDataFormat.class),
+ @XmlElement(required = false, name = "custom", type = CustomDataFormat.class),
+ @XmlElement(required = false, name = "flatpack", type = FlatpackDataFormat.class),
+ @XmlElement(required = false, name = "gzip", type = GzipDataFormat.class),
+ @XmlElement(required = false, name = "hl7", type = HL7DataFormat.class),
+ @XmlElement(required = false, name = "ical", type = IcalDataFormat.class),
+ @XmlElement(required = false, name = "jacksonxml", type = JacksonXMLDataFormat.class),
+ @XmlElement(required = false, name = "jaxb", type = JaxbDataFormat.class),
+ @XmlElement(required = false, name = "jibx", type = JibxDataFormat.class),
+ @XmlElement(required = false, name = "json", type = JsonDataFormat.class),
+ @XmlElement(required = false, name = "protobuf", type = ProtobufDataFormat.class),
+ @XmlElement(required = false, name = "rss", type = RssDataFormat.class),
+ @XmlElement(required = false, name = "secureXML", type = XMLSecurityDataFormat.class),
+ @XmlElement(required = false, name = "serialization", type = SerializationDataFormat.class),
+ @XmlElement(required = false, name = "soapjaxb", type = SoapJaxbDataFormat.class),
+ @XmlElement(required = false, name = "string", type = StringDataFormat.class),
+ @XmlElement(required = false, name = "syslog", type = SyslogDataFormat.class),
+ @XmlElement(required = false, name = "tarfile", type = TarFileDataFormat.class),
+ @XmlElement(required = false, name = "tidyMarkup", type = TidyMarkupDataFormat.class),
+ @XmlElement(required = false, name = "univocity-csv", type = UniVocityCsvDataFormat.class),
+ @XmlElement(required = false, name = "univocity-fixed", type = UniVocityFixedWidthDataFormat.class),
+ @XmlElement(required = false, name = "univocity-tsv", type = UniVocityTsvDataFormat.class),
+ @XmlElement(required = false, name = "xmlBeans", type = XMLBeansDataFormat.class),
+ @XmlElement(required = false, name = "xmljson", type = XmlJsonDataFormat.class),
+ @XmlElement(required = false, name = "xmlrpc", type = XmlRpcDataFormat.class),
+ @XmlElement(required = false, name = "xstream", type = XStreamDataFormat.class),
+ @XmlElement(required = false, name = "pgp", type = PGPDataFormat.class),
+ @XmlElement(required = false, name = "zip", type = ZipDataFormat.class),
+ @XmlElement(required = false, name = "zipFile", type = ZipFileDataFormat.class)}
+ )
+ private DataFormatDefinition dataFormatType;
+
+ @XmlAttribute
+ private String ref;
+
+ @Override
+ protected Transformer doCreateTransformer() {
+ return new DataFormatTransformer(getCamelContext())
+ .setDataFormatType(dataFormatType)
+ .setDataFormatRef(ref)
+ .setModel(getScheme())
+ .setFrom(getFrom())
+ .setTo(getTo());
+ }
+
+ public String getRef() {
+ return ref;
+ }
+
+ /**
+ * Set the reference of the DataFormat.
+ * @param ref reference of the DataFormat
+ */
+ public void setRef(String ref) {
+ this.ref = ref;
+ }
+
+ public DataFormatDefinition getDataFormatType() {
+ return dataFormatType;
+ }
+
+ /**
+ * The data format to be used
+ */
+ public void setDataFormatType(DataFormatDefinition dataFormatType) {
+ this.dataFormatType = dataFormatType;
+ }
+
+}
+
http://git-wip-us.apache.org/repos/asf/camel/blob/7ba090f5/camel-core/src/main/java/org/apache/camel/model/transformer/EndpointTransformerDefinition.java
----------------------------------------------------------------------
diff --git a/camel-core/src/main/java/org/apache/camel/model/transformer/EndpointTransformerDefinition.java b/camel-core/src/main/java/org/apache/camel/model/transformer/EndpointTransformerDefinition.java
new file mode 100644
index 0000000..7b16fc4
--- /dev/null
+++ b/camel-core/src/main/java/org/apache/camel/model/transformer/EndpointTransformerDefinition.java
@@ -0,0 +1,88 @@
+/**
+ * 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.model.transformer;
+
+import java.util.Map;
+import javax.xml.bind.annotation.XmlAccessType;
+import javax.xml.bind.annotation.XmlAccessorType;
+import javax.xml.bind.annotation.XmlAnyAttribute;
+import javax.xml.bind.annotation.XmlAttribute;
+import javax.xml.bind.annotation.XmlTransient;
+import javax.xml.bind.annotation.XmlType;
+import javax.xml.namespace.QName;
+
+import org.apache.camel.CamelContext;
+import org.apache.camel.Endpoint;
+import org.apache.camel.ExchangePattern;
+import org.apache.camel.impl.transformer.ProcessorTransformer;
+import org.apache.camel.processor.SendProcessor;
+import org.apache.camel.spi.DataFormat;
+import org.apache.camel.spi.Metadata;
+import org.apache.camel.spi.RouteContext;
+import org.apache.camel.spi.Transformer;
+
+/**
+ * Represents a EndpointTransformer.
+ */
+@Metadata(label = "transformation")
+@XmlType(name = "endpointTransformer")
+@XmlAccessorType(XmlAccessType.FIELD)
+public class EndpointTransformerDefinition extends TransformerDefinition {
+
+ @XmlAttribute
+ private String ref;
+ @XmlAttribute
+ private String uri;
+
+ @Override
+ protected Transformer doCreateTransformer() throws Exception {
+ Endpoint endpoint = uri != null ? getCamelContext().getEndpoint(uri)
+ : getCamelContext().getRegistry().lookupByNameAndType(ref, Endpoint.class);
+ SendProcessor processor = new SendProcessor(endpoint, ExchangePattern.InOut);
+ return new ProcessorTransformer(getCamelContext())
+ .setProcessor(processor)
+ .setModel(getScheme())
+ .setFrom(getFrom())
+ .setTo(getTo());
+ }
+
+ public String getRef() {
+ return ref;
+ }
+
+ /**
+ * Set the reference of the Endpoint.
+ * @param ref reference of the Endpoint
+ */
+ public void setRef(String ref) {
+ this.ref = ref;
+ }
+
+ public String getUri() {
+ return uri;
+ }
+
+ /**
+ * Set the URI of the Endpoint.
+ * @param uri URI of the Endpoint
+ */
+ public void setUri(String uri) {
+ this.uri = uri;
+ }
+
+}
+
http://git-wip-us.apache.org/repos/asf/camel/blob/7ba090f5/camel-core/src/main/java/org/apache/camel/model/transformer/TransformerDefinition.java
----------------------------------------------------------------------
diff --git a/camel-core/src/main/java/org/apache/camel/model/transformer/TransformerDefinition.java b/camel-core/src/main/java/org/apache/camel/model/transformer/TransformerDefinition.java
new file mode 100644
index 0000000..7695a63
--- /dev/null
+++ b/camel-core/src/main/java/org/apache/camel/model/transformer/TransformerDefinition.java
@@ -0,0 +1,133 @@
+/**
+ * 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.model.transformer;
+
+import java.util.Map;
+import javax.xml.bind.annotation.XmlAccessType;
+import javax.xml.bind.annotation.XmlAccessorType;
+import javax.xml.bind.annotation.XmlAnyAttribute;
+import javax.xml.bind.annotation.XmlAttribute;
+import javax.xml.bind.annotation.XmlTransient;
+import javax.xml.bind.annotation.XmlType;
+import javax.xml.namespace.QName;
+
+import org.apache.camel.CamelContext;
+import org.apache.camel.Endpoint;
+import org.apache.camel.model.IdentifiedType;
+import org.apache.camel.model.OtherAttributesAware;
+import org.apache.camel.spi.DataFormat;
+import org.apache.camel.spi.DataType;
+import org.apache.camel.spi.Metadata;
+import org.apache.camel.spi.RouteContext;
+import org.apache.camel.spi.Transformer;
+import org.apache.camel.util.ObjectHelper;
+
+import static org.apache.camel.util.EndpointHelper.isReferenceParameter;
+
+/**
+ * Represents a Transformer.
+ */
+@Metadata(label = "transformation")
+@XmlType(name = "transformer")
+@XmlAccessorType(XmlAccessType.FIELD)
+public abstract class TransformerDefinition {
+ @XmlAttribute
+ private String scheme;
+ @XmlAttribute
+ private String from;
+ @XmlAttribute
+ private String to;
+ @XmlTransient
+ private CamelContext camelContext;
+
+ public Transformer createTransformer(CamelContext context) throws Exception {
+ this.camelContext = context;
+ return doCreateTransformer();
+ };
+
+ protected abstract Transformer doCreateTransformer() throws Exception;
+
+ public String getScheme() {
+ return scheme;
+ }
+
+ /**
+ * Set a scheme name supported by the transformer.
+ * @param scheme scheme name
+ */
+ public void setScheme(String scheme) {
+ this.scheme = scheme;
+ }
+
+ public String getFrom() {
+ return from;
+ }
+
+ /**
+ * Set the 'from' data type .
+ * @param from 'from' data type
+ */
+ public void setFrom(String from) {
+ this.from = from;
+ }
+
+ /**
+ * Set the 'from' data type using Java class.
+ * @param clazz 'from' Java class
+ */
+ public void setFrom(Class<?> clazz) {
+ this.from = "java:" + clazz.getName();
+ }
+
+ public String getTo() {
+ return to;
+ }
+
+ /**
+ * Set the 'to' data type.
+ * @param to 'to' data type
+ */
+ public void setTo(String to) {
+ this.to = to;
+ }
+
+ /**
+ * Set the 'to' data type using Java class.
+ * @param clazz 'to' Java class
+ */
+ public void setTo(Class<?> clazz) {
+ this.to = "java:" + clazz.getName();
+ }
+
+ /**
+ * Get the CamelContext.
+ * @return
+ */
+ public CamelContext getCamelContext() {
+ return camelContext;
+ }
+
+ /**
+ * Set the CamelContext.
+ * @param camelContext CamelContext
+ */
+ public void setCamelContext(CamelContext camelContext) {
+ this.camelContext = camelContext;
+ }
+
+}
+
http://git-wip-us.apache.org/repos/asf/camel/blob/7ba090f5/camel-core/src/main/java/org/apache/camel/model/transformer/TransformersDefinition.java
----------------------------------------------------------------------
diff --git a/camel-core/src/main/java/org/apache/camel/model/transformer/TransformersDefinition.java b/camel-core/src/main/java/org/apache/camel/model/transformer/TransformersDefinition.java
new file mode 100644
index 0000000..3820c0f
--- /dev/null
+++ b/camel-core/src/main/java/org/apache/camel/model/transformer/TransformersDefinition.java
@@ -0,0 +1,58 @@
+/**
+ * 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.model.transformer;
+
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import javax.xml.bind.annotation.XmlAccessType;
+import javax.xml.bind.annotation.XmlAccessorType;
+import javax.xml.bind.annotation.XmlElement;
+import javax.xml.bind.annotation.XmlElements;
+import javax.xml.bind.annotation.XmlRootElement;
+
+import org.apache.camel.model.DataFormatDefinition;
+import org.apache.camel.spi.Metadata;
+
+/**
+ * To configure transforms.
+ */
+@Metadata(label = "transformation", title = "Transformations")
+@XmlRootElement(name = "transformers")
+@XmlAccessorType(XmlAccessType.FIELD)
+public class TransformersDefinition {
+
+ @XmlElements({
+ @XmlElement(required = false, name = "dataFormatTransformer", type = DataFormatTransformerDefinition.class),
+ @XmlElement(required = false, name = "endpointTransformer", type = EndpointTransformerDefinition.class),
+ @XmlElement(required = false, name = "customTransformer", type = CustomTransformerDefinition.class)}
+ )
+ private List<TransformerDefinition> transforms;
+
+ /**
+ * A list holding the configured transformations
+ */
+ public void setTransformers(List<TransformerDefinition> transforms) {
+ this.transforms = transforms;
+ }
+
+ public List<TransformerDefinition> getTransforms() {
+ return transforms;
+ }
+
+}
http://git-wip-us.apache.org/repos/asf/camel/blob/7ba090f5/camel-core/src/main/java/org/apache/camel/model/transformer/package-info.java
----------------------------------------------------------------------
diff --git a/camel-core/src/main/java/org/apache/camel/model/transformer/package-info.java b/camel-core/src/main/java/org/apache/camel/model/transformer/package-info.java
new file mode 100644
index 0000000..840ddb3
--- /dev/null
+++ b/camel-core/src/main/java/org/apache/camel/model/transformer/package-info.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.
+ */
+
+/**
+ * The JAXB POJOs for the
+ * <a href="http://camel.apache.org/transformer.html">Transformers</a> used to transform message contents
+ * according to declared data types inside <a href="http://camel.apache.org/components.html">components</a>
+ */
+@javax.xml.bind.annotation.XmlSchema(namespace = "http://camel.apache.org/schema/spring", elementFormDefault = javax.xml.bind.annotation.XmlNsForm.QUALIFIED)
+package org.apache.camel.model.transformer;
http://git-wip-us.apache.org/repos/asf/camel/blob/7ba090f5/camel-core/src/main/java/org/apache/camel/processor/CamelInternalProcessor.java
----------------------------------------------------------------------
diff --git a/camel-core/src/main/java/org/apache/camel/processor/CamelInternalProcessor.java b/camel-core/src/main/java/org/apache/camel/processor/CamelInternalProcessor.java
index 50f2af4..ab9892a 100644
--- a/camel-core/src/main/java/org/apache/camel/processor/CamelInternalProcessor.java
+++ b/camel-core/src/main/java/org/apache/camel/processor/CamelInternalProcessor.java
@@ -26,6 +26,7 @@ import java.util.concurrent.RejectedExecutionException;
import org.apache.camel.AsyncCallback;
import org.apache.camel.CamelContext;
import org.apache.camel.Exchange;
+import org.apache.camel.Message;
import org.apache.camel.MessageHistory;
import org.apache.camel.Ordered;
import org.apache.camel.Processor;
@@ -40,11 +41,14 @@ import org.apache.camel.model.ProcessorDefinitionHelper;
import org.apache.camel.processor.interceptor.BacklogDebugger;
import org.apache.camel.processor.interceptor.BacklogTracer;
import org.apache.camel.processor.interceptor.DefaultBacklogTracerEventMessage;
+import org.apache.camel.spi.Contract;
+import org.apache.camel.spi.DataType;
import org.apache.camel.spi.InflightRepository;
import org.apache.camel.spi.MessageHistoryFactory;
import org.apache.camel.spi.RouteContext;
import org.apache.camel.spi.RoutePolicy;
import org.apache.camel.spi.StreamCachingStrategy;
+import org.apache.camel.spi.Transformer;
import org.apache.camel.spi.UnitOfWork;
import org.apache.camel.util.MessageHelper;
import org.apache.camel.util.OrderedComparator;
@@ -854,4 +858,120 @@ public class CamelInternalProcessor extends DelegateAsyncProcessor {
}
}
+ /**
+ * Advice for data type contract
+ * TODO add declarative validation
+ */
+ public static class ContractAdvice implements CamelInternalProcessorAdvice {
+ private Contract contract;
+
+ public ContractAdvice(Contract contract) {
+ this.contract = contract;
+ }
+
+ @Override
+ public Object before(Exchange exchange) throws Exception {
+ DataType from = getCurrentType(exchange, Exchange.INPUT_TYPE);
+ DataType to = contract.getInputType();
+ if (to != null && !to.equals(from)) {
+ LOG.debug("Looking for transformer for INPUT: from='{}', to='{}'", from, to);
+ convertBody(exchange.getIn(), from, to);
+ exchange.setProperty(Exchange.INPUT_TYPE, to);
+ }
+ return null;
+ }
+
+ @Override
+ public void after(Exchange exchange, Object data) throws Exception {
+ Message target = exchange.hasOut() ? exchange.getOut() : exchange.getIn();
+ DataType from = getCurrentType(exchange, exchange.hasOut() ? Exchange.OUTPUT_TYPE : Exchange.INPUT_TYPE);
+ DataType to = contract.getOutputType();
+ if (to != null && !to.equals(from)) {
+ LOG.debug("Looking for transformer for OUTPUT: from='{}', to='{}'", from, to);
+ convertBody(target, from, to);
+ exchange.setProperty(exchange.hasOut() ? Exchange.OUTPUT_TYPE : Exchange.INPUT_TYPE, to);
+ }
+ }
+
+ private static void convertBody(Message message, DataType from, DataType to) throws Exception {
+ CamelContext context = message.getExchange().getContext();
+ // transform into 'from' type before performing declared transformation
+ if (from != null && from.isJavaType() && from.getName() != null) {
+ Class<?> fromJava = getClazz(from.getName(), context);
+ if (!fromJava.isAssignableFrom(message.getBody().getClass())) {
+ LOG.debug("Converting to '{}'", fromJava.getName());
+ Object fromBody = message.getMandatoryBody(fromJava);
+ message.setBody(fromBody);
+ }
+ }
+
+ Transformer transformer = context.resolveTransformer(from, to);
+ if (transformer != null) {
+ // Applying exactly matched transformer. Java-Java transformer is also allowed.
+ LOG.debug("Applying transformer: from='{}', to='{}', transformer='{}'", from, to, transformer);
+ transformer.transform(message, from, to);
+ return;
+ } else if (from == null || from.isJavaType()) {
+ if (to.isJavaType() && to.getName() != null) {
+ // Java->Java transformation just relies on TypeConverter if no declared transformer
+ // TODO for better performance it may be better to add TypeConveterTransformer
+ // into transformer registry to avoid unnecessary scan in transformer registry
+ LOG.debug("Converting to '{}'", to.getName());
+ Object answer = message.getMandatoryBody(getClazz(to.getName(), context));
+ message.setBody(answer);
+ return;
+ } else if (from == null) {
+ // {undefined}->Other transformation - assuming it's already in expected shape
+ return;
+ } else {
+ // Java->Other transformation
+ transformer = context.resolveTransformer(to.getModel());
+ if (transformer != null) {
+ LOG.debug("Applying transformer: from='{}', to='{}', transformer='{}'", from, to, transformer);
+ transformer.transform(message, from, to);
+ return;
+ }
+ }
+ } else if (from != null) {
+ if (to.isJavaType()) {
+ // Other->Java transformation
+ transformer = context.resolveTransformer(from.getModel());
+ if (transformer != null) {
+ LOG.debug("Applying transformer: from='{}', to='{}', transformer='{}'", from, to, transformer);
+ transformer.transform(message, from, to);
+ return;
+ }
+ } else {
+ // Other->Other transformation - look for a transformer chain
+ Transformer fromTransformer = context.resolveTransformer(from.getModel());
+ Transformer toTransformer = context.resolveTransformer(to.getModel());
+ if (fromTransformer != null && toTransformer != null) {
+ LOG.debug("Applying transformer: from='{}', to='{}', transformer='{}'", from, to, transformer);
+ fromTransformer.transform(message, from, new DataType(Object.class));
+ LOG.debug("Applying transformer: from='{}', to='{}', transformer='{}'", from, to, transformer);
+ toTransformer.transform(message, new DataType(Object.class), to);
+ return;
+ }
+ }
+ }
+
+ throw new IllegalArgumentException("No Transformer found for [from='" + from + "', to='" + to + "']");
+ }
+
+ private static Class<?> getClazz(String type, CamelContext context) throws Exception {
+ return context.getClassResolver().resolveMandatoryClass(type);
+ }
+
+ private static DataType getCurrentType(Exchange exchange, String name) {
+ Object prop = exchange.getProperty(name);
+ if (prop instanceof DataType) {
+ return (DataType)prop;
+ } else if (prop instanceof String) {
+ DataType answer = new DataType((String)prop);
+ exchange.setProperty(name, answer);
+ return answer;
+ }
+ return null;
+ }
+ }
}
http://git-wip-us.apache.org/repos/asf/camel/blob/7ba090f5/camel-core/src/main/java/org/apache/camel/spi/Contract.java
----------------------------------------------------------------------
diff --git a/camel-core/src/main/java/org/apache/camel/spi/Contract.java b/camel-core/src/main/java/org/apache/camel/spi/Contract.java
new file mode 100644
index 0000000..0706023
--- /dev/null
+++ b/camel-core/src/main/java/org/apache/camel/spi/Contract.java
@@ -0,0 +1,112 @@
+/**
+ * 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.spi;
+
+import java.util.Map;
+import javax.xml.namespace.QName;
+
+/**
+ * A Contract which represents the input type and/or output type of the {@link Endpoint} or {@link Processor}.
+ */
+public class Contract {
+
+ private DataType inputType;
+ private DataType outputType;
+ private String contractString;
+
+ public DataType getInputType() {
+ return inputType;
+ }
+
+ /**
+ * Set the input data type.
+ * @param inputType input data type
+ */
+ public void setInputType(String inputType) {
+ this.inputType = new DataType(inputType);
+ this.contractString = null;
+ }
+
+ /**
+ * Set the input data type with Java class.
+ * @param clazz Java class which represents input data type
+ */
+ public void setInputType(Class<?> clazz) {
+ this.inputType = new DataType(clazz);
+ this.contractString = null;
+ }
+
+ public DataType getOutputType() {
+ return outputType;
+ }
+
+ /**
+ * Set the output data type.
+ * @param outputType output data type
+ */
+ public void setOutputType(String outputType) {
+ this.outputType = new DataType(outputType);
+ this.contractString = null;
+ }
+
+ /**
+ * Set the output data type with Java class.
+ * @param clazz Java class which represents output data type
+ */
+ public void setOutputType(Class<?> clazz) {
+ this.outputType = new DataType(clazz);
+ this.contractString = null;
+ }
+
+ @Override
+ public String toString() {
+ if (contractString == null) {
+ this.contractString = "DataType[input=" + this.inputType + ", output=" + this.outputType + "]";
+ }
+ return contractString;
+ }
+
+ public boolean isEmpty() {
+ return inputType == null && outputType == null;
+ }
+
+ @Override
+ public boolean equals(Object target) {
+ if (!(target instanceof Contract)) {
+ return false;
+ }
+ Contract targetContract = (Contract)target;
+ if (getInputType() != null || targetContract.getInputType() != null) {
+ if (getInputType() == null || targetContract.getInputType() == null
+ || !getInputType().equals(targetContract.getInputType())) {
+ return false;
+ }
+ }
+ if (getOutputType() != null || targetContract.getOutputType() != null) {
+ if (getOutputType() == null || targetContract.getOutputType() == null
+ || !getOutputType().equals(targetContract.getOutputType())) {
+ return false;
+ }
+ }
+ return true;
+ }
+
+ @Override
+ public int hashCode() {
+ return toString().hashCode();
+ }
+}
http://git-wip-us.apache.org/repos/asf/camel/blob/7ba090f5/camel-core/src/main/java/org/apache/camel/spi/DataType.java
----------------------------------------------------------------------
diff --git a/camel-core/src/main/java/org/apache/camel/spi/DataType.java b/camel-core/src/main/java/org/apache/camel/spi/DataType.java
new file mode 100644
index 0000000..3efae96
--- /dev/null
+++ b/camel-core/src/main/java/org/apache/camel/spi/DataType.java
@@ -0,0 +1,89 @@
+/**
+ * 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.spi;
+
+import org.apache.camel.util.StringHelper;
+
+/**
+ * Represents the data type URN which is used for message data type contract.
+ */
+public class DataType {
+
+ private String model;
+ private String name;
+ private boolean isJavaType;
+ private String typeString;
+
+ public DataType(String urn) {
+ if (urn != null) {
+ String split[] = StringHelper.splitOnCharacter(urn, ":", 2);
+ model = split[0];
+ isJavaType = model.equals("java");
+ if (split.length > 1) {
+ name = split[1];
+ }
+ }
+ }
+
+ public DataType(Class<?> clazz) {
+ model = "java";
+ isJavaType = true;
+ name = clazz.getName();
+ }
+
+ public String getModel() {
+ return model;
+ }
+
+ public String getName() {
+ return name;
+ }
+
+ public boolean isJavaType() {
+ return isJavaType;
+ }
+
+ @Override
+ public String toString() {
+ if (this.typeString == null) {
+ this.typeString = model + ":" + name;
+ }
+ return this.typeString;
+ }
+
+ @Override
+ public boolean equals(Object target) {
+ if (target instanceof DataType) {
+ DataType targetdt = (DataType)target;
+ String targetModel = targetdt.getModel();
+ String targetName = targetdt.getName();
+ if (targetModel == null) {
+ return false;
+ } else if (targetName == null) {
+ return targetModel.equals(getModel()) && getName() == null;
+ } else {
+ return targetModel.equals(getModel()) && targetName.equals(getName());
+ }
+ }
+ return false;
+ }
+
+ @Override
+ public int hashCode() {
+ return toString().hashCode();
+ }
+}
http://git-wip-us.apache.org/repos/asf/camel/blob/7ba090f5/camel-core/src/main/java/org/apache/camel/spi/RouteContext.java
----------------------------------------------------------------------
diff --git a/camel-core/src/main/java/org/apache/camel/spi/RouteContext.java b/camel-core/src/main/java/org/apache/camel/spi/RouteContext.java
index 54e6ad0..194f544 100644
--- a/camel-core/src/main/java/org/apache/camel/spi/RouteContext.java
+++ b/camel-core/src/main/java/org/apache/camel/spi/RouteContext.java
@@ -192,4 +192,9 @@ public interface RouteContext extends RuntimeConfiguration, EndpointAware {
*/
int getAndIncrement(ProcessorDefinition<?> node);
+ /**
+ *
+ * @param contract
+ */
+ void setContract(Contract contract);
}
http://git-wip-us.apache.org/repos/asf/camel/blob/7ba090f5/camel-core/src/main/java/org/apache/camel/spi/Transformer.java
----------------------------------------------------------------------
diff --git a/camel-core/src/main/java/org/apache/camel/spi/Transformer.java b/camel-core/src/main/java/org/apache/camel/spi/Transformer.java
new file mode 100644
index 0000000..adee678
--- /dev/null
+++ b/camel-core/src/main/java/org/apache/camel/spi/Transformer.java
@@ -0,0 +1,128 @@
+/**
+ * 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.spi;
+
+import java.io.InputStream;
+import java.io.OutputStream;
+
+import org.apache.camel.CamelContext;
+import org.apache.camel.CamelContextAware;
+import org.apache.camel.Exchange;
+import org.apache.camel.Message;
+import org.apache.camel.support.ServiceSupport;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+/**
+ * <a href="http://camel.apache.org/transformer.html">Transformer</a>
+ * represents Any to Any data transformation which leverages data format and endpoint
+ * under the cover.
+ */
+public abstract class Transformer extends ServiceSupport implements CamelContextAware {
+
+ private CamelContext camelContext;
+ private String model;
+ private DataType from;
+ private DataType to;
+
+ /**
+ * Perform data transformation with specified from/to type.
+ * @param message message to apply transformation
+ * @param from 'from' data type
+ * @param to 'to' data type
+ */
+ public abstract void transform(Message message, DataType from, DataType to) throws Exception;
+
+ /**
+ * Get a data model which is supported by this transformer.
+ * @return data model
+ */
+ public String getModel() {
+ return model;
+ };
+
+ /**
+ * Get 'from' data type.
+ * @return 'from' data type
+ */
+ public DataType getFrom() {
+ return from;
+ };
+
+ /**
+ * Get 'to' data type.
+ * @return 'to' data type
+ */
+ public DataType getTo() {
+ return to;
+ };
+
+ /**
+ * Set data model.
+ * @param model data model
+ * @return this Transformer instance
+ */
+ public Transformer setModel(String model) {
+ this.model = model;
+ return this;
+ }
+
+ /**
+ * Set 'from' data type.
+ * @param from 'from' data type
+ * @return this Transformer instance
+ */
+ public Transformer setFrom(String from) {
+ this.from = new DataType(from);
+ return this;
+ }
+
+ /**
+ * Set 'to' data type.
+ * @param to 'to' data type
+ * @return this Transformer instance
+ */
+ public Transformer setTo(String to) {
+ this.to = new DataType(to);
+ return this;
+ }
+
+ @Override
+ public CamelContext getCamelContext() {
+ return this.camelContext;
+ }
+
+ @Override
+ public void setCamelContext(CamelContext context) {
+ this.camelContext = context;
+ }
+
+ @Override
+ public String toString() {
+ return String.format("%s[model='%s', from='%s', to='%s']", this.getClass().getSimpleName(), from, to);
+ }
+
+ @Override
+ protected void doStart() throws Exception {
+ // no-op
+ }
+
+ @Override
+ protected void doStop() throws Exception {
+ // no-op
+ }
+}