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
+    }
+}