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 2017/02/22 14:27:47 UTC

[1/4] camel git commit: CAMEL-10538 Added inputTypeWithValidate()/outputTypeWithValidate() instead of adding boolean parameter. Fixed doc.

Repository: camel
Updated Branches:
  refs/heads/master f507f4eed -> d676a2f43


CAMEL-10538 Added inputTypeWithValidate()/outputTypeWithValidate() instead of adding boolean parameter. Fixed doc.


Project: http://git-wip-us.apache.org/repos/asf/camel/repo
Commit: http://git-wip-us.apache.org/repos/asf/camel/commit/d676a2f4
Tree: http://git-wip-us.apache.org/repos/asf/camel/tree/d676a2f4
Diff: http://git-wip-us.apache.org/repos/asf/camel/diff/d676a2f4

Branch: refs/heads/master
Commit: d676a2f43632578dcfa6ca4ef069ad163cb9db8b
Parents: f9946b2
Author: Tomohisa Igarashi <tm...@gmail.com>
Authored: Wed Feb 22 21:42:00 2017 +0900
Committer: Claus Ibsen <da...@apache.org>
Committed: Wed Feb 22 14:00:32 2017 +0100

----------------------------------------------------------------------
 camel-core/src/main/docs/validator.adoc         | 13 ++--
 .../org/apache/camel/model/RouteDefinition.java | 72 +++++++++++++-------
 .../impl/validator/ValidatorContractTest.java   |  4 +-
 .../impl/validator/ValidatorRouteTest.java      |  8 +--
 .../java/sample/camel/SampleCamelRouter.java    |  2 +-
 5 files changed, 63 insertions(+), 36 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/camel/blob/d676a2f4/camel-core/src/main/docs/validator.adoc
----------------------------------------------------------------------
diff --git a/camel-core/src/main/docs/validator.adoc b/camel-core/src/main/docs/validator.adoc
index afae832..477bdcd 100644
--- a/camel-core/src/main/docs/validator.adoc
+++ b/camel-core/src/main/docs/validator.adoc
@@ -78,7 +78,7 @@ XML DSL:
 -------------------------------------------------------------------
 <predicateValidator Type="csv:CSVOrder">
     <simple>${body} contains '{name:XOrder'</simple>
-</dataFormatTransformer>
+</predicateValidator>
 -------------------------------------------------------------------
 
 
@@ -107,8 +107,10 @@ And here is an example to specify endpoint ref in XML DSL:
 -------------------------------------------------------------------
 <endpointValidator uri="validator:xsd/schema.xsd" type="xml"/>
 -------------------------------------------------------------------
-
-
+Note that the Endpoint Validator just forwards the message to the specified endpoint. In above example,
+camel forwards the message to the `validator:` endpoint, which actually is a
+link:validator-component.adoc[Validation Component]. You can also use any other validation component like
+link:bean-validation.html[Bean Validation Component].
 
 [[Validator-Custom]]
 Custom Validator Options
@@ -166,13 +168,14 @@ XML DSL:
 -------------------------------------------------------------------
 
 If you have following route definition, above validator will be applied when `direct:abc` endpoint
-receives the message. Note that the `validate` attribute on the inputType declaration is set to `true`:
+receives the message. Note that `inputTypeWithValidate` is used instead of `inputType` in Java DSL,
+and the `validate` attribute on the inputType declaration is set to `true` in XML DSL:
 
 Java DSL:
 [source,java]
 -------------------------------------------------------------------
 from("direct:abc")
-    .inputType("xml:ABCOrder", true)
+    .inputTypeWithValidate("xml:ABCOrder")
     .log("${body}");
 -------------------------------------------------------------------
 

http://git-wip-us.apache.org/repos/asf/camel/blob/d676a2f4/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 0a3a7ac..688cb64 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
@@ -636,90 +636,114 @@ public class RouteDefinition extends ProcessorDefinition<RouteDefinition> {
 
     /**
      * Declare an input type.
+     * 
+     * @see {@link org.apache.camel.spi.Transformer}
      * @param urn input type URN
-     * @param validate if it's true, content validation is performed for this input type
      * @return the builder
      */
-    public RouteDefinition inputType(String urn, boolean validate) {
+    public RouteDefinition inputType(String urn) {
         inputType = new InputTypeDefinition();
         inputType.setUrn(urn);
-        inputType.setValidate(validate);
+        inputType.setValidate(false);
         return this;
     }
 
     /**
-     * Declare an input type.
+     * Declare an input type with validation enabled.
+     * 
+     * @see {@link org.apache.camel.spi.Transformer}, {@link org.apache.camel.spi.Validator}
      * @param urn input type URN
      * @return the builder
      */
-    public RouteDefinition inputType(String urn) {
-        return inputType(urn, false);
+    public RouteDefinition inputTypeWithValidate(String urn) {
+        inputType = new InputTypeDefinition();
+        inputType.setUrn(urn);
+        inputType.setValidate(true);
+        return this;
     }
 
     /**
      * Declare an input type with Java class.
+     * 
+     * @see {@link org.apache.camel.spi.Transformer}
      * @param clazz Class object of the input type
-     * @param validate if it's true, content validation is performed for this input type
      * @return the builder
      */
-    public RouteDefinition inputType(Class clazz, boolean validate) {
+    public RouteDefinition inputType(Class clazz) {
         inputType = new InputTypeDefinition();
         inputType.setJavaClass(clazz);
-        inputType.setValidate(validate);
+        inputType.setValidate(false);
         return this;
     }
 
     /**
-     * Declare an input type with Java class.
+     * Declare an input type with Java class with validation enabled.
+     * 
+     * @see {@link org.apache.camel.spi.Transformer}, {@link org.apache.camel.spi.Validator}
      * @param clazz Class object of the input type
      * @return the builder
      */
-    public RouteDefinition inputType(Class clazz) {
-        return inputType(clazz, false);
+    public RouteDefinition inputTypeWithValidate(Class clazz) {
+        inputType = new InputTypeDefinition();
+        inputType.setJavaClass(clazz);
+        inputType.setValidate(true);
+        return this;
     }
 
     /**
      * Declare an output type.
+     * 
+     * @see {@link org.apache.camel.spi.Transformer}
      * @param urn output type URN
-     * @param validate if it's true, content validation is performed for this output type
      * @return the builder
      */
-    public RouteDefinition outputType(String urn, boolean validate) {
+    public RouteDefinition outputType(String urn) {
         outputType = new OutputTypeDefinition();
         outputType.setUrn(urn);
-        outputType.setValidate(validate);
+        outputType.setValidate(false);
         return this;
     }
 
     /**
-     * Declare an output type.
+     * Declare an output type with validation enabled.
+     * 
+     * @see {@link org.apache.camel.spi.Transformer}, {@link org.apache.camel.spi.Validator}
      * @param urn output type URN
      * @return the builder
      */
-    public RouteDefinition outputType(String urn) {
-        return outputType(urn, false);
+    public RouteDefinition outputTypeWithValidate(String urn) {
+        outputType = new OutputTypeDefinition();
+        outputType.setUrn(urn);
+        outputType.setValidate(true);
+        return this;
     }
 
     /**
      * Declare an output type with Java class.
+     * 
+     * @see {@link org.apache.camel.spi.Transformer}
      * @param clazz Class object of the output type
-     * @param validate if it's true, content validation is performed for this output type
      * @return the builder
      */
-    public RouteDefinition outputType(Class clazz, boolean validate) {
+    public RouteDefinition outputType(Class clazz) {
         outputType = new OutputTypeDefinition();
         outputType.setJavaClass(clazz);
-        outputType.setValidate(validate);
+        outputType.setValidate(false);
         return this;
     }
 
     /**
-     * Declare an output type with Java class.
+     * Declare an output type with Java class with validation enabled.
+     * 
+     * @see {@link org.apache.camel.spi.Transformer}, {@link org.apache.camel.spi.Validator}
      * @param clazz Class object of the output type
      * @return the builder
      */
-    public RouteDefinition outputType(Class clazz) {
-        return outputType(clazz, false);
+    public RouteDefinition outputTypeWithValidate(Class clazz) {
+        outputType = new OutputTypeDefinition();
+        outputType.setJavaClass(clazz);
+        outputType.setValidate(true);
+        return this;
     }
 
     // Properties

http://git-wip-us.apache.org/repos/asf/camel/blob/d676a2f4/camel-core/src/test/java/org/apache/camel/impl/validator/ValidatorContractTest.java
----------------------------------------------------------------------
diff --git a/camel-core/src/test/java/org/apache/camel/impl/validator/ValidatorContractTest.java b/camel-core/src/test/java/org/apache/camel/impl/validator/ValidatorContractTest.java
index 8633010..a5f65cc 100644
--- a/camel-core/src/test/java/org/apache/camel/impl/validator/ValidatorContractTest.java
+++ b/camel-core/src/test/java/org/apache/camel/impl/validator/ValidatorContractTest.java
@@ -50,7 +50,7 @@ public class ValidatorContractTest extends ContextTestSupport {
                     .type(A.class)
                     .withUri("direct:validator");
                 from("direct:a")
-                    .inputType(A.class, true)
+                    .inputTypeWithValidate(A.class)
                     .to("mock:a");
                 from("direct:validator")
                     .to("mock:validator");
@@ -82,7 +82,7 @@ public class ValidatorContractTest extends ContextTestSupport {
                     .type(A.class)
                     .withUri("direct:validator");
                 from("direct:a")
-                    .outputType(A.class, true)
+                    .outputTypeWithValidate(A.class)
                     .to("mock:a");
                 from("direct:validator")
                     .to("mock:validator");

http://git-wip-us.apache.org/repos/asf/camel/blob/d676a2f4/camel-core/src/test/java/org/apache/camel/impl/validator/ValidatorRouteTest.java
----------------------------------------------------------------------
diff --git a/camel-core/src/test/java/org/apache/camel/impl/validator/ValidatorRouteTest.java b/camel-core/src/test/java/org/apache/camel/impl/validator/ValidatorRouteTest.java
index 3d3f7f1..3d92741 100644
--- a/camel-core/src/test/java/org/apache/camel/impl/validator/ValidatorRouteTest.java
+++ b/camel-core/src/test/java/org/apache/camel/impl/validator/ValidatorRouteTest.java
@@ -99,7 +99,7 @@ public class ValidatorRouteTest extends ContextTestSupport {
                     .type("json")
                     .withExpression(bodyAs(String.class).contains("{name:XOrder}"));
                 from("direct:predicate")
-                    .inputType("json:JsonXOrder", true)
+                    .inputTypeWithValidate("json:JsonXOrder")
                     .outputType("json:JsonXOrderResponse")
                     .setBody(simple("{name:XOrderResponse}"))
                     .setProperty(Exchange.OUTPUT_TYPE, constant("json:JsonXOrderResponse"));
@@ -110,7 +110,7 @@ public class ValidatorRouteTest extends ContextTestSupport {
                     .withUri("myxml:endpoint");
                 from("direct:endpoint")
                     .inputType("xml:XmlXOrder")
-                    .outputType("xml:XmlXOrderResponse", true)
+                    .outputTypeWithValidate("xml:XmlXOrderResponse")
                     .validate(exchangeProperty(VALIDATOR_INVOKED).isNull())
                     .setBody(simple("<XOrderResponse/>"))
                     .setProperty(Exchange.OUTPUT_TYPE, constant("xml:XmlXOrderResponse"));
@@ -122,8 +122,8 @@ public class ValidatorRouteTest extends ContextTestSupport {
                     .type("other:OtherXOrderResponse")
                     .withJava(OtherXOrderResponseValidator.class);
                 from("direct:custom")
-                    .inputType("other:OtherXOrder", true)
-                    .outputType("other:OtherXOrderResponse", true)
+                    .inputTypeWithValidate("other:OtherXOrder")
+                    .outputTypeWithValidate("other:OtherXOrderResponse")
                     .validate(exchangeProperty(VALIDATOR_INVOKED).isEqualTo(OtherXOrderValidator.class))
                     .setBody(simple("name=XOrderResponse"))
                     .setProperty(Exchange.OUTPUT_TYPE, constant("other:OtherXOrderResponse"));

http://git-wip-us.apache.org/repos/asf/camel/blob/d676a2f4/examples/camel-example-validator-spring-boot/src/main/java/sample/camel/SampleCamelRouter.java
----------------------------------------------------------------------
diff --git a/examples/camel-example-validator-spring-boot/src/main/java/sample/camel/SampleCamelRouter.java b/examples/camel-example-validator-spring-boot/src/main/java/sample/camel/SampleCamelRouter.java
index b7535ea..d6a4dcf 100644
--- a/examples/camel-example-validator-spring-boot/src/main/java/sample/camel/SampleCamelRouter.java
+++ b/examples/camel-example-validator-spring-boot/src/main/java/sample/camel/SampleCamelRouter.java
@@ -34,7 +34,7 @@ public class SampleCamelRouter extends RouteBuilder {
             .withBean("greetingValidator");
         
         from("timer:hello?period={{timer.period}}")
-            .outputType("greeting", true)
+            .outputTypeWithValidate("greeting")
             .transform(method("myBean", "saySomething"))
             .to("stream:out");
     }


[2/4] camel git commit: CAMEL-10538 Add declarative validator according to input/output type

Posted by da...@apache.org.
http://git-wip-us.apache.org/repos/asf/camel/blob/f9946b2e/examples/README.adoc
----------------------------------------------------------------------
diff --git a/examples/README.adoc b/examples/README.adoc
index 9eeae55..08e5ff5 100644
--- a/examples/README.adoc
+++ b/examples/README.adoc
@@ -93,7 +93,9 @@ Number of Examples: 84
 | link:camel-example-transformer-cdi/README.md[Transformer CDI] (camel-example-transformer-cdi) | Input/Output Type Contract | An example demonstrating declarative transformation along data type declaration using Java DSL and CDI
   
 
-| link:camel-example-transformer-demo/README.md[Transformer Spring XML] (camel-example-transformer-demo) | Input/Output Type Contract | An example demonstrating declarative transformation along data type declaration using Spring DSL
+| link:camel-example-transformer-demo/README.md[Transformer and Validator Spring XML] (camel-example-transformer-demo) | Input/Output Type Contract | An example demonstrating declarative transformation and validation along data type declaration using Spring DSL
+
+| link:camel-example-validator-spring-boot/README.md[Validator Spring Boot] (camel-example-validator-spring-boot) | Input/Output Type Contract | An example demonstrating declarative validation along data type declaration using Spring Boot
 
 | link:camel-example-bam/README.md[BAM (deprecated)] (camel-example-bam) | Management and Monitoring | *deprecated* An example showing how to use Camel as a Business Activity Monitoring tool
 

http://git-wip-us.apache.org/repos/asf/camel/blob/f9946b2e/examples/camel-example-transformer-demo/README.md
----------------------------------------------------------------------
diff --git a/examples/camel-example-transformer-demo/README.md b/examples/camel-example-transformer-demo/README.md
index 8f203f8..11123d9 100644
--- a/examples/camel-example-transformer-demo/README.md
+++ b/examples/camel-example-transformer-demo/README.md
@@ -1,9 +1,9 @@
-# Declarative Transformer Demo using Spring XML
+# Declarative Transformer and Validator Demo using Spring XML
 
 
 ### Introduction
 
-This example shows how to work with declarative transformation by declaring data types.
+This example shows how to work with declarative transformation and validation by declaring data types.
 
 ### Build
 
@@ -20,6 +20,10 @@ To run the example type
 You can see the routing rules by looking at the Spring XML configuration lives in
 `src/main/resources/META-INF/spring`
 
+If you enable DEBUG level log for org.apache.camel.processor, you can see the details
+of when/which transformers & validators are applied. Check the
+`src/main/resources/log4j2.properties`
+
 
 ### Forum, Help, etc
 

http://git-wip-us.apache.org/repos/asf/camel/blob/f9946b2e/examples/camel-example-transformer-demo/pom.xml
----------------------------------------------------------------------
diff --git a/examples/camel-example-transformer-demo/pom.xml b/examples/camel-example-transformer-demo/pom.xml
index af3759c..d81a437 100644
--- a/examples/camel-example-transformer-demo/pom.xml
+++ b/examples/camel-example-transformer-demo/pom.xml
@@ -27,12 +27,12 @@
 
   <artifactId>camel-example-transformer-demo</artifactId>
   <name>Camel :: Example :: Transformer :: Demo</name>
-  <description>An example demonstrating declarative transformation along data type declaration using Spring DSL</description>
+  <description>An example demonstrating declarative transformation and validation along data type declaration using Spring DSL</description>
   <packaging>jar</packaging>
 
   <properties>
     <category>Input/Output Type Contract</category>
-    <title>Transformer Spring XML</title>
+    <title>Transformer and Validator Spring XML</title>
   </properties>
 
   <dependencies>

http://git-wip-us.apache.org/repos/asf/camel/blob/f9946b2e/examples/camel-example-transformer-demo/src/main/java/org/apache/camel/example/transformer/demo/OrderResponseValidator.java
----------------------------------------------------------------------
diff --git a/examples/camel-example-transformer-demo/src/main/java/org/apache/camel/example/transformer/demo/OrderResponseValidator.java b/examples/camel-example-transformer-demo/src/main/java/org/apache/camel/example/transformer/demo/OrderResponseValidator.java
new file mode 100644
index 0000000..2ebf9f3
--- /dev/null
+++ b/examples/camel-example-transformer-demo/src/main/java/org/apache/camel/example/transformer/demo/OrderResponseValidator.java
@@ -0,0 +1,26 @@
+package org.apache.camel.example.transformer.demo;
+
+import org.apache.camel.Message;
+import org.apache.camel.ValidationException;
+import org.apache.camel.spi.DataType;
+import org.apache.camel.spi.Validator;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+public class OrderResponseValidator extends Validator {
+    private static final Logger LOG = LoggerFactory.getLogger(OrderResponseValidator.class);
+
+    @Override
+    public void validate(Message message, DataType type) throws ValidationException {
+        Object body = message.getBody();
+        LOG.info("Validating message body: {}", body);
+        if (!(body instanceof OrderResponse)) {
+            throw new ValidationException(message.getExchange(), "Expected OrderResponse, but was " + body.getClass());
+        }
+        OrderResponse r = (OrderResponse)body;
+        if (!r.isAccepted()) {
+            throw new ValidationException(message.getExchange(), "Order was not accepted:" + r);
+        }
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/camel/blob/f9946b2e/examples/camel-example-transformer-demo/src/main/resources/META-INF/spring/camel-context.xml
----------------------------------------------------------------------
diff --git a/examples/camel-example-transformer-demo/src/main/resources/META-INF/spring/camel-context.xml b/examples/camel-example-transformer-demo/src/main/resources/META-INF/spring/camel-context.xml
index 09c3b72..fa22fe0 100644
--- a/examples/camel-example-transformer-demo/src/main/resources/META-INF/spring/camel-context.xml
+++ b/examples/camel-example-transformer-demo/src/main/resources/META-INF/spring/camel-context.xml
@@ -51,13 +51,23 @@
             <camel:dataFormatTransformer ref="jsondf" scheme="json"/>
         </camel:transformers>
         <!-- END SNIPPET: e3 -->
+        <!-- START SNIPPET: e8 -->
+        <camel:validators>
+            <camel:endpointValidator type="xml" uri="validator:xsd/schema.xsd"/>
+            <camel:predicateValidator type="json">
+                <camel:simple>${body} contains 'orderId' and ${body} not contains 'accepted'</camel:simple>
+            </camel:predicateValidator>
+            <camel:customValidator type="java:org.apache.camel.example.transformer.demo.OrderResponse"
+            className="org.apache.camel.example.transformer.demo.OrderResponseValidator"/>
+        </camel:validators>
+        <!-- END SNIPPET: e8 -->
 
         <!-- START SNIPPET: e4 -->
         <camel:route id="xml">
             <camel:from uri="direct:xml"/>
             <!--  This route expects XML as an input/output type -->
-            <camel:inputType urn="xml:XMLOrder"/>
-            <camel:outputType urn="xml:XMLOrderResponse"/>
+            <camel:inputType urn="xml:XMLOrder" validate="true"/>
+            <camel:outputType urn="xml:XMLOrderResponse" validate="true"/>
             <camel:to uri="direct:java"/>
         </camel:route>
         <!-- END SNIPPET: e4 -->
@@ -67,7 +77,7 @@
             <camel:from uri="direct:json"/>
             <!--  This route expects JSON as an input/output type -->
             <!--  Only scheme 'json' is specified for the type, which means it handles arbitrary JSON content -->
-            <camel:inputType urn="json"/>
+            <camel:inputType urn="json" validate="true"/>
             <camel:outputType urn="json"/>
             <camel:to uri="direct:java"/>
         </camel:route>
@@ -81,7 +91,7 @@
             <!--  If it comes from json route, the JSON-Java transformer is applied. -->
             <!--  If it's sent via ProducerTemplate directly without specifying input/output type, no transformer is applied. -->
             <camel:inputType urn="java:org.apache.camel.example.transformer.demo.Order"/>
-            <camel:outputType urn="java:org.apache.camel.example.transformer.demo.OrderResponse"/>
+            <camel:outputType urn="java:org.apache.camel.example.transformer.demo.OrderResponse" validate="true"/>
             <camel:wireTap uri="direct:csv"/>
             <camel:process ref="orderProcessor"/>
         </camel:route>

http://git-wip-us.apache.org/repos/asf/camel/blob/f9946b2e/examples/camel-example-transformer-demo/src/main/resources/xsd/schema.xsd
----------------------------------------------------------------------
diff --git a/examples/camel-example-transformer-demo/src/main/resources/xsd/schema.xsd b/examples/camel-example-transformer-demo/src/main/resources/xsd/schema.xsd
new file mode 100644
index 0000000..cd1455e
--- /dev/null
+++ b/examples/camel-example-transformer-demo/src/main/resources/xsd/schema.xsd
@@ -0,0 +1,22 @@
+<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
+<xs:schema version="1.0" xmlns:xs="http://www.w3.org/2001/XMLSchema">
+
+  <xs:element name="order" type="order"/>
+
+  <xs:element name="orderResponse" type="orderResponse"/>
+
+  <xs:complexType name="order">
+    <xs:sequence/>
+    <xs:attribute name="orderId" type="xs:string"/>
+    <xs:attribute name="itemId" type="xs:string"/>
+    <xs:attribute name="quantity" type="xs:int" use="required"/>
+  </xs:complexType>
+
+  <xs:complexType name="orderResponse">
+    <xs:sequence/>
+    <xs:attribute name="orderId" type="xs:string"/>
+    <xs:attribute name="accepted" type="xs:boolean" use="required"/>
+    <xs:attribute name="description" type="xs:string"/>
+  </xs:complexType>
+</xs:schema>
+

http://git-wip-us.apache.org/repos/asf/camel/blob/f9946b2e/examples/camel-example-validator-spring-boot/pom.xml
----------------------------------------------------------------------
diff --git a/examples/camel-example-validator-spring-boot/pom.xml b/examples/camel-example-validator-spring-boot/pom.xml
new file mode 100644
index 0000000..91ebba2
--- /dev/null
+++ b/examples/camel-example-validator-spring-boot/pom.xml
@@ -0,0 +1,120 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+    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.
+-->
+<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
+
+  <modelVersion>4.0.0</modelVersion>
+
+  <parent>
+    <groupId>org.apache.camel</groupId>
+    <artifactId>examples</artifactId>
+    <version>2.19.0-SNAPSHOT</version>
+  </parent>
+
+  <artifactId>camel-example-validator-spring-boot</artifactId>
+  <name>Camel :: Example :: Validator :: Spring Boot</name>
+  <description>An example showing how to work with declarative validation and Spring Boot</description>
+
+  <properties>
+    <category>Input/Output Type Contract</category>
+    <title>Validator Spring Boot</title>
+
+    <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
+    <project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
+    <spring.boot-version>${spring-boot-version}</spring.boot-version>
+  </properties>
+
+  <dependencyManagement>
+    <dependencies>
+      <!-- Spring Boot BOM -->
+      <dependency>
+        <groupId>org.springframework.boot</groupId>
+        <artifactId>spring-boot-dependencies</artifactId>
+        <version>${spring.boot-version}</version>
+        <type>pom</type>
+        <scope>import</scope>
+      </dependency>
+      <!-- Camel BOM -->
+      <dependency>
+        <groupId>org.apache.camel</groupId>
+        <artifactId>camel-spring-boot-dependencies</artifactId>
+        <version>${project.version}</version>
+        <type>pom</type>
+        <scope>import</scope>
+      </dependency>
+    </dependencies>
+  </dependencyManagement>
+
+  <dependencies>
+
+    <!-- Spring Boot -->
+    <dependency>
+      <groupId>org.springframework.boot</groupId>
+      <artifactId>spring-boot-starter-web</artifactId>
+    </dependency>
+    <dependency>
+      <groupId>org.springframework.boot</groupId>
+      <artifactId>spring-boot-starter-undertow</artifactId>
+    </dependency>
+    <dependency>
+      <groupId>org.springframework.boot</groupId>
+      <artifactId>spring-boot-actuator</artifactId>
+    </dependency>
+
+    <!-- Camel -->
+    <dependency>
+      <groupId>org.apache.camel</groupId>
+      <artifactId>camel-spring-boot-starter</artifactId>
+    </dependency>
+    <dependency>
+      <groupId>org.apache.camel</groupId>
+      <artifactId>camel-stream-starter</artifactId>
+    </dependency>
+
+    <!-- test -->
+    <dependency>
+      <groupId>org.springframework.boot</groupId>
+      <artifactId>spring-boot-starter-test</artifactId>
+      <scope>test</scope>
+    </dependency>
+    <dependency>
+      <groupId>org.apache.camel</groupId>
+      <artifactId>camel-test-spring</artifactId>
+      <scope>test</scope>
+    </dependency>
+
+  </dependencies>
+
+  <build>
+    <plugins>
+      <plugin>
+        <groupId>org.springframework.boot</groupId>
+        <artifactId>spring-boot-maven-plugin</artifactId>
+        <version>${spring-boot-version}</version>
+        <executions>
+          <execution>
+            <goals>
+              <goal>repackage</goal>
+            </goals>
+          </execution>
+        </executions>
+      </plugin>
+    </plugins>
+  </build>
+
+</project>

http://git-wip-us.apache.org/repos/asf/camel/blob/f9946b2e/examples/camel-example-validator-spring-boot/readme.adoc
----------------------------------------------------------------------
diff --git a/examples/camel-example-validator-spring-boot/readme.adoc b/examples/camel-example-validator-spring-boot/readme.adoc
new file mode 100644
index 0000000..1bc83e4
--- /dev/null
+++ b/examples/camel-example-validator-spring-boot/readme.adoc
@@ -0,0 +1,28 @@
+# Camel Example Validator Spring Boot
+
+This example shows how to work with a simple Apache Camel application using Spring Boot with declarative content validation enabled.
+
+The example generates messages using timer trigger, writes them to standard output. The output type is declared as `greeting`, which has corresponding validator defined.
+
+## Camel routes
+
+The Camel route is located in the `SampleCamelRouter` class. In this class the route
+starts from a timer, that triggers every 2nd second and calls a Spring Bean `SampleBean`
+which returns a message, that is routed to a stream endpoint which writes to standard output.
+The output type is declared as `greeting`, and the validator `GreetingValidator` is registered
+to be triggered for `greeting` output message right after the routing. 
+
+## Using Camel components
+
+Apache Camel provides 200+ components which you can use to integrate and route messages between many systems
+and data formats. To use any of these Camel components, add the component as a dependency to your project.
+
+## How to run
+
+You can run this example using
+
+    mvn spring-boot:run
+
+## More information
+
+You can find more information about Apache Camel at the website: http://camel.apache.org/

http://git-wip-us.apache.org/repos/asf/camel/blob/f9946b2e/examples/camel-example-validator-spring-boot/src/main/java/sample/camel/GreetingValidator.java
----------------------------------------------------------------------
diff --git a/examples/camel-example-validator-spring-boot/src/main/java/sample/camel/GreetingValidator.java b/examples/camel-example-validator-spring-boot/src/main/java/sample/camel/GreetingValidator.java
new file mode 100644
index 0000000..79129ff
--- /dev/null
+++ b/examples/camel-example-validator-spring-boot/src/main/java/sample/camel/GreetingValidator.java
@@ -0,0 +1,31 @@
+package sample.camel;
+
+import org.apache.camel.Message;
+import org.apache.camel.ValidationException;
+import org.apache.camel.spi.DataType;
+import org.apache.camel.spi.Validator;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.springframework.beans.factory.annotation.Value;
+import org.springframework.stereotype.Component;
+
+@Component("greetingValidator")
+public class GreetingValidator extends Validator {
+
+    private static final Logger LOG = LoggerFactory.getLogger(GreetingValidator.class);
+
+    @Value("${greeting}")
+    private String greeting;
+
+    @Override
+    public void validate(Message message, DataType type) throws ValidationException {
+        Object body = message.getBody();
+        LOG.info("Validating : [{}]", body);
+        if (body instanceof String && body.equals(greeting)) {
+            LOG.info("OK");
+        } else {
+            throw new ValidationException(message.getExchange(), "Wrong content");
+        }
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/camel/blob/f9946b2e/examples/camel-example-validator-spring-boot/src/main/java/sample/camel/SampleBean.java
----------------------------------------------------------------------
diff --git a/examples/camel-example-validator-spring-boot/src/main/java/sample/camel/SampleBean.java b/examples/camel-example-validator-spring-boot/src/main/java/sample/camel/SampleBean.java
new file mode 100644
index 0000000..b60ef69
--- /dev/null
+++ b/examples/camel-example-validator-spring-boot/src/main/java/sample/camel/SampleBean.java
@@ -0,0 +1,38 @@
+/**
+ * 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 sample.camel;
+
+import org.springframework.beans.factory.annotation.Value;
+import org.springframework.stereotype.Component;
+
+/**
+ * A bean that returns a message when you call the {@link #saySomething()} method.
+ * <p/>
+ * Uses <tt>@Component("myBean")</tt> to register this bean with the name <tt>myBean</tt>
+ * that we use in the Camel route to lookup this bean.
+ */
+@Component("myBean")
+public class SampleBean {
+
+    @Value("${greeting}")
+    private String say;
+
+    public String saySomething() {
+        return say;
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/camel/blob/f9946b2e/examples/camel-example-validator-spring-boot/src/main/java/sample/camel/SampleCamelApplication.java
----------------------------------------------------------------------
diff --git a/examples/camel-example-validator-spring-boot/src/main/java/sample/camel/SampleCamelApplication.java b/examples/camel-example-validator-spring-boot/src/main/java/sample/camel/SampleCamelApplication.java
new file mode 100644
index 0000000..5d9304a
--- /dev/null
+++ b/examples/camel-example-validator-spring-boot/src/main/java/sample/camel/SampleCamelApplication.java
@@ -0,0 +1,37 @@
+/**
+ * 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 sample.camel;
+
+import org.springframework.boot.SpringApplication;
+import org.springframework.boot.autoconfigure.SpringBootApplication;
+
+//CHECKSTYLE:OFF
+/**
+ * A sample Spring Boot application that starts the Camel routes.
+ */
+@SpringBootApplication
+public class SampleCamelApplication {
+
+    /**
+     * A main method to start this application.
+     */
+    public static void main(String[] args) {
+        SpringApplication.run(SampleCamelApplication.class, args);
+    }
+
+}
+//CHECKSTYLE:ON

http://git-wip-us.apache.org/repos/asf/camel/blob/f9946b2e/examples/camel-example-validator-spring-boot/src/main/java/sample/camel/SampleCamelRouter.java
----------------------------------------------------------------------
diff --git a/examples/camel-example-validator-spring-boot/src/main/java/sample/camel/SampleCamelRouter.java b/examples/camel-example-validator-spring-boot/src/main/java/sample/camel/SampleCamelRouter.java
new file mode 100644
index 0000000..b7535ea
--- /dev/null
+++ b/examples/camel-example-validator-spring-boot/src/main/java/sample/camel/SampleCamelRouter.java
@@ -0,0 +1,42 @@
+/**
+ * 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 sample.camel;
+
+import org.apache.camel.builder.RouteBuilder;
+import org.springframework.stereotype.Component;
+
+/**
+ * A simple Camel route that triggers from a timer and calls a bean and prints to system out.
+ * <p/>
+ * Use <tt>@Component</tt> to make Camel auto detect this route when starting.
+ */
+@Component
+public class SampleCamelRouter extends RouteBuilder {
+
+    @Override
+    public void configure() throws Exception {
+        validator()
+            .type("greeting")
+            .withBean("greetingValidator");
+        
+        from("timer:hello?period={{timer.period}}")
+            .outputType("greeting", true)
+            .transform(method("myBean", "saySomething"))
+            .to("stream:out");
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/camel/blob/f9946b2e/examples/camel-example-validator-spring-boot/src/main/resources/application.properties
----------------------------------------------------------------------
diff --git a/examples/camel-example-validator-spring-boot/src/main/resources/application.properties b/examples/camel-example-validator-spring-boot/src/main/resources/application.properties
new file mode 100644
index 0000000..1d32a64
--- /dev/null
+++ b/examples/camel-example-validator-spring-boot/src/main/resources/application.properties
@@ -0,0 +1,28 @@
+#
+# 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 name of Camel
+camel.springboot.name = SampleCamel
+
+# properties used in the Camel route and beans
+# --------------------------------------------
+
+# what to say
+greeting = Hello World
+
+# how often to trigger the timer
+timer.period = 2000

http://git-wip-us.apache.org/repos/asf/camel/blob/f9946b2e/examples/camel-example-validator-spring-boot/src/test/java/sample/camel/SampleCamelApplicationTest.java
----------------------------------------------------------------------
diff --git a/examples/camel-example-validator-spring-boot/src/test/java/sample/camel/SampleCamelApplicationTest.java b/examples/camel-example-validator-spring-boot/src/test/java/sample/camel/SampleCamelApplicationTest.java
new file mode 100644
index 0000000..7d53276
--- /dev/null
+++ b/examples/camel-example-validator-spring-boot/src/test/java/sample/camel/SampleCamelApplicationTest.java
@@ -0,0 +1,47 @@
+/**
+ * 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 sample.camel;
+
+import java.util.concurrent.TimeUnit;
+
+import org.apache.camel.CamelContext;
+import org.apache.camel.builder.NotifyBuilder;
+import org.apache.camel.test.spring.CamelSpringBootRunner;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.boot.test.context.SpringBootTest;
+
+import static org.junit.Assert.assertTrue;
+
+@RunWith(CamelSpringBootRunner.class)
+@SpringBootTest(classes = SampleCamelApplication.class)
+public class SampleCamelApplicationTest {
+
+    @Autowired
+    private CamelContext camelContext;
+
+    @Test
+    public void shouldProduceMessages() throws Exception {
+        // we expect that one or more messages is automatic done by the Camel
+        // route as it uses a timer to trigger
+        NotifyBuilder notify = new NotifyBuilder(camelContext).whenDone(1).create();
+
+        assertTrue(notify.matches(10, TimeUnit.SECONDS));
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/camel/blob/f9946b2e/examples/pom.xml
----------------------------------------------------------------------
diff --git a/examples/pom.xml b/examples/pom.xml
index a0c31a1..05a2e98 100644
--- a/examples/pom.xml
+++ b/examples/pom.xml
@@ -110,6 +110,7 @@
     <module>camel-example-twitter-salesforce</module>
     <module>camel-example-twitter-websocket</module>
     <module>camel-example-twitter-websocket-blueprint</module>
+    <module>camel-example-validator-spring-boot</module>
     <module>camel-example-widget-gadget-cdi</module>
     <module>camel-example-widget-gadget-java</module>
     <module>camel-example-widget-gadget-xml</module>

http://git-wip-us.apache.org/repos/asf/camel/blob/f9946b2e/platforms/commands/commands-core/src/main/java/org/apache/camel/commands/AbstractLocalCamelController.java
----------------------------------------------------------------------
diff --git a/platforms/commands/commands-core/src/main/java/org/apache/camel/commands/AbstractLocalCamelController.java b/platforms/commands/commands-core/src/main/java/org/apache/camel/commands/AbstractLocalCamelController.java
index a4d33d4..f37d85b 100644
--- a/platforms/commands/commands-core/src/main/java/org/apache/camel/commands/AbstractLocalCamelController.java
+++ b/platforms/commands/commands-core/src/main/java/org/apache/camel/commands/AbstractLocalCamelController.java
@@ -47,6 +47,7 @@ import org.apache.camel.spi.ManagementAgent;
 import org.apache.camel.spi.RestRegistry;
 import org.apache.camel.spi.RuntimeEndpointRegistry;
 import org.apache.camel.spi.Transformer;
+import org.apache.camel.spi.Validator;
 import org.apache.camel.util.JsonSchemaHelper;
 
 /**
@@ -646,6 +647,27 @@ public abstract class AbstractLocalCamelController extends AbstractCamelControll
         return answer;
     }
 
+    @Override
+    public List<Map<String, String>> getValidators(String camelContextName) throws Exception {
+        List<Map<String, String>> answer = new ArrayList<Map<String, String>>();
+
+        if (camelContextName != null) {
+            CamelContext context = this.getLocalCamelContext(camelContextName);
+            if (context != null) {
+                List<Validator> validators = new ArrayList<Validator>(context.getValidatorRegistry().values());
+                for (Validator validator : validators) {
+                    Map<String, String> row = new LinkedHashMap<String, String>();
+                    row.put("camelContextName", context.getName());
+                    row.put("type", validator.getType().toString());
+                    row.put("state", validator.getStatus().toString());
+                    row.put("description", validator.toString());
+                    answer.add(row);
+                }
+            }
+        }
+        return answer;
+    }
+
     private static String getEndpointState(Endpoint endpoint) {
         // must use String type to be sure remote JMX can read the attribute without requiring Camel classes.
         if (endpoint instanceof StatefulService) {

http://git-wip-us.apache.org/repos/asf/camel/blob/f9946b2e/platforms/commands/commands-core/src/main/java/org/apache/camel/commands/CamelController.java
----------------------------------------------------------------------
diff --git a/platforms/commands/commands-core/src/main/java/org/apache/camel/commands/CamelController.java b/platforms/commands/commands-core/src/main/java/org/apache/camel/commands/CamelController.java
index 2cf70a4..67de587 100644
--- a/platforms/commands/commands-core/src/main/java/org/apache/camel/commands/CamelController.java
+++ b/platforms/commands/commands-core/src/main/java/org/apache/camel/commands/CamelController.java
@@ -376,4 +376,13 @@ public interface CamelController {
      * @throws java.lang.Exception can be thrown
      */
     List<Map<String, String>> getTransformers(String camelContextName) throws Exception;
+
+    /**
+     * Return the validators
+     *
+     * @param camelContextName the Camel context.
+     * @return a list of key/value pairs with validator information
+     * @throws java.lang.Exception can be thrown
+     */
+    List<Map<String, String>> getValidators(String camelContextName) throws Exception;
 }

http://git-wip-us.apache.org/repos/asf/camel/blob/f9946b2e/platforms/commands/commands-core/src/main/java/org/apache/camel/commands/ValidatorListCommand.java
----------------------------------------------------------------------
diff --git a/platforms/commands/commands-core/src/main/java/org/apache/camel/commands/ValidatorListCommand.java b/platforms/commands/commands-core/src/main/java/org/apache/camel/commands/ValidatorListCommand.java
new file mode 100644
index 0000000..07608f0
--- /dev/null
+++ b/platforms/commands/commands-core/src/main/java/org/apache/camel/commands/ValidatorListCommand.java
@@ -0,0 +1,185 @@
+/**
+ * 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.commands;
+
+import java.io.PrintStream;
+import java.net.URLDecoder;
+import java.util.HashMap;
+import java.util.Hashtable;
+import java.util.List;
+import java.util.Map;
+
+import org.apache.camel.util.JsonSchemaHelper;
+import org.apache.camel.util.ObjectHelper;
+import org.apache.camel.util.URISupport;
+
+/**
+ * List the Camel validators available in the JVM.
+ */
+public class ValidatorListCommand extends AbstractCamelCommand {
+
+    private static final String CONTEXT_NAME_COLUMN_LABEL = "Context";
+    private static final String TYPE_COLUMN_LABEL = "Type";
+    private static final String STATE_COLUMN_LABEL = "State";
+    private static final String DESCRIPTION_COLUMN_LABEL = "Description";
+
+    private static final int DEFAULT_COLUMN_WIDTH_INCREMENT = 0;
+    private static final String DEFAULT_FIELD_PREAMBLE = " ";
+    private static final String DEFAULT_FIELD_POSTAMBLE = " ";
+    private static final String DEFAULT_HEADER_PREAMBLE = " ";
+    private static final String DEFAULT_HEADER_POSTAMBLE = " ";
+    private static final int DEFAULT_FORMAT_BUFFER_LENGTH = 24;
+    // endpoint uris can be very long so clip by default after 120 chars
+    private static final int MAX_COLUMN_WIDTH = 120;
+    private static final int MIN_COLUMN_WIDTH = 12;
+
+    boolean decode = true;
+    boolean verbose;
+    boolean explain;
+    private final String context;
+
+    public ValidatorListCommand(String context, boolean decode, boolean verbose, boolean explain) {
+        this.decode = decode;
+        this.verbose = verbose;
+        this.explain = explain;
+        this.context = context;
+    }
+
+    @Override
+    public Object execute(CamelController camelController, PrintStream out, PrintStream err) throws Exception {
+        final List<Map<String, String>> camelContextInfos = camelController.getCamelContexts(this.context);
+        final Map<String, List<Map<String, String>>> contextsToValidators = new HashMap<>();
+        
+        for (Map<String, String> camelContextInfo : camelContextInfos) {
+            String camelContextName = camelContextInfo.get("name");
+            final List<Map<String, String>> validators = camelController.getValidators(camelContextName);
+            if (validators.isEmpty()) {
+                continue;
+            }
+            contextsToValidators.put(camelContextName, validators);
+        }
+
+        final Map<String, Integer> columnWidths = computeColumnWidths(contextsToValidators);
+        final String headerFormat = buildFormatString(columnWidths, true);
+        final String rowFormat = buildFormatString(columnWidths, false);
+
+        for (Map.Entry<String, List<Map<String, String>>> stringListEntry : contextsToValidators.entrySet()) {
+            final String camelContextName = stringListEntry.getKey();
+            final List<Map<String, String>> validators = stringListEntry.getValue();
+
+            if (verbose) {
+                out.println(String.format(headerFormat, CONTEXT_NAME_COLUMN_LABEL, TYPE_COLUMN_LABEL, STATE_COLUMN_LABEL, DESCRIPTION_COLUMN_LABEL));
+                out.println(String.format(headerFormat, "-------", "----", "-----", "-----------"));
+            } else {
+                out.println(String.format(headerFormat, CONTEXT_NAME_COLUMN_LABEL, TYPE_COLUMN_LABEL, STATE_COLUMN_LABEL));
+                out.println(String.format(headerFormat, "-------", "----", "-----"));
+            }
+            for (Map<String, String> row : validators) {
+                String type = row.get("type");
+                String state = row.get("state");
+                if (verbose) {
+                    String desc = row.get("description");
+                    out.println(String.format(rowFormat, camelContextName, type, state, desc));
+                } else {
+                    out.println(String.format(rowFormat, camelContextName, type, state));
+                }
+            }
+        }
+        return null;
+    }
+
+    private Map<String, Integer> computeColumnWidths(final Map<String, List<Map<String, String>>> contextsToValidators) throws Exception {
+        int maxCamelContextLen = 0;
+        int maxTypeLen = 0;
+        int maxStatusLen = 0;
+        int maxDescLen = 0;
+
+        for (Map.Entry<String, List<Map<String, String>>> stringListEntry : contextsToValidators.entrySet()) {
+            final String camelContextName = stringListEntry.getKey();
+
+            maxCamelContextLen = java.lang.Math.max(maxCamelContextLen, camelContextName.length());
+            
+            final List<Map<String, String>> validators = stringListEntry.getValue();
+
+
+            for (Map<String, String> row : validators) {
+                String type = row.get("type");
+                maxTypeLen = java.lang.Math.max(maxTypeLen, type == null ? 0 : type.length());
+                String status = row.get("state");
+                maxStatusLen = java.lang.Math.max(maxStatusLen, status == null ? 0 : status.length());
+                if (verbose) {
+                    String desc = row.get("description");
+                    maxDescLen = java.lang.Math.max(maxDescLen, desc == null ? 0 : desc.length());
+                }
+            }
+        }
+    
+        final Map<String, Integer> retval = new Hashtable<>();
+        retval.put(CONTEXT_NAME_COLUMN_LABEL, maxCamelContextLen);
+        retval.put(TYPE_COLUMN_LABEL, maxTypeLen);
+        retval.put(STATE_COLUMN_LABEL, maxStatusLen);
+        if (verbose) {
+            retval.put(DESCRIPTION_COLUMN_LABEL, maxDescLen);
+        }
+
+        return retval;
+    }
+
+    private String buildFormatString(final Map<String, Integer> columnWidths, final boolean isHeader) {
+        final String fieldPreamble;
+        final String fieldPostamble;
+        final int columnWidthIncrement;
+
+        if (isHeader) {
+            fieldPreamble = DEFAULT_HEADER_PREAMBLE;
+            fieldPostamble = DEFAULT_HEADER_POSTAMBLE;
+        } else {
+            fieldPreamble = DEFAULT_FIELD_PREAMBLE;
+            fieldPostamble = DEFAULT_FIELD_POSTAMBLE;
+        }
+        columnWidthIncrement = DEFAULT_COLUMN_WIDTH_INCREMENT;
+
+        int ctxLen = java.lang.Math.min(columnWidths.get(CONTEXT_NAME_COLUMN_LABEL) + columnWidthIncrement, getMaxColumnWidth());
+        ctxLen = Math.max(MIN_COLUMN_WIDTH, ctxLen);
+        int typeLen = java.lang.Math.min(columnWidths.get(TYPE_COLUMN_LABEL) + columnWidthIncrement, getMaxColumnWidth());
+        typeLen = Math.max(MIN_COLUMN_WIDTH, typeLen);
+        int stateLen = -1;
+        if (verbose) {
+            stateLen = java.lang.Math.min(columnWidths.get(STATE_COLUMN_LABEL) + columnWidthIncrement, getMaxColumnWidth());
+            stateLen = Math.max(MIN_COLUMN_WIDTH, stateLen);
+        }
+        // last row does not have min width
+
+        final StringBuilder retval = new StringBuilder(DEFAULT_FORMAT_BUFFER_LENGTH);
+        retval.append(fieldPreamble).append("%-").append(ctxLen).append('.').append(ctxLen).append('s').append(fieldPostamble).append(' ');
+        retval.append(fieldPreamble).append("%-").append(typeLen).append('.').append(typeLen).append('s').append(fieldPostamble).append(' ');
+        if (verbose) {
+            retval.append(fieldPreamble).append("%-").append(stateLen).append('.').append(stateLen).append('s').append(fieldPostamble).append(' ');
+        }
+        retval.append(fieldPreamble).append("%s").append(fieldPostamble).append(' ');
+
+        return retval.toString();
+    }
+
+    private int getMaxColumnWidth() {
+        if (verbose) {
+            return Integer.MAX_VALUE;
+        } else {
+            return MAX_COLUMN_WIDTH;
+        }
+    }
+}

http://git-wip-us.apache.org/repos/asf/camel/blob/f9946b2e/platforms/commands/commands-core/src/test/java/org/apache/camel/commands/AbstractLocalCamelControllerTest.java
----------------------------------------------------------------------
diff --git a/platforms/commands/commands-core/src/test/java/org/apache/camel/commands/AbstractLocalCamelControllerTest.java b/platforms/commands/commands-core/src/test/java/org/apache/camel/commands/AbstractLocalCamelControllerTest.java
index 682ac0d..896dd46 100644
--- a/platforms/commands/commands-core/src/test/java/org/apache/camel/commands/AbstractLocalCamelControllerTest.java
+++ b/platforms/commands/commands-core/src/test/java/org/apache/camel/commands/AbstractLocalCamelControllerTest.java
@@ -21,11 +21,13 @@ import java.util.Map;
 
 import org.apache.camel.CamelContext;
 import org.apache.camel.Message;
+import org.apache.camel.ValidationException;
 import org.apache.camel.builder.RouteBuilder;
 import org.apache.camel.impl.DefaultCamelContext;
 import org.apache.camel.impl.ExplicitCamelContextNameStrategy;
 import org.apache.camel.spi.DataType;
 import org.apache.camel.spi.Transformer;
+import org.apache.camel.spi.Validator;
 import org.junit.After;
 import org.junit.Before;
 import org.junit.Test;
@@ -50,6 +52,9 @@ public class AbstractLocalCamelControllerTest {
                     .fromType("xml:foo")
                     .toType("json:bar")
                     .withJava(DummyTransformer.class);
+                validator()
+                    .type("xml:foo")
+                    .withJava(DummyValidator.class);
                 from("direct:start1").id("route1").delay(100).to("mock:result1");
                 from("direct:start2").id("route2").delay(100).to("mock:result2");
                 from("direct:start3").id("route3").delay(100).to("mock:result3");
@@ -117,7 +122,6 @@ public class AbstractLocalCamelControllerTest {
 
     @Test
     public void testTransformer() throws Exception {
-        context.resolveTransformer(new DataType("xml:foo"), new DataType("json:bar"));
         List<Map<String, String>> transformers = localCamelController.getTransformers("context1");
         assertEquals(1, transformers.size());
         Map<String, String> dummyTransformer = transformers.get(0);
@@ -129,9 +133,26 @@ public class AbstractLocalCamelControllerTest {
         assertEquals("Started", dummyTransformer.get("state"));
     }
 
+    @Test
+    public void testValidator() throws Exception {
+        List<Map<String, String>> validators = localCamelController.getValidators("context1");
+        assertEquals(1, validators.size());
+        Map<String, String> dummyValidator = validators.get(0);
+        assertEquals("context1", dummyValidator.get("camelContextName"));
+        assertEquals("DummyValidator[type='xml:foo']", dummyValidator.get("description"));
+        assertEquals("xml:foo", dummyValidator.get("type"));
+        assertEquals("Started", dummyValidator.get("state"));
+    }
+
     public static class DummyTransformer extends Transformer {
         @Override
         public void transform(Message message, DataType from, DataType to) throws Exception {
         }
     }
+
+    public static class DummyValidator extends Validator {
+        @Override
+        public void validate(Message message, DataType type) throws ValidationException {
+        }
+    }
 }

http://git-wip-us.apache.org/repos/asf/camel/blob/f9946b2e/platforms/commands/commands-core/src/test/java/org/apache/camel/commands/TransformerListCommandTest.java
----------------------------------------------------------------------
diff --git a/platforms/commands/commands-core/src/test/java/org/apache/camel/commands/TransformerListCommandTest.java b/platforms/commands/commands-core/src/test/java/org/apache/camel/commands/TransformerListCommandTest.java
index 5f71849..0acd9e5 100644
--- a/platforms/commands/commands-core/src/test/java/org/apache/camel/commands/TransformerListCommandTest.java
+++ b/platforms/commands/commands-core/src/test/java/org/apache/camel/commands/TransformerListCommandTest.java
@@ -78,18 +78,15 @@ public class TransformerListCommandTest {
         etd.setToType("json:bar");
         etd.setUri("direct:transformer");
         context.getTransformers().add(etd);
-        context.resolveTransformer(new DataType("xml:foo"), new DataType("json:bar"));
         DataFormatTransformerDefinition dftd = new DataFormatTransformerDefinition();
         dftd.setFromType(this.getClass());
         dftd.setToType("xml:test");
         dftd.setDataFormatType(new StringDataFormat());
         context.getTransformers().add(dftd);
-        context.resolveTransformer(new DataType(this.getClass()), new DataType("xml:test"));
         CustomTransformerDefinition ctd = new CustomTransformerDefinition();
         ctd.setScheme("custom");
-        ctd.setType(MyTransformer.class.getName());
+        ctd.setClassName(MyTransformer.class.getName());
         context.getTransformers().add(ctd);
-        context.resolveTransformer("custom");
         context.setNameStrategy(new ExplicitCamelContextNameStrategy("foobar"));
         context.start();
 

http://git-wip-us.apache.org/repos/asf/camel/blob/f9946b2e/platforms/commands/commands-core/src/test/java/org/apache/camel/commands/ValidatorListCommandTest.java
----------------------------------------------------------------------
diff --git a/platforms/commands/commands-core/src/test/java/org/apache/camel/commands/ValidatorListCommandTest.java b/platforms/commands/commands-core/src/test/java/org/apache/camel/commands/ValidatorListCommandTest.java
new file mode 100644
index 0000000..3457520
--- /dev/null
+++ b/platforms/commands/commands-core/src/test/java/org/apache/camel/commands/ValidatorListCommandTest.java
@@ -0,0 +1,121 @@
+/**
+ * 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.commands;
+
+import java.io.ByteArrayOutputStream;
+import java.io.OutputStream;
+import java.io.PrintStream;
+
+import org.apache.camel.CamelContext;
+import org.apache.camel.Message;
+import org.apache.camel.ValidationException;
+import org.apache.camel.builder.ExpressionBuilder;
+import org.apache.camel.builder.PredicateBuilder;
+import org.apache.camel.builder.RouteBuilder;
+import org.apache.camel.builder.SimpleBuilder;
+import org.apache.camel.impl.DefaultCamelContext;
+import org.apache.camel.impl.ExplicitCamelContextNameStrategy;
+import org.apache.camel.model.dataformat.StringDataFormat;
+import org.apache.camel.model.language.ExpressionDefinition;
+import org.apache.camel.model.transformer.CustomTransformerDefinition;
+import org.apache.camel.model.transformer.DataFormatTransformerDefinition;
+import org.apache.camel.model.transformer.EndpointTransformerDefinition;
+import org.apache.camel.model.validator.CustomValidatorDefinition;
+import org.apache.camel.model.validator.EndpointValidatorDefinition;
+import org.apache.camel.model.validator.PredicateValidatorDefinition;
+import org.apache.camel.spi.DataType;
+import org.apache.camel.spi.Transformer;
+import org.apache.camel.spi.Validator;
+import org.junit.Test;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertTrue;
+
+public class ValidatorListCommandTest {
+
+    private static final Logger LOG = LoggerFactory.getLogger(ValidatorListCommandTest.class);
+
+    @Test
+    public void testValidatorList() throws Exception {
+        String out = doTest(false);
+        assertTrue(out.contains("xml:foo"));
+        assertTrue(out.contains("java:" + this.getClass().getName()));
+        assertTrue(out.contains("custom"));
+        assertTrue(out.contains("Started"));
+        assertFalse(out.contains("ProcessorValidator["));
+        assertFalse(out.contains("processor='validate(body)'"));
+        assertFalse(out.contains("processor='sendTo(direct://validator)'"));
+        assertFalse(out.contains("MyValidator["));
+    }
+    
+    @Test
+    public void testValidatorListVerbose() throws Exception {
+        String out = doTest(true);
+        assertTrue(out.contains("xml:foo"));
+        assertTrue(out.contains("java:" + this.getClass().getName()));
+        assertTrue(out.contains("custom"));
+        assertTrue(out.contains("Started"));
+        assertTrue(out.contains("ProcessorValidator["));
+        assertTrue(out.contains("processor='validate(body)'"));
+        assertTrue(out.contains("processor='sendTo(direct://validator)'"));
+        assertTrue(out.contains("MyValidator["));
+    }
+    
+    private String doTest(boolean verbose) throws Exception {
+        CamelContext context = new DefaultCamelContext();
+        EndpointValidatorDefinition evd = new EndpointValidatorDefinition();
+        evd.setType("xml:foo");
+        evd.setUri("direct:validator");
+        context.getValidators().add(evd);
+        PredicateValidatorDefinition pvd = new PredicateValidatorDefinition();
+        pvd.setType(this.getClass());
+        pvd.setExpression(new ExpressionDefinition(ExpressionBuilder.bodyExpression()));
+        context.getValidators().add(pvd);
+        CustomValidatorDefinition cvd = new CustomValidatorDefinition();
+        cvd.setType("custom");
+        cvd.setClassName(MyValidator.class.getName());
+        context.getValidators().add(cvd);
+        context.setNameStrategy(new ExplicitCamelContextNameStrategy("foobar"));
+        context.start();
+
+        CamelController controller = new DummyCamelController(context);
+
+        OutputStream os = new ByteArrayOutputStream();
+        PrintStream ps = new PrintStream(os);
+
+        ValidatorListCommand command = new ValidatorListCommand(null, false, verbose, false);
+        command.execute(controller, ps, null);
+
+        String out = os.toString();
+        assertNotNull(out);
+        LOG.info("\n\n{}\n", out);
+
+        context.stop();
+        return out;
+    }
+
+    public static class MyValidator extends Validator {
+        @Override
+        public void validate(Message message, DataType type) throws ValidationException {
+            return;
+        }
+    }
+}
+

http://git-wip-us.apache.org/repos/asf/camel/blob/f9946b2e/platforms/commands/commands-jolokia/src/main/java/org/apache/camel/commands/jolokia/DefaultJolokiaCamelController.java
----------------------------------------------------------------------
diff --git a/platforms/commands/commands-jolokia/src/main/java/org/apache/camel/commands/jolokia/DefaultJolokiaCamelController.java b/platforms/commands/commands-jolokia/src/main/java/org/apache/camel/commands/jolokia/DefaultJolokiaCamelController.java
index e342840..cf30c39 100644
--- a/platforms/commands/commands-jolokia/src/main/java/org/apache/camel/commands/jolokia/DefaultJolokiaCamelController.java
+++ b/platforms/commands/commands-jolokia/src/main/java/org/apache/camel/commands/jolokia/DefaultJolokiaCamelController.java
@@ -820,6 +820,50 @@ public class DefaultJolokiaCamelController extends AbstractCamelController imple
         return answer;
     }
 
+    @Override
+    public List<Map<String, String>> getValidators(String camelContextName) throws Exception {
+        if (jolokia == null) {
+            throw new IllegalStateException("Need to connect to remote jolokia first");
+        }
+
+        List<Map<String, String>> answer = new ArrayList<Map<String, String>>();
+
+        ObjectName found = lookupCamelContext(camelContextName);
+        if (found != null) {
+            String pattern = String.format("%s:context=%s,type=services,name=DefaultValidatorRegistry", found.getDomain(), found.getKeyProperty("context"));
+            ObjectName on = ObjectName.getInstance(pattern);
+
+            J4pExecResponse response = jolokia.execute(new J4pExecRequest(on, "listValidators()"));
+            if (response != null) {
+                JSONObject data = response.getValue();
+                if (data != null) {
+                    for (Object obj : data.values()) {
+                        JSONObject data2 = (JSONObject) obj;
+                        JSONObject service = (JSONObject) data2.values().iterator().next();
+
+                        Map<String, String> row = new LinkedHashMap<String, String>();
+                        row.put("type", asString(service.get("type")));
+                        row.put("static", asString(service.get("static")));
+                        row.put("dynamic", asString(service.get("dynamic")));
+                        row.put("description", asString(service.get("description")));
+                        answer.add(row);
+                    }
+                }
+            }
+
+            // sort the list
+            Collections.sort(answer, new Comparator<Map<String, String>>() {
+                @Override
+                public int compare(Map<String, String> service1, Map<String, String> service2) {
+                    String type1 = service1.get("type");
+                    String type2 = service2.get("type");
+                    return type1.compareTo(type2);
+                }
+            });
+        }
+        return answer;
+    }
+
     private static String asKey(String attributeKey) {
         char ch = Character.toLowerCase(attributeKey.charAt(0));
         return ch + attributeKey.substring(1);


[3/4] camel git commit: CAMEL-10538 Add declarative validator according to input/output type

Posted by da...@apache.org.
http://git-wip-us.apache.org/repos/asf/camel/blob/f9946b2e/camel-core/src/main/java/org/apache/camel/model/validator/CustomValidatorDefinition.java
----------------------------------------------------------------------
diff --git a/camel-core/src/main/java/org/apache/camel/model/validator/CustomValidatorDefinition.java b/camel-core/src/main/java/org/apache/camel/model/validator/CustomValidatorDefinition.java
new file mode 100644
index 0000000..5c1e164
--- /dev/null
+++ b/camel-core/src/main/java/org/apache/camel/model/validator/CustomValidatorDefinition.java
@@ -0,0 +1,98 @@
+/**
+ * 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.validator;
+
+import javax.xml.bind.annotation.XmlAccessType;
+import javax.xml.bind.annotation.XmlAccessorType;
+import javax.xml.bind.annotation.XmlAttribute;
+import javax.xml.bind.annotation.XmlType;
+import org.apache.camel.CamelContext;
+import org.apache.camel.spi.Metadata;
+import org.apache.camel.spi.Transformer;
+import org.apache.camel.spi.Validator;
+
+/**
+ * Represents a CustomValidator. One of the bean reference (ref) or fully qualified class name (className)
+ * of the custom {@link Validator} needs to be specified.
+ * 
+ * {@see ValidatorDefinition}
+ * {@see Validator}
+ */
+@Metadata(label = "validation")
+@XmlType(name = "customValidator")
+@XmlAccessorType(XmlAccessType.FIELD)
+public class CustomValidatorDefinition extends ValidatorDefinition {
+
+    @XmlAttribute
+    private String ref;
+    @XmlAttribute
+    private String className;
+
+    @Override
+    protected Validator doCreateValidator(CamelContext context) throws Exception {
+        if (ref == null && className == null) {
+            throw new IllegalArgumentException("'ref' or 'type' must be specified for customValidator");
+        }
+        Validator validator;
+        if (ref != null) {
+            validator = context.getRegistry().lookupByNameAndType(ref, Validator.class);
+            if (validator == null) {
+                throw new IllegalArgumentException("Cannot find validator with ref:" + ref);
+            }
+            if (validator.getType() != null) {
+                throw new IllegalArgumentException(String.format("Validator '%s' is already in use. Please check if duplicate validator exists.", ref));
+            }
+        } else {
+            Class<Validator> validatorClass = context.getClassResolver().resolveMandatoryClass(className, Validator.class);
+            if (validatorClass == null) {
+                throw new IllegalArgumentException("Cannot find validator class: " + className);
+            }
+            validator = context.getInjector().newInstance(validatorClass);
+
+        }
+        validator.setCamelContext(context);
+        return validator.setType(getType());
+    }
+
+    public String getRef() {
+        return ref;
+    }
+
+    /**
+     * Set a bean reference of the {@link Validator}
+     *
+     * @param ref the bean reference of the Transformer
+     */
+    public void setRef(String ref) {
+        this.ref = ref;
+    }
+
+    public String getClassName() {
+        return className;
+    }
+
+    /**
+     * Set a class name of the {@link Validator}
+     *
+     * @param className the class name of the Validator
+     */
+    public void setClassName(String className) {
+        this.className = className;
+    }
+
+}
+

http://git-wip-us.apache.org/repos/asf/camel/blob/f9946b2e/camel-core/src/main/java/org/apache/camel/model/validator/EndpointValidatorDefinition.java
----------------------------------------------------------------------
diff --git a/camel-core/src/main/java/org/apache/camel/model/validator/EndpointValidatorDefinition.java b/camel-core/src/main/java/org/apache/camel/model/validator/EndpointValidatorDefinition.java
new file mode 100644
index 0000000..537216b
--- /dev/null
+++ b/camel-core/src/main/java/org/apache/camel/model/validator/EndpointValidatorDefinition.java
@@ -0,0 +1,97 @@
+/**
+ * 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.validator;
+
+import java.util.HashMap;
+import java.util.Map;
+
+import javax.xml.bind.annotation.XmlAccessType;
+import javax.xml.bind.annotation.XmlAccessorType;
+import javax.xml.bind.annotation.XmlAttribute;
+import javax.xml.bind.annotation.XmlType;
+
+import org.w3c.dom.ls.LSResourceResolver;
+
+import org.apache.camel.CamelContext;
+import org.apache.camel.Endpoint;
+import org.apache.camel.ExchangePattern;
+import org.apache.camel.component.validator.ValidatorEndpoint;
+import org.apache.camel.component.validator.ValidatorResourceResolverFactory;
+import org.apache.camel.impl.validator.ProcessorValidator;
+import org.apache.camel.processor.SendProcessor;
+import org.apache.camel.spi.Metadata;
+import org.apache.camel.spi.Validator;
+import org.apache.camel.util.ObjectHelper;
+
+/**
+ * Represents an endpoint {@link Validator} which leverages camel validator component such as
+ * <a href="http://camel.apache.org/validation.html">Validator Component</a> and 
+ * <a href="http://camel.apache.org/bean-validation.html">Bean Validator Component</a> to
+ * perform content validation. A {@link ProcessorValidator} will be created internally
+ * with a {@link SendProcessor} which forwards the message to the validator Endpoint.
+ * 
+ * {@see ValidatorDefinition}
+ * {@see Validator}
+ */
+@Metadata(label = "validation")
+@XmlType(name = "endpointValidator")
+@XmlAccessorType(XmlAccessType.FIELD)
+public class EndpointValidatorDefinition extends ValidatorDefinition {
+
+    @XmlAttribute
+    private String ref;
+    @XmlAttribute
+    private String uri;
+
+    @Override
+    protected Validator doCreateValidator(CamelContext context) throws Exception {
+        Endpoint endpoint = uri != null ? context.getEndpoint(uri)
+            : context.getRegistry().lookupByNameAndType(ref, Endpoint.class);
+        SendProcessor processor = new SendProcessor(endpoint, ExchangePattern.InOut);
+        return new ProcessorValidator(context)
+            .setProcessor(processor)
+            .setType(getType());
+    }
+
+    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/f9946b2e/camel-core/src/main/java/org/apache/camel/model/validator/PredicateValidatorDefinition.java
----------------------------------------------------------------------
diff --git a/camel-core/src/main/java/org/apache/camel/model/validator/PredicateValidatorDefinition.java b/camel-core/src/main/java/org/apache/camel/model/validator/PredicateValidatorDefinition.java
new file mode 100644
index 0000000..89f72a5
--- /dev/null
+++ b/camel-core/src/main/java/org/apache/camel/model/validator/PredicateValidatorDefinition.java
@@ -0,0 +1,76 @@
+/**
+ * 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.validator;
+
+import javax.xml.bind.annotation.XmlAccessType;
+import javax.xml.bind.annotation.XmlAccessorType;
+import javax.xml.bind.annotation.XmlAttribute;
+import javax.xml.bind.annotation.XmlElementRef;
+import javax.xml.bind.annotation.XmlType;
+import org.apache.camel.CamelContext;
+import org.apache.camel.Expression;
+import org.apache.camel.Predicate;
+import org.apache.camel.impl.validator.ProcessorValidator;
+import org.apache.camel.model.ExpressionNodeHelper;
+import org.apache.camel.model.language.ExpressionDefinition;
+import org.apache.camel.processor.validation.PredicateValidatingProcessor;
+import org.apache.camel.spi.Metadata;
+import org.apache.camel.spi.Transformer;
+import org.apache.camel.spi.Validator;
+
+/**
+ * Represents a predicate {@link Validator} which leverages expression or predicates to
+ * perform content validation. A {@link ProcessorValidator} will be created internally
+ * with a {@link PredicateValidatingProcessor} which validates the message according to specified expression/predicates.
+ * 
+ * {@see ValidatorDefinition}
+ * {@see Validator}
+ */
+@Metadata(label = "validation")
+@XmlType(name = "predicateValidator")
+@XmlAccessorType(XmlAccessType.FIELD)
+public class PredicateValidatorDefinition extends ValidatorDefinition {
+
+    @XmlElementRef
+    private ExpressionDefinition expression;
+
+    @Override
+    protected Validator doCreateValidator(CamelContext context) throws Exception {
+        Predicate pred = getExpression().createPredicate(context);
+        PredicateValidatingProcessor processor = new PredicateValidatingProcessor(pred);
+        return new ProcessorValidator(context)
+            .setProcessor(processor)
+            .setType(getType());
+    }
+
+    public ExpressionDefinition getExpression() {
+        return expression;
+    }
+
+    public void setExpression(ExpressionDefinition expression) {
+        // favour using the helper to set the expression as it can unwrap some unwanted builders when using Java DSL
+        if (expression instanceof Expression) {
+            this.expression = ExpressionNodeHelper.toExpressionDefinition((Expression) expression);
+        } else if (expression instanceof Predicate) {
+            this.expression = ExpressionNodeHelper.toExpressionDefinition((Predicate) expression);
+        } else {
+            this.expression = expression;
+        }
+    }
+
+}
+

http://git-wip-us.apache.org/repos/asf/camel/blob/f9946b2e/camel-core/src/main/java/org/apache/camel/model/validator/ValidatorDefinition.java
----------------------------------------------------------------------
diff --git a/camel-core/src/main/java/org/apache/camel/model/validator/ValidatorDefinition.java b/camel-core/src/main/java/org/apache/camel/model/validator/ValidatorDefinition.java
new file mode 100644
index 0000000..0a0db9f
--- /dev/null
+++ b/camel-core/src/main/java/org/apache/camel/model/validator/ValidatorDefinition.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.validator;
+
+import javax.xml.bind.annotation.XmlAccessType;
+import javax.xml.bind.annotation.XmlAccessorType;
+import javax.xml.bind.annotation.XmlAttribute;
+import javax.xml.bind.annotation.XmlType;
+import org.apache.camel.CamelContext;
+import org.apache.camel.model.InputTypeDefinition;
+import org.apache.camel.model.OutputTypeDefinition;
+import org.apache.camel.spi.DataType;
+import org.apache.camel.spi.Metadata;
+import org.apache.camel.spi.Validator;
+
+/**
+ * <p>Represents a {@link Validator} which declaratively validates message content
+ * according to the input type declared by {@link InputTypeDefinition} and/or output type
+ * declared by {@link OutputTypeDefinition}.</p>
+ * <p>If you specify type='xml:ABC', the validator
+ * will be picked up when current message type is 'xml:ABC'.
+ * If you specify type='json', then it will be picked up for all of json validation.
+ * 
+ * {@see Validator}
+ * {@see InputTypeDefinition}
+ * {@see OutputTypeDefinition}
+ */
+@Metadata(label = "validation")
+@XmlType(name = "validator")
+@XmlAccessorType(XmlAccessType.FIELD)
+public abstract class ValidatorDefinition {
+
+    @XmlAttribute
+    private String type;
+
+    public Validator createValidator(CamelContext context) throws Exception {
+        return doCreateValidator(context);
+    };
+
+    protected abstract Validator doCreateValidator(CamelContext context) throws Exception;
+
+    public String getType() {
+        return type;
+    }
+
+    /**
+     * Set the data type name.
+     * If you specify 'xml:XYZ', the validator will be picked up if message type is
+     * 'xml:XYZ'. If you specify just 'xml', the validator matches with all of
+     * 'xml' message type like 'xml:ABC' or 'xml:DEF'.
+     * 
+     * @param type data type name
+     */
+    public void setType(String type) {
+        this.type = type;
+    }
+
+    /**
+     * Set the data type using Java class.
+     * @param clazz Java class
+     */
+    public void setType(Class<?> clazz) {
+        this.type = new DataType(clazz).toString();
+    }
+}
+

http://git-wip-us.apache.org/repos/asf/camel/blob/f9946b2e/camel-core/src/main/java/org/apache/camel/model/validator/ValidatorsDefinition.java
----------------------------------------------------------------------
diff --git a/camel-core/src/main/java/org/apache/camel/model/validator/ValidatorsDefinition.java b/camel-core/src/main/java/org/apache/camel/model/validator/ValidatorsDefinition.java
new file mode 100644
index 0000000..cb90c2c
--- /dev/null
+++ b/camel-core/src/main/java/org/apache/camel/model/validator/ValidatorsDefinition.java
@@ -0,0 +1,54 @@
+/**
+ * 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.validator;
+
+import java.util.List;
+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.spi.Metadata;
+
+/**
+ * To configure validators.
+ */
+@Metadata(label = "validation", title = "Validations")
+@XmlRootElement(name = "validators")
+@XmlAccessorType(XmlAccessType.FIELD)
+public class ValidatorsDefinition {
+
+    @XmlElements({
+        @XmlElement(required = false, name = "endpointValidator", type = EndpointValidatorDefinition.class),
+        @XmlElement(required = false, name = "predicateValidator", type = PredicateValidatorDefinition.class),
+        @XmlElement(required = false, name = "customValidator", type = CustomValidatorDefinition.class)}
+        )
+    private List<ValidatorDefinition> validators;
+
+    /**
+     * The configured transformers
+     */
+    public void setValidators(List<ValidatorDefinition> validators) {
+        this.validators = validators;
+    }
+
+    public List<ValidatorDefinition> getValidators() {
+        return validators;
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/camel/blob/f9946b2e/camel-core/src/main/java/org/apache/camel/model/validator/package-info.java
----------------------------------------------------------------------
diff --git a/camel-core/src/main/java/org/apache/camel/model/validator/package-info.java b/camel-core/src/main/java/org/apache/camel/model/validator/package-info.java
new file mode 100644
index 0000000..14173ec
--- /dev/null
+++ b/camel-core/src/main/java/org/apache/camel/model/validator/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.validator;

http://git-wip-us.apache.org/repos/asf/camel/blob/f9946b2e/camel-core/src/main/java/org/apache/camel/processor/ContractAdvice.java
----------------------------------------------------------------------
diff --git a/camel-core/src/main/java/org/apache/camel/processor/ContractAdvice.java b/camel-core/src/main/java/org/apache/camel/processor/ContractAdvice.java
index a3dad33..6a53e7b 100644
--- a/camel-core/src/main/java/org/apache/camel/processor/ContractAdvice.java
+++ b/camel-core/src/main/java/org/apache/camel/processor/ContractAdvice.java
@@ -19,9 +19,11 @@ package org.apache.camel.processor;
 import org.apache.camel.CamelContext;
 import org.apache.camel.Exchange;
 import org.apache.camel.Message;
+import org.apache.camel.ValidationException;
 import org.apache.camel.spi.Contract;
 import org.apache.camel.spi.DataType;
 import org.apache.camel.spi.Transformer;
+import org.apache.camel.spi.Validator;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
@@ -29,7 +31,6 @@ import org.slf4j.LoggerFactory;
  * A {@code CamelInternalProcessorAdvice} which performs Transformation and Validation
  * according to the data type Contract.
  * 
- * TODO add declarative validation
  * @see CamelInternalProcessor, CamelInternalProcessorAdvice
  */
 public class ContractAdvice implements CamelInternalProcessorAdvice {
@@ -45,58 +46,66 @@ public class ContractAdvice implements CamelInternalProcessorAdvice {
     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);
-            doTransform(exchange.getIn(), from, to);
-            exchange.setProperty(Exchange.INPUT_TYPE, to);
+        if (to != null) {
+            if (!to.equals(from)) {
+                LOG.debug("Looking for transformer for INPUT: from='{}', to='{}'", from, to);
+                doTransform(exchange.getIn(), from, to);
+                exchange.setProperty(Exchange.INPUT_TYPE, to);
+            }
+            if (contract.isValidateInput()) {
+                doValidate(exchange.getIn(), to);
+            }
         }
         return null;
     }
     
     @Override
     public void after(Exchange exchange, Object data) throws Exception {
+        if (exchange.isFailed()) {
+            // TODO can we add FAULT_TYPE processing?
+            return;
+        }
+        
         Message target = exchange.hasOut() ? exchange.getOut() : exchange.getIn();
         if (!exchange.hasOut() && exchange.getProperty(Exchange.OUTPUT_TYPE) == null) {
             exchange.setProperty(Exchange.OUTPUT_TYPE, exchange.getProperty(Exchange.INPUT_TYPE));
         }
         DataType from = getCurrentType(exchange, Exchange.OUTPUT_TYPE);
         DataType to = contract.getOutputType();
-        if (to != null && !to.equals(from)) {
-            LOG.debug("Looking for transformer for OUTPUT: from='{}', to='{}'", from, to);
-            doTransform(target, from, to);
-            exchange.setProperty(Exchange.OUTPUT_TYPE, to);
+        if (to != null) {
+            if (!to.equals(from)) {
+                LOG.debug("Looking for transformer for OUTPUT: from='{}', to='{}'", from, to);
+                doTransform(target, from, to);
+                exchange.setProperty(Exchange.OUTPUT_TYPE, to);
+            }
+            if (contract.isValidateOutput()) {
+                doValidate(target, to);
+            }
         }
     }
     
     private void doTransform(Message message, DataType from, DataType to) throws Exception {
+        if (from == null) {
+            // If 'from' is null, only Java-Java convertion is performed.
+            // It means if 'to' is other than Java, it's assumed to be already in expected shape.
+            convertIfRequired(message, to);
+            return;
+        }
+        
         // transform into 'from' type before performing declared transformation
         convertIfRequired(message, from);
         
-        if (applyExactlyMatchedTransformer(message, from, to)) {
-            // Found exactly matched transformer. Java-Java transformer is also allowed.
+        if (applyMatchedTransformer(message, from, to)) {
+            // Found matched transformer. Java-Java transformer is also allowed.
             return;
-        } else if (from == null || from.isJavaType()) {
+        } else if (from.isJavaType()) {
             if (convertIfRequired(message, to)) {
                 // Java->Java transformation just relies on TypeConverter if no explicit transformer
                 return;
-            } else if (from == null) {
-                // use body class as a from type, or do nothing with assuming it's already in expected shape
-                applyTransformerByClass(message, to);
-                return;
-            } else if (applyTransformerByToModel(message, from, to)) {
-                // Java->Other transformation - found a transformer supports 'to' data model
-                return;
-            }
-        } else if (from != null) {
-            if (to.isJavaType()) {
-                if (applyTransformerByFromModel(message, from, to)) {
-                    // Other->Java transformation - found a transformer supprts 'from' data model
-                    return;
-                }
-            } else if (applyTransformerChain(message, from, to)) {
-                // Other->Other transformation - found a transformer chain
-                return;
             }
+        } else if (applyTransformerChain(message, from, to)) {
+            // Other->Other transformation - found a transformer chain
+            return;
         }
         
         throw new IllegalArgumentException("No Transformer found for [from='" + from + "', to='" + to + "']");
@@ -125,27 +134,11 @@ public class ContractAdvice implements CamelInternalProcessorAdvice {
         }
         return false;
     }
-    private boolean applyExactlyMatchedTransformer(Message message, DataType from, DataType to) throws Exception {
+    private boolean applyMatchedTransformer(Message message, DataType from, DataType to) throws Exception {
         Transformer transformer = message.getExchange().getContext().resolveTransformer(from, to);
         return applyTransformer(transformer, message, from, to);
     }
     
-    private boolean applyTransformerByClass(Message message, DataType to) throws Exception {
-        DataType from = new DataType(message.getBody().getClass());
-        Transformer transformer = message.getExchange().getContext().resolveTransformer(from, to);
-        return applyTransformer(transformer, message, from, to);
-    }
-    
-    private boolean applyTransformerByToModel(Message message, DataType from, DataType to) throws Exception {
-        Transformer transformer = message.getExchange().getContext().resolveTransformer(to.getModel());
-        return applyTransformer(transformer, message, from, to);
-    }
-    
-    private boolean applyTransformerByFromModel(Message message, DataType from, DataType to) throws Exception {
-        Transformer transformer = message.getExchange().getContext().resolveTransformer(from.getModel());
-        return applyTransformer(transformer, message, from, to);
-    }
-    
     private boolean applyTransformerChain(Message message, DataType from, DataType to) throws Exception {
         CamelContext context = message.getExchange().getContext();
         Transformer fromTransformer = context.resolveTransformer(from.getModel());
@@ -175,4 +168,14 @@ public class ContractAdvice implements CamelInternalProcessorAdvice {
         }
         return null;
     }
+
+    private void doValidate(Message message, DataType type) throws ValidationException {
+        Validator validator = message.getExchange().getContext().resolveValidator(type);
+        if (validator != null) {
+            LOG.debug("Applying validator: type='{}', validator='{}'", type, validator);
+            validator.validate(message, type);
+        } else {
+            throw new ValidationException(message.getExchange(), String.format("No Validator found for '%s'", type));
+        }
+    }
 }
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/camel/blob/f9946b2e/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
index 8cc90c9..b9de3bf 100644
--- a/camel-core/src/main/java/org/apache/camel/spi/Contract.java
+++ b/camel-core/src/main/java/org/apache/camel/spi/Contract.java
@@ -23,6 +23,8 @@ public class Contract {
 
     private DataType inputType;
     private DataType outputType;
+    private boolean validateInput;
+    private boolean validateOutput;
     private String contractString;
     
     public DataType getInputType() {
@@ -69,6 +71,38 @@ public class Contract {
         this.contractString = null;
     }
     
+    /**
+     * 
+     * @return
+     */
+    public boolean isValidateInput() {
+        return validateInput;
+    }
+    
+    /**
+     * 
+     * @param validate
+     */
+    public void setValidateInput(boolean validate) {
+        this.validateInput = validate;
+    }
+    
+    /**
+     * 
+     * @return
+     */
+    public boolean isValidateOutput() {
+        return validateOutput;
+    }
+    
+    /**
+     * 
+     * @param validate
+     */
+    public void setValidateOutput(boolean validate) {
+        this.validateOutput = validate;
+    }
+    
     @Override
     public String toString() {
         if (contractString == null) {

http://git-wip-us.apache.org/repos/asf/camel/blob/f9946b2e/camel-core/src/main/java/org/apache/camel/spi/TransformerRegistry.java
----------------------------------------------------------------------
diff --git a/camel-core/src/main/java/org/apache/camel/spi/TransformerRegistry.java b/camel-core/src/main/java/org/apache/camel/spi/TransformerRegistry.java
index 85acd1c..c4d73d4 100644
--- a/camel-core/src/main/java/org/apache/camel/spi/TransformerRegistry.java
+++ b/camel-core/src/main/java/org/apache/camel/spi/TransformerRegistry.java
@@ -16,10 +16,12 @@
  */
 package org.apache.camel.spi;
 
+import java.util.List;
 import java.util.Map;
 
 import org.apache.camel.Endpoint;
 import org.apache.camel.StaticService;
+import org.apache.camel.model.transformer.TransformerDefinition;
 
 /**
  * Registry to cache transformers in memory.
@@ -40,6 +42,14 @@ import org.apache.camel.StaticService;
 public interface TransformerRegistry<K> extends Map<K, Transformer>, StaticService {
 
     /**
+     * Lookup a {@link Transformer} in the registry which supports the transformation for
+     * the data types represented by the key.
+     * @param key a key represents the from/to data types to transform
+     * @return {@link Transformer} if matched, otherwise null
+     */
+    Transformer resolveTransformer(K key);
+
+    /**
      * Number of transformers in the static registry.
      */
     int staticSize();
@@ -85,7 +95,7 @@ public interface TransformerRegistry<K> extends Map<K, Transformer>, StaticServi
     boolean isDynamic(String scheme);
 
     /**
-     * Whether the given transformer is stored in the dynamic cache
+     * Whether the given {@link Transformer} is stored in the dynamic cache
      *
      * @param from 'from' data type
      * @param to 'to' data type

http://git-wip-us.apache.org/repos/asf/camel/blob/f9946b2e/camel-core/src/main/java/org/apache/camel/spi/Validator.java
----------------------------------------------------------------------
diff --git a/camel-core/src/main/java/org/apache/camel/spi/Validator.java b/camel-core/src/main/java/org/apache/camel/spi/Validator.java
new file mode 100644
index 0000000..1ba2998
--- /dev/null
+++ b/camel-core/src/main/java/org/apache/camel/spi/Validator.java
@@ -0,0 +1,96 @@
+/**
+ * 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.CamelContext;
+import org.apache.camel.CamelContextAware;
+import org.apache.camel.Exchange;
+import org.apache.camel.Message;
+import org.apache.camel.ValidationException;
+import org.apache.camel.model.InputTypeDefinition;
+import org.apache.camel.model.OutputTypeDefinition;
+import org.apache.camel.support.ServiceSupport;
+
+/**
+ * <a href="http://camel.apache.org/transformer.html">Transformer</a>
+ * performs message transformation according to the declared data type.
+ * There are two Exchange property indicates current message type, {@link Exchange#INPUT_TYPE}
+ * holds input message type and {@link Exchange#OUTPUT_TYPE} holds output message type. If the
+ * input type and/or output type declared by {@link InputTypeDefinition}
+ * and/or {@link OutputTypeDefinition} in the route definition is different from those property
+ * at runtime, camel internal processor look for a Transformer which transforms from
+ * the current message type to the expected message type.
+ *  
+ * @see InputTypeDefinition
+ * @see OutputTypeDefinition
+ */
+public abstract class Validator extends ServiceSupport implements CamelContextAware {
+
+    private CamelContext camelContext;
+    private DataType type;
+
+    /**
+     * Perform data validation with specified type.
+     *
+     * @param message message to apply validation
+     * @param type the data type
+     * @throws ValidationException thrown if any validation error is detected
+     */
+    public abstract void validate(Message message, DataType type) throws ValidationException;
+
+    /**
+     * Get 'from' data type.
+     */
+    public DataType getType() {
+        return type;
+    };
+
+    /**
+     * Set data type.
+     *
+     * @param type data type
+     */
+    public Validator setType(String type) {
+        this.type = new DataType(type);
+        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[type='%s']", this.getClass().getSimpleName(), type);
+    }
+
+    @Override
+    protected void doStart() throws Exception {
+        // no-op
+    }
+
+    @Override
+    protected void doStop() throws Exception {
+        // no-op
+    }
+}

http://git-wip-us.apache.org/repos/asf/camel/blob/f9946b2e/camel-core/src/main/java/org/apache/camel/spi/ValidatorRegistry.java
----------------------------------------------------------------------
diff --git a/camel-core/src/main/java/org/apache/camel/spi/ValidatorRegistry.java b/camel-core/src/main/java/org/apache/camel/spi/ValidatorRegistry.java
new file mode 100644
index 0000000..82d1020
--- /dev/null
+++ b/camel-core/src/main/java/org/apache/camel/spi/ValidatorRegistry.java
@@ -0,0 +1,93 @@
+/**
+ * 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.List;
+import java.util.Map;
+
+import org.apache.camel.Endpoint;
+import org.apache.camel.StaticService;
+import org.apache.camel.model.validator.ValidatorDefinition;
+
+/**
+ * Registry to cache validators in memory.
+ * <p/>
+ * The registry contains two caches:
+ * <ul>
+ *     <li>static - which keeps all the validators in the cache for the entire lifecycle</li>
+ *     <li>dynamic - which keeps the validators in a {@link org.apache.camel.util.LRUCache} and may evict validators which hasn't been requested recently</li>
+ * </ul>
+ * The static cache stores all the validators that are created as part of setting up and starting routes.
+ * The static cache has no upper limit.
+ * <p/>
+ * The dynamic cache stores the validators that are created and used ad-hoc, such as from custom Java code that creates new validators etc.
+ * The dynamic cache has an upper limit, that by default is 1000 entries.
+ *
+ * @param <K> validator key
+ */
+public interface ValidatorRegistry<K> extends Map<K, Validator>, StaticService {
+
+    /**
+     * Lookup a {@link Validator} in the registry which supports the validation for
+     * the data type represented by the key.
+     * @param key a key represents the data type
+     * @return {@link Validator} if matched, otherwise null
+     */
+    Validator resolveValidator(K key);
+
+    /**
+     * Number of validators in the static registry.
+     */
+    int staticSize();
+
+    /**
+     * Number of validators in the dynamic registry
+     */
+    int dynamicSize();
+
+    /**
+     * Maximum number of entries to store in the dynamic registry
+     */
+    int getMaximumCacheSize();
+
+    /**
+     * Purges the cache (removes validators from the dynamic cache)
+     */
+    void purge();
+
+    /**
+     * Whether the given {@link Validator} is stored in the static cache
+     *
+     * @param type  the data type
+     * @return <tt>true</tt> if in static cache, <tt>false</tt> if not
+     */
+    boolean isStatic(DataType type);
+
+    /**
+     * Whether the given {@link Validator} is stored in the dynamic cache
+     *
+     * @param type the data type
+     * @return <tt>true</tt> if in dynamic cache, <tt>false</tt> if not
+     */
+    boolean isDynamic(DataType type);
+
+    /**
+     * Cleanup the cache (purging stale entries)
+     */
+    void cleanUp();
+
+}

http://git-wip-us.apache.org/repos/asf/camel/blob/f9946b2e/camel-core/src/main/java/org/apache/camel/util/CamelContextHelper.java
----------------------------------------------------------------------
diff --git a/camel-core/src/main/java/org/apache/camel/util/CamelContextHelper.java b/camel-core/src/main/java/org/apache/camel/util/CamelContextHelper.java
index 8be19d7..a133b73 100644
--- a/camel-core/src/main/java/org/apache/camel/util/CamelContextHelper.java
+++ b/camel-core/src/main/java/org/apache/camel/util/CamelContextHelper.java
@@ -254,6 +254,68 @@ public final class CamelContextHelper {
     }
 
     /**
+     * Gets the maximum transformer cache size.
+     * <p/>
+     * Will use the property set on CamelContext with the key {@link Exchange#MAXIMUM_TRANSFORMER_CACHE_SIZE}.
+     * If no property has been set, then it will fallback to return a size of 1000.
+     *
+     * @param camelContext the camel context
+     * @return the maximum cache size
+     * @throws IllegalArgumentException is thrown if the property is illegal
+     */
+    public static int getMaximumTransformerCacheSize(CamelContext camelContext) throws IllegalArgumentException {
+        if (camelContext != null) {
+            String s = camelContext.getGlobalOption(Exchange.MAXIMUM_TRANSFORMER_CACHE_SIZE);
+            if (s != null) {
+                // we cannot use Camel type converters as they may not be ready this early
+                try {
+                    Integer size = Integer.valueOf(s);
+                    if (size == null || size <= 0) {
+                        throw new IllegalArgumentException("Property " + Exchange.MAXIMUM_TRANSFORMER_CACHE_SIZE + " must be a positive number, was: " + s);
+                    }
+                    return size;
+                } catch (NumberFormatException e) {
+                    throw new IllegalArgumentException("Property " + Exchange.MAXIMUM_TRANSFORMER_CACHE_SIZE + " must be a positive number, was: " + s, e);
+                }
+            }
+        }
+
+        // 1000 is the default fallback
+        return 1000;
+    }
+
+    /**
+     * Gets the maximum validator cache size.
+     * <p/>
+     * Will use the property set on CamelContext with the key {@link Exchange#MAXIMUM_VALIDATOR_CACHE_SIZE}.
+     * If no property has been set, then it will fallback to return a size of 1000.
+     *
+     * @param camelContext the camel context
+     * @return the maximum cache size
+     * @throws IllegalArgumentException is thrown if the property is illegal
+     */
+    public static int getMaximumValidatorCacheSize(CamelContext camelContext) throws IllegalArgumentException {
+        if (camelContext != null) {
+            String s = camelContext.getGlobalOption(Exchange.MAXIMUM_VALIDATOR_CACHE_SIZE);
+            if (s != null) {
+                // we cannot use Camel type converters as they may not be ready this early
+                try {
+                    Integer size = Integer.valueOf(s);
+                    if (size == null || size <= 0) {
+                        throw new IllegalArgumentException("Property " + Exchange.MAXIMUM_VALIDATOR_CACHE_SIZE + " must be a positive number, was: " + s);
+                    }
+                    return size;
+                } catch (NumberFormatException e) {
+                    throw new IllegalArgumentException("Property " + Exchange.MAXIMUM_VALIDATOR_CACHE_SIZE + " must be a positive number, was: " + s, e);
+                }
+            }
+        }
+
+        // 1000 is the default fallback
+        return 1000;
+    }
+
+    /**
      * Parses the given text and handling property placeholders as well
      *
      * @param camelContext the camel context

http://git-wip-us.apache.org/repos/asf/camel/blob/f9946b2e/camel-core/src/main/resources/org/apache/camel/model/validator/jaxb.index
----------------------------------------------------------------------
diff --git a/camel-core/src/main/resources/org/apache/camel/model/validator/jaxb.index b/camel-core/src/main/resources/org/apache/camel/model/validator/jaxb.index
new file mode 100644
index 0000000..7cdaef6
--- /dev/null
+++ b/camel-core/src/main/resources/org/apache/camel/model/validator/jaxb.index
@@ -0,0 +1,21 @@
+## ------------------------------------------------------------------------
+## 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.
+## ------------------------------------------------------------------------
+CustomValidatorDefinition
+EndpointValidatorDefinition
+PredicateValidatorDefinition
+ValidatorDefinition
+ValidatorsDefinition

http://git-wip-us.apache.org/repos/asf/camel/blob/f9946b2e/camel-core/src/test/java/org/apache/camel/builder/TransformerBuilderTest.java
----------------------------------------------------------------------
diff --git a/camel-core/src/test/java/org/apache/camel/builder/TransformerBuilderTest.java b/camel-core/src/test/java/org/apache/camel/builder/TransformerBuilderTest.java
index 9a7e895..1cdd30a 100644
--- a/camel-core/src/test/java/org/apache/camel/builder/TransformerBuilderTest.java
+++ b/camel-core/src/test/java/org/apache/camel/builder/TransformerBuilderTest.java
@@ -59,9 +59,11 @@ public class TransformerBuilderTest extends TestSupport {
             @Override
             public void configure() throws Exception {
                 transformer().fromType("xml:foo").toType("json:bar").withDataFormat(new StringDataFormat());
+                from("direct:input").log("test");
             }
         };
         ctx.addRoutes(builder);
+        ctx.start();
         Transformer transformer = ctx.resolveTransformer(new DataType("xml:foo"), new DataType("json:bar"));
         assertNotNull(transformer);
         assertEquals(DataFormatTransformer.class, transformer.getClass());
@@ -78,10 +80,11 @@ public class TransformerBuilderTest extends TestSupport {
             @Override
             public void configure() throws Exception {
                 transformer().fromType("json:foo").toType("xml:bar").withUri("direct:transformer");
-                from("direct:transformer");
+                from("direct:transformer").log("test");
             }
         };
         ctx.addRoutes(builder);
+        ctx.start();
         Transformer transformer = ctx.resolveTransformer(new DataType("json:foo"), new DataType("xml:bar"));
         assertNotNull(transformer);
         assertEquals(ProcessorTransformer.class, transformer.getClass());
@@ -100,9 +103,11 @@ public class TransformerBuilderTest extends TestSupport {
             @Override
             public void configure() throws Exception {
                 transformer().scheme("other").withJava(MyTransformer.class);
+                from("direct:input").log("test");
             }
         };
         ctx.addRoutes(builder);
+        ctx.start();
         Transformer transformer = ctx.resolveTransformer("other");
         assertNotNull(transformer);
         assertEquals(MyTransformer.class, transformer.getClass());

http://git-wip-us.apache.org/repos/asf/camel/blob/f9946b2e/camel-core/src/test/java/org/apache/camel/impl/MultipleLifecycleStrategyTest.java
----------------------------------------------------------------------
diff --git a/camel-core/src/test/java/org/apache/camel/impl/MultipleLifecycleStrategyTest.java b/camel-core/src/test/java/org/apache/camel/impl/MultipleLifecycleStrategyTest.java
index 2bab7f3..40ef701 100644
--- a/camel-core/src/test/java/org/apache/camel/impl/MultipleLifecycleStrategyTest.java
+++ b/camel-core/src/test/java/org/apache/camel/impl/MultipleLifecycleStrategyTest.java
@@ -51,7 +51,7 @@ public class MultipleLifecycleStrategyTest extends TestSupport {
         context.stop();
 
         List<String> expectedEvents = Arrays.asList("onContextStart", "onServiceAdd", "onServiceAdd", "onServiceAdd", "onServiceAdd", "onServiceAdd", "onServiceAdd", "onServiceAdd",
-                "onServiceAdd", "onServiceAdd", "onServiceAdd", "onServiceAdd", "onServiceAdd", "onComponentAdd", "onEndpointAdd", "onComponentRemove", "onContextStop");
+                "onServiceAdd", "onServiceAdd", "onServiceAdd", "onServiceAdd", "onServiceAdd", "onServiceAdd", "onComponentAdd", "onEndpointAdd", "onComponentRemove", "onContextStop");
         
         assertEquals(expectedEvents, dummy1.getEvents());
         assertEquals(expectedEvents, dummy2.getEvents());

http://git-wip-us.apache.org/repos/asf/camel/blob/f9946b2e/camel-core/src/test/java/org/apache/camel/impl/validator/ValidatorContractTest.java
----------------------------------------------------------------------
diff --git a/camel-core/src/test/java/org/apache/camel/impl/validator/ValidatorContractTest.java b/camel-core/src/test/java/org/apache/camel/impl/validator/ValidatorContractTest.java
new file mode 100644
index 0000000..8633010
--- /dev/null
+++ b/camel-core/src/test/java/org/apache/camel/impl/validator/ValidatorContractTest.java
@@ -0,0 +1,115 @@
+/**
+ * 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.validator;
+
+import java.io.BufferedReader;
+import java.io.InputStream;
+import java.io.InputStreamReader;
+import java.io.OutputStream;
+import java.io.OutputStreamWriter;
+import java.io.PrintWriter;
+import org.apache.camel.ContextTestSupport;
+import org.apache.camel.Converter;
+import org.apache.camel.Exchange;
+import org.apache.camel.TypeConverters;
+import org.apache.camel.builder.RouteBuilder;
+import org.apache.camel.component.mock.MockEndpoint;
+import org.apache.camel.model.DataFormatDefinition;
+import org.apache.camel.spi.DataFormat;
+import org.apache.camel.spi.RouteContext;
+import org.junit.Test;
+
+public class ValidatorContractTest extends ContextTestSupport {
+
+    @Override
+    public boolean isUseRouteBuilder() {
+        return false;
+    }
+
+    @Test
+    public void testInputTypeOnly() throws Exception {
+        context.getTypeConverterRegistry().addTypeConverters(new MyTypeConverters());
+        context.addRoutes(new RouteBuilder() {
+            @Override
+            public void configure() throws Exception {
+                validator()
+                    .type(A.class)
+                    .withUri("direct:validator");
+                from("direct:a")
+                    .inputType(A.class, true)
+                    .to("mock:a");
+                from("direct:validator")
+                    .to("mock:validator");
+            }
+        });
+        context.start();
+        
+        MockEndpoint mocka = context.getEndpoint("mock:a", MockEndpoint.class);
+        MockEndpoint mockv = context.getEndpoint("mock:validator", MockEndpoint.class);
+        mocka.setExpectedCount(1);
+        mockv.setExpectedCount(1);
+        Object answer = template.requestBody("direct:a", "foo");
+        mocka.assertIsSatisfied();
+        mockv.assertIsSatisfied();
+        Exchange exa = mocka.getExchanges().get(0);
+        assertEquals(A.class, exa.getIn().getBody().getClass());
+        Exchange exv = mockv.getExchanges().get(0);
+        assertEquals(A.class, exv.getIn().getBody().getClass());
+        assertEquals(A.class, answer.getClass());
+    }
+
+    @Test
+    public void testOutputTypeOnly() throws Exception {
+        context.getTypeConverterRegistry().addTypeConverters(new MyTypeConverters());
+        context.addRoutes(new RouteBuilder() {
+            @Override
+            public void configure() throws Exception {
+                validator()
+                    .type(A.class)
+                    .withUri("direct:validator");
+                from("direct:a")
+                    .outputType(A.class, true)
+                    .to("mock:a");
+                from("direct:validator")
+                    .to("mock:validator");
+            }
+        });
+        context.start();
+        
+        MockEndpoint mocka = context.getEndpoint("mock:a", MockEndpoint.class);
+        MockEndpoint mockv = context.getEndpoint("mock:validator", MockEndpoint.class);
+        mocka.setExpectedCount(1);
+        mockv.setExpectedCount(1);
+        Object answer = template.requestBody("direct:a", "foo");
+        mocka.assertIsSatisfied();
+        mockv.assertIsSatisfied();
+        Exchange exa = mocka.getExchanges().get(0);
+        assertEquals("foo", exa.getIn().getBody());
+        Exchange exv = mockv.getExchanges().get(0);
+        assertEquals(A.class, exv.getIn().getBody().getClass());
+        assertEquals(A.class, answer.getClass());
+    }
+
+    public static class MyTypeConverters implements TypeConverters {
+        @Converter
+        public A toA(String in) {
+            return new A();
+        }
+    }
+
+    public static class A { }
+}

http://git-wip-us.apache.org/repos/asf/camel/blob/f9946b2e/camel-core/src/test/java/org/apache/camel/impl/validator/ValidatorRouteTest.java
----------------------------------------------------------------------
diff --git a/camel-core/src/test/java/org/apache/camel/impl/validator/ValidatorRouteTest.java b/camel-core/src/test/java/org/apache/camel/impl/validator/ValidatorRouteTest.java
new file mode 100644
index 0000000..3d3f7f1
--- /dev/null
+++ b/camel-core/src/test/java/org/apache/camel/impl/validator/ValidatorRouteTest.java
@@ -0,0 +1,187 @@
+/**
+ * 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.validator;
+
+import java.io.BufferedReader;
+import java.io.InputStream;
+import java.io.InputStreamReader;
+import java.io.OutputStream;
+import java.util.Map;
+
+import org.apache.camel.AsyncCallback;
+import org.apache.camel.Consumer;
+import org.apache.camel.ContextTestSupport;
+import org.apache.camel.Converter;
+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.Producer;
+import org.apache.camel.TypeConverters;
+import org.apache.camel.ValidationException;
+import org.apache.camel.builder.RouteBuilder;
+import org.apache.camel.component.mock.MockEndpoint;
+import org.apache.camel.impl.DefaultAsyncProducer;
+import org.apache.camel.impl.DefaultComponent;
+import org.apache.camel.impl.DefaultEndpoint;
+import org.apache.camel.impl.DefaultExchange;
+import org.apache.camel.model.DataFormatDefinition;
+import org.apache.camel.spi.DataFormat;
+import org.apache.camel.spi.DataType;
+import org.apache.camel.spi.RouteContext;
+import org.apache.camel.spi.Transformer;
+import org.apache.camel.spi.Validator;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+/**
+ * A ValidatorRouteTest demonstrates contract based declarative validation via Java DSL.
+ */
+public class ValidatorRouteTest extends ContextTestSupport {
+
+    protected static final Logger LOG = LoggerFactory.getLogger(ValidatorRouteTest.class);
+    private static final String VALIDATOR_INVOKED = "validator-invoked";
+
+    public void testPredicateValidator() throws Exception {
+        Exchange exchange = new DefaultExchange(context, ExchangePattern.InOut);
+        exchange.getIn().setBody("{name:XOrder}");
+        Exchange answerEx = template.send("direct:predicate", exchange);
+        if (answerEx.getException() != null) {
+            throw answerEx.getException();
+        }
+        assertEquals("{name:XOrderResponse}", answerEx.getOut().getBody(String.class));
+    }
+
+    public void testEndpointValidator() throws Exception {
+        Exchange exchange = new DefaultExchange(context, ExchangePattern.InOut);
+        exchange.getIn().setBody("<XOrder/>");
+        Exchange answerEx = template.send("direct:endpoint", exchange);
+        if (answerEx.getException() != null) {
+            throw answerEx.getException();
+        }
+        assertEquals("<XOrderResponse/>", answerEx.getOut().getBody(String.class));
+        assertEquals(MyXmlEndpoint.class, answerEx.getProperty(VALIDATOR_INVOKED));
+    }
+
+    public void testCustomValidator() throws Exception {
+        Exchange exchange = new DefaultExchange(context, ExchangePattern.InOut);
+        exchange.getIn().setBody("name=XOrder");
+        Exchange answerEx = template.send("direct:custom", exchange);
+        if (answerEx.getException() != null) {
+            throw answerEx.getException();
+        }
+        assertEquals("name=XOrderResponse", answerEx.getOut().getBody(String.class));
+        assertEquals(OtherXOrderResponseValidator.class, answerEx.getProperty(VALIDATOR_INVOKED));
+    }
+
+    @Override
+    protected RouteBuilder createRouteBuilder() throws Exception {
+        return new RouteBuilder() {
+            @Override
+            public void configure() throws Exception {
+
+                validator()
+                    .type("json")
+                    .withExpression(bodyAs(String.class).contains("{name:XOrder}"));
+                from("direct:predicate")
+                    .inputType("json:JsonXOrder", true)
+                    .outputType("json:JsonXOrderResponse")
+                    .setBody(simple("{name:XOrderResponse}"))
+                    .setProperty(Exchange.OUTPUT_TYPE, constant("json:JsonXOrderResponse"));
+                
+                context.addComponent("myxml", new MyXmlComponent());
+                validator()
+                    .type("xml:XmlXOrderResponse")
+                    .withUri("myxml:endpoint");
+                from("direct:endpoint")
+                    .inputType("xml:XmlXOrder")
+                    .outputType("xml:XmlXOrderResponse", true)
+                    .validate(exchangeProperty(VALIDATOR_INVOKED).isNull())
+                    .setBody(simple("<XOrderResponse/>"))
+                    .setProperty(Exchange.OUTPUT_TYPE, constant("xml:XmlXOrderResponse"));
+                
+                validator()
+                    .type("other:OtherXOrder")
+                    .withJava(OtherXOrderValidator.class);
+                validator()
+                    .type("other:OtherXOrderResponse")
+                    .withJava(OtherXOrderResponseValidator.class);
+                from("direct:custom")
+                    .inputType("other:OtherXOrder", true)
+                    .outputType("other:OtherXOrderResponse", true)
+                    .validate(exchangeProperty(VALIDATOR_INVOKED).isEqualTo(OtherXOrderValidator.class))
+                    .setBody(simple("name=XOrderResponse"))
+                    .setProperty(Exchange.OUTPUT_TYPE, constant("other:OtherXOrderResponse"));
+            }
+        };
+    }
+
+    public static class MyXmlComponent extends DefaultComponent {
+        @Override
+        protected Endpoint createEndpoint(String uri, String remaining, Map<String, Object> parameters) throws Exception {
+            return new MyXmlEndpoint();
+        }
+        
+    }
+    
+    public static class MyXmlEndpoint extends DefaultEndpoint {
+        @Override
+        public Producer createProducer() throws Exception {
+            return new DefaultAsyncProducer(this) {
+                @Override
+                public boolean process(Exchange exchange, AsyncCallback callback) {
+                    exchange.setProperty(VALIDATOR_INVOKED, MyXmlEndpoint.class);
+                    assertEquals("<XOrderResponse/>", exchange.getIn().getBody());
+                    callback.done(true);
+                    return true;
+                }
+            };
+        }
+        @Override
+        public Consumer createConsumer(Processor processor) throws Exception {
+            return null;
+        }
+        @Override
+        public boolean isSingleton() {
+            return false;
+        }
+        @Override
+        protected String createEndpointUri() {
+            return "myxml:endpoint";
+        }
+    }
+    
+    public static class OtherXOrderValidator extends Validator {
+        @Override
+        public void validate(Message message, DataType type) throws ValidationException {
+            message.getExchange().setProperty(VALIDATOR_INVOKED, OtherXOrderValidator.class);
+            assertEquals("name=XOrder", message.getBody());
+            LOG.info("Java validation: other XOrder");
+        }
+    }
+    
+    public static class OtherXOrderResponseValidator extends Validator {
+        @Override
+        public void validate(Message message, DataType type) throws ValidationException {
+            message.getExchange().setProperty(VALIDATOR_INVOKED, OtherXOrderResponseValidator.class);
+            assertEquals("name=XOrderResponse", message.getBody());
+            LOG.info("Java validation: other XOrderResponse");
+        }
+    }
+    
+}

http://git-wip-us.apache.org/repos/asf/camel/blob/f9946b2e/camel-core/src/test/java/org/apache/camel/management/ManagedNonManagedServiceTest.java
----------------------------------------------------------------------
diff --git a/camel-core/src/test/java/org/apache/camel/management/ManagedNonManagedServiceTest.java b/camel-core/src/test/java/org/apache/camel/management/ManagedNonManagedServiceTest.java
index c3fcaad..b24957b 100644
--- a/camel-core/src/test/java/org/apache/camel/management/ManagedNonManagedServiceTest.java
+++ b/camel-core/src/test/java/org/apache/camel/management/ManagedNonManagedServiceTest.java
@@ -48,7 +48,7 @@ public class ManagedNonManagedServiceTest extends ManagementTestSupport {
         MBeanServer mbeanServer = getMBeanServer();
 
         Set<ObjectName> set = mbeanServer.queryNames(new ObjectName("*:type=services,*"), null);
-        assertEquals(10, set.size());
+        assertEquals(11, set.size());
     }
 
     public void testNonManagedService() throws Exception {
@@ -69,7 +69,7 @@ public class ManagedNonManagedServiceTest extends ManagementTestSupport {
         MBeanServer mbeanServer = getMBeanServer();
 
         Set<ObjectName> set = mbeanServer.queryNames(new ObjectName("*:type=services,*"), null);
-        assertEquals(9, set.size());
+        assertEquals(10, set.size());
     }
 
     @Override

http://git-wip-us.apache.org/repos/asf/camel/blob/f9946b2e/camel-core/src/test/java/org/apache/camel/management/ManagedProducerRouteAddRemoveRegisterAlwaysTest.java
----------------------------------------------------------------------
diff --git a/camel-core/src/test/java/org/apache/camel/management/ManagedProducerRouteAddRemoveRegisterAlwaysTest.java b/camel-core/src/test/java/org/apache/camel/management/ManagedProducerRouteAddRemoveRegisterAlwaysTest.java
index 55bd69f..b2b58e5 100644
--- a/camel-core/src/test/java/org/apache/camel/management/ManagedProducerRouteAddRemoveRegisterAlwaysTest.java
+++ b/camel-core/src/test/java/org/apache/camel/management/ManagedProducerRouteAddRemoveRegisterAlwaysTest.java
@@ -29,7 +29,7 @@ import org.apache.camel.component.mock.MockEndpoint;
  */
 public class ManagedProducerRouteAddRemoveRegisterAlwaysTest extends ManagementTestSupport {
 
-    private int services = 9;
+    private int services = 10;
 
     @Override
     protected CamelContext createCamelContext() throws Exception {

http://git-wip-us.apache.org/repos/asf/camel/blob/f9946b2e/camel-core/src/test/java/org/apache/camel/management/ManagedRouteAddRemoveTest.java
----------------------------------------------------------------------
diff --git a/camel-core/src/test/java/org/apache/camel/management/ManagedRouteAddRemoveTest.java b/camel-core/src/test/java/org/apache/camel/management/ManagedRouteAddRemoveTest.java
index f00528f..f4804a6 100644
--- a/camel-core/src/test/java/org/apache/camel/management/ManagedRouteAddRemoveTest.java
+++ b/camel-core/src/test/java/org/apache/camel/management/ManagedRouteAddRemoveTest.java
@@ -33,7 +33,7 @@ import org.apache.camel.component.mock.MockEndpoint;
  */
 public class ManagedRouteAddRemoveTest extends ManagementTestSupport {
     
-    private int services = 9;
+    private int services = 10;
 
     @Override
     protected RouteBuilder createRouteBuilder() throws Exception {

http://git-wip-us.apache.org/repos/asf/camel/blob/f9946b2e/camel-core/src/test/java/org/apache/camel/management/ManagedTransformerRegistryTest.java
----------------------------------------------------------------------
diff --git a/camel-core/src/test/java/org/apache/camel/management/ManagedTransformerRegistryTest.java b/camel-core/src/test/java/org/apache/camel/management/ManagedTransformerRegistryTest.java
index 96918a6..e26d3c8 100644
--- a/camel-core/src/test/java/org/apache/camel/management/ManagedTransformerRegistryTest.java
+++ b/camel-core/src/test/java/org/apache/camel/management/ManagedTransformerRegistryTest.java
@@ -33,9 +33,6 @@ import org.apache.camel.spi.Transformer;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
-/**
- * @version 
- */
 public class ManagedTransformerRegistryTest extends ManagementTestSupport {
     private static final Logger LOG = LoggerFactory.getLogger(ManagedTransformerRegistryTest.class);
 
@@ -51,11 +48,6 @@ public class ManagedTransformerRegistryTest extends ManagementTestSupport {
 
         assertMockEndpointsSatisfied();
 
-        // resolve transformers explicitly as the route doesn't actually use them
-        context.resolveTransformer(new DataType("xml:foo"), new DataType("json:bar"));
-        context.resolveTransformer(new DataType(ManagedTransformerRegistryTest.class), new DataType("xml:test"));
-        context.resolveTransformer("custom");
-
         // get the stats for the route
         MBeanServer mbeanServer = getMBeanServer();
         Set<ObjectName> set = mbeanServer.queryNames(new ObjectName("*:type=services,*"), null);

http://git-wip-us.apache.org/repos/asf/camel/blob/f9946b2e/camel-core/src/test/java/org/apache/camel/management/ManagedValidatorRegistryTest.java
----------------------------------------------------------------------
diff --git a/camel-core/src/test/java/org/apache/camel/management/ManagedValidatorRegistryTest.java b/camel-core/src/test/java/org/apache/camel/management/ManagedValidatorRegistryTest.java
new file mode 100644
index 0000000..7ceb111
--- /dev/null
+++ b/camel-core/src/test/java/org/apache/camel/management/ManagedValidatorRegistryTest.java
@@ -0,0 +1,134 @@
+/**
+ * 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.management;
+
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.List;
+import java.util.Set;
+import javax.management.MBeanServer;
+import javax.management.ObjectName;
+import javax.management.openmbean.CompositeData;
+import javax.management.openmbean.TabularData;
+
+import org.apache.camel.Message;
+import org.apache.camel.ValidationException;
+import org.apache.camel.builder.RouteBuilder;
+import org.apache.camel.model.dataformat.StringDataFormat;
+import org.apache.camel.spi.DataType;
+import org.apache.camel.spi.Validator;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+public class ManagedValidatorRegistryTest extends ManagementTestSupport {
+    private static final Logger LOG = LoggerFactory.getLogger(ManagedValidatorRegistryTest.class);
+
+    public void testManageValidatorRegistry() throws Exception {
+        // JMX tests dont work well on AIX CI servers (hangs them)
+        if (isPlatform("aix")) {
+            return;
+        }
+
+        getMockEndpoint("mock:result").expectedMessageCount(1);
+
+        template.sendBody("direct:start", "Hello World");
+
+        assertMockEndpointsSatisfied();
+
+        // get the stats for the route
+        MBeanServer mbeanServer = getMBeanServer();
+        Set<ObjectName> set = mbeanServer.queryNames(new ObjectName("*:type=services,*"), null);
+        List<ObjectName> list = new ArrayList<ObjectName>(set);
+        ObjectName on = null;
+        for (ObjectName name : list) {
+            if (name.getCanonicalName().contains("DefaultValidatorRegistry")) {
+                on = name;
+                break;
+            }
+        }
+
+        assertNotNull("Should have found ValidatorRegistry", on);
+
+        Integer max = (Integer) mbeanServer.getAttribute(on, "MaximumCacheSize");
+        assertEquals(1000, max.intValue());
+
+        Integer current = (Integer) mbeanServer.getAttribute(on, "Size");
+        assertEquals(3, current.intValue());
+
+        current = (Integer) mbeanServer.getAttribute(on, "StaticSize");
+        assertEquals(0, current.intValue());
+
+        current = (Integer) mbeanServer.getAttribute(on, "DynamicSize");
+        assertEquals(3, current.intValue());
+
+        String source = (String) mbeanServer.getAttribute(on, "Source");
+        assertTrue(source.startsWith("ValidatorRegistry"));
+        assertTrue(source.endsWith("capacity: 1000"));
+
+        
+        TabularData data = (TabularData) mbeanServer.invoke(on, "listValidators", null, null);
+        for (Object row : data.values()) {
+            CompositeData composite = (CompositeData)row;
+            String type = (String)composite.get("type");
+            String description = (String)composite.get("description");
+            boolean isStatic = (boolean)composite.get("static");
+            boolean isDynamic = (boolean)composite.get("dynamic");
+            LOG.info("[{}][{}][{}][{}]", type, isStatic, isDynamic, description);
+            if (description.startsWith("ProcessorValidator")) {
+                if (description.contains("direct://transformer")) {
+                    assertEquals("xml:foo", type);
+                } else if (description.contains("validate(simple{${body}} is not null")) {
+                    assertEquals("json:test", type);
+                } else {
+                    fail("Unexpected validator:" + description);
+                }
+            } else if (description.startsWith("MyValidator")) {
+                assertEquals("custom", type);
+            } else {
+                fail("Unexpected validator:" + description);
+            }
+        }
+        assertEquals(3, data.size());
+    }
+
+    @Override
+    protected RouteBuilder createRouteBuilder() throws Exception {
+        return new RouteBuilder() {
+            @Override
+            public void configure() throws Exception {
+                validator()
+                    .type("xml:foo")
+                    .withUri("direct:transformer");
+                validator()
+                    .type("json:test")
+                    .withExpression(body().isNotNull());
+                validator()
+                    .type("custom")
+                    .withJava(MyValidator.class);
+                
+                from("direct:start").to("mock:result");
+            }
+        };
+    }
+
+    public static class MyValidator extends Validator {
+        @Override
+        public void validate(Message message, DataType type) throws ValidationException {
+            // empty
+        }
+    }
+}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/camel/blob/f9946b2e/components/camel-blueprint/src/main/java/org/apache/camel/blueprint/CamelContextFactoryBean.java
----------------------------------------------------------------------
diff --git a/components/camel-blueprint/src/main/java/org/apache/camel/blueprint/CamelContextFactoryBean.java b/components/camel-blueprint/src/main/java/org/apache/camel/blueprint/CamelContextFactoryBean.java
index 717665a..31b54de 100644
--- a/components/camel-blueprint/src/main/java/org/apache/camel/blueprint/CamelContextFactoryBean.java
+++ b/components/camel-blueprint/src/main/java/org/apache/camel/blueprint/CamelContextFactoryBean.java
@@ -64,6 +64,7 @@ import org.apache.camel.model.dataformat.DataFormatsDefinition;
 import org.apache.camel.model.rest.RestConfigurationDefinition;
 import org.apache.camel.model.rest.RestDefinition;
 import org.apache.camel.model.transformer.TransformersDefinition;
+import org.apache.camel.model.validator.ValidatorsDefinition;
 import org.apache.camel.spi.PackageScanFilter;
 import org.apache.camel.spi.Registry;
 import org.osgi.framework.BundleContext;
@@ -177,6 +178,8 @@ public class CamelContextFactoryBean extends AbstractCamelContextFactoryBean<Blu
     private DataFormatsDefinition dataFormats;
     @XmlElement(name = "transformers")
     private TransformersDefinition transformers;
+    @XmlElement(name = "validators")
+    private ValidatorsDefinition validators;
     @XmlElement(name = "redeliveryPolicyProfile")
     private List<CamelRedeliveryPolicyFactoryBean> redeliveryPolicies;
     @XmlElement(name = "onException")
@@ -696,6 +699,14 @@ public class CamelContextFactoryBean extends AbstractCamelContextFactoryBean<Blu
         return transformers;
     }
 
+    public void setValidators(ValidatorsDefinition validators) {
+        this.validators = validators;
+    }
+
+    public ValidatorsDefinition getValidators() {
+        return validators;
+    }
+
     public List<OnExceptionDefinition> getOnExceptions() {
         return onExceptions;
     }

http://git-wip-us.apache.org/repos/asf/camel/blob/f9946b2e/components/camel-cdi/src/main/java/org/apache/camel/cdi/xml/CamelContextFactoryBean.java
----------------------------------------------------------------------
diff --git a/components/camel-cdi/src/main/java/org/apache/camel/cdi/xml/CamelContextFactoryBean.java b/components/camel-cdi/src/main/java/org/apache/camel/cdi/xml/CamelContextFactoryBean.java
index d5336ed..d91605b 100644
--- a/components/camel-cdi/src/main/java/org/apache/camel/cdi/xml/CamelContextFactoryBean.java
+++ b/components/camel-cdi/src/main/java/org/apache/camel/cdi/xml/CamelContextFactoryBean.java
@@ -64,6 +64,7 @@ import org.apache.camel.model.dataformat.DataFormatsDefinition;
 import org.apache.camel.model.rest.RestConfigurationDefinition;
 import org.apache.camel.model.rest.RestDefinition;
 import org.apache.camel.model.transformer.TransformersDefinition;
+import org.apache.camel.model.validator.ValidatorsDefinition;
 import org.apache.camel.spi.PackageScanFilter;
 
 @XmlRootElement(name = "camelContext")
@@ -208,6 +209,9 @@ public class CamelContextFactoryBean extends AbstractCamelContextFactoryBean<Def
     @XmlElement(name = "transformers")
     private TransformersDefinition transformers;
 
+    @XmlElement(name = "validators")
+    private ValidatorsDefinition validators;
+
     @XmlElement(name = "redeliveryPolicyProfile")
     private List<RedeliveryPolicyFactoryBean> redeliveryPolicies;
 
@@ -702,6 +706,14 @@ public class CamelContextFactoryBean extends AbstractCamelContextFactoryBean<Def
         this.transformers = transformers;
     }
 
+    public ValidatorsDefinition getValidators() {
+        return validators;
+    }
+
+    public void setValidators(ValidatorsDefinition validators) {
+        this.validators = validators;
+    }
+
     public List<OnExceptionDefinition> getOnExceptions() {
         return onExceptions;
     }

http://git-wip-us.apache.org/repos/asf/camel/blob/f9946b2e/components/camel-core-xml/src/main/java/org/apache/camel/core/xml/AbstractCamelContextFactoryBean.java
----------------------------------------------------------------------
diff --git a/components/camel-core-xml/src/main/java/org/apache/camel/core/xml/AbstractCamelContextFactoryBean.java b/components/camel-core-xml/src/main/java/org/apache/camel/core/xml/AbstractCamelContextFactoryBean.java
index 0c2c8b9..1b89a39 100644
--- a/components/camel-core-xml/src/main/java/org/apache/camel/core/xml/AbstractCamelContextFactoryBean.java
+++ b/components/camel-core-xml/src/main/java/org/apache/camel/core/xml/AbstractCamelContextFactoryBean.java
@@ -75,6 +75,7 @@ import org.apache.camel.model.rest.RestConfigurationDefinition;
 import org.apache.camel.model.rest.RestContainer;
 import org.apache.camel.model.rest.RestDefinition;
 import org.apache.camel.model.transformer.TransformersDefinition;
+import org.apache.camel.model.validator.ValidatorsDefinition;
 import org.apache.camel.processor.interceptor.BacklogTracer;
 import org.apache.camel.processor.interceptor.HandleFault;
 import org.apache.camel.processor.interceptor.TraceFormatter;
@@ -776,6 +777,8 @@ public abstract class AbstractCamelContextFactoryBean<T extends ModelCamelContex
 
     public abstract TransformersDefinition getTransformers();
 
+    public abstract ValidatorsDefinition getValidators();
+
     public abstract List<OnExceptionDefinition> getOnExceptions();
 
     public abstract List<OnCompletionDefinition> getOnCompletions();
@@ -858,7 +861,10 @@ public abstract class AbstractCamelContextFactoryBean<T extends ModelCamelContex
             ctx.setDataFormats(getDataFormats().asMap());
         }
         if (getTransformers() != null) {
-            ctx.setTransformers(getTransformers().getTransforms());
+            ctx.setTransformers(getTransformers().getTransformers());
+        }
+        if (getValidators() != null) {
+            ctx.setValidators(getValidators().getValidators());
         }
         if (getTypeConverterStatisticsEnabled() != null) {
             ctx.setTypeConverterStatisticsEnabled(getTypeConverterStatisticsEnabled());

http://git-wip-us.apache.org/repos/asf/camel/blob/f9946b2e/components/camel-spring/src/main/java/org/apache/camel/spring/CamelContextFactoryBean.java
----------------------------------------------------------------------
diff --git a/components/camel-spring/src/main/java/org/apache/camel/spring/CamelContextFactoryBean.java b/components/camel-spring/src/main/java/org/apache/camel/spring/CamelContextFactoryBean.java
index 6c2f2d0..e0a3f07 100644
--- a/components/camel-spring/src/main/java/org/apache/camel/spring/CamelContextFactoryBean.java
+++ b/components/camel-spring/src/main/java/org/apache/camel/spring/CamelContextFactoryBean.java
@@ -63,6 +63,7 @@ import org.apache.camel.model.dataformat.DataFormatsDefinition;
 import org.apache.camel.model.rest.RestConfigurationDefinition;
 import org.apache.camel.model.rest.RestDefinition;
 import org.apache.camel.model.transformer.TransformersDefinition;
+import org.apache.camel.model.validator.ValidatorsDefinition;
 import org.apache.camel.spi.Metadata;
 import org.apache.camel.spi.PackageScanFilter;
 import org.apache.camel.spi.Registry;
@@ -186,6 +187,8 @@ public class CamelContextFactoryBean extends AbstractCamelContextFactoryBean<Spr
     private DataFormatsDefinition dataFormats;
     @XmlElement(name = "transformers")
     private TransformersDefinition transformers;
+    @XmlElement(name = "validators")
+    private ValidatorsDefinition validators;
     @XmlElement(name = "redeliveryPolicyProfile")
     private List<CamelRedeliveryPolicyFactoryBean> redeliveryPolicies;
     @XmlElement(name = "onException")
@@ -908,6 +911,17 @@ public class CamelContextFactoryBean extends AbstractCamelContextFactoryBean<Spr
     }
 
     /**
+     * Configuration of validators.
+     */
+    public void setValidators(ValidatorsDefinition validators) {
+        this.validators = validators;
+    }
+
+    public ValidatorsDefinition getValidators() {
+        return validators;
+    }
+
+    /**
      * Configuration of redelivery settings.
      */
     public void setRedeliveryPolicies(List<CamelRedeliveryPolicyFactoryBean> redeliveryPolicies) {

http://git-wip-us.apache.org/repos/asf/camel/blob/f9946b2e/components/camel-spring/src/main/java/org/apache/camel/spring/handler/CamelNamespaceHandler.java
----------------------------------------------------------------------
diff --git a/components/camel-spring/src/main/java/org/apache/camel/spring/handler/CamelNamespaceHandler.java b/components/camel-spring/src/main/java/org/apache/camel/spring/handler/CamelNamespaceHandler.java
index e0ef322..04737cf 100644
--- a/components/camel-spring/src/main/java/org/apache/camel/spring/handler/CamelNamespaceHandler.java
+++ b/components/camel-spring/src/main/java/org/apache/camel/spring/handler/CamelNamespaceHandler.java
@@ -384,6 +384,7 @@ public class CamelNamespaceHandler extends NamespaceHandlerSupport {
                 builder.addPropertyValue("interceptSendToEndpoints", factoryBean.getInterceptSendToEndpoints());
                 builder.addPropertyValue("dataFormats", factoryBean.getDataFormats());
                 builder.addPropertyValue("transformers", factoryBean.getTransformers());
+                builder.addPropertyValue("validators", factoryBean.getValidators());
                 builder.addPropertyValue("onCompletions", factoryBean.getOnCompletions());
                 builder.addPropertyValue("onExceptions", factoryBean.getOnExceptions());
                 builder.addPropertyValue("builderRefs", factoryBean.getBuilderRefs());

http://git-wip-us.apache.org/repos/asf/camel/blob/f9946b2e/components/camel-spring/src/test/java/org/apache/camel/spring/impl/validator/SpringValidatorRouteTest.java
----------------------------------------------------------------------
diff --git a/components/camel-spring/src/test/java/org/apache/camel/spring/impl/validator/SpringValidatorRouteTest.java b/components/camel-spring/src/test/java/org/apache/camel/spring/impl/validator/SpringValidatorRouteTest.java
new file mode 100644
index 0000000..56cb106
--- /dev/null
+++ b/components/camel-spring/src/test/java/org/apache/camel/spring/impl/validator/SpringValidatorRouteTest.java
@@ -0,0 +1,35 @@
+/**
+ * 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.spring.impl.validator;
+
+import org.apache.camel.CamelContext;
+import org.apache.camel.Exchange;
+import org.apache.camel.Processor;
+import org.apache.camel.impl.validator.ValidatorRouteTest;
+
+import static org.apache.camel.spring.processor.SpringTestHelper.createSpringCamelContext;
+
+/**
+ * A SpringValidatorRouteTest demonstrates contract based declarative validation via Spring DSL.
+ */
+public class SpringValidatorRouteTest extends ValidatorRouteTest {
+
+    protected CamelContext createCamelContext() throws Exception {
+        return createSpringCamelContext(this, "org/apache/camel/spring/impl/validator/SpringValidatorRouteTest.xml");
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/camel/blob/f9946b2e/components/camel-spring/src/test/resources/org/apache/camel/spring/impl/validator/SpringValidatorRouteTest.xml
----------------------------------------------------------------------
diff --git a/components/camel-spring/src/test/resources/org/apache/camel/spring/impl/validator/SpringValidatorRouteTest.xml b/components/camel-spring/src/test/resources/org/apache/camel/spring/impl/validator/SpringValidatorRouteTest.xml
new file mode 100644
index 0000000..4e6c090
--- /dev/null
+++ b/components/camel-spring/src/test/resources/org/apache/camel/spring/impl/validator/SpringValidatorRouteTest.xml
@@ -0,0 +1,68 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+    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.
+-->
+<beans xmlns="http://www.springframework.org/schema/beans"
+       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+       xsi:schemaLocation="
+       http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
+       http://camel.apache.org/schema/spring http://camel.apache.org/schema/spring/camel-spring.xsd
+    ">
+
+    <bean id="myxml" class="org.apache.camel.impl.validator.ValidatorRouteTest.MyXmlComponent"/>
+    
+    <camelContext xmlns="http://camel.apache.org/schema/spring">
+    
+        <validators>
+            <predicateValidator type="json"><simple>${body} contains '{name:XOrder'</simple></predicateValidator>
+            <endpointValidator type="xml:XmlXOrderResponse" uri="myxml:endpoint"/>
+            <customValidator type="other:OtherXOrder" className="org.apache.camel.impl.validator.ValidatorRouteTest$OtherXOrderValidator"/>
+            <customValidator type="other:OtherXOrderResponse" className="org.apache.camel.impl.validator.ValidatorRouteTest$OtherXOrderResponseValidator"/>
+        </validators>
+        
+        <route>
+            <from uri="direct:predicate"/>
+            <inputType urn="json:JsonXOrder" validate="true"/>
+            <outputType urn="json:JsonXOrderResponse"/>
+            <setBody><constant>{name:XOrderResponse}</constant></setBody>
+            <setProperty propertyName="CamelOutputType"><constant>json:JsonXOrderResponse</constant></setProperty>
+        </route>
+
+        <route>
+            <from uri="direct:endpoint"/>
+            <inputType urn="xml:XmlXOrder"/>
+            <outputType urn="xml:XmlXOrderResponse" validate="true"/>
+            <validate>
+                <simple>${exchangeProperty.validator-invoked} == null</simple>
+            </validate>
+            <setBody><constant>&lt;XOrderResponse/&gt;</constant></setBody>
+            <setProperty propertyName="CamelOutputType"><constant>xml:XmlXOrderResponse</constant></setProperty>
+        </route>
+        
+        <route>
+            <from uri="direct:custom"/>
+            <inputType urn="other:OtherXOrder" validate="true"/>
+            <outputType urn="other:OtherXOrderResponse" validate="true"/>
+            <validate>
+                <simple>${exchangeProperty.validator-invoked} == 'org.apache.camel.impl.validator.ValidatorRouteTest$OtherXOrderValidator'</simple>
+            </validate>
+            <setBody><constant>name=XOrderResponse</constant></setBody>
+            <setProperty propertyName="CamelOutputType"><constant>other:OtherXOrderResponse</constant></setProperty>
+        </route>
+        
+    </camelContext>
+  
+</beans>


[4/4] camel git commit: CAMEL-10538 Add declarative validator according to input/output type

Posted by da...@apache.org.
CAMEL-10538 Add declarative validator according to input/output type


Project: http://git-wip-us.apache.org/repos/asf/camel/repo
Commit: http://git-wip-us.apache.org/repos/asf/camel/commit/f9946b2e
Tree: http://git-wip-us.apache.org/repos/asf/camel/tree/f9946b2e
Diff: http://git-wip-us.apache.org/repos/asf/camel/diff/f9946b2e

Branch: refs/heads/master
Commit: f9946b2e811884d58c1e5f164866591f07b7d064
Parents: f507f4e
Author: Tomohisa Igarashi <tm...@gmail.com>
Authored: Wed Feb 15 09:18:37 2017 +0900
Committer: Claus Ibsen <da...@apache.org>
Committed: Wed Feb 22 14:00:32 2017 +0100

----------------------------------------------------------------------
 .../src/main/resources/camel-checkstyle.xml     |   2 +-
 camel-core/src/main/docs/transformer.adoc       |  19 +-
 camel-core/src/main/docs/validator.adoc         | 190 +++++++++++++++
 .../java/org/apache/camel/CamelContext.java     |  33 ++-
 .../main/java/org/apache/camel/Exchange.java    |   2 +
 .../management/mbean/CamelOpenMBeanTypes.java   |  12 +
 .../mbean/ManagedValidatorRegistryMBean.java    |  47 ++++
 .../org/apache/camel/builder/RouteBuilder.java  |  23 ++
 .../camel/builder/TransformerBuilder.java       |   2 +-
 .../apache/camel/builder/ValidatorBuilder.java  | 166 +++++++++++++
 .../apache/camel/impl/DefaultCamelContext.java  |  74 +++---
 .../apache/camel/impl/DefaultRouteContext.java  |   2 +
 .../camel/impl/DefaultTransformerRegistry.java  |  84 +++++--
 .../camel/impl/DefaultValidatorRegistry.java    | 231 +++++++++++++++++++
 .../camel/impl/transformer/TransformerKey.java  |  32 ++-
 .../impl/validator/ProcessorValidator.java      |  99 ++++++++
 .../camel/impl/validator/ValidatorKey.java      |  48 ++++
 .../DefaultManagementLifecycleStrategy.java     |   4 +
 .../mbean/ManagedTransformerRegistry.java       |   6 +-
 .../mbean/ManagedValidatorRegistry.java         | 102 ++++++++
 .../java/org/apache/camel/model/Constants.java  |   3 +-
 .../apache/camel/model/InputTypeDefinition.java |  20 +-
 .../camel/model/OutputTypeDefinition.java       |  20 +-
 .../org/apache/camel/model/RouteDefinition.java |  52 ++++-
 .../CustomTransformerDefinition.java            |  24 +-
 .../transformer/TransformersDefinition.java     |  10 +-
 .../validator/CustomValidatorDefinition.java    |  98 ++++++++
 .../validator/EndpointValidatorDefinition.java  |  97 ++++++++
 .../validator/PredicateValidatorDefinition.java |  76 ++++++
 .../model/validator/ValidatorDefinition.java    |  80 +++++++
 .../model/validator/ValidatorsDefinition.java   |  54 +++++
 .../camel/model/validator/package-info.java     |  24 ++
 .../apache/camel/processor/ContractAdvice.java  |  95 ++++----
 .../java/org/apache/camel/spi/Contract.java     |  34 +++
 .../apache/camel/spi/TransformerRegistry.java   |  12 +-
 .../java/org/apache/camel/spi/Validator.java    |  96 ++++++++
 .../org/apache/camel/spi/ValidatorRegistry.java |  93 ++++++++
 .../apache/camel/util/CamelContextHelper.java   |  62 +++++
 .../org/apache/camel/model/validator/jaxb.index |  21 ++
 .../camel/builder/TransformerBuilderTest.java   |   7 +-
 .../impl/MultipleLifecycleStrategyTest.java     |   2 +-
 .../impl/validator/ValidatorContractTest.java   | 115 +++++++++
 .../impl/validator/ValidatorRouteTest.java      | 187 +++++++++++++++
 .../ManagedNonManagedServiceTest.java           |   4 +-
 ...roducerRouteAddRemoveRegisterAlwaysTest.java |   2 +-
 .../management/ManagedRouteAddRemoveTest.java   |   2 +-
 .../ManagedTransformerRegistryTest.java         |   8 -
 .../ManagedValidatorRegistryTest.java           | 134 +++++++++++
 .../blueprint/CamelContextFactoryBean.java      |  11 +
 .../camel/cdi/xml/CamelContextFactoryBean.java  |  12 +
 .../xml/AbstractCamelContextFactoryBean.java    |   8 +-
 .../camel/spring/CamelContextFactoryBean.java   |  14 ++
 .../spring/handler/CamelNamespaceHandler.java   |   1 +
 .../validator/SpringValidatorRouteTest.java     |  35 +++
 .../impl/validator/SpringValidatorRouteTest.xml |  68 ++++++
 examples/README.adoc                            |   4 +-
 .../camel-example-transformer-demo/README.md    |   8 +-
 examples/camel-example-transformer-demo/pom.xml |   4 +-
 .../demo/OrderResponseValidator.java            |  26 +++
 .../resources/META-INF/spring/camel-context.xml |  18 +-
 .../src/main/resources/xsd/schema.xsd           |  22 ++
 .../camel-example-validator-spring-boot/pom.xml | 120 ++++++++++
 .../readme.adoc                                 |  28 +++
 .../java/sample/camel/GreetingValidator.java    |  31 +++
 .../src/main/java/sample/camel/SampleBean.java  |  38 +++
 .../sample/camel/SampleCamelApplication.java    |  37 +++
 .../java/sample/camel/SampleCamelRouter.java    |  42 ++++
 .../src/main/resources/application.properties   |  28 +++
 .../camel/SampleCamelApplicationTest.java       |  47 ++++
 examples/pom.xml                                |   1 +
 .../commands/AbstractLocalCamelController.java  |  22 ++
 .../apache/camel/commands/CamelController.java  |   9 +
 .../camel/commands/ValidatorListCommand.java    | 185 +++++++++++++++
 .../AbstractLocalCamelControllerTest.java       |  23 +-
 .../commands/TransformerListCommandTest.java    |   5 +-
 .../commands/ValidatorListCommandTest.java      | 121 ++++++++++
 .../jolokia/DefaultJolokiaCamelController.java  |  44 ++++
 77 files changed, 3434 insertions(+), 188 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/camel/blob/f9946b2e/buildingtools/src/main/resources/camel-checkstyle.xml
----------------------------------------------------------------------
diff --git a/buildingtools/src/main/resources/camel-checkstyle.xml b/buildingtools/src/main/resources/camel-checkstyle.xml
index 02fd21c..bde7063 100644
--- a/buildingtools/src/main/resources/camel-checkstyle.xml
+++ b/buildingtools/src/main/resources/camel-checkstyle.xml
@@ -53,7 +53,7 @@ lengths, if/try depths, etc...
     </module>
     
     <module name="FileLength">
-        <property name="max" value="4500"/>
+        <property name="max" value="5000"/>
     </module>
     
     <module name="FileTabCharacter">

http://git-wip-us.apache.org/repos/asf/camel/blob/f9946b2e/camel-core/src/main/docs/transformer.adoc
----------------------------------------------------------------------
diff --git a/camel-core/src/main/docs/transformer.adoc b/camel-core/src/main/docs/transformer.adoc
index abe57b3..598f9c2 100644
--- a/camel-core/src/main/docs/transformer.adoc
+++ b/camel-core/src/main/docs/transformer.adoc
@@ -5,16 +5,15 @@ Transformer
 *Available as of Camel 2.19*
 
 Transformer performs declarative transformation of the message according
-to the declared link:eips/inputType-eip.html[Input Type] and/or
-link:eips/outputType-eip.html[Output Type] on a route definition which declares the expected
-message type.
+to the declared `Input Type` and/or `Output Type` on a route definition which declares
+the expected message type.
 There are two Exchange property indicates current message type, `Exchange.INPUT_TYPE`
 holds input message type and `Exchange.OUTPUT_TYPE` holds output message type. If the
-input type and/or output type declared by link:eips/inputType-eip.html[Input Type] and/or
-link:eips/outputType-eip.html[Output Type] in the route definition, and it is different from
-those properties at runtime, camel internal processor look for a Transformer which transforms
-from the current message type to the expected message type and apply. Once transform succeed or message
-is already in expected type, then `Exchange.INPUT_TYPE` or `Exchange.OUTPUT_TYPE` is updated.
+input type and/or output type declared by `Input Type` and/or `Output Type` in the route
+definition, and it is different from those properties at runtime, camel internal processor
+looks for a Transformer which transforms from the current message type to the expected message
+type and apply. Once transform succeed or message is already in expected type, then
+`Exchange.INPUT_TYPE` or `Exchange.OUTPUT_TYPE` is updated.
 
 
 
@@ -133,7 +132,7 @@ Note that Transformer must be a subclass of `org.apache.camel.spi.Transformer`
 
 | ref | Reference to the custom Transformer bean ID
 
-| type | Fully qualified class name of the custom Transformer class
+| className | Fully qualified class name of the custom Transformer class
 |=======================================================================
 Here is an example to specify custom Transformer class:
 Java DSL:
@@ -148,7 +147,7 @@ transformer()
 XML DSL:
 [source,xml]
 -------------------------------------------------------------------
-<customTransformer type="com.example.MyCustomTransformer" fromType="xml" toType="json"/>
+<customTransformer className="com.example.MyCustomTransformer" fromType="xml" toType="json"/>
 -------------------------------------------------------------------
 
 

http://git-wip-us.apache.org/repos/asf/camel/blob/f9946b2e/camel-core/src/main/docs/validator.adoc
----------------------------------------------------------------------
diff --git a/camel-core/src/main/docs/validator.adoc b/camel-core/src/main/docs/validator.adoc
new file mode 100644
index 0000000..afae832
--- /dev/null
+++ b/camel-core/src/main/docs/validator.adoc
@@ -0,0 +1,190 @@
+[[Validator-Validator]]
+Validator
+^^^^^^^^^^
+
+*Available as of Camel 2.19*
+
+Validator performs declarative validation of the message according to the declared
+`Input Type` and/or `Output Type` on a route definition which declares the expected
+message type. Note that the validation is performed only if `validate` attribute on the
+ type declaration is true.
+if `validate` attribute is true on a `Input Type` and/or `Output Type` declaration,
+camel internal processor looks for a corresponding Validator from the registry and apply.
+
+
+
+[[Validator-DataTypeFormat]]
+Data type format
+^^^^^^^^^^^^^^^
+[source,java]
+---------------------------------------------
+scheme:name
+---------------------------------------------
+where *scheme* is the type of data model like `java`, `xml` or `json`, and *name* is the individual
+data type name.
+
+
+
+[[Validator-SupportedValidators]]
+Supported Validators
+^^^^^^^^^^^^^^^^^^^^^
+
+|=======================================================================
+| Validator | Description
+
+| Predicate Validator | Validate with using link:expression.html[Expression] or link:predicate.html[Predicate]
+
+| Endpoint Transformer | Validate by forwarding to the link:endpoint.html[Endpoint] to be used with validation component such as link:validator-component.adoc[Validation Component] or link:bean-validation.html[Bean Validation Component].
+
+| Custom Transformer | Validate with using custom validator class. Validator must be a subclass of `org.apache.camel.spi.Validator`
+|=======================================================================
+
+
+
+[[Validator-CommonOptions]]
+Common Options
+^^^^^^^^^^^^^
+All validators have following common options to specify which data type is supported by the validator.
+`type` must be specified.
+|=======================================================================
+| Name | Description
+
+| type | <<Validator-DataTypeFormat,Data type>> to validate.
+|=======================================================================
+
+
+
+[[Validator-Predicate]]
+Predicate Validator Options
+^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+|=======================================================================
+| Name | Description
+
+| expression | link:expression.html[Expression] or link:predicate.html[Predicate] to be used for validation
+|=======================================================================
+Here is an example to specify a validation predicate:
+
+Java DSL:
+[source,java]
+-------------------------------------------------------------------
+validator()
+    .type("csv:CSVOrder")
+    .withExpression(bodyAs(String.class).contains("{name:XOrder}"));
+-------------------------------------------------------------------
+
+XML DSL:
+[source,xml]
+-------------------------------------------------------------------
+<predicateValidator Type="csv:CSVOrder">
+    <simple>${body} contains '{name:XOrder'</simple>
+</dataFormatTransformer>
+-------------------------------------------------------------------
+
+
+
+[[Validator-Endpoint]]
+Endpoint Validator Options
+^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+|=======================================================================
+| Name | Description
+
+| ref | Reference to the link:endpoint.html[Endpoint] ID
+
+| uri | link:endpoint.html[Endpoint] URI
+|=======================================================================
+Here is an example to specify endpoint URI in Java DSL:
+[source,java]
+-------------------------------------------------------------------
+validator()
+    .type("xml")
+    .withUri("validator:xsd/schema.xsd");
+-------------------------------------------------------------------
+
+And here is an example to specify endpoint ref in XML DSL:
+[source,xml]
+-------------------------------------------------------------------
+<endpointValidator uri="validator:xsd/schema.xsd" type="xml"/>
+-------------------------------------------------------------------
+
+
+
+[[Validator-Custom]]
+Custom Validator Options
+^^^^^^^^^^^^^^^^^^^^^^^^^
+
+Note that Validator must be a subclass of `org.apache.camel.spi.Validator`
+|=======================================================================
+| Name | Description
+
+| ref | Reference to the custom Validator bean ID
+
+| className | Fully qualified class name of the custom Validator class
+|=======================================================================
+Here is an example to specify custom Validator class:
+Java DSL:
+[source,java]
+-------------------------------------------------------------------
+validator()
+    .type("json")
+    .withJava(com.example.MyCustomValidator.class);
+-------------------------------------------------------------------
+
+XML DSL:
+[source,xml]
+-------------------------------------------------------------------
+<customTransformer className="com.example.MyCustomValidator" type="json"/>
+-------------------------------------------------------------------
+
+
+
+[[Validator-Examples]]
+Examples
+^^^^^^^
+
+For example to declare the Endpoint Validator which uses
+validator component to validate `xml:ABCOrder`, we can do as follows:
+
+Java DSL:
+[source,java]
+-------------------------------------------------------------------
+validator()
+    .type("xml:ABCOrder")
+    .withUri("validator:xsd/schema.xsd");
+-------------------------------------------------------------------
+
+XML DSL:
+[source,xml]
+-------------------------------------------------------------------
+<camelContext id="camel" xmlns="http://camel.apache.org/schema/spring">
+    <validators>
+        <endpointValidator uri="validator:xsd/schema.xsd" type="xml:ABCOrder"/>
+    </validators>
+    ....
+</camelContext>
+-------------------------------------------------------------------
+
+If you have following route definition, above validator will be applied when `direct:abc` endpoint
+receives the message. Note that the `validate` attribute on the inputType declaration is set to `true`:
+
+Java DSL:
+[source,java]
+-------------------------------------------------------------------
+from("direct:abc")
+    .inputType("xml:ABCOrder", true)
+    .log("${body}");
+-------------------------------------------------------------------
+
+XML DSL:
+[source,xml]
+-------------------------------------------------------------------
+<camelContext id="camel" xmlns="http://camel.apache.org/schema/spring">
+    ....
+    <route>
+        <from uri="direct:abc"/>
+        <inputType urn="xml:ABCOrder" validate="true"/>
+        <log message="${body}"/>
+    </route>
+</camelContext>
+-------------------------------------------------------------------

http://git-wip-us.apache.org/repos/asf/camel/blob/f9946b2e/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 84269a3..ac0c774 100644
--- a/camel-core/src/main/java/org/apache/camel/CamelContext.java
+++ b/camel-core/src/main/java/org/apache/camel/CamelContext.java
@@ -37,6 +37,7 @@ import org.apache.camel.model.cloud.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.model.validator.ValidatorDefinition;
 import org.apache.camel.spi.AsyncProcessorAwaitManager;
 import org.apache.camel.spi.CamelContextNameStrategy;
 import org.apache.camel.spi.ClassResolver;
@@ -77,6 +78,8 @@ import org.apache.camel.spi.TransformerRegistry;
 import org.apache.camel.spi.TypeConverterRegistry;
 import org.apache.camel.spi.UnitOfWorkFactory;
 import org.apache.camel.spi.UuidGenerator;
+import org.apache.camel.spi.Validator;
+import org.apache.camel.spi.ValidatorRegistry;
 import org.apache.camel.util.LoadPropertiesException;
 
 /**
@@ -1262,7 +1265,7 @@ public interface CamelContext extends SuspendableService, RuntimeConfiguration {
      *
      * @param from from data type
      * @param to to data type
-     * @return the resolved data format, or <tt>null</tt> if not found
+     * @return the resolved transformer, or <tt>null</tt> if not found
      */
     Transformer resolveTransformer(DataType from, DataType to);
 
@@ -1273,6 +1276,34 @@ public interface CamelContext extends SuspendableService, RuntimeConfiguration {
     TransformerRegistry getTransformerRegistry();
 
     /**
+     * Sets the validators that can be referenced in the routes.
+     *
+     * @param validators the validators
+     */
+    void setValidators(List<ValidatorDefinition> validators);
+
+    /**
+     * Gets the validators that can be referenced in the routes.
+     *
+     * @return the validators available
+     */
+    List<ValidatorDefinition> getValidators();
+
+    /**
+     * Resolve a validator given from/to data type.
+     *
+     * @param from the data type
+     * @return the resolved validator, or <tt>null</tt> if not found
+     */
+    Validator resolveValidator(DataType type);
+
+    /**
+     * Gets the {@link org.apache.camel.spi.ValidatorRegistry}
+     * @return the ValidatorRegistry
+     */
+    ValidatorRegistry getValidatorRegistry();
+
+    /**
      * @deprecated use {@link #setGlobalOptions(Map) setGlobalOptions(Map<String,String>) instead}.
      */
     @Deprecated

http://git-wip-us.apache.org/repos/asf/camel/blob/f9946b2e/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 b6f6c37..cc2acaa 100644
--- a/camel-core/src/main/java/org/apache/camel/Exchange.java
+++ b/camel-core/src/main/java/org/apache/camel/Exchange.java
@@ -166,6 +166,8 @@ public interface Exchange {
 
     String MAXIMUM_CACHE_POOL_SIZE     = "CamelMaximumCachePoolSize";
     String MAXIMUM_ENDPOINT_CACHE_SIZE = "CamelMaximumEndpointCacheSize";
+    String MAXIMUM_TRANSFORMER_CACHE_SIZE = "CamelMaximumTransformerCacheSize";
+    String MAXIMUM_VALIDATOR_CACHE_SIZE = "CamelMaximumValidatorCacheSize";
     String MESSAGE_HISTORY             = "CamelMessageHistory";
     String MULTICAST_INDEX             = "CamelMulticastIndex";
     String MULTICAST_COMPLETE          = "CamelMulticastComplete";

http://git-wip-us.apache.org/repos/asf/camel/blob/f9946b2e/camel-core/src/main/java/org/apache/camel/api/management/mbean/CamelOpenMBeanTypes.java
----------------------------------------------------------------------
diff --git a/camel-core/src/main/java/org/apache/camel/api/management/mbean/CamelOpenMBeanTypes.java b/camel-core/src/main/java/org/apache/camel/api/management/mbean/CamelOpenMBeanTypes.java
index b03cda1..2672447 100644
--- a/camel-core/src/main/java/org/apache/camel/api/management/mbean/CamelOpenMBeanTypes.java
+++ b/camel-core/src/main/java/org/apache/camel/api/management/mbean/CamelOpenMBeanTypes.java
@@ -228,4 +228,16 @@ public final class CamelOpenMBeanTypes {
                                  new OpenType[]{SimpleType.STRING, SimpleType.STRING, SimpleType.STRING,
                                                 SimpleType.BOOLEAN, SimpleType.BOOLEAN, SimpleType.STRING});
     }
+
+    public static TabularType listValidatorsTabularType() throws OpenDataException {
+        CompositeType ct = listValidatorsCompositeType();
+        return new TabularType("listValidators", "Lists all the validators in the registry", ct, new String[]{"type"});
+    }
+
+    public static CompositeType listValidatorsCompositeType() throws OpenDataException {
+        return new CompositeType("validators", "Validators",
+                                 new String[]{"type", "static", "dynamic", "description"},
+                                 new String[]{"Type", "Static", "Dynamic", "Description"},
+                                 new OpenType[]{SimpleType.STRING, SimpleType.BOOLEAN, SimpleType.BOOLEAN, SimpleType.STRING});
+    }
 }

http://git-wip-us.apache.org/repos/asf/camel/blob/f9946b2e/camel-core/src/main/java/org/apache/camel/api/management/mbean/ManagedValidatorRegistryMBean.java
----------------------------------------------------------------------
diff --git a/camel-core/src/main/java/org/apache/camel/api/management/mbean/ManagedValidatorRegistryMBean.java b/camel-core/src/main/java/org/apache/camel/api/management/mbean/ManagedValidatorRegistryMBean.java
new file mode 100644
index 0000000..e011f53
--- /dev/null
+++ b/camel-core/src/main/java/org/apache/camel/api/management/mbean/ManagedValidatorRegistryMBean.java
@@ -0,0 +1,47 @@
+/**
+ * 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.api.management.mbean;
+
+import javax.management.openmbean.TabularData;
+
+import org.apache.camel.api.management.ManagedAttribute;
+import org.apache.camel.api.management.ManagedOperation;
+
+public interface ManagedValidatorRegistryMBean extends ManagedServiceMBean {
+
+    @ManagedAttribute(description = "Source")
+    String getSource();
+
+    @ManagedAttribute(description = "Number of dynamic validators cached")
+    Integer getDynamicSize();
+
+    @ManagedAttribute(description = "Number of static validators cached")
+    Integer getStaticSize();
+
+    @ManagedAttribute(description = "Number of total validators cached")
+    Integer getSize();
+
+    @ManagedAttribute(description = "Maximum cache size (capacity)")
+    Integer getMaximumCacheSize();
+
+    @ManagedOperation(description = "Purges the cache")
+    void purge();
+
+    @ManagedOperation(description = "Lists all the validators in the registry")
+    TabularData listValidators();
+
+}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/camel/blob/f9946b2e/camel-core/src/main/java/org/apache/camel/builder/RouteBuilder.java
----------------------------------------------------------------------
diff --git a/camel-core/src/main/java/org/apache/camel/builder/RouteBuilder.java b/camel-core/src/main/java/org/apache/camel/builder/RouteBuilder.java
index fde9494..26c2097 100644
--- a/camel-core/src/main/java/org/apache/camel/builder/RouteBuilder.java
+++ b/camel-core/src/main/java/org/apache/camel/builder/RouteBuilder.java
@@ -54,6 +54,7 @@ public abstract class RouteBuilder extends BuilderSupport implements RoutesBuild
     private RestsDefinition restCollection = new RestsDefinition();
     private Map<String, RestConfigurationDefinition> restConfigurations;
     private List<TransformerBuilder> transformerBuilders = new ArrayList<>();
+    private List<ValidatorBuilder> validatorBuilders = new ArrayList<>();
     private RoutesDefinition routeCollection = new RoutesDefinition();
 
     public RouteBuilder() {
@@ -144,6 +145,17 @@ public abstract class RouteBuilder extends BuilderSupport implements RoutesBuild
     }
 
     /**
+     * Create a new {@code ValidatorBuilder}.
+     * 
+     * @return the builder
+     */
+    public ValidatorBuilder validator() {
+        ValidatorBuilder vb = new ValidatorBuilder();
+        validatorBuilders.add(vb);
+        return vb;
+    }
+
+    /**
      * Creates a new route from the given URI input
      *
      * @param uri  the from uri
@@ -341,6 +353,7 @@ public abstract class RouteBuilder extends BuilderSupport implements RoutesBuild
         // but populate rests before routes, as we want to turn rests into routes
         populateRests();
         populateTransformers();
+        populateValidators();
         populateRoutes();
     }
 
@@ -494,6 +507,16 @@ public abstract class RouteBuilder extends BuilderSupport implements RoutesBuild
         }
     }
 
+    protected void populateValidators() {
+        ModelCamelContext camelContext = getContext();
+        if (camelContext == null) {
+            throw new IllegalArgumentException("CamelContext has not been injected!");
+        }
+        for (ValidatorBuilder vb : validatorBuilders) {
+            vb.configure(camelContext);
+        }
+    }
+
     public RestsDefinition getRestCollection() {
         return restCollection;
     }

http://git-wip-us.apache.org/repos/asf/camel/blob/f9946b2e/camel-core/src/main/java/org/apache/camel/builder/TransformerBuilder.java
----------------------------------------------------------------------
diff --git a/camel-core/src/main/java/org/apache/camel/builder/TransformerBuilder.java b/camel-core/src/main/java/org/apache/camel/builder/TransformerBuilder.java
index 9f5f2ec..a8bab64 100644
--- a/camel-core/src/main/java/org/apache/camel/builder/TransformerBuilder.java
+++ b/camel-core/src/main/java/org/apache/camel/builder/TransformerBuilder.java
@@ -173,7 +173,7 @@ public class TransformerBuilder {
             transformer = dtd;
         } else if (clazz != null) {
             CustomTransformerDefinition ctd = new CustomTransformerDefinition();
-            ctd.setType(clazz.getName());
+            ctd.setClassName(clazz.getName());
             transformer = ctd;
         } else if (beanRef != null) {
             CustomTransformerDefinition ctd = new CustomTransformerDefinition();

http://git-wip-us.apache.org/repos/asf/camel/blob/f9946b2e/camel-core/src/main/java/org/apache/camel/builder/ValidatorBuilder.java
----------------------------------------------------------------------
diff --git a/camel-core/src/main/java/org/apache/camel/builder/ValidatorBuilder.java b/camel-core/src/main/java/org/apache/camel/builder/ValidatorBuilder.java
new file mode 100644
index 0000000..c021939
--- /dev/null
+++ b/camel-core/src/main/java/org/apache/camel/builder/ValidatorBuilder.java
@@ -0,0 +1,166 @@
+/**
+ * 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.builder;
+
+import org.apache.camel.CamelContext;
+import org.apache.camel.Expression;
+import org.apache.camel.Predicate;
+import org.apache.camel.model.language.ExpressionDefinition;
+import org.apache.camel.model.validator.CustomValidatorDefinition;
+import org.apache.camel.model.validator.EndpointValidatorDefinition;
+import org.apache.camel.model.validator.PredicateValidatorDefinition;
+import org.apache.camel.model.validator.ValidatorDefinition;
+import org.apache.camel.spi.AsPredicate;
+import org.apache.camel.spi.DataType;
+import org.apache.camel.spi.Validator;
+
+/**
+ * A <a href="http://camel.apache.org/dsl.html">Java DSL</a> which is
+ * used to build a {@link org.apache.camel.spi.Validator} and register into {@link org.apache.camel.CamelContext}.
+ * It requires a 'type' to be specified by type() method.
+ * And then you can choose a type of validator by withUri(), withPredicate(), withJava() or withBean() method.
+ */
+public class ValidatorBuilder {
+
+    private String type;
+    private String uri;
+    private ExpressionDefinition expression;
+    private Class<? extends Validator> clazz;
+    private String beanRef;
+
+    /**
+     * Set the data type name.
+     * If you specify 'xml:XYZ', the validator will be picked up if source type is
+     * 'xml:XYZ'. If you specify just 'xml', the validator matches with all of
+     * 'xml' source type like 'xml:ABC' or 'xml:DEF'.
+     *
+     * @param type 'from' data type name
+     */
+    public ValidatorBuilder type(String type) {
+        this.type = type;
+        return this;
+    }
+
+    /**
+     * Set the data type using Java class.
+     *
+     * @param clazz Java class represents data type
+     */
+    public ValidatorBuilder type(Class<?> type) {
+        this.type = new DataType(type).toString();
+        return this;
+    }
+
+    /**
+     * Set the URI to be used for the endpoint {@link Validator}.
+     * @see {@link EndpointValidatorDefinition}, {@link ProcessorValidator}
+     * 
+     * @param uri endpoint URI
+     */
+    public ValidatorBuilder withUri(String uri) {
+        resetType();
+        this.uri = uri;
+        return this;
+    }
+
+    /**
+     * Set the {@link Expression} to be used for the predicate {@link Validator}.
+     * @see {@link PredicateValidatorDefinition}, {@link ProcessorValidator}
+     * 
+     * @param expression validation expression
+     */
+    public ValidatorBuilder withExpression(@AsPredicate Expression expression) {
+        resetType();
+        this.expression = new ExpressionDefinition(expression);
+        return this;
+    }
+
+    /**
+     * Set the {@link Predicate} to be used for the predicate {@link Validator}.
+     * @see {@link PredicateValidatorDefinition}, {@link ProcessorValidator}
+     * 
+     * @param predicate validation predicate
+     */
+    public ValidatorBuilder withExpression(@AsPredicate Predicate predicate) {
+        resetType();
+        this.expression = new ExpressionDefinition(predicate);
+        return this;
+    }
+
+    /**
+     * Set the Java {@code Class} represents a custom {@code Validator} implementation class.
+     * @see {@code CustomValidatorDefinition}
+     * 
+     * @param clazz {@code Class} object represents custom validator implementation
+     */
+    public ValidatorBuilder withJava(Class<? extends Validator> clazz) {
+        resetType();
+        this.clazz = clazz;
+        return this;
+    }
+
+    /**
+     * Set the Java Bean name to be used for custom {@code Validator}.
+     * @see {@code CustomValidatorDefinition}
+     * 
+     * @param ref bean name for the custom {@code Validator}
+     */
+    public ValidatorBuilder withBean(String ref) {
+        resetType();
+        this.beanRef = ref;
+        return this;
+    }
+
+    private void resetType() {
+        this.uri = null;
+        this.expression = null;
+        this.clazz = null;
+        this.beanRef = null;
+    }
+
+    /**
+     * Configure a Validator according to the configurations built on this builder
+     * and register it into given {@code CamelContext}.
+     * 
+     * @param camelContext {@code CamelContext}
+     */
+    public void configure(CamelContext camelContext) {
+        ValidatorDefinition validator;
+        if (uri != null) {
+            EndpointValidatorDefinition etd = new EndpointValidatorDefinition();
+            etd.setUri(uri);
+            validator = etd;
+        } else if (expression != null) {
+            PredicateValidatorDefinition dtd = new PredicateValidatorDefinition();
+            dtd.setExpression(expression);
+            validator = dtd;
+        } else if (clazz != null) {
+            CustomValidatorDefinition ctd = new CustomValidatorDefinition();
+            ctd.setClassName(clazz.getName());
+            validator = ctd;
+        } else if (beanRef != null) {
+            CustomValidatorDefinition ctd = new CustomValidatorDefinition();
+            ctd.setRef(beanRef);
+            validator = ctd;
+        } else {
+            throw new IllegalArgumentException("No Validator type was specified");
+        }
+        
+        validator.setType(type);
+        camelContext.getValidators().add(validator);
+    }
+}

http://git-wip-us.apache.org/repos/asf/camel/blob/f9946b2e/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 6a2db9e..4f4648f 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
@@ -91,6 +91,7 @@ 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.impl.validator.ValidatorKey;
 import org.apache.camel.management.DefaultManagementMBeanAssembler;
 import org.apache.camel.management.DefaultManagementStrategy;
 import org.apache.camel.management.JmxSystemPropertyKeys;
@@ -108,6 +109,7 @@ import org.apache.camel.model.cloud.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.model.validator.ValidatorDefinition;
 import org.apache.camel.processor.interceptor.BacklogDebugger;
 import org.apache.camel.processor.interceptor.BacklogTracer;
 import org.apache.camel.processor.interceptor.Debug;
@@ -160,6 +162,8 @@ import org.apache.camel.spi.TransformerRegistry;
 import org.apache.camel.spi.TypeConverterRegistry;
 import org.apache.camel.spi.UnitOfWorkFactory;
 import org.apache.camel.spi.UuidGenerator;
+import org.apache.camel.spi.Validator;
+import org.apache.camel.spi.ValidatorRegistry;
 import org.apache.camel.support.ServiceSupport;
 import org.apache.camel.util.CamelContextHelper;
 import org.apache.camel.util.CollectionStringBuffer;
@@ -283,8 +287,10 @@ 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 List<TransformerDefinition> transformers = new ArrayList<>();
     private TransformerRegistry<TransformerKey> transformerRegistry;
+    private List<ValidatorDefinition> validators = new ArrayList<>();
+    private ValidatorRegistry<ValidatorKey> validatorRegistry;
     private ReloadStrategy reloadStrategy;
 
     /**
@@ -298,7 +304,6 @@ public class DefaultCamelContext extends ServiceSupport implements ModelCamelCon
 
         // create endpoint registry at first since end users may access endpoints before CamelContext is started
         this.endpoints = new DefaultEndpointRegistry(this);
-        this.transformerRegistry = new DefaultTransformerRegistry(this);
 
         // add the defer service startup listener
         this.startupListeners.add(deferStartupListener);
@@ -3134,7 +3139,12 @@ public class DefaultCamelContext extends ServiceSupport implements ModelCamelCon
             log.info("Using ReloadStrategy: {}", reloadStrategy);
             addService(reloadStrategy, true, true);
         }
+
+        // Initialize declarative transformer/validator registry
+        transformerRegistry = new DefaultTransformerRegistry(this, transformers);
         addService(transformerRegistry, true, true);
+        validatorRegistry = new DefaultValidatorRegistry(this, validators);
+        addService(validatorRegistry, true, true);
 
         if (runtimeEndpointRegistry != null) {
             if (runtimeEndpointRegistry instanceof EventNotifier) {
@@ -4315,18 +4325,12 @@ public class DefaultCamelContext extends ServiceSupport implements ModelCamelCon
 
     @Override
     public Transformer resolveTransformer(String scheme) {
-        if (scheme == null) {
-            return null;
-        }
-        return resolveTransformer(getTransformerKey(scheme));
+        return transformerRegistry.resolveTransformer(new TransformerKey(scheme));
     }
 
     @Override
     public Transformer resolveTransformer(DataType from, DataType to) {
-        if (from == null || to == null) {
-            return null;
-        }
-        return resolveTransformer(getTransformerKey(from, to));
+        return transformerRegistry.resolveTransformer(new TransformerKey(from, to));
     }
 
     @Override
@@ -4334,6 +4338,26 @@ public class DefaultCamelContext extends ServiceSupport implements ModelCamelCon
         return transformerRegistry;
     }
 
+    @Override
+    public void setValidators(List<ValidatorDefinition> validators) {
+        this.validators = validators;
+    }
+
+    @Override
+    public List<ValidatorDefinition> getValidators() {
+        return validators;
+    }
+
+    @Override
+    public Validator resolveValidator(DataType type) {
+        return validatorRegistry.resolveValidator(new ValidatorKey(type));
+    }
+
+    @Override
+    public ValidatorRegistry getValidatorRegistry() {
+        return validatorRegistry;
+    }
+
     protected Map<String, RouteService> getRouteServices() {
         return routeServices;
     }
@@ -4365,36 +4389,6 @@ public class DefaultCamelContext extends ServiceSupport implements ModelCamelCon
         return new DefaultModelJAXBContextFactory();
     }
 
-    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);
-    }
-
     @Override
     public String toString() {
         return "CamelContext(" + getName() + ")";

http://git-wip-us.apache.org/repos/asf/camel/blob/f9946b2e/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 fbb3673..594742e 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
@@ -208,9 +208,11 @@ public class DefaultRouteContext implements RouteContext {
                 Contract contract = new Contract();
                 if (route.getInputType() != null) {
                     contract.setInputType(route.getInputType().getUrn());
+                    contract.setValidateInput(route.getInputType().isValidate());
                 }
                 if (route.getOutputType() != null) {
                     contract.setOutputType(route.getOutputType().getUrn());
+                    contract.setValidateOutput(route.getOutputType().isValidate());
                 }
                 internal.addAdvice(new ContractAdvice(contract));
             }

http://git-wip-us.apache.org/repos/asf/camel/blob/f9946b2e/camel-core/src/main/java/org/apache/camel/impl/DefaultTransformerRegistry.java
----------------------------------------------------------------------
diff --git a/camel-core/src/main/java/org/apache/camel/impl/DefaultTransformerRegistry.java b/camel-core/src/main/java/org/apache/camel/impl/DefaultTransformerRegistry.java
index 6969233..afa9968 100644
--- a/camel-core/src/main/java/org/apache/camel/impl/DefaultTransformerRegistry.java
+++ b/camel-core/src/main/java/org/apache/camel/impl/DefaultTransformerRegistry.java
@@ -19,6 +19,7 @@ package org.apache.camel.impl;
 import java.util.ArrayList;
 import java.util.Collection;
 import java.util.LinkedHashSet;
+import java.util.List;
 import java.util.Map;
 import java.util.Set;
 import java.util.concurrent.ConcurrentHashMap;
@@ -27,33 +28,84 @@ import java.util.concurrent.ConcurrentMap;
 import org.apache.camel.CamelContext;
 import org.apache.camel.Endpoint;
 import org.apache.camel.impl.transformer.TransformerKey;
+import org.apache.camel.model.transformer.TransformerDefinition;
 import org.apache.camel.spi.DataType;
 import org.apache.camel.spi.EndpointRegistry;
 import org.apache.camel.spi.Transformer;
 import org.apache.camel.spi.TransformerRegistry;
 import org.apache.camel.util.CamelContextHelper;
 import org.apache.camel.util.LRUCache;
+import org.apache.camel.util.ObjectHelper;
 import org.apache.camel.util.ServiceHelper;
 
 /**
- * Default implementation of {@link org.apache.camel.spi.TransformerRegistry}
+ * Default implementation of {@link org.apache.camel.spi.TransformerRegistry}.
  */
 public class DefaultTransformerRegistry extends LRUCache<TransformerKey, Transformer> implements TransformerRegistry<TransformerKey> {
     private static final long serialVersionUID = 1L;
     private ConcurrentMap<TransformerKey, Transformer> staticMap;
+    private ConcurrentMap<TransformerKey, TransformerKey> aliasMap;
     private final CamelContext context;
 
-    public DefaultTransformerRegistry(CamelContext context) {
-        // do not stop on eviction, as the endpoint may still be in use
-        super(CamelContextHelper.getMaximumEndpointCacheSize(context), CamelContextHelper.getMaximumEndpointCacheSize(context), false);
-        // static map to hold endpoints we do not want to be evicted
-        this.staticMap = new ConcurrentHashMap<TransformerKey, Transformer>();
+    public DefaultTransformerRegistry(CamelContext context) throws Exception {
+        this(context, new ArrayList<>());
+    }
+
+    public DefaultTransformerRegistry(CamelContext context, List<TransformerDefinition> definitions) throws Exception {
+        // do not stop on eviction, as the transformer may still be in use
+        super(CamelContextHelper.getMaximumTransformerCacheSize(context), CamelContextHelper.getMaximumTransformerCacheSize(context), false);
+        // static map to hold transformers we do not want to be evicted
+        this.staticMap = new ConcurrentHashMap<>();
+        this.aliasMap = new ConcurrentHashMap<>();
         this.context = context;
+        
+        for (TransformerDefinition def : definitions) {
+            Transformer transformer = def.createTransformer(context);
+            context.addService(transformer);
+            put(createKey(def), transformer);
+        }
     }
 
-    public DefaultTransformerRegistry(CamelContext context, Map<TransformerKey, Transformer> transformers) {
-        this(context);
-        putAll(transformers);
+    @Override
+    public Transformer resolveTransformer(TransformerKey key) {
+        if (ObjectHelper.isEmpty(key.getScheme()) && key.getTo() == null) {
+            return null;
+        }
+        
+        // try exact match
+        Transformer answer = get(aliasMap.containsKey(key) ? aliasMap.get(key) : key);
+        if (answer != null || ObjectHelper.isNotEmpty(key.getScheme())) {
+            return answer;
+        }
+        
+        // try wildcard match for next - add an alias if matched
+        TransformerKey alias = null;
+        if (key.getFrom() != null && ObjectHelper.isNotEmpty(key.getFrom().getName())) {
+            alias = new TransformerKey(new DataType(key.getFrom().getModel()), key.getTo());
+            answer = get(alias);
+        }
+        if (answer == null && ObjectHelper.isNotEmpty(key.getTo().getName())) {
+            alias = new TransformerKey(key.getFrom(), new DataType(key.getTo().getModel()));
+            answer = get(alias);
+        }
+        if (answer == null && key.getFrom() != null && ObjectHelper.isNotEmpty(key.getFrom().getName())
+            && ObjectHelper.isNotEmpty(key.getTo().getName())) {
+            alias = new TransformerKey(new DataType(key.getFrom().getModel()), new DataType(key.getTo().getModel()));
+            answer = get(alias);
+        }
+        if (answer == null && key.getFrom() != null) {
+            alias = new TransformerKey(key.getFrom().getModel());
+            answer = get(alias);
+        }
+        if (answer == null) {
+            alias = new TransformerKey(key.getTo().getModel());
+            answer = get(alias);
+        }
+        if (answer != null) {
+            aliasMap.put(key, alias);
+        }
+        
+        return answer;
     }
 
     @Override
@@ -90,7 +142,7 @@ public class DefaultTransformerRegistry extends LRUCache<TransformerKey, Transfo
             return answer;
         }
 
-        // we want endpoints to be static if they are part of setting up or starting routes
+        // we want transformers to be static if they are part of setting up or starting routes
         if (context.isSetupRoutes() || context.isStartingRoutes()) {
             answer = staticMap.put(key, transformer);
         } else {
@@ -154,7 +206,7 @@ public class DefaultTransformerRegistry extends LRUCache<TransformerKey, Transfo
 
     @Override
     public Set<TransformerKey> keySet() {
-        Set<TransformerKey> answer = new LinkedHashSet<TransformerKey>();
+        Set<TransformerKey> answer = new LinkedHashSet<>();
         answer.addAll(staticMap.keySet());
         answer.addAll(super.keySet());
         return answer;
@@ -162,7 +214,7 @@ public class DefaultTransformerRegistry extends LRUCache<TransformerKey, Transfo
 
     @Override
     public Collection<Transformer> values() {
-        Collection<Transformer> answer = new ArrayList<Transformer>();
+        Collection<Transformer> answer = new ArrayList<>();
         answer.addAll(staticMap.values());
         answer.addAll(super.values());
         return answer;
@@ -170,7 +222,7 @@ public class DefaultTransformerRegistry extends LRUCache<TransformerKey, Transfo
 
     @Override
     public Set<Entry<TransformerKey, Transformer>> entrySet() {
-        Set<Entry<TransformerKey, Transformer>> answer = new LinkedHashSet<Entry<TransformerKey, Transformer>>();
+        Set<Entry<TransformerKey, Transformer>> answer = new LinkedHashSet<>();
         answer.addAll(staticMap.entrySet());
         answer.addAll(super.entrySet());
         return answer;
@@ -221,4 +273,10 @@ public class DefaultTransformerRegistry extends LRUCache<TransformerKey, Transfo
     public String toString() {
         return "TransformerRegistry for " + context.getName() + ", capacity: " + getMaxCacheSize();
     }
+
+    private TransformerKey createKey(TransformerDefinition def) {
+        return ObjectHelper.isNotEmpty(def.getScheme()) ? new TransformerKey(def.getScheme())
+            : new TransformerKey(new DataType(def.getFromType()), new DataType(def.getToType()));
+    }
+
 }

http://git-wip-us.apache.org/repos/asf/camel/blob/f9946b2e/camel-core/src/main/java/org/apache/camel/impl/DefaultValidatorRegistry.java
----------------------------------------------------------------------
diff --git a/camel-core/src/main/java/org/apache/camel/impl/DefaultValidatorRegistry.java b/camel-core/src/main/java/org/apache/camel/impl/DefaultValidatorRegistry.java
new file mode 100644
index 0000000..9a4d4ca
--- /dev/null
+++ b/camel-core/src/main/java/org/apache/camel/impl/DefaultValidatorRegistry.java
@@ -0,0 +1,231 @@
+/**
+ * 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;
+
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.LinkedHashSet;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+import java.util.concurrent.ConcurrentHashMap;
+import java.util.concurrent.ConcurrentMap;
+
+import org.apache.camel.CamelContext;
+import org.apache.camel.Endpoint;
+import org.apache.camel.impl.validator.ValidatorKey;
+import org.apache.camel.model.validator.ValidatorDefinition;
+import org.apache.camel.spi.DataType;
+import org.apache.camel.spi.EndpointRegistry;
+import org.apache.camel.spi.Validator;
+import org.apache.camel.spi.ValidatorRegistry;
+import org.apache.camel.util.CamelContextHelper;
+import org.apache.camel.util.LRUCache;
+import org.apache.camel.util.ObjectHelper;
+import org.apache.camel.util.ServiceHelper;
+
+/**
+ * Default implementation of {@link org.apache.camel.spi.ValidatorRegistry}.
+ */
+public class DefaultValidatorRegistry extends LRUCache<ValidatorKey, Validator> implements ValidatorRegistry<ValidatorKey> {
+    private static final long serialVersionUID = 1L;
+    private ConcurrentMap<ValidatorKey, Validator> staticMap;
+    private final CamelContext context;
+
+    public DefaultValidatorRegistry(CamelContext context) throws Exception {
+        this(context, new ArrayList<>());
+    }
+
+    public DefaultValidatorRegistry(CamelContext context, List<ValidatorDefinition> definitions) throws Exception {
+        // do not stop on eviction, as the validator may still be in use
+        super(CamelContextHelper.getMaximumValidatorCacheSize(context), CamelContextHelper.getMaximumValidatorCacheSize(context), false);
+        // static map to hold validator we do not want to be evicted
+        this.staticMap = new ConcurrentHashMap<>();
+        this.context = context;
+        
+        for (ValidatorDefinition def : definitions) {
+            Validator validator = def.createValidator(context);
+            context.addService(validator);
+            put(new ValidatorKey(new DataType(def.getType())), validator);
+        }
+    }
+
+    public Validator resolveValidator(ValidatorKey key) {
+        Validator answer = get(key);
+        if (answer == null && ObjectHelper.isNotEmpty(key.getType().getName())) {
+            answer = get(new ValidatorKey(new DataType(key.getType().getModel())));
+        }
+        return answer;
+    }
+
+    @Override
+    public void start() throws Exception {
+        resetStatistics();
+    }
+
+    @Override
+    public Validator get(Object o) {
+        // try static map first
+        Validator answer = staticMap.get(o);
+        if (answer == null) {
+            answer = super.get(o);
+        } else {
+            hits.incrementAndGet();
+        }
+        return answer;
+    }
+
+    @Override
+    public Validator put(ValidatorKey key, Validator validator) {
+        // at first we must see if the key already exists and then replace it back, so it stays the same spot
+        Validator answer = staticMap.remove(key);
+        if (answer != null) {
+            // replace existing
+            staticMap.put(key, validator);
+            return answer;
+        }
+
+        answer = super.remove(key);
+        if (answer != null) {
+            // replace existing
+            super.put(key, validator);
+            return answer;
+        }
+
+        // we want validators to be static if they are part of setting up or starting routes
+        if (context.isSetupRoutes() || context.isStartingRoutes()) {
+            answer = staticMap.put(key, validator);
+        } else {
+            answer = super.put(key, validator);
+        }
+
+        return answer;
+    }
+
+    @Override
+    public void putAll(Map<? extends ValidatorKey, ? extends Validator> map) {
+        // need to use put instead of putAll to ensure the entries gets added to either static or dynamic map
+        for (Map.Entry<? extends ValidatorKey, ? extends Validator> entry : map.entrySet()) {
+            put(entry.getKey(), entry.getValue());
+        }
+    }
+
+    @Override
+    public boolean containsKey(Object o) {
+        return staticMap.containsKey(o) || super.containsKey(o);
+    }
+
+    @Override
+    public boolean containsValue(Object o) {
+        return staticMap.containsValue(o) || super.containsValue(o);
+    }
+
+    @Override
+    public int size() {
+        return staticMap.size() + super.size();
+    }
+
+    public int staticSize() {
+        return staticMap.size();
+    }
+
+    @Override
+    public int dynamicSize() {
+        return super.size();
+    }
+
+    @Override
+    public boolean isEmpty() {
+        return staticMap.isEmpty() && super.isEmpty();
+    }
+
+    @Override
+    public Validator remove(Object o) {
+        Validator answer = staticMap.remove(o);
+        if (answer == null) {
+            answer = super.remove(o);
+        }
+        return answer;
+    }
+
+    @Override
+    public void clear() {
+        staticMap.clear();
+        super.clear();
+    }
+
+    @Override
+    public Set<ValidatorKey> keySet() {
+        Set<ValidatorKey> answer = new LinkedHashSet<>();
+        answer.addAll(staticMap.keySet());
+        answer.addAll(super.keySet());
+        return answer;
+    }
+
+    @Override
+    public Collection<Validator> values() {
+        Collection<Validator> answer = new ArrayList<>();
+        answer.addAll(staticMap.values());
+        answer.addAll(super.values());
+        return answer;
+    }
+
+    @Override
+    public Set<Entry<ValidatorKey, Validator>> entrySet() {
+        Set<Entry<ValidatorKey, Validator>> answer = new LinkedHashSet<>();
+        answer.addAll(staticMap.entrySet());
+        answer.addAll(super.entrySet());
+        return answer;
+    }
+
+    @Override
+    public int getMaximumCacheSize() {
+        return super.getMaxCacheSize();
+    }
+
+    /**
+     * Purges the cache
+     */
+    @Override
+    public void purge() {
+        // only purge the dynamic part
+        super.clear();
+    }
+
+    @Override
+    public boolean isStatic(DataType type) {
+        return staticMap.containsKey(new ValidatorKey(type));
+    }
+
+    @Override
+    public boolean isDynamic(DataType type) {
+        return super.containsKey(new ValidatorKey(type));
+    }
+
+    @Override
+    public void stop() throws Exception {
+        ServiceHelper.stopServices(staticMap.values());
+        ServiceHelper.stopServices(values());
+        purge();
+    }
+
+    @Override
+    public String toString() {
+        return "ValidatorRegistry for " + context.getName() + ", capacity: " + getMaxCacheSize();
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/camel/blob/f9946b2e/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
index f75f9b5..4878bcd 100644
--- 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
@@ -19,11 +19,11 @@ package org.apache.camel.impl.transformer;
 import org.apache.camel.impl.DefaultCamelContext;
 import org.apache.camel.model.transformer.TransformerDefinition;
 import org.apache.camel.spi.DataType;
-import org.apache.camel.util.ObjectHelper;
+import org.apache.camel.util.StringHelper;
 import org.apache.camel.util.ValueHolder;
 
 /**
- * Key used in Transformer registry in {@link DefaultCamelContext},
+ * Key used in {@link org.apache.camel.spi.TransformerRegistry} in {@link DefaultCamelContext},
  * to ensure a consistent lookup.
  */
 public final class TransformerKey extends ValueHolder<String> {
@@ -34,8 +34,8 @@ public final class TransformerKey extends ValueHolder<String> {
 
     public TransformerKey(String scheme) {
         super(scheme);
+        StringHelper.notEmpty(scheme, "scheme");
         this.scheme = scheme;
-        ObjectHelper.notEmpty(scheme, "scheme");
     }
 
     public TransformerKey(DataType from, DataType to) {
@@ -48,22 +48,16 @@ public final class TransformerKey extends ValueHolder<String> {
         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.getToType());
-        }
-        if (to == null) {
-            return from.toString().equals(def.getFromType());
-        }
-        return from.toString().equals(def.getFromType()) && to.toString().equals(def.getToType());
+    public String getScheme() {
+        return scheme;
+    }
+
+    public DataType getFrom() {
+        return from;
+    }
+
+    public DataType getTo() {
+        return to;
     }
 
     @Override

http://git-wip-us.apache.org/repos/asf/camel/blob/f9946b2e/camel-core/src/main/java/org/apache/camel/impl/validator/ProcessorValidator.java
----------------------------------------------------------------------
diff --git a/camel-core/src/main/java/org/apache/camel/impl/validator/ProcessorValidator.java b/camel-core/src/main/java/org/apache/camel/impl/validator/ProcessorValidator.java
new file mode 100644
index 0000000..e02cbcf
--- /dev/null
+++ b/camel-core/src/main/java/org/apache/camel/impl/validator/ProcessorValidator.java
@@ -0,0 +1,99 @@
+/**
+ * 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.validator;
+
+import org.apache.camel.CamelContext;
+import org.apache.camel.Exchange;
+import org.apache.camel.Message;
+import org.apache.camel.Processor;
+import org.apache.camel.ValidationException;
+import org.apache.camel.impl.DefaultExchange;
+import org.apache.camel.spi.DataType;
+import org.apache.camel.spi.Validator;
+import org.apache.camel.util.ServiceHelper;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+/**
+ * A {@link Validator} implementation which leverages {@link Processor} to perform validation.
+ * 
+ * {@see Validator}
+ */
+public class ProcessorValidator extends Validator {
+    private static final Logger LOG = LoggerFactory.getLogger(ProcessorValidator.class);
+
+    private Processor processor;
+    private String validatorString;
+
+    public ProcessorValidator(CamelContext context) {
+        setCamelContext(context);
+    }
+
+    /**
+     * Perform content validation with specified type using Processor.
+     * @param message message to apply validation
+     * @param type 'from' data type
+     */
+    @Override
+    public void validate(Message message, DataType type) throws ValidationException {
+        Exchange exchange = message.getExchange();
+        
+        LOG.debug("Sending to validate processor '{}'", processor);
+        DefaultExchange validateExchange = new DefaultExchange(exchange);
+        validateExchange.setIn(message);
+        validateExchange.setProperties(exchange.getProperties());
+        try {
+            processor.process(validateExchange);
+        } catch (Exception e) {
+            if (e instanceof ValidationException) {
+                throw (ValidationException)e;
+            } else {
+                throw new ValidationException(String.format("Validation failed for '%s'", type), validateExchange, e);
+            }
+        }
+    }
+
+    /**
+     * Set Processor.
+     * @param processor Processor
+     * @return this ProcessorTransformer instance
+     */
+    public ProcessorValidator setProcessor(Processor processor) {
+        this.processor = processor;
+        this.validatorString = null;
+        return this;
+    }
+
+    @Override
+    public String toString() {
+        if (validatorString == null) {
+            validatorString =
+                String.format("ProcessorValidator[type='%s', processor='%s']", getType(), processor);
+        }
+        return validatorString;
+    }
+
+    @Override
+    protected void doStart() throws Exception {
+        ServiceHelper.startService(this.processor);
+    }
+
+    @Override
+    protected void doStop() throws Exception {
+        ServiceHelper.stopService(this.processor);
+    }
+}

http://git-wip-us.apache.org/repos/asf/camel/blob/f9946b2e/camel-core/src/main/java/org/apache/camel/impl/validator/ValidatorKey.java
----------------------------------------------------------------------
diff --git a/camel-core/src/main/java/org/apache/camel/impl/validator/ValidatorKey.java b/camel-core/src/main/java/org/apache/camel/impl/validator/ValidatorKey.java
new file mode 100644
index 0000000..df4989e
--- /dev/null
+++ b/camel-core/src/main/java/org/apache/camel/impl/validator/ValidatorKey.java
@@ -0,0 +1,48 @@
+/**
+ * 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.validator;
+
+import org.apache.camel.impl.DefaultCamelContext;
+import org.apache.camel.model.transformer.TransformerDefinition;
+import org.apache.camel.model.validator.ValidatorDefinition;
+import org.apache.camel.spi.DataType;
+import org.apache.camel.util.StringHelper;
+import org.apache.camel.util.ValueHolder;
+
+/**
+ * Key used in {@link org.apache.camel.spi.ValidatorRegistry} in {@link DefaultCamelContext},
+ * to ensure a consistent lookup.
+ */
+public final class ValidatorKey extends ValueHolder<String> {
+
+    private DataType type;
+
+    public ValidatorKey(DataType type) {
+        super(type.toString());
+        this.type = type;
+    }
+
+    public DataType getType() {
+        return type;
+    }
+
+    @Override
+    public String toString() {
+        return get();
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/camel/blob/f9946b2e/camel-core/src/main/java/org/apache/camel/management/DefaultManagementLifecycleStrategy.java
----------------------------------------------------------------------
diff --git a/camel-core/src/main/java/org/apache/camel/management/DefaultManagementLifecycleStrategy.java b/camel-core/src/main/java/org/apache/camel/management/DefaultManagementLifecycleStrategy.java
index 7c3784e..4ab9ab9 100644
--- a/camel-core/src/main/java/org/apache/camel/management/DefaultManagementLifecycleStrategy.java
+++ b/camel-core/src/main/java/org/apache/camel/management/DefaultManagementLifecycleStrategy.java
@@ -50,6 +50,7 @@ import org.apache.camel.impl.ConsumerCache;
 import org.apache.camel.impl.DefaultCamelContext;
 import org.apache.camel.impl.DefaultEndpointRegistry;
 import org.apache.camel.impl.DefaultTransformerRegistry;
+import org.apache.camel.impl.DefaultValidatorRegistry;
 import org.apache.camel.impl.EventDrivenConsumerRoute;
 import org.apache.camel.impl.ProducerCache;
 import org.apache.camel.impl.ThrottlingExceptionRoutePolicy;
@@ -73,6 +74,7 @@ import org.apache.camel.management.mbean.ManagedThrottlingInflightRoutePolicy;
 import org.apache.camel.management.mbean.ManagedTracer;
 import org.apache.camel.management.mbean.ManagedTransformerRegistry;
 import org.apache.camel.management.mbean.ManagedTypeConverterRegistry;
+import org.apache.camel.management.mbean.ManagedValidatorRegistry;
 import org.apache.camel.model.AOPDefinition;
 import org.apache.camel.model.InterceptDefinition;
 import org.apache.camel.model.OnCompletionDefinition;
@@ -495,6 +497,8 @@ public class DefaultManagementLifecycleStrategy extends ServiceSupport implement
             answer = getManagementObjectStrategy().getManagedObjectForEventNotifier(context, (EventNotifier) service);
         } else if (service instanceof DefaultTransformerRegistry) {
             answer = new ManagedTransformerRegistry(context, (DefaultTransformerRegistry)service);
+        } else if (service instanceof DefaultValidatorRegistry) {
+            answer = new ManagedValidatorRegistry(context, (DefaultValidatorRegistry)service);
         } else if (service != null) {
             // fallback as generic service
             answer = getManagementObjectStrategy().getManagedObjectForService(context, service);

http://git-wip-us.apache.org/repos/asf/camel/blob/f9946b2e/camel-core/src/main/java/org/apache/camel/management/mbean/ManagedTransformerRegistry.java
----------------------------------------------------------------------
diff --git a/camel-core/src/main/java/org/apache/camel/management/mbean/ManagedTransformerRegistry.java b/camel-core/src/main/java/org/apache/camel/management/mbean/ManagedTransformerRegistry.java
index ec58eef..a74c524 100644
--- a/camel-core/src/main/java/org/apache/camel/management/mbean/ManagedTransformerRegistry.java
+++ b/camel-core/src/main/java/org/apache/camel/management/mbean/ManagedTransformerRegistry.java
@@ -40,9 +40,9 @@ import org.apache.camel.util.ObjectHelper;
 public class ManagedTransformerRegistry extends ManagedService implements ManagedTransformerRegistryMBean {
     private final TransformerRegistry transformerRegistry;
 
-    public ManagedTransformerRegistry(CamelContext context, TransformerRegistry endpointRegistry) {
-        super(context, endpointRegistry);
-        this.transformerRegistry = endpointRegistry;
+    public ManagedTransformerRegistry(CamelContext context, TransformerRegistry transformerRegistry) {
+        super(context, transformerRegistry);
+        this.transformerRegistry = transformerRegistry;
     }
 
     public void init(ManagementStrategy strategy) {

http://git-wip-us.apache.org/repos/asf/camel/blob/f9946b2e/camel-core/src/main/java/org/apache/camel/management/mbean/ManagedValidatorRegistry.java
----------------------------------------------------------------------
diff --git a/camel-core/src/main/java/org/apache/camel/management/mbean/ManagedValidatorRegistry.java b/camel-core/src/main/java/org/apache/camel/management/mbean/ManagedValidatorRegistry.java
new file mode 100644
index 0000000..7cdf54a
--- /dev/null
+++ b/camel-core/src/main/java/org/apache/camel/management/mbean/ManagedValidatorRegistry.java
@@ -0,0 +1,102 @@
+/**
+ * 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.management.mbean;
+
+import java.util.Collection;
+import javax.management.openmbean.CompositeData;
+import javax.management.openmbean.CompositeDataSupport;
+import javax.management.openmbean.CompositeType;
+import javax.management.openmbean.TabularData;
+import javax.management.openmbean.TabularDataSupport;
+
+import org.apache.camel.CamelContext;
+import org.apache.camel.api.management.ManagedResource;
+import org.apache.camel.api.management.mbean.CamelOpenMBeanTypes;
+import org.apache.camel.api.management.mbean.ManagedValidatorRegistryMBean;
+import org.apache.camel.spi.DataType;
+import org.apache.camel.spi.ManagementStrategy;
+import org.apache.camel.spi.Validator;
+import org.apache.camel.spi.ValidatorRegistry;
+import org.apache.camel.util.ObjectHelper;
+
+/**
+ * @version 
+ */
+@ManagedResource(description = "Managed ValidatorRegistry")
+public class ManagedValidatorRegistry extends ManagedService implements ManagedValidatorRegistryMBean {
+    private final ValidatorRegistry validatorRegistry;
+
+    public ManagedValidatorRegistry(CamelContext context, ValidatorRegistry validatorRegistry) {
+        super(context, validatorRegistry);
+        this.validatorRegistry = validatorRegistry;
+    }
+
+    public void init(ManagementStrategy strategy) {
+        super.init(strategy);
+    }
+
+    public ValidatorRegistry getValidatorRegistry() {
+        return validatorRegistry;
+    }
+
+    public String getSource() {
+        return validatorRegistry.toString();
+    }
+
+    public Integer getDynamicSize() {
+        return validatorRegistry.dynamicSize();
+    }
+
+    public Integer getStaticSize() {
+        return validatorRegistry.staticSize();
+    }
+
+    public Integer getSize() {
+        return validatorRegistry.size();
+    }
+
+    public Integer getMaximumCacheSize() {
+        return validatorRegistry.getMaximumCacheSize();
+    }
+
+    public void purge() {
+        validatorRegistry.purge();
+    }
+
+    @SuppressWarnings("unchecked")
+    public TabularData listValidators() {
+        try {
+            TabularData answer = new TabularDataSupport(CamelOpenMBeanTypes.listValidatorsTabularType());
+            Collection<Validator> validators = validatorRegistry.values();
+            for (Validator validator : validators) {
+                CompositeType ct = CamelOpenMBeanTypes.listValidatorsCompositeType();
+                DataType type = validator.getType();
+                String desc = validator.toString();
+                boolean isStatic = validatorRegistry.isStatic(type);
+                boolean isDynamic = validatorRegistry.isDynamic(type);
+
+                CompositeData data = new CompositeDataSupport(ct, new String[]{"type", "static", "dynamic", "description"},
+                                                              new Object[]{type.toString(), isStatic, isDynamic, desc});
+                answer.put(data);
+            }
+            return answer;
+        } catch (Exception e) {
+            throw ObjectHelper.wrapRuntimeCamelException(e);
+        }
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/camel/blob/f9946b2e/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 d6bbf3b..c145041 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
@@ -32,7 +32,8 @@ public final class Constants {
         + "org.apache.camel.model.language:"
         + "org.apache.camel.model.loadbalancer:"
         + "org.apache.camel.model.rest:"
-        + "org.apache.camel.model.transformer";
+        + "org.apache.camel.model.transformer:"
+        + "org.apache.camel.model.validator";
 
     public static final String PLACEHOLDER_QNAME = "http://camel.apache.org/schema/placeholder";
 

http://git-wip-us.apache.org/repos/asf/camel/blob/f9946b2e/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
index bbf04eb..7a74f8e 100644
--- a/camel-core/src/main/java/org/apache/camel/model/InputTypeDefinition.java
+++ b/camel-core/src/main/java/org/apache/camel/model/InputTypeDefinition.java
@@ -36,8 +36,10 @@ import org.apache.camel.spi.Metadata;
 @XmlRootElement(name = "inputType")
 @XmlAccessorType(XmlAccessType.FIELD)
 public class InputTypeDefinition extends OptionalIdentifiedDefinition<InputTypeDefinition> {
-    @XmlAttribute(required = true)
+    @XmlAttribute @Metadata(required = "true")
     private String urn;
+    @XmlAttribute  @Metadata(defaultValue = "false")
+    private Boolean validate = false;
 
     public InputTypeDefinition() {
     }
@@ -66,6 +68,22 @@ public class InputTypeDefinition extends OptionalIdentifiedDefinition<InputTypeD
         this.urn = "java:" + clazz.getName();
     }
 
+    /**
+     * Get if validation is required for this input type.
+     * @return true if validate
+     */
+    public boolean isValidate() {
+        return this.validate;
+    }
+
+    /**
+     * Set if validation is required for this input type.
+     * @param validate true if validate
+     */
+    public void setValidate(boolean validate) {
+        this.validate = validate;
+    }
+
     @Override
     public String toString() {
         return "inputType[" + urn + "]";

http://git-wip-us.apache.org/repos/asf/camel/blob/f9946b2e/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
index 837a447..9862f05 100644
--- a/camel-core/src/main/java/org/apache/camel/model/OutputTypeDefinition.java
+++ b/camel-core/src/main/java/org/apache/camel/model/OutputTypeDefinition.java
@@ -36,8 +36,10 @@ import org.apache.camel.spi.Metadata;
 @XmlRootElement(name = "outputType")
 @XmlAccessorType(XmlAccessType.FIELD)
 public class OutputTypeDefinition extends OptionalIdentifiedDefinition<OutputTypeDefinition> {
-    @XmlAttribute(required = true)
+    @XmlAttribute @Metadata(required = "true")
     private String urn;
+    @XmlAttribute  @Metadata(defaultValue = "false")
+    private Boolean validate = false;
 
     public OutputTypeDefinition() {
     }
@@ -67,6 +69,22 @@ public class OutputTypeDefinition extends OptionalIdentifiedDefinition<OutputTyp
         this.urn = "java:" + clazz.getName();
     }
 
+    /**
+     * Get if validation is required for this output type.
+     * @return true if validate
+     */
+    public boolean isValidate() {
+        return this.validate;
+    }
+
+    /**
+     * Set if validation is required for this output type.
+     * @param validate true if validate
+     */
+    public void setValidate(boolean validate) {
+        this.validate = validate;
+    }
+
     @Override
     public String toString() {
         return "outputType[" + urn + "]";

http://git-wip-us.apache.org/repos/asf/camel/blob/f9946b2e/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 97078dd..0a3a7ac 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
@@ -637,47 +637,91 @@ public class RouteDefinition extends ProcessorDefinition<RouteDefinition> {
     /**
      * Declare an input type.
      * @param urn input type URN
+     * @param validate if it's true, content validation is performed for this input type
      * @return the builder
      */
-    public RouteDefinition inputType(String urn) {
+    public RouteDefinition inputType(String urn, boolean validate) {
         inputType = new InputTypeDefinition();
         inputType.setUrn(urn);
+        inputType.setValidate(validate);
         return this;
     }
 
     /**
+     * Declare an input type.
+     * @param urn input type URN
+     * @return the builder
+     */
+    public RouteDefinition inputType(String urn) {
+        return inputType(urn, false);
+    }
+
+    /**
      * Declare an input type with Java class.
      * @param clazz Class object of the input type
+     * @param validate if it's true, content validation is performed for this input type
      * @return the builder
      */
-    public RouteDefinition inputType(Class clazz) {
+    public RouteDefinition inputType(Class clazz, boolean validate) {
         inputType = new InputTypeDefinition();
         inputType.setJavaClass(clazz);
+        inputType.setValidate(validate);
         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) {
+        return inputType(clazz, false);
+    }
+
+    /**
      * Declare an output type.
      * @param urn output type URN
+     * @param validate if it's true, content validation is performed for this output type
      * @return the builder
      */
-    public RouteDefinition outputType(String urn) {
+    public RouteDefinition outputType(String urn, boolean validate) {
         outputType = new OutputTypeDefinition();
         outputType.setUrn(urn);
+        outputType.setValidate(validate);
         return this;
     }
 
     /**
+     * Declare an output type.
+     * @param urn output type URN
+     * @return the builder
+     */
+    public RouteDefinition outputType(String urn) {
+        return outputType(urn, false);
+    }
+
+    /**
      * Declare an output type with Java class.
      * @param clazz Class object of the output type
+     * @param validate if it's true, content validation is performed for this output type
      * @return the builder
      */
-    public RouteDefinition outputType(Class clazz) {
+    public RouteDefinition outputType(Class clazz, boolean validate) {
         outputType = new OutputTypeDefinition();
         outputType.setJavaClass(clazz);
+        outputType.setValidate(validate);
         return this;
     }
 
+    /**
+     * Declare an output type with Java class.
+     * @param clazz Class object of the output type
+     * @return the builder
+     */
+    public RouteDefinition outputType(Class clazz) {
+        return outputType(clazz, false);
+    }
+
     // Properties
     // -----------------------------------------------------------------------
 

http://git-wip-us.apache.org/repos/asf/camel/blob/f9946b2e/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
index bce6a22..d0ff031 100644
--- 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
@@ -39,12 +39,12 @@ public class CustomTransformerDefinition extends TransformerDefinition {
     @XmlAttribute
     private String ref;
     @XmlAttribute
-    private String type;
+    private String className;
 
     @Override
     protected Transformer doCreateTransformer(CamelContext context) throws Exception {
-        if (ref == null && type == null) {
-            throw new IllegalArgumentException("'ref' or 'type' must be specified for customTransformer");
+        if (ref == null && className == null) {
+            throw new IllegalArgumentException("'ref' or 'className' must be specified for customTransformer");
         }
         Transformer transformer;
         if (ref != null) {
@@ -56,9 +56,9 @@ public class CustomTransformerDefinition extends TransformerDefinition {
                 throw new IllegalArgumentException(String.format("Transformer '%s' is already in use. Please check if duplicate transformer exists.", ref));
             }
         } else {
-            Class<Transformer> transformerClass = context.getClassResolver().resolveMandatoryClass(type, Transformer.class);
+            Class<Transformer> transformerClass = context.getClassResolver().resolveMandatoryClass(className, Transformer.class);
             if (transformerClass == null) {
-                throw new IllegalArgumentException("Cannot find transformer class: " + type);
+                throw new IllegalArgumentException("Cannot find transformer class: " + className);
             }
             transformer = context.getInjector().newInstance(transformerClass);
 
@@ -74,7 +74,7 @@ public class CustomTransformerDefinition extends TransformerDefinition {
     }
 
     /**
-     * Set a bean reference of the Transformer
+     * Set a bean reference of the {@link Transformer}
      *
      * @param ref the bean reference of the Transformer
      */
@@ -82,17 +82,17 @@ public class CustomTransformerDefinition extends TransformerDefinition {
         this.ref = ref;
     }
 
-    public String getType() {
-        return type;
+    public String getClassName() {
+        return className;
     }
 
     /**
-     * Set a class name of the Transformer
+     * Set a class name of the {@link Transformer}
      *
-     * @param type the class name of the Transformer
+     * @param className the class name of the Transformer
      */
-    public void setType(String type) {
-        this.type = type;
+    public void setClassName(String className) {
+        this.className = className;
     }
 
 }

http://git-wip-us.apache.org/repos/asf/camel/blob/f9946b2e/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
index ede69cc..88b1b88 100644
--- 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
@@ -38,17 +38,17 @@ public class TransformersDefinition {
         @XmlElement(required = false, name = "endpointTransformer", type = EndpointTransformerDefinition.class),
         @XmlElement(required = false, name = "customTransformer", type = CustomTransformerDefinition.class)}
         )
-    private List<TransformerDefinition> transforms;
+    private List<TransformerDefinition> transformers;
 
     /**
      * The configured transformers
      */
-    public void setTransformers(List<TransformerDefinition> transforms) {
-        this.transforms = transforms;
+    public void setTransformers(List<TransformerDefinition> transformers) {
+        this.transformers = transformers;
     }
 
-    public List<TransformerDefinition> getTransforms() {
-        return transforms;
+    public List<TransformerDefinition> getTransformers() {
+        return transformers;
     }
 
 }