You are viewing a plain text version of this content. The canonical link for it is here.
Posted to issues@camel.apache.org by "ASF GitHub Bot (JIRA)" <ji...@apache.org> on 2018/12/20 10:52:05 UTC

[jira] [Work logged] (CAMEL-12955) Create a Camel-ChatScript component

     [ https://issues.apache.org/jira/browse/CAMEL-12955?focusedWorklogId=177415&page=com.atlassian.jira.plugin.system.issuetabpanels:worklog-tabpanel#worklog-177415 ]

ASF GitHub Bot logged work on CAMEL-12955:
------------------------------------------

                Author: ASF GitHub Bot
            Created on: 20/Dec/18 10:51
            Start Date: 20/Dec/18 10:51
    Worklog Time Spent: 10m 
      Work Description: oscerd closed pull request #2653: CAMEL-12955 Create a Camel-ChatScript component changes
URL: https://github.com/apache/camel/pull/2653
 
 
   

This is a PR merged from a forked repository.
As GitHub hides the original diff on merge, it is displayed below for
the sake of provenance:

As this is a foreign pull request (from a fork), the diff is supplied
below (as it won't show otherwise due to GitHub magic):

diff --git a/apache-camel/pom.xml b/apache-camel/pom.xml
index be1d5431c77..39209c22826 100644
--- a/apache-camel/pom.xml
+++ b/apache-camel/pom.xml
@@ -24,7 +24,7 @@
   <parent>
     <groupId>org.apache.camel</groupId>
     <artifactId>camel-parent</artifactId>
-    <version>2.23.0-SNAPSHOT</version>
+    <version>2.24.0-SNAPSHOT</version>
     <relativePath>../parent</relativePath>
   </parent>
 
@@ -218,6 +218,10 @@
       <groupId>org.apache.camel</groupId>
       <artifactId>camel-context</artifactId>
     </dependency>
+    <dependency>
+      <groupId>org.apache.camel</groupId>
+      <artifactId>camel-corda</artifactId>
+    </dependency>
     <dependency>
       <groupId>org.apache.camel</groupId>
       <artifactId>camel-couchbase</artifactId>
@@ -366,6 +370,10 @@
       <groupId>org.apache.camel</groupId>
       <artifactId>camel-google-calendar</artifactId>
     </dependency>
+    <dependency>
+      <groupId>org.apache.camel</groupId>
+      <artifactId>camel-google-sheets</artifactId>
+    </dependency>
     <dependency>
       <groupId>org.apache.camel</groupId>
       <artifactId>camel-google-drive</artifactId>
@@ -490,6 +498,10 @@
       <groupId>org.apache.camel</groupId>
       <artifactId>camel-influxdb</artifactId>
     </dependency>
+    <dependency>
+      <groupId>org.apache.camel</groupId>
+      <artifactId>camel-ipfs</artifactId>
+    </dependency>
     <dependency>
       <groupId>org.apache.camel</groupId>
       <artifactId>camel-irc</artifactId>
@@ -760,6 +772,10 @@
     <dependency>
       <groupId>org.apache.camel</groupId>
       <artifactId>camel-netty4-http</artifactId>
+    </dependency>
+    <dependency>
+      <groupId>org.apache.camel</groupId>
+      <artifactId>camel-nsq</artifactId>
     </dependency>
      <dependency>
       <groupId>org.apache.camel</groupId>
@@ -1418,6 +1434,11 @@
       <artifactId>camel-core-starter</artifactId>
       <version>${project.version}</version>
     </dependency>
+    <dependency>
+      <groupId>org.apache.camel</groupId>
+      <artifactId>camel-corda-starter</artifactId>
+      <version>${project.version}</version>
+    </dependency>
     <dependency>
       <groupId>org.apache.camel</groupId>
       <artifactId>camel-couchdb-starter</artifactId>
@@ -1541,7 +1562,7 @@
       <groupId>org.apache.camel</groupId>
       <artifactId>camel-fhir-starter</artifactId>
       <version>${project.version}</version>
-    </dependency>    
+    </dependency>
     <dependency>
       <groupId>org.apache.camel</groupId>
       <artifactId>camel-flatpack-starter</artifactId>
@@ -1597,6 +1618,11 @@
       <artifactId>camel-google-calendar-starter</artifactId>
       <version>${project.version}</version>
     </dependency>
+    <dependency>
+      <groupId>org.apache.camel</groupId>
+      <artifactId>camel-google-sheets-starter</artifactId>
+      <version>${project.version}</version>
+    </dependency>
     <dependency>
       <groupId>org.apache.camel</groupId>
       <artifactId>camel-google-drive-starter</artifactId>
@@ -1737,6 +1763,11 @@
       <artifactId>camel-influxdb-starter</artifactId>
       <version>${project.version}</version>
     </dependency>
+    <dependency>
+      <groupId>org.apache.camel</groupId>
+      <artifactId>camel-ipfs-starter</artifactId>
+      <version>${project.version}</version>
+    </dependency>
     <dependency>
       <groupId>org.apache.camel</groupId>
       <artifactId>camel-irc-starter</artifactId>
@@ -2062,6 +2093,11 @@
       <artifactId>camel-netty-starter</artifactId>
       <version>${project.version}</version>
     </dependency>
+    <dependency>
+      <groupId>org.apache.camel</groupId>
+      <artifactId>camel-nsq-starter</artifactId>
+      <version>${project.version}</version>
+    </dependency>
     <dependency>
       <groupId>org.apache.camel</groupId>
       <artifactId>camel-ognl-starter</artifactId>
diff --git a/apache-camel/src/main/descriptors/common-bin.xml b/apache-camel/src/main/descriptors/common-bin.xml
index 8c63bdbc68e..10fe745729a 100644
--- a/apache-camel/src/main/descriptors/common-bin.xml
+++ b/apache-camel/src/main/descriptors/common-bin.xml
@@ -68,6 +68,7 @@
         <include>org.apache.camel:camel-connector</include>
         <include>org.apache.camel:camel-consul</include>
         <include>org.apache.camel:camel-context</include>
+        <include>org.apache.camel:camel-corda</include>
         <include>org.apache.camel:camel-couchdb</include>
         <include>org.apache.camel:camel-couchbase</include>
         <include>org.apache.camel:camel-crypto</include>
@@ -105,6 +106,7 @@
         <include>org.apache.camel:camel-git</include>
         <include>org.apache.camel:camel-github</include>
         <include>org.apache.camel:camel-google-calendar</include>
+        <include>org.apache.camel:camel-google-sheets</include>
         <include>org.apache.camel:camel-google-drive</include>
         <include>org.apache.camel:camel-google-mail</include>
         <include>org.apache.camel:camel-google-bigquery</include>
@@ -134,6 +136,7 @@
         <include>org.apache.camel:camel-infinispan</include>
         <include>org.apache.camel:camel-influxdb</include>
         <include>org.apache.camel:camel-ignite</include>
+        <include>org.apache.camel:camel-ipfs</include>
         <include>org.apache.camel:camel-irc</include>
         <include>org.apache.camel:camel-ironmq</include>
         <include>org.apache.camel:camel-jackson</include>
@@ -392,6 +395,7 @@
         <include>org.apache.camel:camel-cometd-starter</include>
         <include>org.apache.camel:camel-consul-starter</include>
         <include>org.apache.camel:camel-context-starter</include>
+        <include>org.apache.camel:camel-corda-starter</include>
         <include>org.apache.camel:camel-core-starter</include>
         <include>org.apache.camel:camel-couchdb-starter</include>
         <include>org.apache.camel:camel-couchbase-starter</include>
@@ -429,6 +433,7 @@
         <include>org.apache.camel:camel-git-starter</include>
         <include>org.apache.camel:camel-google-bigquery-starter</include>
         <include>org.apache.camel:camel-google-calendar-starter</include>
+        <include>org.apache.camel:camel-google-sheets-starter</include>
         <include>org.apache.camel:camel-google-drive-starter</include>
         <include>org.apache.camel:camel-google-mail-starter</include>
         <include>org.apache.camel:camel-google-pubsub-starter</include>
@@ -457,6 +462,7 @@
         <include>org.apache.camel:camel-ignite-starter</include>
         <include>org.apache.camel:camel-infinispan-starter</include>
         <include>org.apache.camel:camel-influxdb-starter</include>
+        <include>org.apache.camel:camel-ipfs-starter</include>
         <include>org.apache.camel:camel-irc-starter</include>
         <include>org.apache.camel:camel-ironmq-starter</include>
         <include>org.apache.camel:camel-jackson-starter</include>
@@ -504,7 +510,7 @@
         <include>org.apache.camel:camel-mail-starter</include>
         <include>org.apache.camel:camel-master-starter</include>
         <include>org.apache.camel:camel-metrics-starter</include>
-        <include>org.apache.camel:camel-micrometer-starter</include>		
+        <include>org.apache.camel:camel-micrometer-starter</include>
         <include>org.apache.camel:camel-milo-starter</include>
         <include>org.apache.camel:camel-mina2-starter</include>
         <include>org.apache.camel:camel-mllp-starter</include>
diff --git a/archetypes/camel-archetype-activemq/pom.xml b/archetypes/camel-archetype-activemq/pom.xml
index 1366e1c5153..0234e9a4c10 100644
--- a/archetypes/camel-archetype-activemq/pom.xml
+++ b/archetypes/camel-archetype-activemq/pom.xml
@@ -24,7 +24,7 @@
   <parent>
     <groupId>org.apache.camel</groupId>
     <artifactId>archetypes</artifactId>
-    <version>2.23.0-SNAPSHOT</version>
+    <version>2.24.0-SNAPSHOT</version>
   </parent>
 
   <groupId>org.apache.camel.archetypes</groupId>
diff --git a/archetypes/camel-archetype-api-component/pom.xml b/archetypes/camel-archetype-api-component/pom.xml
index 3ebeb43b7c1..33ffd47d391 100644
--- a/archetypes/camel-archetype-api-component/pom.xml
+++ b/archetypes/camel-archetype-api-component/pom.xml
@@ -24,7 +24,7 @@
   <parent>
     <groupId>org.apache.camel</groupId>
     <artifactId>archetypes</artifactId>
-    <version>2.23.0-SNAPSHOT</version>
+    <version>2.24.0-SNAPSHOT</version>
   </parent>
 
   <groupId>org.apache.camel.archetypes</groupId>
diff --git a/archetypes/camel-archetype-blueprint/pom.xml b/archetypes/camel-archetype-blueprint/pom.xml
index dcccb514096..26fb09ab78a 100644
--- a/archetypes/camel-archetype-blueprint/pom.xml
+++ b/archetypes/camel-archetype-blueprint/pom.xml
@@ -24,7 +24,7 @@
   <parent>
     <groupId>org.apache.camel</groupId>
     <artifactId>archetypes</artifactId>
-    <version>2.23.0-SNAPSHOT</version>
+    <version>2.24.0-SNAPSHOT</version>
   </parent>
 
   <groupId>org.apache.camel.archetypes</groupId>
diff --git a/archetypes/camel-archetype-cdi/pom.xml b/archetypes/camel-archetype-cdi/pom.xml
index d8bc7888aa2..ef0243771ac 100644
--- a/archetypes/camel-archetype-cdi/pom.xml
+++ b/archetypes/camel-archetype-cdi/pom.xml
@@ -24,7 +24,7 @@
   <parent>
     <groupId>org.apache.camel</groupId>
     <artifactId>archetypes</artifactId>
-    <version>2.23.0-SNAPSHOT</version>
+    <version>2.24.0-SNAPSHOT</version>
   </parent>
 
   <groupId>org.apache.camel.archetypes</groupId>
diff --git a/archetypes/camel-archetype-component/pom.xml b/archetypes/camel-archetype-component/pom.xml
index 6e75ab096cd..0ed268fb9f1 100644
--- a/archetypes/camel-archetype-component/pom.xml
+++ b/archetypes/camel-archetype-component/pom.xml
@@ -24,7 +24,7 @@
   <parent>
     <groupId>org.apache.camel</groupId>
     <artifactId>archetypes</artifactId>
-    <version>2.23.0-SNAPSHOT</version>
+    <version>2.24.0-SNAPSHOT</version>
   </parent>
 
   <groupId>org.apache.camel.archetypes</groupId>
diff --git a/archetypes/camel-archetype-connector/pom.xml b/archetypes/camel-archetype-connector/pom.xml
index 177d624c8ad..e8504d7602b 100644
--- a/archetypes/camel-archetype-connector/pom.xml
+++ b/archetypes/camel-archetype-connector/pom.xml
@@ -24,12 +24,12 @@
   <parent>
     <groupId>org.apache.camel</groupId>
     <artifactId>archetypes</artifactId>
-    <version>2.23.0-SNAPSHOT</version>
+    <version>2.24.0-SNAPSHOT</version>
   </parent>
 
   <groupId>org.apache.camel.archetypes</groupId>
   <artifactId>camel-archetype-connector</artifactId>
-  <name>Camel :: Archetypes :: Connector</name>
+  <name>Camel :: Archetypes :: Connector (deprecated)</name>
   <description>Creates a new Camel connector.</description>
   <packaging>maven-archetype</packaging>
 
diff --git a/archetypes/camel-archetype-dataformat/pom.xml b/archetypes/camel-archetype-dataformat/pom.xml
index 5882be02333..a32c1ee641d 100644
--- a/archetypes/camel-archetype-dataformat/pom.xml
+++ b/archetypes/camel-archetype-dataformat/pom.xml
@@ -24,7 +24,7 @@
   <parent>
     <groupId>org.apache.camel</groupId>
     <artifactId>archetypes</artifactId>
-    <version>2.23.0-SNAPSHOT</version>
+    <version>2.24.0-SNAPSHOT</version>
   </parent>
 
   <groupId>org.apache.camel.archetypes</groupId>
diff --git a/archetypes/camel-archetype-groovy/pom.xml b/archetypes/camel-archetype-groovy/pom.xml
index 88d596ff020..88aae76ce6d 100644
--- a/archetypes/camel-archetype-groovy/pom.xml
+++ b/archetypes/camel-archetype-groovy/pom.xml
@@ -24,7 +24,7 @@
   <parent>
     <groupId>org.apache.camel</groupId>
     <artifactId>archetypes</artifactId>
-    <version>2.23.0-SNAPSHOT</version>
+    <version>2.24.0-SNAPSHOT</version>
   </parent>
 
   <groupId>org.apache.camel.archetypes</groupId>
diff --git a/archetypes/camel-archetype-java/pom.xml b/archetypes/camel-archetype-java/pom.xml
index 0308191b50a..a9d4bf352bb 100644
--- a/archetypes/camel-archetype-java/pom.xml
+++ b/archetypes/camel-archetype-java/pom.xml
@@ -24,7 +24,7 @@
   <parent>
     <groupId>org.apache.camel</groupId>
     <artifactId>archetypes</artifactId>
-    <version>2.23.0-SNAPSHOT</version>
+    <version>2.24.0-SNAPSHOT</version>
   </parent>
 
   <groupId>org.apache.camel.archetypes</groupId>
diff --git a/archetypes/camel-archetype-java8/pom.xml b/archetypes/camel-archetype-java8/pom.xml
index 81affebf41e..373dff72500 100644
--- a/archetypes/camel-archetype-java8/pom.xml
+++ b/archetypes/camel-archetype-java8/pom.xml
@@ -24,7 +24,7 @@
   <parent>
     <groupId>org.apache.camel</groupId>
     <artifactId>archetypes</artifactId>
-    <version>2.23.0-SNAPSHOT</version>
+    <version>2.24.0-SNAPSHOT</version>
   </parent>
 
   <groupId>org.apache.camel.archetypes</groupId>
diff --git a/archetypes/camel-archetype-scala/pom.xml b/archetypes/camel-archetype-scala/pom.xml
index 9eb048ac5b9..856bb29a1b1 100644
--- a/archetypes/camel-archetype-scala/pom.xml
+++ b/archetypes/camel-archetype-scala/pom.xml
@@ -24,7 +24,7 @@
   <parent>
     <groupId>org.apache.camel</groupId>
     <artifactId>archetypes</artifactId>
-    <version>2.23.0-SNAPSHOT</version>
+    <version>2.24.0-SNAPSHOT</version>
   </parent>
 
   <groupId>org.apache.camel.archetypes</groupId>
diff --git a/archetypes/camel-archetype-scr/pom.xml b/archetypes/camel-archetype-scr/pom.xml
index d73d8bb4f86..4a501e2d4bf 100644
--- a/archetypes/camel-archetype-scr/pom.xml
+++ b/archetypes/camel-archetype-scr/pom.xml
@@ -23,7 +23,7 @@
   <parent>
     <artifactId>archetypes</artifactId>
     <groupId>org.apache.camel</groupId>
-    <version>2.23.0-SNAPSHOT</version>
+    <version>2.24.0-SNAPSHOT</version>
   </parent>
 
   <groupId>org.apache.camel.archetypes</groupId>
diff --git a/archetypes/camel-archetype-spring-boot/pom.xml b/archetypes/camel-archetype-spring-boot/pom.xml
index 78dfebb61fb..23b640a9034 100644
--- a/archetypes/camel-archetype-spring-boot/pom.xml
+++ b/archetypes/camel-archetype-spring-boot/pom.xml
@@ -24,7 +24,7 @@
   <parent>
     <groupId>org.apache.camel</groupId>
     <artifactId>archetypes</artifactId>
-    <version>2.23.0-SNAPSHOT</version>
+    <version>2.24.0-SNAPSHOT</version>
   </parent>
 
   <groupId>org.apache.camel.archetypes</groupId>
diff --git a/archetypes/camel-archetype-spring/pom.xml b/archetypes/camel-archetype-spring/pom.xml
index 4474f5b2568..b871da95a5b 100644
--- a/archetypes/camel-archetype-spring/pom.xml
+++ b/archetypes/camel-archetype-spring/pom.xml
@@ -24,7 +24,7 @@
   <parent>
     <groupId>org.apache.camel</groupId>
     <artifactId>archetypes</artifactId>
-    <version>2.23.0-SNAPSHOT</version>
+    <version>2.24.0-SNAPSHOT</version>
   </parent>
 
   <groupId>org.apache.camel.archetypes</groupId>
diff --git a/archetypes/camel-archetype-web/pom.xml b/archetypes/camel-archetype-web/pom.xml
index 9b3ee2a65fa..bc36a814fb6 100644
--- a/archetypes/camel-archetype-web/pom.xml
+++ b/archetypes/camel-archetype-web/pom.xml
@@ -24,7 +24,7 @@
   <parent>
     <groupId>org.apache.camel</groupId>
     <artifactId>archetypes</artifactId>
-    <version>2.23.0-SNAPSHOT</version>
+    <version>2.24.0-SNAPSHOT</version>
   </parent>
 
   <groupId>org.apache.camel.archetypes</groupId>
diff --git a/archetypes/pom.xml b/archetypes/pom.xml
index 5e7668783ea..bb35eb0cdd0 100644
--- a/archetypes/pom.xml
+++ b/archetypes/pom.xml
@@ -24,7 +24,7 @@
   <parent>
     <groupId>org.apache.camel</groupId>
     <artifactId>camel-parent</artifactId>
-    <version>2.23.0-SNAPSHOT</version>
+    <version>2.24.0-SNAPSHOT</version>
     <relativePath>../parent</relativePath>
   </parent>
   
diff --git a/bom/camel-bom/pom.xml b/bom/camel-bom/pom.xml
index 69a6f752ca5..79d820a6bdf 100644
--- a/bom/camel-bom/pom.xml
+++ b/bom/camel-bom/pom.xml
@@ -22,7 +22,7 @@
   <parent>
     <groupId>org.apache.camel</groupId>
     <artifactId>camel</artifactId>
-    <version>2.23.0-SNAPSHOT</version>
+    <version>2.24.0-SNAPSHOT</version>
     <relativePath>../../</relativePath>
   </parent>
   <artifactId>camel-bom</artifactId>
@@ -491,6 +491,16 @@
         <artifactId>camel-context-starter</artifactId>
         <version>${project.version}</version>
       </dependency>
+      <dependency>
+        <groupId>org.apache.camel</groupId>
+        <artifactId>camel-corda</artifactId>
+        <version>${project.version}</version>
+      </dependency>
+      <dependency>
+        <groupId>org.apache.camel</groupId>
+        <artifactId>camel-corda-starter</artifactId>
+        <version>${project.version}</version>
+      </dependency>
       <dependency>
         <groupId>org.apache.camel</groupId>
         <artifactId>camel-core</artifactId>
@@ -928,6 +938,16 @@
         <artifactId>camel-google-pubsub-starter</artifactId>
         <version>${project.version}</version>
       </dependency>
+      <dependency>
+        <groupId>org.apache.camel</groupId>
+        <artifactId>camel-google-sheets</artifactId>
+        <version>${project.version}</version>
+      </dependency>
+      <dependency>
+        <groupId>org.apache.camel</groupId>
+        <artifactId>camel-google-sheets-starter</artifactId>
+        <version>${project.version}</version>
+      </dependency>
       <dependency>
         <groupId>org.apache.camel</groupId>
         <artifactId>camel-gora</artifactId>
@@ -1188,6 +1208,16 @@
         <artifactId>camel-influxdb-starter</artifactId>
         <version>${project.version}</version>
       </dependency>
+      <dependency>
+        <groupId>org.apache.camel</groupId>
+        <artifactId>camel-ipfs</artifactId>
+        <version>${project.version}</version>
+      </dependency>
+      <dependency>
+        <groupId>org.apache.camel</groupId>
+        <artifactId>camel-ipfs-starter</artifactId>
+        <version>${project.version}</version>
+      </dependency>
       <dependency>
         <groupId>org.apache.camel</groupId>
         <artifactId>camel-irc</artifactId>
diff --git a/bom/pom.xml b/bom/pom.xml
index 3307a829e8b..5c3de896c59 100644
--- a/bom/pom.xml
+++ b/bom/pom.xml
@@ -24,7 +24,7 @@
   <parent>
     <groupId>org.apache.camel</groupId>
     <artifactId>camel-parent</artifactId>
-    <version>2.23.0-SNAPSHOT</version>
+    <version>2.24.0-SNAPSHOT</version>
     <relativePath>../parent</relativePath>
   </parent>
 
diff --git a/buildingtools/pom.xml b/buildingtools/pom.xml
index 5e8d7bdbb89..61a4b3a6280 100644
--- a/buildingtools/pom.xml
+++ b/buildingtools/pom.xml
@@ -23,7 +23,7 @@
     <parent>
         <groupId>org.apache.camel</groupId>
         <artifactId>camel</artifactId>
-        <version>2.23.0-SNAPSHOT</version>
+        <version>2.24.0-SNAPSHOT</version>
     </parent>
 
     <artifactId>camel-buildtools</artifactId>
diff --git a/camel-core/pom.xml b/camel-core/pom.xml
index f5d1c43b2d5..2e09609f134 100644
--- a/camel-core/pom.xml
+++ b/camel-core/pom.xml
@@ -25,7 +25,7 @@
   <parent>
     <groupId>org.apache.camel</groupId>
     <artifactId>camel-parent</artifactId>
-    <version>2.23.0-SNAPSHOT</version>
+    <version>2.24.0-SNAPSHOT</version>
     <relativePath>../parent</relativePath>
   </parent>
 
diff --git a/camel-core/src/main/docs/rest-dsl.adoc b/camel-core/src/main/docs/rest-dsl.adoc
index 570cdc003e3..b5e4fce3604 100644
--- a/camel-core/src/main/docs/rest-dsl.adoc
+++ b/camel-core/src/main/docs/rest-dsl.adoc
@@ -585,7 +585,7 @@ whether the Content-Type and Accept headers from
                         A key without a prefix is a common key for all situations.
 
                         From Camel 2.17: the options value can use the # notation to refer to a bean to lookup in the Registry
-|apiProperties | -|Sets additional options on api level.
+|apiProperty | -|Sets additional options on api level.
 |corsHeaders | -|Allows to configure custom CORS headers.
 |===
 
diff --git a/camel-core/src/main/java/org/apache/camel/component/file/GenericFileEndpoint.java b/camel-core/src/main/java/org/apache/camel/component/file/GenericFileEndpoint.java
index fac9e7e8fbe..c60312375ad 100644
--- a/camel-core/src/main/java/org/apache/camel/component/file/GenericFileEndpoint.java
+++ b/camel-core/src/main/java/org/apache/camel/component/file/GenericFileEndpoint.java
@@ -1420,8 +1420,8 @@ protected String createDoneFileName(String fileName) {
 
         pattern = pattern.replaceFirst("\\$\\{file:name\\}", onlyName);
         pattern = pattern.replaceFirst("\\$simple\\{file:name\\}", onlyName);
-        pattern = pattern.replaceFirst("\\$\\{file:name.noext\\}", FileUtil.stripExt(onlyName));
-        pattern = pattern.replaceFirst("\\$simple\\{file:name.noext\\}", FileUtil.stripExt(onlyName));
+        pattern = pattern.replaceFirst("\\$\\{file:name.noext\\}", FileUtil.stripExt(onlyName, true));
+        pattern = pattern.replaceFirst("\\$simple\\{file:name.noext\\}", FileUtil.stripExt(onlyName, true));
 
         // must be able to resolve all placeholders supported
         if (StringHelper.hasStartToken(pattern, "simple")) {
diff --git a/camel-core/src/main/java/org/apache/camel/component/file/GenericFileOperations.java b/camel-core/src/main/java/org/apache/camel/component/file/GenericFileOperations.java
index 9d1b3c8c851..aaeb3df1ab9 100644
--- a/camel-core/src/main/java/org/apache/camel/component/file/GenericFileOperations.java
+++ b/camel-core/src/main/java/org/apache/camel/component/file/GenericFileOperations.java
@@ -62,7 +62,7 @@
      * folder already exists.
      *
      * @param directory the directory path to build as a relative string name
-     * @param absolute wether the directory is an absolute or relative path
+     * @param absolute whether the directory is an absolute or relative path
      * @return true if build or already exists, false if not possible (could be lack of permissions)
      * @throws GenericFileOperationFailedException can be thrown
      */
diff --git a/camel-core/src/main/java/org/apache/camel/converter/jaxp/XmlConverter.java b/camel-core/src/main/java/org/apache/camel/converter/jaxp/XmlConverter.java
index 4f3125f9bd0..d366b5506c6 100644
--- a/camel-core/src/main/java/org/apache/camel/converter/jaxp/XmlConverter.java
+++ b/camel-core/src/main/java/org/apache/camel/converter/jaxp/XmlConverter.java
@@ -33,6 +33,7 @@
 import java.util.Map;
 import java.util.Properties;
 
+import javax.xml.XMLConstants;
 import javax.xml.parsers.DocumentBuilder;
 import javax.xml.parsers.DocumentBuilderFactory;
 import javax.xml.parsers.ParserConfigurationException;
@@ -1138,6 +1139,13 @@ public DocumentBuilderFactory createDocumentBuilderFactory() {
         factory.setNamespaceAware(true);
         factory.setIgnoringElementContentWhitespace(true);
         factory.setIgnoringComments(true);
+        try {
+            // Set secure processing
+            factory.setFeature(XMLConstants.FEATURE_SECURE_PROCESSING, Boolean.TRUE);
+        } catch (ParserConfigurationException e) {
+            LOG.warn("DocumentBuilderFactory doesn't support the feature {} with value {}, due to {}.",
+                     new Object[]{XMLConstants.FEATURE_SECURE_PROCESSING, true, e});
+        }
         try {
             // Disable the external-general-entities by default
             factory.setFeature("http://xml.org/sax/features/external-general-entities", false);
diff --git a/camel-core/src/main/java/org/apache/camel/management/mbean/RouteCoverageXmlParser.java b/camel-core/src/main/java/org/apache/camel/management/mbean/RouteCoverageXmlParser.java
index 62bc6495246..b9795b0a22e 100644
--- a/camel-core/src/main/java/org/apache/camel/management/mbean/RouteCoverageXmlParser.java
+++ b/camel-core/src/main/java/org/apache/camel/management/mbean/RouteCoverageXmlParser.java
@@ -19,6 +19,7 @@
 import java.io.InputStream;
 import java.util.Stack;
 
+import javax.xml.XMLConstants;
 import javax.xml.parsers.DocumentBuilder;
 import javax.xml.parsers.DocumentBuilderFactory;
 import javax.xml.parsers.SAXParser;
@@ -62,8 +63,10 @@ private RouteCoverageXmlParser() {
      */
     public static Document parseXml(final CamelContext camelContext, final InputStream is) throws Exception {
         final SAXParserFactory factory = SAXParserFactory.newInstance();
+        factory.setFeature(XMLConstants.FEATURE_SECURE_PROCESSING, Boolean.TRUE);
         final SAXParser parser = factory.newSAXParser();
         final DocumentBuilderFactory docBuilderFactory = DocumentBuilderFactory.newInstance();
+        docBuilderFactory.setFeature(XMLConstants.FEATURE_SECURE_PROCESSING, Boolean.TRUE);
         final DocumentBuilder docBuilder = docBuilderFactory.newDocumentBuilder();
         final Document doc = docBuilder.newDocument();
 
@@ -170,4 +173,4 @@ private void addTextIfNeeded() {
 
         return doc;
     }
-}
\ No newline at end of file
+}
diff --git a/camel-core/src/main/java/org/apache/camel/model/RouteDefinitionHelper.java b/camel-core/src/main/java/org/apache/camel/model/RouteDefinitionHelper.java
index 041bdc212dc..83e79f34748 100644
--- a/camel-core/src/main/java/org/apache/camel/model/RouteDefinitionHelper.java
+++ b/camel-core/src/main/java/org/apache/camel/model/RouteDefinitionHelper.java
@@ -19,14 +19,18 @@
 import java.io.UnsupportedEncodingException;
 import java.net.URISyntaxException;
 import java.util.ArrayList;
+import java.util.HashMap;
 import java.util.HashSet;
 import java.util.Iterator;
 import java.util.LinkedHashSet;
 import java.util.List;
+import java.util.Map;
 import java.util.Set;
 
 import org.apache.camel.CamelContext;
 import org.apache.camel.builder.ErrorHandlerBuilder;
+import org.apache.camel.model.rest.RestDefinition;
+import org.apache.camel.model.rest.VerbDefinition;
 import org.apache.camel.util.CamelContextHelper;
 import org.apache.camel.util.EndpointHelper;
 import org.apache.camel.util.ObjectHelper;
@@ -138,6 +142,19 @@ public void run() {
                     });
                 }
                 customIds.add(id);
+            } else {
+                RestDefinition rest = route.getRestDefinition();
+                if (rest != null && route.isRest()) {
+                    VerbDefinition verb = findVerbDefinition(rest, route.getInputs().get(0).getUri());
+                    if (verb != null) {
+                        String id = verb.getId();
+                        if (verb.hasCustomIdAssigned() && ObjectHelper.isNotEmpty(id) && !customIds.contains(id)) {
+                            route.setId(id);
+                            customIds.add(id);
+                            break;
+                        }
+                    }
+                }
             }
         }
 
@@ -145,10 +162,11 @@ public void run() {
         for (final RouteDefinition route : routes) {
             if (route.getId() == null) {
                 // keep assigning id's until we find a free name
+                
                 boolean done = false;
                 String id = null;
                 while (!done) {
-                    id = context.getNodeIdFactory().createId(route);
+                    id = route.idOrCreate(context.getNodeIdFactory());
                     done = !customIds.contains(id);
                 }
                 route.setId(id);
@@ -162,7 +180,47 @@ public void run() {
                 route.setCustomId(false);
                 customIds.add(route.getId());
             }
+            RestDefinition rest = route.getRestDefinition();
+            if (rest != null && route.isRest()) {
+                VerbDefinition verb = findVerbDefinition(rest, route.getInputs().get(0).getUri());
+                if (verb != null) {
+                    String id = verb.idOrCreate(context.getNodeIdFactory());
+                    if (!verb.getUsedForGeneratingNodeId()) {
+                        id = route.getId();
+                    }
+                    verb.setRouteId(id);
+                }
+                List<FromDefinition> fromDefinitions = route.getInputs();
+                
+                if (ObjectHelper.isNotEmpty(fromDefinitions)) {
+                    FromDefinition fromDefinition = fromDefinitions.get(0);
+                    String endpointUri = fromDefinition.getEndpointUri();
+                    if (ObjectHelper.isNotEmpty(endpointUri)) {
+                        Map<String, Object> options = new HashMap<String, Object>();
+                        options.put("routeId", route.getId());
+                        endpointUri = URISupport.appendParametersToURI(endpointUri, options);
+                     
+                        // replace uri with new routeId
+                        fromDefinition.setUri(endpointUri);
+                        fromDefinitions.set(0, fromDefinition);
+                        route.setInputs(fromDefinitions);
+                    }
+                }
+            }
+        }
+    }
+    
+    /**
+     * Find verb associated with the route by mapping uri
+     */
+    private static VerbDefinition findVerbDefinition(RestDefinition rest, String endpointUri) {
+        for (VerbDefinition verb : rest.getVerbs()) {
+            String verbUri = rest.buildFromUri(verb);
+            if (endpointUri.startsWith(verbUri)) {
+                return verb;
+            }
         }
+        return null;
     }
 
     /**
diff --git a/camel-core/src/main/java/org/apache/camel/model/rest/RestDefinition.java b/camel-core/src/main/java/org/apache/camel/model/rest/RestDefinition.java
index 946fb76c16e..3e09b9a1406 100644
--- a/camel-core/src/main/java/org/apache/camel/model/rest/RestDefinition.java
+++ b/camel-core/src/main/java/org/apache/camel/model/rest/RestDefinition.java
@@ -658,6 +658,13 @@ public RouteDefinition route() {
         verb.setRoute(route);
         return route;
     }
+    
+    /**
+     * Build the from endpoint uri for the verb
+     */
+    public String buildFromUri(VerbDefinition verb) {
+        return "rest:" + verb.asVerb() + ":" + buildUri(verb);
+    }
 
     // Implementation
     //-------------------------------------------------------------------------
@@ -799,6 +806,7 @@ public static RouteDefinition asRouteApiDefinition(CamelContext camelContext, Re
         return answer;
     }
 
+    @SuppressWarnings("rawtypes")
     private void addRouteDefinition(CamelContext camelContext, List<RouteDefinition> answer, String component) {
         for (VerbDefinition verb : getVerbs()) {
             // either the verb has a singular to or a embedded route
@@ -877,7 +885,7 @@ private void addRouteDefinition(CamelContext camelContext, List<RouteDefinition>
             route.setRestBindingDefinition(binding);
 
             // create the from endpoint uri which is using the rest component
-            String from = "rest:" + verb.asVerb() + ":" + buildUri(verb);
+            String from = buildFromUri(verb);
 
             // append options
             Map<String, Object> options = new HashMap<>();
@@ -902,23 +910,7 @@ private void addRouteDefinition(CamelContext camelContext, List<RouteDefinition>
             if (outType != null) {
                 options.put("outType", outType);
             }
-            // if no route id has been set, then use the verb id as route id
-            if (!route.hasCustomIdAssigned()) {
-                // use id of verb as route id
-                String id = verb.getId();
-                if (id != null) {
-                    route.setId(id);
-                }
-            }
-
-            String routeId = verb.idOrCreate(camelContext.getNodeIdFactory());
-
-            if (!verb.getUsedForGeneratingNodeId()) {
-                routeId = route.idOrCreate(camelContext.getNodeIdFactory());
-            }
 
-            verb.setRouteId(routeId);
-            options.put("routeId", routeId);
             if (component != null && !component.isEmpty()) {
                 options.put("componentName", component);
             }
@@ -1012,7 +1004,6 @@ private void addRouteDefinition(CamelContext camelContext, List<RouteDefinition>
 
             // the route should be from this rest endpoint
             route.fromRest(from);
-            route.routeId(routeId);
             route.setRestDefinition(this);
             answer.add(route);
         }
diff --git a/camel-core/src/main/java/org/apache/camel/model/rest/VerbDefinition.java b/camel-core/src/main/java/org/apache/camel/model/rest/VerbDefinition.java
index bf56005782e..acbe38a6b4b 100644
--- a/camel-core/src/main/java/org/apache/camel/model/rest/VerbDefinition.java
+++ b/camel-core/src/main/java/org/apache/camel/model/rest/VerbDefinition.java
@@ -141,7 +141,7 @@ public void setParams(List<RestOperationParamDefinition> params) {
     /**
      * Sets swagger operation response messages.
      */
-    public void setResponseMsgs(List<RestOperationResponseMsgDefinition> params) {
+    public void setResponseMsgs(List<RestOperationResponseMsgDefinition> responseMsgs) {
         this.responseMsgs = responseMsgs;
     }
 
diff --git a/camel-core/src/main/java/org/apache/camel/processor/RestBindingAdvice.java b/camel-core/src/main/java/org/apache/camel/processor/RestBindingAdvice.java
index 7b401ac19c3..3b6cabce491 100644
--- a/camel-core/src/main/java/org/apache/camel/processor/RestBindingAdvice.java
+++ b/camel-core/src/main/java/org/apache/camel/processor/RestBindingAdvice.java
@@ -34,6 +34,8 @@
 import org.apache.camel.util.ExchangeHelper;
 import org.apache.camel.util.MessageHelper;
 import org.apache.camel.util.ObjectHelper;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
 
 /**
  * A {@link org.apache.camel.processor.CamelInternalProcessorAdvice} that binds the REST DSL incoming
@@ -47,6 +49,8 @@
  * @see CamelInternalProcessor
  */
 public class RestBindingAdvice implements CamelInternalProcessorAdvice<Map<String, Object>> {
+
+    private static final Logger LOG = LoggerFactory.getLogger(RestBindingAdvice.class);
     private static final String STATE_KEY_DO_MARSHAL = "doMarshal";
     private static final String STATE_KEY_ACCEPT = "accept";
     private static final String STATE_JSON = "json";
@@ -198,6 +202,7 @@ private void unmarshal(Exchange exchange, Map<String, Object> state) throws Exce
         if (clientRequestValidation) {
             // check if the content-type is accepted according to consumes
             if (!isValidOrAcceptedContentType(consumes, contentType)) {
+                LOG.trace("Consuming content type does not match contentType header {}. Stopping routing.", contentType);
                 // the content-type is not something we can process so its a HTTP_ERROR 415
                 exchange.getOut().setHeader(Exchange.HTTP_RESPONSE_CODE, 415);
                 // stop routing and return
@@ -207,6 +212,7 @@ private void unmarshal(Exchange exchange, Map<String, Object> state) throws Exce
 
             // check if what is produces is accepted by the client
             if (!isValidOrAcceptedContentType(produces, accept)) {
+                LOG.trace("Produced content type does not match accept header {}. Stopping routing.", contentType);
                 // the response type is not accepted by the client so its a HTTP_ERROR 406
                 exchange.getOut().setHeader(Exchange.HTTP_RESPONSE_CODE, 406);
                 // stop routing and return
@@ -507,6 +513,12 @@ private static boolean isValidOrAcceptedContentType(String valid, String target)
             return true;
         }
 
+        // Any MIME type
+        // https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Accept#Directives
+        if ("*/*".equals(target)) {
+            return true;
+        }
+
         boolean isXml = valid.toLowerCase(Locale.ENGLISH).contains("xml");
         boolean isJson = valid.toLowerCase(Locale.ENGLISH).contains("json");
 
@@ -522,4 +534,4 @@ private static boolean isValidOrAcceptedContentType(String valid, String target)
         return true;
     }
 
-}
\ No newline at end of file
+}
diff --git a/camel-core/src/main/java/org/apache/camel/spi/Policy.java b/camel-core/src/main/java/org/apache/camel/spi/Policy.java
index aa806f6aaa6..b5f91d94cc9 100644
--- a/camel-core/src/main/java/org/apache/camel/spi/Policy.java
+++ b/camel-core/src/main/java/org/apache/camel/spi/Policy.java
@@ -41,7 +41,7 @@
      * Hook invoked before the wrap.
      * <p/>
      * This allows you to do any custom logic before the processor is wrapped. For example to
-     * manipulate the {@link org.apache.camel.model.ProcessorDefinition definiton}
+     * manipulate the {@link org.apache.camel.model.ProcessorDefinition definition}
      *
      * @param routeContext   the route context
      * @param definition     the processor definition
diff --git a/camel-core/src/main/java/org/apache/camel/util/XmlLineNumberParser.java b/camel-core/src/main/java/org/apache/camel/util/XmlLineNumberParser.java
index d80cb45c9c8..7c01d8a0b21 100644
--- a/camel-core/src/main/java/org/apache/camel/util/XmlLineNumberParser.java
+++ b/camel-core/src/main/java/org/apache/camel/util/XmlLineNumberParser.java
@@ -21,6 +21,7 @@
 import java.io.StringReader;
 import java.util.Stack;
 
+import javax.xml.XMLConstants;
 import javax.xml.parsers.DocumentBuilder;
 import javax.xml.parsers.DocumentBuilderFactory;
 import javax.xml.parsers.SAXParser;
@@ -107,11 +108,13 @@ public static Document parseXml(final InputStream is, XmlTextTransformer xmlTran
         final Document doc;
         SAXParser parser;
         final SAXParserFactory factory = SAXParserFactory.newInstance();
+        factory.setFeature(XMLConstants.FEATURE_SECURE_PROCESSING, Boolean.TRUE);
         parser = factory.newSAXParser();
         final DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance();
         // turn off validator and loading external dtd
         dbf.setValidating(false);
         dbf.setNamespaceAware(true);
+        dbf.setFeature(XMLConstants.FEATURE_SECURE_PROCESSING, Boolean.TRUE);
         dbf.setFeature("http://xml.org/sax/features/namespaces", false);
         dbf.setFeature("http://xml.org/sax/features/validation", false);
         dbf.setFeature("http://apache.org/xml/features/nonvalidating/load-dtd-grammar", false);
diff --git a/camel-core/src/test/java/org/apache/camel/component/file/FileConsumeDynamicDoneFileNameWithTwoDotsTest.java b/camel-core/src/test/java/org/apache/camel/component/file/FileConsumeDynamicDoneFileNameWithTwoDotsTest.java
new file mode 100644
index 00000000000..a45905a36b4
--- /dev/null
+++ b/camel-core/src/test/java/org/apache/camel/component/file/FileConsumeDynamicDoneFileNameWithTwoDotsTest.java
@@ -0,0 +1,68 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.camel.component.file;
+
+import java.io.File;
+import java.lang.invoke.MethodHandles;
+
+import org.apache.camel.ContextTestSupport;
+import org.apache.camel.Exchange;
+import org.apache.camel.builder.NotifyBuilder;
+import org.apache.camel.builder.RouteBuilder;
+import org.junit.Before;
+import org.junit.Test;
+
+/**
+ * This class tests an issue where an input file is not picked up due to a dynamic
+ * doneFileName containing two dots.
+ */
+public class FileConsumeDynamicDoneFileNameWithTwoDotsTest extends ContextTestSupport {
+
+    private static final String TARGET_DIR_NAME = "target/" + MethodHandles.lookup().lookupClass().getSimpleName();
+
+    @Override
+    @Before
+    public void setUp() throws Exception {
+        deleteDirectory(TARGET_DIR_NAME);
+        super.setUp();
+    }
+
+    @Test
+    public void testDynamicDoneFileNameContainingTwoDots() throws Exception {
+        NotifyBuilder notify = new NotifyBuilder(context).whenDone(1).create();
+        getMockEndpoint("mock:result").expectedBodiesReceivedInAnyOrder("input-body");
+
+        template.sendBodyAndHeader("file:" + TARGET_DIR_NAME, "input-body", Exchange.FILE_NAME, "test.twodot.txt");
+        template.sendBodyAndHeader("file:" + TARGET_DIR_NAME, "done-body", Exchange.FILE_NAME, "test.twodot.done");
+
+        assertMockEndpointsSatisfied();
+        assertTrue(notify.matchesMockWaitTime());
+
+        assertFalse("Input file should be deleted", new File(TARGET_DIR_NAME, "test.twodot.txt").exists());
+        assertFalse("Done file should be deleted", new File(TARGET_DIR_NAME, "test.twodot.done").exists());
+    }
+
+    @Override
+    protected RouteBuilder createRouteBuilder() throws Exception {
+        return new RouteBuilder() {
+            @Override
+            public void configure() throws Exception {
+                from("file:" + TARGET_DIR_NAME + "?doneFileName=${file:name.noext}.done&initialDelay=0").to("mock:result");
+            }
+        };
+    }
+}
diff --git a/camel-core/src/test/java/org/apache/camel/component/file/FileConsumeSimpleDynamicDoneFileNameWithTwoDotsTest.java b/camel-core/src/test/java/org/apache/camel/component/file/FileConsumeSimpleDynamicDoneFileNameWithTwoDotsTest.java
new file mode 100644
index 00000000000..d1de7a94bc4
--- /dev/null
+++ b/camel-core/src/test/java/org/apache/camel/component/file/FileConsumeSimpleDynamicDoneFileNameWithTwoDotsTest.java
@@ -0,0 +1,68 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.camel.component.file;
+
+import java.io.File;
+import java.lang.invoke.MethodHandles;
+
+import org.apache.camel.ContextTestSupport;
+import org.apache.camel.Exchange;
+import org.apache.camel.builder.NotifyBuilder;
+import org.apache.camel.builder.RouteBuilder;
+import org.junit.Before;
+import org.junit.Test;
+
+/**
+ * This class tests an issue where an input file is not picked up due to a
+ * dynamic doneFileName using the simple syntax and containing two dots.
+ */
+public class FileConsumeSimpleDynamicDoneFileNameWithTwoDotsTest extends ContextTestSupport {
+
+    private static final String TARGET_DIR_NAME = "target/" + MethodHandles.lookup().lookupClass().getSimpleName();
+
+    @Override
+    @Before
+    public void setUp() throws Exception {
+        deleteDirectory(TARGET_DIR_NAME);
+        super.setUp();
+    }
+
+    @Test
+    public void testSimpleDynamicDoneFileNameContainingTwoDots() throws Exception {
+        NotifyBuilder notify = new NotifyBuilder(context).whenDone(1).create();
+        getMockEndpoint("mock:result").expectedBodiesReceivedInAnyOrder("input-body");
+
+        template.sendBodyAndHeader("file:" + TARGET_DIR_NAME, "input-body", Exchange.FILE_NAME, "test.twodot.txt");
+        template.sendBodyAndHeader("file:" + TARGET_DIR_NAME, "done-body", Exchange.FILE_NAME, "test.twodot.done");
+
+        assertMockEndpointsSatisfied();
+        assertTrue(notify.matchesMockWaitTime());
+
+        assertFalse("Input file should be deleted", new File(TARGET_DIR_NAME, "test.twodot.txt").exists());
+        assertFalse("Done file should be deleted", new File(TARGET_DIR_NAME, "test.twodot.done").exists());
+    }
+
+    @Override
+    protected RouteBuilder createRouteBuilder() throws Exception {
+        return new RouteBuilder() {
+            @Override
+            public void configure() throws Exception {
+                from("file:" + TARGET_DIR_NAME + "?doneFileName=$simple{file:name.noext}.done&initialDelay=0").to("mock:result");
+            }
+        };
+    }
+}
diff --git a/camel-core/src/test/java/org/apache/camel/impl/ComponentConfigurationTest.java b/camel-core/src/test/java/org/apache/camel/impl/ComponentConfigurationTest.java
index 4d1a80b3147..b3da6da26ee 100644
--- a/camel-core/src/test/java/org/apache/camel/impl/ComponentConfigurationTest.java
+++ b/camel-core/src/test/java/org/apache/camel/impl/ComponentConfigurationTest.java
@@ -278,7 +278,7 @@ public void testIntrospectSedaEndpointParameters() throws Exception {
 
     /**
      * Shows we can introspect the parameters of a DefaultComponent (i.e. a non {@link UriEndpointComponent})
-     * though we only get to introspect the parameter values from teh current configuration
+     * though we only get to introspect the parameter values from the current configuration
      */
     @Test
     public void testIntrospectDefaultComponentParameters() throws Exception {
diff --git a/camel-core/src/test/java/org/apache/camel/impl/RouteIdRestDefinitionTest.java b/camel-core/src/test/java/org/apache/camel/impl/RouteIdRestDefinitionTest.java
new file mode 100644
index 00000000000..30b132765d9
--- /dev/null
+++ b/camel-core/src/test/java/org/apache/camel/impl/RouteIdRestDefinitionTest.java
@@ -0,0 +1,52 @@
+/**
+ * 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 org.apache.camel.ContextTestSupport;
+import org.apache.camel.builder.RouteBuilder;
+import org.apache.camel.component.rest.DummyRestConsumerFactory;
+import org.apache.camel.component.rest.DummyRestProcessorFactory;
+import org.junit.Test;
+
+public class RouteIdRestDefinitionTest extends ContextTestSupport {
+
+    @Override
+    protected JndiRegistry createRegistry() throws Exception {
+        JndiRegistry jndi = super.createRegistry();
+        jndi.bind("dummy-rest", new DummyRestConsumerFactory());
+        jndi.bind("dummy-rest-api", new DummyRestProcessorFactory());
+        return jndi;
+    }
+
+    @Override
+    protected RouteBuilder createRouteBuilder() throws Exception {
+        return new RouteBuilder() {
+            @Override
+            public void configure() throws Exception {
+                from("direct:start1?timeout=30000").to("mock:result");
+                from("direct:start2").to("mock:result");
+                rest("/say/hello").get("/bar").id("getSayHelloBar").to("mock:result");
+            }
+        };
+    }
+
+    @Test
+    public void testSayHelloBar() {
+        assertEquals("getSayHelloBar", context.getRouteDefinitions().get(2).getId());
+    }
+    
+}
\ No newline at end of file
diff --git a/components/camel-ahc-ws/pom.xml b/components/camel-ahc-ws/pom.xml
index 8b9acef1fb1..d9bacce7a09 100644
--- a/components/camel-ahc-ws/pom.xml
+++ b/components/camel-ahc-ws/pom.xml
@@ -23,7 +23,7 @@
   <parent>
     <groupId>org.apache.camel</groupId>
     <artifactId>components</artifactId>
-    <version>2.23.0-SNAPSHOT</version>
+    <version>2.24.0-SNAPSHOT</version>
   </parent>
 
   <artifactId>camel-ahc-ws</artifactId>
diff --git a/components/camel-ahc-ws/src/main/java/org/apache/camel/component/ahc/ws/WsEndpoint.java b/components/camel-ahc-ws/src/main/java/org/apache/camel/component/ahc/ws/WsEndpoint.java
index c34b6aea1ee..a5f24a2ce46 100644
--- a/components/camel-ahc-ws/src/main/java/org/apache/camel/component/ahc/ws/WsEndpoint.java
+++ b/components/camel-ahc-ws/src/main/java/org/apache/camel/component/ahc/ws/WsEndpoint.java
@@ -23,6 +23,7 @@
 import org.apache.camel.Processor;
 import org.apache.camel.Producer;
 import org.apache.camel.component.ahc.AhcEndpoint;
+import org.apache.camel.spi.ExceptionHandler;
 import org.apache.camel.spi.UriEndpoint;
 import org.apache.camel.spi.UriParam;
 import org.asynchttpclient.AsyncHttpClient;
@@ -68,7 +69,9 @@ public Producer createProducer() throws Exception {
 
     @Override
     public Consumer createConsumer(Processor processor) throws Exception {
-        return new WsConsumer(this, processor);
+        WsConsumer consumer = new WsConsumer(this, processor);
+        configureConsumer(consumer);
+        return consumer;
     }
 
     WebSocket getWebSocket() throws Exception {
@@ -170,6 +173,10 @@ public void onClose(WebSocket websocket, int code, String reason) {
                 reConnect();
             } catch (Exception e) {
                 LOG.warn("Error re-connecting to websocket", e);
+                ExceptionHandler exceptionHandler = getExceptionHandler();
+                if (exceptionHandler != null) {
+                    exceptionHandler.handleException("Error re-connecting to websocket", e);
+                }
             }
         }
 
@@ -199,6 +206,10 @@ public void onTextFrame(String message, boolean finalFragment, int rsv) {
             }
         }
 
+        public void onPingFrame(byte[] payload) {
+            LOG.debug("Received ping --> {}", payload);
+            websocket.sendPongFrame(payload);
+        }
     }
 
 }
diff --git a/components/camel-ahc/pom.xml b/components/camel-ahc/pom.xml
index 47e511d52d4..fa464b89e90 100644
--- a/components/camel-ahc/pom.xml
+++ b/components/camel-ahc/pom.xml
@@ -24,7 +24,7 @@
   <parent>
     <groupId>org.apache.camel</groupId>
     <artifactId>components</artifactId>
-    <version>2.23.0-SNAPSHOT</version>
+    <version>2.24.0-SNAPSHOT</version>
   </parent>
 
   <artifactId>camel-ahc</artifactId>
diff --git a/components/camel-amqp/pom.xml b/components/camel-amqp/pom.xml
index 92b3bf2fd15..351d39a5694 100644
--- a/components/camel-amqp/pom.xml
+++ b/components/camel-amqp/pom.xml
@@ -23,7 +23,7 @@
   <parent>
     <groupId>org.apache.camel</groupId>
     <artifactId>components</artifactId>
-    <version>2.23.0-SNAPSHOT</version>
+    <version>2.24.0-SNAPSHOT</version>
   </parent>
 
   <artifactId>camel-amqp</artifactId>
diff --git a/components/camel-apns/pom.xml b/components/camel-apns/pom.xml
index 46d41011bb9..49466e9801a 100644
--- a/components/camel-apns/pom.xml
+++ b/components/camel-apns/pom.xml
@@ -23,7 +23,7 @@
   <parent>
     <groupId>org.apache.camel</groupId>
     <artifactId>components</artifactId>
-    <version>2.23.0-SNAPSHOT</version>
+    <version>2.24.0-SNAPSHOT</version>
   </parent>
 
   <artifactId>camel-apns</artifactId>
diff --git a/components/camel-as2/camel-as2-api/pom.xml b/components/camel-as2/camel-as2-api/pom.xml
index 342b5110316..5eb6dc8078b 100644
--- a/components/camel-as2/camel-as2-api/pom.xml
+++ b/components/camel-as2/camel-as2-api/pom.xml
@@ -23,7 +23,7 @@
 	<parent>
 		<groupId>org.apache.camel</groupId>
 		<artifactId>camel-as2-parent</artifactId>
-		<version>2.23.0-SNAPSHOT</version>
+		<version>2.24.0-SNAPSHOT</version>
 	</parent>
 
 	<artifactId>camel-as2-api</artifactId>
diff --git a/components/camel-as2/camel-as2-api/src/main/java/org/apache/camel/component/as2/api/AS2ClientManager.java b/components/camel-as2/camel-as2-api/src/main/java/org/apache/camel/component/as2/api/AS2ClientManager.java
index ecd1f7a9cd5..915d210cc5f 100644
--- a/components/camel-as2/camel-as2-api/src/main/java/org/apache/camel/component/as2/api/AS2ClientManager.java
+++ b/components/camel-as2/camel-as2-api/src/main/java/org/apache/camel/component/as2/api/AS2ClientManager.java
@@ -21,9 +21,11 @@
 import java.security.cert.Certificate;
 
 import org.apache.camel.component.as2.api.entity.ApplicationEDIEntity;
-import org.apache.camel.component.as2.api.entity.ApplicationPkcs7MimeEntity;
+import org.apache.camel.component.as2.api.entity.ApplicationPkcs7MimeCompressedDataEntity;
+import org.apache.camel.component.as2.api.entity.ApplicationPkcs7MimeEnvelopedDataEntity;
 import org.apache.camel.component.as2.api.entity.EntityParser;
 import org.apache.camel.component.as2.api.entity.MultipartSignedEntity;
+import org.apache.camel.component.as2.api.util.CompressionUtils;
 import org.apache.camel.component.as2.api.util.EncryptingUtils;
 import org.apache.camel.component.as2.api.util.EntityUtils;
 import org.apache.camel.component.as2.api.util.SigningUtils;
@@ -33,7 +35,9 @@
 import org.apache.http.message.BasicHttpEntityEnclosingRequest;
 import org.apache.http.protocol.HttpCoreContext;
 import org.apache.http.util.Args;
+import org.bouncycastle.cms.CMSCompressedDataGenerator;
 import org.bouncycastle.cms.CMSEnvelopedDataGenerator;
+import org.bouncycastle.operator.OutputCompressor;
 import org.bouncycastle.operator.OutputEncryptor;
 
 /**
@@ -156,6 +160,12 @@
      */
     public static final String ENCRYPTING_PRIVATE_KEY = CAMEL_AS2_CLIENT_PREFIX + "encrypting-private-key";
 
+    /**
+     * The HTTP Context Attribute containing the algorithm used to compress EDI
+     * message
+     */
+    public static final String COMPRESSION_ALGORITHM = CAMEL_AS2_CLIENT_PREFIX + "compression-algorithm-name";
+
     /**
      * The HTTP Context Attribute containing the internet e-mail address of
      * sending system requesting a message disposition notification.
@@ -213,6 +223,7 @@ public HttpCoreContext send(String ediMessage,
                                 AS2SignatureAlgorithm signingAlgorithm,
                                 Certificate[] signingCertificateChain,
                                 PrivateKey signingPrivateKey,
+                                AS2CompressionAlgorithm compressionAlgorithm,
                                 String dispositionNotificationTo,
                                 String[] signedReceiptMicAlgorithms,
                                 AS2EncryptionAlgorithm encryptingAlgorithm,
@@ -238,6 +249,7 @@ public HttpCoreContext send(String ediMessage,
         httpContext.setAttribute(AS2ClientManager.SIGNING_ALGORITHM, signingAlgorithm);
         httpContext.setAttribute(AS2ClientManager.SIGNING_CERTIFICATE_CHAIN, signingCertificateChain);
         httpContext.setAttribute(AS2ClientManager.SIGNING_PRIVATE_KEY, signingPrivateKey);
+        httpContext.setAttribute(AS2ClientManager.COMPRESSION_ALGORITHM, compressionAlgorithm);
         httpContext.setAttribute(AS2ClientManager.DISPOSITION_NOTIFICATION_TO, dispositionNotificationTo);
         httpContext.setAttribute(AS2ClientManager.SIGNED_RECEIPT_MIC_ALGORITHMS, signedReceiptMicAlgorithms);
         httpContext.setAttribute(AS2ClientManager.ENCRYPTING_ALGORITHM, encryptingAlgorithm);
@@ -256,35 +268,112 @@ public HttpCoreContext send(String ediMessage,
         }
         switch (as2MessageStructure) {
         case PLAIN: {
+            // Add EDI Entity to main body of request.
             applicationEDIEntity.setMainBody(true);
             EntityUtils.setMessageEntity(request, applicationEDIEntity);
             break;
         }
         case SIGNED: {
-            AS2SignedDataGenerator gen = createSigningGenerator(httpContext);
-            // Create Multipart Signed Entity
-            MultipartSignedEntity multipartSignedEntity = new MultipartSignedEntity(applicationEDIEntity, gen,
+            // Create Multipart Signed Entity containing EDI Entity
+            AS2SignedDataGenerator signingGenrator = createSigningGenerator(httpContext);
+            MultipartSignedEntity multipartSignedEntity = new MultipartSignedEntity(applicationEDIEntity, signingGenrator,
                     AS2Charset.US_ASCII, AS2TransferEncoding.BASE64, true, null);
-            multipartSignedEntity.setMainBody(true);
+            
+            // Add Multipart Signed Entity to main body of request.
             EntityUtils.setMessageEntity(request, multipartSignedEntity);
             break;
         }
         case ENCRYPTED: {
+            // Create Enveloped Entity containing EDI Entity
             CMSEnvelopedDataGenerator envelopedDataGenerator = createEncryptingGenerator(httpContext);
             OutputEncryptor encryptor = createEncryptor(httpContext);
-            ApplicationPkcs7MimeEntity pkcs7MimeEntity = new ApplicationPkcs7MimeEntity(applicationEDIEntity, envelopedDataGenerator, encryptor, AS2TransferEncoding.BASE64, true);
-            EntityUtils.setMessageEntity(request, pkcs7MimeEntity);
+            ApplicationPkcs7MimeEnvelopedDataEntity pkcs7MimeEnvelopedDataEntity = new ApplicationPkcs7MimeEnvelopedDataEntity(
+                    applicationEDIEntity, envelopedDataGenerator, encryptor, AS2TransferEncoding.BASE64, true);
+
+            // Add Multipart Enveloped Entity to main body of request.
+            EntityUtils.setMessageEntity(request, pkcs7MimeEnvelopedDataEntity);
             break;
         }
-        case ENCRYPTED_SIGNED: {
+        case SIGNED_ENCRYPTED: {
+            // Create Multipart Signed Entity containing EDI Entity
             AS2SignedDataGenerator signingGenrator = createSigningGenerator(httpContext);
             MultipartSignedEntity multipartSignedEntity = new MultipartSignedEntity(applicationEDIEntity,
                     signingGenrator, AS2Charset.US_ASCII, AS2TransferEncoding.BASE64, false, null);
              
+            // Create Enveloped Entity containing Multipart Signed Entity
+            CMSEnvelopedDataGenerator envelopedDataGenerator = createEncryptingGenerator(httpContext);
+            OutputEncryptor encryptor = createEncryptor(httpContext);
+            ApplicationPkcs7MimeEnvelopedDataEntity pkcs7MimeEnvelopedDataEntity = new ApplicationPkcs7MimeEnvelopedDataEntity(
+                    multipartSignedEntity, envelopedDataGenerator, encryptor, AS2TransferEncoding.BASE64, true);
+
+            // Add Multipart Enveloped Entity to main body of request.
+            EntityUtils.setMessageEntity(request, pkcs7MimeEnvelopedDataEntity);
+            break;
+        }
+        case PLAIN_COMPRESSED: {
+            // Create Compressed Entity containing EDI Entity
+            CMSCompressedDataGenerator compressedDataGenerator = createCompressorGenerator(httpContext);
+            OutputCompressor compressor = createCompressor(httpContext);
+            ApplicationPkcs7MimeCompressedDataEntity pkcs7MimeCompressedDataEntity = new ApplicationPkcs7MimeCompressedDataEntity(
+                    applicationEDIEntity, compressedDataGenerator, compressor, AS2TransferEncoding.BASE64, true);
+
+            // Add Compressed Entity to main body of request.
+            EntityUtils.setMessageEntity(request, pkcs7MimeCompressedDataEntity);
+            break;
+        }
+        case SIGNED_COMPRESSED: {
+            // Create Multipart Signed Entity containing EDI Entity
+            AS2SignedDataGenerator signingGenrator = createSigningGenerator(httpContext);
+            MultipartSignedEntity multipartSignedEntity = new MultipartSignedEntity(applicationEDIEntity,
+                    signingGenrator, AS2Charset.US_ASCII, AS2TransferEncoding.BASE64, false, null);
+            
+            // Create Compressed Entity containing Multipart Signed Entity
+            CMSCompressedDataGenerator compressedDataGenerator = createCompressorGenerator(httpContext);
+            OutputCompressor compressor = createCompressor(httpContext);
+            ApplicationPkcs7MimeCompressedDataEntity pkcs7MimeCompressedDataEntity = new ApplicationPkcs7MimeCompressedDataEntity(
+                    multipartSignedEntity, compressedDataGenerator, compressor, AS2TransferEncoding.BASE64, true);
+
+            // Add Compressed Entity to main body of request.
+            EntityUtils.setMessageEntity(request, pkcs7MimeCompressedDataEntity);
+            break;
+        }
+        case ENCRYPTED_COMPRESSED: {
+            // Create Compressed Entity containing EDI Entity
+            CMSCompressedDataGenerator compressedDataGenerator = createCompressorGenerator(httpContext);
+            OutputCompressor compressor = createCompressor(httpContext);
+            ApplicationPkcs7MimeCompressedDataEntity pkcs7MimeCompressedDataEntity = new ApplicationPkcs7MimeCompressedDataEntity(
+                    applicationEDIEntity, compressedDataGenerator, compressor, AS2TransferEncoding.BASE64, false);
+            
+            // Create Enveloped Entity containing Compressed Entity
             CMSEnvelopedDataGenerator envelopedDataGenerator = createEncryptingGenerator(httpContext);
             OutputEncryptor encryptor = createEncryptor(httpContext);
-            ApplicationPkcs7MimeEntity pkcs7MimeEntity = new ApplicationPkcs7MimeEntity(multipartSignedEntity, envelopedDataGenerator, encryptor, AS2TransferEncoding.BASE64, true);
-            EntityUtils.setMessageEntity(request, pkcs7MimeEntity);
+            ApplicationPkcs7MimeEnvelopedDataEntity pkcs7MimeEnvelopedDataEntity = new ApplicationPkcs7MimeEnvelopedDataEntity(
+                    pkcs7MimeCompressedDataEntity, envelopedDataGenerator, encryptor, AS2TransferEncoding.BASE64, true);
+            
+            // Add Enveloped Entity to main body of request
+            EntityUtils.setMessageEntity(request, pkcs7MimeEnvelopedDataEntity);
+            break;
+        }
+        case SIGNED_ENCRYPTED_COMPRESSED: {
+            // Create Multipart Signed Entity containing EDI Entity
+            AS2SignedDataGenerator signingGenrator = createSigningGenerator(httpContext);
+            MultipartSignedEntity multipartSignedEntity = new MultipartSignedEntity(applicationEDIEntity, signingGenrator,
+                    AS2Charset.US_ASCII, AS2TransferEncoding.BASE64, true, null);
+            
+            // Create Compressed Entity containing Multipart Signed Entity
+            CMSCompressedDataGenerator compressedDataGenerator = createCompressorGenerator(httpContext);
+            OutputCompressor compressor = createCompressor(httpContext);
+            ApplicationPkcs7MimeCompressedDataEntity pkcs7MimeCompressedDataEntity = new ApplicationPkcs7MimeCompressedDataEntity(
+                    multipartSignedEntity, compressedDataGenerator, compressor, AS2TransferEncoding.BASE64, false);
+
+            // Create Enveloped Entity containing Compressed Entity
+            CMSEnvelopedDataGenerator envelopedDataGenerator = createEncryptingGenerator(httpContext);
+            OutputEncryptor encryptor = createEncryptor(httpContext);
+            ApplicationPkcs7MimeEnvelopedDataEntity pkcs7MimeEnvelopedDataEntity = new ApplicationPkcs7MimeEnvelopedDataEntity(
+                    pkcs7MimeCompressedDataEntity, envelopedDataGenerator, encryptor, AS2TransferEncoding.BASE64, true);
+            
+            // Add Enveloped Entity to main body of request
+            EntityUtils.setMessageEntity(request, pkcs7MimeEnvelopedDataEntity);
             break;
         }
         default:
@@ -335,6 +424,10 @@ public CMSEnvelopedDataGenerator createEncryptingGenerator(HttpCoreContext httpC
 
     }
     
+    public CMSCompressedDataGenerator createCompressorGenerator(HttpCoreContext httpContext) {
+        return CompressionUtils.createCompressedDataGenerator();
+    }
+    
     public OutputEncryptor createEncryptor(HttpCoreContext httpContext) throws HttpException {
         
         AS2EncryptionAlgorithm encryptionAlgorithm = httpContext.getAttribute(ENCRYPTING_ALGORITHM, AS2EncryptionAlgorithm.class);
@@ -344,5 +437,14 @@ public OutputEncryptor createEncryptor(HttpCoreContext httpContext) throws HttpE
 
         return EncryptingUtils.createEncryptor(encryptionAlgorithm);
     }
+    
+    public OutputCompressor createCompressor(HttpCoreContext httpContext) throws HttpException {
+        AS2CompressionAlgorithm compressionAlgorithm = httpContext.getAttribute(COMPRESSION_ALGORITHM, AS2CompressionAlgorithm.class);
+        if (compressionAlgorithm == null) {
+            throw new HttpException("Compression algorithm missing");
+        }
+        
+        return CompressionUtils.createCompressor(compressionAlgorithm);
+    }
 
 }
diff --git a/components/camel-as2/camel-as2-api/src/main/java/org/apache/camel/component/as2/api/AS2CompressionAlgorithm.java b/components/camel-as2/camel-as2-api/src/main/java/org/apache/camel/component/as2/api/AS2CompressionAlgorithm.java
new file mode 100644
index 00000000000..b08b5ca6f08
--- /dev/null
+++ b/components/camel-as2/camel-as2-api/src/main/java/org/apache/camel/component/as2/api/AS2CompressionAlgorithm.java
@@ -0,0 +1,44 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.camel.component.as2.api;
+
+import org.bouncycastle.asn1.ASN1ObjectIdentifier;
+import org.bouncycastle.cms.jcajce.ZlibCompressor;
+import org.bouncycastle.operator.OutputCompressor;
+
+public enum AS2CompressionAlgorithm {
+    ZLIB(new ZlibCompressor());
+    
+    private OutputCompressor outputCompressor;
+
+    private AS2CompressionAlgorithm(OutputCompressor outputCompressor) {
+        this.outputCompressor = outputCompressor;
+    }
+
+    public String getAlgorithmName() {
+        return this.name();
+    }
+    
+    public ASN1ObjectIdentifier getAlgorithmOID() {
+        return outputCompressor.getAlgorithmIdentifier().getAlgorithm();
+    }
+
+    public OutputCompressor getOutputCompressor() {
+        return outputCompressor;
+    }
+
+}
diff --git a/components/camel-as2/camel-as2-api/src/main/java/org/apache/camel/component/as2/api/AS2MediaType.java b/components/camel-as2/camel-as2-api/src/main/java/org/apache/camel/component/as2/api/AS2MediaType.java
index d6c4934a657..1aa3816dc01 100644
--- a/components/camel-as2/camel-as2-api/src/main/java/org/apache/camel/component/as2/api/AS2MediaType.java
+++ b/components/camel-as2/camel-as2-api/src/main/java/org/apache/camel/component/as2/api/AS2MediaType.java
@@ -27,9 +27,13 @@
      */
     public static final String APPLICATION_PKCS7_SIGNATURE = "application/pkcs7-signature; name=smime.p7s; smime-type=signed-data";
     /**
-     * Media Type for Application PKCS7 Signature
+     * Media Type for Application PKCS7 Enveloped Data
+     */
+    public static final String APPLICATION_PKCS7_MIME_ENVELOPED = "application/pkcs7-mime; smime-type=enveloped-data; name=smime.p7m";
+    /**
+     * Media Type for Application PKCS7 Compressed Data
      */
-    public static final String APPLICATION_PKCS7_MIME = "application/pkcs7-mime; name=smime.p7m; smime-type=enveloped-data; name=smime.p7m";
+    public static final String APPLICATION_PKCS7_MIME_COMPRESSED = "application/pkcs7-mime; smime-type=compressed-data; name=smime.p7z";
     /**
      * Media Type for Text/Plain Data
      */
diff --git a/components/camel-as2/camel-as2-api/src/main/java/org/apache/camel/component/as2/api/AS2MessageStructure.java b/components/camel-as2/camel-as2-api/src/main/java/org/apache/camel/component/as2/api/AS2MessageStructure.java
index 3c8210aa787..760d9f06949 100644
--- a/components/camel-as2/camel-as2-api/src/main/java/org/apache/camel/component/as2/api/AS2MessageStructure.java
+++ b/components/camel-as2/camel-as2-api/src/main/java/org/apache/camel/component/as2/api/AS2MessageStructure.java
@@ -18,9 +18,13 @@
 
 public enum AS2MessageStructure {
     PLAIN(false, false, false),
-    SIGNED(false, false, false),
-    ENCRYPTED(false, false, false),
-    ENCRYPTED_SIGNED(false, false, false);
+    SIGNED(true, false, false),
+    ENCRYPTED(false, true, false),
+    SIGNED_ENCRYPTED(true, true, false),
+    PLAIN_COMPRESSED(false, false, true),
+    SIGNED_COMPRESSED(true, false, true),
+    ENCRYPTED_COMPRESSED(false, true, true),
+    SIGNED_ENCRYPTED_COMPRESSED(true, true, true);
 
     private final boolean isSigned;
     private final boolean isEncrypted;
diff --git a/components/camel-as2/camel-as2-api/src/main/java/org/apache/camel/component/as2/api/entity/ApplicationPkcs7MimeCompressedDataEntity.java b/components/camel-as2/camel-as2-api/src/main/java/org/apache/camel/component/as2/api/entity/ApplicationPkcs7MimeCompressedDataEntity.java
new file mode 100644
index 00000000000..16402e48294
--- /dev/null
+++ b/components/camel-as2/camel-as2-api/src/main/java/org/apache/camel/component/as2/api/entity/ApplicationPkcs7MimeCompressedDataEntity.java
@@ -0,0 +1,120 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.camel.component.as2.api.entity;
+
+import java.io.ByteArrayOutputStream;
+import java.io.IOException;
+import java.io.OutputStream;
+
+import org.apache.camel.component.as2.api.AS2Charset;
+import org.apache.camel.component.as2.api.AS2Header;
+import org.apache.camel.component.as2.api.CanonicalOutputStream;
+import org.apache.camel.component.as2.api.util.EntityUtils;
+import org.apache.http.Header;
+import org.apache.http.HeaderIterator;
+import org.apache.http.HttpException;
+import org.apache.http.entity.ContentType;
+import org.apache.http.message.BasicNameValuePair;
+import org.apache.http.util.Args;
+import org.bouncycastle.cms.CMSCompressedData;
+import org.bouncycastle.cms.CMSCompressedDataGenerator;
+import org.bouncycastle.cms.CMSProcessableByteArray;
+import org.bouncycastle.cms.CMSTypedData;
+import org.bouncycastle.operator.InputExpanderProvider;
+import org.bouncycastle.operator.OutputCompressor;
+
+public class ApplicationPkcs7MimeCompressedDataEntity extends MimeEntity {
+    
+    private static final String CONTENT_DISPOSITION = "attachment; filename=\"smime.p7z\"";
+    
+    private byte[] compressedData;
+    
+    public ApplicationPkcs7MimeCompressedDataEntity(MimeEntity entity2Encrypt,
+                                                    CMSCompressedDataGenerator dataGenerator,
+                                                    OutputCompressor compressor,
+                                                    String compressedContentTransferEncoding,
+                                                    boolean isMainBody)
+            throws HttpException {
+        setContentType(ContentType.create("application/pkcs7-mime", new BasicNameValuePair("smime-type", "compressed-data"),
+                new BasicNameValuePair("name", "smime.p7z")));
+        setContentTransferEncoding(compressedContentTransferEncoding);
+        addHeader(AS2Header.CONTENT_DISPOSITION, CONTENT_DISPOSITION);
+        setMainBody(isMainBody);
+        try {
+            this.compressedData = createCompressedData(entity2Encrypt, dataGenerator, compressor);
+        } catch (Exception e) {
+            throw new HttpException("Failed to create encrypted data");
+        }
+    }
+    
+    public ApplicationPkcs7MimeCompressedDataEntity(byte[] compressedData, String compressedContentTransferEncoding, boolean isMainBody) {
+        this.compressedData = Args.notNull(compressedData, "encryptedData");
+        
+        setContentType(ContentType.create("application/pkcs7-mime", new BasicNameValuePair("smime-type", "compressed-data"),
+                new BasicNameValuePair("name", "smime.p7z")));
+        setContentTransferEncoding(compressedContentTransferEncoding);
+        addHeader(AS2Header.CONTENT_DISPOSITION, CONTENT_DISPOSITION);
+        setMainBody(isMainBody);
+    }
+    
+    @Override
+    public void writeTo(OutputStream outstream) throws IOException {
+        NoCloseOutputStream ncos = new NoCloseOutputStream(outstream);
+
+        // Write out mime part headers if this is not the main body of message.
+        if (!isMainBody()) {
+            try (CanonicalOutputStream canonicalOutstream = new CanonicalOutputStream(ncos, AS2Charset.US_ASCII)) {
+
+                HeaderIterator it = headerIterator();
+                while (it.hasNext()) {
+                    Header header = it.nextHeader();
+                    canonicalOutstream.writeln(header.toString());
+                }
+                canonicalOutstream.writeln(); // ensure empty line between
+                                              // headers and body; RFC2046 -
+                                              // 5.1.1
+            }
+        }
+        
+        // Write out signed data.
+        String transferEncoding = getContentTransferEncoding() == null ? null : getContentTransferEncoding().getValue();
+        try (OutputStream transferEncodedStream = EntityUtils.encode(ncos, transferEncoding)) {
+
+            transferEncodedStream.write(compressedData);
+        } catch (Exception e) {
+            throw new IOException("Failed to write to output stream", e);
+        }
+    }
+    
+    public MimeEntity getCompressedEntity(InputExpanderProvider expanderProvider) throws HttpException {
+        return EntityParser.parseCompressedEntity(compressedData, expanderProvider);
+    }
+    
+    private byte[] createCompressedData(MimeEntity entity2Encrypt, CMSCompressedDataGenerator compressedDataGenerator, OutputCompressor compressor) throws Exception {
+        try (ByteArrayOutputStream bos = new ByteArrayOutputStream()) {
+            entity2Encrypt.writeTo(bos);
+            bos.flush();
+
+            CMSTypedData contentData = new CMSProcessableByteArray(bos.toByteArray());
+            CMSCompressedData  compressedData = compressedDataGenerator.generate(contentData, compressor);
+            return compressedData.getEncoded();
+        } catch (Exception e) {
+            throw new Exception("", e);
+        }
+    }
+
+}
diff --git a/components/camel-as2/camel-as2-api/src/main/java/org/apache/camel/component/as2/api/entity/ApplicationPkcs7MimeEntity.java b/components/camel-as2/camel-as2-api/src/main/java/org/apache/camel/component/as2/api/entity/ApplicationPkcs7MimeEnvelopedDataEntity.java
similarity index 93%
rename from components/camel-as2/camel-as2-api/src/main/java/org/apache/camel/component/as2/api/entity/ApplicationPkcs7MimeEntity.java
rename to components/camel-as2/camel-as2-api/src/main/java/org/apache/camel/component/as2/api/entity/ApplicationPkcs7MimeEnvelopedDataEntity.java
index c1d6952f413..d6a9be603de 100644
--- a/components/camel-as2/camel-as2-api/src/main/java/org/apache/camel/component/as2/api/entity/ApplicationPkcs7MimeEntity.java
+++ b/components/camel-as2/camel-as2-api/src/main/java/org/apache/camel/component/as2/api/entity/ApplicationPkcs7MimeEnvelopedDataEntity.java
@@ -37,13 +37,13 @@
 import org.bouncycastle.cms.CMSTypedData;
 import org.bouncycastle.operator.OutputEncryptor;
 
-public class ApplicationPkcs7MimeEntity extends MimeEntity {
+public class ApplicationPkcs7MimeEnvelopedDataEntity extends MimeEntity {
     
     private static final String CONTENT_DISPOSITION = "attachment; filename=\"smime.p7m\"";
     
     private byte[] encryptedData;
     
-    public ApplicationPkcs7MimeEntity(MimeEntity entity2Encrypt,
+    public ApplicationPkcs7MimeEnvelopedDataEntity(MimeEntity entity2Encrypt,
                                 CMSEnvelopedDataGenerator dataGenerator,
                                 OutputEncryptor encryptor,
                                 String encryptedContentTransferEncoding,
@@ -61,10 +61,10 @@ public ApplicationPkcs7MimeEntity(MimeEntity entity2Encrypt,
         }
     }
     
-    public ApplicationPkcs7MimeEntity(byte[] encryptedData, String encryptedContentTransferEncoding, boolean isMainBody) {
+    public ApplicationPkcs7MimeEnvelopedDataEntity(byte[] encryptedData, String encryptedContentTransferEncoding, boolean isMainBody) {
         this.encryptedData = Args.notNull(encryptedData, "encryptedData");
         
-        setContentType(ContentType.create("application/pkcs7-mime", new BasicNameValuePair("smime-type", "enveloped-datat"),
+        setContentType(ContentType.create("application/pkcs7-mime", new BasicNameValuePair("smime-type", "enveloped-data"),
                 new BasicNameValuePair("name", "smime.p7m")));
         setContentTransferEncoding(encryptedContentTransferEncoding);
         addHeader(AS2Header.CONTENT_DISPOSITION, CONTENT_DISPOSITION);
@@ -100,11 +100,8 @@ public void writeTo(OutputStream outstream) throws IOException {
         }
     }
     
-    public MimeEntity getEncryptedEntity(PrivateKey privateKey) {
-        
+    public MimeEntity getEncryptedEntity(PrivateKey privateKey) throws HttpException {
         return EntityParser.parseEnvelopedEntity(encryptedData, privateKey);
-        
-        
     }
     
     private byte[] createEncryptedData(MimeEntity entity2Encrypt, CMSEnvelopedDataGenerator envelopedDataGenerator, OutputEncryptor encryptor) throws Exception {
diff --git a/components/camel-as2/camel-as2-api/src/main/java/org/apache/camel/component/as2/api/entity/EntityParser.java b/components/camel-as2/camel-as2-api/src/main/java/org/apache/camel/component/as2/api/entity/EntityParser.java
index aaf12e86c8a..42a4b1bbbdc 100644
--- a/components/camel-as2/camel-as2-api/src/main/java/org/apache/camel/component/as2/api/entity/EntityParser.java
+++ b/components/camel-as2/camel-as2-api/src/main/java/org/apache/camel/component/as2/api/entity/EntityParser.java
@@ -51,11 +51,14 @@
 import org.apache.http.message.ParserCursor;
 import org.apache.http.util.Args;
 import org.apache.http.util.CharArrayBuffer;
+import org.bouncycastle.cms.CMSCompressedData;
 import org.bouncycastle.cms.CMSEnvelopedData;
+import org.bouncycastle.cms.CMSException;
 import org.bouncycastle.cms.Recipient;
 import org.bouncycastle.cms.RecipientInformation;
 import org.bouncycastle.cms.RecipientInformationStore;
 import org.bouncycastle.cms.jcajce.JceKeyTransEnvelopedRecipient;
+import org.bouncycastle.operator.InputExpanderProvider;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
@@ -177,12 +180,26 @@ public static void skipToBoundary(AS2SessionInputBuffer inbuffer, String boundar
 
     }
     
-    public static MimeEntity parseEnvelopedEntity(byte[] envelopedContent, PrivateKey privateKey) {
+    public static MimeEntity parseCompressedEntity(byte[] compressedData, InputExpanderProvider expanderProvider)
+            throws HttpException {
+
+        byte[] uncompressedContent = uncompressData(compressedData, expanderProvider);
+
+        return parseEntity(uncompressedContent);
+    }
+
+    public static MimeEntity parseEnvelopedEntity(byte[] envelopedContent, PrivateKey privateKey) throws HttpException {
+
+        byte[] decryptedContent = decryptData(envelopedContent, privateKey);
+
+        return parseEntity(decryptedContent);
+    }
+
+    public static MimeEntity parseEntity(byte[] content) throws HttpException {
         
         try {
-            byte[] decryptedContent = decryptData(envelopedContent, privateKey);
             
-            InputStream is = new ByteArrayInputStream(decryptedContent);
+            InputStream is = new ByteArrayInputStream(content);
             AS2SessionInputBuffer inbuffer = new AS2SessionInputBuffer(new HttpTransportMetricsImpl(), DEFAULT_BUFFER_SIZE);
             inbuffer.bind(is);
 
@@ -191,54 +208,68 @@ public static MimeEntity parseEnvelopedEntity(byte[] envelopedContent, PrivateKe
                     new ArrayList<CharArrayBuffer>());
 
             // Get Content-Type and Content-Transfer-Encoding
-            ContentType envelopedEntityContentType = null;
-            String envelopedEntityContentTransferEncoding = null;
+            ContentType entityContentType = null;
+            String entityContentTransferEncoding = null;
             for (Header header : headers) {
                 switch (header.getName()) {
                 case AS2Header.CONTENT_TYPE:
-                    envelopedEntityContentType = ContentType.parse(header.getValue());
+                    entityContentType = ContentType.parse(header.getValue());
                     break;
                 case AS2Header.CONTENT_TRANSFER_ENCODING:
-                    envelopedEntityContentTransferEncoding = header.getValue();
+                    entityContentTransferEncoding = header.getValue();
                     break;
                 default:
                     continue;
                 }
             }
-            if (envelopedEntityContentType == null) {
+            if (entityContentType == null) {
                 throw new HttpException("Failed to find Content-Type header in enveloped entity");
             }
 
-            MimeEntity entity = parseEntityBody(inbuffer, null, envelopedEntityContentType, envelopedEntityContentTransferEncoding, headers);
+            MimeEntity entity = parseEntityBody(inbuffer, null, entityContentType, entityContentTransferEncoding, headers);
             entity.removeAllHeaders();
             entity.setHeaders(headers);
             
             return entity;
         } catch (Exception e) {
-            return null;
+            throw new HttpException("Failed to parse entity", e);
         }
     }
 
-    public static byte[] decryptData(byte[] encryptedData, PrivateKey privateKey) throws Exception {
-        // Create enveloped data from encrypted data
-        CMSEnvelopedData cmsEnvelopedData = new CMSEnvelopedData(encryptedData);
-        
-        // Extract recipient information form enveloped data.
-        RecipientInformationStore recipientsInformationStore = cmsEnvelopedData.getRecipientInfos();
-        Collection<RecipientInformation> recipients = recipientsInformationStore.getRecipients();
-        Iterator<RecipientInformation> it = recipients.iterator();
-        
-        // Decrypt if enveloped data contains recipient information
-        if (it.hasNext()) {
-            // Create recipient from private key.
-            Recipient recipient = new JceKeyTransEnvelopedRecipient(privateKey);
-
-            // Extract decrypted data from recipient information
-            RecipientInformation recipientInfo = it.next();
-            return recipientInfo.getContent(recipient);
+    public static byte[] uncompressData(byte[] compressedData, InputExpanderProvider expanderProvider)
+            throws HttpException {
+        try {
+            CMSCompressedData cmsCompressedData = new CMSCompressedData(compressedData);
+            return cmsCompressedData.getContent(expanderProvider);
+        } catch (CMSException e) {
+            throw new HttpException("Failed to decompress data", e);
+        }
+    }
+
+    public static byte[] decryptData(byte[] encryptedData, PrivateKey privateKey) throws HttpException {
+        try {
+            // Create enveloped data from encrypted data
+            CMSEnvelopedData cmsEnvelopedData = new CMSEnvelopedData(encryptedData);
+            
+            // Extract recipient information form enveloped data.
+            RecipientInformationStore recipientsInformationStore = cmsEnvelopedData.getRecipientInfos();
+            Collection<RecipientInformation> recipients = recipientsInformationStore.getRecipients();
+            Iterator<RecipientInformation> it = recipients.iterator();
+            
+            // Decrypt if enveloped data contains recipient information
+            if (it.hasNext()) {
+                // Create recipient from private key.
+                Recipient recipient = new JceKeyTransEnvelopedRecipient(privateKey);
+
+                // Extract decrypted data from recipient information
+                RecipientInformation recipientInfo = it.next();
+                return recipientInfo.getContent(recipient);
+            }
+        } catch (CMSException e) {
+            throw new HttpException("Failed to decrypt data", e);
         }
         
-        return null;
+        throw new HttpException("Failed to decrypt data: bno recipeint information");
     }
     
     public static void parseMultipartSignedEntity(HttpMessage message)
@@ -769,6 +800,20 @@ public static MimeEntity parseEntityBody(AS2SessionInputBuffer inbuffer,
                 entity = parseApplicationPkcs7SignatureEntityBody(inbuffer, boundary, entityContentType,
                         contentTransferEncoding);
                 break;
+            case AS2MimeType.APPLICATION_PKCS7_MIME:
+                switch(entityContentType.getParameter("smime-type")) {
+                case "compressed-data":
+                    entity = parseApplicationPkcs7MimeCompressedDataEntityBody(inbuffer, boundary, entityContentType,
+                            contentTransferEncoding);
+                    break;
+                case "enveloped-data":
+                    entity = parseApplicationPkcs7MimeEnvelopedDataEntityBody(inbuffer, boundary, entityContentType,
+                            contentTransferEncoding);
+                    break;
+                default:
+                    break;
+                }
+                break;
             default:
                 break;
             }
@@ -851,7 +896,7 @@ public static ApplicationPkcs7SignatureEntity parseApplicationPkcs7SignatureEnti
         }
     }
 
-    public static ApplicationPkcs7MimeEntity parseApplicationPkcs7MimeEntityBody(AS2SessionInputBuffer inbuffer,
+    public static ApplicationPkcs7MimeEnvelopedDataEntity parseApplicationPkcs7MimeEnvelopedDataEntityBody(AS2SessionInputBuffer inbuffer,
                                                                                       String boundary,
                                                                                       ContentType contentType,
                                                                                       String contentTransferEncoding)
@@ -872,7 +917,7 @@ public static ApplicationPkcs7MimeEntity parseApplicationPkcs7MimeEntityBody(AS2
 
             byte[] encryptedContent = EntityUtils.decode(pkcs7EncryptedBodyContent.getBytes(charset), contentTransferEncoding);
 
-            ApplicationPkcs7MimeEntity applicationPkcs7MimeEntity = new ApplicationPkcs7MimeEntity(
+            ApplicationPkcs7MimeEnvelopedDataEntity applicationPkcs7MimeEntity = new ApplicationPkcs7MimeEnvelopedDataEntity(
                     encryptedContent, contentTransferEncoding, false);
             return applicationPkcs7MimeEntity;
         } catch (Exception e) {
@@ -884,6 +929,40 @@ public static ApplicationPkcs7MimeEntity parseApplicationPkcs7MimeEntityBody(AS2
         }
     }
 
+    public static ApplicationPkcs7MimeCompressedDataEntity parseApplicationPkcs7MimeCompressedDataEntityBody(AS2SessionInputBuffer inbuffer,
+                                                                                                           String boundary,
+                                                                                                           ContentType contentType,
+                                                                                                           String contentTransferEncoding)
+            throws ParseException {
+
+        CharsetDecoder previousDecoder = inbuffer.getCharsetDecoder();
+
+        try {
+            Charset charset = contentType.getCharset();
+            if (charset == null) {
+                charset = Charset.forName(AS2Charset.US_ASCII);
+            }
+            CharsetDecoder charsetDecoder = charset.newDecoder();
+
+            inbuffer.setCharsetDecoder(charsetDecoder);
+
+            String pkcs7CompressedBodyContent = parseBodyPartText(inbuffer, boundary);
+
+            byte[] compressedContent = EntityUtils.decode(pkcs7CompressedBodyContent.getBytes(charset),
+                    contentTransferEncoding);
+
+            ApplicationPkcs7MimeCompressedDataEntity applicationPkcs7MimeEntity = new ApplicationPkcs7MimeCompressedDataEntity(
+                    compressedContent, contentTransferEncoding, false);
+            return applicationPkcs7MimeEntity;
+        } catch (Exception e) {
+            ParseException parseException = new ParseException("failed to parse PKCS7 Mime entity");
+            parseException.initCause(e);
+            throw parseException;
+        } finally {
+            inbuffer.setCharsetDecoder(previousDecoder);
+        }
+    }
+
     public static String parseBodyPartText(final AS2SessionInputBuffer inbuffer,
                                            final String boundary)
             throws IOException {
diff --git a/components/camel-as2/camel-as2-api/src/main/java/org/apache/camel/component/as2/api/util/CompressionUtils.java b/components/camel-as2/camel-as2-api/src/main/java/org/apache/camel/component/as2/api/util/CompressionUtils.java
new file mode 100644
index 00000000000..89e243f4c13
--- /dev/null
+++ b/components/camel-as2/camel-as2-api/src/main/java/org/apache/camel/component/as2/api/util/CompressionUtils.java
@@ -0,0 +1,36 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.camel.component.as2.api.util;
+
+import org.apache.camel.component.as2.api.AS2CompressionAlgorithm;
+import org.bouncycastle.cms.CMSCompressedDataGenerator;
+import org.bouncycastle.operator.OutputCompressor;
+
+public final class CompressionUtils {
+    
+    private CompressionUtils() {
+    }
+    
+    public static CMSCompressedDataGenerator createCompressedDataGenerator() {
+        return new CMSCompressedDataGenerator();
+    }
+    
+    public static OutputCompressor createCompressor(AS2CompressionAlgorithm compressionAlgorithm) {
+        return compressionAlgorithm.getOutputCompressor();
+    }
+
+}
diff --git a/components/camel-as2/camel-as2-api/src/test/java/org/apache/camel/component/as2/api/AS2MessageTest.java b/components/camel-as2/camel-as2-api/src/test/java/org/apache/camel/component/as2/api/AS2MessageTest.java
index 3cdd384f9d5..5b9dc3e7523 100644
--- a/components/camel-as2/camel-as2-api/src/test/java/org/apache/camel/component/as2/api/AS2MessageTest.java
+++ b/components/camel-as2/camel-as2-api/src/test/java/org/apache/camel/component/as2/api/AS2MessageTest.java
@@ -32,7 +32,8 @@
 import org.apache.camel.component.as2.api.entity.AS2MessageDispositionNotificationEntity;
 import org.apache.camel.component.as2.api.entity.ApplicationEDIEntity;
 import org.apache.camel.component.as2.api.entity.ApplicationEDIFACTEntity;
-import org.apache.camel.component.as2.api.entity.ApplicationPkcs7MimeEntity;
+import org.apache.camel.component.as2.api.entity.ApplicationPkcs7MimeCompressedDataEntity;
+import org.apache.camel.component.as2.api.entity.ApplicationPkcs7MimeEnvelopedDataEntity;
 import org.apache.camel.component.as2.api.entity.ApplicationPkcs7SignatureEntity;
 import org.apache.camel.component.as2.api.entity.DispositionMode;
 import org.apache.camel.component.as2.api.entity.DispositionNotificationMultipartReportEntity;
@@ -70,6 +71,7 @@
 import org.bouncycastle.asn1.x500.X500Name;
 import org.bouncycastle.cert.jcajce.JcaCertStore;
 import org.bouncycastle.cms.jcajce.JcaSimpleSignerInfoGeneratorBuilder;
+import org.bouncycastle.cms.jcajce.ZlibExpanderProvider;
 import org.bouncycastle.jce.provider.BouncyCastleProvider;
 import org.junit.AfterClass;
 import org.junit.Before;
@@ -270,7 +272,7 @@ public void plainEDIMessageTest() throws Exception {
 
         HttpCoreContext httpContext = clientManager.send(EDI_MESSAGE, REQUEST_URI, SUBJECT, FROM, AS2_NAME, AS2_NAME,
                 AS2MessageStructure.PLAIN, ContentType.create(AS2MediaType.APPLICATION_EDIFACT, AS2Charset.US_ASCII),
-                null, null, null, null, DISPOSITION_NOTIFICATION_TO, SIGNED_RECEIPT_MIC_ALGORITHMS, null, null, null);
+                null, null, null, null, null, DISPOSITION_NOTIFICATION_TO, SIGNED_RECEIPT_MIC_ALGORITHMS, null, null, null);
 
         HttpRequest request = httpContext.getRequest();
         assertEquals("Unexpected method value", METHOD, request.getRequestLine().getMethod());
@@ -313,8 +315,8 @@ public void multipartSignedMessageTest() throws Exception {
 
         HttpCoreContext httpContext = clientManager.send(EDI_MESSAGE, REQUEST_URI, SUBJECT, FROM, AS2_NAME, AS2_NAME,
                 AS2MessageStructure.SIGNED, ContentType.create(AS2MediaType.APPLICATION_EDIFACT, AS2Charset.US_ASCII),
-                null, AS2SignatureAlgorithm.SHA256WITHRSA, certList.toArray(new Certificate[0]), signingKP.getPrivate(), DISPOSITION_NOTIFICATION_TO,
-                SIGNED_RECEIPT_MIC_ALGORITHMS, null, null, null);
+                null, AS2SignatureAlgorithm.SHA256WITHRSA, certList.toArray(new Certificate[0]), signingKP.getPrivate(),
+                null, DISPOSITION_NOTIFICATION_TO, SIGNED_RECEIPT_MIC_ALGORITHMS, null, null, null);
 
         HttpRequest request = httpContext.getRequest();
         assertEquals("Unexpected method value", METHOD, request.getRequestLine().getMethod());
@@ -472,10 +474,11 @@ public void envelopedMessageTest(AS2EncryptionAlgorithm encryptionAlgorithm) thr
         LOG.info("Key Algoritm: " + signingKP.getPrivate().getAlgorithm());
 
         HttpCoreContext httpContext = clientManager.send(EDI_MESSAGE, REQUEST_URI, SUBJECT, FROM, AS2_NAME, AS2_NAME,
-                AS2MessageStructure.ENCRYPTED, ContentType.create(AS2MediaType.APPLICATION_EDIFACT, AS2Charset.US_ASCII),
-                null, AS2SignatureAlgorithm.SHA256WITHRSA, certList.toArray(new Certificate[0]), signingKP.getPrivate(), DISPOSITION_NOTIFICATION_TO,
-                SIGNED_RECEIPT_MIC_ALGORITHMS, encryptionAlgorithm, certList.toArray(new Certificate[0]),
-                signingKP.getPrivate());
+                AS2MessageStructure.ENCRYPTED,
+                ContentType.create(AS2MediaType.APPLICATION_EDIFACT, AS2Charset.US_ASCII), null,
+                AS2SignatureAlgorithm.SHA256WITHRSA, certList.toArray(new Certificate[0]), signingKP.getPrivate(), null,
+                DISPOSITION_NOTIFICATION_TO, SIGNED_RECEIPT_MIC_ALGORITHMS, encryptionAlgorithm,
+                certList.toArray(new Certificate[0]), signingKP.getPrivate());
 
         HttpRequest request = httpContext.getRequest();
         assertEquals("Unexpected method value", METHOD, request.getRequestLine().getMethod());
@@ -503,8 +506,8 @@ public void envelopedMessageTest(AS2EncryptionAlgorithm encryptionAlgorithm) thr
         assertTrue("Request does not contain entity", request instanceof BasicHttpEntityEnclosingRequest);
         HttpEntity entity = ((BasicHttpEntityEnclosingRequest) request).getEntity();
         assertNotNull("Request does not contain entity", entity);
-        assertTrue("Unexpected request entity type", entity instanceof ApplicationPkcs7MimeEntity);
-        ApplicationPkcs7MimeEntity envelopedEntity = (ApplicationPkcs7MimeEntity) entity;
+        assertTrue("Unexpected request entity type", entity instanceof ApplicationPkcs7MimeEnvelopedDataEntity);
+        ApplicationPkcs7MimeEnvelopedDataEntity envelopedEntity = (ApplicationPkcs7MimeEnvelopedDataEntity) entity;
         assertTrue("Entity not set as main body of request", envelopedEntity.isMainBody());
 
         // Validated enveloped part.
@@ -532,10 +535,11 @@ public void envelopedAndSignedMessageTest(AS2EncryptionAlgorithm encryptionAlgor
         LOG.info("Key Algoritm: " + signingKP.getPrivate().getAlgorithm());
 
         HttpCoreContext httpContext = clientManager.send(EDI_MESSAGE, REQUEST_URI, SUBJECT, FROM, AS2_NAME, AS2_NAME,
-                AS2MessageStructure.ENCRYPTED_SIGNED, ContentType.create(AS2MediaType.APPLICATION_EDIFACT, AS2Charset.US_ASCII),
-                null, AS2SignatureAlgorithm.SHA256WITHRSA, certList.toArray(new Certificate[0]), signingKP.getPrivate(), DISPOSITION_NOTIFICATION_TO,
-                SIGNED_RECEIPT_MIC_ALGORITHMS, encryptionAlgorithm, certList.toArray(new Certificate[0]),
-                signingKP.getPrivate());
+                AS2MessageStructure.SIGNED_ENCRYPTED,
+                ContentType.create(AS2MediaType.APPLICATION_EDIFACT, AS2Charset.US_ASCII), null,
+                AS2SignatureAlgorithm.SHA256WITHRSA, certList.toArray(new Certificate[0]), signingKP.getPrivate(), null,
+                DISPOSITION_NOTIFICATION_TO, SIGNED_RECEIPT_MIC_ALGORITHMS, encryptionAlgorithm,
+                certList.toArray(new Certificate[0]), signingKP.getPrivate());
 
         HttpRequest request = httpContext.getRequest();
         assertEquals("Unexpected method value", METHOD, request.getRequestLine().getMethod());
@@ -563,8 +567,8 @@ public void envelopedAndSignedMessageTest(AS2EncryptionAlgorithm encryptionAlgor
         assertTrue("Request does not contain entity", request instanceof BasicHttpEntityEnclosingRequest);
         HttpEntity entity = ((BasicHttpEntityEnclosingRequest) request).getEntity();
         assertNotNull("Request does not contain entity", entity);
-        assertTrue("Unexpected request entity type", entity instanceof ApplicationPkcs7MimeEntity);
-        ApplicationPkcs7MimeEntity envelopedEntity = (ApplicationPkcs7MimeEntity) entity;
+        assertTrue("Unexpected request entity type", entity instanceof ApplicationPkcs7MimeEnvelopedDataEntity);
+        ApplicationPkcs7MimeEnvelopedDataEntity envelopedEntity = (ApplicationPkcs7MimeEnvelopedDataEntity) entity;
         assertTrue("Entity not set as main body of request", envelopedEntity.isMainBody());
 
         // Validated enveloped part.
@@ -601,8 +605,8 @@ public void signatureVerificationTest() throws Exception {
 
         HttpCoreContext httpContext = clientManager.send(EDI_MESSAGE, REQUEST_URI, SUBJECT, FROM, AS2_NAME, AS2_NAME,
                 AS2MessageStructure.SIGNED, ContentType.create(AS2MediaType.APPLICATION_EDIFACT, AS2Charset.US_ASCII),
-                null, AS2SignatureAlgorithm.SHA256WITHRSA, certList.toArray(new Certificate[0]), signingKP.getPrivate(), DISPOSITION_NOTIFICATION_TO,
-                SIGNED_RECEIPT_MIC_ALGORITHMS, null, null, null);
+                null, AS2SignatureAlgorithm.SHA256WITHRSA, certList.toArray(new Certificate[0]), signingKP.getPrivate(),
+                null, DISPOSITION_NOTIFICATION_TO, SIGNED_RECEIPT_MIC_ALGORITHMS, null, null, null);
 
         HttpRequest request = httpContext.getRequest();
         assertTrue("Request does not contain entity", request instanceof BasicHttpEntityEnclosingRequest);
@@ -630,7 +634,8 @@ public void mdnMessageTest() throws Exception {
 
         HttpCoreContext httpContext = clientManager.send(EDI_MESSAGE, REQUEST_URI, SUBJECT, FROM, AS2_NAME, AS2_NAME,
                 AS2MessageStructure.PLAIN, ContentType.create(AS2MediaType.APPLICATION_EDIFACT, AS2Charset.US_ASCII),
-                null, null, null, null, DISPOSITION_NOTIFICATION_TO, SIGNED_RECEIPT_MIC_ALGORITHMS, null, null, null);
+                null, null, null, null, null, DISPOSITION_NOTIFICATION_TO, SIGNED_RECEIPT_MIC_ALGORITHMS, null, null,
+                null);
 
         HttpResponse response = httpContext.getResponse();
         assertEquals("Unexpected method value", HttpVersion.HTTP_1_1, response.getStatusLine().getProtocolVersion());
@@ -732,5 +737,198 @@ public void asynchronousMdnMessageTest() throws Exception {
                 mdnMic.getEncodedMessageDigest());
         LOG.debug("\r\n" + AS2Utils.printMessage(mndRequest));
     }
+    
+    @Test
+    public void compressedMessageTest() throws Exception {
+        AS2ClientConnection clientConnection = new AS2ClientConnection(AS2_VERSION, USER_AGENT, CLIENT_FQDN,
+                TARGET_HOST, TARGET_PORT);
+        AS2ClientManager clientManager = new AS2ClientManager(clientConnection);
+        
+        LOG.info("Key Algoritm: " + signingKP.getPrivate().getAlgorithm());
+
+        HttpCoreContext httpContext = clientManager.send(EDI_MESSAGE, REQUEST_URI, SUBJECT, FROM, AS2_NAME, AS2_NAME,
+                AS2MessageStructure.PLAIN_COMPRESSED,
+                ContentType.create(AS2MediaType.APPLICATION_EDIFACT, AS2Charset.US_ASCII), null,
+                null, null, null, AS2CompressionAlgorithm.ZLIB,
+                DISPOSITION_NOTIFICATION_TO, SIGNED_RECEIPT_MIC_ALGORITHMS, null,
+                null, null);
+
+        HttpRequest request = httpContext.getRequest();
+        assertEquals("Unexpected method value", METHOD, request.getRequestLine().getMethod());
+        assertEquals("Unexpected request URI value", REQUEST_URI, request.getRequestLine().getUri());
+        assertEquals("Unexpected HTTP version value", HttpVersion.HTTP_1_1,
+                request.getRequestLine().getProtocolVersion());
+
+        assertEquals("Unexpected subject value", SUBJECT, request.getFirstHeader(AS2Header.SUBJECT).getValue());
+        assertEquals("Unexpected from value", FROM, request.getFirstHeader(AS2Header.FROM).getValue());
+        assertEquals("Unexpected AS2 version value", AS2_VERSION,
+                request.getFirstHeader(AS2Header.AS2_VERSION).getValue());
+        assertEquals("Unexpected AS2 from value", AS2_NAME, request.getFirstHeader(AS2Header.AS2_FROM).getValue());
+        assertEquals("Unexpected AS2 to value", AS2_NAME, request.getFirstHeader(AS2Header.AS2_TO).getValue());
+        assertTrue("Unexpected message id value",
+                request.getFirstHeader(AS2Header.MESSAGE_ID).getValue().endsWith(CLIENT_FQDN + ">"));
+        assertEquals("Unexpected target host value", TARGET_HOST + ":" + TARGET_PORT,
+                request.getFirstHeader(AS2Header.TARGET_HOST).getValue());
+        assertEquals("Unexpected user agent value", USER_AGENT,
+                request.getFirstHeader(AS2Header.USER_AGENT).getValue());
+        assertNotNull("Date value missing", request.getFirstHeader(AS2Header.DATE));
+        assertNotNull("Content length value missing", request.getFirstHeader(AS2Header.CONTENT_LENGTH));
+        assertTrue("Unexpected content type for message",
+                request.getFirstHeader(AS2Header.CONTENT_TYPE).getValue().startsWith(AS2MimeType.APPLICATION_PKCS7_MIME));
+
+        assertTrue("Request does not contain entity", request instanceof BasicHttpEntityEnclosingRequest);
+        HttpEntity entity = ((BasicHttpEntityEnclosingRequest) request).getEntity();
+        assertNotNull("Request does not contain entity", entity);
+        assertTrue("Unexpected request entity type", entity instanceof ApplicationPkcs7MimeCompressedDataEntity);
+        ApplicationPkcs7MimeCompressedDataEntity compressedDataEntity = (ApplicationPkcs7MimeCompressedDataEntity) entity;
+        assertTrue("Entity not set as main body of request", compressedDataEntity.isMainBody());
+
+        // Validated compessed part.
+        MimeEntity compressedEntity = compressedDataEntity.getCompressedEntity(new ZlibExpanderProvider());
+        assertTrue("Enveloped mime part incorrect type ", compressedEntity instanceof ApplicationEDIFACTEntity);
+        ApplicationEDIFACTEntity ediEntity = (ApplicationEDIFACTEntity) compressedEntity;
+        assertTrue("Unexpected content type for compressed entity",
+                ediEntity.getContentType().getValue().startsWith(AS2MediaType.APPLICATION_EDIFACT));
+        assertFalse("Compressed entity set as main body of request", ediEntity.isMainBody());
+
+    }
+
+
+    @Test
+    public void compressedAndSignedMessageTest() throws Exception {
+        AS2ClientConnection clientConnection = new AS2ClientConnection(AS2_VERSION, USER_AGENT, CLIENT_FQDN,
+                TARGET_HOST, TARGET_PORT);
+        AS2ClientManager clientManager = new AS2ClientManager(clientConnection);
+        
+        LOG.info("Key Algoritm: " + signingKP.getPrivate().getAlgorithm());
+
+        HttpCoreContext httpContext = clientManager.send(EDI_MESSAGE, REQUEST_URI, SUBJECT, FROM, AS2_NAME, AS2_NAME,
+                AS2MessageStructure.SIGNED_COMPRESSED,
+                ContentType.create(AS2MediaType.APPLICATION_EDIFACT, AS2Charset.US_ASCII), null,
+                AS2SignatureAlgorithm.SHA256WITHRSA, certList.toArray(new Certificate[0]), signingKP.getPrivate(), AS2CompressionAlgorithm.ZLIB,
+                DISPOSITION_NOTIFICATION_TO, SIGNED_RECEIPT_MIC_ALGORITHMS, null,
+                null, null);
+
+        HttpRequest request = httpContext.getRequest();
+        assertEquals("Unexpected method value", METHOD, request.getRequestLine().getMethod());
+        assertEquals("Unexpected request URI value", REQUEST_URI, request.getRequestLine().getUri());
+        assertEquals("Unexpected HTTP version value", HttpVersion.HTTP_1_1,
+                request.getRequestLine().getProtocolVersion());
+
+        assertEquals("Unexpected subject value", SUBJECT, request.getFirstHeader(AS2Header.SUBJECT).getValue());
+        assertEquals("Unexpected from value", FROM, request.getFirstHeader(AS2Header.FROM).getValue());
+        assertEquals("Unexpected AS2 version value", AS2_VERSION,
+                request.getFirstHeader(AS2Header.AS2_VERSION).getValue());
+        assertEquals("Unexpected AS2 from value", AS2_NAME, request.getFirstHeader(AS2Header.AS2_FROM).getValue());
+        assertEquals("Unexpected AS2 to value", AS2_NAME, request.getFirstHeader(AS2Header.AS2_TO).getValue());
+        assertTrue("Unexpected message id value",
+                request.getFirstHeader(AS2Header.MESSAGE_ID).getValue().endsWith(CLIENT_FQDN + ">"));
+        assertEquals("Unexpected target host value", TARGET_HOST + ":" + TARGET_PORT,
+                request.getFirstHeader(AS2Header.TARGET_HOST).getValue());
+        assertEquals("Unexpected user agent value", USER_AGENT,
+                request.getFirstHeader(AS2Header.USER_AGENT).getValue());
+        assertNotNull("Date value missing", request.getFirstHeader(AS2Header.DATE));
+        assertNotNull("Content length value missing", request.getFirstHeader(AS2Header.CONTENT_LENGTH));
+        assertTrue("Unexpected content type for message",
+                request.getFirstHeader(AS2Header.CONTENT_TYPE).getValue().startsWith(AS2MimeType.APPLICATION_PKCS7_MIME));
+
+        assertTrue("Request does not contain entity", request instanceof BasicHttpEntityEnclosingRequest);
+        HttpEntity entity = ((BasicHttpEntityEnclosingRequest) request).getEntity();
+        assertNotNull("Request does not contain entity", entity);
+        assertTrue("Unexpected request entity type", entity instanceof ApplicationPkcs7MimeCompressedDataEntity);
+        ApplicationPkcs7MimeCompressedDataEntity compressedDataEntity = (ApplicationPkcs7MimeCompressedDataEntity) entity;
+        assertTrue("Entity not set as main body of request", compressedDataEntity.isMainBody());
+
+        // Validated compressed part.
+        MimeEntity compressedEntity = compressedDataEntity.getCompressedEntity(new ZlibExpanderProvider());
+        assertTrue("Enveloped mime part incorrect type ", compressedEntity instanceof MultipartSignedEntity);
+        MultipartSignedEntity multipartSignedEntity = (MultipartSignedEntity) compressedEntity;
+        assertTrue("Unexpected content type for compressed entity",
+                multipartSignedEntity.getContentType().getValue().startsWith(AS2MediaType.MULTIPART_SIGNED));
+        assertFalse("Multipart signed entity set as main body of request", multipartSignedEntity.isMainBody());
+        assertTrue("Multipart signed entity contains invalid number of mime parts",
+                multipartSignedEntity.getPartCount() == 2);
+
+        // Validated first mime part.
+        assertTrue("First mime part incorrect type ", multipartSignedEntity.getPart(0) instanceof ApplicationEDIFACTEntity);
+        ApplicationEDIFACTEntity ediEntity = (ApplicationEDIFACTEntity) multipartSignedEntity.getPart(0);
+        assertTrue("Unexpected content type for first mime part",
+                ediEntity.getContentType().getValue().startsWith(AS2MediaType.APPLICATION_EDIFACT));
+        assertFalse("First mime type set as main body of request", ediEntity.isMainBody());
+        
+        // Validate second mime part.
+        assertTrue("Second mime part incorrect type ",
+                multipartSignedEntity.getPart(1) instanceof ApplicationPkcs7SignatureEntity);
+        ApplicationPkcs7SignatureEntity signatureEntity = (ApplicationPkcs7SignatureEntity) multipartSignedEntity.getPart(1);
+        assertTrue("Unexpected content type for second mime part",
+                signatureEntity.getContentType().getValue().startsWith(AS2MediaType.APPLICATION_PKCS7_SIGNATURE));
+        assertFalse("First mime type set as main body of request", signatureEntity.isMainBody());
+    }
+
+    @Test
+    public void envelopedAndCompressedMessageTest() throws Exception {
+        AS2ClientConnection clientConnection = new AS2ClientConnection(AS2_VERSION, USER_AGENT, CLIENT_FQDN,
+                TARGET_HOST, TARGET_PORT);
+        AS2ClientManager clientManager = new AS2ClientManager(clientConnection);
+        
+        LOG.info("Key Algoritm: " + signingKP.getPrivate().getAlgorithm());
+
+        HttpCoreContext httpContext = clientManager.send(EDI_MESSAGE, REQUEST_URI, SUBJECT, FROM, AS2_NAME, AS2_NAME,
+                AS2MessageStructure.ENCRYPTED_COMPRESSED,
+                ContentType.create(AS2MediaType.APPLICATION_EDIFACT, AS2Charset.US_ASCII), null,
+                null, null, null, AS2CompressionAlgorithm.ZLIB,
+                DISPOSITION_NOTIFICATION_TO, SIGNED_RECEIPT_MIC_ALGORITHMS, AS2EncryptionAlgorithm.AES128_CBC,
+                certList.toArray(new Certificate[0]), signingKP.getPrivate());
+
+        HttpRequest request = httpContext.getRequest();
+        assertEquals("Unexpected method value", METHOD, request.getRequestLine().getMethod());
+        assertEquals("Unexpected request URI value", REQUEST_URI, request.getRequestLine().getUri());
+        assertEquals("Unexpected HTTP version value", HttpVersion.HTTP_1_1,
+                request.getRequestLine().getProtocolVersion());
+
+        assertEquals("Unexpected subject value", SUBJECT, request.getFirstHeader(AS2Header.SUBJECT).getValue());
+        assertEquals("Unexpected from value", FROM, request.getFirstHeader(AS2Header.FROM).getValue());
+        assertEquals("Unexpected AS2 version value", AS2_VERSION,
+                request.getFirstHeader(AS2Header.AS2_VERSION).getValue());
+        assertEquals("Unexpected AS2 from value", AS2_NAME, request.getFirstHeader(AS2Header.AS2_FROM).getValue());
+        assertEquals("Unexpected AS2 to value", AS2_NAME, request.getFirstHeader(AS2Header.AS2_TO).getValue());
+        assertTrue("Unexpected message id value",
+                request.getFirstHeader(AS2Header.MESSAGE_ID).getValue().endsWith(CLIENT_FQDN + ">"));
+        assertEquals("Unexpected target host value", TARGET_HOST + ":" + TARGET_PORT,
+                request.getFirstHeader(AS2Header.TARGET_HOST).getValue());
+        assertEquals("Unexpected user agent value", USER_AGENT,
+                request.getFirstHeader(AS2Header.USER_AGENT).getValue());
+        assertNotNull("Date value missing", request.getFirstHeader(AS2Header.DATE));
+        assertNotNull("Content length value missing", request.getFirstHeader(AS2Header.CONTENT_LENGTH));
+        assertTrue("Unexpected content type for message",
+                request.getFirstHeader(AS2Header.CONTENT_TYPE).getValue().startsWith(AS2MimeType.APPLICATION_PKCS7_MIME));
+
+        assertTrue("Request does not contain entity", request instanceof BasicHttpEntityEnclosingRequest);
+        HttpEntity entity = ((BasicHttpEntityEnclosingRequest) request).getEntity();
+        assertNotNull("Request does not contain entity", entity);
+        assertTrue("Unexpected request entity type", entity instanceof ApplicationPkcs7MimeEnvelopedDataEntity);
+        ApplicationPkcs7MimeEnvelopedDataEntity envelopedEntity = (ApplicationPkcs7MimeEnvelopedDataEntity) entity;
+        assertTrue("Entity not set as main body of request", envelopedEntity.isMainBody());
+
+        // Validated enveloped part.
+        MimeEntity encryptedEntity = envelopedEntity.getEncryptedEntity(signingKP.getPrivate());
+        assertTrue("Enveloped mime part incorrect type ", encryptedEntity instanceof ApplicationPkcs7MimeCompressedDataEntity);
+        ApplicationPkcs7MimeCompressedDataEntity compressedDataEntity = (ApplicationPkcs7MimeCompressedDataEntity) encryptedEntity;
+        assertTrue("Unexpected content type for compressed mime part",
+                compressedDataEntity.getContentType().getValue().startsWith(AS2MimeType.APPLICATION_PKCS7_MIME));
+        assertFalse("Enveloped mime type set as main body of request", compressedDataEntity.isMainBody());
+
+        // Validated compressed part.
+        MimeEntity compressedEntity = compressedDataEntity.getCompressedEntity(new ZlibExpanderProvider());
+        assertTrue("Enveloped mime part incorrect type ", compressedEntity instanceof ApplicationEDIFACTEntity);
+        ApplicationEDIFACTEntity ediEntity = (ApplicationEDIFACTEntity) compressedEntity;
+        assertTrue("Unexpected content type for compressed entity",
+                ediEntity.getContentType().getValue().startsWith(AS2MediaType.APPLICATION_EDIFACT));
+        assertFalse("Compressed entity set as main body of request", ediEntity.isMainBody());
+        assertEquals("Unexpected content for enveloped mime part", EDI_MESSAGE.replaceAll("[\n\r]", ""),
+                ediEntity.getEdiMessage().replaceAll("[\n\r]", ""));
+    }
+
+
 
 }
diff --git a/components/camel-as2/camel-as2-api/src/test/java/org/apache/camel/component/as2/api/entity/CompressedEntityTest.java b/components/camel-as2/camel-as2-api/src/test/java/org/apache/camel/component/as2/api/entity/CompressedEntityTest.java
new file mode 100644
index 00000000000..dc549e9bc8d
--- /dev/null
+++ b/components/camel-as2/camel-as2-api/src/test/java/org/apache/camel/component/as2/api/entity/CompressedEntityTest.java
@@ -0,0 +1,89 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.camel.component.as2.api.entity;
+
+import org.bouncycastle.cms.CMSCompressedDataGenerator;
+import org.bouncycastle.cms.jcajce.ZlibCompressor;
+import org.bouncycastle.cms.jcajce.ZlibExpanderProvider;
+import org.bouncycastle.operator.OutputCompressor;
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Test;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertTrue;
+
+public class CompressedEntityTest {
+    
+    public static final String TEXT_PLAIN_CONTENT =
+            "MDN for -\r\n"
+            + " Message ID: <200207310834482A70BF63@\\\"~~foo~~\\\">\r\n"
+            + "  From: \"\\\"  as2Name  \\\"\"\r\n"
+            + "  To: \"0123456780000\""
+            + "  Received on: 2002-07-31 at 09:34:14 (EDT)\r\n"
+            + " Status: processed\r\n"
+            + " Comment: This is not a guarantee that the message has\r\n"
+            + "  been completely processed or &understood by the receiving\r\n"
+            + "  translator\r\n"
+            + "\r\n";
+
+    public static final String TEXT_PLAIN_CONTENT_CHARSET_NAME = "US-ASCII";
+
+    public static final String TEXT_PLAIN_CONTENT_TRANSFER_ENCODING = "7bit";
+
+    public static final String EXPECTED_TEXT_PLAIN_CONTENT =
+            "MDN for -\r\n"
+            + " Message ID: <200207310834482A70BF63@\\\"~~foo~~\\\">\r\n"
+            + "  From: \"\\\"  as2Name  \\\"\"\r\n"
+            + "  To: \"0123456780000\""
+            + "  Received on: 2002-07-31 at 09:34:14 (EDT)\r\n"
+            + " Status: processed\r\n"
+            + " Comment: This is not a guarantee that the message has\r\n"
+            + "  been completely processed or &understood by the receiving\r\n"
+            + "  translator\r\n"
+            + "\r\n";
+
+    
+    public static final String APPLICATION_PKCS7_MIME_COMPRESSED_TRANSFER_ENCODING = "base64";
+
+    @Before
+    public void setUp() throws Exception {
+    }
+
+    @After
+    public void tearDown() throws Exception {
+    }
+    
+    @Test
+    public void createCompressedEntityTest() throws Exception {
+        TextPlainEntity textPlainEntity = new TextPlainEntity(TEXT_PLAIN_CONTENT, TEXT_PLAIN_CONTENT_CHARSET_NAME,
+                TEXT_PLAIN_CONTENT_TRANSFER_ENCODING, false);
+
+        CMSCompressedDataGenerator cGen = new CMSCompressedDataGenerator();
+
+        OutputCompressor compressor = new ZlibCompressor();
+
+        ApplicationPkcs7MimeCompressedDataEntity compressedEntity = new ApplicationPkcs7MimeCompressedDataEntity(
+                textPlainEntity, cGen, compressor, APPLICATION_PKCS7_MIME_COMPRESSED_TRANSFER_ENCODING, false);
+
+        MimeEntity decompressedEntity = compressedEntity.getCompressedEntity(new ZlibExpanderProvider());
+        assertTrue("", decompressedEntity instanceof TextPlainEntity);
+        TextPlainEntity decompressedTextPlainEntity = (TextPlainEntity) decompressedEntity;
+        assertEquals("", EXPECTED_TEXT_PLAIN_CONTENT, decompressedTextPlainEntity.getText());
+    }
+
+}
diff --git a/components/camel-as2/camel-as2-api/src/test/java/org/apache/camel/component/as2/api/entity/EntityParserTest.java b/components/camel-as2/camel-as2-api/src/test/java/org/apache/camel/component/as2/api/entity/EntityParserTest.java
index cd47c82d9e0..d5b3a0dd646 100644
--- a/components/camel-as2/camel-as2-api/src/test/java/org/apache/camel/component/as2/api/entity/EntityParserTest.java
+++ b/components/camel-as2/camel-as2-api/src/test/java/org/apache/camel/component/as2/api/entity/EntityParserTest.java
@@ -317,7 +317,7 @@ public void parseEnvelopedBodyTest() throws Exception {
         // Build Enveloped Entity
         //
         TextPlainEntity textEntity = new TextPlainEntity("This is a super secret messatge!", "US-ASCII", "7bit", false);
-        ApplicationPkcs7MimeEntity applicationPkcs7MimeEntity = new ApplicationPkcs7MimeEntity(textEntity, cmsEnvelopeDataGenerator, contentEncryptor, "binary", true);
+        ApplicationPkcs7MimeEnvelopedDataEntity applicationPkcs7MimeEntity = new ApplicationPkcs7MimeEnvelopedDataEntity(textEntity, cmsEnvelopeDataGenerator, contentEncryptor, "binary", true);
         
         MimeEntity decryptedMimeEntity = applicationPkcs7MimeEntity.getEncryptedEntity(encryptKP.getPrivate());
         assertEquals("Decrypted entity has unexpected content type", "text/plain; charset=US-ASCII", decryptedMimeEntity.getContentTypeValue());
diff --git a/components/camel-as2/camel-as2-component/pom.xml b/components/camel-as2/camel-as2-component/pom.xml
index d7756f7a0e1..8903e25dca7 100644
--- a/components/camel-as2/camel-as2-component/pom.xml
+++ b/components/camel-as2/camel-as2-component/pom.xml
@@ -22,7 +22,7 @@
   <parent>
     <groupId>org.apache.camel</groupId>
     <artifactId>camel-as2-parent</artifactId>
-    <version>2.23.0-SNAPSHOT</version>
+    <version>2.24.0-SNAPSHOT</version>
   </parent>
 
   <artifactId>camel-as2</artifactId>
diff --git a/components/camel-as2/camel-as2-component/src/main/docs/as2-component.adoc b/components/camel-as2/camel-as2-component/src/main/docs/as2-component.adoc
index aef14ca7444..0c1180cd1c7 100644
--- a/components/camel-as2/camel-as2-component/src/main/docs/as2-component.adoc
+++ b/components/camel-as2/camel-as2-component/src/main/docs/as2-component.adoc
@@ -70,7 +70,7 @@ with the following path and query parameters:
 |===
 
 
-==== Query Parameters (30 parameters):
+==== Query Parameters (31 parameters):
 
 
 [width="100%",cols="2,5,^1,2",options="header"]
@@ -81,6 +81,7 @@ with the following path and query parameters:
 | *as2To* (common) | The value of the AS2To header of AS2 message. |  | String
 | *as2Version* (common) | The version of the AS2 protocol. | 1.1 | String
 | *clientFqdn* (common) | The Client Fully Qualified Domain Name (FQDN). Used in message ids sent by endpoint. | camel.apache.org | String
+| *compressionAlgorithm* (common) | The algorithm used to compress EDI message. |  | AS2Compression Algorithm
 | *dispositionNotificationTo* (common) | The value of the Disposition-Notification-To header. Assigning a value to this parameter requests a message disposition notification (MDN) for the AS2 message. |  | String
 | *ediMessageTransferEncoding* (common) | The transfer encoding of EDI message. |  | String
 | *ediMessageType* (common) | The content type of EDI message. One of application/edifact, application/edi-x12, application/edi-consent |  | ContentType
@@ -112,7 +113,7 @@ with the following path and query parameters:
 === Spring Boot Auto-Configuration
 
 
-The component supports 28 options, which are listed below.
+The component supports 29 options, which are listed below.
 
 
 
@@ -125,6 +126,7 @@ The component supports 28 options, which are listed below.
 | *camel.component.as2.configuration.as2-to* | The value of the AS2To header of AS2 message. |  | String
 | *camel.component.as2.configuration.as2-version* | The version of the AS2 protocol. | 1.1 | String
 | *camel.component.as2.configuration.client-fqdn* | The Client Fully Qualified Domain Name (FQDN). Used in message ids sent by endpoint. | camel.apache.org | String
+| *camel.component.as2.configuration.compression-algorithm* | The algorithm used to compress EDI message. |  | AS2Compression Algorithm
 | *camel.component.as2.configuration.disposition-notification-to* | The value of the Disposition-Notification-To header. Assigning a value to this parameter requests a message disposition notification (MDN) for the AS2 message. |  | String
 | *camel.component.as2.configuration.edi-message-transfer-encoding* | The transfer encoding of EDI message. |  | String
 | *camel.component.as2.configuration.edi-message-type* | The content type of EDI message. One of application/edifact, application/edi-x12, application/edi-consent |  | ContentType
diff --git a/components/camel-as2/camel-as2-component/src/main/java/org/apache/camel/component/as2/AS2Configuration.java b/components/camel-as2/camel-as2-component/src/main/java/org/apache/camel/component/as2/AS2Configuration.java
index bd5a34746a9..c92b50e2a9f 100644
--- a/components/camel-as2/camel-as2-component/src/main/java/org/apache/camel/component/as2/AS2Configuration.java
+++ b/components/camel-as2/camel-as2-component/src/main/java/org/apache/camel/component/as2/AS2Configuration.java
@@ -20,6 +20,7 @@
 import java.security.cert.Certificate;
 
 import org.apache.camel.RuntimeCamelException;
+import org.apache.camel.component.as2.api.AS2CompressionAlgorithm;
 import org.apache.camel.component.as2.api.AS2EncryptionAlgorithm;
 import org.apache.camel.component.as2.api.AS2MessageStructure;
 import org.apache.camel.component.as2.api.AS2SignatureAlgorithm;
@@ -101,6 +102,9 @@
     @UriParam
     private PrivateKey signingPrivateKey;
 
+    @UriParam
+    private AS2CompressionAlgorithm compressionAlgorithm;
+
     @UriParam
     private String dispositionNotificationTo;
 
@@ -388,6 +392,17 @@ public void setSigningPrivateKey(PrivateKey signingPrivateKey) {
         this.signingPrivateKey = signingPrivateKey;
     }
 
+    public AS2CompressionAlgorithm getCompressionAlgorithm() {
+        return compressionAlgorithm;
+    }
+
+    /**
+     * The algorithm used to compress EDI message.
+     */
+    public void setCompressionAlgorithm(AS2CompressionAlgorithm compressionAlgorithm) {
+        this.compressionAlgorithm = compressionAlgorithm;
+    }
+
     public String getDispositionNotificationTo() {
         return dispositionNotificationTo;
     }
@@ -415,7 +430,7 @@ public void setSignedReceiptMicAlgorithms(String[] signedReceiptMicAlgorithms) {
         this.signedReceiptMicAlgorithms = signedReceiptMicAlgorithms;
     }
 
-    public AS2EncryptionAlgorithm getEncryptingingAlgorithm() {
+    public AS2EncryptionAlgorithm getEncryptingAlgorithm() {
         return encryptingAlgorithm;
     }
 
diff --git a/components/camel-as2/camel-as2-component/src/test/java/org/apache/camel/component/as2/AS2ClientManagerIntegrationTest.java b/components/camel-as2/camel-as2-component/src/test/java/org/apache/camel/component/as2/AS2ClientManagerIntegrationTest.java
index ca14bf6f8f4..36c03866316 100644
--- a/components/camel-as2/camel-as2-component/src/test/java/org/apache/camel/component/as2/AS2ClientManagerIntegrationTest.java
+++ b/components/camel-as2/camel-as2-component/src/test/java/org/apache/camel/component/as2/AS2ClientManagerIntegrationTest.java
@@ -45,7 +45,7 @@
 import org.apache.camel.component.as2.api.entity.AS2DispositionType;
 import org.apache.camel.component.as2.api.entity.AS2MessageDispositionNotificationEntity;
 import org.apache.camel.component.as2.api.entity.ApplicationEDIEntity;
-import org.apache.camel.component.as2.api.entity.ApplicationPkcs7MimeEntity;
+import org.apache.camel.component.as2.api.entity.ApplicationPkcs7MimeEnvelopedDataEntity;
 import org.apache.camel.component.as2.api.entity.ApplicationPkcs7SignatureEntity;
 import org.apache.camel.component.as2.api.entity.DispositionMode;
 import org.apache.camel.component.as2.api.entity.DispositionNotificationMultipartReportEntity;
@@ -326,8 +326,8 @@ public void envelopedMessageSendTest() throws Exception {
         assertTrue("Request does not contain body", request instanceof HttpEntityEnclosingRequest);
         HttpEntity entity = ((HttpEntityEnclosingRequest)request).getEntity();
         assertNotNull("Request body", entity);
-        assertTrue("Request body does not contain ApplicationPkcs7Mime entity", entity instanceof ApplicationPkcs7MimeEntity);
-        MimeEntity envelopeEntity = ((ApplicationPkcs7MimeEntity)entity).getEncryptedEntity(signingKP.getPrivate());
+        assertTrue("Request body does not contain ApplicationPkcs7Mime entity", entity instanceof ApplicationPkcs7MimeEnvelopedDataEntity);
+        MimeEntity envelopeEntity = ((ApplicationPkcs7MimeEnvelopedDataEntity)entity).getEncryptedEntity(signingKP.getPrivate());
         assertTrue("Enveloped entity is not an EDI entity", envelopeEntity instanceof ApplicationEDIEntity);
         String ediMessage = ((ApplicationEDIEntity)envelopeEntity).getEdiMessage();
         assertEquals("EDI message is different", EDI_MESSAGE.replaceAll("[\n\r]", ""), ediMessage.replaceAll("[\n\r]", ""));
diff --git a/components/camel-as2/camel-as2-component/src/test/java/org/apache/camel/component/as2/AS2ServerManagerIntegrationTest.java b/components/camel-as2/camel-as2-component/src/test/java/org/apache/camel/component/as2/AS2ServerManagerIntegrationTest.java
index 9cb635fcbb8..0f6b93125ca 100644
--- a/components/camel-as2/camel-as2-component/src/test/java/org/apache/camel/component/as2/AS2ServerManagerIntegrationTest.java
+++ b/components/camel-as2/camel-as2-component/src/test/java/org/apache/camel/component/as2/AS2ServerManagerIntegrationTest.java
@@ -128,7 +128,7 @@ public void receivePlainEDIMessageTest() throws Exception {
 
         clientManager.send(EDI_MESSAGE, REQUEST_URI, SUBJECT, FROM, AS2_NAME, AS2_NAME, AS2MessageStructure.PLAIN,
                 ContentType.create(AS2MediaType.APPLICATION_EDIFACT, AS2Charset.US_ASCII), null, null, null, null,
-                DISPOSITION_NOTIFICATION_TO, SIGNED_RECEIPT_MIC_ALGORITHMS, null, null, null);
+                null, DISPOSITION_NOTIFICATION_TO, SIGNED_RECEIPT_MIC_ALGORITHMS, null, null, null);
 
         MockEndpoint mockEndpoint = getMockEndpoint("mock:as2RcvMsgs");
         mockEndpoint.expectedMinimumMessageCount(1);
@@ -185,7 +185,7 @@ public void receiveMultipartSignedMessageTest() throws Exception {
 
         clientManager.send(EDI_MESSAGE, REQUEST_URI, SUBJECT, FROM, AS2_NAME, AS2_NAME, AS2MessageStructure.SIGNED,
                 ContentType.create(AS2MediaType.APPLICATION_EDIFACT, AS2Charset.US_ASCII), null, AS2SignatureAlgorithm.SHA256WITHRSA,
-                certList.toArray(new Certificate[0]), signingKP.getPrivate(), DISPOSITION_NOTIFICATION_TO,
+                certList.toArray(new Certificate[0]), signingKP.getPrivate(), null, DISPOSITION_NOTIFICATION_TO,
                 SIGNED_RECEIPT_MIC_ALGORITHMS, null, null, null);
 
         MockEndpoint mockEndpoint = getMockEndpoint("mock:as2RcvMsgs");
diff --git a/components/camel-as2/pom.xml b/components/camel-as2/pom.xml
index a22725942d2..b489461b939 100644
--- a/components/camel-as2/pom.xml
+++ b/components/camel-as2/pom.xml
@@ -22,7 +22,7 @@
   <parent>
     <artifactId>components</artifactId>
     <groupId>org.apache.camel</groupId>
-    <version>2.23.0-SNAPSHOT</version>
+    <version>2.24.0-SNAPSHOT</version>
   </parent>
 
   <artifactId>camel-as2-parent</artifactId>
diff --git a/components/camel-asn1/pom.xml b/components/camel-asn1/pom.xml
index 120539f1dcb..8e49211b214 100644
--- a/components/camel-asn1/pom.xml
+++ b/components/camel-asn1/pom.xml
@@ -23,7 +23,7 @@
   <parent>
     <groupId>org.apache.camel</groupId>
     <artifactId>components</artifactId>
-    <version>2.23.0-SNAPSHOT</version>
+    <version>2.24.0-SNAPSHOT</version>
   </parent>
 
   <artifactId>camel-asn1</artifactId>
diff --git a/components/camel-asterisk/pom.xml b/components/camel-asterisk/pom.xml
index 82d3e606c54..a829e4e97d4 100644
--- a/components/camel-asterisk/pom.xml
+++ b/components/camel-asterisk/pom.xml
@@ -23,7 +23,7 @@
   <parent>
     <groupId>org.apache.camel</groupId>
     <artifactId>components</artifactId>
-    <version>2.23.0-SNAPSHOT</version>
+    <version>2.24.0-SNAPSHOT</version>
   </parent>
 
   <artifactId>camel-asterisk</artifactId>
diff --git a/components/camel-atmos/pom.xml b/components/camel-atmos/pom.xml
index 2733acc4ee1..cd1aaf3a62f 100644
--- a/components/camel-atmos/pom.xml
+++ b/components/camel-atmos/pom.xml
@@ -24,7 +24,7 @@
   <parent>
     <groupId>org.apache.camel</groupId>
     <artifactId>components</artifactId>
-    <version>2.23.0-SNAPSHOT</version>
+    <version>2.24.0-SNAPSHOT</version>
   </parent>
 
   <artifactId>camel-atmos</artifactId>
diff --git a/components/camel-atmosphere-websocket/pom.xml b/components/camel-atmosphere-websocket/pom.xml
index 35d6c1a1672..b00a4ee0e41 100644
--- a/components/camel-atmosphere-websocket/pom.xml
+++ b/components/camel-atmosphere-websocket/pom.xml
@@ -24,7 +24,7 @@
     <parent>
         <groupId>org.apache.camel</groupId>
         <artifactId>components</artifactId>
-        <version>2.23.0-SNAPSHOT</version>
+        <version>2.24.0-SNAPSHOT</version>
     </parent>
 
     <artifactId>camel-atmosphere-websocket</artifactId>
diff --git a/components/camel-atom/pom.xml b/components/camel-atom/pom.xml
index 8d4201d437d..a3f8b268374 100644
--- a/components/camel-atom/pom.xml
+++ b/components/camel-atom/pom.xml
@@ -23,7 +23,7 @@
   <parent>
     <groupId>org.apache.camel</groupId>
     <artifactId>components</artifactId>
-    <version>2.23.0-SNAPSHOT</version>
+    <version>2.24.0-SNAPSHOT</version>
   </parent>
 
   <artifactId>camel-atom</artifactId>
diff --git a/components/camel-atomix/pom.xml b/components/camel-atomix/pom.xml
index 147c404c99f..cd1a4c76272 100644
--- a/components/camel-atomix/pom.xml
+++ b/components/camel-atomix/pom.xml
@@ -25,7 +25,7 @@
   <parent>
     <groupId>org.apache.camel</groupId>
     <artifactId>components</artifactId>
-    <version>2.23.0-SNAPSHOT</version>
+    <version>2.24.0-SNAPSHOT</version>
   </parent>
 
   <artifactId>camel-atomix</artifactId>
diff --git a/components/camel-avro/pom.xml b/components/camel-avro/pom.xml
index 94f05a4b122..d20d5bc6528 100644
--- a/components/camel-avro/pom.xml
+++ b/components/camel-avro/pom.xml
@@ -23,7 +23,7 @@
     <parent>
         <groupId>org.apache.camel</groupId>
         <artifactId>components</artifactId>
-        <version>2.23.0-SNAPSHOT</version>
+        <version>2.24.0-SNAPSHOT</version>
     </parent>
 
     <artifactId>camel-avro</artifactId>
diff --git a/components/camel-aws-xray/pom.xml b/components/camel-aws-xray/pom.xml
index feac69bce82..92415e97c51 100644
--- a/components/camel-aws-xray/pom.xml
+++ b/components/camel-aws-xray/pom.xml
@@ -23,7 +23,7 @@
   <parent>
     <artifactId>components</artifactId>
     <groupId>org.apache.camel</groupId>
-    <version>2.23.0-SNAPSHOT</version>
+    <version>2.24.0-SNAPSHOT</version>
   </parent>
 
   <artifactId>camel-aws-xray</artifactId>
diff --git a/components/camel-aws/pom.xml b/components/camel-aws/pom.xml
index 2572064332f..6d1e732ec71 100644
--- a/components/camel-aws/pom.xml
+++ b/components/camel-aws/pom.xml
@@ -23,7 +23,7 @@
     <parent>
         <groupId>org.apache.camel</groupId>
         <artifactId>components</artifactId>
-        <version>2.23.0-SNAPSHOT</version>
+        <version>2.24.0-SNAPSHOT</version>
     </parent>
 
     <artifactId>camel-aws</artifactId>
diff --git a/components/camel-aws/src/main/docs/aws-sqs-component.adoc b/components/camel-aws/src/main/docs/aws-sqs-component.adoc
index 970bb77f4c0..d5dc6e82edd 100644
--- a/components/camel-aws/src/main/docs/aws-sqs-component.adoc
+++ b/components/camel-aws/src/main/docs/aws-sqs-component.adoc
@@ -128,7 +128,7 @@ with the following path and query parameters:
 === Spring Boot Auto-Configuration
 
 
-The component supports 30 options, which are listed below.
+The component supports 31 options, which are listed below.
 
 
 
@@ -142,6 +142,7 @@ The component supports 30 options, which are listed below.
 | *camel.component.aws-sqs.configuration.attribute-names* | A list of attribute names to receive when consuming. Multiple names can be separated by comma. |  | String
 | *camel.component.aws-sqs.configuration.concurrent-consumers* | Allows you to use multiple threads to poll the sqs queue to increase throughput | 1 | Integer
 | *camel.component.aws-sqs.configuration.default-visibility-timeout* | The default visibility timeout (in seconds) |  | Integer
+| *camel.component.aws-sqs.configuration.delay-queue* | Define if you want to apply delaySeconds option to the queue or on single messages | false | Boolean
 | *camel.component.aws-sqs.configuration.delay-seconds* | Delay sending messages for a number of seconds. |  | Integer
 | *camel.component.aws-sqs.configuration.delete-after-read* | Delete message from SQS after it has been read | true | Boolean
 | *camel.component.aws-sqs.configuration.delete-if-filtered* | Whether or not to send the DeleteMessage to the SQS queue if an exchange fails to get through a filter. If 'false' and exchange does not make it through a Camel filter upstream in the route, then don't send DeleteMessage. | true | Boolean
diff --git a/components/camel-azure/pom.xml b/components/camel-azure/pom.xml
index 86842ca620b..a1cd1ead408 100644
--- a/components/camel-azure/pom.xml
+++ b/components/camel-azure/pom.xml
@@ -24,7 +24,7 @@
   <parent>
     <groupId>org.apache.camel</groupId>
     <artifactId>components</artifactId>
-    <version>2.23.0-SNAPSHOT</version>
+    <version>2.24.0-SNAPSHOT</version>
   </parent>
 
   <artifactId>camel-azure</artifactId>
diff --git a/components/camel-bam/pom.xml b/components/camel-bam/pom.xml
index 790bc26381e..e16d66bcaeb 100644
--- a/components/camel-bam/pom.xml
+++ b/components/camel-bam/pom.xml
@@ -23,7 +23,7 @@
   <parent>
     <groupId>org.apache.camel</groupId>
     <artifactId>components</artifactId>
-    <version>2.23.0-SNAPSHOT</version>
+    <version>2.24.0-SNAPSHOT</version>
   </parent>
 
   <artifactId>camel-bam</artifactId>
diff --git a/components/camel-barcode/pom.xml b/components/camel-barcode/pom.xml
index 354143f18fa..d7be47649c1 100644
--- a/components/camel-barcode/pom.xml
+++ b/components/camel-barcode/pom.xml
@@ -24,7 +24,7 @@
     <parent>
         <groupId>org.apache.camel</groupId>
         <artifactId>components</artifactId>
-        <version>2.23.0-SNAPSHOT</version>
+        <version>2.24.0-SNAPSHOT</version>
     </parent>
 
     <artifactId>camel-barcode</artifactId>
diff --git a/components/camel-base64/pom.xml b/components/camel-base64/pom.xml
index da14db6d8bd..2a29962e75f 100644
--- a/components/camel-base64/pom.xml
+++ b/components/camel-base64/pom.xml
@@ -23,7 +23,7 @@
   <parent>
     <groupId>org.apache.camel</groupId>
     <artifactId>components</artifactId>
-    <version>2.23.0-SNAPSHOT</version>
+    <version>2.24.0-SNAPSHOT</version>
   </parent>
 
   <artifactId>camel-base64</artifactId>
diff --git a/components/camel-bean-validator/pom.xml b/components/camel-bean-validator/pom.xml
index 5a3a1628235..4029ee2376b 100644
--- a/components/camel-bean-validator/pom.xml
+++ b/components/camel-bean-validator/pom.xml
@@ -24,7 +24,7 @@
   <parent>
     <groupId>org.apache.camel</groupId>
     <artifactId>components</artifactId>
-    <version>2.23.0-SNAPSHOT</version>
+    <version>2.24.0-SNAPSHOT</version>
   </parent>
 
   <artifactId>camel-bean-validator</artifactId>
diff --git a/components/camel-beanio/pom.xml b/components/camel-beanio/pom.xml
index 4086640467d..d123077691b 100644
--- a/components/camel-beanio/pom.xml
+++ b/components/camel-beanio/pom.xml
@@ -23,7 +23,7 @@
   <parent>
     <groupId>org.apache.camel</groupId>
     <artifactId>components</artifactId>
-    <version>2.23.0-SNAPSHOT</version>
+    <version>2.24.0-SNAPSHOT</version>
   </parent>
 
   <artifactId>camel-beanio</artifactId>
diff --git a/components/camel-beanstalk/pom.xml b/components/camel-beanstalk/pom.xml
index 1bb7ef282ae..071bba3faed 100644
--- a/components/camel-beanstalk/pom.xml
+++ b/components/camel-beanstalk/pom.xml
@@ -23,7 +23,7 @@
   <parent>
     <groupId>org.apache.camel</groupId>
     <artifactId>components</artifactId>
-    <version>2.23.0-SNAPSHOT</version>
+    <version>2.24.0-SNAPSHOT</version>
   </parent>
 
   <artifactId>camel-beanstalk</artifactId>
diff --git a/components/camel-bindy/pom.xml b/components/camel-bindy/pom.xml
index 413f63e6c6e..46e530df518 100644
--- a/components/camel-bindy/pom.xml
+++ b/components/camel-bindy/pom.xml
@@ -23,7 +23,7 @@
     <parent>
         <groupId>org.apache.camel</groupId>
         <artifactId>components</artifactId>
-        <version>2.23.0-SNAPSHOT</version>
+        <version>2.24.0-SNAPSHOT</version>
     </parent>
 
     <artifactId>camel-bindy</artifactId>
diff --git a/components/camel-blueprint/pom.xml b/components/camel-blueprint/pom.xml
index 86711cef587..06b9e1e6c33 100644
--- a/components/camel-blueprint/pom.xml
+++ b/components/camel-blueprint/pom.xml
@@ -24,7 +24,7 @@
   <parent>
     <groupId>org.apache.camel</groupId>
     <artifactId>components</artifactId>
-    <version>2.23.0-SNAPSHOT</version>
+    <version>2.24.0-SNAPSHOT</version>
   </parent>
 
   <artifactId>camel-blueprint</artifactId>
diff --git a/components/camel-bonita/pom.xml b/components/camel-bonita/pom.xml
index 585565fda44..27505ae85b0 100644
--- a/components/camel-bonita/pom.xml
+++ b/components/camel-bonita/pom.xml
@@ -25,7 +25,7 @@
   <parent>
     <groupId>org.apache.camel</groupId>
     <artifactId>components</artifactId>
-    <version>2.23.0-SNAPSHOT</version>
+    <version>2.24.0-SNAPSHOT</version>
   </parent>
 
   <artifactId>camel-bonita</artifactId>
diff --git a/components/camel-boon/pom.xml b/components/camel-boon/pom.xml
index 7a9b2392f38..ae8b7c4ac88 100644
--- a/components/camel-boon/pom.xml
+++ b/components/camel-boon/pom.xml
@@ -23,7 +23,7 @@
     <parent>
         <groupId>org.apache.camel</groupId>
         <artifactId>components</artifactId>
-        <version>2.23.0-SNAPSHOT</version>
+        <version>2.24.0-SNAPSHOT</version>
     </parent>
 
     <artifactId>camel-boon</artifactId>
diff --git a/components/camel-box/camel-box-api/pom.xml b/components/camel-box/camel-box-api/pom.xml
index 0043d306343..2e6b0b81055 100644
--- a/components/camel-box/camel-box-api/pom.xml
+++ b/components/camel-box/camel-box-api/pom.xml
@@ -24,7 +24,7 @@
   <parent>
     <groupId>org.apache.camel</groupId>
     <artifactId>camel-box-parent</artifactId>
-    <version>2.23.0-SNAPSHOT</version>
+    <version>2.24.0-SNAPSHOT</version>
   </parent>
 
   <artifactId>camel-box-api</artifactId>
diff --git a/components/camel-box/camel-box-component/pom.xml b/components/camel-box/camel-box-component/pom.xml
index b675750ce1d..57348d1818d 100644
--- a/components/camel-box/camel-box-component/pom.xml
+++ b/components/camel-box/camel-box-component/pom.xml
@@ -24,7 +24,7 @@
   <parent>
     <groupId>org.apache.camel</groupId>
     <artifactId>camel-box-parent</artifactId>
-    <version>2.23.0-SNAPSHOT</version>
+    <version>2.24.0-SNAPSHOT</version>
   </parent>
 
   <artifactId>camel-box</artifactId>
diff --git a/components/camel-box/camel-box-component/src/main/docs/box-component.adoc b/components/camel-box/camel-box-component/src/main/docs/box-component.adoc
index a00d2e34677..e04398ba49a 100644
--- a/components/camel-box/camel-box-component/src/main/docs/box-component.adoc
+++ b/components/camel-box/camel-box-component/src/main/docs/box-component.adoc
@@ -352,7 +352,7 @@ box:files/endpoint?[options]
 
 |getFileVersions |versions |fileId |java.util.Collection
 
-|downloadPreviousFileVersions |downloadVersion |fileId, version, output, [listener] |java.io.OutputStream
+|downloadPreviousFileVersion |downloadVersion |fileId, version, output, [listener] |java.io.OutputStream
 
 |deleteFileVersion |deleteVersion |fileId, version |
 
diff --git a/components/camel-box/pom.xml b/components/camel-box/pom.xml
index 7f8f9a0d938..59aabc1990e 100644
--- a/components/camel-box/pom.xml
+++ b/components/camel-box/pom.xml
@@ -24,7 +24,7 @@
   <parent>
     <artifactId>components</artifactId>
     <groupId>org.apache.camel</groupId>
-    <version>2.23.0-SNAPSHOT</version>
+    <version>2.24.0-SNAPSHOT</version>
   </parent>
 
   <artifactId>camel-box-parent</artifactId>
diff --git a/components/camel-braintree/pom.xml b/components/camel-braintree/pom.xml
index 737a743baf7..bddc2fa1973 100644
--- a/components/camel-braintree/pom.xml
+++ b/components/camel-braintree/pom.xml
@@ -24,7 +24,7 @@
   <parent>
     <groupId>org.apache.camel</groupId>
     <artifactId>components</artifactId>
-    <version>2.23.0-SNAPSHOT</version>
+    <version>2.24.0-SNAPSHOT</version>
   </parent>
 
   <artifactId>camel-braintree</artifactId>
diff --git a/components/camel-cache/pom.xml b/components/camel-cache/pom.xml
index 4984ce71180..5a3eecc31cd 100644
--- a/components/camel-cache/pom.xml
+++ b/components/camel-cache/pom.xml
@@ -23,7 +23,7 @@
     <parent>
         <groupId>org.apache.camel</groupId>
         <artifactId>components</artifactId>
-        <version>2.23.0-SNAPSHOT</version>
+        <version>2.24.0-SNAPSHOT</version>
     </parent>
 
     <artifactId>camel-cache</artifactId>
diff --git a/components/camel-caffeine/pom.xml b/components/camel-caffeine/pom.xml
index 0f7353bca4c..0ba9925f5da 100644
--- a/components/camel-caffeine/pom.xml
+++ b/components/camel-caffeine/pom.xml
@@ -24,7 +24,7 @@
   <parent>
     <groupId>org.apache.camel</groupId>
     <artifactId>components</artifactId>
-    <version>2.23.0-SNAPSHOT</version>
+    <version>2.24.0-SNAPSHOT</version>
   </parent>
 
   <artifactId>camel-caffeine</artifactId>
diff --git a/components/camel-cassandraql/pom.xml b/components/camel-cassandraql/pom.xml
index 36c975ba2da..c0df2a9272d 100644
--- a/components/camel-cassandraql/pom.xml
+++ b/components/camel-cassandraql/pom.xml
@@ -25,7 +25,7 @@
   <parent>
     <groupId>org.apache.camel</groupId>
     <artifactId>components</artifactId>
-    <version>2.23.0-SNAPSHOT</version>
+    <version>2.24.0-SNAPSHOT</version>
   </parent>
 
   <artifactId>camel-cassandraql</artifactId>
diff --git a/components/camel-castor/pom.xml b/components/camel-castor/pom.xml
index d5b4c483cc9..909322b7c4e 100644
--- a/components/camel-castor/pom.xml
+++ b/components/camel-castor/pom.xml
@@ -23,7 +23,7 @@
     <parent>
         <groupId>org.apache.camel</groupId>
         <artifactId>components</artifactId>
-        <version>2.23.0-SNAPSHOT</version>
+        <version>2.24.0-SNAPSHOT</version>
     </parent>
 
     <artifactId>camel-castor</artifactId>
diff --git a/components/camel-cdi/pom.xml b/components/camel-cdi/pom.xml
index 41ea258c997..f31fa11f114 100644
--- a/components/camel-cdi/pom.xml
+++ b/components/camel-cdi/pom.xml
@@ -23,7 +23,7 @@
   <parent>
     <groupId>org.apache.camel</groupId>
     <artifactId>components</artifactId>
-    <version>2.23.0-SNAPSHOT</version>
+    <version>2.24.0-SNAPSHOT</version>
   </parent>
 
   <artifactId>camel-cdi</artifactId>
diff --git a/components/camel-chatscript/pom.xml b/components/camel-chatscript/pom.xml
new file mode 100644
index 00000000000..5e2cc870b35
--- /dev/null
+++ b/components/camel-chatscript/pom.xml
@@ -0,0 +1,108 @@
+<?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>components</artifactId>
+    <version>2.24.0-SNAPSHOT</version>
+</parent>
+    
+  <groupId>org.apache.camel.component</groupId>
+  <artifactId>camel-chatscript</artifactId>
+  <packaging>jar</packaging>
+
+  <name>Camel :: ChatScript</name>
+  <description>Camel support for ChatScript</description>
+
+  <properties>
+    <camel.osgi.export.pkg>org.apache.camel.component.chatscript.*</camel.osgi.export.pkg>
+    <camel.osgi.export.service>org.apache.camel.spi.ComponentResolver;component=chatscript</camel.osgi.export.service>
+</properties>
+  <dependencies>
+    <dependency>
+      <groupId>org.apache.camel</groupId>
+      <artifactId>camel-core</artifactId>
+    </dependency>  
+    <!-- for testing -->
+    <dependency>
+      <groupId>org.apache.camel</groupId>
+      <artifactId>camel-test</artifactId>
+      <scope>test</scope>
+    </dependency>
+    <!-- logging -->
+    <dependency>
+      <groupId>org.slf4j</groupId>
+      <artifactId>slf4j-api</artifactId>
+    </dependency>      
+    <dependency>
+      <groupId>org.slf4j</groupId>
+      <artifactId>slf4j-log4j12</artifactId>
+      <scope>test</scope>
+    </dependency>
+    <dependency>
+      <groupId>log4j</groupId> 
+      <artifactId>log4j</artifactId> 
+      <scope>test</scope> 
+    </dependency>
+	 <dependency> 
+    	<groupId>com.fasterxml.jackson.core</groupId>
+    	<artifactId>jackson-databind</artifactId>
+    	<version>${jackson2-version}</version>
+    </dependency>
+  </dependencies>
+  <profiles>
+        <profile>
+            <id>chatscript-skip-tests</id>
+            <activation>
+                <activeByDefault>true</activeByDefault>
+            </activation>
+            <build>
+                <plugins>
+                    <plugin>
+                        <artifactId>maven-surefire-plugin</artifactId>
+                        <configuration>
+                            <skipTests>true</skipTests>
+                        </configuration>
+                    </plugin>
+                </plugins>
+            </build>
+        </profile>
+ 	<profile>
+            <id>chatscript-test</id>
+            <activation>
+                <activeByDefault>false</activeByDefault>
+            </activation>
+            <build>
+                <plugins>
+                    <plugin>
+                        <artifactId>maven-surefire-plugin</artifactId>
+                        <configuration>
+                            <skipTests>false</skipTests>
+                        </configuration>
+                    </plugin>
+                </plugins>
+            </build>
+        </profile>
+</profiles>
+
+</project>
+
diff --git a/components/camel-chatscript/src/main/docs/camel-chatscript-component.adoc b/components/camel-chatscript/src/main/docs/camel-chatscript-component.adoc
new file mode 100644
index 00000000000..a5d73adac97
--- /dev/null
+++ b/components/camel-chatscript/src/main/docs/camel-chatscript-component.adoc
@@ -0,0 +1,77 @@
+[[ChatScript-component]]
+== ChatScript Component
+
+*Available as of Camel version 2.24*
+
+The *ChatScript:* component allows you to interact with ChatScript Server and have conversations. This component is stateless and relies on ChatScript to maintain chat history. 
+
+Original ChatScript is available here : https://github.com/bwilcox-1234/ChatScript
+
+This component expects a JSON having the following fields:
+{
+username:
+botname:
+body:
+}
+
+Refer ChatScriptMessage.java and samples  
+
+Maven users will need to add the following dependency to their `pom.xml`
+for this component:
+
+[source,xml]
+------------------------------------------------------------
+<dependency>
+    <groupId>org.apache.camel</groupId>
+      <artifactId>camel-chatscript</artifactId>
+    <version>x.x.x</version>
+    <!-- use the same version as your Camel core version -->
+</dependency>
+------------------------------------------------------------
+
+### URI format
+[source,java]
+-------------------------------------------------------------------------------------------------------------------------
+ChatScript:host:[port]/botName[?options]
+-------------------------------------------------------------------------------------------------------------------------
+
+### Options
+
+// component options: START
+This component has one option resetchat which when set to true will issue :reset command to CS when the endpoint is created.
+// component options: END
+
+// endpoint options: START
+The ChatScript endpoint is configured using URI syntax:
+
+----
+ChatScript:hostname:port/BotName
+----
+
+with the following path and query parameters:
+
+==== Path Parameters (1 parameters):
+
+
+[width="100%",cols="2,5,^1,2",options="header"]
+|===
+| Name | Description | Default | Type
+| *hostname* | *Required* Host where ChatScript is running in server mode | none | String |
+| *port* | *Required* Port on which ChatScript is listening to| 1024 | String |
+| *botName* | *Required* Name of the Bot in CS to converse with | Harry | String |
+|===
+
+
+==== Query Parameters (8 parameters):
+
+
+[width="100%",cols="2,5,^1,2",options="header"]
+|===
+| Name | Description | Default | Type
+| *resetchat* (common) | *Optional* Issues :reset command to start a new conversation everytime |  | String |
+
+// endpoint options: END
+// spring-boot-auto-configure options: START
+
+
+
diff --git a/components/camel-chatscript/src/main/docs/chatscript-component.adoc b/components/camel-chatscript/src/main/docs/chatscript-component.adoc
new file mode 100644
index 00000000000..4a9850a6279
--- /dev/null
+++ b/components/camel-chatscript/src/main/docs/chatscript-component.adoc
@@ -0,0 +1,79 @@
+[[chatscript-component]]
+== ChatScript Component
+== ChatScript Component
+*Available as of Camel version 2.24*
+
+
+*Available as of Camel version 2.24*
+
+The *ChatScript:* component allows you to interact with ChatScript Server and have conversations. This component is stateless and relies on ChatScript to maintain chat history. 
+
+Original ChatScript is available here : https://github.com/bwilcox-1234/ChatScript
+
+This component expects a JSON having the following fields:
+{
+username:
+botname:
+body:
+}
+
+Refer ChatScriptMessage.java and samples  
+
+Maven users will need to add the following dependency to their `pom.xml`
+for this component:
+
+[source,xml]
+------------------------------------------------------------
+<dependency>
+    <groupId>org.apache.camel</groupId>
+      <artifactId>camel-chatscript</artifactId>
+    <version>x.x.x</version>
+    <!-- use the same version as your Camel core version -->
+</dependency>
+------------------------------------------------------------
+
+### URI format
+[source,java]
+-------------------------------------------------------------------------------------------------------------------------
+ChatScript:host:[port]/botName[?options]
+-------------------------------------------------------------------------------------------------------------------------
+
+### Options
+
+// component options: START
+The ChatScript component has no options.
+// component options: END
+
+// endpoint options: START
+The ChatScript endpoint is configured using URI syntax:
+
+----
+chatscript:host:port/botname
+----
+
+with the following path and query parameters:
+
+==== Path Parameters (3 parameters):
+
+
+[width="100%",cols="2,5,^1,2",options="header"]
+|===
+| Name | Description | Default | Type
+| *host* | *Required* Hostname or IP of the server on which CS server is running |  | String
+| *port* | Port on which ChatScript is listening to | 1024 | int
+| *botname* | *Required* Name of the Bot in CS to converse with |  | String
+|===
+
+
+==== Query Parameters (3 parameters):
+
+
+[width="100%",cols="2,5,^1,2",options="header"]
+|===
+| Name | Description | Default | Type
+| *synchronous* (advanced) | Sets whether synchronous processing should be strictly used, or Camel is allowed to use asynchronous processing (if supported). | false | boolean
+| *resetchat* (reset) | Issues :reset command to start a new conversation everytime | false | boolean
+| *chatusername* (username) | Username who initializes the CS conversation. To be set when chat is initialized from camel route |  | String
+|===
+// endpoint options: END
+// spring-boot-auto-configure options: START
\ No newline at end of file
diff --git a/components/camel-chatscript/src/main/java/org/apache/camel/component/chatscript/ChatScriptBot.java b/components/camel-chatscript/src/main/java/org/apache/camel/component/chatscript/ChatScriptBot.java
new file mode 100644
index 00000000000..aa2954f097c
--- /dev/null
+++ b/components/camel-chatscript/src/main/java/org/apache/camel/component/chatscript/ChatScriptBot.java
@@ -0,0 +1,147 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.camel.component.chatscript;
+
+import java.io.BufferedReader;
+import java.io.IOException;
+import java.io.InputStreamReader;
+import java.io.PrintWriter;
+import java.net.Socket;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+public class ChatScriptBot {
+
+    private static final transient Logger LOG = LoggerFactory.getLogger(ChatScriptBot.class);
+    String host;
+    int port;
+    String message;
+    String botName;
+    String userName;
+    boolean initialized;
+
+    public ChatScriptBot(String iHost, int port, String iBotName, String iUserName) {
+        this.host = iHost;
+        this.port = port;
+        this.botName = iBotName;
+        this.userName = iUserName;
+    }
+
+    public String sendChat(String input) throws Exception {
+        if (!initialized) {
+            return init(null);
+        }
+        ChatScriptMessage g = new ChatScriptMessage(this.userName, this.botName, input);
+        return doMessage(g.toCSFormat());
+    }
+
+    public String sendChat(ChatScriptMessage input) throws Exception {
+        if (!initialized) {
+            return init(input);
+        }
+        return doMessage(input.toCSFormat());
+    }
+
+    private String doMessage(ChatScriptMessage msg) throws Exception {
+        return doMessage(msg.toCSFormat());
+    }
+
+    private String doMessage(String msg) throws Exception {
+        Socket echoSocket;
+        String resp = "";
+
+        try {
+            echoSocket = new Socket(this.host, this.port);
+            PrintWriter out = new PrintWriter(echoSocket.getOutputStream(), true);
+            BufferedReader in = new BufferedReader(new InputStreamReader(echoSocket.getInputStream()));
+            out.println(msg);
+            resp = in.readLine();
+            echoSocket.close();
+        } catch (IOException e) {
+            e.printStackTrace();
+            throw new Exception("Unable to send message to ChatScript Server. Reason:" + e.getMessage());
+        }
+
+        return resp;
+
+    }
+
+    public String init(ChatScriptMessage input) throws Exception {
+        ChatScriptMessage g = new ChatScriptMessage(input.getUserName(), this.botName, null);
+        String response = doMessage(g);
+        LOG.info("Conversation started between the bot " + this.botName + " and " + input.getUserName());
+        initialized = true;
+        return response;
+    }
+
+    public String getBotType() {
+        return "ChatSCript";
+    }
+
+    public void reset() {
+        //TODO
+    }
+
+    public String getHost() {
+        return host;
+    }
+
+    public void setHost(String host) {
+        this.host = host;
+    }
+
+    public int getPort() {
+        return port;
+    }
+
+    public void setPort(int iPort) {
+        this.port = iPort;
+    }
+
+    public String getMessage() {
+        return message;
+    }
+
+    public void setMessage(String iMessage) {
+        this.message = iMessage;
+    }
+
+    public String getBotName() {
+        return botName;
+    }
+
+    public void setBotName(String iBotName) {
+        this.botName = iBotName;
+    }
+
+    public String getUserName() {
+        return userName;
+    }
+
+    public void setUserName(String iUserName) {
+        this.userName = iUserName;
+    }
+
+    public boolean isInitialized() {
+        return initialized;
+    }
+
+    public void setInitialized(boolean initialized) {
+        this.initialized = initialized;
+    }
+
+}
diff --git a/components/camel-chatscript/src/main/java/org/apache/camel/component/chatscript/ChatScriptComponent.java b/components/camel-chatscript/src/main/java/org/apache/camel/component/chatscript/ChatScriptComponent.java
new file mode 100644
index 00000000000..7d34188ab48
--- /dev/null
+++ b/components/camel-chatscript/src/main/java/org/apache/camel/component/chatscript/ChatScriptComponent.java
@@ -0,0 +1,34 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.camel.component.chatscript;
+
+import java.util.Map;
+
+import org.apache.camel.Endpoint;
+import org.apache.camel.impl.DefaultComponent;
+
+/**
+ * Represents the component that manages {@link ChatScriptEndpoint}.
+ */
+public class ChatScriptComponent extends DefaultComponent {
+
+    protected Endpoint createEndpoint(String uri, String remaining, Map<String, Object> parameters) throws Exception {
+        Endpoint endpoint = new ChatScriptEndpoint(uri, remaining, this);
+        setProperties(endpoint, parameters);
+        return endpoint;
+    }
+}
diff --git a/components/camel-chatscript/src/main/java/org/apache/camel/component/chatscript/ChatScriptEndpoint.java b/components/camel-chatscript/src/main/java/org/apache/camel/component/chatscript/ChatScriptEndpoint.java
new file mode 100644
index 00000000000..7e6141e2fbd
--- /dev/null
+++ b/components/camel-chatscript/src/main/java/org/apache/camel/component/chatscript/ChatScriptEndpoint.java
@@ -0,0 +1,143 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.camel.component.chatscript;
+
+import java.net.URI;
+import java.net.URISyntaxException;
+
+import org.apache.camel.Consumer;
+import org.apache.camel.Processor;
+import org.apache.camel.Producer;
+import org.apache.camel.impl.DefaultEndpoint;
+import org.apache.camel.spi.Metadata;
+import org.apache.camel.spi.UriEndpoint;
+import org.apache.camel.spi.UriParam;
+import org.apache.camel.spi.UriPath;
+import org.apache.camel.util.ObjectHelper;
+import static org.apache.camel.component.chatscript.utils.ChatScriptConstants.*;
+
+/**
+ * Represents a ChatScript endpoint.
+ */
+@UriEndpoint(firstVersion = "2.24.0", scheme = "chatscript", title = "ChatScript", syntax = "chatscript:host:port/botname",  producerOnly = true, label = "ai,chatscript")
+public class ChatScriptEndpoint extends DefaultEndpoint { 
+    private static final String URI_ERROR = "Invalid URI. Format must be of the form chatscript://host[:port]/botname?[options...]";
+    @UriPath (description = "Hostname or IP of the server on which CS server is running") 
+    @Metadata(required = "true")
+    private String host;
+    @UriPath(description = "Port on which ChatScript is listening to", defaultValue = "" + DEFAULT_PORT)
+    private int port;
+    @UriPath(description = "Name of the Bot in CS to converse with")
+    @Metadata(required = "true")
+    private String botname;
+    @UriParam(description = "Username who initializes the CS conversation. To be set when chat is initialized from camel route", label = "username")
+    private String chatusername;
+    @UriParam (description = "Issues :reset command to start a new conversation everytime", label = "reset", defaultValue = "false")
+    private boolean resetchat;
+    private ChatScriptBot bot;
+
+    public ChatScriptEndpoint(String endpointUri) {
+        super(endpointUri);
+    }
+    public ChatScriptEndpoint() {
+    }
+
+    public ChatScriptEndpoint(String uri, String remaining,
+            ChatScriptComponent component) throws URISyntaxException {
+        super(uri, component);
+
+        URI remainingUri = new URI("tcp://" + remaining);
+        port = remainingUri.getPort() == -1 ? DEFAULT_PORT : remainingUri.getPort();
+        if (ObjectHelper.isEmpty(remainingUri.getPath())) {
+            throw new IllegalArgumentException(URI_ERROR);
+        }
+        host = remainingUri.getHost();
+        if (ObjectHelper.isEmpty(host)) { 
+            throw new IllegalArgumentException(URI_ERROR);
+        }
+        botname = remainingUri.getPath();
+        if (ObjectHelper.isEmpty(botname)) {
+            throw new IllegalArgumentException(URI_ERROR);
+        }
+        botname = botname.substring(1);
+        setBot(new ChatScriptBot(getHostName(), getPort(), getBotName(), ""));
+
+    }
+    public boolean isResetChat() {
+        return resetchat;
+    }
+
+    public void setResetchat(boolean resetChat) {
+        this.resetchat = resetChat;
+    }
+
+    public String getChatUserName() {
+        return chatusername;
+    }
+
+    public void setChatUserName(String chatusername) {
+        this.chatusername = chatusername;
+    }
+
+    public Producer createProducer() throws Exception {
+        return new ChatScriptProducer(this);
+    }
+
+    public Consumer createConsumer(Processor processor) throws Exception {
+        throw new UnsupportedOperationException("Chatscript consumer not supported");
+    }
+
+    public boolean isSingleton() {
+        return true;
+    }
+
+    public String getHostName() {
+        return host;
+    }
+
+    public void setHostName(String hostName) {
+        this.host = hostName;
+    }
+
+    public int getPort() {
+        return port;
+    }
+
+    public void setPort(int port) {
+        this.port = port;
+    }
+
+    public String getBotName() {
+        return botname;
+    }
+
+    public void setBotName(String botname) {
+        this.botname = botname;
+    }
+
+    public static int getDefaultPort() {
+        return DEFAULT_PORT;
+    }
+
+    public ChatScriptBot getBot() {
+        return bot;
+    }
+
+    public void setBot(ChatScriptBot thisBot) {
+        this.bot = thisBot;
+    }
+}
diff --git a/components/camel-chatscript/src/main/java/org/apache/camel/component/chatscript/ChatScriptMessage.java b/components/camel-chatscript/src/main/java/org/apache/camel/component/chatscript/ChatScriptMessage.java
new file mode 100644
index 00000000000..c69ac8c1835
--- /dev/null
+++ b/components/camel-chatscript/src/main/java/org/apache/camel/component/chatscript/ChatScriptMessage.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.component.chatscript;
+
+import com.fasterxml.jackson.annotation.JsonProperty;
+
+public class ChatScriptMessage {
+    @JsonProperty("username")
+    private String username;
+    @JsonProperty("botname")
+    private String botname;
+    @JsonProperty("message")
+    private String body;
+    @JsonProperty("response")
+    private String reply;
+    public ChatScriptMessage(final String userName, final String botName, final String iBody) {
+        this.username = userName;
+        this.botname = botName;
+        this.body = iBody;
+    }
+    public ChatScriptMessage() {
+
+    }
+
+    public String getUserName() {
+        return username;
+    }
+
+    public void setUserName(String userName) {
+        this.username = userName;
+    }
+
+    public String getBotName() {
+        return botname;
+    }
+
+    public void setBotName(String botName) {
+        this.botname = botName;
+    }
+
+    public String getBody() {
+        return body;
+    }
+
+    public void setBody(String iBody) {
+        this.body = iBody;
+    }
+    public String getReply() {
+        return reply;
+    }
+    public void setReply(String iReply) {
+        this.reply = iReply;
+    }
+    public String toCSFormat() {
+        String s;
+        final char nullChar = (char) 0;
+        s = this.username + nullChar + this.botname + nullChar + this.body + nullChar;
+        return s;
+    }
+    @Override
+    public String toString() {
+        return "ChatScriptMessage [username=" + username + ", botname=" + botname + ", message=" + body + ", reply=" + reply + "]";
+    }
+
+
+}
\ No newline at end of file
diff --git a/components/camel-chatscript/src/main/java/org/apache/camel/component/chatscript/ChatScriptProducer.java b/components/camel-chatscript/src/main/java/org/apache/camel/component/chatscript/ChatScriptProducer.java
new file mode 100644
index 00000000000..cccf0930546
--- /dev/null
+++ b/components/camel-chatscript/src/main/java/org/apache/camel/component/chatscript/ChatScriptProducer.java
@@ -0,0 +1,73 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.camel.component.chatscript;
+
+import com.fasterxml.jackson.databind.ObjectMapper;
+import org.apache.camel.Exchange;
+import org.apache.camel.impl.DefaultProducer;
+
+/**
+ * The ChatScript producer.
+ */
+public class ChatScriptProducer extends DefaultProducer {
+    private ChatScriptEndpoint endpoint;
+    private ObjectMapper mapper = new ObjectMapper();
+    public ChatScriptProducer(ChatScriptEndpoint endpoint) {
+        super(endpoint);
+        this.endpoint = endpoint;
+
+        if (endpoint.isResetChat()) {
+            this.endpoint.getBot().reset();
+        }
+    }
+
+    public void process(Exchange exchange) throws Exception {
+
+        Object body = exchange.getIn().getBody();
+        ChatScriptMessage inputMessage = new ChatScriptMessage();
+        /* use can pass message object as json or the object it self */
+        if (!(body instanceof ChatScriptMessage)) {
+            inputMessage = buildMessage(body);
+        } else {
+            inputMessage = (ChatScriptMessage) body;
+        }
+        inputMessage.setBotName(endpoint.getBotName());
+        String response = this.endpoint.getBot().sendChat(inputMessage);
+        inputMessage.setReply(response);
+        exchange.getOut().setBody(inputMessage);
+    }
+
+    private ChatScriptMessage buildMessage(Object body) throws Exception {
+
+        if (body instanceof String) {
+            return createMessage(String.valueOf(body));
+        }
+        return null;
+    }
+
+    private ChatScriptMessage createMessage(String message) throws Exception {
+        ChatScriptMessage ret = null;
+        try {
+            ret = mapper.readValue(message, ChatScriptMessage.class);
+        } catch (Exception e) {
+            e.printStackTrace();
+            throw new Exception("Unable to parse the input message. Error Message" + e.getMessage());
+        } 
+        return ret;
+    }
+
+}
diff --git a/components/camel-chatscript/src/main/java/org/apache/camel/component/chatscript/utils/ChatScriptConstants.java b/components/camel-chatscript/src/main/java/org/apache/camel/component/chatscript/utils/ChatScriptConstants.java
new file mode 100644
index 00000000000..7bb12f8a529
--- /dev/null
+++ b/components/camel-chatscript/src/main/java/org/apache/camel/component/chatscript/utils/ChatScriptConstants.java
@@ -0,0 +1,27 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.camel.component.chatscript.utils;
+
+public final class ChatScriptConstants {
+    public static final int DEFAULT_PORT = 1024;
+
+    private ChatScriptConstants() {
+        // restrict instantiation
+    }
+
+
+}
\ No newline at end of file
diff --git a/components/camel-chatscript/src/main/resources/META-INF/LICENSE.txt b/components/camel-chatscript/src/main/resources/META-INF/LICENSE.txt
new file mode 100644
index 00000000000..6b0b1270ff0
--- /dev/null
+++ b/components/camel-chatscript/src/main/resources/META-INF/LICENSE.txt
@@ -0,0 +1,203 @@
+
+                                 Apache License
+                           Version 2.0, January 2004
+                        http://www.apache.org/licenses/
+
+   TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
+
+   1. Definitions.
+
+      "License" shall mean the terms and conditions for use, reproduction,
+      and distribution as defined by Sections 1 through 9 of this document.
+
+      "Licensor" shall mean the copyright owner or entity authorized by
+      the copyright owner that is granting the License.
+
+      "Legal Entity" shall mean the union of the acting entity and all
+      other entities that control, are controlled by, or are under common
+      control with that entity. For the purposes of this definition,
+      "control" means (i) the power, direct or indirect, to cause the
+      direction or management of such entity, whether by contract or
+      otherwise, or (ii) ownership of fifty percent (50%) or more of the
+      outstanding shares, or (iii) beneficial ownership of such entity.
+
+      "You" (or "Your") shall mean an individual or Legal Entity
+      exercising permissions granted by this License.
+
+      "Source" form shall mean the preferred form for making modifications,
+      including but not limited to software source code, documentation
+      source, and configuration files.
+
+      "Object" form shall mean any form resulting from mechanical
+      transformation or translation of a Source form, including but
+      not limited to compiled object code, generated documentation,
+      and conversions to other media types.
+
+      "Work" shall mean the work of authorship, whether in Source or
+      Object form, made available under the License, as indicated by a
+      copyright notice that is included in or attached to the work
+      (an example is provided in the Appendix below).
+
+      "Derivative Works" shall mean any work, whether in Source or Object
+      form, that is based on (or derived from) the Work and for which the
+      editorial revisions, annotations, elaborations, or other modifications
+      represent, as a whole, an original work of authorship. For the purposes
+      of this License, Derivative Works shall not include works that remain
+      separable from, or merely link (or bind by name) to the interfaces of,
+      the Work and Derivative Works thereof.
+
+      "Contribution" shall mean any work of authorship, including
+      the original version of the Work and any modifications or additions
+      to that Work or Derivative Works thereof, that is intentionally
+      submitted to Licensor for inclusion in the Work by the copyright owner
+      or by an individual or Legal Entity authorized to submit on behalf of
+      the copyright owner. For the purposes of this definition, "submitted"
+      means any form of electronic, verbal, or written communication sent
+      to the Licensor or its representatives, including but not limited to
+      communication on electronic mailing lists, source code control systems,
+      and issue tracking systems that are managed by, or on behalf of, the
+      Licensor for the purpose of discussing and improving the Work, but
+      excluding communication that is conspicuously marked or otherwise
+      designated in writing by the copyright owner as "Not a Contribution."
+
+      "Contributor" shall mean Licensor and any individual or Legal Entity
+      on behalf of whom a Contribution has been received by Licensor and
+      subsequently incorporated within the Work.
+
+   2. Grant of Copyright License. Subject to the terms and conditions of
+      this License, each Contributor hereby grants to You a perpetual,
+      worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+      copyright license to reproduce, prepare Derivative Works of,
+      publicly display, publicly perform, sublicense, and distribute the
+      Work and such Derivative Works in Source or Object form.
+
+   3. Grant of Patent License. Subject to the terms and conditions of
+      this License, each Contributor hereby grants to You a perpetual,
+      worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+      (except as stated in this section) patent license to make, have made,
+      use, offer to sell, sell, import, and otherwise transfer the Work,
+      where such license applies only to those patent claims licensable
+      by such Contributor that are necessarily infringed by their
+      Contribution(s) alone or by combination of their Contribution(s)
+      with the Work to which such Contribution(s) was submitted. If You
+      institute patent litigation against any entity (including a
+      cross-claim or counterclaim in a lawsuit) alleging that the Work
+      or a Contribution incorporated within the Work constitutes direct
+      or contributory patent infringement, then any patent licenses
+      granted to You under this License for that Work shall terminate
+      as of the date such litigation is filed.
+
+   4. Redistribution. You may reproduce and distribute copies of the
+      Work or Derivative Works thereof in any medium, with or without
+      modifications, and in Source or Object form, provided that You
+      meet the following conditions:
+
+      (a) You must give any other recipients of the Work or
+          Derivative Works a copy of this License; and
+
+      (b) You must cause any modified files to carry prominent notices
+          stating that You changed the files; and
+
+      (c) You must retain, in the Source form of any Derivative Works
+          that You distribute, all copyright, patent, trademark, and
+          attribution notices from the Source form of the Work,
+          excluding those notices that do not pertain to any part of
+          the Derivative Works; and
+
+      (d) If the Work includes a "NOTICE" text file as part of its
+          distribution, then any Derivative Works that You distribute must
+          include a readable copy of the attribution notices contained
+          within such NOTICE file, excluding those notices that do not
+          pertain to any part of the Derivative Works, in at least one
+          of the following places: within a NOTICE text file distributed
+          as part of the Derivative Works; within the Source form or
+          documentation, if provided along with the Derivative Works; or,
+          within a display generated by the Derivative Works, if and
+          wherever such third-party notices normally appear. The contents
+          of the NOTICE file are for informational purposes only and
+          do not modify the License. You may add Your own attribution
+          notices within Derivative Works that You distribute, alongside
+          or as an addendum to the NOTICE text from the Work, provided
+          that such additional attribution notices cannot be construed
+          as modifying the License.
+
+      You may add Your own copyright statement to Your modifications and
+      may provide additional or different license terms and conditions
+      for use, reproduction, or distribution of Your modifications, or
+      for any such Derivative Works as a whole, provided Your use,
+      reproduction, and distribution of the Work otherwise complies with
+      the conditions stated in this License.
+
+   5. Submission of Contributions. Unless You explicitly state otherwise,
+      any Contribution intentionally submitted for inclusion in the Work
+      by You to the Licensor shall be under the terms and conditions of
+      this License, without any additional terms or conditions.
+      Notwithstanding the above, nothing herein shall supersede or modify
+      the terms of any separate license agreement you may have executed
+      with Licensor regarding such Contributions.
+
+   6. Trademarks. This License does not grant permission to use the trade
+      names, trademarks, service marks, or product names of the Licensor,
+      except as required for reasonable and customary use in describing the
+      origin of the Work and reproducing the content of the NOTICE file.
+
+   7. Disclaimer of Warranty. Unless required by applicable law or
+      agreed to in writing, Licensor provides the Work (and each
+      Contributor provides its Contributions) on an "AS IS" BASIS,
+      WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
+      implied, including, without limitation, any warranties or conditions
+      of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
+      PARTICULAR PURPOSE. You are solely responsible for determining the
+      appropriateness of using or redistributing the Work and assume any
+      risks associated with Your exercise of permissions under this License.
+
+   8. Limitation of Liability. In no event and under no legal theory,
+      whether in tort (including negligence), contract, or otherwise,
+      unless required by applicable law (such as deliberate and grossly
+      negligent acts) or agreed to in writing, shall any Contributor be
+      liable to You for damages, including any direct, indirect, special,
+      incidental, or consequential damages of any character arising as a
+      result of this License or out of the use or inability to use the
+      Work (including but not limited to damages for loss of goodwill,
+      work stoppage, computer failure or malfunction, or any and all
+      other commercial damages or losses), even if such Contributor
+      has been advised of the possibility of such damages.
+
+   9. Accepting Warranty or Additional Liability. While redistributing
+      the Work or Derivative Works thereof, You may choose to offer,
+      and charge a fee for, acceptance of support, warranty, indemnity,
+      or other liability obligations and/or rights consistent with this
+      License. However, in accepting such obligations, You may act only
+      on Your own behalf and on Your sole responsibility, not on behalf
+      of any other Contributor, and only if You agree to indemnify,
+      defend, and hold each Contributor harmless for any liability
+      incurred by, or claims asserted against, such Contributor by reason
+      of your accepting any such warranty or additional liability.
+
+   END OF TERMS AND CONDITIONS
+
+   APPENDIX: How to apply the Apache License to your work.
+
+      To apply the Apache License to your work, attach the following
+      boilerplate notice, with the fields enclosed by brackets "[]"
+      replaced with your own identifying information. (Don't include
+      the brackets!)  The text should be enclosed in the appropriate
+      comment syntax for the file format. We also recommend that a
+      file or class name and description of purpose be included on the
+      same "printed page" as the copyright notice for easier
+      identification within third-party archives.
+
+   Copyright [yyyy] [name of copyright owner]
+
+   Licensed 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.
+
diff --git a/components/camel-chatscript/src/main/resources/META-INF/NOTICE.txt b/components/camel-chatscript/src/main/resources/META-INF/NOTICE.txt
new file mode 100644
index 00000000000..2e215bf2e6b
--- /dev/null
+++ b/components/camel-chatscript/src/main/resources/META-INF/NOTICE.txt
@@ -0,0 +1,11 @@
+   =========================================================================
+   ==  NOTICE file corresponding to the section 4 d of                    ==
+   ==  the Apache License, Version 2.0,                                   ==
+   ==  in this case for the Apache Camel distribution.                    ==
+   =========================================================================
+
+   This product includes software developed by
+   The Apache Software Foundation (http://www.apache.org/).
+
+   Please read the different LICENSE files present in the licenses directory of
+   this distribution.
diff --git a/components/camel-chatscript/src/main/resources/META-INF/services/org/apache/camel/component/chatscript b/components/camel-chatscript/src/main/resources/META-INF/services/org/apache/camel/component/chatscript
new file mode 100644
index 00000000000..e6d4bb332eb
--- /dev/null
+++ b/components/camel-chatscript/src/main/resources/META-INF/services/org/apache/camel/component/chatscript
@@ -0,0 +1,18 @@
+#
+# 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.
+#
+
+class=org.apache.camel.component.chatscript.ChatScriptComponent
diff --git a/components/camel-chatscript/src/test/java/org/apache/camel/component/ChatScriptComponentTest.java b/components/camel-chatscript/src/test/java/org/apache/camel/component/ChatScriptComponentTest.java
new file mode 100644
index 00000000000..0704d874e13
--- /dev/null
+++ b/components/camel-chatscript/src/test/java/org/apache/camel/component/ChatScriptComponentTest.java
@@ -0,0 +1,70 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.camel.component;
+
+import com.fasterxml.jackson.core.JsonProcessingException;
+import com.fasterxml.jackson.databind.ObjectMapper;
+import org.apache.camel.builder.RouteBuilder;
+import org.apache.camel.component.chatscript.ChatScriptMessage;
+import org.apache.camel.component.mock.MockEndpoint;
+import org.apache.camel.model.language.SimpleExpression;
+import org.apache.camel.test.junit4.CamelTestSupport;
+import org.junit.Test;
+
+public class ChatScriptComponentTest extends CamelTestSupport {
+
+    @Test
+    public void testChatScript() throws Exception {
+        MockEndpoint mock = getMockEndpoint("mock:result");
+        mock.expectedMinimumMessageCount(1);       
+        Thread.sleep(100);
+        assertMockEndpointsSatisfied();
+    }
+
+    @Override
+    protected RouteBuilder createRouteBuilder() throws Exception {
+        return new RouteBuilder() {
+            public void configure() throws JsonProcessingException {
+                String g = "CS" + Math.random();
+                ChatScriptMessage rqMsg = new ChatScriptMessage(g, "", "");
+                ChatScriptMessage rq2Msg = new ChatScriptMessage(g, "", "Hello");
+                ChatScriptMessage rq3Msg = new ChatScriptMessage(g, "", "No");
+                String rq = "";
+                String rq2 = "";
+                String rq3 = "";
+                try {
+                        rq = new ObjectMapper().writeValueAsString(rqMsg);
+                        rq2 = new ObjectMapper().writeValueAsString(rq2Msg);
+                        rq3 = new ObjectMapper().writeValueAsString(rq3Msg);
+                } catch (JsonProcessingException e) {
+                        e.printStackTrace();
+                }
+                from("timer://foo?repeatCount=1")
+                .setBody(new SimpleExpression(rq))
+                .to("chatscript://localhost:1024/Harry?resetchat=true")
+                .log("Response 2 = ${body}")
+                .setBody(new SimpleExpression(rq2))
+                .to("chatscript://localhost:1024/Harry")
+                .log("Response 3 = ${body}")
+                .setBody(new SimpleExpression(rq3))
+                .to("chatscript://localhost:1024/Harry")
+                .log("Response 4 = ${body}")
+                    .to("mock:result");
+            }
+        };
+    }
+}
diff --git a/components/camel-chatscript/src/test/resources/log4j.properties b/components/camel-chatscript/src/test/resources/log4j.properties
new file mode 100644
index 00000000000..c890e97a57b
--- /dev/null
+++ b/components/camel-chatscript/src/test/resources/log4j.properties
@@ -0,0 +1,33 @@
+## ---------------------------------------------------------------------------
+## 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.
+## ---------------------------------------------------------------------------
+
+# Root logger option
+log4j.rootLogger=DEBUG, file, console
+ 
+# Direct log messages to a log file
+log4j.appender.file=org.apache.log4j.FileAppender
+log4j.appender.file.file=target/test.log
+log4j.appender.file.layout=org.apache.log4j.PatternLayout
+log4j.appender.file.layout.ConversionPattern=%d{yyyy-MM-dd HH:mm:ss} %-5p [%c] (%t) - %m%n
+log4j.appender.file.threshold=DEBUG
+ 
+# Direct log messages to console
+log4j.appender.console=org.apache.log4j.ConsoleAppender
+log4j.appender.console.target=System.out
+log4j.appender.console.layout=org.apache.log4j.PatternLayout
+log4j.appender.console.layout.ConversionPattern=%d{yyyy-MM-dd HH:mm:ss} %-5p [%c] (%t) - %m%n
+log4j.appender.console.threshold=WARN
diff --git a/components/camel-chatscript/src/test/resources/log4j2.properties b/components/camel-chatscript/src/test/resources/log4j2.properties
new file mode 100644
index 00000000000..6642452e819
--- /dev/null
+++ b/components/camel-chatscript/src/test/resources/log4j2.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.
+## ---------------------------------------------------------------------------
+
+appender.file.type = File
+appender.file.name = file
+appender.file.fileName = target/camel-chatscript-test.log
+appender.file.layout.type = PatternLayout
+appender.file.layout.pattern = %d [%-15.15t] %-5p %-30.30c{1} - %m%n
+appender.out.type = Console
+appender.out.name = out
+appender.out.layout.type = PatternLayout
+appender.out.layout.pattern = %d [%-15.15t] %-5p %-30.30c{1} - %m%n
+rootLogger.level = INFO
+rootLogger.appenderRef.file.ref = file
diff --git a/components/camel-chronicle/pom.xml b/components/camel-chronicle/pom.xml
index 8412eebaecb..8e875004618 100644
--- a/components/camel-chronicle/pom.xml
+++ b/components/camel-chronicle/pom.xml
@@ -25,7 +25,7 @@
   <parent>
     <groupId>org.apache.camel</groupId>
     <artifactId>components</artifactId>
-    <version>2.23.0-SNAPSHOT</version>
+    <version>2.24.0-SNAPSHOT</version>
   </parent>
 
   <artifactId>camel-chronicle</artifactId>
diff --git a/components/camel-chunk/pom.xml b/components/camel-chunk/pom.xml
index e0efd92db49..c6eb4f1910d 100644
--- a/components/camel-chunk/pom.xml
+++ b/components/camel-chunk/pom.xml
@@ -23,7 +23,7 @@
   <parent>
     <artifactId>components</artifactId>
     <groupId>org.apache.camel</groupId>
-    <version>2.23.0-SNAPSHOT</version>
+    <version>2.24.0-SNAPSHOT</version>
   </parent>
 
   <artifactId>camel-chunk</artifactId>
diff --git a/components/camel-cm-sms/pom.xml b/components/camel-cm-sms/pom.xml
index e94c1eaf55a..b2cbb7d2d8d 100644
--- a/components/camel-cm-sms/pom.xml
+++ b/components/camel-cm-sms/pom.xml
@@ -24,7 +24,7 @@
   <parent>
     <groupId>org.apache.camel</groupId>
     <artifactId>components</artifactId>
-    <version>2.23.0-SNAPSHOT</version>
+    <version>2.24.0-SNAPSHOT</version>
   </parent>
 
   <artifactId>camel-cm-sms</artifactId>
diff --git a/components/camel-cm-sms/src/main/java/org/apache/camel/component/cm/CMSenderOneMessageImpl.java b/components/camel-cm-sms/src/main/java/org/apache/camel/component/cm/CMSenderOneMessageImpl.java
index 07e0e14c5b3..64bb92d1cce 100644
--- a/components/camel-cm-sms/src/main/java/org/apache/camel/component/cm/CMSenderOneMessageImpl.java
+++ b/components/camel-cm-sms/src/main/java/org/apache/camel/component/cm/CMSenderOneMessageImpl.java
@@ -23,6 +23,7 @@
 import java.nio.charset.Charset;
 import java.util.UUID;
 
+import javax.xml.XMLConstants;
 import javax.xml.parsers.DocumentBuilder;
 import javax.xml.parsers.DocumentBuilderFactory;
 import javax.xml.parsers.ParserConfigurationException;
@@ -90,6 +91,7 @@ private String createXml(final CMMessage message) {
 
             final ByteArrayOutputStream xml = new ByteArrayOutputStream();
             final DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
+            factory.setFeature(XMLConstants.FEATURE_SECURE_PROCESSING, Boolean.TRUE);
             factory.setNamespaceAware(true);
 
             // Get the DocumentBuilder
@@ -158,7 +160,9 @@ private String createXml(final CMMessage message) {
             }
 
             // Creatate XML as String
-            final Transformer aTransformer = TransformerFactory.newInstance().newTransformer();
+            TransformerFactory transformerFactory = TransformerFactory.newInstance();
+            transformerFactory.setFeature(XMLConstants.FEATURE_SECURE_PROCESSING, Boolean.TRUE);
+            final Transformer aTransformer = transformerFactory.newTransformer();
             aTransformer.setOutputProperty(OutputKeys.INDENT, "yes");
             final Source src = new DOMSource(doc);
             final Result dest = new StreamResult(xml);
diff --git a/components/camel-cmis/pom.xml b/components/camel-cmis/pom.xml
index 204db1ce3ac..d2196ca4be1 100644
--- a/components/camel-cmis/pom.xml
+++ b/components/camel-cmis/pom.xml
@@ -23,7 +23,7 @@
     <parent>
         <groupId>org.apache.camel</groupId>
         <artifactId>components</artifactId>
-        <version>2.23.0-SNAPSHOT</version>
+        <version>2.24.0-SNAPSHOT</version>
     </parent>
 
     <artifactId>camel-cmis</artifactId>
diff --git a/components/camel-coap/pom.xml b/components/camel-coap/pom.xml
index e11dfe1485c..d4b991ab932 100644
--- a/components/camel-coap/pom.xml
+++ b/components/camel-coap/pom.xml
@@ -24,7 +24,7 @@
   <parent>
     <groupId>org.apache.camel</groupId>
     <artifactId>components</artifactId>
-    <version>2.23.0-SNAPSHOT</version>
+    <version>2.24.0-SNAPSHOT</version>
   </parent>
 
   <artifactId>camel-coap</artifactId>
diff --git a/components/camel-cometd/pom.xml b/components/camel-cometd/pom.xml
index a2af82d9a87..a2c2f4d440b 100644
--- a/components/camel-cometd/pom.xml
+++ b/components/camel-cometd/pom.xml
@@ -23,7 +23,7 @@
     <parent>
         <groupId>org.apache.camel</groupId>
         <artifactId>components</artifactId>
-        <version>2.23.0-SNAPSHOT</version>
+        <version>2.24.0-SNAPSHOT</version>
     </parent>
 
     <artifactId>camel-cometd</artifactId>
diff --git a/components/camel-consul/pom.xml b/components/camel-consul/pom.xml
index e2722a7c6f5..d9a1d14378f 100644
--- a/components/camel-consul/pom.xml
+++ b/components/camel-consul/pom.xml
@@ -25,7 +25,7 @@
   <parent>
     <groupId>org.apache.camel</groupId>
     <artifactId>components</artifactId>
-    <version>2.23.0-SNAPSHOT</version>
+    <version>2.24.0-SNAPSHOT</version>
   </parent>
 
   <artifactId>camel-consul</artifactId>
diff --git a/components/camel-context/pom.xml b/components/camel-context/pom.xml
index 91482992149..6cf017548f3 100644
--- a/components/camel-context/pom.xml
+++ b/components/camel-context/pom.xml
@@ -23,7 +23,7 @@
     <parent>
         <groupId>org.apache.camel</groupId>
         <artifactId>components</artifactId>
-        <version>2.23.0-SNAPSHOT</version>
+        <version>2.24.0-SNAPSHOT</version>
     </parent>
 
     <artifactId>camel-context</artifactId>
diff --git a/components/camel-corda/.gitignore b/components/camel-corda/.gitignore
new file mode 100644
index 00000000000..f1ea348215c
--- /dev/null
+++ b/components/camel-corda/.gitignore
@@ -0,0 +1,6 @@
+**/.DS_Store
+.DS_Store
+target
+.idea
+*.iml
+*.log
diff --git a/components/camel-corda/README.md b/components/camel-corda/README.md
new file mode 100644
index 00000000000..ddbbbad0564
--- /dev/null
+++ b/components/camel-corda/README.md
@@ -0,0 +1,3 @@
+# camel-corda
+
+[Apache Camel](http://camel.apache.org/) connector for R3's [Corda](https://www.corda.net/) blockchain platform using corda-rpc library. 
diff --git a/components/camel-corda/pom.xml b/components/camel-corda/pom.xml
new file mode 100644
index 00000000000..6cc750c1c44
--- /dev/null
+++ b/components/camel-corda/pom.xml
@@ -0,0 +1,84 @@
+<?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>components</artifactId>
+        <version>2.24.0-SNAPSHOT</version>
+      </parent>
+
+      <artifactId>camel-corda</artifactId>
+      <packaging>jar</packaging>
+
+      <name>Camel :: Corda</name>
+      <description>Camel Corda which is based on corda-rpc support</description>
+
+    <properties>
+        <camel.osgi.export.pkg>org.apache.camel.component.corda.*</camel.osgi.export.pkg>
+        <camel.osgi.export.service>org.apache.camel.spi.ComponentResolver;component=corda</camel.osgi.export.service>
+    </properties>
+
+    <dependencies>
+        <dependency>
+            <groupId>org.apache.camel</groupId>
+            <artifactId>camel-core</artifactId>
+        </dependency>
+        <dependency>
+            <groupId>net.corda</groupId>
+            <artifactId>corda-rpc</artifactId>
+        </dependency>
+        <dependency>
+            <groupId>org.osgi</groupId>
+            <artifactId>org.osgi.core</artifactId>
+            <scope>provided</scope>
+            <optional>true</optional>
+        </dependency>
+
+        <!-- for testing -->
+        <dependency>
+            <groupId>org.apache.camel</groupId>
+            <artifactId>camel-test</artifactId>
+            <scope>test</scope>
+        </dependency>
+        <dependency>
+            <groupId>org.apache.logging.log4j</groupId>
+            <artifactId>log4j-api</artifactId>
+            <scope>test</scope>
+        </dependency>
+        <dependency>
+            <groupId>org.apache.logging.log4j</groupId>
+            <artifactId>log4j-core</artifactId>
+            <scope>test</scope>
+        </dependency>
+        <dependency>
+            <groupId>org.apache.logging.log4j</groupId>
+            <artifactId>log4j-slf4j-impl</artifactId>
+            <scope>test</scope>
+        </dependency>
+        <dependency>
+            <groupId>org.mockito</groupId>
+            <artifactId>mockito-core</artifactId>
+            <scope>test</scope>
+        </dependency>
+    </dependencies>
+
+</project>
diff --git a/components/camel-corda/src/main/docs/corda-component.adoc b/components/camel-corda/src/main/docs/corda-component.adoc
new file mode 100644
index 00000000000..9ce7fd31c56
--- /dev/null
+++ b/components/camel-corda/src/main/docs/corda-component.adoc
@@ -0,0 +1,139 @@
+[[corda-component]]
+== corda Component
+
+*Available as of Camel version 2.23*
+
+
+The *Corda* blockchain component uses the https://www.corda.net/[corda] rpc client
+
+Maven users will need to add the following dependency to their `pom.xml`
+for this component:
+
+[source,xml]
+------------------------------------------------------------
+<dependency>
+    <groupId>org.apache.camel</groupId>
+    <artifactId>camel-corda</artifactId>
+    <version>x.x.x</version>
+    <!-- use the same version as your Camel core version -->
+</dependency>
+------------------------------------------------------------
+
+=== URI Format
+
+[source,text]
+----
+corda://<host:port>[?options]
+----
+
+=== Corda Options
+
+
+// component options: START
+The corda component supports 2 options, which are listed below.
+
+
+
+[width="100%",cols="2,5,^1,2",options="header"]
+|===
+| Name | Description | Default | Type
+| *configuration* (common) | Default configuration |  | CordaConfiguration
+| *resolveProperty Placeholders* (advanced) | Whether the component should resolve property placeholders on itself when starting. Only properties which are of String type can use property placeholders. | true | boolean
+|===
+// component options: END
+
+
+// endpoint options: START
+The corda endpoint is configured using URI syntax:
+
+----
+corda:url
+----
+
+with the following path and query parameters:
+
+==== Path Parameters (1 parameters):
+
+
+[width="100%",cols="2,5,^1,2",options="header"]
+|===
+| Name | Description | Default | Type
+| *configuration* | *Required* URL to the corda node |  | CordaConfiguration
+|===
+
+
+==== Query Parameters (4 parameters):
+
+
+[width="100%",cols="2,5,^1,2",options="header"]
+|===
+| Name | Description | Default | Type
+| *bridgeErrorHandler* (consumer) | Allows for bridging the consumer to the Camel routing Error Handler, which mean any exceptions occurred while the consumer is trying to pickup incoming messages, or the likes, will now be processed as a message and handled by the routing Error Handler. By default the consumer will use the org.apache.camel.spi.ExceptionHandler to deal with exceptions, that will be logged at WARN or ERROR level and ignored. | false | boolean
+| *exceptionHandler* (consumer) | To let the consumer use a custom ExceptionHandler. Notice if the option bridgeErrorHandler is enabled then this option is not in use. By default the consumer will deal with exceptions, that will be logged at WARN or ERROR level and ignored. |  | ExceptionHandler
+| *exchangePattern* (consumer) | Sets the exchange pattern when the consumer creates an exchange. |  | ExchangePattern
+| *synchronous* (advanced) | Sets whether synchronous processing should be strictly used, or Camel is allowed to use asynchronous processing (if supported). | false | boolean
+|===
+// endpoint options: END
+// spring-boot-auto-configure options: START
+=== Spring Boot Auto-Configuration
+
+
+The component supports 14 options, which are listed below.
+
+
+
+[width="100%",cols="2,5,^1,2",options="header"]
+|===
+| Name | Description | Default | Type
+| *camel.component.corda.configuration.arguments* |  |  | Object[]
+| *camel.component.corda.configuration.contract-state-class* |  |  | Class
+| *camel.component.corda.configuration.flow-loci-class* |  |  | Class
+| *camel.component.corda.configuration.host* |  |  | String
+| *camel.component.corda.configuration.operation* |  |  | String
+| *camel.component.corda.configuration.page-specification* |  |  | PageSpecification
+| *camel.component.corda.configuration.password* |  |  | String
+| *camel.component.corda.configuration.port* |  |  | Integer
+| *camel.component.corda.configuration.process-snapshot* |  |  | Boolean
+| *camel.component.corda.configuration.query-criteria* |  |  | QueryCriteria
+| *camel.component.corda.configuration.sort* |  |  | Sort
+| *camel.component.corda.configuration.username* |  |  | String
+| *camel.component.corda.enabled* | Enable corda component | true | Boolean
+| *camel.component.corda.resolve-property-placeholders* | Whether the component should resolve property placeholders on itself when starting. Only properties which are of String type can use property placeholders. | true | Boolean
+|===
+// spring-boot-auto-configure options: END
+
+
+
+You can append query options to the URI in the following format,
+?options=value&option2=value&...
+
+
+### Message Headers
+
+[width="100%",cols="10%,90%",options="header",]
+|=======================================================================
+|Header |Description
+
+|`All URI options` |All URI options can also be set as exchange headers.
+
+|=======================================================================
+
+
+
+### Samples
+
+Subscribe for new vault state changes:
+
+[source,java]
+---------------------------------------------------------------------------------------------
+from("corda://localhost:10006?username=user1&password=test?operation=VAULT_TRACK&contractStateClass=#contractStateClass")
+    .to("jms:queue:vault");
+---------------------------------------------------------------------------------------------
+
+Read the node information:
+
+[source,java]
+--------------------------------------------------------
+from("direct:start")
+    .to("corda://localhost:10006?username=user1&password=test?operation=NODE_INFO");
+--------------------------------------------------------
diff --git a/components/camel-corda/src/main/java/org/apache/camel/component/corda/CordaComponent.java b/components/camel-corda/src/main/java/org/apache/camel/component/corda/CordaComponent.java
new file mode 100644
index 00000000000..04cf6d547d8
--- /dev/null
+++ b/components/camel-corda/src/main/java/org/apache/camel/component/corda/CordaComponent.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.component.corda;
+
+import java.util.Map;
+import org.apache.camel.CamelContext;
+import org.apache.camel.Endpoint;
+import org.apache.camel.impl.DefaultComponent;
+import org.apache.camel.spi.Metadata;
+
+/**
+ * Represents the component that manages {@link CordaComponent}.
+ */
+public class CordaComponent extends DefaultComponent {
+
+    @Metadata(description = "Default configuration")
+    private CordaConfiguration configuration;
+
+    public CordaComponent() {
+    }
+
+    public CordaComponent(CamelContext camelContext) {
+        super(camelContext);
+    }
+
+    public CordaConfiguration getConfiguration() {
+        return configuration;
+    }
+
+    public void setConfiguration(CordaConfiguration configuration) {
+        this.configuration = configuration;
+    }
+
+    protected Endpoint createEndpoint(String uri, final String remaining, final Map<String, Object> parameters) throws Exception {
+        CordaConfiguration conf =  configuration != null ? configuration.copy() : new CordaConfiguration();
+        setProperties(conf, parameters);
+        return new CordaEndpoint(uri, remaining, this, conf);
+    }
+
+}
diff --git a/components/camel-corda/src/main/java/org/apache/camel/component/corda/CordaConfiguration.java b/components/camel-corda/src/main/java/org/apache/camel/component/corda/CordaConfiguration.java
new file mode 100644
index 00000000000..4d932ba75db
--- /dev/null
+++ b/components/camel-corda/src/main/java/org/apache/camel/component/corda/CordaConfiguration.java
@@ -0,0 +1,168 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.camel.component.corda;
+
+import net.corda.core.contracts.ContractState;
+import net.corda.core.flows.FlowLogic;
+import net.corda.core.node.services.vault.PageSpecification;
+import net.corda.core.node.services.vault.QueryCriteria;
+import net.corda.core.node.services.vault.Sort;
+import org.apache.camel.RuntimeCamelException;
+import org.apache.camel.spi.Metadata;
+import org.apache.camel.spi.UriParam;
+import org.apache.camel.spi.UriParams;
+
+@UriParams
+public class CordaConfiguration implements Cloneable {
+    @UriParam
+    @Metadata(required = "true")
+    private String operation;
+
+    @UriParam
+    @Metadata(required = "true", secret = true)
+    private String username;
+
+    @UriParam
+    @Metadata(required = "true", secret = true)
+    private String password;
+
+    @Metadata(required = "true")
+    private String host;
+
+    @Metadata(required = "true")
+    private int port;
+
+    @Metadata(required = "false", defaultValue = "true")
+    private boolean processSnapshot = true;
+
+    private Class<FlowLogic<?>> flowLociClass;
+
+    private Object [] arguments;
+
+    private Class<ContractState> contractStateClass;
+
+    private QueryCriteria queryCriteria;
+
+    private PageSpecification pageSpecification;
+
+    private Sort sort;
+
+    public String getOperation() {
+        return operation;
+    }
+
+    public void setOperation(String operation) {
+        this.operation = operation;
+    }
+
+    public String getUsername() {
+        return username;
+    }
+
+    public void setUsername(String username) {
+        this.username = username;
+    }
+
+    public String getPassword() {
+        return password;
+    }
+
+    public void setPassword(String password) {
+        this.password = password;
+    }
+
+    public String getHost() {
+        return host;
+    }
+
+    public void setHost(String host) {
+        this.host = host;
+    }
+
+    public int getPort() {
+        return port;
+    }
+
+    public void setPort(int port) {
+        this.port = port;
+    }
+
+    public boolean isProcessSnapshot() {
+        return processSnapshot;
+    }
+
+    public void setProcessSnapshot(boolean processSnapshot) {
+        this.processSnapshot = processSnapshot;
+    }
+
+    public Class<FlowLogic<?>> getFlowLociClass() {
+        return flowLociClass;
+    }
+
+    public void setFlowLociClass(Class<FlowLogic<?>> flowLociClass) {
+        this.flowLociClass = flowLociClass;
+    }
+
+    public Object[] getArguments() {
+        return arguments;
+    }
+
+    public void setArguments(Object[] arguments) {
+        this.arguments = arguments;
+    }
+
+    public Class<ContractState> getContractStateClass() {
+        return contractStateClass;
+    }
+
+    public void setContractStateClass(Class<ContractState> contractStateClass) {
+        this.contractStateClass = contractStateClass;
+    }
+
+    public QueryCriteria getQueryCriteria() {
+        return queryCriteria;
+    }
+
+    public void setQueryCriteria(QueryCriteria queryCriteria) {
+        this.queryCriteria = queryCriteria;
+    }
+
+    public PageSpecification getPageSpecification() {
+        return pageSpecification;
+    }
+
+    public void setPageSpecification(PageSpecification pageSpecification) {
+        this.pageSpecification = pageSpecification;
+    }
+
+    public Sort getSort() {
+        return sort;
+    }
+
+    public void setSort(Sort sort) {
+        this.sort = sort;
+    }
+
+    public CordaConfiguration copy() {
+        try {
+            return (CordaConfiguration)super.clone();
+        } catch (CloneNotSupportedException e) {
+            throw new RuntimeCamelException(e);
+        }
+    }
+
+}
diff --git a/components/camel-corda/src/main/java/org/apache/camel/component/corda/CordaConstants.java b/components/camel-corda/src/main/java/org/apache/camel/component/corda/CordaConstants.java
new file mode 100644
index 00000000000..f7c29be0627
--- /dev/null
+++ b/components/camel-corda/src/main/java/org/apache/camel/component/corda/CordaConstants.java
@@ -0,0 +1,69 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.camel.component.corda;
+
+public interface CordaConstants {
+    String OPERATION = "OPERATION";
+    String NODE_INFO = "NODE_INFO";
+    String CURRENT_NODE_TIME = "CURRENT_NODE_TIME";
+    String GET_PROTOCOL_VERSION = "GET_PROTOCOL_VERSION";
+    String NETWORK_MAP_SNAPSHOT = "NETWORK_MAP_SNAPSHOT";
+    String REGISTERED_FLOWS = "REGISTERED_FLOWS";
+    String CLEAR_NETWORK_MAP_CACHE = "CLEAR_NETWORK_MAP_CACHE";
+    String IS_FLOWS_DRAINING_MODE_ENABLED = "IS_FLOWS_DRAINING_MODE_ENABLED";
+    String ADD_VAULT_TRANSACTION_NOTE = "ADD_VAULT_TRANSACTION_NOTE";
+    String NOTARY_IDENTITIES = "NOTARY_IDENTITIES";
+    String SET_FLOWS_DRAINING_MODE_ENABLED = "SET_FLOWS_DRAINING_MODE_ENABLED";
+    String GET_VAULT_TRANSACTION_NOTES = "GET_VAULT_TRANSACTION_NOTES";
+    String UPLOAD_ATTACHMENT = "UPLOAD_ATTACHMENT";
+    String ATTACHMENT_EXISTS = "ATTACHMENT_EXISTS";
+    String OPEN_ATTACHMENT = "OPEN_ATTACHMENT";
+    String QUERY_ATTACHMENTS = "QUERY_ATTACHMENTS";
+    String NODE_INFO_FROM_PARTY = "NODE_INFO_FROM_PARTY";
+    String NOTARY_PARTY_FROM_X500_NAME = "NOTARY_PARTY_FROM_X500_NAME";
+    String PARTIES_FROM_NAME = "PARTIES_FROM_NAME";
+    String PARTIES_FROM_KEY = "PARTIES_FROM_KEY";
+    String START_FLOW_DYNAMIC = "START_FLOW_DYNAMIC";
+    String STATE_MACHINE_SNAPSHOT = "STATE_MACHINE_SNAPSHOT";
+    String STATE_MACHINE_RECORDED_TRANSACTION_MAPPING_SNAPSHOT = "STATE_MACHINE_RECORDED_TRANSACTION_MAPPING_SNAPSHOT";
+    String WELL_KNOWN_PARTY_FROM_X500_NAME = "WELL_KNOWN_PARTY_FROM_X500_NAME";
+    String WELL_KNOWN_PARTY_FROM_ANONYMOUS = "WELL_KNOWN_PARTY_FROM_ANONYMOUS";
+    String VAULT_QUERY = "VAULT_QUERY";
+    String VAULT_QUERY_BY = "VAULT_QUERY_BY";
+    String VAULT_QUERY_BY_CRITERIA = "VAULT_QUERY_BY_CRITERIA";
+    String VAULT_QUERY_BY_WITH_PAGING_SPEC = "VAULT_QUERY_BY_WITH_PAGING_SPEC";
+    String VAULT_QUERY_BY_WITH_SORTING = "VAULT_QUERY_BY_WITH_SORTING";
+
+    String VAULT_TRACK = "VAULT_TRACK";
+    String VAULT_TRACK_BY = "VAULT_TRACK_BY";
+    String VAULT_TRACK_BY_CRITERIA = "VAULT_TRACK_BY_CRITERIA";
+    String VAULT_TRACK_BY_WITH_PAGING_SPEC = "VAULT_TRACK_BY_WITH_PAGING_SPEC";
+    String VAULT_TRACK_BY_WITH_SORTING = "VAULT_TRACK_BY_WITH_SORTING";
+    String STATE_MACHINE_FEED = "STATE_MACHINE_FEED";
+    String NETWORK_MAP_FEED = "NETWORK_MAP_FEED";
+    String STATE_MACHINE_RECORDED_TRANSACTION_MAPPING_FEED = "STATE_MACHINE_RECORDED_TRANSACTION_MAPPING_FEED";
+    String START_TRACKED_FLOW_DYNAMIC = "START_TRACKED_FLOW_DYNAMIC";
+
+    String ATTACHMENT_QUERY_CRITERIA = "ATTACHMENT_QUERY_CRITERIA";
+    String SORT = "SORT";
+    String EXACT_MATCH = "EXACT_MATCH";
+    String ARGUMENTS = "ARGUMENTS";
+    String DRAINING_MODE = "DRAINING_MODE";
+    String SECURE_HASH = "SECURE_HASH";
+    String QUERY_CRITERIA = "QUERY_CRITERIA";
+    String PAGE_SPECIFICATION = "PAGE_SPECIFICATION";
+}
diff --git a/components/camel-corda/src/main/java/org/apache/camel/component/corda/CordaConsumer.java b/components/camel-corda/src/main/java/org/apache/camel/component/corda/CordaConsumer.java
new file mode 100644
index 00000000000..3c1f6175bd9
--- /dev/null
+++ b/components/camel-corda/src/main/java/org/apache/camel/component/corda/CordaConsumer.java
@@ -0,0 +1,267 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.camel.component.corda;
+
+import java.util.List;
+import net.corda.core.contracts.ContractState;
+import net.corda.core.messaging.CordaRPCOps;
+import net.corda.core.messaging.DataFeed;
+import net.corda.core.messaging.FlowProgressHandle;
+import net.corda.core.messaging.StateMachineInfo;
+import net.corda.core.messaging.StateMachineTransactionMapping;
+import net.corda.core.messaging.StateMachineUpdate;
+import net.corda.core.node.NodeInfo;
+import net.corda.core.node.services.NetworkMapCache;
+import net.corda.core.node.services.Vault;
+import net.corda.core.node.services.vault.PageSpecification;
+import net.corda.core.node.services.vault.QueryCriteria;
+import net.corda.core.node.services.vault.Sort;
+import org.apache.camel.Exchange;
+import org.apache.camel.Processor;
+import org.apache.camel.impl.DefaultConsumer;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import rx.Observable;
+import rx.Subscription;
+
+import static org.apache.camel.component.corda.CordaConstants.NETWORK_MAP_FEED;
+import static org.apache.camel.component.corda.CordaConstants.START_TRACKED_FLOW_DYNAMIC;
+import static org.apache.camel.component.corda.CordaConstants.STATE_MACHINE_FEED;
+import static org.apache.camel.component.corda.CordaConstants.STATE_MACHINE_RECORDED_TRANSACTION_MAPPING_FEED;
+import static org.apache.camel.component.corda.CordaConstants.VAULT_TRACK;
+import static org.apache.camel.component.corda.CordaConstants.VAULT_TRACK_BY;
+import static org.apache.camel.component.corda.CordaConstants.VAULT_TRACK_BY_CRITERIA;
+import static org.apache.camel.component.corda.CordaConstants.VAULT_TRACK_BY_WITH_PAGING_SPEC;
+import static org.apache.camel.component.corda.CordaConstants.VAULT_TRACK_BY_WITH_SORTING;
+
+/**
+ * The corda consumer.
+ */
+public class CordaConsumer extends DefaultConsumer {
+    private static final Logger LOG = LoggerFactory.getLogger(CordaConsumer.class);
+    private final CordaConfiguration configuration;
+    private CordaRPCOps cordaRPCOps;
+    private Subscription subscription;
+
+    public CordaConsumer(CordaEndpoint endpoint, Processor processor, CordaConfiguration configuration, CordaRPCOps cordaRPCOps) {
+        super(endpoint, processor);
+        this.configuration = configuration;
+        this.cordaRPCOps = cordaRPCOps;
+    }
+
+    @Override
+    public CordaEndpoint getEndpoint() {
+        return (CordaEndpoint) super.getEndpoint();
+    }
+
+    @Override
+    protected void doStart() throws Exception {
+        super.doStart();
+        Exchange exchange = this.getEndpoint().createExchange();
+        Class<ContractState> contractStateClass = configuration.getContractStateClass();
+        QueryCriteria criteria = configuration.getQueryCriteria();
+        PageSpecification pageSpec = configuration.getPageSpecification();
+        Sort sorting = configuration.getSort();
+
+        DataFeed<Vault.Page<ContractState>, Vault.Update<ContractState>> pageUpdateDataFeed = null;
+        switch (configuration.getOperation()) {
+
+        case VAULT_TRACK:
+            LOG.debug("subscribing for operation: " + VAULT_TRACK);
+            pageUpdateDataFeed = cordaRPCOps.vaultTrack(contractStateClass);
+            processSnapshot(exchange, pageUpdateDataFeed.getSnapshot());
+            subscription = pageUpdateDataFeed.getUpdates().subscribe(
+                x -> processContractStateUpdate(x),
+                t -> processError(t, CordaConstants.VAULT_TRACK),
+                () -> processDone(CordaConstants.VAULT_TRACK)
+            );
+            break;
+
+        case VAULT_TRACK_BY:
+            LOG.debug("subscribing for operation: " + VAULT_TRACK_BY);
+            pageUpdateDataFeed = cordaRPCOps.vaultTrackBy(criteria, pageSpec, sorting, contractStateClass);
+            processSnapshot(exchange, pageUpdateDataFeed.getSnapshot());
+            subscription = pageUpdateDataFeed.getUpdates().subscribe(
+                x -> processContractStateUpdate(x),
+                t -> processError(t, CordaConstants.VAULT_TRACK_BY),
+                () -> processDone(CordaConstants.VAULT_TRACK_BY)
+            );
+            break;
+
+        case VAULT_TRACK_BY_CRITERIA:
+            LOG.debug("subscribing for operation: " + VAULT_TRACK_BY_CRITERIA);
+            pageUpdateDataFeed = cordaRPCOps.vaultTrackByCriteria(contractStateClass, criteria);
+            processSnapshot(exchange, pageUpdateDataFeed.getSnapshot());
+            subscription = pageUpdateDataFeed.getUpdates().subscribe(
+                x -> processContractStateUpdate(x),
+                t -> processError(t, CordaConstants.VAULT_TRACK_BY_CRITERIA),
+                () -> processDone(CordaConstants.VAULT_TRACK_BY_CRITERIA)
+            );
+            break;
+
+        case VAULT_TRACK_BY_WITH_PAGING_SPEC:
+            LOG.debug("subscribing for operation: " + VAULT_TRACK_BY_WITH_PAGING_SPEC);
+            pageUpdateDataFeed = cordaRPCOps.vaultTrackByWithPagingSpec(contractStateClass, criteria, pageSpec);
+            processSnapshot(exchange, pageUpdateDataFeed.getSnapshot());
+            subscription = pageUpdateDataFeed.getUpdates().subscribe(
+                x -> processContractStateUpdate(x),
+                t -> processError(t, CordaConstants.VAULT_TRACK_BY_WITH_PAGING_SPEC),
+                () -> processDone(CordaConstants.VAULT_TRACK_BY_WITH_PAGING_SPEC)
+            );
+            break;
+
+        case VAULT_TRACK_BY_WITH_SORTING:
+            LOG.debug("subscribing for operation: " + VAULT_TRACK_BY_WITH_SORTING);
+            pageUpdateDataFeed = cordaRPCOps.vaultTrackByWithSorting(contractStateClass, criteria, sorting);
+            processSnapshot(exchange, pageUpdateDataFeed.getSnapshot());
+            subscription = pageUpdateDataFeed.getUpdates().subscribe(
+                x -> processContractStateUpdate(x),
+                t -> processError(t, CordaConstants.VAULT_TRACK_BY_WITH_SORTING),
+                () -> processDone(CordaConstants.VAULT_TRACK_BY_WITH_SORTING)
+            );
+            break;
+
+        case STATE_MACHINE_FEED:
+            LOG.debug("subscribing for operation: " + STATE_MACHINE_FEED);
+            DataFeed<List<StateMachineInfo>, StateMachineUpdate> stateFeed = cordaRPCOps.stateMachinesFeed();
+            processSnapshot(exchange, stateFeed.getSnapshot());
+            subscription = stateFeed.getUpdates().subscribe(
+                x -> processStateMachineUpdate(x),
+                t -> processError(t, CordaConstants.STATE_MACHINE_FEED),
+                () -> processDone(CordaConstants.STATE_MACHINE_FEED)
+            );
+            break;
+
+        case NETWORK_MAP_FEED:
+            LOG.debug("subscribing for operation: " + NETWORK_MAP_FEED);
+
+            DataFeed<List<NodeInfo>, NetworkMapCache.MapChange> networkMapFeed = cordaRPCOps.networkMapFeed();
+            processSnapshot(exchange, networkMapFeed.getSnapshot());
+            subscription = networkMapFeed.getUpdates().subscribe(
+                x -> proceedNetworkMapFeed(x),
+                t -> processError(t, CordaConstants.NETWORK_MAP_FEED),
+                () -> processDone(CordaConstants.NETWORK_MAP_FEED)
+            );
+            break;
+
+        case STATE_MACHINE_RECORDED_TRANSACTION_MAPPING_FEED:
+            LOG.debug("subscribing for operation: " + STATE_MACHINE_RECORDED_TRANSACTION_MAPPING_FEED);
+
+            DataFeed<List<StateMachineTransactionMapping>, StateMachineTransactionMapping> transactionFeed = cordaRPCOps.stateMachineRecordedTransactionMappingFeed();
+            processSnapshot(exchange, transactionFeed.getSnapshot());
+            subscription = transactionFeed.getUpdates().subscribe(
+                x -> processTransactionMappingFeed(x),
+                t -> processError(t, CordaConstants.STATE_MACHINE_RECORDED_TRANSACTION_MAPPING_FEED),
+                () -> processDone(CordaConstants.STATE_MACHINE_RECORDED_TRANSACTION_MAPPING_FEED)
+            );
+            break;
+
+        case START_TRACKED_FLOW_DYNAMIC:
+            LOG.debug("subscribing for operation: " + START_TRACKED_FLOW_DYNAMIC);
+
+            FlowProgressHandle<Object> objectFlowProgressHandle = cordaRPCOps.startTrackedFlowDynamic(configuration.getFlowLociClass(), configuration.getArguments());
+            Object result = objectFlowProgressHandle.getReturnValue().get();
+            Observable<String> progress = objectFlowProgressHandle.getProgress();
+            processSnapshot(exchange, result);
+            subscription = progress.subscribe(
+                x -> processFlowProcess(x),
+                t -> processError(t, CordaConstants.START_TRACKED_FLOW_DYNAMIC),
+                () -> processDone(CordaConstants.START_TRACKED_FLOW_DYNAMIC)
+            );
+            break;
+
+        default:
+            throw new IllegalArgumentException("Unsupported operation " + configuration.getOperation());
+        }
+
+        LOG.info("Subscribed: {}", this.configuration);
+    }
+
+    private void processSnapshot(Exchange exchange, Object page) {
+        if (configuration.isProcessSnapshot()) {
+            try {
+                exchange.getIn().setBody(page);
+                getProcessor().process(exchange);
+            } catch (Exception e) {
+                LOG.error("Error processing snapshot", e);
+            }
+        }
+    }
+
+    private void processFlowProcess(String x) {
+        LOG.debug("processFlowProcess {}", x);
+        Exchange exchange = this.getEndpoint().createExchange();
+        exchange.getIn().setBody(x);
+        processEvent(exchange);
+    }
+
+    private void processTransactionMappingFeed(StateMachineTransactionMapping x) {
+        LOG.debug("processTransactionMappingFeed {}", x);
+        Exchange exchange = this.getEndpoint().createExchange();
+        exchange.getIn().setBody(x);
+        processEvent(exchange);
+    }
+
+    private void proceedNetworkMapFeed(NetworkMapCache.MapChange x) {
+        LOG.debug("proceedNetworkMapFeed {}", x);
+        Exchange exchange = this.getEndpoint().createExchange();
+        exchange.getIn().setBody(x);
+        processEvent(exchange);
+    }
+
+    private void processStateMachineUpdate(StateMachineUpdate x) {
+        LOG.debug("processStateMachineUpdate {}", x);
+        Exchange exchange = this.getEndpoint().createExchange();
+        exchange.getIn().setBody(x);
+        processEvent(exchange);
+    }
+
+    private void processContractStateUpdate(Vault.Update<ContractState> x) {
+        LOG.debug("processContractStateUpdate {}", x);
+        Exchange exchange = this.getEndpoint().createExchange();
+        exchange.getIn().setBody(x);
+        processEvent(exchange);
+    }
+
+    private void processError(Throwable throwable, String operation) {
+        LOG.debug("processError for operation: " + operation + " " + throwable);
+        Exchange exchange = this.getEndpoint().createExchange();
+        exchange.setException(throwable);
+        processEvent(exchange);
+    }
+
+    public void processEvent(Exchange exchange) {
+        LOG.debug("processEvent {}", exchange);
+        try {
+            getProcessor().process(exchange);
+        } catch (Exception e) {
+            LOG.error("Error processing event ", e);
+        }
+    }
+
+    private void processDone(String operation) {
+        LOG.debug("processDone for operation: {}", operation);
+    }
+
+    @Override
+    protected void doStop() throws Exception {
+        if (subscription != null) {
+            subscription.unsubscribe();
+        }
+        super.doStop();
+    }
+}
diff --git a/components/camel-corda/src/main/java/org/apache/camel/component/corda/CordaEndpoint.java b/components/camel-corda/src/main/java/org/apache/camel/component/corda/CordaEndpoint.java
new file mode 100644
index 00000000000..4ba221a50fd
--- /dev/null
+++ b/components/camel-corda/src/main/java/org/apache/camel/component/corda/CordaEndpoint.java
@@ -0,0 +1,101 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.camel.component.corda;
+
+import java.net.URI;
+import java.net.URISyntaxException;
+import net.corda.client.rpc.CordaRPCClient;
+import net.corda.client.rpc.CordaRPCConnection;
+import net.corda.core.messaging.CordaRPCOps;
+import net.corda.core.utilities.NetworkHostAndPort;
+import org.apache.camel.Consumer;
+import org.apache.camel.Processor;
+import org.apache.camel.Producer;
+import org.apache.camel.impl.DefaultEndpoint;
+import org.apache.camel.spi.Metadata;
+import org.apache.camel.spi.UriEndpoint;
+import org.apache.camel.spi.UriPath;
+
+/**
+ * The corda component uses the corda-rpc to interact with corda nodes.
+ */
+@UriEndpoint(firstVersion = "2.23.0", scheme = "corda", title = "corda", syntax = "corda:url", consumerClass = CordaConsumer.class, label = "corda,blockchain")
+public class CordaEndpoint extends DefaultEndpoint {
+
+    @UriPath(description = "URL to the corda node")
+    @Metadata(required = "true")
+    private CordaConfiguration configuration;
+    private CordaRPCConnection rpcConnection;
+    private CordaRPCOps proxy;
+
+    public CordaEndpoint(String uri, String remaining, CordaComponent component, CordaConfiguration configuration) {
+        super(uri, component);
+        this.configuration = configuration;
+
+        try {
+            URI nodeURI = new URI(uri);
+            configuration.setHost(nodeURI.getHost());
+            configuration.setPort(nodeURI.getPort());
+
+            if (nodeURI.getUserInfo() != null) {
+                String[] creds = nodeURI.getUserInfo().split(":");
+                if (configuration.getUsername() == null) {
+                    configuration.setUsername(creds[0]);
+                }
+                if (configuration.getPassword() == null) {
+                    configuration.setPassword(creds.length > 1 ? creds[1] : "");
+                }
+            }
+        } catch (URISyntaxException e) {
+            throw new IllegalArgumentException("Invalid URI: " + remaining, e);
+        }
+    }
+
+    @Override
+    public Producer createProducer() throws Exception {
+        return new CordaProducer(this, configuration, proxy);
+    }
+
+    @Override
+    public Consumer createConsumer(Processor processor) throws Exception {
+        CordaConsumer consumer = new CordaConsumer(this, processor, configuration, proxy);
+        configureConsumer(consumer);
+        return consumer;
+    }
+
+    @Override
+    protected void doStart() throws Exception {
+        NetworkHostAndPort rpcAddress = new NetworkHostAndPort(configuration.getHost(), configuration.getPort());
+        CordaRPCClient rpcClient = new CordaRPCClient(rpcAddress);
+        rpcConnection = rpcClient.start(this.configuration.getUsername(), this.configuration.getPassword());
+        proxy = rpcConnection.getProxy();
+        super.doStart();
+    }
+
+    @Override
+    protected void doStop() throws Exception {
+        if (rpcConnection != null) {
+            rpcConnection.notifyServerAndClose();
+        }
+        super.doStop();
+    }
+
+    public boolean isSingleton() {
+        return true;
+    }
+
+}
diff --git a/components/camel-corda/src/main/java/org/apache/camel/component/corda/CordaProducer.java b/components/camel-corda/src/main/java/org/apache/camel/component/corda/CordaProducer.java
new file mode 100644
index 00000000000..ea9fe7bf9c5
--- /dev/null
+++ b/components/camel-corda/src/main/java/org/apache/camel/component/corda/CordaProducer.java
@@ -0,0 +1,240 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.camel.component.corda;
+
+import java.io.InputStream;
+import java.security.PublicKey;
+import net.corda.core.contracts.ContractState;
+import net.corda.core.crypto.SecureHash;
+import net.corda.core.flows.FlowLogic;
+import net.corda.core.identity.AbstractParty;
+import net.corda.core.identity.CordaX500Name;
+import net.corda.core.messaging.CordaRPCOps;
+import net.corda.core.node.services.vault.AttachmentQueryCriteria;
+import net.corda.core.node.services.vault.AttachmentSort;
+import net.corda.core.node.services.vault.PageSpecification;
+import net.corda.core.node.services.vault.QueryCriteria;
+import net.corda.core.node.services.vault.Sort;
+import org.apache.camel.InvokeOnHeader;
+import org.apache.camel.Message;
+import org.apache.camel.impl.HeaderSelectorProducer;
+
+import static org.apache.camel.component.corda.CordaConstants.ARGUMENTS;
+import static org.apache.camel.component.corda.CordaConstants.ATTACHMENT_QUERY_CRITERIA;
+import static org.apache.camel.component.corda.CordaConstants.DRAINING_MODE;
+import static org.apache.camel.component.corda.CordaConstants.EXACT_MATCH;
+import static org.apache.camel.component.corda.CordaConstants.PAGE_SPECIFICATION;
+import static org.apache.camel.component.corda.CordaConstants.QUERY_CRITERIA;
+import static org.apache.camel.component.corda.CordaConstants.SECURE_HASH;
+import static org.apache.camel.component.corda.CordaConstants.SORT;
+
+/**
+ * The corda producer.
+ */
+
+public class CordaProducer extends HeaderSelectorProducer {
+    private CordaConfiguration configuration;
+    private CordaRPCOps cordaRPCOps;
+
+    public CordaProducer(CordaEndpoint endpoint, final CordaConfiguration configuration, CordaRPCOps cordaRPCOps) {
+        super(endpoint, CordaConstants.OPERATION, () -> configuration.getOperation(), false);
+        this.configuration = configuration;
+        this.cordaRPCOps = cordaRPCOps;
+    }
+
+    @Override
+    public CordaEndpoint getEndpoint() {
+        return (CordaEndpoint) super.getEndpoint();
+    }
+
+    @InvokeOnHeader(CordaConstants.CURRENT_NODE_TIME)
+    void currentNodeTime(Message message) throws Exception {
+        message.setBody(cordaRPCOps.currentNodeTime());
+    }
+
+    @InvokeOnHeader(CordaConstants.GET_PROTOCOL_VERSION)
+    void getProtocolVersion(Message message) throws Exception {
+        message.setBody(cordaRPCOps.getProtocolVersion());
+    }
+
+    @InvokeOnHeader(CordaConstants.NETWORK_MAP_SNAPSHOT)
+    void networkMapSnapshot(Message message) throws Exception {
+        message.setBody(cordaRPCOps.networkMapSnapshot());
+    }
+
+    @InvokeOnHeader(CordaConstants.STATE_MACHINE_SNAPSHOT)
+    void stateMachinesSnapshot(Message message) throws Exception {
+        message.setBody(cordaRPCOps.stateMachinesSnapshot());
+    }
+
+    @InvokeOnHeader(CordaConstants.STATE_MACHINE_RECORDED_TRANSACTION_MAPPING_SNAPSHOT)
+    void stateMachineRecordedTransactionMappingSnapshot(Message message) throws Exception {
+        message.setBody(cordaRPCOps.stateMachineRecordedTransactionMappingSnapshot());
+    }
+
+    @InvokeOnHeader(CordaConstants.REGISTERED_FLOWS)
+    void registeredFlows(Message message) throws Exception {
+        message.setBody(cordaRPCOps.registeredFlows());
+    }
+
+    @InvokeOnHeader(CordaConstants.CLEAR_NETWORK_MAP_CACHE)
+    void clearNetworkMapCache(Message message) throws Exception {
+        cordaRPCOps.clearNetworkMapCache();
+    }
+
+    @InvokeOnHeader(CordaConstants.IS_FLOWS_DRAINING_MODE_ENABLED)
+    void isFlowsDrainingModeEnabled(Message message) throws Exception {
+        message.setBody(cordaRPCOps.isFlowsDrainingModeEnabled());
+    }
+
+    @InvokeOnHeader(CordaConstants.SET_FLOWS_DRAINING_MODE_ENABLED)
+    void setFlowsDrainingModeEnabled(Message message) throws Exception {
+        Boolean mode = message.getHeader(DRAINING_MODE, Boolean.class);
+        cordaRPCOps.setFlowsDrainingModeEnabled(mode);
+    }
+
+    @InvokeOnHeader(CordaConstants.NOTARY_IDENTITIES)
+    void notaryIdentities(Message message) throws Exception {
+        message.setBody(cordaRPCOps.notaryIdentities());
+    }
+
+    @InvokeOnHeader(CordaConstants.NODE_INFO)
+    void nodeInfo(Message message) throws Exception {
+        message.setBody(cordaRPCOps.nodeInfo());
+    }
+
+    @InvokeOnHeader(CordaConstants.ADD_VAULT_TRANSACTION_NOTE)
+    void addVaultTransactionNote(Message message) throws Exception {
+        SecureHash secureHash = message.getHeader(SECURE_HASH, SecureHash.class);
+        String note = message.getBody(String.class);
+        cordaRPCOps.addVaultTransactionNote(secureHash, note);
+    }
+
+    @InvokeOnHeader(CordaConstants.GET_VAULT_TRANSACTION_NOTES)
+    void getVaultTransactionNotes(Message message) throws Exception {
+        SecureHash secureHash = message.getHeader(SECURE_HASH, SecureHash.class);
+        message.setBody(cordaRPCOps.getVaultTransactionNotes(secureHash));
+    }
+
+    @InvokeOnHeader(CordaConstants.UPLOAD_ATTACHMENT)
+    void uploadAttachment(Message message) throws Exception {
+        InputStream inputStream = message.getBody(InputStream.class);
+        SecureHash secureHash = cordaRPCOps.uploadAttachment(inputStream);
+        message.setHeader(SECURE_HASH, secureHash);
+    }
+
+    @InvokeOnHeader(CordaConstants.ATTACHMENT_EXISTS)
+    void attachmentExists(Message message) throws Exception {
+        SecureHash secureHash = message.getHeader(SECURE_HASH, SecureHash.class);
+        message.setBody(cordaRPCOps.attachmentExists(secureHash));
+    }
+
+    @InvokeOnHeader(CordaConstants.OPEN_ATTACHMENT)
+    void openAttachment(Message message) throws Exception {
+        SecureHash secureHash = message.getHeader(SECURE_HASH, SecureHash.class);
+        message.setBody(cordaRPCOps.openAttachment(secureHash));
+    }
+
+    @InvokeOnHeader(CordaConstants.QUERY_ATTACHMENTS)
+    void queryAttachments(Message message) throws Exception {
+        AttachmentQueryCriteria queryCriteria = message.getHeader(ATTACHMENT_QUERY_CRITERIA, AttachmentQueryCriteria.class);
+        AttachmentSort attachmentSort = message.getHeader(SORT, AttachmentSort.class);
+        message.setBody(cordaRPCOps.queryAttachments(queryCriteria, attachmentSort));
+    }
+
+    @InvokeOnHeader(CordaConstants.NODE_INFO_FROM_PARTY)
+    void nodeInfoFromParty(Message message) throws Exception {
+        AbstractParty party = message.getBody(AbstractParty.class);
+        message.setBody(cordaRPCOps.nodeInfoFromParty(party));
+    }
+
+    @InvokeOnHeader(CordaConstants.NOTARY_PARTY_FROM_X500_NAME)
+    void notaryPartyFromX500Name(Message message) throws Exception {
+        CordaX500Name x500Name = message.getBody(CordaX500Name.class);
+        message.setBody(cordaRPCOps.notaryPartyFromX500Name(x500Name));
+    }
+
+    @InvokeOnHeader(CordaConstants.PARTIES_FROM_NAME)
+    void partiesFromName(Message message) throws Exception {
+        String query = message.getBody(String.class);
+        Boolean exactMatch = message.getHeader(EXACT_MATCH, Boolean.class);
+        message.setBody(cordaRPCOps.partiesFromName(query, exactMatch));
+    }
+
+    @InvokeOnHeader(CordaConstants.PARTIES_FROM_KEY)
+    void partyFromKey(Message message) throws Exception {
+        PublicKey key = message.getBody(PublicKey.class);
+        message.setBody(cordaRPCOps.partyFromKey(key));
+    }
+
+    @InvokeOnHeader(CordaConstants.WELL_KNOWN_PARTY_FROM_X500_NAME)
+    void wellKnownPartyFromX500Name(Message message) throws Exception {
+        CordaX500Name x500Name = message.getBody(CordaX500Name.class);
+        message.setBody(cordaRPCOps.wellKnownPartyFromX500Name(x500Name));
+    }
+
+    @InvokeOnHeader(CordaConstants.WELL_KNOWN_PARTY_FROM_ANONYMOUS)
+    void wellKnownPartyFromAnonymous(Message message) throws Exception {
+        AbstractParty party = message.getBody(AbstractParty.class);
+        message.setBody(cordaRPCOps.wellKnownPartyFromAnonymous(party));
+    }
+
+    @InvokeOnHeader(CordaConstants.START_FLOW_DYNAMIC)
+    void startFlowDynamic(Message message) throws Exception {
+        Object [] args = message.getHeader(ARGUMENTS, Object [].class);
+        Class<FlowLogic<?>> aClass = message.getBody(Class.class);
+        message.setBody(cordaRPCOps.startFlowDynamic(aClass, args).getReturnValue().get());
+    }
+
+    @InvokeOnHeader(CordaConstants.VAULT_QUERY)
+    void vaultQuery(Message message) throws Exception {
+        Class<ContractState> contractStateClass = (Class<ContractState>) message.getBody(Class.class);
+        message.setBody(cordaRPCOps.vaultQuery(contractStateClass));
+    }
+
+    @InvokeOnHeader(CordaConstants.VAULT_QUERY_BY)
+    void vaultQueryBy(Message message) throws Exception {
+        Class<ContractState> contractStateClass = (Class<ContractState>) message.getBody(Class.class);
+        QueryCriteria criteria = message.getHeader(QUERY_CRITERIA, QueryCriteria.class);
+        PageSpecification pageSpec = message.getHeader(PAGE_SPECIFICATION, PageSpecification.class);
+        Sort sorting = message.getHeader(SORT, Sort.class);
+        message.setBody(cordaRPCOps.vaultQueryBy(criteria, pageSpec, sorting, contractStateClass));
+    }
+
+    @InvokeOnHeader(CordaConstants.VAULT_QUERY_BY_CRITERIA)
+    void vaultQueryByCriteria(Message message) throws Exception {
+        Class<ContractState> contractStateClass = (Class<ContractState>) message.getBody(Class.class);
+        QueryCriteria criteria = message.getHeader(QUERY_CRITERIA, QueryCriteria.class);
+        message.setBody(cordaRPCOps.vaultQueryByCriteria(criteria, contractStateClass));
+    }
+
+    @InvokeOnHeader(CordaConstants.VAULT_QUERY_BY_WITH_PAGING_SPEC)
+    void vaultQueryByWithPagingSpec(Message message) throws Exception {
+        Class<ContractState> contractStateClass = (Class<ContractState>) message.getBody(Class.class);
+        QueryCriteria criteria = message.getHeader(QUERY_CRITERIA, QueryCriteria.class);
+        PageSpecification pageSpec = message.getHeader(PAGE_SPECIFICATION, PageSpecification.class);
+        message.setBody(cordaRPCOps.vaultQueryByWithPagingSpec(contractStateClass, criteria, pageSpec));
+    }
+
+    @InvokeOnHeader(CordaConstants.VAULT_QUERY_BY_WITH_SORTING)
+    void vaultQueryByWithSorting(Message message) throws Exception {
+        Class<ContractState> contractStateClass = (Class<ContractState>) message.getBody(Class.class);
+        QueryCriteria criteria = message.getHeader(QUERY_CRITERIA, QueryCriteria.class);
+        Sort sorting = message.getHeader(SORT, Sort.class);
+        message.setBody(cordaRPCOps.vaultQueryByWithSorting(contractStateClass, criteria, sorting));
+    }
+}
diff --git a/components/camel-corda/src/main/resources/META-INF/LICENSE.txt b/components/camel-corda/src/main/resources/META-INF/LICENSE.txt
new file mode 100755
index 00000000000..6b0b1270ff0
--- /dev/null
+++ b/components/camel-corda/src/main/resources/META-INF/LICENSE.txt
@@ -0,0 +1,203 @@
+
+                                 Apache License
+                           Version 2.0, January 2004
+                        http://www.apache.org/licenses/
+
+   TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
+
+   1. Definitions.
+
+      "License" shall mean the terms and conditions for use, reproduction,
+      and distribution as defined by Sections 1 through 9 of this document.
+
+      "Licensor" shall mean the copyright owner or entity authorized by
+      the copyright owner that is granting the License.
+
+      "Legal Entity" shall mean the union of the acting entity and all
+      other entities that control, are controlled by, or are under common
+      control with that entity. For the purposes of this definition,
+      "control" means (i) the power, direct or indirect, to cause the
+      direction or management of such entity, whether by contract or
+      otherwise, or (ii) ownership of fifty percent (50%) or more of the
+      outstanding shares, or (iii) beneficial ownership of such entity.
+
+      "You" (or "Your") shall mean an individual or Legal Entity
+      exercising permissions granted by this License.
+
+      "Source" form shall mean the preferred form for making modifications,
+      including but not limited to software source code, documentation
+      source, and configuration files.
+
+      "Object" form shall mean any form resulting from mechanical
+      transformation or translation of a Source form, including but
+      not limited to compiled object code, generated documentation,
+      and conversions to other media types.
+
+      "Work" shall mean the work of authorship, whether in Source or
+      Object form, made available under the License, as indicated by a
+      copyright notice that is included in or attached to the work
+      (an example is provided in the Appendix below).
+
+      "Derivative Works" shall mean any work, whether in Source or Object
+      form, that is based on (or derived from) the Work and for which the
+      editorial revisions, annotations, elaborations, or other modifications
+      represent, as a whole, an original work of authorship. For the purposes
+      of this License, Derivative Works shall not include works that remain
+      separable from, or merely link (or bind by name) to the interfaces of,
+      the Work and Derivative Works thereof.
+
+      "Contribution" shall mean any work of authorship, including
+      the original version of the Work and any modifications or additions
+      to that Work or Derivative Works thereof, that is intentionally
+      submitted to Licensor for inclusion in the Work by the copyright owner
+      or by an individual or Legal Entity authorized to submit on behalf of
+      the copyright owner. For the purposes of this definition, "submitted"
+      means any form of electronic, verbal, or written communication sent
+      to the Licensor or its representatives, including but not limited to
+      communication on electronic mailing lists, source code control systems,
+      and issue tracking systems that are managed by, or on behalf of, the
+      Licensor for the purpose of discussing and improving the Work, but
+      excluding communication that is conspicuously marked or otherwise
+      designated in writing by the copyright owner as "Not a Contribution."
+
+      "Contributor" shall mean Licensor and any individual or Legal Entity
+      on behalf of whom a Contribution has been received by Licensor and
+      subsequently incorporated within the Work.
+
+   2. Grant of Copyright License. Subject to the terms and conditions of
+      this License, each Contributor hereby grants to You a perpetual,
+      worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+      copyright license to reproduce, prepare Derivative Works of,
+      publicly display, publicly perform, sublicense, and distribute the
+      Work and such Derivative Works in Source or Object form.
+
+   3. Grant of Patent License. Subject to the terms and conditions of
+      this License, each Contributor hereby grants to You a perpetual,
+      worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+      (except as stated in this section) patent license to make, have made,
+      use, offer to sell, sell, import, and otherwise transfer the Work,
+      where such license applies only to those patent claims licensable
+      by such Contributor that are necessarily infringed by their
+      Contribution(s) alone or by combination of their Contribution(s)
+      with the Work to which such Contribution(s) was submitted. If You
+      institute patent litigation against any entity (including a
+      cross-claim or counterclaim in a lawsuit) alleging that the Work
+      or a Contribution incorporated within the Work constitutes direct
+      or contributory patent infringement, then any patent licenses
+      granted to You under this License for that Work shall terminate
+      as of the date such litigation is filed.
+
+   4. Redistribution. You may reproduce and distribute copies of the
+      Work or Derivative Works thereof in any medium, with or without
+      modifications, and in Source or Object form, provided that You
+      meet the following conditions:
+
+      (a) You must give any other recipients of the Work or
+          Derivative Works a copy of this License; and
+
+      (b) You must cause any modified files to carry prominent notices
+          stating that You changed the files; and
+
+      (c) You must retain, in the Source form of any Derivative Works
+          that You distribute, all copyright, patent, trademark, and
+          attribution notices from the Source form of the Work,
+          excluding those notices that do not pertain to any part of
+          the Derivative Works; and
+
+      (d) If the Work includes a "NOTICE" text file as part of its
+          distribution, then any Derivative Works that You distribute must
+          include a readable copy of the attribution notices contained
+          within such NOTICE file, excluding those notices that do not
+          pertain to any part of the Derivative Works, in at least one
+          of the following places: within a NOTICE text file distributed
+          as part of the Derivative Works; within the Source form or
+          documentation, if provided along with the Derivative Works; or,
+          within a display generated by the Derivative Works, if and
+          wherever such third-party notices normally appear. The contents
+          of the NOTICE file are for informational purposes only and
+          do not modify the License. You may add Your own attribution
+          notices within Derivative Works that You distribute, alongside
+          or as an addendum to the NOTICE text from the Work, provided
+          that such additional attribution notices cannot be construed
+          as modifying the License.
+
+      You may add Your own copyright statement to Your modifications and
+      may provide additional or different license terms and conditions
+      for use, reproduction, or distribution of Your modifications, or
+      for any such Derivative Works as a whole, provided Your use,
+      reproduction, and distribution of the Work otherwise complies with
+      the conditions stated in this License.
+
+   5. Submission of Contributions. Unless You explicitly state otherwise,
+      any Contribution intentionally submitted for inclusion in the Work
+      by You to the Licensor shall be under the terms and conditions of
+      this License, without any additional terms or conditions.
+      Notwithstanding the above, nothing herein shall supersede or modify
+      the terms of any separate license agreement you may have executed
+      with Licensor regarding such Contributions.
+
+   6. Trademarks. This License does not grant permission to use the trade
+      names, trademarks, service marks, or product names of the Licensor,
+      except as required for reasonable and customary use in describing the
+      origin of the Work and reproducing the content of the NOTICE file.
+
+   7. Disclaimer of Warranty. Unless required by applicable law or
+      agreed to in writing, Licensor provides the Work (and each
+      Contributor provides its Contributions) on an "AS IS" BASIS,
+      WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
+      implied, including, without limitation, any warranties or conditions
+      of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
+      PARTICULAR PURPOSE. You are solely responsible for determining the
+      appropriateness of using or redistributing the Work and assume any
+      risks associated with Your exercise of permissions under this License.
+
+   8. Limitation of Liability. In no event and under no legal theory,
+      whether in tort (including negligence), contract, or otherwise,
+      unless required by applicable law (such as deliberate and grossly
+      negligent acts) or agreed to in writing, shall any Contributor be
+      liable to You for damages, including any direct, indirect, special,
+      incidental, or consequential damages of any character arising as a
+      result of this License or out of the use or inability to use the
+      Work (including but not limited to damages for loss of goodwill,
+      work stoppage, computer failure or malfunction, or any and all
+      other commercial damages or losses), even if such Contributor
+      has been advised of the possibility of such damages.
+
+   9. Accepting Warranty or Additional Liability. While redistributing
+      the Work or Derivative Works thereof, You may choose to offer,
+      and charge a fee for, acceptance of support, warranty, indemnity,
+      or other liability obligations and/or rights consistent with this
+      License. However, in accepting such obligations, You may act only
+      on Your own behalf and on Your sole responsibility, not on behalf
+      of any other Contributor, and only if You agree to indemnify,
+      defend, and hold each Contributor harmless for any liability
+      incurred by, or claims asserted against, such Contributor by reason
+      of your accepting any such warranty or additional liability.
+
+   END OF TERMS AND CONDITIONS
+
+   APPENDIX: How to apply the Apache License to your work.
+
+      To apply the Apache License to your work, attach the following
+      boilerplate notice, with the fields enclosed by brackets "[]"
+      replaced with your own identifying information. (Don't include
+      the brackets!)  The text should be enclosed in the appropriate
+      comment syntax for the file format. We also recommend that a
+      file or class name and description of purpose be included on the
+      same "printed page" as the copyright notice for easier
+      identification within third-party archives.
+
+   Copyright [yyyy] [name of copyright owner]
+
+   Licensed 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.
+
diff --git a/components/camel-corda/src/main/resources/META-INF/NOTICE.txt b/components/camel-corda/src/main/resources/META-INF/NOTICE.txt
new file mode 100755
index 00000000000..2e215bf2e6b
--- /dev/null
+++ b/components/camel-corda/src/main/resources/META-INF/NOTICE.txt
@@ -0,0 +1,11 @@
+   =========================================================================
+   ==  NOTICE file corresponding to the section 4 d of                    ==
+   ==  the Apache License, Version 2.0,                                   ==
+   ==  in this case for the Apache Camel distribution.                    ==
+   =========================================================================
+
+   This product includes software developed by
+   The Apache Software Foundation (http://www.apache.org/).
+
+   Please read the different LICENSE files present in the licenses directory of
+   this distribution.
diff --git a/components/camel-corda/src/main/resources/META-INF/services/org/apache/camel/component/corda b/components/camel-corda/src/main/resources/META-INF/services/org/apache/camel/component/corda
new file mode 100755
index 00000000000..b7423d9f974
--- /dev/null
+++ b/components/camel-corda/src/main/resources/META-INF/services/org/apache/camel/component/corda
@@ -0,0 +1,18 @@
+#
+# 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.
+#
+
+class=org.apache.camel.component.corda.CordaComponent
diff --git a/components/camel-corda/src/test/java/org/apache/camel/component/corda/CamelFlow.java b/components/camel-corda/src/test/java/org/apache/camel/component/corda/CamelFlow.java
new file mode 100644
index 00000000000..fc3a0012121
--- /dev/null
+++ b/components/camel-corda/src/test/java/org/apache/camel/component/corda/CamelFlow.java
@@ -0,0 +1,32 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.camel.component.corda;
+
+import net.corda.core.flows.FlowLogic;
+
+public class CamelFlow extends FlowLogic<String> {
+    private String in;
+
+    public CamelFlow(String in) {
+        this.in = in;
+    }
+
+    @Override
+    public String call() {
+        return in + " world!";
+    }
+}
diff --git a/components/camel-dropbox/src/test/java/org/apache/camel/component/dropbox/integration/consumer/DropboxConsumerSearchTest.java b/components/camel-corda/src/test/java/org/apache/camel/component/corda/CordaConsumerNetworkMapFeedTest.java
similarity index 54%
rename from components/camel-dropbox/src/test/java/org/apache/camel/component/dropbox/integration/consumer/DropboxConsumerSearchTest.java
rename to components/camel-corda/src/test/java/org/apache/camel/component/corda/CordaConsumerNetworkMapFeedTest.java
index b6f32730d4d..a08c90a5531 100644
--- a/components/camel-dropbox/src/test/java/org/apache/camel/component/dropbox/integration/consumer/DropboxConsumerSearchTest.java
+++ b/components/camel-corda/src/test/java/org/apache/camel/component/corda/CordaConsumerNetworkMapFeedTest.java
@@ -14,41 +14,34 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
-package org.apache.camel.component.dropbox.integration.consumer;
+package org.apache.camel.component.corda;
 
-import java.util.List;
-
-import org.apache.camel.Exchange;
 import org.apache.camel.builder.RouteBuilder;
-import org.apache.camel.component.dropbox.integration.DropboxTestSupport;
-import org.apache.camel.component.dropbox.util.DropboxResultHeader;
 import org.apache.camel.component.mock.MockEndpoint;
+import org.junit.Ignore;
 import org.junit.Test;
 
-public class DropboxConsumerSearchTest extends DropboxTestSupport {
+import static org.apache.camel.component.corda.CordaConstants.NETWORK_MAP_FEED;
+import static org.apache.camel.component.corda.CordaConstants.OPERATION;
+import static org.apache.camel.component.corda.CordaConstants.STATE_MACHINE_FEED;
 
-    public DropboxConsumerSearchTest() throws Exception { }
+@Ignore("This integration test requires a locally running corda node such cordapp-template-java")
+public class CordaConsumerNetworkMapFeedTest extends CordaConsumerTestSupport {
 
     @Test
-    public void testCamelDropbox() throws Exception {
-
-        MockEndpoint mock = getMockEndpoint("mock:result");
-        mock.expectedMinimumMessageCount(1);       
-        assertMockEndpointsSatisfied();
-
-        List<Exchange> exchanges = mock.getReceivedExchanges();
-        Exchange exchange = exchanges.get(0);
-        Object header =  exchange.getIn().getHeader(DropboxResultHeader.FOUND_FILES.name());
-        Object body = exchange.getIn().getBody();
-        assertNotNull(header);
-        assertNotNull(body);
+    public void networkMapFeedTest() throws Exception {
+        mockResult.expectedMinimumMessageCount(1);
+        mockError.expectedMessageCount(0);
+        MockEndpoint.assertIsSatisfied(context);
     }
 
     @Override
     protected RouteBuilder createRouteBuilder() throws Exception {
         return new RouteBuilder() {
             public void configure() {
-                from("dropbox://search?accessToken={{accessToken}}&remotePath=/XXX")
+                errorHandler(deadLetterChannel("mock:error"));
+
+                from(getUrl() + "&" + OPERATION.toLowerCase() + "=" + NETWORK_MAP_FEED)
                         .to("mock:result");
             }
         };
diff --git a/components/camel-corda/src/test/java/org/apache/camel/component/corda/CordaConsumerStartTrackedFlowDynamicTest.java b/components/camel-corda/src/test/java/org/apache/camel/component/corda/CordaConsumerStartTrackedFlowDynamicTest.java
new file mode 100644
index 00000000000..96a01825000
--- /dev/null
+++ b/components/camel-corda/src/test/java/org/apache/camel/component/corda/CordaConsumerStartTrackedFlowDynamicTest.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.component.corda;
+
+import org.apache.camel.builder.RouteBuilder;
+import org.apache.camel.component.mock.MockEndpoint;
+import org.junit.Ignore;
+import org.junit.Test;
+
+import static org.apache.camel.component.corda.CordaConstants.OPERATION;
+import static org.apache.camel.component.corda.CordaConstants.START_TRACKED_FLOW_DYNAMIC;
+import static org.apache.camel.component.corda.CordaConstants.VAULT_TRACK_BY;
+
+@Ignore("This integration test requires a locally running corda node such cordapp-template-java")
+public class CordaConsumerStartTrackedFlowDynamicTest extends CordaConsumerTestSupport {
+
+
+    @Test
+    public void startTrackedFlowDynamicTest() throws Exception {
+        //Expects CamelFlow is deployed on the node
+        mockResult.expectedMinimumMessageCount(1);
+        mockError.expectedMessageCount(0);
+        MockEndpoint.assertIsSatisfied(context);
+        assertEquals("Hello world!", mockResult.getExchanges().get(0).getIn().getBody());
+    }
+
+    @Override
+    protected RouteBuilder createRouteBuilder() throws Exception {
+        return new RouteBuilder() {
+            public void configure() {
+                errorHandler(deadLetterChannel("mock:error"));
+
+                from(getUrl() + "&" + OPERATION.toLowerCase() + "=" + START_TRACKED_FLOW_DYNAMIC
+                    + "&flowLociClass=#flowLociClass"
+                    + "&arguments=#arguments")
+                        .to("mock:result");
+            }
+        };
+    }
+}
diff --git a/components/camel-corda/src/test/java/org/apache/camel/component/corda/CordaConsumerStateMachineFeedTest.java b/components/camel-corda/src/test/java/org/apache/camel/component/corda/CordaConsumerStateMachineFeedTest.java
new file mode 100644
index 00000000000..eefc988857d
--- /dev/null
+++ b/components/camel-corda/src/test/java/org/apache/camel/component/corda/CordaConsumerStateMachineFeedTest.java
@@ -0,0 +1,49 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.camel.component.corda;
+
+import org.apache.camel.builder.RouteBuilder;
+import org.apache.camel.component.mock.MockEndpoint;
+import org.junit.Ignore;
+import org.junit.Test;
+
+import static org.apache.camel.component.corda.CordaConstants.OPERATION;
+import static org.apache.camel.component.corda.CordaConstants.STATE_MACHINE_FEED;
+import static org.apache.camel.component.corda.CordaConstants.VAULT_TRACK_BY;
+
+@Ignore("This integration test requires a locally running corda node such cordapp-template-java")
+public class CordaConsumerStateMachineFeedTest extends CordaConsumerTestSupport {
+
+    @Test
+    public void stateMachineFeedTest() throws Exception {
+        mockResult.expectedMinimumMessageCount(1);
+        mockError.expectedMessageCount(0);
+        MockEndpoint.assertIsSatisfied(context);
+    }
+
+    @Override
+    protected RouteBuilder createRouteBuilder() throws Exception {
+        return new RouteBuilder() {
+            public void configure() {
+                errorHandler(deadLetterChannel("mock:error"));
+
+                from(getUrl() + "&" + OPERATION.toLowerCase() + "=" + STATE_MACHINE_FEED)
+                        .to("mock:result");
+            }
+        };
+    }
+}
diff --git a/components/camel-corda/src/test/java/org/apache/camel/component/corda/CordaConsumerTestSupport.java b/components/camel-corda/src/test/java/org/apache/camel/component/corda/CordaConsumerTestSupport.java
new file mode 100644
index 00000000000..c27dd12c408
--- /dev/null
+++ b/components/camel-corda/src/test/java/org/apache/camel/component/corda/CordaConsumerTestSupport.java
@@ -0,0 +1,62 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.camel.component.corda;
+
+import com.google.common.collect.ImmutableSet;
+import net.corda.core.contracts.OwnableState;
+import net.corda.core.flows.FlowLogic;
+import net.corda.core.node.services.Vault;
+import net.corda.core.node.services.vault.PageSpecification;
+import net.corda.core.node.services.vault.QueryCriteria;
+import net.corda.core.node.services.vault.Sort;
+import net.corda.core.node.services.vault.SortAttribute;
+import org.apache.camel.impl.JndiRegistry;
+import org.junit.Ignore;
+
+import static net.corda.core.node.services.vault.QueryCriteriaUtils.DEFAULT_PAGE_NUM;
+import static net.corda.core.node.services.vault.QueryCriteriaUtils.MAX_PAGE_SIZE;
+
+@Ignore("This integration test requires a locally running corda node such cordapp-template-java")
+public class CordaConsumerTestSupport extends CordaTestSupport {
+
+    @Override
+    public boolean isUseAdviceWith() {
+        return false;
+    }
+
+    @Override
+    protected JndiRegistry createRegistry() throws Exception {
+        JndiRegistry registry = super.createRegistry();
+
+        String [] args = new String[] {"Hello"};
+        Class<FlowLogic<String>> flowLociClass = (Class<FlowLogic<String>>) Class.forName("org.apache.camel.component.corda.CamelFlow");
+
+        QueryCriteria.VaultQueryCriteria criteria = new QueryCriteria.VaultQueryCriteria(Vault.StateStatus.CONSUMED);
+        PageSpecification pageSpec = new PageSpecification(DEFAULT_PAGE_NUM, MAX_PAGE_SIZE);
+        Sort.SortColumn sortByUid = new Sort.SortColumn(new SortAttribute.Standard(Sort.LinearStateAttribute.UUID), Sort.Direction.DESC);
+        Sort sort = new Sort(ImmutableSet.of(sortByUid));
+
+        registry.bind("contractStateClass", OwnableState.class);
+        registry.bind("queryCriteria", criteria);
+        registry.bind("pageSpecification", pageSpec);
+        registry.bind("sort", sort);
+        registry.bind("flowLociClass", flowLociClass);
+        registry.bind("arguments", args);
+        return registry;
+    }
+
+}
diff --git a/components/camel-corda/src/test/java/org/apache/camel/component/corda/CordaConsumerTransactionMapFeedTest.java b/components/camel-corda/src/test/java/org/apache/camel/component/corda/CordaConsumerTransactionMapFeedTest.java
new file mode 100644
index 00000000000..2e6c3005bfd
--- /dev/null
+++ b/components/camel-corda/src/test/java/org/apache/camel/component/corda/CordaConsumerTransactionMapFeedTest.java
@@ -0,0 +1,49 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.camel.component.corda;
+
+import org.apache.camel.builder.RouteBuilder;
+import org.apache.camel.component.mock.MockEndpoint;
+import org.junit.Ignore;
+import org.junit.Test;
+
+import static org.apache.camel.component.corda.CordaConstants.NETWORK_MAP_FEED;
+import static org.apache.camel.component.corda.CordaConstants.OPERATION;
+import static org.apache.camel.component.corda.CordaConstants.STATE_MACHINE_RECORDED_TRANSACTION_MAPPING_FEED;
+
+@Ignore("This integration test requires a locally running corda node such cordapp-template-java")
+public class CordaConsumerTransactionMapFeedTest extends CordaConsumerTestSupport {
+
+    @Test
+    public void transactionMapFeedTest() throws Exception {
+        mockResult.expectedMinimumMessageCount(1);
+        mockError.expectedMessageCount(0);
+        MockEndpoint.assertIsSatisfied(context);
+    }
+
+    @Override
+    protected RouteBuilder createRouteBuilder() throws Exception {
+        return new RouteBuilder() {
+            public void configure() {
+                errorHandler(deadLetterChannel("mock:error"));
+
+                from(getUrl() + "&" + OPERATION.toLowerCase() + "=" + STATE_MACHINE_RECORDED_TRANSACTION_MAPPING_FEED)
+                        .to("mock:result");
+            }
+        };
+    }
+}
diff --git a/components/camel-corda/src/test/java/org/apache/camel/component/corda/CordaConsumerVaultTrackByCriteriaTest.java b/components/camel-corda/src/test/java/org/apache/camel/component/corda/CordaConsumerVaultTrackByCriteriaTest.java
new file mode 100644
index 00000000000..d7048f0357c
--- /dev/null
+++ b/components/camel-corda/src/test/java/org/apache/camel/component/corda/CordaConsumerVaultTrackByCriteriaTest.java
@@ -0,0 +1,51 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.camel.component.corda;
+
+import org.apache.camel.builder.RouteBuilder;
+import org.apache.camel.component.mock.MockEndpoint;
+import org.junit.Ignore;
+import org.junit.Test;
+
+import static org.apache.camel.component.corda.CordaConstants.OPERATION;
+import static org.apache.camel.component.corda.CordaConstants.VAULT_TRACK_BY;
+import static org.apache.camel.component.corda.CordaConstants.VAULT_TRACK_BY_CRITERIA;
+
+@Ignore("This integration test requires a locally running corda node such cordapp-template-java")
+public class CordaConsumerVaultTrackByCriteriaTest extends CordaConsumerTestSupport {
+
+    @Test
+    public void vaultTrackByCriteriaTest() throws Exception {
+        mockResult.expectedMinimumMessageCount(1);
+        mockError.expectedMessageCount(0);
+        MockEndpoint.assertIsSatisfied(context);
+    }
+
+    @Override
+    protected RouteBuilder createRouteBuilder() throws Exception {
+        return new RouteBuilder() {
+            public void configure() {
+                errorHandler(deadLetterChannel("mock:error"));
+
+                from(getUrl() + "&" + OPERATION.toLowerCase() + "=" + VAULT_TRACK_BY_CRITERIA
+                        + "&contractStateClass=#contractStateClass"
+                        + "&queryCriteria=#queryCriteria")
+                        .to("mock:result");
+            }
+        };
+    }
+}
diff --git a/components/camel-corda/src/test/java/org/apache/camel/component/corda/CordaConsumerVaultTrackByTest.java b/components/camel-corda/src/test/java/org/apache/camel/component/corda/CordaConsumerVaultTrackByTest.java
new file mode 100644
index 00000000000..cbef3beb5d7
--- /dev/null
+++ b/components/camel-corda/src/test/java/org/apache/camel/component/corda/CordaConsumerVaultTrackByTest.java
@@ -0,0 +1,53 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.camel.component.corda;
+
+import org.apache.camel.builder.RouteBuilder;
+import org.apache.camel.component.mock.MockEndpoint;
+import org.junit.Ignore;
+import org.junit.Test;
+
+import static org.apache.camel.component.corda.CordaConstants.OPERATION;
+import static org.apache.camel.component.corda.CordaConstants.VAULT_TRACK;
+import static org.apache.camel.component.corda.CordaConstants.VAULT_TRACK_BY;
+
+@Ignore("This integration test requires a locally running corda node such cordapp-template-java")
+public class CordaConsumerVaultTrackByTest extends CordaConsumerTestSupport {
+
+    @Test
+    public void vaultTrackByTest() throws Exception {
+        mockResult.expectedMinimumMessageCount(1);
+        mockError.expectedMessageCount(0);
+        MockEndpoint.assertIsSatisfied(context);
+    }
+
+    @Override
+    protected RouteBuilder createRouteBuilder() throws Exception {
+        return new RouteBuilder() {
+            public void configure() {
+                errorHandler(deadLetterChannel("mock:error"));
+
+                from(getUrl() + "&" + OPERATION.toLowerCase() + "=" + VAULT_TRACK_BY
+                        + "&contractStateClass=#contractStateClass"
+                        + "&queryCriteria=#queryCriteria"
+                        + "&pageSpecification=#pageSpecification"
+                        + "&sort=#sort")
+                        .to("mock:result");
+            }
+        };
+    }
+}
diff --git a/components/camel-corda/src/test/java/org/apache/camel/component/corda/CordaConsumerVaultTrackByWithPagingSpecTest.java b/components/camel-corda/src/test/java/org/apache/camel/component/corda/CordaConsumerVaultTrackByWithPagingSpecTest.java
new file mode 100644
index 00000000000..b2fefac4d05
--- /dev/null
+++ b/components/camel-corda/src/test/java/org/apache/camel/component/corda/CordaConsumerVaultTrackByWithPagingSpecTest.java
@@ -0,0 +1,52 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.camel.component.corda;
+
+import org.apache.camel.builder.RouteBuilder;
+import org.apache.camel.component.mock.MockEndpoint;
+import org.junit.Ignore;
+import org.junit.Test;
+
+import static org.apache.camel.component.corda.CordaConstants.OPERATION;
+import static org.apache.camel.component.corda.CordaConstants.VAULT_TRACK_BY;
+import static org.apache.camel.component.corda.CordaConstants.VAULT_TRACK_BY_WITH_PAGING_SPEC;
+
+@Ignore("This integration test requires a locally running corda node such cordapp-template-java")
+public class CordaConsumerVaultTrackByWithPagingSpecTest extends CordaConsumerTestSupport {
+
+    @Test
+    public void vaultTrackByWithPagingSpecTest() throws Exception {
+        mockResult.expectedMinimumMessageCount(1);
+        mockError.expectedMessageCount(0);
+        MockEndpoint.assertIsSatisfied(context);
+    }
+
+    @Override
+    protected RouteBuilder createRouteBuilder() throws Exception {
+        return new RouteBuilder() {
+            public void configure() {
+                errorHandler(deadLetterChannel("mock:error"));
+
+                from(getUrl() + "&" + OPERATION.toLowerCase() + "=" + VAULT_TRACK_BY_WITH_PAGING_SPEC
+                        + "&contractStateClass=#contractStateClass"
+                        + "&queryCriteria=#queryCriteria"
+                        + "&pageSpecification=#pageSpecification")
+                        .to("mock:result");
+            }
+        };
+    }
+}
diff --git a/components/camel-corda/src/test/java/org/apache/camel/component/corda/CordaConsumerVaultTrackByWithSortingTest.java b/components/camel-corda/src/test/java/org/apache/camel/component/corda/CordaConsumerVaultTrackByWithSortingTest.java
new file mode 100644
index 00000000000..4835ee0a1ab
--- /dev/null
+++ b/components/camel-corda/src/test/java/org/apache/camel/component/corda/CordaConsumerVaultTrackByWithSortingTest.java
@@ -0,0 +1,52 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.camel.component.corda;
+
+import org.apache.camel.builder.RouteBuilder;
+import org.apache.camel.component.mock.MockEndpoint;
+import org.junit.Ignore;
+import org.junit.Test;
+
+import static org.apache.camel.component.corda.CordaConstants.OPERATION;
+import static org.apache.camel.component.corda.CordaConstants.VAULT_TRACK_BY;
+import static org.apache.camel.component.corda.CordaConstants.VAULT_TRACK_BY_WITH_SORTING;
+
+@Ignore("This integration test requires a locally running corda node such cordapp-template-java")
+public class CordaConsumerVaultTrackByWithSortingTest extends CordaConsumerTestSupport {
+
+    @Test
+    public void vaultTrackByWithSortingTest() throws Exception {
+        mockResult.expectedMinimumMessageCount(1);
+        mockError.expectedMessageCount(0);
+        MockEndpoint.assertIsSatisfied(context);
+    }
+
+    @Override
+    protected RouteBuilder createRouteBuilder() throws Exception {
+        return new RouteBuilder() {
+            public void configure() {
+                errorHandler(deadLetterChannel("mock:error"));
+
+                from(getUrl() + "&" + OPERATION.toLowerCase() + "=" + VAULT_TRACK_BY_WITH_SORTING
+                        + "&contractStateClass=#contractStateClass"
+                        + "&queryCriteria=#queryCriteria"
+                        + "&sort=#sort")
+                        .to("mock:result");
+            }
+        };
+    }
+}
diff --git a/components/camel-corda/src/test/java/org/apache/camel/component/corda/CordaConsumerVaultTrackTest.java b/components/camel-corda/src/test/java/org/apache/camel/component/corda/CordaConsumerVaultTrackTest.java
new file mode 100644
index 00000000000..b5ffa430415
--- /dev/null
+++ b/components/camel-corda/src/test/java/org/apache/camel/component/corda/CordaConsumerVaultTrackTest.java
@@ -0,0 +1,49 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.camel.component.corda;
+
+import org.apache.camel.builder.RouteBuilder;
+import org.apache.camel.component.mock.MockEndpoint;
+import org.junit.Ignore;
+import org.junit.Test;
+
+import static org.apache.camel.component.corda.CordaConstants.OPERATION;
+import static org.apache.camel.component.corda.CordaConstants.VAULT_TRACK;
+
+@Ignore("This integration test requires a locally running corda node such cordapp-template-java")
+public class CordaConsumerVaultTrackTest extends CordaConsumerTestSupport {
+
+    @Test
+    public void vaultTrackTest() throws Exception {
+        mockResult.expectedMinimumMessageCount(1);
+        mockError.expectedMessageCount(0);
+        MockEndpoint.assertIsSatisfied(context);
+    }
+
+    @Override
+    protected RouteBuilder createRouteBuilder() throws Exception {
+        return new RouteBuilder() {
+            public void configure() {
+                errorHandler(deadLetterChannel("mock:error"));
+
+                from(getUrl() + "&" + OPERATION.toLowerCase() + "=" + VAULT_TRACK
+                        + "&contractStateClass=#contractStateClass")
+                        .to("mock:result");
+            }
+        };
+    }
+}
diff --git a/components/camel-corda/src/test/java/org/apache/camel/component/corda/CordaProducerTest.java b/components/camel-corda/src/test/java/org/apache/camel/component/corda/CordaProducerTest.java
new file mode 100644
index 00000000000..c76a663a4a6
--- /dev/null
+++ b/components/camel-corda/src/test/java/org/apache/camel/component/corda/CordaProducerTest.java
@@ -0,0 +1,498 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.camel.component.corda;
+
+import java.io.ByteArrayInputStream;
+import java.io.ByteArrayOutputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.security.KeyPair;
+import java.security.KeyPairGenerator;
+import java.security.NoSuchAlgorithmException;
+import java.security.PublicKey;
+import java.util.zip.ZipEntry;
+import java.util.zip.ZipOutputStream;
+import com.google.common.collect.ImmutableSet;
+import net.corda.core.contracts.OwnableState;
+import net.corda.core.crypto.SecureHash;
+import net.corda.core.flows.FlowLogic;
+import net.corda.core.identity.AbstractParty;
+import net.corda.core.identity.AnonymousParty;
+import net.corda.core.identity.CordaX500Name;
+import net.corda.core.identity.Party;
+import net.corda.core.node.services.Vault;
+import net.corda.core.node.services.vault.AttachmentQueryCriteria;
+import net.corda.core.node.services.vault.AttachmentSort;
+import net.corda.core.node.services.vault.ColumnPredicate;
+import net.corda.core.node.services.vault.EqualityComparisonOperator;
+import net.corda.core.node.services.vault.PageSpecification;
+import net.corda.core.node.services.vault.QueryCriteria;
+import net.corda.core.node.services.vault.Sort;
+import net.corda.core.node.services.vault.SortAttribute;
+import org.apache.camel.Exchange;
+import org.apache.camel.Produce;
+import org.apache.camel.ProducerTemplate;
+import org.apache.camel.builder.RouteBuilder;
+import org.junit.Ignore;
+import org.junit.Test;
+
+import static net.corda.core.node.services.vault.QueryCriteriaUtils.DEFAULT_PAGE_NUM;
+import static net.corda.core.node.services.vault.QueryCriteriaUtils.MAX_PAGE_SIZE;
+import static org.apache.camel.component.corda.CordaConstants.ADD_VAULT_TRANSACTION_NOTE;
+import static org.apache.camel.component.corda.CordaConstants.ARGUMENTS;
+import static org.apache.camel.component.corda.CordaConstants.ATTACHMENT_EXISTS;
+import static org.apache.camel.component.corda.CordaConstants.ATTACHMENT_QUERY_CRITERIA;
+import static org.apache.camel.component.corda.CordaConstants.CLEAR_NETWORK_MAP_CACHE;
+import static org.apache.camel.component.corda.CordaConstants.CURRENT_NODE_TIME;
+import static org.apache.camel.component.corda.CordaConstants.DRAINING_MODE;
+import static org.apache.camel.component.corda.CordaConstants.EXACT_MATCH;
+import static org.apache.camel.component.corda.CordaConstants.GET_PROTOCOL_VERSION;
+import static org.apache.camel.component.corda.CordaConstants.GET_VAULT_TRANSACTION_NOTES;
+import static org.apache.camel.component.corda.CordaConstants.IS_FLOWS_DRAINING_MODE_ENABLED;
+import static org.apache.camel.component.corda.CordaConstants.NETWORK_MAP_SNAPSHOT;
+import static org.apache.camel.component.corda.CordaConstants.NODE_INFO;
+import static org.apache.camel.component.corda.CordaConstants.NODE_INFO_FROM_PARTY;
+import static org.apache.camel.component.corda.CordaConstants.NOTARY_IDENTITIES;
+import static org.apache.camel.component.corda.CordaConstants.NOTARY_PARTY_FROM_X500_NAME;
+import static org.apache.camel.component.corda.CordaConstants.OPEN_ATTACHMENT;
+import static org.apache.camel.component.corda.CordaConstants.OPERATION;
+import static org.apache.camel.component.corda.CordaConstants.PAGE_SPECIFICATION;
+import static org.apache.camel.component.corda.CordaConstants.PARTIES_FROM_KEY;
+import static org.apache.camel.component.corda.CordaConstants.PARTIES_FROM_NAME;
+import static org.apache.camel.component.corda.CordaConstants.QUERY_ATTACHMENTS;
+import static org.apache.camel.component.corda.CordaConstants.QUERY_CRITERIA;
+import static org.apache.camel.component.corda.CordaConstants.REGISTERED_FLOWS;
+import static org.apache.camel.component.corda.CordaConstants.SECURE_HASH;
+import static org.apache.camel.component.corda.CordaConstants.SET_FLOWS_DRAINING_MODE_ENABLED;
+import static org.apache.camel.component.corda.CordaConstants.SORT;
+import static org.apache.camel.component.corda.CordaConstants.START_FLOW_DYNAMIC;
+import static org.apache.camel.component.corda.CordaConstants.STATE_MACHINE_RECORDED_TRANSACTION_MAPPING_SNAPSHOT;
+import static org.apache.camel.component.corda.CordaConstants.STATE_MACHINE_SNAPSHOT;
+import static org.apache.camel.component.corda.CordaConstants.UPLOAD_ATTACHMENT;
+import static org.apache.camel.component.corda.CordaConstants.VAULT_QUERY;
+import static org.apache.camel.component.corda.CordaConstants.VAULT_QUERY_BY;
+import static org.apache.camel.component.corda.CordaConstants.VAULT_QUERY_BY_CRITERIA;
+import static org.apache.camel.component.corda.CordaConstants.VAULT_QUERY_BY_WITH_PAGING_SPEC;
+import static org.apache.camel.component.corda.CordaConstants.VAULT_QUERY_BY_WITH_SORTING;
+import static org.apache.camel.component.corda.CordaConstants.WELL_KNOWN_PARTY_FROM_ANONYMOUS;
+import static org.apache.camel.component.corda.CordaConstants.WELL_KNOWN_PARTY_FROM_X500_NAME;
+
+@Ignore("This integration test requires a locally running corda node such cordapp-template-java")
+public class CordaProducerTest extends CordaTestSupport {
+    private static final SecureHash.SHA256 TEST_SHA_256 = SecureHash.parse("6D1687C143DF792A011A1E80670A4E4E0C25D0D87A39514409B1ABFC2043581F");
+
+    @Produce(uri = "direct:start")
+    protected ProducerTemplate template;
+
+    @Override
+    public boolean isUseAdviceWith() {
+        return false;
+    }
+
+    @Test
+    public void currentNodeTimeTest() throws Exception {
+        Exchange exchange = createExchangeWithBodyAndHeader(null, OPERATION, CURRENT_NODE_TIME);
+        template.send(exchange);
+        Object body = exchange.getIn().getBody();
+        assertNotNull(body);
+        Object exception = exchange.getException();
+        assertNull(exception);
+    }
+
+    @Test
+    public void getProtocolVersionTest() throws Exception {
+        Exchange exchange = createExchangeWithBodyAndHeader(null, OPERATION, GET_PROTOCOL_VERSION);
+        template.send(exchange);
+        Object body = exchange.getIn().getBody();
+        assertNotNull(body);
+        Object exception = exchange.getException();
+        assertNull(exception);
+    }
+
+    @Test
+    public void networkMapSnapshotTest() throws Exception {
+        Exchange exchange = createExchangeWithBodyAndHeader(null, OPERATION, NETWORK_MAP_SNAPSHOT);
+        template.send(exchange);
+        Object body = exchange.getIn().getBody();
+        assertNotNull(body);
+        Object exception = exchange.getException();
+        assertNull(exception);
+    }
+
+    @Test
+    public void stateMachinesSnapshotTest() throws Exception {
+        Exchange exchange = createExchangeWithBodyAndHeader(null, OPERATION, STATE_MACHINE_SNAPSHOT);
+        template.send(exchange);
+        Object body = exchange.getIn().getBody();
+        assertNotNull(body);
+        Object exception = exchange.getException();
+        assertNull(exception);
+    }
+
+    @Test
+    public void stateMachineRecordedTransactionMappingSnapshotTest() throws Exception {
+        Exchange exchange = createExchangeWithBodyAndHeader(null, OPERATION, STATE_MACHINE_RECORDED_TRANSACTION_MAPPING_SNAPSHOT);
+        template.send(exchange);
+        Object body = exchange.getIn().getBody();
+        assertNotNull(body);
+        Object exception = exchange.getException();
+        assertNull(exception);
+    }
+
+    @Test
+    public void registeredFlowsTest() throws Exception {
+        Exchange exchange = createExchangeWithBodyAndHeader(null, OPERATION, REGISTERED_FLOWS);
+        template.send(exchange);
+        Object body = exchange.getIn().getBody();
+        assertNotNull(body);
+        Object exception = exchange.getException();
+        assertNull(exception);
+    }
+
+    @Test
+    public void clearNetworkMapCacheTest() throws Exception {
+        Exchange exchange = createExchangeWithBodyAndHeader(null, OPERATION, CLEAR_NETWORK_MAP_CACHE);
+        template.send(exchange);
+        Object body = exchange.getException();
+        assertNull(body);
+        Object exception = exchange.getException();
+        assertNull(exception);
+    }
+
+    @Test
+    public void isFlowsDrainingModeEnabledTest() throws Exception {
+        Exchange exchange = createExchangeWithBodyAndHeader(null, OPERATION, IS_FLOWS_DRAINING_MODE_ENABLED);
+        template.send(exchange);
+        Object body = exchange.getIn().getBody();
+        assertNotNull(body);
+        Object exception = exchange.getException();
+        assertNull(exception);
+    }
+
+    @Test
+    public void setFlowsDrainingModeEnabledTest() throws Exception {
+        Exchange exchange = createExchangeWithBodyAndHeader(null, OPERATION, SET_FLOWS_DRAINING_MODE_ENABLED);
+        exchange.getIn().setHeader(DRAINING_MODE, false);
+        template.send(exchange);
+        Object exception = exchange.getException();
+        assertNull(exception);
+    }
+
+    @Test
+    public void notaryIdentitiesTest() throws Exception {
+        Exchange exchange = createExchangeWithBodyAndHeader(null, OPERATION, NOTARY_IDENTITIES);
+        template.send(exchange);
+        Object body = exchange.getIn().getBody();
+        assertNotNull(body);
+        Object exception = exchange.getException();
+        assertNull(exception);
+    }
+
+    @Test
+    public void nodeInfoTest() throws Exception {
+        Exchange exchange = createExchangeWithBodyAndHeader(null, OPERATION, NODE_INFO);
+        template.send(exchange);
+        Object body = exchange.getIn().getBody();
+        assertNotNull(body);
+        Object exception = exchange.getException();
+        assertNull(exception);
+    }
+
+    @Test
+    public void addVaultTransactionNoteTest() throws Exception {
+        Exchange exchange = createExchangeWithBodyAndHeader("Some note", OPERATION, ADD_VAULT_TRANSACTION_NOTE);
+
+        exchange.getIn().setHeader(SECURE_HASH, TEST_SHA_256);
+        template.send(exchange);
+        Object exception = exchange.getException();
+        assertNull(exception);
+    }
+
+    @Test
+    public void getVaultTransactionNotesTest() throws Exception {
+        Exchange exchange = createExchangeWithBodyAndHeader(null, OPERATION, GET_VAULT_TRANSACTION_NOTES);
+
+        exchange.getIn().setHeader(SECURE_HASH, TEST_SHA_256);
+        template.send(exchange);
+        Object body = exchange.getIn().getBody();
+        assertNotNull(body);
+        Object exception = exchange.getException();
+        assertNull(exception);
+    }
+
+    @Test
+    public void uploadAttachmentTest() throws Exception {
+        Exchange exchange = createExchangeWithBodyAndHeader(null, OPERATION, UPLOAD_ATTACHMENT);
+        exchange.getIn().setBody(zipIt("HELLO" + System.nanoTime(), "test1.txt"));
+        template.send(exchange);
+
+        Object body = exchange.getIn().getHeader(SECURE_HASH);
+        assertNotNull(body);
+        Object exception = exchange.getException();
+        assertNull(exception);
+    }
+
+    @Test
+    public void attachmentExistsTest() throws Exception {
+        Exchange exchange = createExchangeWithBodyAndHeader(null, OPERATION, ATTACHMENT_EXISTS);
+        exchange.getIn().setHeader(SECURE_HASH, TEST_SHA_256);
+
+        template.send(exchange);
+
+        Boolean body = exchange.getIn().getBody(Boolean.class);
+        assertNotNull(body);
+        Object exception = exchange.getException();
+        assertNull(exception);
+    }
+
+    @Test
+    public void openAttachmentTest() throws Exception {
+        //Setup node with attachment
+        Exchange uploadExchange = createExchangeWithBodyAndHeader(null, OPERATION, UPLOAD_ATTACHMENT);
+        uploadExchange.getIn().setBody(zipIt("HELLO" + System.nanoTime(), "test2.txt"));
+        template.send(uploadExchange);
+
+        Object hash = uploadExchange.getIn().getHeader(SECURE_HASH);
+        Exchange exchange = createExchangeWithBodyAndHeader(null, OPERATION, OPEN_ATTACHMENT);
+        exchange.getIn().setHeader(SECURE_HASH, hash);
+
+        template.send(exchange);
+
+        InputStream body = exchange.getIn().getBody(InputStream.class);
+        assertNotNull(body);
+        Object exception = exchange.getException();
+        assertNull(exception);
+    }
+
+    @Test
+    public void queryAttachmentsTest() throws Exception {
+        Exchange exchange = createExchangeWithBodyAndHeader(null, OPERATION, QUERY_ATTACHMENTS);
+        AttachmentQueryCriteria.AttachmentsQueryCriteria queryCriteria =
+                new AttachmentQueryCriteria.AttachmentsQueryCriteria(
+                        new ColumnPredicate.EqualityComparison(EqualityComparisonOperator.EQUAL, "Daredevil"));
+        AttachmentSort attachmentSort = null;
+
+        exchange.getIn().setHeader(ATTACHMENT_QUERY_CRITERIA, queryCriteria);
+        exchange.getIn().setHeader(SORT, attachmentSort);
+
+        template.send(exchange);
+        Object body = exchange.getIn().getBody();
+        assertNotNull(body);
+        Object exception = exchange.getException();
+        assertNull(exception);
+    }
+
+    @Test
+    public void nodeInfoFromPartyTest() throws Exception {
+        //Expects IntegrationWhiteList is deployed on the node
+        Exchange exchange = createExchangeWithBodyAndHeader(null, OPERATION, NODE_INFO_FROM_PARTY);
+        PublicKey pub = generatePublicKey();
+        CordaX500Name cordaX500Name1 = new CordaX500Name("PartyA", "London", "GB");
+        Party party = new Party(cordaX500Name1, pub);
+        exchange.getIn().setBody(party);
+
+        template.send(exchange);
+        Object exception = exchange.getException();
+        assertNull(exception);
+    }
+
+    @Test
+    public void notaryPartyFromX500NameTest() throws Exception {
+        Exchange exchange = createExchangeWithBodyAndHeader(null, OPERATION, NOTARY_PARTY_FROM_X500_NAME);
+        CordaX500Name cordaX500Name = new CordaX500Name("Notary", "London", "GB");
+        exchange.getIn().setBody(cordaX500Name);
+
+        template.send(exchange);
+        Object body = exchange.getIn().getBody();
+        assertNotNull(body);
+        Object exception = exchange.getException();
+        assertNull(exception);
+    }
+
+    @Test
+    public void partiesFromNameTest() throws Exception {
+        Exchange exchange = createExchangeWithBodyAndHeader("A", OPERATION, PARTIES_FROM_NAME);
+        exchange.getIn().setHeader(EXACT_MATCH, false);
+
+        template.send(exchange);
+        Object body = exchange.getIn().getBody();
+        assertNotNull(body);
+        Object exception = exchange.getException();
+        assertNull(exception);
+    }
+
+    @Test
+    public void partyFromKeyTest() throws Exception {
+        //Expects IntegrationWhiteList is deployed on the node
+        Exchange exchange = createExchangeWithBodyAndHeader(null, OPERATION, PARTIES_FROM_KEY);
+        PublicKey pub = generatePublicKey();
+        exchange.getIn().setBody(pub);
+
+        template.send(exchange);
+        Object exception = exchange.getException();
+        assertNull(exception);
+    }
+
+    @Test
+    public void wellKnownPartyFromX500NameTest() throws Exception {
+        Exchange exchange = createExchangeWithBodyAndHeader(null, OPERATION, WELL_KNOWN_PARTY_FROM_X500_NAME);
+        CordaX500Name cordaX500Name1 = new CordaX500Name("PartyA", "London", "GB");
+        exchange.getIn().setBody(cordaX500Name1);
+
+        template.send(exchange);
+        Object body = exchange.getIn().getBody();
+        assertNotNull(body);
+        Object exception = exchange.getException();
+        assertNull(exception);
+    }
+
+    @Test
+    public void wellKnownPartyFromAnonymousTest() throws Exception {
+        //Expects IntegrationWhiteList is deployed on the node
+        Exchange exchange = createExchangeWithBodyAndHeader(null, OPERATION, WELL_KNOWN_PARTY_FROM_ANONYMOUS);
+        PublicKey pub = generatePublicKey();
+
+        AbstractParty party = new AnonymousParty(pub);
+        exchange.getIn().setBody(party);
+
+        template.send(exchange);
+        Object exception = exchange.getException();
+        assertNull(exception);
+    }
+
+    @Test
+    public void startFlowDynamicTest() throws Exception {
+        //Expects CamelFlow is deployed on the node
+        Exchange exchange = createExchangeWithBodyAndHeader(null, OPERATION, START_FLOW_DYNAMIC);
+        String [] args = new String[] {"Hello"};
+        Class<FlowLogic<String>> aClass = (Class<FlowLogic<String>>) Class.forName("org.apache.camel.component.corda.CamelFlow");
+        exchange.getIn().setBody(aClass);
+        exchange.getIn().setHeader(ARGUMENTS, args);
+
+        template.send(exchange);
+        Object body = exchange.getIn().getBody();
+        assertNotNull(body);
+        assertEquals("Hello world!", body.toString());
+        Object exception = exchange.getException();
+        assertNull(exception);
+    }
+
+    @Test
+    public void vaultQueryTest() throws Exception {
+        Exchange exchange = createExchangeWithBodyAndHeader(OwnableState.class, OPERATION, VAULT_QUERY);
+
+        template.send(exchange);
+        Object body = exchange.getIn().getBody();
+        assertNotNull(body);
+        Object exception = exchange.getException();
+        assertNull(exception);
+    }
+
+    @Test
+    public void vaultQueryByTest() throws Exception {
+        Exchange exchange = createExchangeWithBodyAndHeader(OwnableState.class, OPERATION, VAULT_QUERY_BY);
+        QueryCriteria.VaultQueryCriteria criteria = new QueryCriteria.VaultQueryCriteria(Vault.StateStatus.CONSUMED);
+        PageSpecification pageSpec = new PageSpecification(DEFAULT_PAGE_NUM, MAX_PAGE_SIZE);
+        Sort.SortColumn sortByUid = new Sort.SortColumn(new SortAttribute.Standard(Sort.LinearStateAttribute.UUID), Sort.Direction.DESC);
+        Sort sorting = new Sort(ImmutableSet.of(sortByUid));
+        exchange.getIn().setHeader(QUERY_CRITERIA, criteria);
+        exchange.getIn().setHeader(PAGE_SPECIFICATION, pageSpec);
+        exchange.getIn().setHeader(SORT, sorting);
+
+        template.send(exchange);
+        Object body = exchange.getIn().getBody();
+        assertNotNull(body);
+        Object exception = exchange.getException();
+        assertNull(exception);
+    }
+
+    @Test
+    public void vaultQueryByCriteriaTest() throws Exception {
+        Exchange exchange = createExchangeWithBodyAndHeader(OwnableState.class, OPERATION, VAULT_QUERY_BY_CRITERIA);
+        QueryCriteria.VaultQueryCriteria criteria = new QueryCriteria.VaultQueryCriteria(Vault.StateStatus.CONSUMED);
+        exchange.getIn().setHeader(QUERY_CRITERIA, criteria);
+
+        template.send(exchange);
+        Object body = exchange.getIn().getBody();
+        assertNotNull(body);
+        Object exception = exchange.getException();
+        assertNull(exception);
+    }
+
+    @Test
+    public void vaultQueryByWithPagingSpecTest() throws Exception {
+        Exchange exchange = createExchangeWithBodyAndHeader(OwnableState.class, OPERATION, VAULT_QUERY_BY_WITH_PAGING_SPEC);
+        QueryCriteria.VaultQueryCriteria criteria = new QueryCriteria.VaultQueryCriteria(Vault.StateStatus.CONSUMED);
+        PageSpecification pageSpec = new PageSpecification(DEFAULT_PAGE_NUM, MAX_PAGE_SIZE);
+        exchange.getIn().setHeader(QUERY_CRITERIA, criteria);
+        exchange.getIn().setHeader(PAGE_SPECIFICATION, pageSpec);
+
+        template.send(exchange);
+        Object body = exchange.getIn().getBody();
+        assertNotNull(body);
+        Object exception = exchange.getException();
+        assertNull(exception);
+    }
+
+    @Test
+    public void vaultQueryByWithSortingTest() throws Exception {
+        Exchange exchange = createExchangeWithBodyAndHeader(OwnableState.class, OPERATION, VAULT_QUERY_BY_WITH_SORTING);
+        QueryCriteria.VaultQueryCriteria criteria = new QueryCriteria.VaultQueryCriteria(Vault.StateStatus.CONSUMED);
+        Sort.SortColumn sortByUid = new Sort.SortColumn(new SortAttribute.Standard(Sort.LinearStateAttribute.UUID), Sort.Direction.DESC);
+        Sort sorting = new Sort(ImmutableSet.of(sortByUid));
+        exchange.getIn().setHeader(QUERY_CRITERIA, criteria);
+        exchange.getIn().setHeader(SORT, sorting);
+
+        template.send(exchange);
+        Object body = exchange.getIn().getBody();
+        assertNotNull(body);
+        Object exception = exchange.getException();
+        assertNull(exception);
+    }
+
+    private ByteArrayInputStream zipIt(String in, String name) {
+        ByteArrayOutputStream baos = new ByteArrayOutputStream();
+        try {
+            ZipOutputStream zos = new ZipOutputStream(baos);
+            ZipEntry entry = new ZipEntry(name);
+            zos.putNextEntry(entry);
+            zos.write(in.getBytes());
+            zos.closeEntry();
+        } catch (IOException ioe) {
+            ioe.printStackTrace();
+        }
+
+        return new ByteArrayInputStream(baos.toByteArray());
+    }
+
+    private PublicKey generatePublicKey() throws NoSuchAlgorithmException {
+        KeyPairGenerator kpg = KeyPairGenerator.getInstance("RSA");
+        kpg.initialize(2048);
+        KeyPair kp = kpg.generateKeyPair();
+        return kp.getPublic();
+    }
+
+    @Override
+    protected RouteBuilder createRouteBuilder() throws Exception {
+        return new RouteBuilder() {
+            public void configure() {
+                from("direct:start")
+                        .to(getUrl());
+            }
+        };
+    }
+}
diff --git a/components/camel-corda/src/test/java/org/apache/camel/component/corda/CordaTestSupport.java b/components/camel-corda/src/test/java/org/apache/camel/component/corda/CordaTestSupport.java
new file mode 100755
index 00000000000..7586e3fd56b
--- /dev/null
+++ b/components/camel-corda/src/test/java/org/apache/camel/component/corda/CordaTestSupport.java
@@ -0,0 +1,74 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.camel.component.corda;
+
+import org.apache.camel.EndpointInject;
+import org.apache.camel.Exchange;
+import org.apache.camel.component.mock.MockEndpoint;
+import org.apache.camel.impl.DefaultExchange;
+import org.apache.camel.impl.JndiRegistry;
+import org.apache.camel.test.junit4.CamelTestSupport;
+import org.junit.AfterClass;
+import org.junit.Before;
+import org.junit.BeforeClass;
+import org.mockito.MockitoAnnotations;
+
+public class CordaTestSupport extends CamelTestSupport {
+
+    @EndpointInject(uri = "mock:result")
+    protected MockEndpoint mockResult;
+
+    @EndpointInject(uri = "mock:error")
+    protected MockEndpoint mockError;
+
+    @Override
+    public boolean isUseAdviceWith() {
+        return true;
+    }
+
+    @Override
+    protected JndiRegistry createRegistry() throws Exception {
+        JndiRegistry registry = super.createRegistry();
+        return registry;
+    }
+
+    protected String getUrl() {
+        return "corda://localhost:10006?username=user1&password=test";
+    }
+
+    protected Exchange createExchangeWithBodyAndHeader(Object body, String key, Object value) {
+        DefaultExchange exchange = new DefaultExchange(context);
+        exchange.getIn().setBody(body);
+        exchange.getIn().setHeader(key, value);
+        return exchange;
+    }
+
+    @BeforeClass
+    public static void startServer() throws Exception {
+    }
+
+    @AfterClass
+    public static void stopServer() throws Exception {
+    }
+
+    @Override
+    @Before
+    public void setUp() throws Exception {
+        MockitoAnnotations.initMocks(this);
+        super.setUp();
+    }
+}
diff --git a/components/camel-corda/src/test/java/org/apache/camel/component/corda/IntegrationWhiteList.java b/components/camel-corda/src/test/java/org/apache/camel/component/corda/IntegrationWhiteList.java
new file mode 100644
index 00000000000..cdee2859f8a
--- /dev/null
+++ b/components/camel-corda/src/test/java/org/apache/camel/component/corda/IntegrationWhiteList.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.component.corda;
+
+import java.util.ArrayList;
+import java.util.List;
+import net.corda.core.serialization.SerializationWhitelist;
+
+public class IntegrationWhiteList implements SerializationWhitelist {
+
+    @Override
+    public List<Class<?>> getWhitelist() {
+        List list = new ArrayList();
+//        list.add(RSAPublicKeyImpl.class);
+//        list.add(AlgorithmId.class);
+//        list.add(ObjectIdentifier.class);
+//        list.add(BitArray.class);
+//        list.add(BigInteger.class);
+        return list;
+    }
+}
diff --git a/components/camel-corda/src/test/resources/META-INF/services/net.corda.core.serialization.SerializationWhitelist b/components/camel-corda/src/test/resources/META-INF/services/net.corda.core.serialization.SerializationWhitelist
new file mode 100644
index 00000000000..8c42a02ebee
--- /dev/null
+++ b/components/camel-corda/src/test/resources/META-INF/services/net.corda.core.serialization.SerializationWhitelist
@@ -0,0 +1 @@
+org.apache.camel.component.corda.IntegrationWhiteList
diff --git a/components/camel-corda/src/test/resources/log4j2.properties b/components/camel-corda/src/test/resources/log4j2.properties
new file mode 100644
index 00000000000..952c0fb4796
--- /dev/null
+++ b/components/camel-corda/src/test/resources/log4j2.properties
@@ -0,0 +1,34 @@
+## ---------------------------------------------------------------------------
+## 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.
+## ---------------------------------------------------------------------------
+rootLogger.level = DEBUG
+rootLogger.appenderRef.file.ref = file
+
+appender.file.type = File
+appender.file.name = file
+appender.file.fileName = target/camel-corda-test.log
+appender.file.layout.type = PatternLayout
+appender.file.layout.pattern = %d [%-15.15t] %-5p %-30.30c{1} - %m%n
+
+appender.out.type = Console
+appender.out.name = out
+appender.out.layout.type = PatternLayout
+appender.out.layout.pattern = %d [%-15.15t] %-5p %-30.30c{1} - %m%n
+
+#rootLogger.org.fabric=DEBUG
+#rootLogger.org.apache.http=DEBUG
+
+
diff --git a/components/camel-corda/src/test/resources/mockito-extensions/org.mockito.plugins.MockMaker b/components/camel-corda/src/test/resources/mockito-extensions/org.mockito.plugins.MockMaker
new file mode 100644
index 00000000000..ca6ee9cea8e
--- /dev/null
+++ b/components/camel-corda/src/test/resources/mockito-extensions/org.mockito.plugins.MockMaker
@@ -0,0 +1 @@
+mock-maker-inline
\ No newline at end of file
diff --git a/components/camel-core-osgi/pom.xml b/components/camel-core-osgi/pom.xml
index ef0508ea91e..9cf8183c40c 100644
--- a/components/camel-core-osgi/pom.xml
+++ b/components/camel-core-osgi/pom.xml
@@ -23,7 +23,7 @@
   <parent>
     <groupId>org.apache.camel</groupId>
     <artifactId>components</artifactId>
-    <version>2.23.0-SNAPSHOT</version>
+    <version>2.24.0-SNAPSHOT</version>
   </parent>
 
   <artifactId>camel-core-osgi</artifactId>
diff --git a/components/camel-core-xml/pom.xml b/components/camel-core-xml/pom.xml
index b61504f3ab7..d60287333ac 100644
--- a/components/camel-core-xml/pom.xml
+++ b/components/camel-core-xml/pom.xml
@@ -23,7 +23,7 @@
   <parent>
     <groupId>org.apache.camel</groupId>
     <artifactId>components</artifactId>
-    <version>2.23.0-SNAPSHOT</version>
+    <version>2.24.0-SNAPSHOT</version>
   </parent>
 
   <artifactId>camel-core-xml</artifactId>
diff --git a/components/camel-couchbase/pom.xml b/components/camel-couchbase/pom.xml
index 0ec87a51e43..487710a7c1f 100644
--- a/components/camel-couchbase/pom.xml
+++ b/components/camel-couchbase/pom.xml
@@ -23,7 +23,7 @@
   <parent>
     <groupId>org.apache.camel</groupId>
     <artifactId>components</artifactId>
-    <version>2.23.0-SNAPSHOT</version>
+    <version>2.24.0-SNAPSHOT</version>
   </parent>
 
   <artifactId>camel-couchbase</artifactId>
diff --git a/components/camel-couchdb/pom.xml b/components/camel-couchdb/pom.xml
index bd45a8fe991..5aeb88b954b 100644
--- a/components/camel-couchdb/pom.xml
+++ b/components/camel-couchdb/pom.xml
@@ -24,7 +24,7 @@
 	<parent>
 		<groupId>org.apache.camel</groupId>
 		<artifactId>components</artifactId>
-		<version>2.23.0-SNAPSHOT</version>
+		<version>2.24.0-SNAPSHOT</version>
 	</parent>
 
 	<artifactId>camel-couchdb</artifactId>
diff --git a/components/camel-crypto-cms/pom.xml b/components/camel-crypto-cms/pom.xml
index 13284065643..770d2de7306 100644
--- a/components/camel-crypto-cms/pom.xml
+++ b/components/camel-crypto-cms/pom.xml
@@ -24,7 +24,7 @@
   <parent>
     <groupId>org.apache.camel</groupId>
     <artifactId>components</artifactId>
-    <version>2.23.0-SNAPSHOT</version>
+    <version>2.24.0-SNAPSHOT</version>
   </parent>
 
   <artifactId>camel-crypto-cms</artifactId>
diff --git a/components/camel-crypto/pom.xml b/components/camel-crypto/pom.xml
index 2bfe4c27834..45ae8fd7402 100644
--- a/components/camel-crypto/pom.xml
+++ b/components/camel-crypto/pom.xml
@@ -23,7 +23,7 @@
 	<parent>
 		<groupId>org.apache.camel</groupId>
 		<artifactId>components</artifactId>
-		<version>2.23.0-SNAPSHOT</version>
+		<version>2.24.0-SNAPSHOT</version>
 	</parent>
 
 	<artifactId>camel-crypto</artifactId>
diff --git a/components/camel-csv/pom.xml b/components/camel-csv/pom.xml
index 3fb92c2526d..7dae89ccef8 100644
--- a/components/camel-csv/pom.xml
+++ b/components/camel-csv/pom.xml
@@ -23,7 +23,7 @@
   <parent>
     <groupId>org.apache.camel</groupId>
     <artifactId>components</artifactId>
-    <version>2.23.0-SNAPSHOT</version>
+    <version>2.24.0-SNAPSHOT</version>
   </parent>
 
   <artifactId>camel-csv</artifactId>
diff --git a/components/camel-cxf-transport/pom.xml b/components/camel-cxf-transport/pom.xml
index 02e1480417d..751495bea11 100644
--- a/components/camel-cxf-transport/pom.xml
+++ b/components/camel-cxf-transport/pom.xml
@@ -23,7 +23,7 @@
   <parent>
     <groupId>org.apache.camel</groupId>
     <artifactId>components</artifactId>
-    <version>2.23.0-SNAPSHOT</version>
+    <version>2.24.0-SNAPSHOT</version>
   </parent>
 
   <artifactId>camel-cxf-transport</artifactId>
diff --git a/components/camel-cxf/pom.xml b/components/camel-cxf/pom.xml
index 13146000b94..1a3facce9ef 100644
--- a/components/camel-cxf/pom.xml
+++ b/components/camel-cxf/pom.xml
@@ -24,7 +24,7 @@
   <parent>
     <groupId>org.apache.camel</groupId>
     <artifactId>components</artifactId>
-    <version>2.23.0-SNAPSHOT</version>
+    <version>2.24.0-SNAPSHOT</version>
   </parent>
 
   <artifactId>camel-cxf</artifactId>
diff --git a/components/camel-cxf/src/main/docs/cxf-component.adoc b/components/camel-cxf/src/main/docs/cxf-component.adoc
index df9ea783f95..bb006a5ef62 100644
--- a/components/camel-cxf/src/main/docs/cxf-component.adoc
+++ b/components/camel-cxf/src/main/docs/cxf-component.adoc
@@ -812,7 +812,7 @@ response context with the following code:
          // Get the response context form outMessage
          Map<String, Object> responseContext = CastUtils.cast((Map)out.getHeader(Client.RESPONSE_CONTEXT));
          assertNotNull(responseContext);
-         assertEquals("Get the wrong wsdl opertion name", "{http://apache.org/hello_world_soap_http}greetMe",
+         assertEquals("Get the wrong wsdl operation name", "{http://apache.org/hello_world_soap_http}greetMe",
                       responseContext.get("javax.xml.ws.wsdl.operation").toString());
 -------------------------------------------------------------------------------------------------------------
 
@@ -824,7 +824,7 @@ Attachment is not tested.  Since attachments are marshalled and
 unmarshalled into POJOs, users typically do not need to deal with the
 attachment themself.  Attachments are propagated to Camel message's
 attachments if the MTOM is not enabled, since Camel 2.12.3.  So, it is
-possible to retreive attachments by Camel Message API
+possible to retrieve attachments by Camel Message API
 
 [source,java]
 --------------------------------------------
diff --git a/components/camel-cxf/src/main/resources/META-INF/spring.schemas b/components/camel-cxf/src/main/resources/META-INF/spring.schemas
index 62cba3af8ec..e3d3c0a89e7 100644
--- a/components/camel-cxf/src/main/resources/META-INF/spring.schemas
+++ b/components/camel-cxf/src/main/resources/META-INF/spring.schemas
@@ -126,4 +126,5 @@ http\://camel.apache.org/schema/cxf/camel-cxf-2.21.3.xsd=schema/cxfEndpoint.xsd
 http\://camel.apache.org/schema/cxf/camel-cxf-2.22.0.xsd=schema/cxfEndpoint.xsd
 http\://camel.apache.org/schema/cxf/camel-cxf-2.22.1.xsd=schema/cxfEndpoint.xsd
 http\://camel.apache.org/schema/cxf/camel-cxf-2.22.2.xsd=schema/cxfEndpoint.xsd
+http\://camel.apache.org/schema/cxf/camel-cxf-2.23.0.xsd=schema/cxfEndpoint.xsd
 http\://camel.apache.org/schema/cxf/camel-cxf-${project.version}.xsd=schema/cxfEndpoint.xsd
diff --git a/components/camel-cxf/src/test/java/org/apache/camel/component/cxf/CxfProducerTest.java b/components/camel-cxf/src/test/java/org/apache/camel/component/cxf/CxfProducerTest.java
index 7b0a4f1241a..6df44421c9b 100644
--- a/components/camel-cxf/src/test/java/org/apache/camel/component/cxf/CxfProducerTest.java
+++ b/components/camel-cxf/src/test/java/org/apache/camel/component/cxf/CxfProducerTest.java
@@ -155,7 +155,7 @@ public void testInvokingJaxWsServerWithParams() throws Exception {
         LOG.info("Received output text: " + result);
         Map<String, Object> responseContext = CastUtils.cast((Map<?, ?>)out.getHeader(Client.RESPONSE_CONTEXT));
         assertNotNull(responseContext);
-        assertEquals("Get the wrong wsdl opertion name", "{http://apache.org/hello_world_soap_http}greetMe", responseContext.get("javax.xml.ws.wsdl.operation").toString());
+        assertEquals("Get the wrong wsdl operation name", "{http://apache.org/hello_world_soap_http}greetMe", responseContext.get("javax.xml.ws.wsdl.operation").toString());
         assertEquals("reply body on Camel", "Hello " + TEST_MESSAGE, result);
         
         // check the other camel header copying
diff --git a/components/camel-digitalocean/pom.xml b/components/camel-digitalocean/pom.xml
index d73af8096eb..56a4395d707 100644
--- a/components/camel-digitalocean/pom.xml
+++ b/components/camel-digitalocean/pom.xml
@@ -25,7 +25,7 @@
   <parent>
     <groupId>org.apache.camel</groupId>
     <artifactId>components</artifactId>
-    <version>2.23.0-SNAPSHOT</version>
+    <version>2.24.0-SNAPSHOT</version>
   </parent>
 
   <artifactId>camel-digitalocean</artifactId>
diff --git a/components/camel-disruptor/pom.xml b/components/camel-disruptor/pom.xml
index b00c1f2be14..e3d40897ac9 100644
--- a/components/camel-disruptor/pom.xml
+++ b/components/camel-disruptor/pom.xml
@@ -23,7 +23,7 @@
     <parent>
         <groupId>org.apache.camel</groupId>
         <artifactId>components</artifactId>
-        <version>2.23.0-SNAPSHOT</version>
+        <version>2.24.0-SNAPSHOT</version>
     </parent>
 
     <name>Camel :: Disruptor</name>
diff --git a/components/camel-dns/pom.xml b/components/camel-dns/pom.xml
index b2f1970be28..c9cd2639c12 100644
--- a/components/camel-dns/pom.xml
+++ b/components/camel-dns/pom.xml
@@ -23,7 +23,7 @@
   <parent>
     <groupId>org.apache.camel</groupId>
     <artifactId>components</artifactId>
-    <version>2.23.0-SNAPSHOT</version>
+    <version>2.24.0-SNAPSHOT</version>
   </parent>
 
   <name>Camel :: DNS</name>
diff --git a/components/camel-docker/pom.xml b/components/camel-docker/pom.xml
index 7dc03d4a517..a136479e507 100644
--- a/components/camel-docker/pom.xml
+++ b/components/camel-docker/pom.xml
@@ -24,7 +24,7 @@
   <parent>
       <groupId>org.apache.camel</groupId>
       <artifactId>components</artifactId>
-      <version>2.23.0-SNAPSHOT</version>
+      <version>2.24.0-SNAPSHOT</version>
   </parent>
     
   <artifactId>camel-docker</artifactId>
diff --git a/components/camel-dozer/pom.xml b/components/camel-dozer/pom.xml
index a7440c4f675..bc70c33e1c3 100644
--- a/components/camel-dozer/pom.xml
+++ b/components/camel-dozer/pom.xml
@@ -24,7 +24,7 @@
   <parent>
     <artifactId>components</artifactId>
     <groupId>org.apache.camel</groupId>
-    <version>2.23.0-SNAPSHOT</version>
+    <version>2.24.0-SNAPSHOT</version>
   </parent>
 
   <artifactId>camel-dozer</artifactId>
diff --git a/components/camel-drill/pom.xml b/components/camel-drill/pom.xml
index d4af84986af..d0b5ed21810 100644
--- a/components/camel-drill/pom.xml
+++ b/components/camel-drill/pom.xml
@@ -23,7 +23,7 @@
     <parent>
         <groupId>org.apache.camel</groupId>
         <artifactId>components</artifactId>
-        <version>2.23.0-SNAPSHOT</version>
+        <version>2.24.0-SNAPSHOT</version>
     </parent>
 
     <artifactId>camel-drill</artifactId>
diff --git a/components/camel-dropbox/pom.xml b/components/camel-dropbox/pom.xml
index f93165b070f..a920a2fd670 100644
--- a/components/camel-dropbox/pom.xml
+++ b/components/camel-dropbox/pom.xml
@@ -25,7 +25,7 @@
   <parent>
     <groupId>org.apache.camel</groupId>
     <artifactId>components</artifactId>
-    <version>2.23.0-SNAPSHOT</version>
+    <version>2.24.0-SNAPSHOT</version>
   </parent>
 
   <artifactId>camel-dropbox</artifactId>
@@ -97,27 +97,39 @@
     </dependency>
   </dependencies>
 
+  <build>
+    <plugins>
+      <plugin>
+        <groupId>org.apache.maven.plugins</groupId>
+        <artifactId>maven-surefire-plugin</artifactId>
+        <configuration>
+          <excludes>
+            <exclude>
+              **/integration/**
+            </exclude>
+          </excludes>
+        </configuration>
+      </plugin>
+    </plugins>
+  </build>
+
   <profiles>
     <profile>
-      <id>no-integration-test</id>
-      <activation>
-        <activeByDefault>true</activeByDefault>
-      </activation>
+      <id>dropbox-test</id>
       <build>
         <plugins>
           <plugin>
             <groupId>org.apache.maven.plugins</groupId>
             <artifactId>maven-surefire-plugin</artifactId>
-            <configuration>
-              <excludes>
-                <exclude>
-                  **/integration/**
-                </exclude>
-              </excludes>
+            <configuration combine.self="override">
+              <includes>
+                <include>**/*Test.java</include>
+              </includes>
             </configuration>
           </plugin>
         </plugins>
       </build>
+
     </profile>
   </profiles>
 
diff --git a/components/camel-dropbox/src/main/java/org/apache/camel/component/dropbox/core/DropboxAPIFacade.java b/components/camel-dropbox/src/main/java/org/apache/camel/component/dropbox/core/DropboxAPIFacade.java
index 1b43179a377..d6e3c7b14eb 100644
--- a/components/camel-dropbox/src/main/java/org/apache/camel/component/dropbox/core/DropboxAPIFacade.java
+++ b/components/camel-dropbox/src/main/java/org/apache/camel/component/dropbox/core/DropboxAPIFacade.java
@@ -92,31 +92,31 @@ public DropboxFileUploadResult put(String localPath, String remotePath, DropboxU
         // in case the remote path is not specified, the remotePath = localPath
         String dropboxPath = remotePath == null ? localPath : remotePath;
 
-        UploadUploader entry;
+        boolean isPresent = true;
         try {
-            entry = client.files().upload(dropboxPath);
+            client.files().getMetadata(dropboxPath);
         } catch (DbxException e) {
-            throw new DropboxException(dropboxPath + " does not exist or cannot obtain metadata", e);
+            isPresent = false;
         }
 
         if (localPath != null) {
-            return putFile(localPath, mode, dropboxPath, entry);
+            return putFile(localPath, mode, dropboxPath, isPresent);
         } else {
-            return putBody(exchange, mode, dropboxPath, entry);
+            return putBody(exchange, mode, dropboxPath, isPresent);
         }
     }
 
-    private DropboxFileUploadResult putFile(String localPath, DropboxUploadMode mode, String dropboxPath, UploadUploader entry) throws DropboxException {
+    private DropboxFileUploadResult putFile(String localPath, DropboxUploadMode mode, String dropboxPath, boolean isPresent) throws DropboxException {
         File fileLocalPath = new File(localPath);
         // verify uploading of a single file
         if (fileLocalPath.isFile()) {
             // check if dropbox file exists
-            if (entry != null && !DropboxUploadMode.force.equals(mode)) {
-                throw new DropboxException(dropboxPath + " exists on dropbox and is not a file!");
+            if (isPresent && !DropboxUploadMode.force.equals(mode)) {
+                throw new DropboxException(dropboxPath + " exists on dropbox. Use force upload mode to override");
             }
             // in case the entry not exists on dropbox check if the filename
             // should be appended
-            if (entry == null) {
+            if (!isPresent) {
                 if (dropboxPath.endsWith(DropboxConstants.DROPBOX_FILE_SEPARATOR)) {
                     dropboxPath = dropboxPath + fileLocalPath.getName();
                 }
@@ -139,7 +139,7 @@ private DropboxFileUploadResult putFile(String localPath, DropboxUploadMode mode
             // verify uploading of a list of files inside a dir
             LOG.debug("Uploading a dir...");
             // check if dropbox folder exists
-            if (entry != null && !DropboxUploadMode.force.equals(mode)) {
+            if (isPresent && !DropboxUploadMode.force.equals(mode)) {
                 throw new DropboxException(dropboxPath + " exists on dropbox and is not a folder!");
             }
             if (!dropboxPath.endsWith(DropboxConstants.DROPBOX_FILE_SEPARATOR)) {
@@ -181,7 +181,7 @@ private DropboxFileUploadResult putFile(String localPath, DropboxUploadMode mode
         }
     }
 
-    private DropboxFileUploadResult putBody(Exchange exchange, DropboxUploadMode mode, String dropboxPath, UploadUploader entry) throws DropboxException {
+    private DropboxFileUploadResult putBody(Exchange exchange, DropboxUploadMode mode, String dropboxPath, boolean isPresent) throws DropboxException {
         String name = exchange.getIn().getHeader(HEADER_PUT_FILE_NAME, String.class);
         if (name == null) {
             // fallback to use CamelFileName
@@ -194,7 +194,7 @@ private DropboxFileUploadResult putBody(Exchange exchange, DropboxUploadMode mod
 
         // in case the entry not exists on dropbox check if the filename should
         // be appended
-        if (entry == null) {
+        if (!isPresent) {
             if (dropboxPath.endsWith(DropboxConstants.DROPBOX_FILE_SEPARATOR)) {
                 dropboxPath = dropboxPath + name;
             }
diff --git a/components/camel-dropbox/src/test/java/org/apache/camel/component/dropbox/DropboxConsumerTest.java b/components/camel-dropbox/src/test/java/org/apache/camel/component/dropbox/DropboxConsumerTest.java
index 199d5daaba5..6fee8a640c4 100644
--- a/components/camel-dropbox/src/test/java/org/apache/camel/component/dropbox/DropboxConsumerTest.java
+++ b/components/camel-dropbox/src/test/java/org/apache/camel/component/dropbox/DropboxConsumerTest.java
@@ -21,22 +21,20 @@
 import org.apache.camel.builder.RouteBuilder;
 import org.apache.camel.component.dropbox.integration.DropboxTestSupport;
 import org.apache.camel.component.dropbox.integration.consumer.DropboxScheduledPollGetConsumer;
+import org.apache.camel.test.junit4.CamelTestSupport;
 import org.junit.Assert;
 import org.junit.Test;
 
-public class DropboxConsumerTest extends DropboxTestSupport {
-
-    public DropboxConsumerTest() throws Exception {
-    }
+public class DropboxConsumerTest extends CamelTestSupport {
 
     @Override
-    protected RouteBuilder createRouteBuilder() throws Exception {
+    protected RouteBuilder createRouteBuilder() {
         return new RouteBuilder() {
             @Override
             public void configure() throws Exception {
-                from("dropbox://get?accessToken={{accessToken}}&remotePath=/path").to("mock:test1");
+                from("dropbox://get?accessToken=accessToken&remotePath=/path").to("mock:test1");
                 
-                from("dropbox://get?accessToken={{accessToken}}&remotePath=/path with spaces/file").to("mock:test2");
+                from("dropbox://get?accessToken=accessToken&remotePath=/path with spaces/file").to("mock:test2");
             }
         };
     }
@@ -44,7 +42,7 @@ public void configure() throws Exception {
     @Test
     public void shouldCreateGetConsumer() throws Exception {
         // Given
-        Endpoint dropboxEndpoint1 = context.getEndpoint("dropbox://get?accessToken={{accessToken}}&remotePath=/path");
+        Endpoint dropboxEndpoint1 = context.getEndpoint("dropbox://get?accessToken=accessToken&remotePath=/path");
 
         // When
         Consumer consumer1 = dropboxEndpoint1.createConsumer(null);
@@ -53,7 +51,7 @@ public void shouldCreateGetConsumer() throws Exception {
         Assert.assertTrue(consumer1 instanceof DropboxScheduledPollGetConsumer);
         
         // Given
-        Endpoint dropboxEndpoint2 = context.getEndpoint("dropbox://get?accessToken={{accessToken}}&remotePath=/path with spaces/file");
+        Endpoint dropboxEndpoint2 = context.getEndpoint("dropbox://get?accessToken=accessToken&remotePath=/path with spaces/file");
 
         // When
         Consumer consumer2 = dropboxEndpoint2.createConsumer(null);
diff --git a/components/camel-dropbox/src/test/java/org/apache/camel/component/dropbox/integration/DropboxTestSupport.java b/components/camel-dropbox/src/test/java/org/apache/camel/component/dropbox/integration/DropboxTestSupport.java
index 9636142b345..ef174b7d611 100644
--- a/components/camel-dropbox/src/test/java/org/apache/camel/component/dropbox/integration/DropboxTestSupport.java
+++ b/components/camel-dropbox/src/test/java/org/apache/camel/component/dropbox/integration/DropboxTestSupport.java
@@ -16,36 +16,78 @@
  */
 package org.apache.camel.component.dropbox.integration;
 
+import java.io.ByteArrayInputStream;
+import java.io.ByteArrayOutputStream;
 import java.io.IOException;
 import java.io.InputStream;
-import java.net.URL;
 import java.util.Properties;
-
+import com.dropbox.core.DbxDownloader;
+import com.dropbox.core.DbxException;
+import com.dropbox.core.DbxRequestConfig;
+import com.dropbox.core.v2.DbxClientV2;
+import com.dropbox.core.v2.files.FileMetadata;
 import org.apache.camel.test.junit4.CamelTestSupport;
+import org.junit.Before;
 
 
 public class DropboxTestSupport extends CamelTestSupport {
 
+
     protected final Properties properties;
+    protected String workdir;
+    protected String token;
+    private DbxClientV2 client;
 
     protected DropboxTestSupport() {
-        URL url = getClass().getResource("/test-options.properties");
-
-        InputStream inStream;
-        try {
-            inStream = url.openStream();
+        properties = new Properties();
+        try (InputStream inStream = getClass().getResourceAsStream("/test-options.properties")) {
+            properties.load(inStream);
         } catch (IOException e) {
             e.printStackTrace();
             throw new IllegalAccessError("test-options.properties could not be found");
         }
 
-        properties = new Properties();
+        workdir = properties.getProperty("workDir");
+        token = properties.getProperty("accessToken");
+
+        DbxRequestConfig config = DbxRequestConfig.newBuilder(properties.getProperty("clientIdentifier")).build();
+        client = new DbxClientV2(config, token);
+
+    }
+
+    @Before
+    public void setUpWorkingFolder() throws DbxException {
+        createDir(workdir);
+    }
+
+    protected void createDir(String name) throws DbxException {
         try {
-            properties.load(inStream);
-        } catch (IOException e) {
-            e.printStackTrace();
-            throw new IllegalAccessError("test-options.properties could not be found");
+            removeDir(name);
+        } finally {
+            client.files().createFolder(name);
+        }
+    }
+
+    protected void removeDir(String name) throws DbxException {
+        client.files().delete(name);
+    }
+
+    protected void createFile(String fileName, String content) throws IOException {
+        try {
+            client.files().uploadBuilder(workdir + "/" + fileName).uploadAndFinish(new ByteArrayInputStream(content.getBytes()));
+        } catch (DbxException e) {
+            log.info("folder is already created");
+        }
+
+    }
+
+    protected String getFileContent(String path) throws DbxException, IOException {
+        ByteArrayOutputStream target = new ByteArrayOutputStream();
+        DbxDownloader<FileMetadata> downloadedFile = client.files().download(path);
+        if (downloadedFile != null) {
+            downloadedFile.download(target);
         }
+        return new String(target.toByteArray());
     }
 
     @Override
diff --git a/components/camel-dropbox/src/test/java/org/apache/camel/component/dropbox/integration/consumer/DropboxConsumerGetSingleTest.java b/components/camel-dropbox/src/test/java/org/apache/camel/component/dropbox/integration/consumer/DropboxConsumerGetSingleTest.java
index b9b340cdae0..c923c682a0a 100644
--- a/components/camel-dropbox/src/test/java/org/apache/camel/component/dropbox/integration/consumer/DropboxConsumerGetSingleTest.java
+++ b/components/camel-dropbox/src/test/java/org/apache/camel/component/dropbox/integration/consumer/DropboxConsumerGetSingleTest.java
@@ -16,9 +16,6 @@
  */
 package org.apache.camel.component.dropbox.integration.consumer;
 
-import java.util.List;
-
-import org.apache.camel.Exchange;
 import org.apache.camel.builder.RouteBuilder;
 import org.apache.camel.component.dropbox.integration.DropboxTestSupport;
 import org.apache.camel.component.dropbox.util.DropboxResultHeader;
@@ -27,29 +24,27 @@
 
 public class DropboxConsumerGetSingleTest extends DropboxTestSupport {
 
-    public DropboxConsumerGetSingleTest() throws Exception { }
+    public static final String FILE_NAME = "myFile.txt";
 
     @Test
     public void testCamelDropbox() throws Exception {
+        final String content = "Hi camels";
+        createFile(FILE_NAME, content);
 
-        MockEndpoint mock = getMockEndpoint("mock:result");
-        mock.expectedMinimumMessageCount(1);       
-        assertMockEndpointsSatisfied();
+        context.startRoute("consumer");
 
-        List<Exchange> exchanges = mock.getReceivedExchanges();
-        Exchange exchange = exchanges.get(0);
-        Object header =  exchange.getIn().getHeader(DropboxResultHeader.DOWNLOADED_FILE.name());
-        Object body = exchange.getIn().getBody();
-        assertNotNull(header);
-        assertNotNull(body);
+        MockEndpoint mock = getMockEndpoint("mock:result");
+        mock.expectedMinimumMessageCount(1);
+        mock.expectedBodiesReceived(content);
+        mock.expectedHeaderReceived(DropboxResultHeader.DOWNLOADED_FILE.name(), String.format("%s/%s", workdir, FILE_NAME));
+        mock.assertIsSatisfied();
     }
 
     @Override
     protected RouteBuilder createRouteBuilder() throws Exception {
         return new RouteBuilder() {
             public void configure() {
-                from("dropbox://get?accessToken={{accessToken}}&remotePath=XXX")
-                        .to("file:XXX")
+                from(String.format("dropbox://get?accessToken={{accessToken}}&remotePath=%s/%s", workdir, FILE_NAME)).autoStartup(false).id("consumer")
                         .to("mock:result");
             }
         };
diff --git a/components/camel-dropbox/src/test/java/org/apache/camel/component/dropbox/integration/consumer/DropboxConsumerSearchQueryTest.java b/components/camel-dropbox/src/test/java/org/apache/camel/component/dropbox/integration/consumer/DropboxConsumerSearchQueryTest.java
index 253efd1bc1b..d343a7537ad 100644
--- a/components/camel-dropbox/src/test/java/org/apache/camel/component/dropbox/integration/consumer/DropboxConsumerSearchQueryTest.java
+++ b/components/camel-dropbox/src/test/java/org/apache/camel/component/dropbox/integration/consumer/DropboxConsumerSearchQueryTest.java
@@ -16,9 +16,6 @@
  */
 package org.apache.camel.component.dropbox.integration.consumer;
 
-import java.util.List;
-
-import org.apache.camel.Exchange;
 import org.apache.camel.builder.RouteBuilder;
 import org.apache.camel.component.dropbox.integration.DropboxTestSupport;
 import org.apache.camel.component.dropbox.util.DropboxResultHeader;
@@ -27,28 +24,26 @@
 
 public class DropboxConsumerSearchQueryTest extends DropboxTestSupport {
 
-    public DropboxConsumerSearchQueryTest() throws Exception { }
+    public static final String FILE_NAME = "myTestFile.txt";
 
     @Test
     public void testCamelDropbox() throws Exception {
+        final String content = "Hi camels";
+        createFile(FILE_NAME, content);
 
-        MockEndpoint mock = getMockEndpoint("mock:result");
-        mock.expectedMinimumMessageCount(1);       
-        assertMockEndpointsSatisfied();
+        context.startRoute("consumer");
 
-        List<Exchange> exchanges = mock.getReceivedExchanges();
-        Exchange exchange = exchanges.get(0);
-        Object header =  exchange.getIn().getHeader(DropboxResultHeader.FOUND_FILES.name());
-        Object body = exchange.getIn().getBody();
-        assertNotNull(header);
-        assertNotNull(body);
+        MockEndpoint mock = getMockEndpoint("mock:result");
+        mock.expectedMinimumMessageCount(1);
+        mock.message(0).header(DropboxResultHeader.FOUND_FILES.name()).contains(String.format("%s/%s", workdir, FILE_NAME));
+        mock.assertIsSatisfied();
     }
 
     @Override
     protected RouteBuilder createRouteBuilder() throws Exception {
         return new RouteBuilder() {
             public void configure() {
-                from("dropbox://search?accessToken={{accessToken}}&remotePath=/XXX&query=XXX")
+                from(String.format("dropbox://search?accessToken={{accessToken}}&remotePath=%s&query=%s", workdir, FILE_NAME)).id("consumer").autoStartup(false)
                         .to("mock:result");
             }
         };
diff --git a/components/camel-dropbox/src/test/java/org/apache/camel/component/dropbox/integration/producer/DropboxProducerDelTest.java b/components/camel-dropbox/src/test/java/org/apache/camel/component/dropbox/integration/producer/DropboxProducerDelTest.java
index 766a22c897c..1934edbcf0c 100644
--- a/components/camel-dropbox/src/test/java/org/apache/camel/component/dropbox/integration/producer/DropboxProducerDelTest.java
+++ b/components/camel-dropbox/src/test/java/org/apache/camel/component/dropbox/integration/producer/DropboxProducerDelTest.java
@@ -16,63 +16,41 @@
  */
 package org.apache.camel.component.dropbox.integration.producer;
 
-import java.util.List;
-
-import org.apache.camel.Exchange;
-import org.apache.camel.Processor;
+import java.io.IOException;
 import org.apache.camel.builder.RouteBuilder;
 import org.apache.camel.component.dropbox.integration.DropboxTestSupport;
 import org.apache.camel.component.dropbox.util.DropboxConstants;
 import org.apache.camel.component.dropbox.util.DropboxResultHeader;
 import org.apache.camel.component.mock.MockEndpoint;
+import org.junit.Before;
 import org.junit.Test;
 
 public class DropboxProducerDelTest extends DropboxTestSupport {
 
-    public DropboxProducerDelTest() throws Exception { }
+    public static final String FILE_NAME = "file.txt";
+
+    @Before
+    public void createFile() throws IOException {
+        createFile(FILE_NAME, "content");
+    }
 
     @Test
     public void testCamelDropbox() throws Exception {
-        template.send("direct:start", new Processor() {
-            @Override
-            public void process(Exchange exchange) throws Exception {
-                exchange.getIn().setHeader("test", "test");
-            }
-        });
-
-
-        MockEndpoint mock = getMockEndpoint("mock:result");
-        mock.expectedMinimumMessageCount(1);       
-        assertMockEndpointsSatisfied();
-
-        List<Exchange> exchanges = mock.getReceivedExchanges();
-        Exchange exchange = exchanges.get(0);
-        Object header =  exchange.getIn().getHeader(DropboxResultHeader.DELETED_PATH.name());
-        Object body = exchange.getIn().getBody();
-        assertNotNull(header);
-        assertNotNull(body);
+        test("direct:start");
     }
 
     @Test
     public void testCamelDropboxWithOptionInHeader() throws Exception {
-        template.send("direct:start2", new Processor() {
-            @Override
-            public void process(Exchange exchange) throws Exception {
-                exchange.getIn().setHeader("test", "test");
-            }
-        });
+        test("direct:start2");
+    }
 
 
+    private void test(String endpointURI) throws InterruptedException {
+        template.sendBody(endpointURI, null);
         MockEndpoint mock = getMockEndpoint("mock:result");
         mock.expectedMinimumMessageCount(1);
+        mock.expectedHeaderReceived(DropboxResultHeader.DELETED_PATH.name(), workdir + "/" + FILE_NAME);
         assertMockEndpointsSatisfied();
-
-        List<Exchange> exchanges = mock.getReceivedExchanges();
-        Exchange exchange = exchanges.get(0);
-        Object header =  exchange.getIn().getHeader(DropboxResultHeader.DELETED_PATH.name());
-        Object body = exchange.getIn().getBody();
-        assertNotNull(header);
-        assertNotNull(body);
     }
 
     @Override
@@ -80,11 +58,11 @@ protected RouteBuilder createRouteBuilder() throws Exception {
         return new RouteBuilder() {
             public void configure() {
                 from("direct:start")
-                        .to("dropbox://del?accessToken={{accessToken}}&remotePath=/XXX")
+                        .to("dropbox://del?accessToken={{accessToken}}&remotePath=" + workdir + "/" + FILE_NAME)
                         .to("mock:result");
 
                 from("direct:start2")
-                    .setHeader(DropboxConstants.HEADER_REMOTE_PATH, constant("/XXX"))
+                        .setHeader(DropboxConstants.HEADER_REMOTE_PATH, constant(workdir + "/" + FILE_NAME))
                     .to("dropbox://del?accessToken={{accessToken}}")
                     .to("mock:result");
             }
diff --git a/components/camel-dropbox/src/test/java/org/apache/camel/component/dropbox/integration/producer/DropboxProducerGetFolderTest.java b/components/camel-dropbox/src/test/java/org/apache/camel/component/dropbox/integration/producer/DropboxProducerGetFolderTest.java
index f39d213c587..6d8eb8288d0 100644
--- a/components/camel-dropbox/src/test/java/org/apache/camel/component/dropbox/integration/producer/DropboxProducerGetFolderTest.java
+++ b/components/camel-dropbox/src/test/java/org/apache/camel/component/dropbox/integration/producer/DropboxProducerGetFolderTest.java
@@ -16,120 +16,74 @@
  */
 package org.apache.camel.component.dropbox.integration.producer;
 
-import java.util.List;
-
-import org.apache.camel.Exchange;
-import org.apache.camel.Processor;
+import java.io.IOException;
+import java.util.Map;
 import org.apache.camel.builder.RouteBuilder;
 import org.apache.camel.component.dropbox.integration.DropboxTestSupport;
 import org.apache.camel.component.dropbox.util.DropboxConstants;
 import org.apache.camel.component.dropbox.util.DropboxResultHeader;
 import org.apache.camel.component.mock.MockEndpoint;
+import org.junit.Before;
 import org.junit.Test;
 
 public class DropboxProducerGetFolderTest extends DropboxTestSupport {
 
-    public DropboxProducerGetFolderTest() throws Exception { }
+    public static final String FILE_NAME1 = "myFile.txt";
+    public static final String FILE_NAME2 = "myFile2.txt";
+    private static final String CONTENT1 = "content1";
+    private static final String CONTENT2 = "content2";
+
+    @Before
+    public void createFile() throws IOException {
+        createFile(FILE_NAME1, CONTENT1);
+        createFile(FILE_NAME2, CONTENT2);
+    }
 
     @Test
     public void testCamelDropbox() throws Exception {
-        template.send("direct:start", new Processor() {
-            @Override
-            public void process(Exchange exchange) throws Exception {
-                exchange.getIn().setHeader("test", "test");
-            }
-        });
-
-        MockEndpoint mock = getMockEndpoint("mock:result");
-        mock.expectedMinimumMessageCount(1);
-        assertMockEndpointsSatisfied();
-
-        List<Exchange> exchanges = mock.getReceivedExchanges();
-        Exchange exchange = exchanges.get(0);
-        Object header =  exchange.getIn().getHeader(DropboxResultHeader.DOWNLOADED_FILES.name());
-        Object body = exchange.getIn().getBody();
-        assertNotNull(header);
-        assertNotNull(body);
+        test("direct:start");
     }
 
     @Test
     public void testCamelDropboxWithOptionInHeader() throws Exception {
-        template.send("direct:start2", new Processor() {
-            @Override
-            public void process(Exchange exchange) throws Exception {
-                exchange.getIn().setHeader("test", "test");
-            }
-        });
-
-
-        template.send("direct:start3", new Processor() {
-            @Override
-            public void process(Exchange exchange) throws Exception {
-                exchange.getIn().setHeader("test", "test");
-                exchange.getIn().setHeader(DropboxConstants.HEADER_REMOTE_PATH, "/XXX");
-            }
-        });
-
-
-        MockEndpoint mock = getMockEndpoint("mock:result");
-        mock.expectedMinimumMessageCount(2);
-        assertMockEndpointsSatisfied();
-
-        List<Exchange> exchanges = mock.getReceivedExchanges();
-        Exchange exchange = exchanges.get(0);
-        Object header =  exchange.getIn().getHeader(DropboxResultHeader.DOWNLOADED_FILES.name());
-        Object body = exchange.getIn().getBody();
-        assertNotNull(header);
-        assertNotNull(body);
-
-        exchange = exchanges.get(1);
-        header =  exchange.getIn().getHeader(DropboxResultHeader.DOWNLOADED_FILES.name());
-        body = exchange.getIn().getBody();
-        assertNotNull(header);
-        assertNotNull(body);
+        test("direct:start2");
     }
 
 
     @Test
     public void testCamelDropboxHeaderHasPriorityOnParameter() throws Exception {
-        template.send("direct:start4", new Processor() {
-            @Override
-            public void process(Exchange exchange) throws Exception {
-                exchange.getIn().setHeader("test", "test");
-            }
-        });
+        test("direct:start3");
+    }
 
+    private void test(String endpoint) throws InterruptedException {
+        template.sendBody(endpoint, null);
         MockEndpoint mock = getMockEndpoint("mock:result");
         mock.expectedMinimumMessageCount(1);
-        assertMockEndpointsSatisfied();
+        mock.message(0).header(DropboxResultHeader.DOWNLOADED_FILES.name()).contains(String.format("%s/%s", workdir, FILE_NAME1));
+        mock.message(0).header(DropboxResultHeader.DOWNLOADED_FILES.name()).contains(String.format("%s/%s", workdir, FILE_NAME2));
+        mock.assertIsSatisfied();
 
-        List<Exchange> exchanges = mock.getReceivedExchanges();
-        Exchange exchange = exchanges.get(0);
-        Object header =  exchange.getIn().getHeader(DropboxResultHeader.DOWNLOADED_FILES.name());
-        Object body = exchange.getIn().getBody();
-        assertNotNull(header);
-        assertNotNull(body);
+        final Map<String, byte[]> items = mock.getExchanges().get(0).getIn().getBody(Map.class);
+        assertEquals(CONTENT1, new String(items.get(String.format("%s/%s", workdir, FILE_NAME1))));
+        assertEquals(CONTENT2, new String(items.get(String.format("%s/%s", workdir, FILE_NAME2))));
     }
 
     @Override
-    protected RouteBuilder createRouteBuilder() throws Exception {
+    protected RouteBuilder createRouteBuilder() {
         return new RouteBuilder() {
             public void configure() {
                 from("direct:start")
-                        .to("dropbox://get?accessToken={{accessToken}}&remotePath=/XXX")
+                        .to("dropbox://get?accessToken={{accessToken}}&remotePath=" + workdir)
                         .to("mock:result");
 
                 from("direct:start2")
-                    .setHeader(DropboxConstants.HEADER_REMOTE_PATH, constant("/XXX"))
+                        .setHeader(DropboxConstants.HEADER_REMOTE_PATH, constant(workdir))
                     .to("dropbox://get?accessToken={{accessToken}}")
                     .to("mock:result");
 
-                from("direct:start3")
-                    .to("dropbox://get?accessToken={{accessToken}}")
-                    .to("mock:result");
 
-                from("direct:start4")
-                    .setHeader(DropboxConstants.HEADER_REMOTE_PATH, constant("/XXX"))
+                from("direct:start3")
+                        .setHeader(DropboxConstants.HEADER_REMOTE_PATH, constant(workdir))
                     .to("dropbox://get?accessToken={{accessToken}}&remotePath=/aWrongPath")
                     .to("mock:result");
 
diff --git a/components/camel-dropbox/src/test/java/org/apache/camel/component/dropbox/integration/producer/DropboxProducerGetSingleTest.java b/components/camel-dropbox/src/test/java/org/apache/camel/component/dropbox/integration/producer/DropboxProducerGetSingleTest.java
index 27f604b95d2..fd4cbc228db 100644
--- a/components/camel-dropbox/src/test/java/org/apache/camel/component/dropbox/integration/producer/DropboxProducerGetSingleTest.java
+++ b/components/camel-dropbox/src/test/java/org/apache/camel/component/dropbox/integration/producer/DropboxProducerGetSingleTest.java
@@ -16,63 +16,42 @@
  */
 package org.apache.camel.component.dropbox.integration.producer;
 
-import java.util.List;
-
-import org.apache.camel.Exchange;
-import org.apache.camel.Processor;
+import java.io.IOException;
 import org.apache.camel.builder.RouteBuilder;
 import org.apache.camel.component.dropbox.integration.DropboxTestSupport;
 import org.apache.camel.component.dropbox.util.DropboxConstants;
 import org.apache.camel.component.dropbox.util.DropboxResultHeader;
 import org.apache.camel.component.mock.MockEndpoint;
+import org.junit.Before;
 import org.junit.Test;
 
 public class DropboxProducerGetSingleTest extends DropboxTestSupport {
 
-    public DropboxProducerGetSingleTest() throws Exception { }
+    public static final String FILE_NAME = "myFile.txt";
+    public static final String CONTENT = "Hi camels";
+
+    @Before
+    public void createFile() throws IOException {
+        createFile(FILE_NAME, CONTENT);
+    }
 
     @Test
     public void testCamelDropbox() throws Exception {
-        template.send("direct:start", new Processor() {
-            @Override
-            public void process(Exchange exchange) throws Exception {
-                exchange.getIn().setHeader("test", "test");
-            }
-        });
-
-
-        MockEndpoint mock = getMockEndpoint("mock:result");
-        mock.expectedMinimumMessageCount(1);       
-        assertMockEndpointsSatisfied();
-
-        List<Exchange> exchanges = mock.getReceivedExchanges();
-        Exchange exchange = exchanges.get(0);
-        Object header =  exchange.getIn().getHeader(DropboxResultHeader.DOWNLOADED_FILE.name());
-        Object body = exchange.getIn().getBody();
-        assertNotNull(header);
-        assertNotNull(body);
+        test("direct:start");
     }
 
     @Test
     public void testCamelDropboxWithOptionInHeader() throws Exception {
-        template.send("direct:start2", new Processor() {
-            @Override
-            public void process(Exchange exchange) throws Exception {
-                exchange.getIn().setHeader("test", "test");
-            }
-        });
-
+        test("direct:start2");
+    }
 
+    private void test(String endpoint) throws InterruptedException {
+        template.sendBody(endpoint, null);
         MockEndpoint mock = getMockEndpoint("mock:result");
         mock.expectedMinimumMessageCount(1);
-        assertMockEndpointsSatisfied();
-
-        List<Exchange> exchanges = mock.getReceivedExchanges();
-        Exchange exchange = exchanges.get(0);
-        Object header =  exchange.getIn().getHeader(DropboxResultHeader.DOWNLOADED_FILE.name());
-        Object body = exchange.getIn().getBody();
-        assertNotNull(header);
-        assertNotNull(body);
+        mock.message(0).header(DropboxResultHeader.DOWNLOADED_FILE.name()).contains(String.format("%s/%s", workdir, FILE_NAME));
+        mock.message(0).body(String.class).isEqualTo(CONTENT);
+        mock.assertIsSatisfied();
     }
 
     @Override
@@ -80,14 +59,12 @@ protected RouteBuilder createRouteBuilder() throws Exception {
         return new RouteBuilder() {
             public void configure() {
                 from("direct:start")
-                        .to("dropbox://get?accessToken={{accessToken}}&remotePath=/XXX")
-                        .to("file:///XXX?fileName=XXX")
+                        .to("dropbox://get?accessToken={{accessToken}}&remotePath=" + workdir + "/" + FILE_NAME)
                         .to("mock:result");
 
                 from("direct:start2")
-                    .setHeader(DropboxConstants.HEADER_REMOTE_PATH, constant("/XXX"))
+                        .setHeader(DropboxConstants.HEADER_REMOTE_PATH, constant(workdir + "/" + FILE_NAME))
                     .to("dropbox://get?accessToken={{accessToken}}")
-                    .to("file:///XXX?fileName=XXX")
                     .to("mock:result");
             }
         };
diff --git a/components/camel-dropbox/src/test/java/org/apache/camel/component/dropbox/integration/producer/DropboxProducerMoveTest.java b/components/camel-dropbox/src/test/java/org/apache/camel/component/dropbox/integration/producer/DropboxProducerMoveTest.java
index f3968973745..086ab583f0c 100644
--- a/components/camel-dropbox/src/test/java/org/apache/camel/component/dropbox/integration/producer/DropboxProducerMoveTest.java
+++ b/components/camel-dropbox/src/test/java/org/apache/camel/component/dropbox/integration/producer/DropboxProducerMoveTest.java
@@ -16,63 +16,44 @@
  */
 package org.apache.camel.component.dropbox.integration.producer;
 
-import java.util.List;
-
-import org.apache.camel.Exchange;
-import org.apache.camel.Processor;
+import java.io.IOException;
+import com.dropbox.core.DbxException;
 import org.apache.camel.builder.RouteBuilder;
 import org.apache.camel.component.dropbox.integration.DropboxTestSupport;
 import org.apache.camel.component.dropbox.util.DropboxConstants;
 import org.apache.camel.component.dropbox.util.DropboxResultHeader;
 import org.apache.camel.component.mock.MockEndpoint;
+import org.junit.Before;
 import org.junit.Test;
 
 public class DropboxProducerMoveTest extends DropboxTestSupport {
 
-    public DropboxProducerMoveTest() throws Exception { }
+    public static final String COPY_WORKDIR = "/test-workdir";
+    public static final String FILE = "file.txt";
+
+    @Before
+    public void removeDir() throws DbxException, IOException {
+        createDir(COPY_WORKDIR);
+        createFile(FILE, "content");
+    }
 
     @Test
     public void testCamelDropbox() throws Exception {
-        template.send("direct:start", new Processor() {
-            @Override
-            public void process(Exchange exchange) throws Exception {
-                exchange.getIn().setHeader("test", "test");
-            }
-        });
-
-
-        MockEndpoint mock = getMockEndpoint("mock:result");
-        mock.expectedMinimumMessageCount(1);       
-        assertMockEndpointsSatisfied();
-
-        List<Exchange> exchanges = mock.getReceivedExchanges();
-        Exchange exchange = exchanges.get(0);
-        Object header =  exchange.getIn().getHeader(DropboxResultHeader.MOVED_PATH.name());
-        Object body = exchange.getIn().getBody();
-        assertNotNull(header);
-        assertNotNull(body);
+        test("direct:start");
     }
 
     @Test
     public void testCamelDropboxWithOptionInHeader() throws Exception {
-        template.send("direct:start2", new Processor() {
-            @Override
-            public void process(Exchange exchange) throws Exception {
-                exchange.getIn().setHeader("test", "test");
-            }
-        });
+        test("direct:start2");
+    }
 
+    private void test(String endpoint) throws InterruptedException {
+        template.sendBody(endpoint, null);
 
         MockEndpoint mock = getMockEndpoint("mock:result");
         mock.expectedMinimumMessageCount(1);
+        mock.expectedHeaderReceived(DropboxResultHeader.MOVED_PATH.name(), workdir + "/" + FILE);
         assertMockEndpointsSatisfied();
-
-        List<Exchange> exchanges = mock.getReceivedExchanges();
-        Exchange exchange = exchanges.get(0);
-        Object header =  exchange.getIn().getHeader(DropboxResultHeader.MOVED_PATH.name());
-        Object body = exchange.getIn().getBody();
-        assertNotNull(header);
-        assertNotNull(body);
     }
 
     @Override
@@ -80,12 +61,12 @@ protected RouteBuilder createRouteBuilder() throws Exception {
         return new RouteBuilder() {
             public void configure() {
                 from("direct:start")
-                        .to("dropbox://move?accessToken={{accessToken}}&remotePath=/XXX&newRemotePath=/XXX")
+                        .to(String.format("dropbox://move?accessToken={{accessToken}}&remotePath=%s&newRemotePath=%s", workdir + "/" + FILE, COPY_WORKDIR + "/" + FILE))
                         .to("mock:result");
 
                 from("direct:start2")
-                    .setHeader(DropboxConstants.HEADER_REMOTE_PATH, constant("/XXX"))
-                    .setHeader(DropboxConstants.HEADER_NEW_REMOTE_PATH, constant("/XXX"))
+                        .setHeader(DropboxConstants.HEADER_REMOTE_PATH, constant(workdir + "/" + FILE))
+                        .setHeader(DropboxConstants.HEADER_NEW_REMOTE_PATH, constant(COPY_WORKDIR + "/" + FILE))
                     .to("dropbox://move?accessToken={{accessToken}}")
                     .to("mock:result");
             }
diff --git a/components/camel-dropbox/src/test/java/org/apache/camel/component/dropbox/integration/producer/DropboxProducerPutSingleFileTest.java b/components/camel-dropbox/src/test/java/org/apache/camel/component/dropbox/integration/producer/DropboxProducerPutSingleFileTest.java
index a4acea71a38..a7ba22d5afe 100644
--- a/components/camel-dropbox/src/test/java/org/apache/camel/component/dropbox/integration/producer/DropboxProducerPutSingleFileTest.java
+++ b/components/camel-dropbox/src/test/java/org/apache/camel/component/dropbox/integration/producer/DropboxProducerPutSingleFileTest.java
@@ -16,64 +16,85 @@
  */
 package org.apache.camel.component.dropbox.integration.producer;
 
-import java.util.List;
-
-import org.apache.camel.Exchange;
-import org.apache.camel.Processor;
+import java.io.BufferedWriter;
+import java.io.FileWriter;
+import java.nio.file.Files;
+import java.nio.file.Path;
+import java.util.HashMap;
+import java.util.Map;
+import java.util.UUID;
 import org.apache.camel.builder.RouteBuilder;
 import org.apache.camel.component.dropbox.integration.DropboxTestSupport;
 import org.apache.camel.component.dropbox.util.DropboxConstants;
+import org.apache.camel.component.dropbox.util.DropboxException;
 import org.apache.camel.component.dropbox.util.DropboxResultHeader;
 import org.apache.camel.component.dropbox.util.DropboxUploadMode;
 import org.apache.camel.component.mock.MockEndpoint;
+import org.hamcrest.core.IsInstanceOf;
+import org.junit.Assert;
+import org.junit.Rule;
 import org.junit.Test;
+import org.junit.rules.ExpectedException;
 
 public class DropboxProducerPutSingleFileTest extends DropboxTestSupport {
+    public static final String FILENAME = "newFile.txt";
 
-    public DropboxProducerPutSingleFileTest() throws Exception { }
+    @Rule
+    public ExpectedException thrown = ExpectedException.none();
 
     @Test
-    public void testCamelDropbox() throws Exception {
-        template.send("direct:start", new Processor() {
-            @Override
-            public void process(Exchange exchange) throws Exception {
-                exchange.getIn().setHeader("test", "test");
-            }
-        });
+    public void testCamelDropboxWithOptionInHeader() throws Exception {
+        final Path file = Files.createTempFile("camel", ".txt");
+        final Map<String, Object> headers = new HashMap<>();
+        headers.put(DropboxConstants.HEADER_LOCAL_PATH, file.toAbsolutePath().toString());
+        headers.put(DropboxConstants.HEADER_UPLOAD_MODE, DropboxUploadMode.add);
+        template.sendBodyAndHeaders("direct:start", null, headers);
 
+        assertFileUploaded();
+    }
 
-        MockEndpoint mock = getMockEndpoint("mock:result");
-        mock.expectedMinimumMessageCount(1);       
-        assertMockEndpointsSatisfied();
+    @Test
+    public void uploadBodyTest() throws Exception {
+        template.sendBodyAndHeader("direct:start", "Helo Camels", DropboxConstants.HEADER_UPLOAD_MODE, DropboxUploadMode.add);
 
-        List<Exchange> exchanges = mock.getReceivedExchanges();
-        Exchange exchange = exchanges.get(0);
-        Object header =  exchange.getIn().getHeader(DropboxResultHeader.UPLOADED_FILE.name());
-        Object body = exchange.getIn().getBody();
-        assertNotNull(header);
-        assertNotNull(body);
+        assertFileUploaded();
     }
 
     @Test
-    public void testCamelDropboxWithOptionInHeader() throws Exception {
-        template.send("direct:start2", new Processor() {
-            @Override
-            public void process(Exchange exchange) throws Exception {
-                exchange.getIn().setHeader("test", "test");
-            }
-        });
+    public void uploadIfExistsAddTest() throws Exception {
+        thrown.expectCause(IsInstanceOf.instanceOf(DropboxException.class));
+        createFile(FILENAME, "content");
+        final Path file = Files.createTempFile("camel", ".txt");
+        final Map<String, Object> headers = new HashMap<>();
+        headers.put(DropboxConstants.HEADER_LOCAL_PATH, file.toAbsolutePath().toString());
+        headers.put(DropboxConstants.HEADER_UPLOAD_MODE, DropboxUploadMode.add);
+        template.sendBodyAndHeaders("direct:start", null, headers);
+    }
+
+    @Test
+    public void uploadIfExistsForceTest() throws Exception {
+        final String newContent = UUID.randomUUID().toString();
+        createFile(FILENAME, "Hi camels");
+        final Path file = Files.createTempFile("camel", ".txt");
+        try (BufferedWriter bw = new BufferedWriter(new FileWriter(file.toFile()))) {
+            bw.write(newContent);
+            bw.flush();
+        }
+        final Map<String, Object> headers = new HashMap<>();
+        headers.put(DropboxConstants.HEADER_LOCAL_PATH, file.toAbsolutePath().toString());
+        headers.put(DropboxConstants.HEADER_UPLOAD_MODE, DropboxUploadMode.force);
+        template.sendBodyAndHeaders("direct:start", null, headers);
 
+        assertFileUploaded();
 
+        Assert.assertEquals(newContent, getFileContent(workdir + "/" + FILENAME));
+    }
+
+    private void assertFileUploaded() throws InterruptedException {
         MockEndpoint mock = getMockEndpoint("mock:result");
         mock.expectedMinimumMessageCount(1);
+        mock.expectedHeaderReceived(DropboxResultHeader.UPLOADED_FILE.name(), workdir + "/" + FILENAME);
         assertMockEndpointsSatisfied();
-
-        List<Exchange> exchanges = mock.getReceivedExchanges();
-        Exchange exchange = exchanges.get(0);
-        Object header =  exchange.getIn().getHeader(DropboxResultHeader.UPLOADED_FILE.name());
-        Object body = exchange.getIn().getBody();
-        assertNotNull(header);
-        assertNotNull(body);
     }
 
     @Override
@@ -81,13 +102,7 @@ protected RouteBuilder createRouteBuilder() throws Exception {
         return new RouteBuilder() {
             public void configure() {
                 from("direct:start")
-                        .to("dropbox://put?accessToken={{accessToken}}&uploadMode=add&localPath=/XXX")
-                        .to("mock:result");
-
-                from("direct:start2")
-                    .setHeader(DropboxConstants.HEADER_LOCAL_PATH, constant("/XXX"))
-                    .setHeader(DropboxConstants.HEADER_UPLOAD_MODE, constant(DropboxUploadMode.add))
-                    .to("dropbox://put?accessToken={{accessToken}}")
+                        .to("dropbox://put?accessToken={{accessToken}}&remotePath=" + workdir + "/" + FILENAME)
                     .to("mock:result");
             }
         };
diff --git a/components/camel-dropbox/src/test/java/org/apache/camel/component/dropbox/integration/producer/DropboxProducerPutSingleFileWithRemotePathTest.java b/components/camel-dropbox/src/test/java/org/apache/camel/component/dropbox/integration/producer/DropboxProducerPutSingleFileWithRemotePathTest.java
deleted file mode 100644
index 42bd460018a..00000000000
--- a/components/camel-dropbox/src/test/java/org/apache/camel/component/dropbox/integration/producer/DropboxProducerPutSingleFileWithRemotePathTest.java
+++ /dev/null
@@ -1,96 +0,0 @@
-/**
- * Licensed to the Apache Software Foundation (ASF) under one or more
- * contributor license agreements.  See the NOTICE file distributed with
- * this work for additional information regarding copyright ownership.
- * The ASF licenses this file to You under the Apache License, Version 2.0
- * (the "License"); you may not use this file except in compliance with
- * the License.  You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package org.apache.camel.component.dropbox.integration.producer;
-
-import java.util.List;
-
-import org.apache.camel.Exchange;
-import org.apache.camel.Processor;
-import org.apache.camel.builder.RouteBuilder;
-import org.apache.camel.component.dropbox.integration.DropboxTestSupport;
-import org.apache.camel.component.dropbox.util.DropboxConstants;
-import org.apache.camel.component.dropbox.util.DropboxResultHeader;
-import org.apache.camel.component.dropbox.util.DropboxUploadMode;
-import org.apache.camel.component.mock.MockEndpoint;
-import org.junit.Test;
-
-public class DropboxProducerPutSingleFileWithRemotePathTest extends DropboxTestSupport {
-
-    public DropboxProducerPutSingleFileWithRemotePathTest() throws Exception { }
-
-    @Test
-    public void testCamelDropbox() throws Exception {
-        template.send("direct:start", new Processor() {
-            @Override
-            public void process(Exchange exchange) throws Exception {
-                exchange.getIn().setHeader("test", "test");
-            }
-        });
-
-
-        MockEndpoint mock = getMockEndpoint("mock:result");
-        mock.expectedMinimumMessageCount(1);       
-        assertMockEndpointsSatisfied();
-
-        List<Exchange> exchanges = mock.getReceivedExchanges();
-        Exchange exchange = exchanges.get(0);
-        Object header =  exchange.getIn().getHeader(DropboxResultHeader.UPLOADED_FILE.name());
-        Object body = exchange.getIn().getBody();
-        assertNotNull(header);
-        assertNotNull(body);
-    }
-
-    @Test
-    public void testCamelDropboxWithOptionInHeader() throws Exception {
-        template.send("direct:start2", new Processor() {
-            @Override
-            public void process(Exchange exchange) throws Exception {
-                exchange.getIn().setHeader("test", "test");
-            }
-        });
-
-
-        MockEndpoint mock = getMockEndpoint("mock:result");
-        mock.expectedMinimumMessageCount(1);
-        assertMockEndpointsSatisfied();
-
-        List<Exchange> exchanges = mock.getReceivedExchanges();
-        Exchange exchange = exchanges.get(0);
-        Object header =  exchange.getIn().getHeader(DropboxResultHeader.UPLOADED_FILE.name());
-        Object body = exchange.getIn().getBody();
-        assertNotNull(header);
-        assertNotNull(body);
-    }
-
-    @Override
-    protected RouteBuilder createRouteBuilder() throws Exception {
-        return new RouteBuilder() {
-            public void configure() {
-                from("direct:start")
-                        .to("dropbox://put?accessToken={{accessToken}}&uploadMode=add&localPath=/XXX&remotePath=/XXX")
-                        .to("mock:result");
-
-                from("direct:start2")
-                    .setHeader(DropboxConstants.HEADER_UPLOAD_MODE, constant(DropboxUploadMode.add))
-                    .setHeader(DropboxConstants.HEADER_LOCAL_PATH, constant("/tmp/toto.txt"))
-                    .setHeader(DropboxConstants.HEADER_REMOTE_PATH, constant("/test"))
-                    .to("dropbox://put?accessToken={{accessToken}}")
-                    .to("mock:result");
-            }
-        };
-    }
-}
diff --git a/components/camel-dropbox/src/test/java/org/apache/camel/component/dropbox/integration/producer/DropboxProducerPutWithRemotePathTest.java b/components/camel-dropbox/src/test/java/org/apache/camel/component/dropbox/integration/producer/DropboxProducerPutWithRemotePathTest.java
deleted file mode 100644
index 2de352c6317..00000000000
--- a/components/camel-dropbox/src/test/java/org/apache/camel/component/dropbox/integration/producer/DropboxProducerPutWithRemotePathTest.java
+++ /dev/null
@@ -1,95 +0,0 @@
-/**
- * Licensed to the Apache Software Foundation (ASF) under one or more
- * contributor license agreements.  See the NOTICE file distributed with
- * this work for additional information regarding copyright ownership.
- * The ASF licenses this file to You under the Apache License, Version 2.0
- * (the "License"); you may not use this file except in compliance with
- * the License.  You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package org.apache.camel.component.dropbox.integration.producer;
-
-import java.util.List;
-
-import org.apache.camel.Exchange;
-import org.apache.camel.Processor;
-import org.apache.camel.builder.RouteBuilder;
-import org.apache.camel.component.dropbox.integration.DropboxTestSupport;
-import org.apache.camel.component.dropbox.util.DropboxConstants;
-import org.apache.camel.component.dropbox.util.DropboxResultHeader;
-import org.apache.camel.component.dropbox.util.DropboxUploadMode;
-import org.apache.camel.component.mock.MockEndpoint;
-import org.junit.Test;
-
-public class DropboxProducerPutWithRemotePathTest extends DropboxTestSupport {
-
-    public DropboxProducerPutWithRemotePathTest() throws Exception { }
-
-    @Test
-    public void testCamelDropbox() throws Exception {
-        template.send("direct:start", new Processor() {
-            @Override
-            public void process(Exchange exchange) throws Exception {
-                exchange.getIn().setHeader("test", "test");
-            }
-        });
-
-
-        MockEndpoint mock = getMockEndpoint("mock:result");
-        mock.expectedMinimumMessageCount(1);       
-        assertMockEndpointsSatisfied();
-
-        List<Exchange> exchanges = mock.getReceivedExchanges();
-        Exchange exchange = exchanges.get(0);
-        Object header =  exchange.getIn().getHeader(DropboxResultHeader.UPLOADED_FILES.name());
-        Object body = exchange.getIn().getBody();
-        assertNotNull(header);
-        assertNotNull(body);
-    }
-
-    @Test
-    public void testCamelDropboxWithOptionInHeader() throws Exception {
-        template.send("direct:start2", new Processor() {
-            @Override
-            public void process(Exchange exchange) throws Exception {
-                exchange.getIn().setHeader("test", "test");
-            }
-        });
-
-        MockEndpoint mock = getMockEndpoint("mock:result");
-        mock.expectedMinimumMessageCount(1);
-        assertMockEndpointsSatisfied();
-
-        List<Exchange> exchanges = mock.getReceivedExchanges();
-        Exchange exchange = exchanges.get(0);
-        Object header =  exchange.getIn().getHeader(DropboxResultHeader.UPLOADED_FILES.name());
-        Object body = exchange.getIn().getBody();
-        assertNotNull(header);
-        assertNotNull(body);
-    }
-
-    @Override
-    protected RouteBuilder createRouteBuilder() throws Exception {
-        return new RouteBuilder() {
-            public void configure() {
-                from("direct:start")
-                        .to("dropbox://put?accessToken={{accessToken}}&uploadMode=add&localPath=/XXX&remotePath=/XXX")
-                        .to("mock:result");
-
-                from("direct:start2")
-                    .setHeader(DropboxConstants.HEADER_LOCAL_PATH, constant("/XXX"))
-                    .setHeader(DropboxConstants.HEADER_REMOTE_PATH, constant("/XXX"))
-                    .setHeader(DropboxConstants.HEADER_UPLOAD_MODE, constant(DropboxUploadMode.add))
-                    .to("dropbox://put?accessToken={{accessToken}}")
-                    .to("mock:result");
-            }
-        };
-    }
-}
diff --git a/components/camel-dropbox/src/test/java/org/apache/camel/component/dropbox/integration/producer/DropboxProducerSearchQueryTest.java b/components/camel-dropbox/src/test/java/org/apache/camel/component/dropbox/integration/producer/DropboxProducerSearchQueryTest.java
index 4c8939fa1f3..2a541cd9b60 100644
--- a/components/camel-dropbox/src/test/java/org/apache/camel/component/dropbox/integration/producer/DropboxProducerSearchQueryTest.java
+++ b/components/camel-dropbox/src/test/java/org/apache/camel/component/dropbox/integration/producer/DropboxProducerSearchQueryTest.java
@@ -16,79 +16,57 @@
  */
 package org.apache.camel.component.dropbox.integration.producer;
 
-import java.util.List;
-
-import org.apache.camel.Exchange;
-import org.apache.camel.Processor;
+import java.io.IOException;
 import org.apache.camel.builder.RouteBuilder;
 import org.apache.camel.component.dropbox.integration.DropboxTestSupport;
 import org.apache.camel.component.dropbox.util.DropboxConstants;
 import org.apache.camel.component.dropbox.util.DropboxResultHeader;
 import org.apache.camel.component.mock.MockEndpoint;
+import org.junit.Before;
 import org.junit.Test;
 
 public class DropboxProducerSearchQueryTest extends DropboxTestSupport {
 
-    public DropboxProducerSearchQueryTest() throws Exception { }
-
-    @Test
-    public void testCamelDropbox() throws Exception {
-        template.send("direct:start", new Processor() {
-            @Override
-            public void process(Exchange exchange) throws Exception {
-                exchange.getIn().setHeader("test", "test");
-            }
-        });
-
-
-        MockEndpoint mock = getMockEndpoint("mock:result");
-        mock.expectedMinimumMessageCount(1);       
-        assertMockEndpointsSatisfied();
 
-        List<Exchange> exchanges = mock.getReceivedExchanges();
-        Exchange exchange = exchanges.get(0);
-        Object header =  exchange.getIn().getHeader(DropboxResultHeader.FOUND_FILES.name());
-        Object body = exchange.getIn().getBody();
-        assertNotNull(header);
-        assertNotNull(body);
+    public static final String FILE_NAME = "myTestFile.txt";
 
+    @Before
+    public void createFile() throws IOException {
+        final String content = "Hi camels";
+        createFile(FILE_NAME, content);
     }
 
+    @Test
+    public void testCamelDropbox() throws Exception {
+        test("direct:start");
+    }
 
     @Test
     public void testCamelDropboxWithOptionInHeader() throws Exception {
-        template.send("direct:start2", new Processor() {
-            @Override
-            public void process(Exchange exchange) throws Exception {
-                exchange.getIn().setHeader("test", "test");
-            }
-        });
+        test("direct:start2");
+    }
+
 
+    private void test(String endpoint) throws InterruptedException {
+        template.sendBody(endpoint, null);
 
         MockEndpoint mock = getMockEndpoint("mock:result");
         mock.expectedMinimumMessageCount(1);
-        assertMockEndpointsSatisfied();
-
-        List<Exchange> exchanges = mock.getReceivedExchanges();
-        Exchange exchange = exchanges.get(0);
-        Object header =  exchange.getIn().getHeader(DropboxResultHeader.FOUND_FILES.name());
-        Object body = exchange.getIn().getBody();
-        assertNotNull(header);
-        assertNotNull(body);
-
+        mock.message(0).header(DropboxResultHeader.FOUND_FILES.name()).contains(String.format("%s/%s", workdir, FILE_NAME));
+        mock.assertIsSatisfied();
     }
 
     @Override
-    protected RouteBuilder createRouteBuilder() throws Exception {
+    protected RouteBuilder createRouteBuilder() {
         return new RouteBuilder() {
             public void configure() {
                 from("direct:start")
-                        .to("dropbox://search?accessToken={{accessToken}}&remotePath=/XXX&query=XXX")
+                        .to(String.format("dropbox://search?accessToken={{accessToken}}&remotePath=%s&query=%s", workdir, FILE_NAME))
                         .to("mock:result");
 
                 from("direct:start2")
-                    .setHeader(DropboxConstants.HEADER_REMOTE_PATH, constant("/XXX"))
-                    .setHeader(DropboxConstants.HEADER_QUERY, constant("/XXX"))
+                        .setHeader(DropboxConstants.HEADER_REMOTE_PATH, constant(workdir))
+                        .setHeader(DropboxConstants.HEADER_QUERY, constant(FILE_NAME))
                     .to("dropbox://search?accessToken={{accessToken}}")
                     .to("mock:result");
             }
diff --git a/components/camel-dropbox/src/test/java/org/apache/camel/component/dropbox/integration/producer/DropboxProducerSearchTest.java b/components/camel-dropbox/src/test/java/org/apache/camel/component/dropbox/integration/producer/DropboxProducerSearchTest.java
deleted file mode 100644
index 38ce2aa6835..00000000000
--- a/components/camel-dropbox/src/test/java/org/apache/camel/component/dropbox/integration/producer/DropboxProducerSearchTest.java
+++ /dev/null
@@ -1,92 +0,0 @@
-/**
- * Licensed to the Apache Software Foundation (ASF) under one or more
- * contributor license agreements.  See the NOTICE file distributed with
- * this work for additional information regarding copyright ownership.
- * The ASF licenses this file to You under the Apache License, Version 2.0
- * (the "License"); you may not use this file except in compliance with
- * the License.  You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package org.apache.camel.component.dropbox.integration.producer;
-
-import java.util.List;
-
-import org.apache.camel.Exchange;
-import org.apache.camel.Processor;
-import org.apache.camel.builder.RouteBuilder;
-import org.apache.camel.component.dropbox.integration.DropboxTestSupport;
-import org.apache.camel.component.dropbox.util.DropboxConstants;
-import org.apache.camel.component.dropbox.util.DropboxResultHeader;
-import org.apache.camel.component.mock.MockEndpoint;
-import org.junit.Test;
-
-public class DropboxProducerSearchTest extends DropboxTestSupport {
-
-    public DropboxProducerSearchTest() throws Exception { }
-
-    @Test
-    public void testCamelDropbox() throws Exception {
-        template.send("direct:start", new Processor() {
-            @Override
-            public void process(Exchange exchange) throws Exception {
-                exchange.getIn().setHeader("test", "test");
-            }
-        });
-
-        MockEndpoint mock = getMockEndpoint("mock:result");
-        mock.expectedMinimumMessageCount(1);       
-        assertMockEndpointsSatisfied();
-
-        List<Exchange> exchanges = mock.getReceivedExchanges();
-        Exchange exchange = exchanges.get(0);
-        Object header =  exchange.getIn().getHeader(DropboxResultHeader.FOUND_FILES.name());
-        Object body = exchange.getIn().getBody();
-        assertNotNull(header);
-        assertNotNull(body);
-    }
-
-    @Test
-    public void testCamelDropboxWithOptionInHeader() throws Exception {
-        template.send("direct:start2", new Processor() {
-            @Override
-            public void process(Exchange exchange) throws Exception {
-                exchange.getIn().setHeader("test", "test");
-            }
-        });
-
-
-        MockEndpoint mock = getMockEndpoint("mock:result");
-        mock.expectedMinimumMessageCount(1);
-        assertMockEndpointsSatisfied();
-
-        List<Exchange> exchanges = mock.getReceivedExchanges();
-        Exchange exchange = exchanges.get(0);
-        Object header =  exchange.getIn().getHeader(DropboxResultHeader.FOUND_FILES.name());
-        Object body = exchange.getIn().getBody();
-        assertNotNull(header);
-        assertNotNull(body);
-    }
-
-    @Override
-    protected RouteBuilder createRouteBuilder() throws Exception {
-        return new RouteBuilder() {
-            public void configure() {
-                from("direct:start")
-                        .to("dropbox://search?accessToken={{accessToken}}&remotePath=/XXX")
-                        .to("mock:result");
-
-                from("direct:start")
-                    .setHeader(DropboxConstants.HEADER_REMOTE_PATH, constant("/XXX"))
-                    .to("dropbox://search?accessToken={{accessToken}}")
-                    .to("mock:result");
-            }
-        };
-    }
-}
diff --git a/components/camel-dropbox/src/test/resources/test-options.properties b/components/camel-dropbox/src/test/resources/test-options.properties
index 84dfb21745a..5c070590320 100644
--- a/components/camel-dropbox/src/test/resources/test-options.properties
+++ b/components/camel-dropbox/src/test/resources/test-options.properties
@@ -15,5 +15,6 @@
 ## limitations under the License.
 ## ---------------------------------------------------------------------------
 
-accessToken=<access-token>
+accessToken=<api-token>
 clientIdentifier=camel-dropbox
+workDir=/camel-test
diff --git a/components/camel-eclipse/pom.xml b/components/camel-eclipse/pom.xml
index c6838614a42..0dcb7fe37e8 100644
--- a/components/camel-eclipse/pom.xml
+++ b/components/camel-eclipse/pom.xml
@@ -23,7 +23,7 @@
   <parent>
     <groupId>org.apache.camel</groupId>
     <artifactId>components</artifactId>
-    <version>2.23.0-SNAPSHOT</version>
+    <version>2.24.0-SNAPSHOT</version>
   </parent>
 
   <artifactId>camel-eclipse</artifactId>
diff --git a/components/camel-ehcache/pom.xml b/components/camel-ehcache/pom.xml
index 80f7d7ac6fa..374a4770984 100644
--- a/components/camel-ehcache/pom.xml
+++ b/components/camel-ehcache/pom.xml
@@ -24,7 +24,7 @@
   <parent>
     <groupId>org.apache.camel</groupId>
     <artifactId>components</artifactId>
-    <version>2.23.0-SNAPSHOT</version>
+    <version>2.24.0-SNAPSHOT</version>
   </parent>
 
   <artifactId>camel-ehcache</artifactId>
diff --git a/components/camel-ejb/pom.xml b/components/camel-ejb/pom.xml
index 80a6f281613..a71e731959a 100644
--- a/components/camel-ejb/pom.xml
+++ b/components/camel-ejb/pom.xml
@@ -23,7 +23,7 @@
     <parent>
         <groupId>org.apache.camel</groupId>
         <artifactId>components</artifactId>
-        <version>2.23.0-SNAPSHOT</version>
+        <version>2.24.0-SNAPSHOT</version>
     </parent>
 
     <artifactId>camel-ejb</artifactId>
diff --git a/components/camel-elasticsearch-rest/pom.xml b/components/camel-elasticsearch-rest/pom.xml
index cdd4a1599aa..110255cca2b 100644
--- a/components/camel-elasticsearch-rest/pom.xml
+++ b/components/camel-elasticsearch-rest/pom.xml
@@ -24,7 +24,7 @@
   <parent>
     <groupId>org.apache.camel</groupId>
     <artifactId>components</artifactId>
-    <version>2.23.0-SNAPSHOT</version>
+    <version>2.24.0-SNAPSHOT</version>
   </parent>
 
   <artifactId>camel-elasticsearch-rest</artifactId>
diff --git a/components/camel-elasticsearch-rest/src/main/java/org/apache/camel/component/elasticsearch/converter/ElasticsearchActionRequestConverter.java b/components/camel-elasticsearch-rest/src/main/java/org/apache/camel/component/elasticsearch/converter/ElasticsearchActionRequestConverter.java
index 1347219e8cf..6572c960b51 100644
--- a/components/camel-elasticsearch-rest/src/main/java/org/apache/camel/component/elasticsearch/converter/ElasticsearchActionRequestConverter.java
+++ b/components/camel-elasticsearch-rest/src/main/java/org/apache/camel/component/elasticsearch/converter/ElasticsearchActionRequestConverter.java
@@ -61,7 +61,7 @@ private static UpdateRequest createUpdateRequest(Object document, Exchange excha
         } else if (document instanceof Map) {
             updateRequest.doc((Map<String, Object>) document);
         } else if (document instanceof String) {
-            updateRequest.doc(XContentFactory.xContent((String) document), (String) document);
+            updateRequest.doc((String) document, XContentFactory.xContentType((String) document));
         } else if (document instanceof XContentBuilder) {
             updateRequest.doc((XContentBuilder) document);
         } else {
diff --git a/components/camel-elasticsearch-rest/src/test/java/org/apache/camel/component/elasticsearch/ElasticsearchGetSearchDeleteExistsUpdateTest.java b/components/camel-elasticsearch-rest/src/test/java/org/apache/camel/component/elasticsearch/ElasticsearchGetSearchDeleteExistsUpdateTest.java
index 96e994fee93..161e629c6c9 100644
--- a/components/camel-elasticsearch-rest/src/test/java/org/apache/camel/component/elasticsearch/ElasticsearchGetSearchDeleteExistsUpdateTest.java
+++ b/components/camel-elasticsearch-rest/src/test/java/org/apache/camel/component/elasticsearch/ElasticsearchGetSearchDeleteExistsUpdateTest.java
@@ -49,6 +49,7 @@ public void testGet() throws Exception {
         GetResponse response = template.requestBody("direct:get", indexId, GetResponse.class);
         assertNotNull("response should not be null", response);
         assertNotNull("response source should not be null", response.getSource());
+        System.err.println(response.getSource());
     }
 
     @Test
@@ -303,12 +304,15 @@ public void testStringUpdate() throws Exception {
         String indexId = template.requestBody("direct:index", map, String.class);
         assertNotNull("indexId should be set", indexId);
 
-        String body = "{\"id\" : 1}";
+        String body = "{\"teststringupdate-key\" : \"teststringupdate-updated\"}";
 
         Map<String, Object> headers = new HashMap<>();
         headers.put(ElasticsearchConstants.PARAM_INDEX_ID, indexId);
         indexId = template.requestBodyAndHeaders("direct:update", body, headers, String.class);
         assertNotNull("indexId should be set", indexId);
+        
+        GetResponse response = template.requestBody("direct:get", indexId, GetResponse.class);
+        assertEquals("teststringupdate-updated", response.getSource().get("teststringupdate-key"));
     }
 
     @Override
diff --git a/components/camel-elasticsearch/pom.xml b/components/camel-elasticsearch/pom.xml
index 5ee02565e4b..f248fb68419 100644
--- a/components/camel-elasticsearch/pom.xml
+++ b/components/camel-elasticsearch/pom.xml
@@ -24,7 +24,7 @@
   <parent>
     <groupId>org.apache.camel</groupId>
     <artifactId>components</artifactId>
-    <version>2.23.0-SNAPSHOT</version>
+    <version>2.24.0-SNAPSHOT</version>
   </parent>
 
   <artifactId>camel-elasticsearch</artifactId>
diff --git a/components/camel-elasticsearch5/pom.xml b/components/camel-elasticsearch5/pom.xml
index 8ff9d24a2a0..4db7b8acdcc 100644
--- a/components/camel-elasticsearch5/pom.xml
+++ b/components/camel-elasticsearch5/pom.xml
@@ -24,7 +24,7 @@
   <parent>
     <groupId>org.apache.camel</groupId>
     <artifactId>components</artifactId>
-    <version>2.23.0-SNAPSHOT</version>
+    <version>2.24.0-SNAPSHOT</version>
   </parent>
 
   <artifactId>camel-elasticsearch5</artifactId>
diff --git a/components/camel-elsql/pom.xml b/components/camel-elsql/pom.xml
index 2945141e21e..5df3caffd6e 100644
--- a/components/camel-elsql/pom.xml
+++ b/components/camel-elsql/pom.xml
@@ -23,7 +23,7 @@
   <parent>
     <groupId>org.apache.camel</groupId>
     <artifactId>components</artifactId>
-    <version>2.23.0-SNAPSHOT</version>
+    <version>2.24.0-SNAPSHOT</version>
   </parent>
 
   <artifactId>camel-elsql</artifactId>
diff --git a/components/camel-etcd/pom.xml b/components/camel-etcd/pom.xml
index 7e247762ecf..02270aa3538 100644
--- a/components/camel-etcd/pom.xml
+++ b/components/camel-etcd/pom.xml
@@ -25,7 +25,7 @@
   <parent>
     <groupId>org.apache.camel</groupId>
     <artifactId>components</artifactId>
-    <version>2.23.0-SNAPSHOT</version>
+    <version>2.24.0-SNAPSHOT</version>
   </parent>
 
   <artifactId>camel-etcd</artifactId>
diff --git a/components/camel-eventadmin/pom.xml b/components/camel-eventadmin/pom.xml
index c8ebcaae340..017b891176d 100644
--- a/components/camel-eventadmin/pom.xml
+++ b/components/camel-eventadmin/pom.xml
@@ -23,7 +23,7 @@
     <parent>
         <groupId>org.apache.camel</groupId>
         <artifactId>components</artifactId>
-        <version>2.23.0-SNAPSHOT</version>
+        <version>2.24.0-SNAPSHOT</version>
     </parent>
 
     <artifactId>camel-eventadmin</artifactId>
diff --git a/components/camel-exec/pom.xml b/components/camel-exec/pom.xml
index d0e5bbd7b07..db8b2e7b9e2 100644
--- a/components/camel-exec/pom.xml
+++ b/components/camel-exec/pom.xml
@@ -23,7 +23,7 @@
   <parent>
     <groupId>org.apache.camel</groupId>
     <artifactId>components</artifactId>
-    <version>2.23.0-SNAPSHOT</version>
+    <version>2.24.0-SNAPSHOT</version>
   </parent>
 
   <artifactId>camel-exec</artifactId>
diff --git a/components/camel-facebook/pom.xml b/components/camel-facebook/pom.xml
index 859244f9326..62f8a78a7e2 100644
--- a/components/camel-facebook/pom.xml
+++ b/components/camel-facebook/pom.xml
@@ -23,7 +23,7 @@
   <parent>
     <artifactId>components</artifactId>
     <groupId>org.apache.camel</groupId>
-    <version>2.23.0-SNAPSHOT</version>
+    <version>2.24.0-SNAPSHOT</version>
   </parent>
 
   <artifactId>camel-facebook</artifactId>
diff --git a/components/camel-fastjson/pom.xml b/components/camel-fastjson/pom.xml
index bb55aa4946c..b178d6cda72 100644
--- a/components/camel-fastjson/pom.xml
+++ b/components/camel-fastjson/pom.xml
@@ -23,7 +23,7 @@
     <parent>
         <groupId>org.apache.camel</groupId>
         <artifactId>components</artifactId>
-        <version>2.23.0-SNAPSHOT</version>
+        <version>2.24.0-SNAPSHOT</version>
     </parent>
 
     <artifactId>camel-fastjson</artifactId>
diff --git a/components/camel-fhir/camel-fhir-api/pom.xml b/components/camel-fhir/camel-fhir-api/pom.xml
index fa3130b3e40..c51df250872 100644
--- a/components/camel-fhir/camel-fhir-api/pom.xml
+++ b/components/camel-fhir/camel-fhir-api/pom.xml
@@ -23,7 +23,7 @@
   <parent>
     <groupId>org.apache.camel</groupId>
     <artifactId>camel-fhir-parent</artifactId>
-    <version>2.23.0-SNAPSHOT</version>
+    <version>2.24.0-SNAPSHOT</version>
   </parent>
 
   <artifactId>camel-fhir-api</artifactId>
diff --git a/components/camel-fhir/camel-fhir-component/pom.xml b/components/camel-fhir/camel-fhir-component/pom.xml
index 5e1d7c5c2b9..aedefcb1005 100644
--- a/components/camel-fhir/camel-fhir-component/pom.xml
+++ b/components/camel-fhir/camel-fhir-component/pom.xml
@@ -24,7 +24,7 @@
   <parent>
     <groupId>org.apache.camel</groupId>
     <artifactId>camel-fhir-parent</artifactId>
-    <version>2.23.0-SNAPSHOT</version>
+    <version>2.24.0-SNAPSHOT</version>
   </parent>
   
   <artifactId>camel-fhir</artifactId>
diff --git a/components/camel-fhir/pom.xml b/components/camel-fhir/pom.xml
index cfc4be48118..12b246be3ab 100644
--- a/components/camel-fhir/pom.xml
+++ b/components/camel-fhir/pom.xml
@@ -23,7 +23,7 @@
   <parent>
     <groupId>org.apache.camel</groupId>
     <artifactId>components</artifactId>
-    <version>2.23.0-SNAPSHOT</version>
+    <version>2.24.0-SNAPSHOT</version>
   </parent>
 
   <artifactId>camel-fhir-parent</artifactId>
diff --git a/components/camel-flatpack/pom.xml b/components/camel-flatpack/pom.xml
index 21db4e28390..87445f0d507 100644
--- a/components/camel-flatpack/pom.xml
+++ b/components/camel-flatpack/pom.xml
@@ -23,7 +23,7 @@
   <parent>
     <groupId>org.apache.camel</groupId>
     <artifactId>components</artifactId>
-    <version>2.23.0-SNAPSHOT</version>
+    <version>2.24.0-SNAPSHOT</version>
   </parent>
 
   <artifactId>camel-flatpack</artifactId>
diff --git a/components/camel-flatpack/src/main/java/org/apache/camel/component/flatpack/FlatpackConverter.java b/components/camel-flatpack/src/main/java/org/apache/camel/component/flatpack/FlatpackConverter.java
index e101acd51fe..335861b5308 100644
--- a/components/camel-flatpack/src/main/java/org/apache/camel/component/flatpack/FlatpackConverter.java
+++ b/components/camel-flatpack/src/main/java/org/apache/camel/component/flatpack/FlatpackConverter.java
@@ -21,6 +21,7 @@
 import java.util.List;
 import java.util.Map;
 
+import javax.xml.XMLConstants;
 import javax.xml.parsers.DocumentBuilderFactory;
 import javax.xml.parsers.ParserConfigurationException;
 
@@ -63,7 +64,9 @@ private FlatpackConverter() {
 
     @Converter
     public static Document toDocument(DataSet dataSet) throws ParserConfigurationException {
-        Document doc = DocumentBuilderFactory.newInstance().newDocumentBuilder().newDocument();
+        DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance();
+        dbf.setFeature(XMLConstants.FEATURE_SECURE_PROCESSING, Boolean.TRUE);
+        Document doc = dbf.newDocumentBuilder().newDocument();
 
         if (dataSet.getIndex() == -1) {
             Element list = doc.createElement("Dataset");
diff --git a/components/camel-flink/pom.xml b/components/camel-flink/pom.xml
index e073a9d967c..b9b6df00e20 100644
--- a/components/camel-flink/pom.xml
+++ b/components/camel-flink/pom.xml
@@ -25,7 +25,7 @@
   <parent>
     <artifactId>components</artifactId>
     <groupId>org.apache.camel</groupId>
-    <version>2.23.0-SNAPSHOT</version>
+    <version>2.24.0-SNAPSHOT</version>
   </parent>
 
   <artifactId>camel-flink</artifactId>
diff --git a/components/camel-fop/pom.xml b/components/camel-fop/pom.xml
index ba1fd97846b..a88e0d2485a 100644
--- a/components/camel-fop/pom.xml
+++ b/components/camel-fop/pom.xml
@@ -23,7 +23,7 @@
     <parent>
         <groupId>org.apache.camel</groupId>
         <artifactId>components</artifactId>
-        <version>2.23.0-SNAPSHOT</version>
+        <version>2.24.0-SNAPSHOT</version>
     </parent>
 
     <artifactId>camel-fop</artifactId>
diff --git a/components/camel-fop/src/main/java/org/apache/camel/component/fop/FopProducer.java b/components/camel-fop/src/main/java/org/apache/camel/component/fop/FopProducer.java
index dd77570aade..5aa82641f1d 100644
--- a/components/camel-fop/src/main/java/org/apache/camel/component/fop/FopProducer.java
+++ b/components/camel-fop/src/main/java/org/apache/camel/component/fop/FopProducer.java
@@ -19,6 +19,8 @@
 import java.io.ByteArrayOutputStream;
 import java.io.OutputStream;
 import java.util.Map;
+
+import javax.xml.XMLConstants;
 import javax.xml.transform.Result;
 import javax.xml.transform.Source;
 import javax.xml.transform.Transformer;
@@ -85,8 +87,9 @@ private OutputStream transform(FOUserAgent userAgent, String outputFormat, Sourc
         throws FOPException, TransformerException {
         OutputStream out = new ByteArrayOutputStream();
         Fop fop = fopFactory.newFop(outputFormat, userAgent, out);
-        TransformerFactory factory = TransformerFactory.newInstance();
-        Transformer transformer = factory.newTransformer();
+        TransformerFactory transformerFactory = TransformerFactory.newInstance();
+        transformerFactory.setFeature(XMLConstants.FEATURE_SECURE_PROCESSING, Boolean.TRUE);
+        Transformer transformer = transformerFactory.newTransformer();
 
         Result res = new SAXResult(fop.getDefaultHandler());
         transformer.transform(src, res);
diff --git a/components/camel-freemarker/pom.xml b/components/camel-freemarker/pom.xml
index 6ace7aa902a..eb659841321 100644
--- a/components/camel-freemarker/pom.xml
+++ b/components/camel-freemarker/pom.xml
@@ -23,7 +23,7 @@
     <parent>
         <groupId>org.apache.camel</groupId>
         <artifactId>components</artifactId>
-        <version>2.23.0-SNAPSHOT</version>
+        <version>2.24.0-SNAPSHOT</version>
     </parent>
 
     <artifactId>camel-freemarker</artifactId>
diff --git a/components/camel-ftp/pom.xml b/components/camel-ftp/pom.xml
index de0c3fc2a3e..7411ffa80f1 100644
--- a/components/camel-ftp/pom.xml
+++ b/components/camel-ftp/pom.xml
@@ -23,7 +23,7 @@
   <parent>
     <groupId>org.apache.camel</groupId>
     <artifactId>components</artifactId>
-    <version>2.23.0-SNAPSHOT</version>
+    <version>2.24.0-SNAPSHOT</version>
   </parent>
 
   <artifactId>camel-ftp</artifactId>
diff --git a/components/camel-ftp/src/main/java/org/apache/camel/component/file/remote/RemoteFile.java b/components/camel-ftp/src/main/java/org/apache/camel/component/file/remote/RemoteFile.java
index cd1d18eb340..e29c2484889 100644
--- a/components/camel-ftp/src/main/java/org/apache/camel/component/file/remote/RemoteFile.java
+++ b/components/camel-ftp/src/main/java/org/apache/camel/component/file/remote/RemoteFile.java
@@ -42,6 +42,11 @@ public void populateHeaders(GenericFileMessage<T> message) {
             message.setHeader("CamelFileHost", getHostname());
         }
     }
+    
+    @Override
+    public void populateHeaders(GenericFileMessage<T> message, boolean isProbeContentTypeFromEndpoint) {
+        populateHeaders(message);
+    }
 
     public String getHostname() {
         return hostname;
diff --git a/components/camel-ftp/src/main/java/org/apache/camel/component/file/remote/SftpOperations.java b/components/camel-ftp/src/main/java/org/apache/camel/component/file/remote/SftpOperations.java
index b912151f119..834595aedbb 100644
--- a/components/camel-ftp/src/main/java/org/apache/camel/component/file/remote/SftpOperations.java
+++ b/components/camel-ftp/src/main/java/org/apache/camel/component/file/remote/SftpOperations.java
@@ -47,6 +47,7 @@
 import com.jcraft.jsch.SocketFactory;
 import com.jcraft.jsch.UIKeyboardInteractive;
 import com.jcraft.jsch.UserInfo;
+
 import org.apache.camel.Exchange;
 import org.apache.camel.InvalidPayloadException;
 import org.apache.camel.LoggingLevel;
@@ -70,7 +71,8 @@
 /**
  * SFTP remote file operations
  * <p/>
- * The JSCH session and channel are not thread-safe so we need to synchronize access to using this operation.
+ * The JSCH session and channel are not thread-safe so we need to synchronize
+ * access to using this operation.
  */
 public class SftpOperations implements RemoteFileOperations<SftpRemoteFile> {
     private static final Logger LOG = LoggerFactory.getLogger(SftpOperations.class);
@@ -88,13 +90,14 @@ public SftpOperations(Proxy proxy) {
     }
 
     /**
-     * Extended user info which supports interactive keyboard mode, by entering the password.
+     * Extended user info which supports interactive keyboard mode, by entering
+     * the password.
      */
     public interface ExtendedUserInfo extends UserInfo, UIKeyboardInteractive {
     }
 
     public void setEndpoint(GenericFileEndpoint<SftpRemoteFile> endpoint) {
-        this.endpoint = (SftpEndpoint) endpoint;
+        this.endpoint = (SftpEndpoint)endpoint;
     }
 
     public synchronized boolean connect(RemoteFileConfiguration configuration) throws GenericFileOperationFailedException {
@@ -126,7 +129,7 @@ public synchronized boolean connect(RemoteFileConfiguration configuration) throw
                     }
 
                     LOG.trace("Channel isn't connected, trying to recreate and connect.");
-                    channel = (ChannelSftp) session.openChannel("sftp");
+                    channel = (ChannelSftp)session.openChannel("sftp");
 
                     if (endpoint.getConfiguration().getConnectTimeout() > 0) {
                         LOG.trace("Connecting use connectTimeout: {} ...", endpoint.getConfiguration().getConnectTimeout());
@@ -191,7 +194,7 @@ protected Session createSession(final RemoteFileConfiguration configuration) thr
         final JSch jsch = new JSch();
         JSch.setLogger(new JSchLogger(endpoint.getConfiguration().getJschLoggingLevel()));
 
-        SftpConfiguration sftpConfig = (SftpConfiguration) configuration;
+        SftpConfiguration sftpConfig = (SftpConfiguration)configuration;
 
         if (isNotEmpty(sftpConfig.getCiphers())) {
             LOG.debug("Using ciphers: {}", sftpConfig.getCiphers());
@@ -333,7 +336,8 @@ public boolean promptPassphrase(String s) {
 
             public boolean promptYesNo(String s) {
                 LOG.warn("Server asks for confirmation (yes|no): {}. Camel will answer no.", s);
-                // Return 'false' indicating modification of the hosts file is disabled.
+                // Return 'false' indicating modification of the hosts file is
+                // disabled.
                 return false;
             }
 
@@ -341,21 +345,24 @@ public void showMessage(String s) {
                 LOG.trace("Message received from Server: {}", s);
             }
 
-            public String[] promptKeyboardInteractive(String destination, String name,
-                                                      String instruction, String[] prompt, boolean[] echo) {
+            public String[] promptKeyboardInteractive(String destination, String name, String instruction, String[] prompt, boolean[] echo) {
                 // must return an empty array if password is null
                 if (configuration.getPassword() == null) {
                     return new String[0];
                 } else {
-                    return new String[]{configuration.getPassword()};
+                    return new String[] {configuration.getPassword()};
                 }
             }
 
         });
 
         // set the SO_TIMEOUT for the time after the connect phase
-        if (configuration.getSoTimeout() > 0) {
-            session.setTimeout(configuration.getSoTimeout());
+        if (sftpConfig.getServerAliveInterval() == 0) {
+            if (configuration.getSoTimeout() > 0) {
+                session.setTimeout(configuration.getSoTimeout());
+            }
+        } else {
+            LOG.debug("The Server Alive Internal is already set, the socket timeout won't be considered to avoid overidding the provided Server alive interval value");
         }
 
         // set proxy if configured
@@ -482,7 +489,7 @@ public synchronized boolean renameFile(String from, String to) throws GenericFil
         LOG.debug("Renaming file: {} to: {}", from, to);
         try {
             reconnectIfNecessary();
-            //make use of the '/' separator because JSch expects this 
+            // make use of the '/' separator because JSch expects this
             // as the file separator even on Windows
             to = FileUtil.compactPath(to, '/');
             channel.rename(from, to);
@@ -507,7 +514,8 @@ public synchronized boolean buildDirectory(String directory, boolean absolute) t
                 channel.ls(directory);
                 success = true;
             } catch (SftpException e) {
-                // ignore, we could not change directory so try to create it instead
+                // ignore, we could not change directory so try to create it
+                // instead
             }
 
             if (!success) {
@@ -517,7 +525,8 @@ public synchronized boolean buildDirectory(String directory, boolean absolute) t
                     channel.mkdir(directory);
                     success = true;
                 } catch (SftpException e) {
-                    // we are here if the server side doesn't create intermediate folders
+                    // we are here if the server side doesn't create
+                    // intermediate folders
                     // so create the folder one by one
                     success = buildDirectoryChunks(directory);
                 }
@@ -578,8 +587,10 @@ public synchronized void changeCurrentDirectory(String path) throws GenericFileO
             return;
         }
 
-        // must compact path so SFTP server can traverse correctly, make use of the '/'
-        // separator because JSch expects this as the file separator even on Windows
+        // must compact path so SFTP server can traverse correctly, make use of
+        // the '/'
+        // separator because JSch expects this as the file separator even on
+        // Windows
         String before = path;
         char separatorChar = '/';
         path = FileUtil.compactPath(path, separatorChar);
@@ -593,8 +604,9 @@ public synchronized void changeCurrentDirectory(String path) throws GenericFileO
             return;
         }
         if (getCurrentDirectory().startsWith(path)) {
-            // extract the path segment relative to the target path and make sure it keeps the preceding '/' for the regex op
-            String p = getCurrentDirectory().substring(path.length() - (path.endsWith("/") ?  1 : 0));
+            // extract the path segment relative to the target path and make
+            // sure it keeps the preceding '/' for the regex op
+            String p = getCurrentDirectory().substring(path.length() - (path.endsWith("/") ? 1 : 0));
             if (p.length() == 0) {
                 return;
             }
@@ -602,7 +614,8 @@ public synchronized void changeCurrentDirectory(String path) throws GenericFileO
             path = UP_DIR_PATTERN.matcher(p).replaceAll("/..").substring(1);
         }
 
-        // if it starts with the root path then a little special handling for that
+        // if it starts with the root path then a little special handling for
+        // that
         if (FileUtil.hasLeadingSeparator(path)) {
             // change to root path
             if (!FileUtil.isWindows()) {
@@ -673,7 +686,7 @@ public synchronized void changeToParentDirectory() throws GenericFileOperationFa
             // can return either null or an empty list depending on FTP servers
             if (files != null) {
                 for (Object file : files) {
-                    list.add(new SftpRemoteFileJCraft((ChannelSftp.LsEntry) file));
+                    list.add(new SftpRemoteFileJCraft((ChannelSftp.LsEntry)file));
                 }
             }
             return list;
@@ -685,7 +698,8 @@ public synchronized void changeToParentDirectory() throws GenericFileOperationFa
     public synchronized boolean retrieveFile(String name, Exchange exchange, long size) throws GenericFileOperationFailedException {
         LOG.trace("retrieveFile({})", name);
         if (ObjectHelper.isNotEmpty(endpoint.getLocalWorkDirectory())) {
-            // local work directory is configured so we should store file content as files in this local directory
+            // local work directory is configured so we should store file
+            // content as files in this local directory
             return retrieveFileToFileInLocalWorkDirectory(name, exchange);
         } else {
             // store file content directory as stream on the body
@@ -709,8 +723,7 @@ public synchronized void releaseRetrievedFileResources(Exchange exchange) throws
     private boolean retrieveFileToStreamInBody(String name, Exchange exchange) throws GenericFileOperationFailedException {
         String currentDir = null;
         try {
-            GenericFile<ChannelSftp.LsEntry> target =
-                    (GenericFile<ChannelSftp.LsEntry>) exchange.getProperty(FileComponent.FILE_EXCHANGE_FILE);
+            GenericFile<ChannelSftp.LsEntry> target = (GenericFile<ChannelSftp.LsEntry>)exchange.getProperty(FileComponent.FILE_EXCHANGE_FILE);
             ObjectHelper.notNull(target, "Exchange should have the " + FileComponent.FILE_EXCHANGE_FILE + " set");
 
             String remoteName = name;
@@ -719,12 +732,14 @@ private boolean retrieveFileToStreamInBody(String name, Exchange exchange) throw
                 currentDir = getCurrentDirectory();
 
                 // change directory to path where the file is to be retrieved
-                // (must do this as some FTP servers cannot retrieve using absolute path)
+                // (must do this as some FTP servers cannot retrieve using
+                // absolute path)
                 String path = FileUtil.onlyPath(name);
                 if (path != null) {
                     changeCurrentDirectory(path);
                 }
-                // remote name is now only the file name as we just changed directory
+                // remote name is now only the file name as we just changed
+                // directory
                 remoteName = FileUtil.stripPath(name);
             }
 
@@ -760,8 +775,7 @@ private boolean retrieveFileToFileInLocalWorkDirectory(String name, Exchange exc
         File temp;
         File local = new File(endpoint.getLocalWorkDirectory());
         OutputStream os;
-        GenericFile<ChannelSftp.LsEntry> file =
-                (GenericFile<ChannelSftp.LsEntry>) exchange.getProperty(FileComponent.FILE_EXCHANGE_FILE);
+        GenericFile<ChannelSftp.LsEntry> file = (GenericFile<ChannelSftp.LsEntry>)exchange.getProperty(FileComponent.FILE_EXCHANGE_FILE);
         ObjectHelper.notNull(file, "Exchange should have the " + FileComponent.FILE_EXCHANGE_FILE + " set");
         try {
             // use relative filename in local work directory
@@ -790,7 +804,8 @@ private boolean retrieveFileToFileInLocalWorkDirectory(String name, Exchange exc
                 throw new GenericFileOperationFailedException("Cannot create new local work file: " + temp);
             }
 
-            // store content as a file in the local work directory in the temp handle
+            // store content as a file in the local work directory in the temp
+            // handle
             os = new FileOutputStream(temp);
 
             // set header with the path to the local work file
@@ -809,12 +824,14 @@ private boolean retrieveFileToFileInLocalWorkDirectory(String name, Exchange exc
                 currentDir = getCurrentDirectory();
 
                 // change directory to path where the file is to be retrieved
-                // (must do this as some FTP servers cannot retrieve using absolute path)
+                // (must do this as some FTP servers cannot retrieve using
+                // absolute path)
                 String path = FileUtil.onlyPath(name);
                 if (path != null) {
                     changeCurrentDirectory(path);
                 }
-                // remote name is now only the file name as we just changed directory
+                // remote name is now only the file name as we just changed
+                // directory
                 remoteName = FileUtil.stripPath(name);
             }
 
@@ -822,7 +839,8 @@ private boolean retrieveFileToFileInLocalWorkDirectory(String name, Exchange exc
 
         } catch (SftpException e) {
             LOG.trace("Error occurred during retrieving file: {} to local directory. Deleting local work file: {}", name, temp);
-            // failed to retrieve the file so we need to close streams and delete in progress file
+            // failed to retrieve the file so we need to close streams and
+            // delete in progress file
             // must close stream before deleting file
             IOHelper.close(os, "retrieve: " + name, LOG);
             boolean deleted = FileUtil.deleteFile(temp);
@@ -841,7 +859,8 @@ private boolean retrieveFileToFileInLocalWorkDirectory(String name, Exchange exc
 
         LOG.debug("Retrieve file to local work file result: true");
 
-        // operation went okay so rename temp to local after we have retrieved the data
+        // operation went okay so rename temp to local after we have retrieved
+        // the data
         LOG.trace("Renaming local in progress file from: {} to: {}", temp, local);
         try {
             if (!FileUtil.renameFile(temp, local, false)) {
@@ -867,13 +886,15 @@ public synchronized boolean storeFile(String name, Exchange exchange, long size)
 
         try {
             if (path != null && endpoint.getConfiguration().isStepwise()) {
-                // must remember current dir so we stay in that directory after the write
+                // must remember current dir so we stay in that directory after
+                // the write
                 currentDir = getCurrentDirectory();
 
                 // change to path of name
                 changeCurrentDirectory(path);
 
-                // the target name should be without path, as we have changed directory
+                // the target name should be without path, as we have changed
+                // directory
                 targetName = FileUtil.stripPath(name);
             }
 
@@ -893,9 +914,7 @@ private boolean doStoreFile(String name, String targetName, Exchange exchange) t
         LOG.trace("doStoreFile({})", targetName);
 
         // if an existing file already exists what should we do?
-        if (endpoint.getFileExist() == GenericFileExist.Ignore
-                || endpoint.getFileExist() == GenericFileExist.Fail
-                || endpoint.getFileExist() == GenericFileExist.Move) {
+        if (endpoint.getFileExist() == GenericFileExist.Ignore || endpoint.getFileExist() == GenericFileExist.Fail || endpoint.getFileExist() == GenericFileExist.Move) {
             boolean existFile = existsFile(targetName);
             if (existFile && endpoint.getFileExist() == GenericFileExist.Ignore) {
                 // ignore but indicate that the file was written
@@ -914,7 +933,7 @@ private boolean doStoreFile(String name, String targetName, Exchange exchange) t
             // Do an explicit test for a null body and decide what to do
             if (endpoint.isAllowNullBody()) {
                 LOG.trace("Writing empty file.");
-                is = new ByteArrayInputStream(new byte[]{});
+                is = new ByteArrayInputStream(new byte[] {});
             } else {
                 throw new GenericFileOperationFailedException("Cannot write null body to file: " + name);
             }
@@ -945,8 +964,7 @@ private boolean doStoreFile(String name, String targetName, Exchange exchange) t
             }
             if (LOG.isDebugEnabled()) {
                 long time = watch.taken();
-                LOG.debug("Took {} ({} millis) to store file: {} and FTP client returned: true",
-                        new Object[]{TimeUtils.printDuration(time), time, targetName});
+                LOG.debug("Took {} ({} millis) to store file: {} and FTP client returned: true", new Object[] {TimeUtils.printDuration(time), time, targetName});
             }
 
             // after storing file, we may set chmod on the file
@@ -970,7 +988,7 @@ private boolean doStoreFile(String name, String targetName, Exchange exchange) t
             IOHelper.close(is, "store: " + name, LOG);
         }
     }
-    
+
     public synchronized boolean existsFile(String name) throws GenericFileOperationFailedException {
         LOG.trace("existsFile({})", name);
         if (endpoint.isFastExistsCheck()) {
@@ -992,7 +1010,7 @@ public synchronized boolean existsFile(String name) throws GenericFileOperationF
                 return false;
             }
             for (Object file : files) {
-                ChannelSftp.LsEntry entry = (ChannelSftp.LsEntry) file;
+                ChannelSftp.LsEntry entry = (ChannelSftp.LsEntry)file;
                 String existing = entry.getFilename();
                 LOG.trace("Existing file: {}, target file: {}", existing, name);
                 existing = FileUtil.stripPath(existing);
@@ -1002,7 +1020,8 @@ public synchronized boolean existsFile(String name) throws GenericFileOperationF
             }
             return false;
         } catch (SftpException e) {
-            // or an exception can be thrown with id 2 which means file does not exists
+            // or an exception can be thrown with id 2 which means file does not
+            // exists
             if (ChannelSftp.SSH_FX_NO_SUCH_FILE == e.id) {
                 return false;
             }
@@ -1021,7 +1040,8 @@ protected boolean fastExistsFile(String name) throws GenericFileOperationFailedE
             }
             return files.size() >= 1;
         } catch (SftpException e) {
-            // or an exception can be thrown with id 2 which means file does not exists
+            // or an exception can be thrown with id 2 which means file does not
+            // exists
             if (ChannelSftp.SSH_FX_NO_SUCH_FILE == e.id) {
                 return false;
             }
@@ -1050,10 +1070,9 @@ public synchronized boolean sendSiteCommand(String command) throws GenericFileOp
     }
 
     /*
-     * adapted from com.jcraft.jsch.Util.createSocket(String, int, int)
-     *
-     * added possibility to specify the address of the local network interface, against the
-     * connection should bind
+     * adapted from com.jcraft.jsch.Util.createSocket(String, int, int) added
+     * possibility to specify the address of the local network interface,
+     * against the connection should bind
      */
     static Socket createSocketUtil(final String host, final int port, final String bindAddress, final int timeout) {
         Socket socket = null;
@@ -1082,7 +1101,8 @@ public void run() {
                     if (sockp[0] != null && sockp[0].isConnected()) {
                         try {
                             sockp[0].close();
-                        } catch (Exception eee) { }
+                        } catch (Exception eee) {
+                        }
                     }
                     sockp[0] = null;
                 }
diff --git a/components/camel-ganglia/pom.xml b/components/camel-ganglia/pom.xml
index 16ef470729b..6c5e96236df 100644
--- a/components/camel-ganglia/pom.xml
+++ b/components/camel-ganglia/pom.xml
@@ -23,7 +23,7 @@
   <parent>
     <groupId>org.apache.camel</groupId>
     <artifactId>components</artifactId>
-    <version>2.23.0-SNAPSHOT</version>
+    <version>2.24.0-SNAPSHOT</version>
   </parent>
 
   <artifactId>camel-ganglia</artifactId>
diff --git a/components/camel-geocoder/pom.xml b/components/camel-geocoder/pom.xml
index 7a414a3f693..3f118e3f9ee 100644
--- a/components/camel-geocoder/pom.xml
+++ b/components/camel-geocoder/pom.xml
@@ -23,7 +23,7 @@
   <parent>
     <groupId>org.apache.camel</groupId>
     <artifactId>components</artifactId>
-    <version>2.23.0-SNAPSHOT</version>
+    <version>2.24.0-SNAPSHOT</version>
   </parent>
 
   <artifactId>camel-geocoder</artifactId>
diff --git a/components/camel-git/pom.xml b/components/camel-git/pom.xml
index 1562c0b3626..1f1a4f1b5d1 100644
--- a/components/camel-git/pom.xml
+++ b/components/camel-git/pom.xml
@@ -24,7 +24,7 @@
   <parent>
     <groupId>org.apache.camel</groupId>
     <artifactId>components</artifactId>
-    <version>2.23.0-SNAPSHOT</version>
+    <version>2.24.0-SNAPSHOT</version>
   </parent>
 
   <artifactId>camel-git</artifactId>
diff --git a/components/camel-github/pom.xml b/components/camel-github/pom.xml
index f2aba198aa6..69b364a4d04 100644
--- a/components/camel-github/pom.xml
+++ b/components/camel-github/pom.xml
@@ -24,7 +24,7 @@
   <parent>
     <groupId>org.apache.camel</groupId>
     <artifactId>components</artifactId>
-    <version>2.23.0-SNAPSHOT</version>
+    <version>2.24.0-SNAPSHOT</version>
   </parent>
 
   <artifactId>camel-github</artifactId>
diff --git a/components/camel-google-bigquery/pom.xml b/components/camel-google-bigquery/pom.xml
index ae87b2ccbb1..dc1715c9be5 100644
--- a/components/camel-google-bigquery/pom.xml
+++ b/components/camel-google-bigquery/pom.xml
@@ -25,7 +25,7 @@
   <parent>
     <groupId>org.apache.camel</groupId>
     <artifactId>components</artifactId>
-    <version>2.23.0-SNAPSHOT</version>
+    <version>2.24.0-SNAPSHOT</version>
   </parent>
 
   <artifactId>camel-google-bigquery</artifactId>
diff --git a/components/camel-google-bigquery/src/main/docs/google-bigquery-component.adoc b/components/camel-google-bigquery/src/main/docs/google-bigquery-component.adoc
index 5af187d5f94..765591ea58f 100644
--- a/components/camel-google-bigquery/src/main/docs/google-bigquery-component.adoc
+++ b/components/camel-google-bigquery/src/main/docs/google-bigquery-component.adoc
@@ -3,8 +3,6 @@
 
 *Available as of Camel version 2.20*
 
-### Component Description
-
 The Google Bigquery component provides access
 to https://cloud.google.com/bigquery/[Cloud BigQuery Infrastructure] via
 the https://developers.google.com/api-client-library/java/apis/bigquery/v2[Google Client Services API].
@@ -29,7 +27,7 @@ for this component:
 
 [[GoogleBigQuery-AuthenticationConfiguration]]
 
-### Authentication Configuration
+=== Authentication Configuration
 
 Google BigQuery component authentication is targeted for use with the GCP Service Accounts.
 For more information please refer to https://cloud.google.com/docs/authentication[Google Cloud Platform Auth Guide]
@@ -48,15 +46,15 @@ https://developers.google.com/identity/protocols/application-default-credentials
 
 Service Account Email and Service Account Key can be found in the GCP JSON credentials file as client_email and private_key respectively.
 
-### URI Format
+=== URI Format
 
-[source,java]
+[source,text]
 --------------------------------------------------------
         google-bigquery://project-id:datasetId[:tableId]?[options]
 --------------------------------------------------------
 
 
-### Options
+=== Options
 
 // component options: START
 The Google BigQuery component supports 4 options, which are listed below.
@@ -124,7 +122,7 @@ The component supports 4 options, which are listed below.
 // spring-boot-auto-configure options: END
 
 
-### Message Headers
+=== Message Headers
 
 [width="100%",cols="10%,10%,80%",options="header",]
 |=======================================================================
@@ -136,7 +134,7 @@ The component supports 4 options, which are listed below.
 |=======================================================================
 
 
-### Producer Endpoints
+=== Producer Endpoints
 
 Producer endpoints can accept and deliver to BigQuery individual and grouped
 exchanges alike. Grouped exchanges have `Exchange.GROUPED_EXCHANGE` property set.
@@ -148,7 +146,7 @@ correct suffix or partition decorator.
 Google BigQuery endpoint expects the payload to be either a map or list of maps. A payload containing a map
 will insert a single row and a payload containing a list of map's will insert a row for each entry in the list.
 
-### Template tables
+=== Template tables
 
 Reference: https://cloud.google.com/bigquery/streaming-data-into-bigquery#template-tables
 
@@ -159,13 +157,12 @@ I.e. the following route will create tables and insert records sharded on a per
 [source,java]
 ------------------------------------------------------
 from("direct:start")
-.header(GoogleBigQueryConstants.TABLE_SUFFIX, "_${date:now:yyyyMMdd}")
-.to("google-bigquery:sampleDataset:sampleTable")
-
+  .header(GoogleBigQueryConstants.TABLE_SUFFIX, "_${date:now:yyyyMMdd}")
+  .to("google-bigquery:sampleDataset:sampleTable")
 ------------------------------------------------------
 Note it is recommended to use partitioning for this use case.
 
-### Partitioning
+=== Partitioning
 
 Reference: https://cloud.google.com/bigquery/docs/creating-partitioned-tables
 
@@ -173,7 +170,7 @@ Partitioning is specified when creating a table and if set data will be automati
 separate tables. When inserting data a specific partition can be specified by setting the
 `GoogleBigQueryConstants.PARTITION_DECORATOR` header on the exchange.
 
-### Ensuring data consistency
+=== Ensuring data consistency
 
 Reference: https://cloud.google.com/bigquery/streaming-data-into-bigquery#dataconsistency
 
diff --git a/components/camel-google-bigquery/src/main/docs/google-bigquery-sql-component.adoc b/components/camel-google-bigquery/src/main/docs/google-bigquery-sql-component.adoc
new file mode 100644
index 00000000000..44379ca358d
--- /dev/null
+++ b/components/camel-google-bigquery/src/main/docs/google-bigquery-sql-component.adoc
@@ -0,0 +1,151 @@
+[[google-bigquery-sql-component]]
+== Google BigQuery Standard SQL Component
+*Available as of Camel version 2.23*
+*Available as of Camel version 2.23*
+
+
+
+The Google Bigquery SQL component provides access
+to https://cloud.google.com/bigquery/[Cloud BigQuery Infrastructure] via
+the https://developers.google.com/apis-explorer/#p/bigquery/v2/bigquery.jobs.query[Google Client Services API].
+
+The current implementation supports only standard SQL
+https://cloud.google.com/bigquery/docs/reference/standard-sql/dml-syntax[DML queries].
+
+Maven users will need to add the following dependency to their pom.xml
+for this component:
+
+[source,xml]
+------------------------------------------------------
+<dependency>
+    <groupId>org.apache.camel</groupId>
+    <artifactId>camel-google-bigquery</artifactId>
+    <version>x.x.x</version>
+    <!-- use the same version as your Camel core version -->
+</dependency>
+
+------------------------------------------------------
+
+[[GoogleBigQuery-AuthenticationConfiguration]]
+
+=== Authentication Configuration
+
+Google BigQuery component authentication is targeted for use with the GCP Service Accounts.
+For more information please refer to https://cloud.google.com/docs/authentication[Google Cloud Platform Auth Guide]
+
+Google security credentials can be set explicitly via one of the two options:
+
+* Service Account Email and Service Account Key (PEM format)
+* GCP credentials file location
+
+If both are set, the Service Account Email/Key will take precedence.
+
+Or implicitly, where the connection factory falls back on
+https://developers.google.com/identity/protocols/application-default-credentials#howtheywork[Application Default Credentials].
+
+*OBS!* The location of the default credentials file is configurable - via GOOGLE_APPLICATION_CREDENTIALS environment variable.
+
+Service Account Email and Service Account Key can be found in the GCP JSON credentials file as client_email and private_key respectively.
+
+=== URI Format
+
+[source,text]
+--------------------------------------------------------
+        google-bigquery-sql://project-id:query?[options]
+--------------------------------------------------------
+
+Examples:
+[source,text]
+--------------------------------------------------------
+        google-bigquery-sql://project-17248459:delete * from test.table where id=@myId
+        google-bigquery-sql://project-17248459:delete * from ${datasetId}.${tableId} where id=@myId
+--------------------------------------------------------
+where
+
+ * parameters in form ${name} are extracted from message headers and formed the translated query
+ * parameters in form @name are extracted from body or message headers and sent to Google Bigquery
+
+You can externalize your SQL queries to files in the classpath or file system as shown:
+[source,text]
+--------------------------------------------------------
+        google-bigquery-sql://project-17248459::classpath:delete.sql
+--------------------------------------------------------
+
+
+
+=== Options
+
+// component options: START
+The Google BigQuery Standard SQL component supports 3 options, which are listed below.
+
+
+
+[width="100%",cols="2,5,^1,2",options="header"]
+|===
+| Name | Description | Default | Type
+| *projectId* (producer) | Google Cloud Project Id |  | String
+| *connectionFactory* (producer) | ConnectionFactory to obtain connection to Bigquery Service. If non provided the default one will be used |  | GoogleBigQuery ConnectionFactory
+| *resolveProperty Placeholders* (advanced) | Whether the component should resolve property placeholders on itself when starting. Only properties which are of String type can use property placeholders. | true | boolean
+|===
+// component options: END
+
+// endpoint options: START
+The Google BigQuery Standard SQL endpoint is configured using URI syntax:
+
+----
+google-bigquery-sql:query
+----
+
+with the following path and query parameters:
+
+==== Path Parameters (2 parameters):
+
+
+[width="100%",cols="2,5,^1,2",options="header"]
+|===
+| Name | Description | Default | Type
+| *projectId* | *Required* Google Cloud Project Id |  | String
+| *query* | *Required* BigQuery standard SQL query |  | String
+|===
+
+
+==== Query Parameters (2 parameters):
+
+
+[width="100%",cols="2,5,^1,2",options="header"]
+|===
+| Name | Description | Default | Type
+| *connectionFactory* (producer) | ConnectionFactory to obtain connection to Bigquery Service. If non provided the default will be used. |  | GoogleBigQuery ConnectionFactory
+| *synchronous* (advanced) | Sets whether synchronous processing should be strictly used, or Camel is allowed to use asynchronous processing (if supported). | false | boolean
+|===
+// endpoint options: END
+// spring-boot-auto-configure options: START
+=== Spring Boot Auto-Configuration
+
+
+The component supports 3 options, which are listed below.
+
+
+
+[width="100%",cols="2,5,^1,2",options="header"]
+|===
+| Name | Description | Default | Type
+| *camel.component.google-bigquery-sql.enabled* | Whether to enable auto configuration of the google-bigquery-sql component. This is enabled by default. |  | Boolean
+| *camel.component.google-bigquery-sql.project-id* | Google Cloud Project Id |  | String
+| *camel.component.google-bigquery-sql.resolve-property-placeholders* | Whether the component should resolve property placeholders on itself when starting. Only properties which are of String type can use property placeholders. | true | Boolean
+|===
+// spring-boot-auto-configure options: END
+
+
+=== Ouput Message Headers
+
+[width="100%",cols="10%,10%,80%",options="header",]
+|=======================================================================
+|Name |Type |Description
+|`CamelGoogleBigQueryTranslatedQuery` |`String` | Preprocessed query text
+|=======================================================================
+
+
+=== Producer Endpoints
+
+Google BigQuery SQL endpoint expects the payload to be either empty or a map of query parameters.
\ No newline at end of file
diff --git a/components/camel-google-bigquery/src/main/java/org/apache/camel/component/google/bigquery/GoogleBigQueryConstants.java b/components/camel-google-bigquery/src/main/java/org/apache/camel/component/google/bigquery/GoogleBigQueryConstants.java
index 89d0eebac92..945cde7551e 100644
--- a/components/camel-google-bigquery/src/main/java/org/apache/camel/component/google/bigquery/GoogleBigQueryConstants.java
+++ b/components/camel-google-bigquery/src/main/java/org/apache/camel/component/google/bigquery/GoogleBigQueryConstants.java
@@ -16,9 +16,17 @@
  */
 package org.apache.camel.component.google.bigquery;
 
-public interface GoogleBigQueryConstants {
-    String TABLE_SUFFIX = "CamelGoogleBigQueryTableSuffix";
-    String TABLE_ID = "CamelGoogleBigQueryTableId";
-    String INSERT_ID = "CamelGoogleBigQueryInsertId";
-    String PARTITION_DECORATOR = "CamelGoogleBigQueryPartitionDecorator";
+public final class GoogleBigQueryConstants {
+    public static final String TABLE_SUFFIX = "CamelGoogleBigQueryTableSuffix";
+    public static final String TABLE_ID = "CamelGoogleBigQueryTableId";
+    public static final String INSERT_ID = "CamelGoogleBigQueryInsertId";
+    public static final String PARTITION_DECORATOR = "CamelGoogleBigQueryPartitionDecorator";
+    public static final String TRANSLATED_QUERY = "CamelGoogleBigQueryTranslatedQuery";
+
+    /**
+     * Prevent instantiation.
+     */
+    private GoogleBigQueryConstants() {
+        super();
+    }
 }
diff --git a/components/camel-google-bigquery/src/main/java/org/apache/camel/component/google/bigquery/sql/GoogleBigQuerySQLComponent.java b/components/camel-google-bigquery/src/main/java/org/apache/camel/component/google/bigquery/sql/GoogleBigQuerySQLComponent.java
new file mode 100644
index 00000000000..a0b23639f50
--- /dev/null
+++ b/components/camel-google-bigquery/src/main/java/org/apache/camel/component/google/bigquery/sql/GoogleBigQuerySQLComponent.java
@@ -0,0 +1,82 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.camel.component.google.bigquery.sql;
+
+import java.util.Map;
+import org.apache.camel.CamelContext;
+import org.apache.camel.Endpoint;
+import org.apache.camel.component.google.bigquery.GoogleBigQueryConnectionFactory;
+import org.apache.camel.impl.DefaultComponent;
+
+public class GoogleBigQuerySQLComponent extends DefaultComponent {
+    private String projectId;
+    private GoogleBigQueryConnectionFactory connectionFactory;
+
+    public GoogleBigQuerySQLComponent() {
+        super();
+    }
+
+    public GoogleBigQuerySQLComponent(CamelContext camelContext) {
+        super(camelContext);
+    }
+
+    // Endpoint represents a single table
+    @Override
+    protected Endpoint createEndpoint(String uri, String remaining, Map<String, Object> parameters) throws Exception {
+        String[] parts = remaining.split(":");
+
+        if (parts.length < 2) {
+            throw new IllegalArgumentException("Google BigQuery Endpoint format \"projectId:<query>\"");
+        }
+
+        GoogleBigQuerySQLConfiguration configuration = new GoogleBigQuerySQLConfiguration();
+        setProperties(configuration, parameters);
+        configuration.parseRemaining(remaining);
+
+        if (configuration.getConnectionFactory() == null) {
+            configuration.setConnectionFactory(getConnectionFactory());
+        }
+
+        return new GoogleBigQuerySQLEndpoint(uri, this, configuration);
+    }
+
+    public String getProjectId() {
+        return projectId;
+    }
+
+    /**
+     * Google Cloud Project Id
+     */
+    public void setProjectId(String projectId) {
+        this.projectId = projectId;
+    }
+
+    public GoogleBigQueryConnectionFactory getConnectionFactory() {
+        if (connectionFactory == null) {
+            connectionFactory = new GoogleBigQueryConnectionFactory();
+        }
+        return connectionFactory;
+    }
+
+    /**
+     * ConnectionFactory to obtain connection to Bigquery Service. If non
+     * provided the default one will be used
+     */
+    public void setConnectionFactory(GoogleBigQueryConnectionFactory connectionFactory) {
+        this.connectionFactory = connectionFactory;
+    }
+}
diff --git a/components/camel-google-bigquery/src/main/java/org/apache/camel/component/google/bigquery/sql/GoogleBigQuerySQLConfiguration.java b/components/camel-google-bigquery/src/main/java/org/apache/camel/component/google/bigquery/sql/GoogleBigQuerySQLConfiguration.java
new file mode 100644
index 00000000000..5e766a07cd5
--- /dev/null
+++ b/components/camel-google-bigquery/src/main/java/org/apache/camel/component/google/bigquery/sql/GoogleBigQuerySQLConfiguration.java
@@ -0,0 +1,77 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.camel.component.google.bigquery.sql;
+
+import org.apache.camel.component.google.bigquery.GoogleBigQueryConnectionFactory;
+import org.apache.camel.spi.Metadata;
+import org.apache.camel.spi.UriParam;
+import org.apache.camel.spi.UriParams;
+import org.apache.camel.spi.UriPath;
+
+@UriParams
+public class GoogleBigQuerySQLConfiguration {
+
+    @UriParam(description = "ConnectionFactory to obtain connection to Bigquery Service. If non provided the default one will be used")
+    private GoogleBigQueryConnectionFactory connectionFactory;
+    @UriPath(label = "common", description = "Google Cloud Project Id")
+    @Metadata(required = "true")
+    private String projectId;
+    @UriPath(label = "common", description = "BigQuery standard SQL query")
+    @Metadata(required = "true")
+    private String query;
+
+    public void parseRemaining(String remaining) {
+        int indexOfColon = remaining.indexOf(":");
+
+        if (indexOfColon < 0) {
+            throw new IllegalArgumentException("Google BigQuery Endpoint format \"projectId:query\"");
+        }
+
+        projectId = remaining.substring(0, indexOfColon);
+        query = remaining.substring(indexOfColon + 1);
+    }
+
+    /**
+     * ConnectionFactory to obtain connection to Bigquery Service. If non
+     * provided the default will be used.
+     */
+    public GoogleBigQueryConnectionFactory getConnectionFactory() {
+        return connectionFactory;
+    }
+
+    public void setConnectionFactory(GoogleBigQueryConnectionFactory connectionFactory) {
+        this.connectionFactory = connectionFactory;
+    }
+
+    public String getQuery() {
+        return query;
+    }
+
+    public GoogleBigQuerySQLConfiguration setQuery(String query) {
+        this.query = query;
+        return this;
+    }
+
+    public String getProjectId() {
+        return projectId;
+    }
+
+    public GoogleBigQuerySQLConfiguration setProjectId(String projectId) {
+        this.projectId = projectId;
+        return this;
+    }
+}
diff --git a/components/camel-google-bigquery/src/main/java/org/apache/camel/component/google/bigquery/sql/GoogleBigQuerySQLEndpoint.java b/components/camel-google-bigquery/src/main/java/org/apache/camel/component/google/bigquery/sql/GoogleBigQuerySQLEndpoint.java
new file mode 100644
index 00000000000..2d4e15f6091
--- /dev/null
+++ b/components/camel-google-bigquery/src/main/java/org/apache/camel/component/google/bigquery/sql/GoogleBigQuerySQLEndpoint.java
@@ -0,0 +1,78 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.camel.component.google.bigquery.sql;
+
+import com.google.api.services.bigquery.Bigquery;
+import org.apache.camel.Consumer;
+import org.apache.camel.Processor;
+import org.apache.camel.Producer;
+import org.apache.camel.impl.DefaultEndpoint;
+import org.apache.camel.spi.UriEndpoint;
+import org.apache.camel.spi.UriParam;
+
+/**
+ * Google BigQuery data warehouse for analytics (using SQL queries).
+ *
+ * BigQuery Endpoint Definition
+ * Represents a table within a BigQuery dataset
+ * Contains configuration details for a single table and the utility methods (such as check, create) to ease operations
+ * URI Parameters:
+ * * Logger ID - To ensure that logging is unified under Route Logger, the logger ID can be passed on
+ *               via an endpoint URI parameter
+ * * Partitioned - to indicate that the table needs to be partitioned - every UTC day to be written into a
+ *                 timestamped separate table
+ *                 side effect: Australian operational day is always split between two UTC days, and, therefore, tables
+ *
+ * Another consideration is that exceptions are not handled within the class. They are expected to bubble up and be handled
+ * by Camel.
+ */
+@UriEndpoint(firstVersion = "2.23.0", scheme = "google-bigquery-sql", title = "Google BigQuery Standard SQL", syntax = "google-bigquery-sql:query", label = "cloud,messaging", producerOnly = true)
+public class GoogleBigQuerySQLEndpoint extends DefaultEndpoint {
+
+    @UriParam
+    protected final GoogleBigQuerySQLConfiguration configuration;
+
+    protected GoogleBigQuerySQLEndpoint(String endpointUri, GoogleBigQuerySQLComponent component, GoogleBigQuerySQLConfiguration configuration) {
+        super(endpointUri, component);
+        this.configuration = configuration;
+    }
+
+    @Override
+    public Producer createProducer() throws Exception {
+        Bigquery bigquery = getConfiguration().getConnectionFactory().getDefaultClient();
+        GoogleBigQuerySQLProducer producer = new GoogleBigQuerySQLProducer(bigquery, this, configuration);
+        return producer;
+    }
+
+    public Consumer createConsumer(Processor processor) throws Exception {
+        throw new UnsupportedOperationException("Cannot consume from the BigQuery endpoint: " + getEndpointUri());
+    }
+
+    public boolean isSingleton() {
+        return true;
+    }
+
+    public GoogleBigQuerySQLConfiguration getConfiguration() {
+        return configuration;
+    }
+
+    @Override
+    public GoogleBigQuerySQLComponent getComponent() {
+        return (GoogleBigQuerySQLComponent)super.getComponent();
+    }
+
+}
diff --git a/components/camel-google-bigquery/src/main/java/org/apache/camel/component/google/bigquery/sql/GoogleBigQuerySQLProducer.java b/components/camel-google-bigquery/src/main/java/org/apache/camel/component/google/bigquery/sql/GoogleBigQuerySQLProducer.java
new file mode 100644
index 00000000000..eb136669365
--- /dev/null
+++ b/components/camel-google-bigquery/src/main/java/org/apache/camel/component/google/bigquery/sql/GoogleBigQuerySQLProducer.java
@@ -0,0 +1,160 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.camel.component.google.bigquery.sql;
+
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+
+import com.google.api.services.bigquery.Bigquery;
+import com.google.api.services.bigquery.model.QueryParameter;
+import com.google.api.services.bigquery.model.QueryParameterType;
+import com.google.api.services.bigquery.model.QueryParameterValue;
+import com.google.api.services.bigquery.model.QueryRequest;
+import com.google.api.services.bigquery.model.QueryResponse;
+
+import org.apache.camel.Exchange;
+import org.apache.camel.Message;
+import org.apache.camel.RuntimeExchangeException;
+import org.apache.camel.component.google.bigquery.GoogleBigQueryConstants;
+import org.apache.camel.impl.DefaultProducer;
+
+/**
+ * Generic BigQuery Producer
+ */
+public class GoogleBigQuerySQLProducer extends DefaultProducer {
+
+    private final GoogleBigQuerySQLConfiguration configuration;
+    private Bigquery bigquery;
+    private String query;
+    private Set<String> queryParameterNames;
+
+    public GoogleBigQuerySQLProducer(Bigquery bigquery, GoogleBigQuerySQLEndpoint endpoint, GoogleBigQuerySQLConfiguration configuration) {
+        super(endpoint);
+        this.bigquery = bigquery;
+        this.configuration = configuration;
+    }
+
+    /**
+     * Process the exchange The incoming exchange can be a grouped exchange in
+     * which case all the exchanges will be combined. The incoming can be
+     * <ul>
+     * <li>A map where all map keys will map to field records. One map object
+     * maps to one bigquery row</li>
+     * <li>A list of maps. Each entry in the list will map to one bigquery
+     * row</li>
+     * </ul>
+     * The incoming message is expected to be a List of Maps The assumptions: -
+     * All incoming records go into the same table - Incoming records sorted by
+     * the timestamp
+     */
+    @Override
+    public void process(Exchange exchange) throws Exception {
+        String translatedQuery = SqlHelper.translateQuery(query, exchange);
+        Map<String, Object> queryParameters = extractParameters(exchange);
+        exchange.getMessage().setHeader(GoogleBigQueryConstants.TRANSLATED_QUERY, translatedQuery);
+        Long affectedRows = executeSQL(translatedQuery, queryParameters);
+        log.debug("The query {} affected {} rows", query, affectedRows);
+        exchange.getMessage().setBody(affectedRows);
+    }
+
+    private Long executeSQL(String translatedQuery, Map<String, Object> queryParameters) throws Exception {
+        QueryRequest apiQueryRequest = new QueryRequest().setQuery(translatedQuery).setUseLegacySql(false);
+
+        Bigquery.Jobs.Query apiQuery = bigquery.jobs().query(configuration.getProjectId(), apiQueryRequest);
+
+        setQueryParameters(queryParameters, apiQueryRequest);
+
+        if (log.isTraceEnabled()) {
+            log.trace("Sending query to bigquery standard sql: {}", translatedQuery);
+        }
+
+        QueryResponse apiResponse = apiQuery.execute();
+
+        if (apiResponse.getErrors() != null && !apiResponse.getErrors().isEmpty()) {
+            throw new Exception("Query " + translatedQuery + " failed: " + apiResponse.getErrors());
+        }
+
+        if (log.isTraceEnabled()) {
+            log.trace("Result of query {} is {}", translatedQuery, apiResponse.toPrettyString());
+        }
+        return apiResponse.getNumDmlAffectedRows();
+    }
+
+    private Map<String, Object> extractParameters(Exchange exchange) {
+        if (queryParameterNames == null || queryParameterNames.size() == 0) {
+            return null;
+        }
+
+        Message message = exchange.getMessage();
+
+        HashMap<String, Object> headers = new HashMap<>(message.getHeaders());
+        if (message.getBody() instanceof Map) {
+            try {
+                headers.putAll(message.getBody(Map.class));
+            } catch (ClassCastException e) {
+                e.printStackTrace();
+            }
+        }
+
+        HashMap<String, Object> result = new HashMap<>(queryParameterNames.size());
+        queryParameterNames.forEach(s -> {
+            Object value = headers.get(s);
+            if (value == null) {
+                throw new RuntimeExchangeException("SQL parameter with name '" + s + "' not found in the message headers", exchange);
+            }
+
+            result.put(s, headers.get(s));
+        });
+
+        return result;
+    }
+
+    private void setQueryParameters(Map<String, Object> params, QueryRequest apiQueryRequest) {
+        if (params == null) {
+            return;
+        }
+
+        List<QueryParameter> list = new ArrayList<>();
+        params.forEach((key, value) -> {
+            QueryParameter param = new QueryParameter();
+            param.setName(key).setParameterType(new QueryParameterType().setType("STRING")).setParameterValue(new QueryParameterValue().setValue(value.toString()));
+            list.add(param);
+        });
+        apiQueryRequest.setQueryParameters(list);
+    }
+
+    @Override
+    public boolean isSingleton() {
+        return true;
+    }
+
+    @Override
+    public GoogleBigQuerySQLEndpoint getEndpoint() {
+        return (GoogleBigQuerySQLEndpoint)super.getEndpoint();
+    }
+
+    @Override
+    protected void doStart() throws Exception {
+        super.doStart();
+        String placeholder = ":#"; // TODO
+        query = SqlHelper.resolveQuery(getEndpoint().getCamelContext(), configuration.getQuery(), placeholder);
+        queryParameterNames = SqlHelper.extractParameterNames(query);
+    }
+}
diff --git a/components/camel-google-bigquery/src/main/java/org/apache/camel/component/google/bigquery/sql/SqlHelper.java b/components/camel-google-bigquery/src/main/java/org/apache/camel/component/google/bigquery/sql/SqlHelper.java
new file mode 100644
index 00000000000..9ecd2e2d54c
--- /dev/null
+++ b/components/camel-google-bigquery/src/main/java/org/apache/camel/component/google/bigquery/sql/SqlHelper.java
@@ -0,0 +1,101 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.camel.component.google.bigquery.sql;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.util.HashSet;
+import java.util.Set;
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
+
+import org.apache.camel.CamelContext;
+import org.apache.camel.Exchange;
+import org.apache.camel.Message;
+import org.apache.camel.NoTypeConversionAvailableException;
+import org.apache.camel.RuntimeExchangeException;
+import org.apache.camel.util.ResourceHelper;
+
+public final class SqlHelper {
+
+    private static Pattern pattern = Pattern.compile("\\$\\{(\\w+)}");
+    private static Pattern parameterPattern = Pattern.compile("@(\\w+)");
+
+    private SqlHelper() {
+    }
+
+    /**
+     * Resolve the query by loading the query from the classpath or file
+     * resource if needed.
+     */
+    public static String resolveQuery(CamelContext camelContext, String query, String placeholder) throws NoTypeConversionAvailableException, IOException {
+        String answer = query;
+        if (ResourceHelper.hasScheme(query)) {
+            InputStream is = ResourceHelper.resolveMandatoryResourceAsInputStream(camelContext, query);
+            answer = camelContext.getTypeConverter().mandatoryConvertTo(String.class, is);
+            if (placeholder != null) {
+                answer = answer.replaceAll(placeholder, "@");
+            }
+        }
+        return answer;
+    }
+
+    /**
+     * Replaces pattern in query in form of "${param}" with values from message
+     * header Raises an error if param value not found in headers
+     * 
+     * @param exchange
+     * @return Translated query text
+     */
+    public static String translateQuery(String query, Exchange exchange) {
+        Message message = exchange.getMessage();
+        Matcher matcher = pattern.matcher(query);
+        StringBuffer stringBuffer = new StringBuffer();
+        while (matcher.find()) {
+            String paramKey = matcher.group(1);
+
+            String value = message.getHeader(paramKey, String.class);
+            if (value == null) {
+                value = exchange.getProperty(paramKey, String.class);
+                if (value == null) {
+                    throw new RuntimeExchangeException("SQL pattern with name '" + paramKey + "' not found in the message headers", exchange);
+                }
+            }
+
+            String replacement = Matcher.quoteReplacement(value);
+            matcher.appendReplacement(stringBuffer, replacement);
+        }
+        matcher.appendTail(stringBuffer);
+        return stringBuffer.toString();
+    }
+
+    /**
+     * Extracts list of parameters in form "@name" from query text
+     * 
+     * @param query
+     * @return list of parameter names
+     */
+    public static Set<String> extractParameterNames(String query) {
+        Matcher matcher = parameterPattern.matcher(query);
+        Set<String> result = new HashSet<>();
+        while (matcher.find()) {
+            String paramName = matcher.group(1);
+            result.add(paramName);
+        }
+        return result;
+    }
+}
diff --git a/components/camel-google-bigquery/src/main/resources/META-INF/services/org/apache/camel/component/google-bigquery-sql b/components/camel-google-bigquery/src/main/resources/META-INF/services/org/apache/camel/component/google-bigquery-sql
new file mode 100644
index 00000000000..1bf97f0eb25
--- /dev/null
+++ b/components/camel-google-bigquery/src/main/resources/META-INF/services/org/apache/camel/component/google-bigquery-sql
@@ -0,0 +1,18 @@
+## ------------------------------------------------------------------------
+## 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.
+## ------------------------------------------------------------------------
+
+class=org.apache.camel.component.google.bigquery.sql.GoogleBigQuerySQLComponent
diff --git a/components/camel-google-bigquery/src/test/java/org/apache/camel/component/google/bigquery/integration/sql/SqlQueryFromResourceTest.java b/components/camel-google-bigquery/src/test/java/org/apache/camel/component/google/bigquery/integration/sql/SqlQueryFromResourceTest.java
new file mode 100644
index 00000000000..1ea8f46fc46
--- /dev/null
+++ b/components/camel-google-bigquery/src/test/java/org/apache/camel/component/google/bigquery/integration/sql/SqlQueryFromResourceTest.java
@@ -0,0 +1,85 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.camel.component.google.bigquery.integration.sql;
+
+import java.util.HashMap;
+import java.util.Map;
+import java.util.UUID;
+import org.apache.camel.Endpoint;
+import org.apache.camel.EndpointInject;
+import org.apache.camel.Exchange;
+import org.apache.camel.Produce;
+import org.apache.camel.ProducerTemplate;
+import org.apache.camel.builder.RouteBuilder;
+import org.apache.camel.component.google.bigquery.integration.BigQueryTestSupport;
+import org.apache.camel.component.mock.MockEndpoint;
+import org.apache.camel.impl.DefaultExchange;
+import org.junit.Before;
+import org.junit.Test;
+
+public class SqlQueryFromResourceTest extends BigQueryTestSupport {
+    private static final String TABLE_ID = "test_sql_table";
+
+    @EndpointInject(uri = "direct:in")
+    private Endpoint directIn;
+
+    @EndpointInject(uri = "google-bigquery-sql:{{project.id}}:classpath:sql/insert.sql")
+    private Endpoint bigqueryEndpoint;
+
+    @EndpointInject(uri = "mock:sendResult")
+    private MockEndpoint sendResult;
+
+    @Produce(uri = "direct:in")
+    private ProducerTemplate producer;
+
+    @Before
+    public void init() throws Exception {
+        createBqTable(TABLE_ID);
+    }
+
+    @Override
+    protected RouteBuilder createRouteBuilder() throws Exception {
+        return new RouteBuilder() {
+            public void configure() {
+                from(directIn)
+                        .routeId("InsertRow")
+                        .to(bigqueryEndpoint)
+                        .to(sendResult);
+            }
+        };
+    }
+
+    @Test
+    public void insertRecordBySql() throws Exception {
+        Exchange exchange = new DefaultExchange(context);
+        String uuidCol1 = UUID.randomUUID().toString();
+        String uuidCol2 = UUID.randomUUID().toString();
+
+        Map<String, String> object = new HashMap<>();
+        object.put("col1", uuidCol1);
+        object.put("col2", uuidCol2);
+        exchange.getIn().setBody(object);
+
+        sendResult.expectedMessageCount(1);
+        sendResult.expectedBodiesReceived(1);
+        producer.send(exchange);
+        sendResult.assertIsSatisfied(4000);
+
+        assertRowExist(TABLE_ID, object);
+    }
+
+}
diff --git a/components/camel-google-bigquery/src/test/java/org/apache/camel/component/google/bigquery/integration/sql/SqlQueryTest.java b/components/camel-google-bigquery/src/test/java/org/apache/camel/component/google/bigquery/integration/sql/SqlQueryTest.java
new file mode 100644
index 00000000000..fc490e5571e
--- /dev/null
+++ b/components/camel-google-bigquery/src/test/java/org/apache/camel/component/google/bigquery/integration/sql/SqlQueryTest.java
@@ -0,0 +1,85 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.camel.component.google.bigquery.integration.sql;
+
+import java.util.HashMap;
+import java.util.Map;
+import java.util.UUID;
+import org.apache.camel.Endpoint;
+import org.apache.camel.EndpointInject;
+import org.apache.camel.Exchange;
+import org.apache.camel.Produce;
+import org.apache.camel.ProducerTemplate;
+import org.apache.camel.builder.RouteBuilder;
+import org.apache.camel.component.google.bigquery.integration.BigQueryTestSupport;
+import org.apache.camel.component.mock.MockEndpoint;
+import org.apache.camel.impl.DefaultExchange;
+import org.junit.Before;
+import org.junit.Test;
+
+public class SqlQueryTest extends BigQueryTestSupport {
+    private static final String TABLE_ID = "test_sql_table";
+
+    @EndpointInject(uri = "direct:in")
+    private Endpoint directIn;
+
+    @EndpointInject(uri = "google-bigquery-sql:{{project.id}}: insert into {{bigquery.datasetId}}." + TABLE_ID + "(col1, col2) values (@col1, @col2)")
+    private Endpoint bigqueryEndpoint;
+
+    @EndpointInject(uri = "mock:sendResult")
+    private MockEndpoint sendResult;
+
+    @Produce(uri = "direct:in")
+    private ProducerTemplate producer;
+
+    @Before
+    public void init() throws Exception {
+        createBqTable(TABLE_ID);
+    }
+
+    @Override
+    protected RouteBuilder createRouteBuilder() throws Exception {
+        return new RouteBuilder() {
+            public void configure() {
+                from(directIn)
+                        .routeId("InsertRow")
+                        .to(bigqueryEndpoint)
+                        .to(sendResult);
+            }
+        };
+    }
+
+    @Test
+    public void insertRecordBySql() throws Exception {
+        Exchange exchange = new DefaultExchange(context);
+        String uuidCol1 = UUID.randomUUID().toString();
+        String uuidCol2 = UUID.randomUUID().toString();
+
+        Map<String, String> object = new HashMap<>();
+        object.put("col1", uuidCol1);
+        object.put("col2", uuidCol2);
+        exchange.getIn().setBody(object);
+
+        sendResult.expectedMessageCount(1);
+        sendResult.expectedBodiesReceived(1);
+        producer.send(exchange);
+        sendResult.assertIsSatisfied(4000);
+
+        assertRowExist(TABLE_ID, object);
+    }
+
+}
diff --git a/components/camel-google-bigquery/src/test/java/org/apache/camel/component/google/bigquery/unit/sql/GoogleBigQuerySQLComponentTest.java b/components/camel-google-bigquery/src/test/java/org/apache/camel/component/google/bigquery/unit/sql/GoogleBigQuerySQLComponentTest.java
new file mode 100644
index 00000000000..5cd5d2cb6f4
--- /dev/null
+++ b/components/camel-google-bigquery/src/test/java/org/apache/camel/component/google/bigquery/unit/sql/GoogleBigQuerySQLComponentTest.java
@@ -0,0 +1,49 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.camel.component.google.bigquery.unit.sql;
+
+import org.apache.camel.CamelContext;
+import org.apache.camel.component.google.bigquery.sql.GoogleBigQuerySQLComponent;
+import org.apache.camel.component.google.bigquery.sql.GoogleBigQuerySQLEndpoint;
+import org.junit.Test;
+import org.mockito.Mockito;
+
+import static org.junit.Assert.assertEquals;
+
+public class GoogleBigQuerySQLComponentTest {
+    private CamelContext context = Mockito.mock(CamelContext.class);
+
+    @Test
+    public void testQuerySet() throws Exception {
+        String uri = "google-bigquery-sql:myproject:insert into testDatasetId.testTableId(id) values(1)";
+
+        GoogleBigQuerySQLEndpoint endpoint = (GoogleBigQuerySQLEndpoint)new GoogleBigQuerySQLComponent(context).createEndpoint(uri);
+
+        assertEquals("myproject", endpoint.getConfiguration().getProjectId());
+        assertEquals("insert into testDatasetId.testTableId(id) values(1)", endpoint.getConfiguration().getQuery());
+    }
+
+    @Test
+    public void testQueryFromResourceSet() throws Exception {
+        String uri = "google-bigquery-sql:myproject:classpath:sql/delete.sql";
+
+        GoogleBigQuerySQLEndpoint endpoint = (GoogleBigQuerySQLEndpoint)new GoogleBigQuerySQLComponent(context).createEndpoint(uri);
+
+        assertEquals("myproject", endpoint.getConfiguration().getProjectId());
+        assertEquals("classpath:sql/delete.sql", endpoint.getConfiguration().getQuery());
+    }
+}
diff --git a/components/camel-google-bigquery/src/test/java/org/apache/camel/component/google/bigquery/unit/sql/GoogleBigQuerySQLProducerBaseTest.java b/components/camel-google-bigquery/src/test/java/org/apache/camel/component/google/bigquery/unit/sql/GoogleBigQuerySQLProducerBaseTest.java
new file mode 100644
index 00000000000..fa28b70e235
--- /dev/null
+++ b/components/camel-google-bigquery/src/test/java/org/apache/camel/component/google/bigquery/unit/sql/GoogleBigQuerySQLProducerBaseTest.java
@@ -0,0 +1,59 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.camel.component.google.bigquery.unit.sql;
+
+import com.google.api.services.bigquery.Bigquery;
+import com.google.api.services.bigquery.model.QueryResponse;
+import org.apache.camel.component.google.bigquery.sql.GoogleBigQuerySQLConfiguration;
+import org.apache.camel.component.google.bigquery.sql.GoogleBigQuerySQLEndpoint;
+import org.apache.camel.component.google.bigquery.sql.GoogleBigQuerySQLProducer;
+import org.apache.camel.test.junit4.CamelTestSupport;
+
+import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.ArgumentMatchers.anyString;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.when;
+
+public class GoogleBigQuerySQLProducerBaseTest extends CamelTestSupport {
+    protected GoogleBigQuerySQLEndpoint endpoint = mock(GoogleBigQuerySQLEndpoint.class);
+    protected Bigquery.Jobs mockJobs = mock(Bigquery.Jobs.class);
+    protected Bigquery.Jobs.Query mockQuery = mock(Bigquery.Jobs.Query.class);
+    protected GoogleBigQuerySQLProducer producer;
+    protected String sql;
+    protected String projectId = "testProjectId";
+    protected GoogleBigQuerySQLConfiguration configuration = new GoogleBigQuerySQLConfiguration();
+    protected Bigquery bigquery;
+
+    protected GoogleBigQuerySQLProducer createAndStartProducer() throws Exception {
+        configuration.setProjectId(projectId);
+        configuration.setQuery(sql);
+
+        GoogleBigQuerySQLProducer sqlProducer = new GoogleBigQuerySQLProducer(bigquery, endpoint, configuration);
+        sqlProducer.start();
+        return sqlProducer;
+    }
+
+    protected void setupBigqueryMock() throws Exception {
+        bigquery = mock(Bigquery.class);
+
+        when(bigquery.jobs()).thenReturn(mockJobs);
+        when(bigquery.jobs().query(anyString(), any())).thenReturn(mockQuery);
+
+        QueryResponse mockResponse = new QueryResponse().setNumDmlAffectedRows(1L);
+        when(mockQuery.execute()).thenReturn(mockResponse);
+    }
+}
diff --git a/components/camel-google-bigquery/src/test/java/org/apache/camel/component/google/bigquery/unit/sql/GoogleBigQuerySQLProducerWithParamersTest.java b/components/camel-google-bigquery/src/test/java/org/apache/camel/component/google/bigquery/unit/sql/GoogleBigQuerySQLProducerWithParamersTest.java
new file mode 100644
index 00000000000..5eaa916578a
--- /dev/null
+++ b/components/camel-google-bigquery/src/test/java/org/apache/camel/component/google/bigquery/unit/sql/GoogleBigQuerySQLProducerWithParamersTest.java
@@ -0,0 +1,91 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.camel.component.google.bigquery.unit.sql;
+
+import java.util.HashMap;
+import java.util.Map;
+
+import com.google.api.services.bigquery.model.QueryRequest;
+import org.apache.camel.Exchange;
+import org.apache.camel.RuntimeExchangeException;
+import org.junit.Before;
+import org.junit.Test;
+import org.mockito.ArgumentCaptor;
+
+import static org.mockito.ArgumentMatchers.eq;
+import static org.mockito.Mockito.verify;
+
+public class GoogleBigQuerySQLProducerWithParamersTest extends GoogleBigQuerySQLProducerBaseTest {
+
+    @Before
+    public void init() throws Exception {
+        sql = "insert into testDatasetId.testTableId(id, data) values(@id, @data)";
+        setupBigqueryMock();
+        producer = createAndStartProducer();
+    }
+
+    @Test
+    public void sendMessageWithParametersInBody() throws Exception {
+        Map<String, String> body = new HashMap<>();
+        body.put("id", "100");
+        body.put("data", "some data");
+        producer.process(createExchangeWithBody(body));
+
+        ArgumentCaptor<QueryRequest> dataCaptor = ArgumentCaptor.forClass(QueryRequest.class);
+        verify(bigquery.jobs()).query(eq(projectId), dataCaptor.capture());
+
+        QueryRequest request = dataCaptor.getValue();
+        assertEquals(sql, request.getQuery());
+        assertEquals(2, request.getQueryParameters().size());
+
+        assertEquals("id", request.getQueryParameters().get(1).getName());
+        assertEquals("100", request.getQueryParameters().get(1).getParameterValue().getValue());
+
+        assertEquals("data", request.getQueryParameters().get(0).getName());
+        assertEquals("some data", request.getQueryParameters().get(0).getParameterValue().getValue());
+    }
+
+    @Test
+    public void sendMessageWithParametersInBodyAndHeaders() throws Exception {
+        Map<String, String> body = new HashMap<>();
+        body.put("id", "100");
+
+        Exchange exchange = createExchangeWithBody(body);
+        exchange.getMessage().getHeaders().put("id", "200");
+        exchange.getMessage().getHeaders().put("data", "some data");
+
+        producer.process(exchange);
+
+        ArgumentCaptor<QueryRequest> dataCaptor = ArgumentCaptor.forClass(QueryRequest.class);
+        verify(bigquery.jobs()).query(eq(projectId), dataCaptor.capture());
+
+        QueryRequest request = dataCaptor.getValue();
+        assertEquals(sql, request.getQuery());
+        assertEquals(2, request.getQueryParameters().size());
+
+        assertEquals("id", request.getQueryParameters().get(1).getName());
+        assertEquals("Body data must have higher priority", "100", request.getQueryParameters().get(1).getParameterValue().getValue());
+
+        assertEquals("data", request.getQueryParameters().get(0).getName());
+        assertEquals("some data", request.getQueryParameters().get(0).getParameterValue().getValue());
+    }
+
+    @Test(expected = RuntimeExchangeException.class)
+    public void sendMessageWithoutParameters() throws Exception {
+        producer.process(createExchangeWithBody(new HashMap<>()));
+    }
+}
diff --git a/components/camel-google-bigquery/src/test/java/org/apache/camel/component/google/bigquery/unit/sql/GoogleBigQuerySQLProducerWithPatternTest.java b/components/camel-google-bigquery/src/test/java/org/apache/camel/component/google/bigquery/unit/sql/GoogleBigQuerySQLProducerWithPatternTest.java
new file mode 100644
index 00000000000..93ac9970b2c
--- /dev/null
+++ b/components/camel-google-bigquery/src/test/java/org/apache/camel/component/google/bigquery/unit/sql/GoogleBigQuerySQLProducerWithPatternTest.java
@@ -0,0 +1,69 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.camel.component.google.bigquery.unit.sql;
+
+import java.util.List;
+
+import com.google.api.services.bigquery.model.QueryRequest;
+import org.apache.camel.Exchange;
+import org.junit.Before;
+import org.junit.Test;
+import org.mockito.ArgumentCaptor;
+
+import static org.mockito.ArgumentMatchers.eq;
+import static org.mockito.Mockito.verify;
+
+public class GoogleBigQuerySQLProducerWithPatternTest extends GoogleBigQuerySQLProducerBaseTest {
+
+    @Before
+    public void init() throws Exception {
+        sql = "insert into ${testDatasetId}.testTableId(id, data) values(1, 'test')";
+        setupBigqueryMock();
+        producer = createAndStartProducer();
+    }
+
+    @Test
+    public void sendExchangeWithProperties() throws Exception {
+        Exchange exchange = createExchangeWithBody(null);
+        exchange.getProperties().put("testDatasetId", "dataset");
+        String expected = "insert into dataset.testTableId(id, data) values(1, 'test')";
+        producer.process(exchange);
+
+        ArgumentCaptor<QueryRequest> dataCaptor = ArgumentCaptor.forClass(QueryRequest.class);
+        verify(bigquery.jobs()).query(eq(projectId), dataCaptor.capture());
+
+        List<QueryRequest> requests = dataCaptor.getAllValues();
+        assertEquals(1, requests.size());
+        assertEquals(expected, requests.get(0).getQuery());
+    }
+
+    @Test
+    public void sendMessageWithHeaders() throws Exception {
+        Exchange exchange = createExchangeWithBody(null);
+        exchange.getMessage().getHeaders().put("testDatasetId", "dataset");
+        String expected = "insert into dataset.testTableId(id, data) values(1, 'test')";
+        producer.process(exchange);
+
+        ArgumentCaptor<QueryRequest> dataCaptor = ArgumentCaptor.forClass(QueryRequest.class);
+        verify(bigquery.jobs()).query(eq(projectId), dataCaptor.capture());
+
+        List<QueryRequest> requests = dataCaptor.getAllValues();
+        assertEquals(1, requests.size());
+        assertEquals(expected, requests.get(0).getQuery());
+    }
+
+}
diff --git a/components/camel-google-bigquery/src/test/java/org/apache/camel/component/google/bigquery/unit/sql/SqlHelperTest.java b/components/camel-google-bigquery/src/test/java/org/apache/camel/component/google/bigquery/unit/sql/SqlHelperTest.java
new file mode 100644
index 00000000000..1ab2b2fe120
--- /dev/null
+++ b/components/camel-google-bigquery/src/test/java/org/apache/camel/component/google/bigquery/unit/sql/SqlHelperTest.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.component.google.bigquery.unit.sql;
+
+import java.util.Set;
+
+import org.apache.camel.CamelContext;
+import org.apache.camel.Exchange;
+import org.apache.camel.Message;
+import org.apache.camel.RuntimeExchangeException;
+import org.apache.camel.component.google.bigquery.sql.SqlHelper;
+import org.junit.Ignore;
+import org.junit.Test;
+import org.mockito.Mockito;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertTrue;
+import static org.junit.Assert.fail;
+import static org.mockito.ArgumentMatchers.eq;
+import static org.mockito.Mockito.when;
+
+public class SqlHelperTest {
+
+    String query = "INSERT INTO ${report}.test( -- TODO \n" + "  id,\n" + "  region\n" + ")\n" + "SELECT\n" + "  id,\n" + "  region\n" + "FROM\n" + "  ${import}.test\n" + "WHERE\n"
+                   + "  rec_date = @date AND id = @id\n";
+
+    String expected = "INSERT INTO report_data.test( -- TODO \n" + "  id,\n" + "  region\n" + ")\n" + "SELECT\n" + "  id,\n" + "  region\n" + "FROM\n" + "  import_data.test\n"
+                      + "WHERE\n" + "  rec_date = @date AND id = @id\n";
+
+    Exchange exchange = Mockito.mock(Exchange.class);
+    Message message = Mockito.mock(Message.class);
+    
+    private CamelContext context = Mockito.mock(CamelContext.class);
+
+    @Test
+    public void testResolveQuery() throws Exception {
+        String answer = SqlHelper.resolveQuery(context, "delete from test.test_sql_table where id = 1", null);
+        assertEquals("delete from test.test_sql_table where id = 1", answer);
+    }
+
+    @Test
+    @Ignore
+    public void testResolveClasspathQuery() throws Exception {
+        String answer = SqlHelper.resolveQuery(context, "classpath:sql/delete.sql", ":");
+        assertEquals("delete from test.test_sql_table where id = @id", answer);
+    }
+
+    @Test
+    public void testTranslateQuery() {
+        when(exchange.getMessage()).thenReturn(message);
+        when(message.getHeader(eq("report"), eq(String.class))).thenReturn("report_data");
+        when(message.getHeader(eq("import"), eq(String.class))).thenReturn("import_data");
+
+        String answer = SqlHelper.translateQuery(query, exchange);
+        assertEquals(expected, answer);
+    }
+
+    @Test
+    public void testTranslateQueryProperties() {
+        when(exchange.getMessage()).thenReturn(message);
+        when(exchange.getProperty(eq("report"), eq(String.class))).thenReturn("report_data");
+        when(exchange.getProperty(eq("import"), eq(String.class))).thenReturn("import_data");
+
+        String answer = SqlHelper.translateQuery(query, exchange);
+        assertEquals(expected, answer);
+    }
+
+    @Test(expected = RuntimeExchangeException.class)
+    public void testTranslateQueryWithoutParam() {
+        when(exchange.getMessage()).thenReturn(message);
+        when(message.getHeader(eq("report"), eq(String.class))).thenReturn("report_data");
+
+        SqlHelper.translateQuery(query, exchange);
+        fail("Should have thrown exception");
+    }
+
+    @Test
+    public void testExtractParameterNames() {
+        Set<String> answer = SqlHelper.extractParameterNames(query);
+        assertEquals(2, answer.size());
+        assertTrue("Parameter 'date' not found", answer.contains("date"));
+        assertTrue("Parameter 'id' not found", answer.contains("id"));
+    }
+}
diff --git a/components/camel-google-bigquery/src/test/resources/sql/delete.sql b/components/camel-google-bigquery/src/test/resources/sql/delete.sql
new file mode 100644
index 00000000000..d074f551105
--- /dev/null
+++ b/components/camel-google-bigquery/src/test/resources/sql/delete.sql
@@ -0,0 +1 @@
+delete from test.test_sql_table where id = :id
\ No newline at end of file
diff --git a/components/camel-google-bigquery/src/test/resources/sql/insert.sql b/components/camel-google-bigquery/src/test/resources/sql/insert.sql
new file mode 100644
index 00000000000..74048aaa83d
--- /dev/null
+++ b/components/camel-google-bigquery/src/test/resources/sql/insert.sql
@@ -0,0 +1,2 @@
+insert into test.test_sql_table (col1, col2)
+values (@col1, @col2)
\ No newline at end of file
diff --git a/components/camel-google-calendar/pom.xml b/components/camel-google-calendar/pom.xml
index f9be968d55c..fb7b006d3e8 100644
--- a/components/camel-google-calendar/pom.xml
+++ b/components/camel-google-calendar/pom.xml
@@ -24,7 +24,7 @@
   <parent>
     <groupId>org.apache.camel</groupId>
     <artifactId>components</artifactId>
-    <version>2.23.0-SNAPSHOT</version>
+    <version>2.24.0-SNAPSHOT</version>
   </parent>
 
   <artifactId>camel-google-calendar</artifactId>
diff --git a/components/camel-google-calendar/src/main/docs/google-calendar-stream-component.adoc b/components/camel-google-calendar/src/main/docs/google-calendar-stream-component.adoc
index 93090f493b7..bcfe0362e89 100644
--- a/components/camel-google-calendar/src/main/docs/google-calendar-stream-component.adoc
+++ b/components/camel-google-calendar/src/main/docs/google-calendar-stream-component.adoc
@@ -12,7 +12,7 @@ Google Calendar uses
 the https://developers.google.com/accounts/docs/OAuth2[OAuth 2.0
 protocol] for authenticating a Google account and authorizing access to
 user data. Before you can use this component, you will need
-to https://developers.google.com/gmail/api/auth/web-server[create an
+to https://developers.google.com/calendar/auth[create an
 account and generate OAuth credentials]. Credentials comprise of a
 clientId, clientSecret, and a refreshToken. A handy resource for
 generating a long-lived refreshToken is
@@ -27,7 +27,7 @@ for this component:
             <artifactId>camel-google-calendar</artifactId>
             <version>2.23.0</version>
     </dependency>
-        
+
 ------------------------------------------------------
 
 ### URI Format
@@ -36,10 +36,10 @@ The Google Calendar Component uses the following URI format:
 
 --------------------------------------------------------
         google-calendar-stream://index?[options]
-    
+
 --------------------------------------------------------
 
-### GoogleMailStreamComponent
+### GoogleCalendarStreamComponent
 
 
 // component options: START
@@ -88,14 +88,14 @@ with the following path and query parameters:
 | *applicationName* (consumer) | Google Calendar application name. Example would be camel-google-calendar/1.0 |  | String
 | *bridgeErrorHandler* (consumer) | Allows for bridging the consumer to the Camel routing Error Handler, which mean any exceptions occurred while the consumer is trying to pickup incoming messages, or the likes, will now be processed as a message and handled by the routing Error Handler. By default the consumer will use the org.apache.camel.spi.ExceptionHandler to deal with exceptions, that will be logged at WARN or ERROR level and ignored. | false | boolean
 | *calendarId* (consumer) | The calendarId to be used | primary | String
-| *clientId* (consumer) | Client ID of the mail application |  | String
-| *clientSecret* (consumer) | Client secret of the mail application |  | String
+| *clientId* (consumer) | Client ID of the calendar application |  | String
+| *clientSecret* (consumer) | Client secret of the calendar application |  | String
 | *considerLastUpdate* (consumer) | Take into account the lastUpdate of the last event polled as start date for the next poll | false | boolean
 | *consumeFromNow* (consumer) | Consume events in the selected calendar from now on | true | boolean
 | *maxResults* (consumer) | Max results to be returned | 10 | int
 | *query* (consumer) | The query to execute on calendar |  | String
 | *refreshToken* (consumer) | OAuth 2 refresh token. Using this, the Google Calendar component can obtain a new accessToken whenever the current one expires - a necessity if the application is long-lived. |  | String
-| *scopes* (consumer) | Specifies the level of permissions you want a mail application to have to a user account. See https://developers.google.com/calendar/api/auth/scopes for more info. |  | List
+| *scopes* (consumer) | Specifies the level of permissions you want a calendar application to have to a user account. See https://developers.google.com/calendar/auth for more info. |  | List
 | *sendEmptyMessageWhenIdle* (consumer) | If the polling consumer did not poll any files, you can enable this option to send an empty message (no body) instead. | false | boolean
 | *exceptionHandler* (consumer) | To let the consumer use a custom ExceptionHandler. Notice if the option bridgeErrorHandler is enabled then this option is not in use. By default the consumer will deal with exceptions, that will be logged at WARN or ERROR level and ignored. |  | ExceptionHandler
 | *exchangePattern* (consumer) | Sets the exchange pattern when the consumer creates an exchange. |  | ExchangePattern
@@ -131,15 +131,15 @@ The component supports 15 options, which are listed below.
 | *camel.component.google-calendar-stream.configuration.access-token* | OAuth 2 access token. This typically expires after an hour so refreshToken is recommended for long term usage. |  | String
 | *camel.component.google-calendar-stream.configuration.application-name* | Google Calendar application name. Example would be camel-google-calendar/1.0 |  | String
 | *camel.component.google-calendar-stream.configuration.calendar-id* | The calendarId to be used | primary | String
-| *camel.component.google-calendar-stream.configuration.client-id* | Client ID of the mail application |  | String
-| *camel.component.google-calendar-stream.configuration.client-secret* | Client secret of the mail application |  | String
+| *camel.component.google-calendar-stream.configuration.client-id* | Client ID of the calendar application |  | String
+| *camel.component.google-calendar-stream.configuration.client-secret* | Client secret of the calendar application |  | String
 | *camel.component.google-calendar-stream.configuration.consider-last-update* | Take into account the lastUpdate of the last event polled as start date for the next poll | false | Boolean
 | *camel.component.google-calendar-stream.configuration.consume-from-now* | Consume events in the selected calendar from now on | true | Boolean
 | *camel.component.google-calendar-stream.configuration.index* | Specifies an index for the endpoint |  | String
 | *camel.component.google-calendar-stream.configuration.max-results* | Max results to be returned | 10 | Integer
 | *camel.component.google-calendar-stream.configuration.query* | The query to execute on calendar |  | String
 | *camel.component.google-calendar-stream.configuration.refresh-token* | OAuth 2 refresh token. Using this, the Google Calendar component can obtain a new accessToken whenever the current one expires - a necessity if the application is long-lived. |  | String
-| *camel.component.google-calendar-stream.configuration.scopes* | Specifies the level of permissions you want a mail application to have to a user account. See https://developers.google.com/calendar/api/auth/scopes for more info. |  | List
+| *camel.component.google-calendar-stream.configuration.scopes* | Specifies the level of permissions you want a calendar application to have to a user account. See https://developers.google.com/calendar/auth for more info. |  | List
 | *camel.component.google-calendar-stream.enabled* | Whether to enable auto configuration of the google-calendar-stream component. This is enabled by default. |  | Boolean
 | *camel.component.google-calendar-stream.resolve-property-placeholders* | Whether the component should resolve property placeholders on itself when starting. Only properties which are of String type can use property placeholders. | true | Boolean
 |===
@@ -148,7 +148,7 @@ The component supports 15 options, which are listed below.
 
 ### Consumer
 
-The consumer will poll by default with maxResults equals to 10.
+The consumer will poll by default with maxResults equals to 5.
 
 For example
 
@@ -157,6 +157,6 @@ For example
 from("google-calendar-stream://test?markAsRead=true&delay=5000&maxResults=5").to("mock:result");
 ---------------------------------------------------------
 
-This route will consume the next ten events starting from the date of polling.
+This route will consume the next five events starting from the date of polling.
 
    
diff --git a/components/camel-google-calendar/src/main/java/org/apache/camel/component/google/calendar/internal/GoogleCalendarConstants.java b/components/camel-google-calendar/src/main/java/org/apache/camel/component/google/calendar/internal/GoogleCalendarConstants.java
index b604ad036c7..f25f84c59d9 100644
--- a/components/camel-google-calendar/src/main/java/org/apache/camel/component/google/calendar/internal/GoogleCalendarConstants.java
+++ b/components/camel-google-calendar/src/main/java/org/apache/camel/component/google/calendar/internal/GoogleCalendarConstants.java
@@ -19,11 +19,18 @@
 /**
  * Constants for GoogleCalendar component.
  */
-public interface GoogleCalendarConstants {
+public final class GoogleCalendarConstants {
 
     // suffix for parameters when passed as exchange header properties
-    String PROPERTY_PREFIX = "CamelGoogleCalendar.";
+    public static final String PROPERTY_PREFIX = "CamelGoogleCalendar.";
 
     // thread profile name for this component
-    String THREAD_PROFILE_NAME = "CamelGoogleCalendar";
+    public static final String THREAD_PROFILE_NAME = "CamelGoogleCalendar";
+
+    /**
+     * Prevent instantiation.
+     */
+    private GoogleCalendarConstants() {
+        super();
+    }
 }
diff --git a/components/camel-google-calendar/src/main/java/org/apache/camel/component/google/calendar/stream/GoogleCalendarStreamComponent.java b/components/camel-google-calendar/src/main/java/org/apache/camel/component/google/calendar/stream/GoogleCalendarStreamComponent.java
index 150e432fb36..4c55eef6f22 100644
--- a/components/camel-google-calendar/src/main/java/org/apache/camel/component/google/calendar/stream/GoogleCalendarStreamComponent.java
+++ b/components/camel-google-calendar/src/main/java/org/apache/camel/component/google/calendar/stream/GoogleCalendarStreamComponent.java
@@ -19,7 +19,6 @@
 import java.util.Map;
 
 import com.google.api.services.calendar.Calendar;
-
 import org.apache.camel.CamelContext;
 import org.apache.camel.Endpoint;
 import org.apache.camel.component.google.calendar.BatchGoogleCalendarClientFactory;
@@ -49,11 +48,11 @@ public GoogleCalendarStreamComponent(CamelContext context) {
         this.configuration = new GoogleCalendarStreamConfiguration();
     }
 
-    public Calendar getClient(GoogleCalendarStreamConfiguration googleMailConfiguration) {
+    public Calendar getClient(GoogleCalendarStreamConfiguration endpointConfiguration) {
         if (client == null) {
-            client = getClientFactory().makeClient(googleMailConfiguration.getClientId(), googleMailConfiguration.getClientSecret(), configuration.getScopes(),
-                                                   googleMailConfiguration.getApplicationName(), googleMailConfiguration.getRefreshToken(),
-                                                   googleMailConfiguration.getAccessToken(), null, null, "me");
+            client = getClientFactory().makeClient(endpointConfiguration.getClientId(), endpointConfiguration.getClientSecret(), endpointConfiguration.getScopes(),
+                                                    endpointConfiguration.getApplicationName(), endpointConfiguration.getRefreshToken(),
+                                                    endpointConfiguration.getAccessToken(), null, null, "me");
         }
         return client;
     }
diff --git a/components/camel-google-calendar/src/main/java/org/apache/camel/component/google/calendar/stream/GoogleCalendarStreamConfiguration.java b/components/camel-google-calendar/src/main/java/org/apache/camel/component/google/calendar/stream/GoogleCalendarStreamConfiguration.java
index 8b5648d56df..4fbc43ecd37 100644
--- a/components/camel-google-calendar/src/main/java/org/apache/camel/component/google/calendar/stream/GoogleCalendarStreamConfiguration.java
+++ b/components/camel-google-calendar/src/main/java/org/apache/camel/component/google/calendar/stream/GoogleCalendarStreamConfiguration.java
@@ -16,11 +16,10 @@
  */
 package org.apache.camel.component.google.calendar.stream;
 
-import java.util.Arrays;
+import java.util.Collections;
 import java.util.List;
 
 import com.google.api.services.calendar.CalendarScopes;
-
 import org.apache.camel.RuntimeCamelException;
 import org.apache.camel.spi.UriParam;
 import org.apache.camel.spi.UriParams;
@@ -31,7 +30,7 @@
  */
 @UriParams
 public class GoogleCalendarStreamConfiguration implements Cloneable {
-    private static final List<String> DEFAULT_SCOPES = Arrays.asList(CalendarScopes.CALENDAR);
+    private static final List<String> DEFAULT_SCOPES = Collections.singletonList(CalendarScopes.CALENDAR);
 
     @UriPath
     private String index;
@@ -59,13 +58,13 @@
 
     @UriParam(defaultValue = "10")
     private int maxResults = 10;
-    
+
     @UriParam(defaultValue = "primary")
     private String calendarId = "primary";
-    
+
     @UriParam(defaultValue = "true")
     private boolean consumeFromNow = true;
-    
+
     @UriParam(defaultValue = "false")
     private boolean considerLastUpdate;
 
@@ -74,7 +73,7 @@ public String getClientId() {
     }
 
     /**
-     * Client ID of the mail application
+     * Client ID of the calendar application
      */
     public void setClientId(String clientId) {
         this.clientId = clientId;
@@ -85,7 +84,7 @@ public String getClientSecret() {
     }
 
     /**
-     * Client secret of the mail application
+     * Client secret of the calendar application
      */
     public void setClientSecret(String clientSecret) {
         this.clientSecret = clientSecret;
@@ -132,8 +131,8 @@ public void setApplicationName(String applicationName) {
     }
 
     /**
-     * Specifies the level of permissions you want a mail application to have to
-     * a user account. See https://developers.google.com/calendar/api/auth/scopes
+     * Specifies the level of permissions you want a calendar application to have to
+     * a user account. See https://developers.google.com/calendar/auth
      * for more info.
      */
     public void setScopes(List<String> scopes) {
@@ -187,7 +186,7 @@ public void setCalendarId(String calendarId) {
     public boolean isConsumeFromNow() {
         return consumeFromNow;
     }
-    
+
     /**
      * Consume events in the selected calendar from now on
      */
diff --git a/components/camel-google-calendar/src/main/java/org/apache/camel/component/google/calendar/stream/GoogleCalendarStreamConstants.java b/components/camel-google-calendar/src/main/java/org/apache/camel/component/google/calendar/stream/GoogleCalendarStreamConstants.java
index c671c544471..6f61d54a9d4 100644
--- a/components/camel-google-calendar/src/main/java/org/apache/camel/component/google/calendar/stream/GoogleCalendarStreamConstants.java
+++ b/components/camel-google-calendar/src/main/java/org/apache/camel/component/google/calendar/stream/GoogleCalendarStreamConstants.java
@@ -19,12 +19,14 @@
 /**
  * Constants used in Camel Google Calendar Stream
  */
-public interface GoogleCalendarStreamConstants {
+public final class GoogleCalendarStreamConstants {
 
-    String MAIL_TO = "CamelGoogleMailStreamTo";
-    String MAIL_FROM = "CamelGoogleMailStreamFrom";
-    String MAIL_CC = "CamelGoogleMailStreamCc";
-    String MAIL_BCC = "CamelGoogleMailStreamBcc";
-    String MAIL_SUBJECT = "CamelGoogleMailStreamSubject";
-    String MAIL_ID = "CamelGoogleMailId";
+    public static final String EVENT_ID = "CamelGoogleCalendarEventId";
+
+    /**
+     * Prevent instantiation.
+     */
+    private GoogleCalendarStreamConstants() {
+        super();
+    }
 }
diff --git a/components/camel-google-calendar/src/main/java/org/apache/camel/component/google/calendar/stream/GoogleCalendarStreamEndpoint.java b/components/camel-google-calendar/src/main/java/org/apache/camel/component/google/calendar/stream/GoogleCalendarStreamEndpoint.java
index eab297bd02f..b6e270c9e15 100644
--- a/components/camel-google-calendar/src/main/java/org/apache/camel/component/google/calendar/stream/GoogleCalendarStreamEndpoint.java
+++ b/components/camel-google-calendar/src/main/java/org/apache/camel/component/google/calendar/stream/GoogleCalendarStreamEndpoint.java
@@ -16,12 +16,8 @@
  */
 package org.apache.camel.component.google.calendar.stream;
 
-import java.io.UnsupportedEncodingException;
-
 import com.google.api.services.calendar.Calendar;
-import com.google.api.services.calendar.model.CalendarListEntry;
 import com.google.api.services.calendar.model.Event;
-
 import org.apache.camel.Consumer;
 import org.apache.camel.Exchange;
 import org.apache.camel.ExchangePattern;
@@ -32,22 +28,21 @@
 import org.apache.camel.impl.ScheduledPollEndpoint;
 import org.apache.camel.spi.UriEndpoint;
 import org.apache.camel.spi.UriParam;
-import org.apache.camel.util.ObjectHelper;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
 /**
- * The google-calendar component provides access to Google Calendar in a streaming mod.
+ * The google-calendar component provides access to Google Calendar in a streaming mode.
  */
-@UriEndpoint(firstVersion = "2.23.0", 
-             scheme = "google-calendar-stream", 
-             title = "Google Calendar Stream", 
-             syntax = "google-calendar-stream:index", 
+@UriEndpoint(firstVersion = "2.23.0",
+             scheme = "google-calendar-stream",
+             title = "Google Calendar Stream",
+             syntax = "google-calendar-stream:index",
              consumerClass = GoogleCalendarStreamConsumer.class,
              consumerOnly = true,
              label = "api,cloud")
 public class GoogleCalendarStreamEndpoint extends ScheduledPollEndpoint {
-    
+
     private static final Logger LOG = LoggerFactory.getLogger(GoogleCalendarStreamEndpoint.class);
 
     @UriParam
@@ -91,11 +86,11 @@ public boolean isSingleton() {
         return true;
     }
 
-    public Exchange createExchange(ExchangePattern pattern, Event event) throws UnsupportedEncodingException {
-
-        Exchange exchange = super.createExchange();
+    public Exchange createExchange(ExchangePattern pattern, Event event) {
+        Exchange exchange = super.createExchange(pattern);
         Message message = exchange.getIn();
         message.setBody(event);
+        message.setHeader(GoogleCalendarStreamConstants.EVENT_ID, event.getId());
         return exchange;
     }
 }
diff --git a/components/camel-google-calendar/src/test/java/org/apache/camel/component/google/calendar/stream/AbstractGoogleCalendarStreamTestSupport.java b/components/camel-google-calendar/src/test/java/org/apache/camel/component/google/calendar/stream/AbstractGoogleCalendarStreamTestSupport.java
index 6cf4a25af42..56e24fbf2af 100644
--- a/components/camel-google-calendar/src/test/java/org/apache/camel/component/google/calendar/stream/AbstractGoogleCalendarStreamTestSupport.java
+++ b/components/camel-google-calendar/src/test/java/org/apache/camel/component/google/calendar/stream/AbstractGoogleCalendarStreamTestSupport.java
@@ -26,7 +26,7 @@
 import org.apache.camel.util.IntrospectionSupport;
 
 /**
- * Abstract base class for GoogleMail Integration tests generated by Camel API
+ * Abstract base class for GoogleCalendar Integration tests generated by Camel API
  * component maven plugin.
  */
 public class AbstractGoogleCalendarStreamTestSupport extends CamelTestSupport {
@@ -40,7 +40,7 @@ protected CamelContext createCamelContext() throws Exception {
 
         final CamelContext context = super.createCamelContext();
 
-        // read GoogleMail component configuration from TEST_OPTIONS_PROPERTIES
+        // read GoogleCalendar component configuration from TEST_OPTIONS_PROPERTIES
         final Properties properties = new Properties();
         try {
             properties.load(getClass().getResourceAsStream(TEST_OPTIONS_PROPERTIES));
@@ -56,7 +56,7 @@ protected CamelContext createCamelContext() throws Exception {
         final GoogleCalendarStreamConfiguration configuration = new GoogleCalendarStreamConfiguration();
         IntrospectionSupport.setProperties(configuration, options);
 
-        // add GoogleMailComponent to Camel context
+        // add GoogleCalendarComponent to Camel context
         final GoogleCalendarStreamComponent component = new GoogleCalendarStreamComponent(context);
         component.setConfiguration(configuration);
         context.addComponent("google-calendar-stream", component);
diff --git a/components/camel-google-drive/pom.xml b/components/camel-google-drive/pom.xml
index e0e9e5e993c..b101766fb90 100644
--- a/components/camel-google-drive/pom.xml
+++ b/components/camel-google-drive/pom.xml
@@ -24,7 +24,7 @@
   <parent>
     <groupId>org.apache.camel</groupId>
     <artifactId>components</artifactId>
-    <version>2.23.0-SNAPSHOT</version>
+    <version>2.24.0-SNAPSHOT</version>
   </parent>
 
   <artifactId>camel-google-drive</artifactId>
diff --git a/components/camel-google-drive/src/main/java/org/apache/camel/component/google/drive/internal/GoogleDriveConstants.java b/components/camel-google-drive/src/main/java/org/apache/camel/component/google/drive/internal/GoogleDriveConstants.java
index 9f824f539c3..d19ba20c9ab 100644
--- a/components/camel-google-drive/src/main/java/org/apache/camel/component/google/drive/internal/GoogleDriveConstants.java
+++ b/components/camel-google-drive/src/main/java/org/apache/camel/component/google/drive/internal/GoogleDriveConstants.java
@@ -19,11 +19,18 @@
 /**
  * Constants for GoogleDrive component.
  */
-public interface GoogleDriveConstants {
+public final class GoogleDriveConstants {
 
     // suffix for parameters when passed as exchange header properties
-    String PROPERTY_PREFIX = "CamelGoogleDrive.";
+    public static final String PROPERTY_PREFIX = "CamelGoogleDrive.";
 
     // thread profile name for this component
-    String THREAD_PROFILE_NAME = "CamelGoogleDrive";
+    public static final String THREAD_PROFILE_NAME = "CamelGoogleDrive";
+
+    /**
+     * Prevent instantiation.
+     */
+    private GoogleDriveConstants() {
+        super();
+    }
 }
diff --git a/components/camel-google-mail/pom.xml b/components/camel-google-mail/pom.xml
index 6e93a981deb..e513a2daff2 100644
--- a/components/camel-google-mail/pom.xml
+++ b/components/camel-google-mail/pom.xml
@@ -24,7 +24,7 @@
   <parent>
     <groupId>org.apache.camel</groupId>
     <artifactId>components</artifactId>
-    <version>2.23.0-SNAPSHOT</version>
+    <version>2.24.0-SNAPSHOT</version>
   </parent>
 
   <artifactId>camel-google-mail</artifactId>
diff --git a/components/camel-google-mail/src/main/docs/google-mail-stream-component.adoc b/components/camel-google-mail/src/main/docs/google-mail-stream-component.adoc
index ed2086bc1eb..ae40384e74c 100644
--- a/components/camel-google-mail/src/main/docs/google-mail-stream-component.adoc
+++ b/components/camel-google-mail/src/main/docs/google-mail-stream-component.adoc
@@ -27,7 +27,7 @@ for this component:
             <artifactId>camel-google-mail</artifactId>
             <version>2.22-SNAPSHOT</version>
     </dependency>
-        
+
 ------------------------------------------------------
 
 ### URI Format
@@ -36,7 +36,7 @@ The GoogleMail Component uses the following URI format:
 
 --------------------------------------------------------
         google-mail-stream://index?[options]
-    
+
 --------------------------------------------------------
 
 ### GoogleMailStreamComponent
@@ -78,7 +78,7 @@ with the following path and query parameters:
 |===
 
 
-==== Query Parameters (29 parameters):
+==== Query Parameters (28 parameters):
 
 
 [width="100%",cols="2,5,^1,2",options="header"]
@@ -94,7 +94,6 @@ with the following path and query parameters:
 | *maxResults* (consumer) | Max results to be returned | 10 | long
 | *query* (consumer) | The query to execute on gmail box | is:unread | String
 | *refreshToken* (consumer) | OAuth 2 refresh token. Using this, the Google Calendar component can obtain a new accessToken whenever the current one expires - a necessity if the application is long-lived. |  | String
-| *scopes* (consumer) | Specifies the level of permissions you want a mail application to have to a user account. See https://developers.google.com/gmail/api/auth/scopes for more info. |  | List
 | *sendEmptyMessageWhenIdle* (consumer) | If the polling consumer did not poll any files, you can enable this option to send an empty message (no body) instead. | false | boolean
 | *exceptionHandler* (consumer) | To let the consumer use a custom ExceptionHandler. Notice if the option bridgeErrorHandler is enabled then this option is not in use. By default the consumer will deal with exceptions, that will be logged at WARN or ERROR level and ignored. |  | ExceptionHandler
 | *exchangePattern* (consumer) | Sets the exchange pattern when the consumer creates an exchange. |  | ExchangePattern
@@ -119,7 +118,7 @@ with the following path and query parameters:
 === Spring Boot Auto-Configuration
 
 
-The component supports 14 options, which are listed below.
+The component supports 13 options, which are listed below.
 
 
 
@@ -137,7 +136,6 @@ The component supports 14 options, which are listed below.
 | *camel.component.google-mail-stream.configuration.max-results* | Max results to be returned | 10 | Long
 | *camel.component.google-mail-stream.configuration.query* | The query to execute on gmail box | is:unread | String
 | *camel.component.google-mail-stream.configuration.refresh-token* | OAuth 2 refresh token. Using this, the Google Calendar component can obtain a new accessToken whenever the current one expires - a necessity if the application is long-lived. |  | String
-| *camel.component.google-mail-stream.configuration.scopes* | Specifies the level of permissions you want a mail application to have to a user account. See https://developers.google.com/gmail/api/auth/scopes for more info. |  | List
 | *camel.component.google-mail-stream.enabled* | Whether to enable auto configuration of the google-mail-stream component. This is enabled by default. |  | Boolean
 | *camel.component.google-mail-stream.resolve-property-placeholders* | Whether the component should resolve property placeholders on itself when starting. Only properties which are of String type can use property placeholders. | true | Boolean
 |===
diff --git a/components/camel-google-mail/src/main/java/org/apache/camel/component/google/mail/internal/GoogleMailConstants.java b/components/camel-google-mail/src/main/java/org/apache/camel/component/google/mail/internal/GoogleMailConstants.java
index f788ff3c6e0..a8345495893 100644
--- a/components/camel-google-mail/src/main/java/org/apache/camel/component/google/mail/internal/GoogleMailConstants.java
+++ b/components/camel-google-mail/src/main/java/org/apache/camel/component/google/mail/internal/GoogleMailConstants.java
@@ -19,11 +19,18 @@
 /**
  * Constants for GoogleMail component.
  */
-public interface GoogleMailConstants {
+public final class GoogleMailConstants {
 
     // suffix for parameters when passed as exchange header properties
-    String PROPERTY_PREFIX = "CamelGoogleMail.";
+    public static final String PROPERTY_PREFIX = "CamelGoogleMail.";
 
     // thread profile name for this component
-    String THREAD_PROFILE_NAME = "CamelGoogleMail";
+    public static final String THREAD_PROFILE_NAME = "CamelGoogleMail";
+
+    /**
+     * Prevent instantiation.
+     */
+    private GoogleMailConstants() {
+        super();
+    }
 }
diff --git a/components/camel-google-mail/src/main/java/org/apache/camel/component/google/mail/stream/GoogleMailStreamConfiguration.java b/components/camel-google-mail/src/main/java/org/apache/camel/component/google/mail/stream/GoogleMailStreamConfiguration.java
index a69f719d19f..d8164782c32 100644
--- a/components/camel-google-mail/src/main/java/org/apache/camel/component/google/mail/stream/GoogleMailStreamConfiguration.java
+++ b/components/camel-google-mail/src/main/java/org/apache/camel/component/google/mail/stream/GoogleMailStreamConfiguration.java
@@ -16,11 +16,6 @@
  */
 package org.apache.camel.component.google.mail.stream;
 
-import java.util.Arrays;
-import java.util.List;
-
-import com.google.api.services.gmail.GmailScopes;
-
 import org.apache.camel.RuntimeCamelException;
 import org.apache.camel.spi.UriParam;
 import org.apache.camel.spi.UriParams;
@@ -31,14 +26,9 @@
  */
 @UriParams
 public class GoogleMailStreamConfiguration implements Cloneable {
-    private static final List<String> DEFAULT_SCOPES = Arrays.asList(GmailScopes.GMAIL_COMPOSE, GmailScopes.GMAIL_MODIFY, GmailScopes.MAIL_GOOGLE_COM);
-
     @UriPath
     private String index;
 
-    @UriParam
-    private List<String> scopes = DEFAULT_SCOPES;
-
     @UriParam
     private String clientId;
 
@@ -124,19 +114,6 @@ public void setApplicationName(String applicationName) {
         this.applicationName = applicationName;
     }
 
-    public List<String> getScopes() {
-        return scopes;
-    }
-
-    /**
-     * Specifies the level of permissions you want a mail application to have to
-     * a user account. See https://developers.google.com/gmail/api/auth/scopes
-     * for more info.
-     */
-    public void setScopes(List<String> scopes) {
-        this.scopes = scopes;
-    }
-
     public String getIndex() {
         return index;
     }
diff --git a/components/camel-google-mail/src/main/java/org/apache/camel/component/google/mail/stream/GoogleMailStreamConstants.java b/components/camel-google-mail/src/main/java/org/apache/camel/component/google/mail/stream/GoogleMailStreamConstants.java
index ccd2c0fb6f1..e8ca7c2d224 100644
--- a/components/camel-google-mail/src/main/java/org/apache/camel/component/google/mail/stream/GoogleMailStreamConstants.java
+++ b/components/camel-google-mail/src/main/java/org/apache/camel/component/google/mail/stream/GoogleMailStreamConstants.java
@@ -19,12 +19,19 @@
 /**
  * Constants used in Camel Google Mail Stream
  */
-public interface GoogleMailStreamConstants {
+public final class GoogleMailStreamConstants {
 
-    String MAIL_TO = "CamelGoogleMailStreamTo";
-    String MAIL_FROM = "CamelGoogleMailStreamFrom";
-    String MAIL_CC = "CamelGoogleMailStreamCc";
-    String MAIL_BCC = "CamelGoogleMailStreamBcc";
-    String MAIL_SUBJECT = "CamelGoogleMailStreamSubject";
-    String MAIL_ID = "CamelGoogleMailId";
+    public static final String MAIL_TO = "CamelGoogleMailStreamTo";
+    public static final String MAIL_FROM = "CamelGoogleMailStreamFrom";
+    public static final String MAIL_CC = "CamelGoogleMailStreamCc";
+    public static final String MAIL_BCC = "CamelGoogleMailStreamBcc";
+    public static final String MAIL_SUBJECT = "CamelGoogleMailStreamSubject";
+    public static final String MAIL_ID = "CamelGoogleMailId";
+
+    /**
+     * Prevent instantiation.
+     */
+    private GoogleMailStreamConstants() {
+        super();
+    }
 }
diff --git a/components/camel-google-mail/src/main/java/org/apache/camel/component/google/mail/stream/GoogleMailStreamEndpoint.java b/components/camel-google-mail/src/main/java/org/apache/camel/component/google/mail/stream/GoogleMailStreamEndpoint.java
index 4f49ebaedd1..34428dd9b61 100644
--- a/components/camel-google-mail/src/main/java/org/apache/camel/component/google/mail/stream/GoogleMailStreamEndpoint.java
+++ b/components/camel-google-mail/src/main/java/org/apache/camel/component/google/mail/stream/GoogleMailStreamEndpoint.java
@@ -16,13 +16,10 @@
  */
 package org.apache.camel.component.google.mail.stream;
 
-import java.io.UnsupportedEncodingException;
 import java.nio.charset.StandardCharsets;
 import java.util.ArrayList;
 import java.util.List;
 
-import javax.mail.internet.AddressException;
-
 import com.google.api.client.util.Base64;
 import com.google.api.services.gmail.Gmail;
 import com.google.api.services.gmail.model.Label;
@@ -30,7 +27,6 @@
 import com.google.api.services.gmail.model.MessagePart;
 import com.google.api.services.gmail.model.MessagePartHeader;
 import com.google.common.base.Splitter;
-
 import org.apache.camel.Consumer;
 import org.apache.camel.Exchange;
 import org.apache.camel.ExchangePattern;
@@ -46,10 +42,10 @@
 /**
  * The google-mail component provides access to Google Mail.
  */
-@UriEndpoint(firstVersion = "2.22.0", 
-             scheme = "google-mail-stream", 
-             title = "Google Mail Stream", 
-             syntax = "google-mail-stream:index", 
+@UriEndpoint(firstVersion = "2.22.0",
+             scheme = "google-mail-stream",
+             title = "Google Mail Stream",
+             syntax = "google-mail-stream:index",
              consumerClass = GoogleMailStreamConsumer.class,
              consumerOnly = true,
              label = "api,cloud,mail")
@@ -116,14 +112,14 @@ public boolean isSingleton() {
         return true;
     }
 
-    public Exchange createExchange(ExchangePattern pattern, com.google.api.services.gmail.model.Message mail) throws UnsupportedEncodingException {
+    public Exchange createExchange(ExchangePattern pattern, com.google.api.services.gmail.model.Message mail) {
 
-        Exchange exchange = super.createExchange();
+        Exchange exchange = super.createExchange(pattern);
         Message message = exchange.getIn();
         exchange.getIn().setHeader(GoogleMailStreamConstants.MAIL_ID, mail.getId());
         List<MessagePart> parts = mail.getPayload().getParts();
         if (parts != null && parts.get(0).getBody().getData() != null) {
-            byte[] bodyBytes = Base64.decodeBase64(parts.get(0).getBody().getData().trim().toString()); 
+            byte[] bodyBytes = Base64.decodeBase64(parts.get(0).getBody().getData().trim());
             String body = new String(bodyBytes, StandardCharsets.UTF_8);
             message.setBody(body);
         }
@@ -151,8 +147,8 @@ private void setHeaders(Message message, List<MessagePartHeader> headers) {
             }
         }
     }
-    
-    private List<String> splitLabels(String labels) throws AddressException {
+
+    private List<String> splitLabels(String labels) {
         return Splitter.on(',').splitToList(labels);
     }
 }
diff --git a/components/camel-google-pubsub/pom.xml b/components/camel-google-pubsub/pom.xml
index 369b1cbb667..48cd3713de4 100644
--- a/components/camel-google-pubsub/pom.xml
+++ b/components/camel-google-pubsub/pom.xml
@@ -25,7 +25,7 @@
     <parent>
         <groupId>org.apache.camel</groupId>
         <artifactId>components</artifactId>
-        <version>2.23.0-SNAPSHOT</version>
+        <version>2.24.0-SNAPSHOT</version>
     </parent>
 
     <artifactId>camel-google-pubsub</artifactId>
diff --git a/components/camel-google-sheets/pom.xml b/components/camel-google-sheets/pom.xml
new file mode 100644
index 00000000000..01d6bfe19ab
--- /dev/null
+++ b/components/camel-google-sheets/pom.xml
@@ -0,0 +1,289 @@
+<?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>components</artifactId>
+    <version>2.24.0-SNAPSHOT</version>
+  </parent>
+
+  <artifactId>camel-google-sheets</artifactId>
+  <packaging>jar</packaging>
+  <name>Camel :: GoogleSheets</name>
+  <description>Camel Component for GoogleSheets</description>
+
+  <properties>
+    <schemeName>google-sheets</schemeName>
+    <componentName>GoogleSheets</componentName>
+    <componentPackage>org.apache.camel.component.google.sheets</componentPackage>
+    <outPackage>org.apache.camel.component.google.sheets.internal</outPackage>
+    <camel.osgi.private.pkg>org.apache.camel.component.google.sheets.internal</camel.osgi.private.pkg>
+    <camel.osgi.export.pkg>org.apache.camel.component.google.sheets</camel.osgi.export.pkg>
+    <camel.osgi.export.service>org.apache.camel.spi.ComponentResolver;component=google-sheets</camel.osgi.export.service>
+  </properties>
+
+  <dependencies>
+    <dependency>
+      <groupId>org.apache.camel</groupId>
+      <artifactId>camel-core</artifactId>
+    </dependency>
+    <dependency>
+        <groupId>com.google.api-client</groupId>
+        <artifactId>google-api-client</artifactId>
+        <version>${google-api-client-version}</version>
+    </dependency>
+    <dependency>
+        <groupId>com.google.oauth-client</groupId>
+        <artifactId>google-oauth-client</artifactId>
+        <version>${google-api-client-version}</version>
+    </dependency>
+    <dependency>
+        <groupId>com.google.http-client</groupId>
+        <artifactId>google-http-client-jackson2</artifactId>
+        <version>${google-api-client-version}</version>
+    </dependency>
+    <dependency>
+        <groupId>com.google.apis</groupId>
+        <artifactId>google-api-services-sheets</artifactId>
+        <version>${google-api-services-sheets-version}</version>
+    </dependency>
+
+    <!-- Camel annotations in provided scope to avoid compile errors in IDEs -->
+    <dependency>
+      <groupId>org.apache.camel</groupId>
+      <artifactId>spi-annotations</artifactId>
+      <version>${project.version}</version>
+      <scope>provided</scope>
+    </dependency>
+
+    <!-- Component API javadoc in provided scope to read API signatures -->
+    <dependency>
+        <groupId>com.google.apis</groupId>
+        <artifactId>google-api-services-sheets</artifactId>
+        <version>${google-api-services-sheets-version}</version>
+      <type>javadoc</type>
+      <scope>provided</scope>
+    </dependency>
+
+    <!-- logging -->
+    <dependency>
+      <groupId>org.apache.logging.log4j</groupId>
+      <artifactId>log4j-api</artifactId>
+      <scope>test</scope>
+    </dependency>
+    <dependency>
+      <groupId>org.apache.logging.log4j</groupId>
+      <artifactId>log4j-core</artifactId>
+      <scope>test</scope>
+    </dependency>
+    <dependency>
+      <groupId>org.apache.logging.log4j</groupId>
+      <artifactId>log4j-slf4j-impl</artifactId>
+      <scope>test</scope>
+    </dependency>
+
+    <!-- testing -->
+    <dependency>
+      <groupId>org.apache.camel</groupId>
+      <artifactId>camel-test</artifactId>
+      <scope>test</scope>
+    </dependency>
+  </dependencies>
+
+  <build>
+    <defaultGoal>install</defaultGoal>
+
+    <plugins>
+
+      <!-- generate Component source and test source -->
+      <plugin>
+        <groupId>org.apache.camel</groupId>
+        <artifactId>camel-api-component-maven-plugin</artifactId>
+        <executions>
+          <execution>
+            <id>generate-test-component-classes</id>
+            <goals>
+              <goal>fromApis</goal>
+            </goals>
+            <configuration>
+              <apis>
+                <api>
+                  <apiName>spreadsheets</apiName>
+                  <proxyClass>com.google.api.services.sheets.v4.Sheets$Spreadsheets</proxyClass>
+                  <fromJavadoc />
+                </api>
+                <api>
+                  <apiName>data</apiName>
+                  <proxyClass>com.google.api.services.sheets.v4.Sheets$Spreadsheets$Values</proxyClass>
+                  <fromJavadoc />
+                </api>
+              </apis>
+              <substitutions>
+                <substitution>
+                  <method>^.+$</method>
+                  <argName>content</argName>
+                  <argType>com.google.api.services.sheets.v4.model.ValueRange</argType>
+                  <replacement>values</replacement>
+                </substitution>
+                <substitution>
+                  <method>^.+$</method>
+                  <argName>content</argName>
+                  <argType>com.google.api.services.sheets.v4.model.BatchUpdateSpreadsheetRequest</argType>
+                  <replacement>batchUpdateSpreadsheetRequest</replacement>
+                </substitution>
+                <substitution>
+                  <method>^.+$</method>
+                  <argName>content</argName>
+                  <argType>com.google.api.services.sheets.v4.model.GetSpreadsheetByDataFilterRequest</argType>
+                  <replacement>getSpreadsheetByDataFilterRequest</replacement>
+                </substitution>
+                <substitution>
+                  <method>^.+$</method>
+                  <argName>content</argName>
+                  <argType>com.google.api.services.sheets.v4.model.ClearValuesRequest</argType>
+                  <replacement>clearValuesRequest</replacement>
+                </substitution>
+                <substitution>
+                  <method>^.+$</method>
+                  <argName>content</argName>
+                  <argType>com.google.api.services.sheets.v4.model.BatchClearValuesRequest</argType>
+                  <replacement>batchClearValuesRequest</replacement>
+                </substitution>
+                <substitution>
+                  <method>^.+$</method>
+                  <argName>content</argName>
+                  <argType>com.google.api.services.sheets.v4.model.BatchUpdateValuesByDataFilterRequest</argType>
+                  <replacement>batchUpdateValuesByDataFilterRequest</replacement>
+                </substitution>
+                <substitution>
+                  <method>^.+$</method>
+                  <argName>content</argName>
+                  <argType>com.google.api.services.sheets.v4.model.BatchGetValuesByDataFilterRequest</argType>
+                  <replacement>batchGetValuesByDataFilterRequest</replacement>
+                </substitution>
+                <substitution>
+                  <method>^.+$</method>
+                  <argName>content</argName>
+                  <argType>com.google.api.services.sheets.v4.model.BatchUpdateValuesRequest</argType>
+                  <replacement>batchUpdateValuesRequest</replacement>
+                </substitution>
+              </substitutions>
+            </configuration>
+          </execution>
+        </executions>
+      </plugin>
+
+      <!-- add generated source and test source to build -->
+      <plugin>
+        <groupId>org.codehaus.mojo</groupId>
+        <artifactId>build-helper-maven-plugin</artifactId>
+        <version>1.8</version>
+        <executions>
+          <execution>
+            <id>add-generated-sources</id>
+            <goals>
+              <goal>add-source</goal>
+            </goals>
+            <configuration>
+              <sources>
+                <source>${project.build.directory}/generated-sources/camel-component</source>
+              </sources>
+            </configuration>
+          </execution>
+          <execution>
+            <id>add-generated-test-sources</id>
+            <goals>
+              <goal>add-test-source</goal>
+            </goals>
+            <configuration>
+              <sources>
+                <source>${project.build.directory}/generated-test-sources/camel-component</source>
+              </sources>
+            </configuration>
+          </execution>
+        </executions>
+      </plugin>
+
+    </plugins>
+
+    <pluginManagement>
+      <plugins>
+        <plugin>
+          <groupId>org.apache.camel</groupId>
+          <artifactId>camel-api-component-maven-plugin</artifactId>
+          <version>${project.version}</version>
+          <configuration>
+            <scheme>${schemeName}</scheme>
+            <componentName>${componentName}</componentName>
+            <componentPackage>${componentPackage}</componentPackage>
+            <outPackage>${outPackage}</outPackage>
+          </configuration>
+        </plugin>
+      </plugins>
+    </pluginManagement>
+
+  </build>
+
+  <reporting>
+    <plugins>
+      <plugin>
+        <groupId>org.apache.camel</groupId>
+        <artifactId>camel-api-component-maven-plugin</artifactId>
+        <version>${project.version}</version>
+        <configuration>
+          <scheme>${schemeName}</scheme>
+          <componentName>${componentName}</componentName>
+          <componentPackage>${componentPackage}</componentPackage>
+          <outPackage>${outPackage}</outPackage>
+        </configuration>
+      </plugin>
+    </plugins>
+  </reporting>
+
+  <profiles>
+    <profile>
+      <id>google-sheets-test</id>
+      <build>
+        <plugins>
+          <plugin>
+            <artifactId>maven-surefire-plugin</artifactId>
+            <configuration>
+              <childDelegation>false</childDelegation>
+              <useFile>true</useFile>
+              <forkCount>1</forkCount>
+              <reuseForks>true</reuseForks>
+              <forkedProcessTimeoutInSeconds>300</forkedProcessTimeoutInSeconds>
+              <excludes>
+                <exclude>**/*XXXTest.java</exclude>
+              </excludes>
+              <includes>
+                <include>**/*Test.java</include>
+              </includes>
+            </configuration>
+          </plugin>
+        </plugins>
+      </build>
+    </profile>
+  </profiles>
+
+</project>
diff --git a/components/camel-google-sheets/src/main/docs/google-sheets-component.adoc b/components/camel-google-sheets/src/main/docs/google-sheets-component.adoc
new file mode 100644
index 00000000000..0cba9c99b51
--- /dev/null
+++ b/components/camel-google-sheets/src/main/docs/google-sheets-component.adoc
@@ -0,0 +1,180 @@
+[[google-sheets-component]]
+== Google Sheets Component
+
+*Available as of Camel version 2.23*
+
+The Google Sheets component provides access
+to http://google.com/sheets[Google Sheets] via
+the https://developers.google.com/sheets/api/reference/rest/[Google
+Sheets Web APIs].
+
+Google Sheets uses
+the https://developers.google.com/accounts/docs/OAuth2[OAuth 2.0
+protocol] for authenticating a Google account and authorizing access to
+user data. Before you can use this component, you will need
+to https://developers.google.com/google-apps/sheets/auth[create an
+account and generate OAuth credentials]. Credentials comprise of a
+clientId, clientSecret, and a refreshToken. A handy resource for
+generating a long-lived refreshToken is
+the https://developers.google.com/oauthplayground[OAuth playground].
+
+Maven users will need to add the following dependency to their pom.xml
+for this component:
+
+----------------------------------------------------------
+    <dependency>
+            <groupId>org.apache.camel</groupId>
+            <artifactId>camel-google-sheets</artifactId>
+            <version>2.23.0</version>
+    </dependency>
+
+----------------------------------------------------------
+
+### URI Format
+
+The GoogleSheets Component uses the following URI format:
+
+------------------------------------------------------------
+        google-sheets://endpoint-prefix/endpoint?[options]
+
+------------------------------------------------------------
+
+Endpoint prefix can be one of:
+
+* spreadsheets
+* data
+
+### GoogleSheetsComponent
+
+
+
+
+
+// component options: START
+The Google Sheets component supports 3 options, which are listed below.
+
+
+
+[width="100%",cols="2,5,^1,2",options="header"]
+|===
+| Name | Description | Default | Type
+| *configuration* (common) | To use the shared configuration |  | GoogleSheets Configuration
+| *clientFactory* (advanced) | To use the GoogleSheetsClientFactory as factory for creating the client. Will by default use BatchGoogleSheetsClientFactory |  | GoogleSheetsClient Factory
+| *resolveProperty Placeholders* (advanced) | Whether the component should resolve property placeholders on itself when starting. Only properties which are of String type can use property placeholders. | true | boolean
+|===
+// component options: END
+
+
+
+
+
+
+
+// endpoint options: START
+The Google Sheets endpoint is configured using URI syntax:
+
+----
+google-sheets:apiName/methodName
+----
+
+with the following path and query parameters:
+
+==== Path Parameters (2 parameters):
+
+
+[width="100%",cols="2,5,^1,2",options="header"]
+|===
+| Name | Description | Default | Type
+| *apiName* | *Required* What kind of operation to perform |  | GoogleSheetsApiName
+| *methodName* | *Required* What sub operation to use for the selected operation |  | String
+|===
+
+
+==== Query Parameters (10 parameters):
+
+
+[width="100%",cols="2,5,^1,2",options="header"]
+|===
+| Name | Description | Default | Type
+| *accessToken* (common) | OAuth 2 access token. This typically expires after an hour so refreshToken is recommended for long term usage. |  | String
+| *applicationName* (common) | Google Sheets application name. Example would be camel-google-sheets/1.0 |  | String
+| *clientId* (common) | Client ID of the sheets application |  | String
+| *clientSecret* (common) | Client secret of the sheets application |  | String
+| *inBody* (common) | Sets the name of a parameter to be passed in the exchange In Body |  | String
+| *refreshToken* (common) | OAuth 2 refresh token. Using this, the Google Sheets component can obtain a new accessToken whenever the current one expires - a necessity if the application is long-lived. |  | String
+| *bridgeErrorHandler* (consumer) | Allows for bridging the consumer to the Camel routing Error Handler, which mean any exceptions occurred while the consumer is trying to pickup incoming messages, or the likes, will now be processed as a message and handled by the routing Error Handler. By default the consumer will use the org.apache.camel.spi.ExceptionHandler to deal with exceptions, that will be logged at WARN or ERROR level and ignored. | false | boolean
+| *exceptionHandler* (consumer) | To let the consumer use a custom ExceptionHandler. Notice if the option bridgeErrorHandler is enabled then this option is not in use. By default the consumer will deal with exceptions, that will be logged at WARN or ERROR level and ignored. |  | ExceptionHandler
+| *exchangePattern* (consumer) | Sets the exchange pattern when the consumer creates an exchange. |  | ExchangePattern
+| *synchronous* (advanced) | Sets whether synchronous processing should be strictly used, or Camel is allowed to use asynchronous processing (if supported). | false | boolean
+|===
+// endpoint options: END
+// spring-boot-auto-configure options: START
+=== Spring Boot Auto-Configuration
+
+
+The component supports 10 options, which are listed below.
+
+
+
+[width="100%",cols="2,5,^1,2",options="header"]
+|===
+| Name | Description | Default | Type
+| *camel.component.google-sheets.client-factory* | To use the GoogleSheetsClientFactory as factory for creating the client. Will by default use BatchGoogleSheetsClientFactory. The option is a org.apache.camel.component.google.sheets.GoogleSheetsClientFactory type. |  | String
+| *camel.component.google-sheets.configuration.access-token* | OAuth 2 access token. This typically expires after an hour so refreshToken is recommended for long term usage. |  | String
+| *camel.component.google-sheets.configuration.api-name* | What kind of operation to perform |  | GoogleSheetsApiName
+| *camel.component.google-sheets.configuration.application-name* | Google Sheets application name. Example would be camel-google-sheets/1.0 |  | String
+| *camel.component.google-sheets.configuration.client-id* | Client ID of the sheets application |  | String
+| *camel.component.google-sheets.configuration.client-secret* | Client secret of the sheets application |  | String
+| *camel.component.google-sheets.configuration.method-name* | What sub operation to use for the selected operation |  | String
+| *camel.component.google-sheets.configuration.refresh-token* | OAuth 2 refresh token. Using this, the Google Sheets component can obtain a new accessToken whenever the current one expires - a necessity if the application is long-lived. |  | String
+| *camel.component.google-sheets.enabled* | Whether to enable auto configuration of the google-sheets component. This is enabled by default. |  | Boolean
+| *camel.component.google-sheets.resolve-property-placeholders* | Whether the component should resolve property placeholders on itself when starting. Only properties which are of String type can use property placeholders. | true | Boolean
+|===
+// spring-boot-auto-configure options: END
+
+
+
+
+### Producer Endpoints
+
+Producer endpoints can use endpoint prefixes followed by endpoint names
+and associated options described next. A shorthand alias can be used for
+some endpoints. The endpoint URI MUST contain a prefix.
+
+Endpoint options that are not mandatory are denoted by []. When there
+are no mandatory options for an endpoint, one of the set of [] options
+MUST be provided. Producer endpoints can also use a special option
+*`inBody`* that in turn should contain the name of the endpoint option
+whose value will be contained in the Camel Exchange In message.
+
+Any of the endpoint options can be provided in either the endpoint URI,
+or dynamically in a message header. The message header name must be of
+the format `CamelGoogleSheets.<option>`. Note that the `inBody` option
+overrides message header, i.e. the endpoint option `inBody=option` would
+override a `CamelGoogleSheets.option` header.
+
+For more information on the endpoints and options see API documentation
+at: https://developers.google.com/sheets/api/reference/rest/[https://developers.google.com/sheets/api/reference/rest/]
+
+### Consumer Endpoints
+
+Any of the producer endpoints can be used as a consumer endpoint.
+Consumer endpoints can use
+http://camel.apache.org/polling-consumer.html#PollingConsumer-ScheduledPollConsumerOptions[Scheduled
+Poll Consumer Options] with a `consumer.` prefix to schedule endpoint
+invocation. Consumer endpoints that return an array or collection will
+generate one exchange per element, and their routes will be executed
+once for each exchange.
+
+### Message Headers
+
+Any URI option can be provided in a message header for producer
+endpoints with a `CamelGoogleSheets.` prefix.
+
+### Message Body
+
+All result message bodies utilize objects provided by the underlying
+APIs used by the GoogleSheetsComponent. Producer endpoints can specify
+the option name for incoming message body in the `inBody` endpoint URI
+parameter. For endpoints that return an array or collection, a consumer
+endpoint will map every element to distinct messages.     
diff --git a/components/camel-google-sheets/src/main/docs/google-sheets-stream-component.adoc b/components/camel-google-sheets/src/main/docs/google-sheets-stream-component.adoc
new file mode 100644
index 00000000000..ac98fdc0006
--- /dev/null
+++ b/components/camel-google-sheets/src/main/docs/google-sheets-stream-component.adoc
@@ -0,0 +1,166 @@
+[[google-sheets-stream-component]]
+== Google Sheets Stream Component
+
+*Available as of Camel version 2.23*
+
+The Google Sheets component provides access
+to https://sheets.google.com/[Sheets] via
+the https://developers.google.com/sheets/api/reference/rest/[Google Sheets
+Web APIs].
+
+Google Sheets uses
+the https://developers.google.com/accounts/docs/OAuth2[OAuth 2.0
+protocol] for authenticating a Google account and authorizing access to
+user data. Before you can use this component, you will need
+to https://developers.google.com/google-apps/sheets/auth[create an
+account and generate OAuth credentials]. Credentials comprise of a
+clientId, clientSecret, and a refreshToken. A handy resource for
+generating a long-lived refreshToken is
+the https://developers.google.com/oauthplayground[OAuth playground].
+
+Maven users will need to add the following dependency to their pom.xml
+for this component:
+
+------------------------------------------------------
+    <dependency>
+            <groupId>org.apache.camel</groupId>
+            <artifactId>camel-google-sheets</artifactId>
+            <version>2.23.0</version>
+    </dependency>
+
+------------------------------------------------------
+
+### URI Format
+
+The Google Sheets Component uses the following URI format:
+
+--------------------------------------------------------
+        google-sheets-stream://apiName?[options]
+
+--------------------------------------------------------
+
+### GoogleSheetsStreamComponent
+
+
+// component options: START
+The Google Sheets Stream component supports 3 options, which are listed below.
+
+
+
+[width="100%",cols="2,5,^1,2",options="header"]
+|===
+| Name | Description | Default | Type
+| *configuration* (consumer) | To use the shared configuration |  | GoogleSheetsStream Configuration
+| *clientFactory* (advanced) | To use the GoogleSheetsClientFactory as factory for creating the client. Will by default use BatchGoogleSheetsClientFactory |  | GoogleSheetsClient Factory
+| *resolveProperty Placeholders* (advanced) | Whether the component should resolve property placeholders on itself when starting. Only properties which are of String type can use property placeholders. | true | boolean
+|===
+// component options: END
+
+
+
+
+// endpoint options: START
+The Google Sheets Stream endpoint is configured using URI syntax:
+
+----
+google-sheets-stream:apiName
+----
+
+with the following path and query parameters:
+
+==== Path Parameters (1 parameters):
+
+
+[width="100%",cols="2,5,^1,2",options="header"]
+|===
+| Name | Description | Default | Type
+| *apiName* | Sets the apiName. |  | String
+|===
+
+
+==== Query Parameters (32 parameters):
+
+
+[width="100%",cols="2,5,^1,2",options="header"]
+|===
+| Name | Description | Default | Type
+| *accessToken* (consumer) | OAuth 2 access token. This typically expires after an hour so refreshToken is recommended for long term usage. |  | String
+| *applicationName* (consumer) | Google sheets application name. Example would be camel-google-sheets/1.0 |  | String
+| *bridgeErrorHandler* (consumer) | Allows for bridging the consumer to the Camel routing Error Handler, which mean any exceptions occurred while the consumer is trying to pickup incoming messages, or the likes, will now be processed as a message and handled by the routing Error Handler. By default the consumer will use the org.apache.camel.spi.ExceptionHandler to deal with exceptions, that will be logged at WARN or ERROR level and ignored. | false | boolean
+| *clientId* (consumer) | Client ID of the sheets application |  | String
+| *clientSecret* (consumer) | Client secret of the sheets application |  | String
+| *includeGridData* (consumer) | True if grid data should be returned. | false | boolean
+| *majorDimension* (consumer) | Specifies the major dimension that results should use.. | ROWS | String
+| *maxResults* (consumer) | Specify the maximum number of returned results. This will limit the number of rows in a returned value range data set or the number of returned value ranges in a batch request. | 10 | int
+| *range* (consumer) | Specifies the range of rows and columns in a sheet to get data from. |  | String
+| *refreshToken* (consumer) | OAuth 2 refresh token. Using this, the Google Calendar component can obtain a new accessToken whenever the current one expires - a necessity if the application is long-lived. |  | String
+| *scopes* (consumer) | Specifies the level of permissions you want a sheets application to have to a user account. See https://developers.google.com/identity/protocols/googlescopes for more info. |  | List
+| *sendEmptyMessageWhenIdle* (consumer) | If the polling consumer did not poll any files, you can enable this option to send an empty message (no body) instead. | false | boolean
+| *splitResults* (consumer) | True if value range result should be split into rows or columns to process each of them individually. When true each row or column is represented with a separate exchange in batch processing. Otherwise value range object is used as exchange junk size. | false | boolean
+| *spreadsheetId* (consumer) | Specifies the spreadsheet identifier that is used to identify the target to obtain. |  | String
+| *valueRenderOption* (consumer) | Determines how values should be rendered in the output. | FORMATTED_VALUE | String
+| *exceptionHandler* (consumer) | To let the consumer use a custom ExceptionHandler. Notice if the option bridgeErrorHandler is enabled then this option is not in use. By default the consumer will deal with exceptions, that will be logged at WARN or ERROR level and ignored. |  | ExceptionHandler
+| *exchangePattern* (consumer) | Sets the exchange pattern when the consumer creates an exchange. |  | ExchangePattern
+| *pollStrategy* (consumer) | A pluggable org.apache.camel.PollingConsumerPollingStrategy allowing you to provide your custom implementation to control error handling usually occurred during the poll operation before an Exchange have been created and being routed in Camel. |  | PollingConsumerPoll Strategy
+| *synchronous* (advanced) | Sets whether synchronous processing should be strictly used, or Camel is allowed to use asynchronous processing (if supported). | false | boolean
+| *backoffErrorThreshold* (scheduler) | The number of subsequent error polls (failed due some error) that should happen before the backoffMultipler should kick-in. |  | int
+| *backoffIdleThreshold* (scheduler) | The number of subsequent idle polls that should happen before the backoffMultipler should kick-in. |  | int
+| *backoffMultiplier* (scheduler) | To let the scheduled polling consumer backoff if there has been a number of subsequent idles/errors in a row. The multiplier is then the number of polls that will be skipped before the next actual attempt is happening again. When this option is in use then backoffIdleThreshold and/or backoffErrorThreshold must also be configured. |  | int
+| *delay* (scheduler) | Milliseconds before the next poll. You can also specify time values using units, such as 60s (60 seconds), 5m30s (5 minutes and 30 seconds), and 1h (1 hour). | 500 | long
+| *greedy* (scheduler) | If greedy is enabled, then the ScheduledPollConsumer will run immediately again, if the previous run polled 1 or more messages. | false | boolean
+| *initialDelay* (scheduler) | Milliseconds before the first poll starts. You can also specify time values using units, such as 60s (60 seconds), 5m30s (5 minutes and 30 seconds), and 1h (1 hour). | 1000 | long
+| *runLoggingLevel* (scheduler) | The consumer logs a start/complete log line when it polls. This option allows you to configure the logging level for that. | TRACE | LoggingLevel
+| *scheduledExecutorService* (scheduler) | Allows for configuring a custom/shared thread pool to use for the consumer. By default each consumer has its own single threaded thread pool. |  | ScheduledExecutor Service
+| *scheduler* (scheduler) | To use a cron scheduler from either camel-spring or camel-quartz2 component | none | ScheduledPollConsumer Scheduler
+| *schedulerProperties* (scheduler) | To configure additional properties when using a custom scheduler or any of the Quartz2, Spring based scheduler. |  | Map
+| *startScheduler* (scheduler) | Whether the scheduler should be auto started. | true | boolean
+| *timeUnit* (scheduler) | Time unit for initialDelay and delay options. | MILLISECONDS | TimeUnit
+| *useFixedDelay* (scheduler) | Controls if fixed delay or fixed rate is used. See ScheduledExecutorService in JDK for details. | true | boolean
+|===
+// endpoint options: END
+// spring-boot-auto-configure options: START
+=== Spring Boot Auto-Configuration
+
+
+The component supports 17 options, which are listed below.
+
+
+
+[width="100%",cols="2,5,^1,2",options="header"]
+|===
+| Name | Description | Default | Type
+| *camel.component.google-sheets-stream.client-factory* | To use the GoogleSheetsClientFactory as factory for creating the client. Will by default use BatchGoogleSheetsClientFactory. The option is a org.apache.camel.component.google.sheets.GoogleSheetsClientFactory type. |  | String
+| *camel.component.google-sheets-stream.configuration.access-token* | OAuth 2 access token. This typically expires after an hour so refreshToken is recommended for long term usage. |  | String
+| *camel.component.google-sheets-stream.configuration.api-name* | Sets the apiName. |  | String
+| *camel.component.google-sheets-stream.configuration.application-name* | Google sheets application name. Example would be camel-google-sheets/1.0 |  | String
+| *camel.component.google-sheets-stream.configuration.client-id* | Client ID of the sheets application |  | String
+| *camel.component.google-sheets-stream.configuration.client-secret* | Client secret of the sheets application |  | String
+| *camel.component.google-sheets-stream.configuration.include-grid-data* | True if grid data should be returned. | false | Boolean
+| *camel.component.google-sheets-stream.configuration.major-dimension* | Specifies the major dimension that results should use.. | ROWS | String
+| *camel.component.google-sheets-stream.configuration.max-results* | Specify the maximum number of returned results. This will limit the number of rows in a returned value range data set or the number of returned value ranges in a batch request. | 10 | Integer
+| *camel.component.google-sheets-stream.configuration.range* | Specifies the range of rows and columns in a sheet to get data from. |  | String
+| *camel.component.google-sheets-stream.configuration.refresh-token* | OAuth 2 refresh token. Using this, the Google Calendar component can obtain a new accessToken whenever the current one expires - a necessity if the application is long-lived. |  | String
+| *camel.component.google-sheets-stream.configuration.scopes* | Specifies the level of permissions you want a sheets application to have to a user account. See https://developers.google.com/identity/protocols/googlescopes for more info. |  | List
+| *camel.component.google-sheets-stream.configuration.split-results* | True if value range result should be split into rows or columns to process each of them individually. When true each row or column is represented with a separate exchange in batch processing. Otherwise value range object is used as exchange junk size. | false | Boolean
+| *camel.component.google-sheets-stream.configuration.spreadsheet-id* | Specifies the spreadsheet identifier that is used to identify the target to obtain. |  | String
+| *camel.component.google-sheets-stream.configuration.value-render-option* | Determines how values should be rendered in the output. | FORMATTED_VALUE | String
+| *camel.component.google-sheets-stream.enabled* | Whether to enable auto configuration of the google-sheets-stream component. This is enabled by default. |  | Boolean
+| *camel.component.google-sheets-stream.resolve-property-placeholders* | Whether the component should resolve property placeholders on itself when starting. Only properties which are of String type can use property placeholders. | true | Boolean
+|===
+// spring-boot-auto-configure options: END
+
+
+### Consumer
+
+The consumer will poll by default with maxResults equals to 5.
+
+For example
+
+[source,java]
+---------------------------------------------------------
+from("google-sheets-stream://data?range=A:B&delay=5000&maxResults=5").to("mock:result");
+---------------------------------------------------------
+
+This route will consume the next ten events starting from the date of polling.
+
+   
diff --git a/components/camel-google-sheets/src/main/java/org/apache/camel/component/google/sheets/BatchGoogleSheetsClientFactory.java b/components/camel-google-sheets/src/main/java/org/apache/camel/component/google/sheets/BatchGoogleSheetsClientFactory.java
new file mode 100644
index 00000000000..1c5a91a582b
--- /dev/null
+++ b/components/camel-google-sheets/src/main/java/org/apache/camel/component/google/sheets/BatchGoogleSheetsClientFactory.java
@@ -0,0 +1,66 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.camel.component.google.sheets;
+
+import com.google.api.client.auth.oauth2.Credential;
+import com.google.api.client.googleapis.auth.oauth2.GoogleCredential;
+import com.google.api.client.http.javanet.NetHttpTransport;
+import com.google.api.client.json.jackson2.JacksonFactory;
+import com.google.api.services.sheets.v4.Sheets;
+import org.apache.camel.RuntimeCamelException;
+
+public class BatchGoogleSheetsClientFactory implements GoogleSheetsClientFactory {
+
+    private final NetHttpTransport transport;
+    private final JacksonFactory jsonFactory;
+
+    public BatchGoogleSheetsClientFactory() {
+        this.transport = new NetHttpTransport();
+        this.jsonFactory = new JacksonFactory();
+    }
+
+    @Override
+    public Sheets makeClient(String clientId, String clientSecret, String applicationName, String refreshToken, String accessToken) {
+        if (clientId == null || clientSecret == null) {
+            throw new IllegalArgumentException("clientId and clientSecret are required to create Google Sheets client.");
+        }
+        try {
+            Credential credential = authorize(clientId, clientSecret);
+
+            if (refreshToken != null && !"".equals(refreshToken)) {
+                credential.setRefreshToken(refreshToken);
+            }
+            if (accessToken != null && !"".equals(accessToken)) {
+                credential.setAccessToken(accessToken);
+            }
+            return new Sheets.Builder(transport, jsonFactory, credential)
+                                .setApplicationName(applicationName)
+                                .build();
+        } catch (Exception e) {
+            throw new RuntimeCamelException("Could not create Google Sheets client.", e);
+        }
+    }
+
+    // Authorizes the installed application to access user's protected data.
+    private Credential authorize(String clientId, String clientSecret) {
+        // authorize
+        return new GoogleCredential.Builder()
+                        .setJsonFactory(jsonFactory)
+                        .setTransport(transport)
+                        .setClientSecrets(clientId, clientSecret).build();
+    }
+}
diff --git a/components/camel-google-sheets/src/main/java/org/apache/camel/component/google/sheets/GoogleSheetsClientFactory.java b/components/camel-google-sheets/src/main/java/org/apache/camel/component/google/sheets/GoogleSheetsClientFactory.java
new file mode 100644
index 00000000000..78b4e9790be
--- /dev/null
+++ b/components/camel-google-sheets/src/main/java/org/apache/camel/component/google/sheets/GoogleSheetsClientFactory.java
@@ -0,0 +1,25 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.camel.component.google.sheets;
+
+import com.google.api.services.sheets.v4.Sheets;
+
+public interface GoogleSheetsClientFactory {
+
+    Sheets makeClient(String clientId, String clientSecret, String applicationName, String refreshToken, String accessToken);
+
+}
diff --git a/components/camel-google-sheets/src/main/java/org/apache/camel/component/google/sheets/GoogleSheetsComponent.java b/components/camel-google-sheets/src/main/java/org/apache/camel/component/google/sheets/GoogleSheetsComponent.java
new file mode 100644
index 00000000000..f5764b16899
--- /dev/null
+++ b/components/camel-google-sheets/src/main/java/org/apache/camel/component/google/sheets/GoogleSheetsComponent.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.component.google.sheets;
+
+import com.google.api.services.sheets.v4.Sheets;
+import org.apache.camel.CamelContext;
+import org.apache.camel.Endpoint;
+import org.apache.camel.component.google.sheets.internal.GoogleSheetsApiCollection;
+import org.apache.camel.component.google.sheets.internal.GoogleSheetsApiName;
+import org.apache.camel.spi.Metadata;
+import org.apache.camel.util.component.AbstractApiComponent;
+
+/**
+ * Represents the component that manages {@link GoogleSheetsEndpoint}.
+ */
+@Metadata(label = "verifiers", enums = "parameters,connectivity")
+public class GoogleSheetsComponent extends AbstractApiComponent<GoogleSheetsApiName, GoogleSheetsConfiguration, GoogleSheetsApiCollection> {
+
+    @Metadata(label = "advanced")
+    private Sheets client;
+    @Metadata(label = "advanced")
+    private GoogleSheetsClientFactory clientFactory;
+
+    public GoogleSheetsComponent() {
+        super(GoogleSheetsEndpoint.class, GoogleSheetsApiName.class, GoogleSheetsApiCollection.getCollection());
+        registerExtension(new GoogleSheetsVerifierExtension("google-sheets"));
+    }
+
+    public GoogleSheetsComponent(CamelContext context) {
+        super(context, GoogleSheetsEndpoint.class, GoogleSheetsApiName.class, GoogleSheetsApiCollection.getCollection());
+        registerExtension(new GoogleSheetsVerifierExtension("google-sheets", context));
+    }
+
+    @Override
+    protected GoogleSheetsApiName getApiName(String apiNameStr) throws IllegalArgumentException {
+        return GoogleSheetsApiName.fromValue(apiNameStr);
+    }
+
+    public Sheets getClient(GoogleSheetsConfiguration config) {
+        if (client == null) {
+            client = getClientFactory().makeClient(config.getClientId(),
+                    config.getClientSecret(),
+                    config.getApplicationName(),
+                    config.getRefreshToken(),
+                    config.getAccessToken());
+        }
+        return client;
+    }
+
+    public GoogleSheetsClientFactory getClientFactory() {
+        if (clientFactory == null) {
+            clientFactory = new BatchGoogleSheetsClientFactory();
+        }
+        return clientFactory;
+    }
+
+    /**
+     * To use the shared configuration
+     */
+    @Override
+    public void setConfiguration(GoogleSheetsConfiguration configuration) {
+        super.setConfiguration(configuration);
+    }
+
+    @Override
+    public GoogleSheetsConfiguration getConfiguration() {
+        if (configuration == null) {
+            configuration = new GoogleSheetsConfiguration();
+        }
+        return super.getConfiguration();
+    }
+
+    /**
+     * To use the GoogleSheetsClientFactory as factory for creating the client.
+     * Will by default use {@link BatchGoogleSheetsClientFactory}
+     */
+    public void setClientFactory(GoogleSheetsClientFactory clientFactory) {
+        this.clientFactory = clientFactory;
+    }
+
+    @Override
+    protected Endpoint createEndpoint(String uri, String methodName, GoogleSheetsApiName apiName,
+                                      GoogleSheetsConfiguration endpointConfiguration) {
+        endpointConfiguration.setApiName(apiName);
+        endpointConfiguration.setMethodName(methodName);
+        return new GoogleSheetsEndpoint(uri, this, apiName, methodName, endpointConfiguration);
+    }
+}
diff --git a/components/camel-google-sheets/src/main/java/org/apache/camel/component/google/sheets/GoogleSheetsConfiguration.java b/components/camel-google-sheets/src/main/java/org/apache/camel/component/google/sheets/GoogleSheetsConfiguration.java
new file mode 100644
index 00000000000..3492c59581d
--- /dev/null
+++ b/components/camel-google-sheets/src/main/java/org/apache/camel/component/google/sheets/GoogleSheetsConfiguration.java
@@ -0,0 +1,130 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.camel.component.google.sheets;
+
+import org.apache.camel.component.google.sheets.internal.GoogleSheetsApiName;
+import org.apache.camel.spi.Metadata;
+import org.apache.camel.spi.UriParam;
+import org.apache.camel.spi.UriParams;
+import org.apache.camel.spi.UriPath;
+
+/**
+ * Component configuration for GoogleSheets component.
+ */
+@UriParams
+public class GoogleSheetsConfiguration {
+
+    @UriPath
+    @Metadata(required = "true")
+    private GoogleSheetsApiName apiName;
+
+    @UriPath(enums = "create,get,update,append,batchUpdate,clear")
+    @Metadata(required = "true")
+    private String methodName;
+
+    @UriParam
+    private String clientId;
+
+    @UriParam
+    private String clientSecret;
+
+    @UriParam
+    private String accessToken;
+
+    @UriParam
+    private String refreshToken;
+
+    @UriParam
+    private String applicationName;
+
+    public GoogleSheetsApiName getApiName() {
+        return apiName;
+    }
+
+    /**
+     * What kind of operation to perform
+     */
+    public void setApiName(GoogleSheetsApiName apiName) {
+        this.apiName = apiName;
+    }
+
+    public String getMethodName() {
+        return methodName;
+    }
+
+    /**
+     * What sub operation to use for the selected operation
+     */
+    public void setMethodName(String methodName) {
+        this.methodName = methodName;
+    }
+
+    public String getClientId() {
+        return clientId;
+    }
+
+    /**
+     * Client ID of the sheets application
+     */
+    public void setClientId(String clientId) {
+        this.clientId = clientId;
+    }
+
+    public String getClientSecret() {
+        return clientSecret;
+    }
+
+    /**
+     * Client secret of the sheets application
+     */
+    public void setClientSecret(String clientSecret) {
+        this.clientSecret = clientSecret;
+    }
+
+    public String getAccessToken() {
+        return accessToken;
+    }
+
+    /**
+     * OAuth 2 access token. This typically expires after an hour so refreshToken is recommended for long term usage.
+     */
+    public void setAccessToken(String accessToken) {
+        this.accessToken = accessToken;
+    }
+
+    public String getRefreshToken() {
+        return refreshToken;
+    }
+
+    /**
+     * OAuth 2 refresh token. Using this, the Google Sheets component can obtain a new accessToken whenever the current one expires - a necessity if the application is long-lived.
+     */
+    public void setRefreshToken(String refreshToken) {
+        this.refreshToken = refreshToken;
+    }
+
+    public String getApplicationName() {
+        return applicationName;
+    }
+
+    /**
+     * Google Sheets application name. Example would be "camel-google-sheets/1.0"
+     */
+    public void setApplicationName(String applicationName) {
+        this.applicationName = applicationName;
+    }
+}
diff --git a/components/camel-google-sheets/src/main/java/org/apache/camel/component/google/sheets/GoogleSheetsConsumer.java b/components/camel-google-sheets/src/main/java/org/apache/camel/component/google/sheets/GoogleSheetsConsumer.java
new file mode 100644
index 00000000000..526c679f5de
--- /dev/null
+++ b/components/camel-google-sheets/src/main/java/org/apache/camel/component/google/sheets/GoogleSheetsConsumer.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.component.google.sheets;
+
+
+import java.util.Map;
+import java.util.Map.Entry;
+
+
+import com.google.api.client.googleapis.services.AbstractGoogleClientRequest;
+import org.apache.camel.Processor;
+import org.apache.camel.RuntimeCamelException;
+import org.apache.camel.TypeConverter;
+import org.apache.camel.component.google.sheets.internal.GoogleSheetsApiName;
+import org.apache.camel.util.IntrospectionSupport;
+import org.apache.camel.util.component.AbstractApiConsumer;
+
+/**
+ * The GoogleSheets consumer.
+ */
+public class GoogleSheetsConsumer extends AbstractApiConsumer<GoogleSheetsApiName, GoogleSheetsConfiguration> {
+
+    public GoogleSheetsConsumer(GoogleSheetsEndpoint endpoint, Processor processor) {
+        super(endpoint, processor);
+    }
+
+    @Override
+    protected Object doInvokeMethod(Map<String, Object> properties) throws RuntimeCamelException {
+        AbstractGoogleClientRequest<?> request = (AbstractGoogleClientRequest) super.doInvokeMethod(properties);
+        try {
+            TypeConverter typeConverter = getEndpoint().getCamelContext().getTypeConverter();
+            for (Entry<String, Object> p : properties.entrySet()) {
+                IntrospectionSupport.setProperty(typeConverter, request, p.getKey(), p.getValue());
+            }
+            return request.execute();
+        } catch (Exception e) {
+            throw new RuntimeCamelException(e);
+        }
+    }
+}
diff --git a/components/camel-google-sheets/src/main/java/org/apache/camel/component/google/sheets/GoogleSheetsEndpoint.java b/components/camel-google-sheets/src/main/java/org/apache/camel/component/google/sheets/GoogleSheetsEndpoint.java
new file mode 100644
index 00000000000..a6d176840c6
--- /dev/null
+++ b/components/camel-google-sheets/src/main/java/org/apache/camel/component/google/sheets/GoogleSheetsEndpoint.java
@@ -0,0 +1,109 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.camel.component.google.sheets;
+
+import java.util.Map;
+
+import com.google.api.services.sheets.v4.Sheets;
+import org.apache.camel.Consumer;
+import org.apache.camel.Processor;
+import org.apache.camel.Producer;
+import org.apache.camel.component.google.sheets.internal.GoogleSheetsApiCollection;
+import org.apache.camel.component.google.sheets.internal.GoogleSheetsApiName;
+import org.apache.camel.component.google.sheets.internal.GoogleSheetsConstants;
+import org.apache.camel.component.google.sheets.internal.GoogleSheetsPropertiesHelper;
+import org.apache.camel.spi.UriEndpoint;
+import org.apache.camel.spi.UriParam;
+import org.apache.camel.util.component.AbstractApiEndpoint;
+import org.apache.camel.util.component.ApiMethod;
+import org.apache.camel.util.component.ApiMethodPropertiesHelper;
+
+/**
+ * The google-sheets component provides access to Google Sheets.
+ */
+@UriEndpoint(firstVersion = "2.23.0", scheme = "google-sheets", title = "Google Sheets", 
+             syntax = "google-sheets:apiName/methodName", consumerClass = GoogleSheetsConsumer.class, consumerPrefix = "consumer", label = "api,cloud,sheets")
+public class GoogleSheetsEndpoint extends AbstractApiEndpoint<GoogleSheetsApiName, GoogleSheetsConfiguration> {
+
+    @UriParam
+    private GoogleSheetsConfiguration configuration;
+
+    private Object apiProxy;
+
+    public GoogleSheetsEndpoint(String uri, GoogleSheetsComponent component, GoogleSheetsApiName apiName, String methodName, GoogleSheetsConfiguration endpointConfiguration) {
+        super(uri, component, apiName, methodName, GoogleSheetsApiCollection.getCollection().getHelper(apiName), endpointConfiguration);
+        this.configuration = endpointConfiguration;
+    }
+
+    @Override
+    public Producer createProducer() throws Exception {
+        return new org.apache.camel.component.google.sheets.GoogleSheetsProducer(this);
+    }
+
+    @Override
+    public Consumer createConsumer(Processor processor) throws Exception {
+        // make sure inBody is not set for consumers
+        if (inBody != null) {
+            throw new IllegalArgumentException("Option inBody is not supported for consumer endpoint");
+        }
+        final GoogleSheetsConsumer consumer = new GoogleSheetsConsumer(this, processor);
+        // also set consumer.* properties
+        configureConsumer(consumer);
+        return consumer;
+    }
+
+    @Override
+    protected ApiMethodPropertiesHelper<GoogleSheetsConfiguration> getPropertiesHelper() {
+        return GoogleSheetsPropertiesHelper.getHelper();
+    }
+
+    @Override
+    protected String getThreadProfileName() {
+        return GoogleSheetsConstants.THREAD_PROFILE_NAME;
+    }
+
+    @Override
+    protected void afterConfigureProperties() {
+        switch (apiName) {
+        case SPREADSHEETS:
+            apiProxy = getClient().spreadsheets();
+            break;
+        case DATA:
+            apiProxy = getClient().spreadsheets().values();
+            break;
+        default:
+            throw new IllegalArgumentException("Invalid API name " + apiName);
+        }
+    }
+
+    public Sheets getClient() {
+        return ((GoogleSheetsComponent)getComponent()).getClient(configuration);
+    }
+
+    @Override
+    public Object getApiProxy(ApiMethod method, Map<String, Object> args) {
+        return apiProxy;
+    }
+
+    public GoogleSheetsClientFactory getClientFactory() {
+        return ((GoogleSheetsComponent)getComponent()).getClientFactory();
+    }
+
+    public void setClientFactory(GoogleSheetsClientFactory clientFactory) {
+        ((GoogleSheetsComponent)getComponent()).setClientFactory(clientFactory);
+    }
+}
diff --git a/components/camel-google-sheets/src/main/java/org/apache/camel/component/google/sheets/GoogleSheetsProducer.java b/components/camel-google-sheets/src/main/java/org/apache/camel/component/google/sheets/GoogleSheetsProducer.java
new file mode 100644
index 00000000000..abc40608994
--- /dev/null
+++ b/components/camel-google-sheets/src/main/java/org/apache/camel/component/google/sheets/GoogleSheetsProducer.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.component.google.sheets;
+
+import java.util.Map;
+import java.util.Map.Entry;
+
+import com.google.api.client.googleapis.services.AbstractGoogleClientRequest;
+import org.apache.camel.RuntimeCamelException;
+import org.apache.camel.TypeConverter;
+import org.apache.camel.component.google.sheets.internal.GoogleSheetsApiName;
+import org.apache.camel.component.google.sheets.internal.GoogleSheetsPropertiesHelper;
+import org.apache.camel.util.IntrospectionSupport;
+import org.apache.camel.util.component.AbstractApiProducer;
+import org.apache.camel.util.component.ApiMethod;
+
+/**
+ * The GoogleSheets producer.
+ */
+public class GoogleSheetsProducer extends AbstractApiProducer<GoogleSheetsApiName, GoogleSheetsConfiguration> {
+
+    public GoogleSheetsProducer(GoogleSheetsEndpoint endpoint) {
+        super(endpoint, GoogleSheetsPropertiesHelper.getHelper());
+    }
+
+    @Override
+    protected Object doInvokeMethod(ApiMethod method, Map<String, Object> properties) throws RuntimeCamelException {
+        AbstractGoogleClientRequest<?> request = (AbstractGoogleClientRequest)super.doInvokeMethod(method, properties);
+        try {
+            TypeConverter typeConverter = getEndpoint().getCamelContext().getTypeConverter();
+            for (Entry<String, Object> p : properties.entrySet()) {
+                IntrospectionSupport.setProperty(typeConverter, request, p.getKey(), p.getValue());
+            }
+            return request.execute();
+        } catch (Exception e) {
+            throw new RuntimeCamelException(e);
+        }
+    }
+
+}
diff --git a/components/camel-google-sheets/src/main/java/org/apache/camel/component/google/sheets/GoogleSheetsVerifierExtension.java b/components/camel-google-sheets/src/main/java/org/apache/camel/component/google/sheets/GoogleSheetsVerifierExtension.java
new file mode 100644
index 00000000000..26100cfd8d6
--- /dev/null
+++ b/components/camel-google-sheets/src/main/java/org/apache/camel/component/google/sheets/GoogleSheetsVerifierExtension.java
@@ -0,0 +1,77 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.camel.component.google.sheets;
+
+import java.util.Map;
+import java.util.Optional;
+import java.util.UUID;
+
+import com.google.api.services.sheets.v4.Sheets;
+import org.apache.camel.CamelContext;
+import org.apache.camel.component.extension.verifier.DefaultComponentVerifierExtension;
+import org.apache.camel.component.extension.verifier.ResultBuilder;
+import org.apache.camel.component.extension.verifier.ResultErrorBuilder;
+import org.apache.camel.component.extension.verifier.ResultErrorHelper;
+
+public class GoogleSheetsVerifierExtension extends DefaultComponentVerifierExtension {
+
+    public GoogleSheetsVerifierExtension(String defaultScheme) {
+        super(defaultScheme);
+    }
+
+    public GoogleSheetsVerifierExtension(String defaultScheme, CamelContext context) {
+        super(defaultScheme, context);
+    }
+
+    // *********************************
+    // Parameters validation
+    // *********************************
+
+    @Override
+    protected Result verifyParameters(Map<String, Object> parameters) {
+        ResultBuilder builder = ResultBuilder.withStatusAndScope(Result.Status.OK, Scope.PARAMETERS).error(ResultErrorHelper.requiresOption("applicationName", parameters))
+            .error(ResultErrorHelper.requiresOption("clientId", parameters)).error(ResultErrorHelper.requiresOption("clientSecret", parameters));
+
+        return builder.build();
+    }
+
+    // *********************************
+    // Connectivity validation
+    // *********************************
+
+    @Override
+    @SuppressWarnings("PMD.AvoidCatchingGenericException")
+    protected Result verifyConnectivity(Map<String, Object> parameters) {
+        ResultBuilder builder = ResultBuilder.withStatusAndScope(Result.Status.OK, Scope.CONNECTIVITY);
+
+        try {
+            GoogleSheetsConfiguration configuration = setProperties(new GoogleSheetsConfiguration(), parameters);
+            GoogleSheetsClientFactory clientFactory = new BatchGoogleSheetsClientFactory();
+            Sheets client = clientFactory.makeClient(configuration.getClientId(), configuration.getClientSecret(), configuration.getApplicationName(),
+                                                     configuration.getRefreshToken(), configuration.getAccessToken());
+            client.spreadsheets().get(Optional.ofNullable(parameters.get("spreadsheetId")).map(Object::toString).orElse(UUID.randomUUID().toString())).execute();
+        } catch (Exception e) {
+            ResultErrorBuilder errorBuilder = ResultErrorBuilder.withCodeAndDescription(VerificationError.StandardCode.AUTHENTICATION, e.getMessage())
+                .detail("google_sheets_exception_message", e.getMessage()).detail(VerificationError.ExceptionAttribute.EXCEPTION_CLASS, e.getClass().getName())
+                .detail(VerificationError.ExceptionAttribute.EXCEPTION_INSTANCE, e);
+
+            builder.error(errorBuilder.build());
+        }
+
+        return builder.build();
+    }
+}
diff --git a/components/camel-google-sheets/src/main/java/org/apache/camel/component/google/sheets/internal/GoogleSheetsConstants.java b/components/camel-google-sheets/src/main/java/org/apache/camel/component/google/sheets/internal/GoogleSheetsConstants.java
new file mode 100644
index 00000000000..feb91419558
--- /dev/null
+++ b/components/camel-google-sheets/src/main/java/org/apache/camel/component/google/sheets/internal/GoogleSheetsConstants.java
@@ -0,0 +1,33 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.camel.component.google.sheets.internal;
+
+/**
+ * Constants for Camel Google Sheets component.
+ */
+public final class GoogleSheetsConstants {
+
+    // suffix for parameters when passed as exchange header properties
+    public static final String PROPERTY_PREFIX = "CamelGoogleSheets.";
+    // thread profile name for this component
+    public static final String THREAD_PROFILE_NAME = "CamelGoogleSheets";
+
+    /**
+     * Prevent instantiation.
+     */
+    private GoogleSheetsConstants() { }
+}
diff --git a/components/camel-google-sheets/src/main/java/org/apache/camel/component/google/sheets/internal/GoogleSheetsPropertiesHelper.java b/components/camel-google-sheets/src/main/java/org/apache/camel/component/google/sheets/internal/GoogleSheetsPropertiesHelper.java
new file mode 100644
index 00000000000..48c345e7efe
--- /dev/null
+++ b/components/camel-google-sheets/src/main/java/org/apache/camel/component/google/sheets/internal/GoogleSheetsPropertiesHelper.java
@@ -0,0 +1,39 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.camel.component.google.sheets.internal;
+
+import org.apache.camel.component.google.sheets.GoogleSheetsConfiguration;
+import org.apache.camel.util.component.ApiMethodPropertiesHelper;
+
+/**
+ * Singleton {@link ApiMethodPropertiesHelper} for GoogleSheets component.
+ */
+public final class GoogleSheetsPropertiesHelper extends ApiMethodPropertiesHelper<GoogleSheetsConfiguration> {
+
+    private static GoogleSheetsPropertiesHelper helper;
+
+    private GoogleSheetsPropertiesHelper() {
+        super(GoogleSheetsConfiguration.class, GoogleSheetsConstants.PROPERTY_PREFIX);
+    }
+
+    public static synchronized GoogleSheetsPropertiesHelper getHelper() {
+        if (helper == null) {
+            helper = new GoogleSheetsPropertiesHelper();
+        }
+        return helper;
+    }
+}
diff --git a/components/camel-google-sheets/src/main/java/org/apache/camel/component/google/sheets/stream/GoogleSheetsStreamComponent.java b/components/camel-google-sheets/src/main/java/org/apache/camel/component/google/sheets/stream/GoogleSheetsStreamComponent.java
new file mode 100644
index 00000000000..d602326bd6b
--- /dev/null
+++ b/components/camel-google-sheets/src/main/java/org/apache/camel/component/google/sheets/stream/GoogleSheetsStreamComponent.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.component.google.sheets.stream;
+
+import java.util.Map;
+
+import com.google.api.services.sheets.v4.Sheets;
+import org.apache.camel.CamelContext;
+import org.apache.camel.Endpoint;
+import org.apache.camel.component.google.sheets.BatchGoogleSheetsClientFactory;
+import org.apache.camel.component.google.sheets.GoogleSheetsClientFactory;
+import org.apache.camel.component.google.sheets.GoogleSheetsVerifierExtension;
+import org.apache.camel.impl.DefaultComponent;
+import org.apache.camel.spi.Metadata;
+
+/**
+ * Represents the component that manages {@link GoogleSheetsStreamEndpoint}.
+ */
+@Metadata(label = "verifiers", enums = "parameters,connectivity")
+public class GoogleSheetsStreamComponent extends DefaultComponent {
+
+    @Metadata(label = "advanced")
+    private Sheets client;
+    @Metadata(label = "advanced")
+    private GoogleSheetsClientFactory clientFactory;
+    @Metadata
+    private GoogleSheetsStreamConfiguration configuration;
+
+    public GoogleSheetsStreamComponent() {
+        this(null);
+    }
+
+    public GoogleSheetsStreamComponent(CamelContext context) {
+        super(context);
+        registerExtension(new GoogleSheetsVerifierExtension("google-sheets-stream", context));
+        this.configuration = new GoogleSheetsStreamConfiguration();
+    }
+
+    public Sheets getClient(GoogleSheetsStreamConfiguration endpointConfiguration) {
+        if (client == null) {
+            client = getClientFactory().makeClient(endpointConfiguration.getClientId(),
+                                                endpointConfiguration.getClientSecret(),
+                                                endpointConfiguration.getApplicationName(),
+                                                endpointConfiguration.getRefreshToken(),
+                                                endpointConfiguration.getAccessToken());
+        }
+        return client;
+    }
+
+    public GoogleSheetsClientFactory getClientFactory() {
+        if (clientFactory == null) {
+            clientFactory = new BatchGoogleSheetsClientFactory();
+        }
+        return clientFactory;
+    }
+
+    public GoogleSheetsStreamConfiguration getConfiguration() {
+        return configuration;
+    }
+
+    /**
+     * To use the shared configuration
+     */
+    public void setConfiguration(GoogleSheetsStreamConfiguration configuration) {
+        this.configuration = configuration;
+    }
+
+    /**
+     * To use the GoogleSheetsClientFactory as factory for creating the client.
+     * Will by default use {@link BatchGoogleSheetsClientFactory}
+     */
+    public void setClientFactory(GoogleSheetsClientFactory clientFactory) {
+        this.clientFactory = clientFactory;
+    }
+
+    @Override
+    protected Endpoint createEndpoint(String uri, String remaining, Map<String, Object> parameters) throws Exception {
+        final GoogleSheetsStreamConfiguration configuration = this.configuration.copy();
+        setProperties(configuration, parameters);
+        GoogleSheetsStreamEndpoint endpoint = new GoogleSheetsStreamEndpoint(uri, this, configuration);
+        setProperties(endpoint, parameters);
+        return endpoint;
+    }
+}
diff --git a/components/camel-google-sheets/src/main/java/org/apache/camel/component/google/sheets/stream/GoogleSheetsStreamConfiguration.java b/components/camel-google-sheets/src/main/java/org/apache/camel/component/google/sheets/stream/GoogleSheetsStreamConfiguration.java
new file mode 100644
index 00000000000..4de52222be7
--- /dev/null
+++ b/components/camel-google-sheets/src/main/java/org/apache/camel/component/google/sheets/stream/GoogleSheetsStreamConfiguration.java
@@ -0,0 +1,273 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.camel.component.google.sheets.stream;
+
+import java.util.Collections;
+import java.util.List;
+
+import com.google.api.services.sheets.v4.SheetsScopes;
+import org.apache.camel.RuntimeCamelException;
+import org.apache.camel.spi.UriParam;
+import org.apache.camel.spi.UriParams;
+import org.apache.camel.spi.UriPath;
+
+/**
+ * Component configuration for GoogleSheets stream component.
+ */
+@UriParams
+public class GoogleSheetsStreamConfiguration implements Cloneable {
+
+    private static final List<String> DEFAULT_SCOPES = Collections.singletonList(SheetsScopes.SPREADSHEETS);
+
+    @UriPath
+    private String apiName;
+
+    @UriParam
+    private List<String> scopes = DEFAULT_SCOPES;
+
+    @UriParam
+    private String clientId;
+
+    @UriParam
+    private String clientSecret;
+
+    @UriParam
+    private String accessToken;
+
+    @UriParam
+    private String refreshToken;
+
+    @UriParam
+    private String applicationName;
+
+    @UriParam
+    private String spreadsheetId;
+
+    @UriParam(defaultValue = "10")
+    private int maxResults = 10;
+
+    @UriParam
+    private String range;
+
+    @UriParam
+    private boolean includeGridData;
+
+    @UriParam
+    private boolean splitResults;
+
+    @UriParam(enums = "ROWS,COLUMNS,DIMENSION_UNSPECIFIED", defaultValue = "ROWS")
+    private String majorDimension = "ROWS";
+
+    @UriParam(enums = "FORMATTED_VALUE,UNFORMATTED_VALUE,FORMULA", defaultValue = "FORMATTED_VALUE")
+    private String valueRenderOption = "FORMATTED_VALUE";
+
+    public String getClientId() {
+        return clientId;
+    }
+
+    /**
+     * Client ID of the sheets application
+     */
+    public void setClientId(String clientId) {
+        this.clientId = clientId;
+    }
+
+    public String getClientSecret() {
+        return clientSecret;
+    }
+
+    /**
+     * Client secret of the sheets application
+     */
+    public void setClientSecret(String clientSecret) {
+        this.clientSecret = clientSecret;
+    }
+
+    public String getAccessToken() {
+        return accessToken;
+    }
+
+    /**
+     * OAuth 2 access token. This typically expires after an hour so
+     * refreshToken is recommended for long term usage.
+     */
+    public void setAccessToken(String accessToken) {
+        this.accessToken = accessToken;
+    }
+
+    public String getRefreshToken() {
+        return refreshToken;
+    }
+
+    /**
+     * OAuth 2 refresh token. Using this, the Google Calendar component can
+     * obtain a new accessToken whenever the current one expires - a necessity
+     * if the application is long-lived.
+     */
+    public void setRefreshToken(String refreshToken) {
+        this.refreshToken = refreshToken;
+    }
+
+    public String getApplicationName() {
+        return applicationName;
+    }
+
+    /**
+     * Google sheets application name. Example would be "camel-google-sheets/1.0"
+     */
+    public void setApplicationName(String applicationName) {
+        this.applicationName = applicationName;
+    }
+
+    public List<String> getScopes() {
+        return scopes;
+    }
+
+    /**
+     * Specifies the level of permissions you want a sheets application to have to
+     * a user account. See https://developers.google.com/identity/protocols/googlescopes
+     * for more info.
+     */
+    public void setScopes(List<String> scopes) {
+        this.scopes = scopes;
+    }
+
+    /**
+     * Gets the apiName.
+     *
+     * @return
+     */
+    public String getApiName() {
+        return apiName;
+    }
+
+    /**
+     * Sets the apiName.
+     *
+     * @param apiName
+     */
+    public void setApiName(String apiName) {
+        this.apiName = apiName;
+    }
+
+    public String getSpreadsheetId() {
+        return spreadsheetId;
+    }
+
+    /**
+     * Specifies the spreadsheet identifier that is used to identify the target to obtain.
+     *
+     * @param spreadsheetId
+     */
+    public void setSpreadsheetId(String spreadsheetId) {
+        this.spreadsheetId = spreadsheetId;
+    }
+
+    public int getMaxResults() {
+        return maxResults;
+    }
+
+    /**
+     * Specify the maximum number of returned results. This will limit the number of rows in a returned value range
+     * data set or the number of returned value ranges in a batch request.
+     *
+     * @param maxResults
+     */
+    public void setMaxResults(int maxResults) {
+        this.maxResults = maxResults;
+    }
+
+    public String getRange() {
+        return range;
+    }
+
+    /**
+     * Specifies the range of rows and columns in a sheet to get data from.
+     *
+     * @param range
+     */
+    public void setRange(String range) {
+        this.range = range;
+    }
+
+    public String getMajorDimension() {
+        return majorDimension;
+    }
+
+    /**
+     * Specifies the major dimension that results should use..
+     *
+     * @param majorDimension
+     */
+    public void setMajorDimension(String majorDimension) {
+        this.majorDimension = majorDimension;
+    }
+
+    public String getValueRenderOption() {
+        return valueRenderOption;
+    }
+
+    /**
+     * Determines how values should be rendered in the output.
+     *
+     * @param valueRenderOption
+     */
+    public void setValueRenderOption(String valueRenderOption) {
+        this.valueRenderOption = valueRenderOption;
+    }
+
+    public boolean isIncludeGridData() {
+        return includeGridData;
+    }
+
+    /**
+     * True if grid data should be returned.
+     *
+     * @param includeGridData
+     */
+    public void setIncludeGridData(boolean includeGridData) {
+        this.includeGridData = includeGridData;
+    }
+
+    public boolean isSplitResults() {
+        return splitResults;
+    }
+
+    /**
+     * True if value range result should be split into rows or columns to process each of them individually. When true
+     * each row or column is represented with a separate exchange in batch processing. Otherwise value range object is used
+     * as exchange junk size.
+     *
+     * @param splitResults
+     */
+    public void setSplitResults(boolean splitResults) {
+        this.splitResults = splitResults;
+    }
+
+    // *************************************************
+    //
+    // *************************************************
+
+    public GoogleSheetsStreamConfiguration copy() {
+        try {
+            return (GoogleSheetsStreamConfiguration)super.clone();
+        } catch (CloneNotSupportedException e) {
+            throw new RuntimeCamelException(e);
+        }
+    }
+
+}
diff --git a/components/camel-google-sheets/src/main/java/org/apache/camel/component/google/sheets/stream/GoogleSheetsStreamConstants.java b/components/camel-google-sheets/src/main/java/org/apache/camel/component/google/sheets/stream/GoogleSheetsStreamConstants.java
new file mode 100644
index 00000000000..65365882def
--- /dev/null
+++ b/components/camel-google-sheets/src/main/java/org/apache/camel/component/google/sheets/stream/GoogleSheetsStreamConstants.java
@@ -0,0 +1,39 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.camel.component.google.sheets.stream;
+
+/**
+ * Constants used in Camel Google Sheets Stream
+ */
+public final class GoogleSheetsStreamConstants {
+
+    private static final String PROPERTY_PREFIX = "CamelGoogleSheets";
+
+    public static final String SPREADSHEET_ID =  PROPERTY_PREFIX + "SpreadsheetId";
+    public static final String SPREADSHEET_URL =  PROPERTY_PREFIX + "SpreadsheetUrl";
+    public static final String MAJOR_DIMENSION = PROPERTY_PREFIX + "MajorDimension";
+    public static final String RANGE = PROPERTY_PREFIX + "Range";
+    public static final String RANGE_INDEX = PROPERTY_PREFIX + "RangeIndex";
+    public static final String VALUE_INDEX = PROPERTY_PREFIX + "ValueIndex";
+
+    /**
+     * Prevent instantiation.
+     */
+    private GoogleSheetsStreamConstants() {
+        super();
+    }
+}
diff --git a/components/camel-google-sheets/src/main/java/org/apache/camel/component/google/sheets/stream/GoogleSheetsStreamConsumer.java b/components/camel-google-sheets/src/main/java/org/apache/camel/component/google/sheets/stream/GoogleSheetsStreamConsumer.java
new file mode 100644
index 00000000000..35b88152dca
--- /dev/null
+++ b/components/camel-google-sheets/src/main/java/org/apache/camel/component/google/sheets/stream/GoogleSheetsStreamConsumer.java
@@ -0,0 +1,135 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.camel.component.google.sheets.stream;
+
+import java.util.ArrayDeque;
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.Queue;
+import java.util.concurrent.atomic.AtomicInteger;
+import java.util.stream.Collectors;
+
+import com.google.api.services.sheets.v4.Sheets;
+import com.google.api.services.sheets.v4.model.BatchGetValuesResponse;
+import com.google.api.services.sheets.v4.model.Spreadsheet;
+import com.google.api.services.sheets.v4.model.ValueRange;
+import org.apache.camel.Endpoint;
+import org.apache.camel.Exchange;
+import org.apache.camel.Processor;
+import org.apache.camel.impl.ScheduledBatchPollingConsumer;
+import org.apache.camel.util.CastUtils;
+import org.apache.camel.util.ObjectHelper;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+/**
+ * The GoogleSheets consumer.
+ */
+public class GoogleSheetsStreamConsumer extends ScheduledBatchPollingConsumer {
+
+    private static final Logger LOG = LoggerFactory.getLogger(GoogleSheetsStreamConsumer.class);
+
+    public GoogleSheetsStreamConsumer(Endpoint endpoint, Processor processor) {
+        super(endpoint, processor);
+    }
+
+    protected GoogleSheetsStreamConfiguration getConfiguration() {
+        return getEndpoint().getConfiguration();
+    }
+
+    protected Sheets getClient() {
+        return getEndpoint().getClient();
+    }
+
+    @Override
+    public GoogleSheetsStreamEndpoint getEndpoint() {
+        return (GoogleSheetsStreamEndpoint)super.getEndpoint();
+    }
+
+    @Override
+    protected int poll() throws Exception {
+        Queue<Exchange> answer = new ArrayDeque<>();
+
+        if (ObjectHelper.isNotEmpty(getConfiguration().getRange())) {
+            Sheets.Spreadsheets.Values.BatchGet request = getClient().spreadsheets().values().batchGet(getConfiguration().getSpreadsheetId());
+
+            request.setMajorDimension(getConfiguration().getMajorDimension());
+            request.setValueRenderOption(getConfiguration().getValueRenderOption());
+
+            if (getConfiguration().getRange().contains(",")) {
+                request.setRanges(Arrays.stream(getConfiguration().getRange().split(","))
+                        .map(String::trim)
+                        .collect(Collectors.toList()));
+            } else {
+                request.setRanges(Collections.singletonList(getConfiguration().getRange()));
+            }
+
+            BatchGetValuesResponse response = request.execute();
+
+            if (response.getValueRanges() != null) {
+                if (getConfiguration().isSplitResults()) {
+                    for (ValueRange valueRange : response.getValueRanges()) {
+                        AtomicInteger rangeIndex = new AtomicInteger(1);
+                        AtomicInteger valueIndex = new AtomicInteger();
+                        valueRange.getValues().stream()
+                            .limit(getConfiguration().getMaxResults())
+                            .map(values -> getEndpoint().createExchange(rangeIndex.get(), valueIndex.incrementAndGet(), valueRange.getRange(), valueRange.getMajorDimension(), values))
+                            .forEach(answer::add);
+                        rangeIndex.incrementAndGet();
+                    }
+                } else {
+                    AtomicInteger rangeIndex = new AtomicInteger();
+                    response.getValueRanges()
+                            .stream()
+                            .limit(getConfiguration().getMaxResults())
+                            .map(valueRange -> getEndpoint().createExchange(rangeIndex.incrementAndGet(), valueRange))
+                            .forEach(answer::add);
+                }
+            }
+        } else {
+            Sheets.Spreadsheets.Get request = getClient().spreadsheets().get(getConfiguration().getSpreadsheetId());
+
+            request.setIncludeGridData(getConfiguration().isIncludeGridData());
+
+            Spreadsheet spreadsheet = request.execute();
+            answer.add(getEndpoint().createExchange(spreadsheet));
+        }
+
+        return processBatch(CastUtils.cast(answer));
+    }
+
+    @Override
+    public int processBatch(Queue<Object> exchanges) throws Exception {
+        int total = exchanges.size();
+
+        for (int index = 0; index < total && isBatchAllowed(); index++) {
+            // only loop if we are started (allowed to run)
+            final Exchange exchange = ObjectHelper.cast(Exchange.class, exchanges.poll());
+            // add current index and total as properties
+            exchange.setProperty(Exchange.BATCH_INDEX, index);
+            exchange.setProperty(Exchange.BATCH_SIZE, total);
+            exchange.setProperty(Exchange.BATCH_COMPLETE, index == total - 1);
+
+            // update pending number of exchanges
+            pendingExchanges = total - index - 1;
+
+            getAsyncProcessor().process(exchange, doneSync -> LOG.trace("Processing exchange done"));
+        }
+
+        return total;
+    }
+}
diff --git a/components/camel-google-sheets/src/main/java/org/apache/camel/component/google/sheets/stream/GoogleSheetsStreamEndpoint.java b/components/camel-google-sheets/src/main/java/org/apache/camel/component/google/sheets/stream/GoogleSheetsStreamEndpoint.java
new file mode 100644
index 00000000000..6d2adaff155
--- /dev/null
+++ b/components/camel-google-sheets/src/main/java/org/apache/camel/component/google/sheets/stream/GoogleSheetsStreamEndpoint.java
@@ -0,0 +1,118 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.camel.component.google.sheets.stream;
+
+import java.util.List;
+
+import com.google.api.services.sheets.v4.Sheets;
+import com.google.api.services.sheets.v4.model.Spreadsheet;
+import com.google.api.services.sheets.v4.model.ValueRange;
+import org.apache.camel.Consumer;
+import org.apache.camel.Exchange;
+import org.apache.camel.Message;
+import org.apache.camel.Processor;
+import org.apache.camel.Producer;
+import org.apache.camel.component.google.sheets.GoogleSheetsClientFactory;
+import org.apache.camel.impl.ScheduledPollEndpoint;
+import org.apache.camel.spi.UriEndpoint;
+import org.apache.camel.spi.UriParam;
+
+/**
+ * The google-sheets component provides access to Google Sheets.
+ */
+@UriEndpoint(firstVersion = "2.23.0",
+        scheme = "google-sheets-stream",
+        title = "Google Sheets Stream",
+        syntax = "google-sheets-stream:apiName",
+        consumerClass = GoogleSheetsStreamConsumer.class,
+        consumerOnly = true,
+        label = "api,cloud,sheets")
+public class GoogleSheetsStreamEndpoint extends ScheduledPollEndpoint {
+
+    @UriParam
+    private GoogleSheetsStreamConfiguration configuration;
+
+    public GoogleSheetsStreamEndpoint(String uri, GoogleSheetsStreamComponent component, GoogleSheetsStreamConfiguration endpointConfiguration) {
+        super(uri, component);
+        this.configuration = endpointConfiguration;
+    }
+
+    @Override
+    public Producer createProducer() throws Exception {
+        throw new UnsupportedOperationException("The camel google sheets stream component doesn't support producer");
+    }
+
+    @Override
+    public Consumer createConsumer(Processor processor) throws Exception {
+        final GoogleSheetsStreamConsumer consumer = new GoogleSheetsStreamConsumer(this, processor);
+        configureConsumer(consumer);
+        return consumer;
+    }
+
+    public Sheets getClient() {
+        return ((GoogleSheetsStreamComponent)getComponent()).getClient(configuration);
+    }
+
+    public GoogleSheetsClientFactory getClientFactory() {
+        return ((GoogleSheetsStreamComponent)getComponent()).getClientFactory();
+    }
+
+    public void setClientFactory(GoogleSheetsClientFactory clientFactory) {
+        ((GoogleSheetsStreamComponent)getComponent()).setClientFactory(clientFactory);
+    }
+
+    public GoogleSheetsStreamConfiguration getConfiguration() {
+        return configuration;
+    }
+
+    @Override
+    public boolean isSingleton() {
+        return true;
+    }
+
+    public Exchange createExchange(int rangeIndex, ValueRange valueRange) {
+        Exchange exchange = super.createExchange(getExchangePattern());
+        Message message = exchange.getIn();
+        exchange.getIn().setHeader(GoogleSheetsStreamConstants.SPREADSHEET_ID, configuration.getSpreadsheetId());
+        exchange.getIn().setHeader(GoogleSheetsStreamConstants.RANGE, valueRange.getRange());
+        exchange.getIn().setHeader(GoogleSheetsStreamConstants.RANGE_INDEX, rangeIndex);
+        exchange.getIn().setHeader(GoogleSheetsStreamConstants.MAJOR_DIMENSION, valueRange.getMajorDimension());
+        message.setBody(valueRange);
+        return exchange;
+    }
+
+    public Exchange createExchange(int rangeIndex, int valueIndex, String range, String majorDimension, List<Object> values) {
+        Exchange exchange = super.createExchange(getExchangePattern());
+        Message message = exchange.getIn();
+        exchange.getIn().setHeader(GoogleSheetsStreamConstants.SPREADSHEET_ID, configuration.getSpreadsheetId());
+        exchange.getIn().setHeader(GoogleSheetsStreamConstants.RANGE_INDEX, rangeIndex);
+        exchange.getIn().setHeader(GoogleSheetsStreamConstants.VALUE_INDEX, valueIndex);
+        exchange.getIn().setHeader(GoogleSheetsStreamConstants.RANGE, range);
+        exchange.getIn().setHeader(GoogleSheetsStreamConstants.MAJOR_DIMENSION, majorDimension);
+        message.setBody(values);
+        return exchange;
+    }
+
+    public Exchange createExchange(Spreadsheet spreadsheet) {
+        Exchange exchange = super.createExchange(getExchangePattern());
+        Message message = exchange.getIn();
+        exchange.getIn().setHeader(GoogleSheetsStreamConstants.SPREADSHEET_ID, spreadsheet.getSpreadsheetId());
+        exchange.getIn().setHeader(GoogleSheetsStreamConstants.SPREADSHEET_URL, spreadsheet.getSpreadsheetUrl());
+        message.setBody(spreadsheet);
+        return exchange;
+    }
+}
diff --git a/components/camel-google-sheets/src/main/resources/META-INF/LICENSE.txt b/components/camel-google-sheets/src/main/resources/META-INF/LICENSE.txt
new file mode 100644
index 00000000000..6b0b1270ff0
--- /dev/null
+++ b/components/camel-google-sheets/src/main/resources/META-INF/LICENSE.txt
@@ -0,0 +1,203 @@
+
+                                 Apache License
+                           Version 2.0, January 2004
+                        http://www.apache.org/licenses/
+
+   TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
+
+   1. Definitions.
+
+      "License" shall mean the terms and conditions for use, reproduction,
+      and distribution as defined by Sections 1 through 9 of this document.
+
+      "Licensor" shall mean the copyright owner or entity authorized by
+      the copyright owner that is granting the License.
+
+      "Legal Entity" shall mean the union of the acting entity and all
+      other entities that control, are controlled by, or are under common
+      control with that entity. For the purposes of this definition,
+      "control" means (i) the power, direct or indirect, to cause the
+      direction or management of such entity, whether by contract or
+      otherwise, or (ii) ownership of fifty percent (50%) or more of the
+      outstanding shares, or (iii) beneficial ownership of such entity.
+
+      "You" (or "Your") shall mean an individual or Legal Entity
+      exercising permissions granted by this License.
+
+      "Source" form shall mean the preferred form for making modifications,
+      including but not limited to software source code, documentation
+      source, and configuration files.
+
+      "Object" form shall mean any form resulting from mechanical
+      transformation or translation of a Source form, including but
+      not limited to compiled object code, generated documentation,
+      and conversions to other media types.
+
+      "Work" shall mean the work of authorship, whether in Source or
+      Object form, made available under the License, as indicated by a
+      copyright notice that is included in or attached to the work
+      (an example is provided in the Appendix below).
+
+      "Derivative Works" shall mean any work, whether in Source or Object
+      form, that is based on (or derived from) the Work and for which the
+      editorial revisions, annotations, elaborations, or other modifications
+      represent, as a whole, an original work of authorship. For the purposes
+      of this License, Derivative Works shall not include works that remain
+      separable from, or merely link (or bind by name) to the interfaces of,
+      the Work and Derivative Works thereof.
+
+      "Contribution" shall mean any work of authorship, including
+      the original version of the Work and any modifications or additions
+      to that Work or Derivative Works thereof, that is intentionally
+      submitted to Licensor for inclusion in the Work by the copyright owner
+      or by an individual or Legal Entity authorized to submit on behalf of
+      the copyright owner. For the purposes of this definition, "submitted"
+      means any form of electronic, verbal, or written communication sent
+      to the Licensor or its representatives, including but not limited to
+      communication on electronic mailing lists, source code control systems,
+      and issue tracking systems that are managed by, or on behalf of, the
+      Licensor for the purpose of discussing and improving the Work, but
+      excluding communication that is conspicuously marked or otherwise
+      designated in writing by the copyright owner as "Not a Contribution."
+
+      "Contributor" shall mean Licensor and any individual or Legal Entity
+      on behalf of whom a Contribution has been received by Licensor and
+      subsequently incorporated within the Work.
+
+   2. Grant of Copyright License. Subject to the terms and conditions of
+      this License, each Contributor hereby grants to You a perpetual,
+      worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+      copyright license to reproduce, prepare Derivative Works of,
+      publicly display, publicly perform, sublicense, and distribute the
+      Work and such Derivative Works in Source or Object form.
+
+   3. Grant of Patent License. Subject to the terms and conditions of
+      this License, each Contributor hereby grants to You a perpetual,
+      worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+      (except as stated in this section) patent license to make, have made,
+      use, offer to sell, sell, import, and otherwise transfer the Work,
+      where such license applies only to those patent claims licensable
+      by such Contributor that are necessarily infringed by their
+      Contribution(s) alone or by combination of their Contribution(s)
+      with the Work to which such Contribution(s) was submitted. If You
+      institute patent litigation against any entity (including a
+      cross-claim or counterclaim in a lawsuit) alleging that the Work
+      or a Contribution incorporated within the Work constitutes direct
+      or contributory patent infringement, then any patent licenses
+      granted to You under this License for that Work shall terminate
+      as of the date such litigation is filed.
+
+   4. Redistribution. You may reproduce and distribute copies of the
+      Work or Derivative Works thereof in any medium, with or without
+      modifications, and in Source or Object form, provided that You
+      meet the following conditions:
+
+      (a) You must give any other recipients of the Work or
+          Derivative Works a copy of this License; and
+
+      (b) You must cause any modified files to carry prominent notices
+          stating that You changed the files; and
+
+      (c) You must retain, in the Source form of any Derivative Works
+          that You distribute, all copyright, patent, trademark, and
+          attribution notices from the Source form of the Work,
+          excluding those notices that do not pertain to any part of
+          the Derivative Works; and
+
+      (d) If the Work includes a "NOTICE" text file as part of its
+          distribution, then any Derivative Works that You distribute must
+          include a readable copy of the attribution notices contained
+          within such NOTICE file, excluding those notices that do not
+          pertain to any part of the Derivative Works, in at least one
+          of the following places: within a NOTICE text file distributed
+          as part of the Derivative Works; within the Source form or
+          documentation, if provided along with the Derivative Works; or,
+          within a display generated by the Derivative Works, if and
+          wherever such third-party notices normally appear. The contents
+          of the NOTICE file are for informational purposes only and
+          do not modify the License. You may add Your own attribution
+          notices within Derivative Works that You distribute, alongside
+          or as an addendum to the NOTICE text from the Work, provided
+          that such additional attribution notices cannot be construed
+          as modifying the License.
+
+      You may add Your own copyright statement to Your modifications and
+      may provide additional or different license terms and conditions
+      for use, reproduction, or distribution of Your modifications, or
+      for any such Derivative Works as a whole, provided Your use,
+      reproduction, and distribution of the Work otherwise complies with
+      the conditions stated in this License.
+
+   5. Submission of Contributions. Unless You explicitly state otherwise,
+      any Contribution intentionally submitted for inclusion in the Work
+      by You to the Licensor shall be under the terms and conditions of
+      this License, without any additional terms or conditions.
+      Notwithstanding the above, nothing herein shall supersede or modify
+      the terms of any separate license agreement you may have executed
+      with Licensor regarding such Contributions.
+
+   6. Trademarks. This License does not grant permission to use the trade
+      names, trademarks, service marks, or product names of the Licensor,
+      except as required for reasonable and customary use in describing the
+      origin of the Work and reproducing the content of the NOTICE file.
+
+   7. Disclaimer of Warranty. Unless required by applicable law or
+      agreed to in writing, Licensor provides the Work (and each
+      Contributor provides its Contributions) on an "AS IS" BASIS,
+      WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
+      implied, including, without limitation, any warranties or conditions
+      of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
+      PARTICULAR PURPOSE. You are solely responsible for determining the
+      appropriateness of using or redistributing the Work and assume any
+      risks associated with Your exercise of permissions under this License.
+
+   8. Limitation of Liability. In no event and under no legal theory,
+      whether in tort (including negligence), contract, or otherwise,
+      unless required by applicable law (such as deliberate and grossly
+      negligent acts) or agreed to in writing, shall any Contributor be
+      liable to You for damages, including any direct, indirect, special,
+      incidental, or consequential damages of any character arising as a
+      result of this License or out of the use or inability to use the
+      Work (including but not limited to damages for loss of goodwill,
+      work stoppage, computer failure or malfunction, or any and all
+      other commercial damages or losses), even if such Contributor
+      has been advised of the possibility of such damages.
+
+   9. Accepting Warranty or Additional Liability. While redistributing
+      the Work or Derivative Works thereof, You may choose to offer,
+      and charge a fee for, acceptance of support, warranty, indemnity,
+      or other liability obligations and/or rights consistent with this
+      License. However, in accepting such obligations, You may act only
+      on Your own behalf and on Your sole responsibility, not on behalf
+      of any other Contributor, and only if You agree to indemnify,
+      defend, and hold each Contributor harmless for any liability
+      incurred by, or claims asserted against, such Contributor by reason
+      of your accepting any such warranty or additional liability.
+
+   END OF TERMS AND CONDITIONS
+
+   APPENDIX: How to apply the Apache License to your work.
+
+      To apply the Apache License to your work, attach the following
+      boilerplate notice, with the fields enclosed by brackets "[]"
+      replaced with your own identifying information. (Don't include
+      the brackets!)  The text should be enclosed in the appropriate
+      comment syntax for the file format. We also recommend that a
+      file or class name and description of purpose be included on the
+      same "printed page" as the copyright notice for easier
+      identification within third-party archives.
+
+   Copyright [yyyy] [name of copyright owner]
+
+   Licensed 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.
+
diff --git a/components/camel-google-sheets/src/main/resources/META-INF/NOTICE.txt b/components/camel-google-sheets/src/main/resources/META-INF/NOTICE.txt
new file mode 100644
index 00000000000..2e215bf2e6b
--- /dev/null
+++ b/components/camel-google-sheets/src/main/resources/META-INF/NOTICE.txt
@@ -0,0 +1,11 @@
+   =========================================================================
+   ==  NOTICE file corresponding to the section 4 d of                    ==
+   ==  the Apache License, Version 2.0,                                   ==
+   ==  in this case for the Apache Camel distribution.                    ==
+   =========================================================================
+
+   This product includes software developed by
+   The Apache Software Foundation (http://www.apache.org/).
+
+   Please read the different LICENSE files present in the licenses directory of
+   this distribution.
diff --git a/components/camel-google-sheets/src/main/resources/META-INF/services/org/apache/camel/component/google-sheets b/components/camel-google-sheets/src/main/resources/META-INF/services/org/apache/camel/component/google-sheets
new file mode 100644
index 00000000000..a3e7e265002
--- /dev/null
+++ b/components/camel-google-sheets/src/main/resources/META-INF/services/org/apache/camel/component/google-sheets
@@ -0,0 +1,17 @@
+#
+# 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.
+#
+class=org.apache.camel.component.google.sheets.GoogleSheetsComponent
diff --git a/components/camel-google-sheets/src/main/resources/META-INF/services/org/apache/camel/component/google-sheets-stream b/components/camel-google-sheets/src/main/resources/META-INF/services/org/apache/camel/component/google-sheets-stream
new file mode 100644
index 00000000000..0ac26794364
--- /dev/null
+++ b/components/camel-google-sheets/src/main/resources/META-INF/services/org/apache/camel/component/google-sheets-stream
@@ -0,0 +1,17 @@
+#
+# 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.
+#
+class=org.apache.camel.component.google.sheets.stream.GoogleSheetsStreamComponent
diff --git a/components/camel-google-sheets/src/test/java/org/apache/camel/component/google/sheets/AbstractGoogleSheetsTestSupport.java b/components/camel-google-sheets/src/test/java/org/apache/camel/component/google/sheets/AbstractGoogleSheetsTestSupport.java
new file mode 100644
index 00000000000..d52905c8f10
--- /dev/null
+++ b/components/camel-google-sheets/src/test/java/org/apache/camel/component/google/sheets/AbstractGoogleSheetsTestSupport.java
@@ -0,0 +1,164 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.camel.component.google.sheets;
+
+import java.io.IOException;
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.Map;
+import java.util.Properties;
+import java.util.Random;
+
+import com.google.api.services.sheets.v4.model.Sheet;
+import com.google.api.services.sheets.v4.model.SheetProperties;
+import com.google.api.services.sheets.v4.model.Spreadsheet;
+import com.google.api.services.sheets.v4.model.SpreadsheetProperties;
+import com.google.api.services.sheets.v4.model.ValueRange;
+import org.apache.camel.CamelContext;
+import org.apache.camel.CamelExecutionException;
+import org.apache.camel.test.junit4.CamelTestSupport;
+import org.apache.camel.util.IntrospectionSupport;
+
+/**
+ * Abstract base class for GoogleSheets Integration tests generated by Camel
+ * API component maven plugin.
+ */
+public class AbstractGoogleSheetsTestSupport extends CamelTestSupport {
+
+    protected static final String TEST_SHEET = "TestData";
+    private static final String TEST_OPTIONS_PROPERTIES = "/test-options.properties";
+
+    private Spreadsheet spreadsheet;
+
+    /**
+     * Create test spreadsheet that is used throughout all tests.
+     */
+    private void createTestSpreadsheet() {
+        Spreadsheet spreadsheet = new Spreadsheet();
+        SpreadsheetProperties spreadsheetProperties = new SpreadsheetProperties();
+        spreadsheetProperties.setTitle("camel-sheets-" + Math.abs(new Random().nextInt()));
+
+        spreadsheet.setProperties(spreadsheetProperties);
+
+        Sheet sheet = new Sheet();
+        SheetProperties sheetProperties = new SheetProperties();
+        sheetProperties.setTitle(TEST_SHEET);
+        sheet.setProperties(sheetProperties);
+
+        spreadsheet.setSheets(Collections.singletonList(sheet));
+
+        this.spreadsheet = requestBody("google-sheets://spreadsheets/create?inBody=content", spreadsheet);
+    }
+
+    /**
+     * Add some initial test data to test spreadsheet.
+     */
+    private void createTestData() {
+        if (spreadsheet == null) {
+            createTestSpreadsheet();
+        }
+
+        ValueRange valueRange = new ValueRange();
+        valueRange.setValues(Arrays.asList(Arrays.asList("a1", "b1"), Arrays.asList("a2", "b2")));
+
+        final Map<String, Object> headers = new HashMap<>();
+        // parameter type is String
+        headers.put("CamelGoogleSheets.spreadsheetId", spreadsheet.getSpreadsheetId());
+        // parameter type is String
+        headers.put("CamelGoogleSheets.range", TEST_SHEET + "!A1:B2");
+
+        // parameter type is String
+        headers.put("CamelGoogleSheets.valueInputOption", "USER_ENTERED");
+
+        requestBodyAndHeaders("google-sheets://data/update?inBody=values", valueRange, headers);
+    }
+
+    @Override
+    protected CamelContext createCamelContext() throws Exception {
+
+        final CamelContext context = super.createCamelContext();
+
+        final GoogleSheetsConfiguration configuration = new GoogleSheetsConfiguration();
+        IntrospectionSupport.setProperties(configuration, getTestOptions());
+
+        // add GoogleSheetsComponent to Camel context
+        final GoogleSheetsComponent component = new GoogleSheetsComponent(context);
+        component.setConfiguration(configuration);
+        context.addComponent("google-sheets", component);
+
+        return context;
+    }
+
+    /**
+     * Read component configuration from TEST_OPTIONS_PROPERTIES.
+     * @return Map of component options.
+     * @throws IOException when TEST_OPTIONS_PROPERTIES could not be loaded.
+     */
+    protected Map<String, Object> getTestOptions() throws IOException {
+        final Properties properties = new Properties();
+        try {
+            properties.load(getClass().getResourceAsStream(TEST_OPTIONS_PROPERTIES));
+        } catch (Exception e) {
+            throw new IOException(String.format("%s could not be loaded: %s", TEST_OPTIONS_PROPERTIES, e.getMessage()), e);
+        }
+
+        Map<String, Object> options = new HashMap<>();
+        for (Map.Entry<Object, Object> entry : properties.entrySet()) {
+            options.put(entry.getKey().toString(), entry.getValue());
+        }
+
+        return options;
+    }
+
+    @Override
+    public boolean isCreateCamelContextPerClass() {
+        // only create the context once for this class
+        return true;
+    }
+
+    @SuppressWarnings("unchecked")
+    protected <T> T requestBodyAndHeaders(String endpointUri, Object body, Map<String, Object> headers) throws CamelExecutionException {
+        return (T) template().requestBodyAndHeaders(endpointUri, body, headers);
+    }
+
+    @SuppressWarnings("unchecked")
+    protected <T> T requestBody(String endpoint, Object body) throws CamelExecutionException {
+        return (T) template().requestBody(endpoint, body);
+    }
+
+    public Spreadsheet getSpreadsheet() {
+        if (spreadsheet == null) {
+            createTestSpreadsheet();
+        }
+        return spreadsheet;
+    }
+
+    public Spreadsheet getSpreadsheetWithTestData() {
+        if (spreadsheet == null) {
+            createTestSpreadsheet();
+        }
+
+        createTestData();
+
+        return spreadsheet;
+    }
+
+    public void setSpreadsheet(Spreadsheet sheet) {
+        this.spreadsheet = sheet;
+    }
+}
diff --git a/components/camel-google-sheets/src/test/java/org/apache/camel/component/google/sheets/GoogleSheetsVerifierExtensionTest.java b/components/camel-google-sheets/src/test/java/org/apache/camel/component/google/sheets/GoogleSheetsVerifierExtensionTest.java
new file mode 100644
index 00000000000..9af19c73eaa
--- /dev/null
+++ b/components/camel-google-sheets/src/test/java/org/apache/camel/component/google/sheets/GoogleSheetsVerifierExtensionTest.java
@@ -0,0 +1,68 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.camel.component.google.sheets;
+
+import java.util.HashMap;
+import java.util.Map;
+import java.util.UUID;
+
+import org.apache.camel.Component;
+import org.apache.camel.component.extension.ComponentVerifierExtension;
+import org.apache.camel.test.junit4.CamelTestSupport;
+import org.junit.Assert;
+import org.junit.Test;
+
+public class GoogleSheetsVerifierExtensionTest extends CamelTestSupport {
+
+    @Override
+    public boolean isUseRouteBuilder() {
+        return false;
+    }
+
+    @Test
+    public void testVerifyParameters() {
+        Component component = context().getComponent("google-sheets");
+
+        ComponentVerifierExtension verifier = component.getExtension(ComponentVerifierExtension.class)
+                                                       .orElseThrow(IllegalStateException::new);
+
+        Map<String, Object> parameters = new HashMap<>();
+        parameters.put("clientId", "l");
+        parameters.put("clientSecret", "k");
+        parameters.put("applicationName", "test");
+
+        ComponentVerifierExtension.Result result = verifier.verify(ComponentVerifierExtension.Scope.PARAMETERS, parameters);
+        Assert.assertEquals(ComponentVerifierExtension.Result.Status.OK, result.getStatus());
+    }
+
+    @Test
+    public void testVerifyConnectivity() {
+        Component component = context().getComponent("google-sheets");
+        ComponentVerifierExtension verifier = component.getExtension(ComponentVerifierExtension.class)
+                                                       .orElseThrow(IllegalStateException::new);
+
+        Map<String, Object> parameters = new HashMap<>();
+        parameters.put("clientId", "l");
+        parameters.put("clientSecret", "k");
+        parameters.put("applicationName", "test");
+        parameters.put("spreadsheetId", UUID.randomUUID().toString());
+
+        ComponentVerifierExtension.Result result = verifier.verify(ComponentVerifierExtension.Scope.CONNECTIVITY, parameters);
+        Assert.assertEquals(ComponentVerifierExtension.Result.Status.ERROR, result.getStatus());
+    }
+
+}
diff --git a/components/camel-google-sheets/src/test/java/org/apache/camel/component/google/sheets/SheetsConfigurationTest.java b/components/camel-google-sheets/src/test/java/org/apache/camel/component/google/sheets/SheetsConfigurationTest.java
new file mode 100644
index 00000000000..298ffaf61e2
--- /dev/null
+++ b/components/camel-google-sheets/src/test/java/org/apache/camel/component/google/sheets/SheetsConfigurationTest.java
@@ -0,0 +1,64 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.camel.component.google.sheets;
+
+import org.apache.camel.CamelContext;
+import org.apache.camel.builder.RouteBuilder;
+import org.apache.camel.component.google.sheets.internal.GoogleSheetsApiCollection;
+import org.apache.camel.component.google.sheets.internal.SheetsSpreadsheetsApiMethod;
+import org.apache.camel.impl.DefaultCamelContext;
+import org.apache.camel.test.junit4.CamelTestSupport;
+import org.junit.Test;
+
+public class SheetsConfigurationTest extends CamelTestSupport {
+
+    private static final String PATH_PREFIX = GoogleSheetsApiCollection.getCollection().getApiName(SheetsSpreadsheetsApiMethod.class).getName();
+    private static final String TEST_URI = "google-sheets://" + PATH_PREFIX + "/create?clientId=a&clientSecret=b&applicationName=c&accessToken=d&refreshToken=e";
+
+    @Override
+    protected CamelContext createCamelContext() throws Exception {
+        final CamelContext context = new DefaultCamelContext(createRegistry());
+
+        // add GoogleSheetsComponent to Camel context but don't set up configuration
+        final GoogleSheetsComponent component = new GoogleSheetsComponent(context);
+        context.addComponent("google-sheets", component);
+
+        return context;
+    }
+
+    @Test
+    public void testConfiguration() throws Exception {
+        GoogleSheetsEndpoint endpoint = getMandatoryEndpoint(TEST_URI, GoogleSheetsEndpoint.class);
+        GoogleSheetsConfiguration configuration = endpoint.getConfiguration();
+        assertNotNull(configuration);
+        assertEquals("a", configuration.getClientId());
+        assertEquals("b", configuration.getClientSecret());
+        assertEquals("c", configuration.getApplicationName());
+        assertEquals("d", configuration.getAccessToken());
+        assertEquals("e", configuration.getRefreshToken());
+    }
+
+    @Override
+    protected RouteBuilder createRouteBuilder() throws Exception {
+        return new RouteBuilder() {
+            @Override
+            public void configure() {
+                from("direct://CREATE").to(TEST_URI);
+            }
+        };
+    }
+}
diff --git a/components/camel-google-sheets/src/test/java/org/apache/camel/component/google/sheets/SheetsSpreadsheetsIntegrationTest.java b/components/camel-google-sheets/src/test/java/org/apache/camel/component/google/sheets/SheetsSpreadsheetsIntegrationTest.java
new file mode 100644
index 00000000000..800d0234426
--- /dev/null
+++ b/components/camel-google-sheets/src/test/java/org/apache/camel/component/google/sheets/SheetsSpreadsheetsIntegrationTest.java
@@ -0,0 +1,120 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.camel.component.google.sheets;
+
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.Map;
+import java.util.Random;
+
+import com.google.api.services.sheets.v4.model.BatchUpdateSpreadsheetRequest;
+import com.google.api.services.sheets.v4.model.BatchUpdateSpreadsheetResponse;
+import com.google.api.services.sheets.v4.model.Request;
+import com.google.api.services.sheets.v4.model.Spreadsheet;
+import com.google.api.services.sheets.v4.model.SpreadsheetProperties;
+import com.google.api.services.sheets.v4.model.UpdateSpreadsheetPropertiesRequest;
+
+import org.apache.camel.builder.RouteBuilder;
+import org.apache.camel.component.google.sheets.internal.GoogleSheetsApiCollection;
+import org.apache.camel.component.google.sheets.internal.SheetsSpreadsheetsApiMethod;
+import org.junit.Test;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+/**
+ * Test class for {@link com.google.api.services.sheets.v4.Sheets.Spreadsheets} APIs.
+ */
+public class SheetsSpreadsheetsIntegrationTest extends AbstractGoogleSheetsTestSupport {
+
+    private static final Logger LOG = LoggerFactory.getLogger(SheetsSpreadsheetsIntegrationTest.class);
+    private static final String PATH_PREFIX = GoogleSheetsApiCollection.getCollection().getApiName(SheetsSpreadsheetsApiMethod.class).getName();
+
+    @Test
+    public void testCreate() throws Exception {
+        String title = "camel-sheets-" + Math.abs(new Random().nextInt());
+        Spreadsheet sheetToCreate = new Spreadsheet();
+        SpreadsheetProperties sheetProperties = new SpreadsheetProperties();
+        sheetProperties.setTitle(title);
+
+        sheetToCreate.setProperties(sheetProperties);
+
+        // using com.google.api.services.sheets.v4.model.Spreadsheet message body for single parameter "content"
+        final Spreadsheet result = requestBody("direct://CREATE", sheetToCreate);
+
+        assertNotNull("create result is null", result);
+        assertEquals(title, result.getProperties().getTitle());
+
+        LOG.debug("create: " + result);
+    }
+
+    @Test
+    public void testGet() throws Exception {
+        Spreadsheet testSheet = getSpreadsheet();
+
+        // using String message body for single parameter "spreadsheetId"
+        final Spreadsheet result = requestBody("direct://GET", testSheet.getSpreadsheetId());
+
+        assertNotNull("get result is null", result);
+        assertEquals(testSheet.getSpreadsheetId(), result.getSpreadsheetId());
+
+        LOG.debug("get: " + result);
+    }
+
+    @Test
+    public void testBatchUpdate() throws Exception {
+        Spreadsheet testSheet = getSpreadsheet();
+        String updateTitle = "updated-" + testSheet.getProperties().getTitle();
+
+        final Map<String, Object> headers = new HashMap<>();
+        // parameter type is String
+        headers.put("CamelGoogleSheets.spreadsheetId", testSheet.getSpreadsheetId());
+        // parameter type is com.google.api.services.sheets.v4.model.BatchUpdateSpreadsheetRequest
+        headers.put("CamelGoogleSheets.batchUpdateSpreadsheetRequest", new BatchUpdateSpreadsheetRequest()
+                                                                            .setIncludeSpreadsheetInResponse(true)
+                                                                            .setRequests(Collections.singletonList(new Request().setUpdateSpreadsheetProperties(new UpdateSpreadsheetPropertiesRequest()
+                                                                                    .setProperties(new SpreadsheetProperties().setTitle(updateTitle))
+                                                                                    .setFields("title")))));
+
+        final BatchUpdateSpreadsheetResponse result = requestBodyAndHeaders("direct://BATCHUPDATE", null, headers);
+
+        assertNotNull("batchUpdate result in null", result);
+        assertEquals(updateTitle, result.getUpdatedSpreadsheet().getProperties().getTitle());
+
+        LOG.debug("batchUpdate: " + result);
+    }
+
+    @Override
+    protected RouteBuilder createRouteBuilder() throws Exception {
+        return new RouteBuilder() {
+            @Override
+            public void configure() {
+                // test route for batchUpdate
+                from("direct://BATCHUPDATE")
+                        .to("google-sheets://" + PATH_PREFIX + "/batchUpdate");
+
+                // test route for create
+                from("direct://CREATE")
+                        .to("google-sheets://" + PATH_PREFIX + "/create?inBody=content");
+
+                // test route for get
+                from("direct://GET")
+                        .to("google-sheets://" + PATH_PREFIX + "/get?inBody=spreadsheetId");
+
+            }
+        };
+    }
+}
diff --git a/components/camel-google-sheets/src/test/java/org/apache/camel/component/google/sheets/SheetsSpreadsheetsValuesIntegrationTest.java b/components/camel-google-sheets/src/test/java/org/apache/camel/component/google/sheets/SheetsSpreadsheetsValuesIntegrationTest.java
new file mode 100644
index 00000000000..0075f7a3d64
--- /dev/null
+++ b/components/camel-google-sheets/src/test/java/org/apache/camel/component/google/sheets/SheetsSpreadsheetsValuesIntegrationTest.java
@@ -0,0 +1,169 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.camel.component.google.sheets;
+
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+import com.google.api.services.sheets.v4.model.AppendValuesResponse;
+import com.google.api.services.sheets.v4.model.ClearValuesRequest;
+import com.google.api.services.sheets.v4.model.ClearValuesResponse;
+import com.google.api.services.sheets.v4.model.Spreadsheet;
+import com.google.api.services.sheets.v4.model.UpdateValuesResponse;
+import com.google.api.services.sheets.v4.model.ValueRange;
+
+import org.apache.camel.builder.RouteBuilder;
+import org.apache.camel.component.google.sheets.internal.GoogleSheetsApiCollection;
+import org.apache.camel.component.google.sheets.internal.SheetsSpreadsheetsValuesApiMethod;
+import org.junit.Test;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+/**
+ * Test class for {@link com.google.api.services.sheets.v4.Sheets.Spreadsheets.Values} APIs.
+ */
+public class SheetsSpreadsheetsValuesIntegrationTest extends AbstractGoogleSheetsTestSupport {
+
+    private static final Logger LOG = LoggerFactory.getLogger(SheetsSpreadsheetsValuesIntegrationTest.class);
+    private static final String PATH_PREFIX = GoogleSheetsApiCollection.getCollection().getApiName(SheetsSpreadsheetsValuesApiMethod.class).getName();
+
+    @Test
+    public void testGet() throws Exception {
+        Spreadsheet testSheet = getSpreadsheet();
+
+        final Map<String, Object> headers = new HashMap<>();
+        // parameter type is String
+        headers.put("CamelGoogleSheets.spreadsheetId", testSheet.getSpreadsheetId());
+        // parameter type is String
+        headers.put("CamelGoogleSheets.range", TEST_SHEET + "!A1:B2");
+
+        final ValueRange result = requestBodyAndHeaders("direct://GET", null, headers);
+
+        assertNotNull("get result is null", result);
+        assertEquals(TEST_SHEET + "!A1:B2", result.getRange());
+        assertNull("expected empty value range but found entries", result.getValues());
+
+        LOG.debug("get: " + result);
+    }
+
+    @Test
+    public void testUpdate() throws Exception {
+        Spreadsheet testSheet = getSpreadsheet();
+
+        List<List<Object>> data = Arrays.asList(
+                Arrays.asList("A1", "B1"),
+                Arrays.asList("A2", "B2")
+        );
+        ValueRange values = new ValueRange();
+        values.setValues(data);
+
+        final Map<String, Object> headers = new HashMap<>();
+        // parameter type is String
+        headers.put("CamelGoogleSheets.spreadsheetId", testSheet.getSpreadsheetId());
+        // parameter type is String
+        headers.put("CamelGoogleSheets.range", TEST_SHEET + "!A1:B2");
+        // parameter type is com.google.api.services.sheets.v4.model.ValueRange
+        headers.put("CamelGoogleSheets.values", values);
+
+        // parameter type is String
+        headers.put("CamelGoogleSheets.valueInputOption", "USER_ENTERED");
+
+        final UpdateValuesResponse result = requestBodyAndHeaders("direct://UPDATE", null, headers);
+
+        assertNotNull("update result is null", result);
+        assertEquals(testSheet.getSpreadsheetId(), result.getSpreadsheetId());
+        assertEquals(TEST_SHEET + "!A1:B2", result.getUpdatedRange());
+        assertEquals(Integer.valueOf(2), result.getUpdatedRows());
+        assertEquals(Integer.valueOf(4), result.getUpdatedCells());
+
+        LOG.debug("update: " + result);
+    }
+
+    @Test
+    public void testAppend() throws Exception {
+        Spreadsheet testSheet = getSpreadsheet();
+
+        final Map<String, Object> headers = new HashMap<>();
+        // parameter type is String
+        headers.put("CamelGoogleSheets.spreadsheetId", testSheet.getSpreadsheetId());
+        // parameter type is String
+        headers.put("CamelGoogleSheets.range", TEST_SHEET + "!A10");
+        // parameter type is com.google.api.services.sheets.v4.model.ValueRange
+        headers.put("CamelGoogleSheets.values", new ValueRange().setValues(Collections.singletonList(Arrays.asList("A10", "B10", "C10"))));
+
+        // parameter type is String
+        headers.put("CamelGoogleSheets.valueInputOption", "USER_ENTERED");
+
+        final AppendValuesResponse result = requestBodyAndHeaders("direct://APPEND", null, headers);
+
+        assertNotNull("append result is null", result);
+        assertEquals(testSheet.getSpreadsheetId(), result.getSpreadsheetId());
+        assertEquals(TEST_SHEET + "!A10:C10", result.getUpdates().getUpdatedRange());
+        assertEquals(Integer.valueOf(1), result.getUpdates().getUpdatedRows());
+        assertEquals(Integer.valueOf(3), result.getUpdates().getUpdatedCells());
+
+        LOG.debug("append: " + result);
+    }
+
+    @Test
+    public void testClear() throws Exception {
+        Spreadsheet testSheet = getSpreadsheetWithTestData();
+
+        final Map<String, Object> headers = new HashMap<>();
+        // parameter type is String
+        headers.put("CamelGoogleSheets.spreadsheetId", testSheet.getSpreadsheetId());
+        // parameter type is String
+        headers.put("CamelGoogleSheets.range", TEST_SHEET + "!A1:B2");
+        // parameter type is com.google.api.services.sheets.v4.model.ClearValuesRequest
+        headers.put("CamelGoogleSheets.clearValuesRequest", new ClearValuesRequest());
+
+        final ClearValuesResponse result = requestBodyAndHeaders("direct://CLEAR", null, headers);
+
+        assertNotNull("clear result is null", result);
+        assertEquals(testSheet.getSpreadsheetId(), result.getSpreadsheetId());
+        assertEquals(TEST_SHEET + "!A1:B2", result.getClearedRange());
+
+        LOG.debug("clear: " + result);
+    }
+
+    @Override
+    protected RouteBuilder createRouteBuilder() throws Exception {
+        return new RouteBuilder() {
+            @Override
+            public void configure() {
+                // test route for append
+                from("direct://APPEND")
+                        .to("google-sheets://" + PATH_PREFIX + "/append");
+
+                // test route for clear
+                from("direct://CLEAR")
+                        .to("google-sheets://" + PATH_PREFIX + "/clear");
+
+                // test route for get
+                from("direct://GET")
+                        .to("google-sheets://" + PATH_PREFIX + "/get");
+
+                // test route for update
+                from("direct://UPDATE")
+                        .to("google-sheets://" + PATH_PREFIX + "/update");
+            }
+        };
+    }
+}
diff --git a/components/camel-google-sheets/src/test/java/org/apache/camel/component/google/sheets/stream/AbstractGoogleSheetsStreamTestSupport.java b/components/camel-google-sheets/src/test/java/org/apache/camel/component/google/sheets/stream/AbstractGoogleSheetsStreamTestSupport.java
new file mode 100644
index 00000000000..4767a0cbd12
--- /dev/null
+++ b/components/camel-google-sheets/src/test/java/org/apache/camel/component/google/sheets/stream/AbstractGoogleSheetsStreamTestSupport.java
@@ -0,0 +1,44 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.camel.component.google.sheets.stream;
+
+import org.apache.camel.CamelContext;
+import org.apache.camel.component.google.sheets.AbstractGoogleSheetsTestSupport;
+import org.apache.camel.util.IntrospectionSupport;
+
+/**
+ * Abstract base class for GoogleSheets Integration tests generated by Camel API
+ * component maven plugin.
+ */
+public class AbstractGoogleSheetsStreamTestSupport extends AbstractGoogleSheetsTestSupport {
+
+    @Override
+    protected CamelContext createCamelContext() throws Exception {
+
+        final CamelContext context = super.createCamelContext();
+
+        final GoogleSheetsStreamConfiguration configuration = new GoogleSheetsStreamConfiguration();
+        IntrospectionSupport.setProperties(configuration, getTestOptions());
+
+        // add GoogleSheetsComponent to Camel context
+        final GoogleSheetsStreamComponent component = new GoogleSheetsStreamComponent(context);
+        component.setConfiguration(configuration);
+        context.addComponent("google-sheets-stream", component);
+
+        return context;
+    }
+}
diff --git a/components/camel-google-sheets/src/test/java/org/apache/camel/component/google/sheets/stream/SheetsStreamConsumerIntegrationTest.java b/components/camel-google-sheets/src/test/java/org/apache/camel/component/google/sheets/stream/SheetsStreamConsumerIntegrationTest.java
new file mode 100644
index 00000000000..2aa7c5d666b
--- /dev/null
+++ b/components/camel-google-sheets/src/test/java/org/apache/camel/component/google/sheets/stream/SheetsStreamConsumerIntegrationTest.java
@@ -0,0 +1,123 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.camel.component.google.sheets.stream;
+
+import java.util.List;
+
+import com.google.api.services.sheets.v4.model.Spreadsheet;
+import com.google.api.services.sheets.v4.model.ValueRange;
+import org.apache.camel.Exchange;
+import org.apache.camel.builder.RouteBuilder;
+import org.apache.camel.component.mock.MockEndpoint;
+import org.junit.Assert;
+import org.junit.Test;
+
+import static org.apache.camel.component.google.sheets.stream.GoogleSheetsStreamConstants.MAJOR_DIMENSION;
+import static org.apache.camel.component.google.sheets.stream.GoogleSheetsStreamConstants.RANGE;
+import static org.apache.camel.component.google.sheets.stream.GoogleSheetsStreamConstants.RANGE_INDEX;
+import static org.apache.camel.component.google.sheets.stream.GoogleSheetsStreamConstants.SPREADSHEET_ID;
+import static org.apache.camel.component.google.sheets.stream.GoogleSheetsStreamConstants.VALUE_INDEX;
+
+public class SheetsStreamConsumerIntegrationTest extends AbstractGoogleSheetsStreamTestSupport {
+
+    private String range = "A1:B2";
+
+    @Test
+    public void testConsumeValueRange() throws Exception {
+        Spreadsheet testSheet = getSpreadsheetWithTestData();
+
+        context().addRoutes(createGoogleStreamRouteBuilder(testSheet.getSpreadsheetId()));
+        context().startRoute("google-stream-test");
+
+        MockEndpoint mock = getMockEndpoint("mock:result");
+        mock.expectedMinimumMessageCount(1);
+        assertMockEndpointsSatisfied();
+
+        Exchange exchange = mock.getReceivedExchanges().get(0);
+        Assert.assertTrue(exchange.getIn().getHeaders().containsKey(SPREADSHEET_ID));
+        Assert.assertTrue(exchange.getIn().getHeaders().containsKey(RANGE));
+        Assert.assertTrue(exchange.getIn().getHeaders().containsKey(RANGE_INDEX));
+        Assert.assertTrue(exchange.getIn().getHeaders().containsKey(MAJOR_DIMENSION));
+        Assert.assertEquals(testSheet.getSpreadsheetId(), exchange.getIn().getHeaders().get(SPREADSHEET_ID));
+        Assert.assertEquals(TEST_SHEET + "!" + range, exchange.getIn().getHeaders().get(RANGE));
+        Assert.assertEquals(1, exchange.getIn().getHeaders().get(RANGE_INDEX));
+        Assert.assertEquals("ROWS", exchange.getIn().getHeaders().get(MAJOR_DIMENSION));
+
+        ValueRange values = (ValueRange) exchange.getIn().getBody();
+        Assert.assertEquals(2L, values.getValues().size());
+        Assert.assertEquals("a1", values.getValues().get(0).get(0));
+        Assert.assertEquals("b1", values.getValues().get(0).get(1));
+        Assert.assertEquals("a2", values.getValues().get(1).get(0));
+        Assert.assertEquals("b2", values.getValues().get(1).get(1));
+    }
+
+    @Test
+    public void testConsumeRowValues() throws Exception {
+        Spreadsheet testSheet = getSpreadsheetWithTestData();
+
+        context().addRoutes(createGoogleStreamRouteBuilder(testSheet.getSpreadsheetId()));
+        context().startRoute("google-stream-values-test");
+
+        MockEndpoint mock = getMockEndpoint("mock:rows");
+        mock.expectedMinimumMessageCount(2);
+        assertMockEndpointsSatisfied();
+
+        Exchange exchange = mock.getReceivedExchanges().get(0);
+        Assert.assertTrue(exchange.getIn().getHeaders().containsKey(SPREADSHEET_ID));
+        Assert.assertTrue(exchange.getIn().getHeaders().containsKey(RANGE));
+        Assert.assertTrue(exchange.getIn().getHeaders().containsKey(RANGE_INDEX));
+        Assert.assertTrue(exchange.getIn().getHeaders().containsKey(VALUE_INDEX));
+        Assert.assertTrue(exchange.getIn().getHeaders().containsKey(MAJOR_DIMENSION));
+        Assert.assertEquals(testSheet.getSpreadsheetId(), exchange.getIn().getHeaders().get(SPREADSHEET_ID));
+        Assert.assertEquals(TEST_SHEET + "!" + range, exchange.getIn().getHeaders().get(RANGE));
+        Assert.assertEquals(1, exchange.getIn().getHeaders().get(RANGE_INDEX));
+        Assert.assertEquals(1, exchange.getIn().getHeaders().get(VALUE_INDEX));
+        Assert.assertEquals("ROWS", exchange.getIn().getHeaders().get(MAJOR_DIMENSION));
+
+        List<?> values = (List) exchange.getIn().getBody();
+        Assert.assertEquals(2L, values.size());
+        Assert.assertEquals("a1", values.get(0));
+        Assert.assertEquals("b1", values.get(1));
+
+        exchange = mock.getReceivedExchanges().get(1);
+        Assert.assertTrue(exchange.getIn().getHeaders().containsKey(SPREADSHEET_ID));
+        Assert.assertTrue(exchange.getIn().getHeaders().containsKey(RANGE));
+        Assert.assertTrue(exchange.getIn().getHeaders().containsKey(RANGE_INDEX));
+        Assert.assertTrue(exchange.getIn().getHeaders().containsKey(VALUE_INDEX));
+        Assert.assertTrue(exchange.getIn().getHeaders().containsKey(MAJOR_DIMENSION));
+        Assert.assertEquals(testSheet.getSpreadsheetId(), exchange.getIn().getHeaders().get(SPREADSHEET_ID));
+        Assert.assertEquals(1, exchange.getIn().getHeaders().get(RANGE_INDEX));
+        Assert.assertEquals(2, exchange.getIn().getHeaders().get(VALUE_INDEX));
+
+        values = (List) exchange.getIn().getBody();
+        Assert.assertEquals(2L, values.size());
+        Assert.assertEquals("a2", values.get(0));
+        Assert.assertEquals("b2", values.get(1));
+    }
+
+    private RouteBuilder createGoogleStreamRouteBuilder(String spreadsheetId) throws Exception {
+        return new RouteBuilder() {
+            @Override
+            public void configure() {
+                from("google-sheets-stream://data?spreadsheetId=" + spreadsheetId + "&range=" + range + "&delay=2000&maxResults=5").routeId("google-stream-test").to("mock:result");
+
+                from("google-sheets-stream://data?spreadsheetId=" + spreadsheetId 
+                    + "&range=" + range + "&delay=2000&maxResults=5&splitResults=true").routeId("google-stream-values-test").to("mock:rows");
+            }
+        };
+    }
+}
diff --git a/components/camel-google-sheets/src/test/resources/log4j2.properties b/components/camel-google-sheets/src/test/resources/log4j2.properties
new file mode 100644
index 00000000000..17088a953b3
--- /dev/null
+++ b/components/camel-google-sheets/src/test/resources/log4j2.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.
+## ---------------------------------------------------------------------------
+
+appender.file.type = File
+appender.file.name = file
+appender.file.fileName = target/camel-google-sheets-test.log
+appender.file.layout.type = PatternLayout
+appender.file.layout.pattern = %d [%-15.15t] %-5p %-30.30c{1} - %m%n
+appender.out.type = Console
+appender.out.name = out
+appender.out.layout.type = PatternLayout
+appender.out.layout.pattern = %d [%-15.15t] %-5p %-30.30c{1} - %m%n
+rootLogger.level = DEBUG
+rootLogger.appenderRef.file.ref = file
diff --git a/components/camel-google-sheets/src/test/resources/test-options.properties b/components/camel-google-sheets/src/test/resources/test-options.properties
new file mode 100644
index 00000000000..b21908cff57
--- /dev/null
+++ b/components/camel-google-sheets/src/test/resources/test-options.properties
@@ -0,0 +1,26 @@
+## ---------------------------------------------------------------------------
+## 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.
+## ---------------------------------------------------------------------------
+
+#####################################
+## Login properties for Google Sheets Component
+#####################################
+## Application client id and secret
+clientId=
+clientSecret=
+applicationName=camel-google-sheets/1.0
+accessToken=
+refreshToken=
diff --git a/components/camel-gora/pom.xml b/components/camel-gora/pom.xml
index abef2abed17..4368f35944e 100644
--- a/components/camel-gora/pom.xml
+++ b/components/camel-gora/pom.xml
@@ -25,7 +25,7 @@
   <parent>
     <groupId>org.apache.camel</groupId>
     <artifactId>components</artifactId>
-    <version>2.23.0-SNAPSHOT</version>
+    <version>2.24.0-SNAPSHOT</version>
   </parent>
 
   <artifactId>camel-gora</artifactId>
diff --git a/components/camel-grape/pom.xml b/components/camel-grape/pom.xml
index e408f6dc789..151d7edfed9 100644
--- a/components/camel-grape/pom.xml
+++ b/components/camel-grape/pom.xml
@@ -24,7 +24,7 @@
   <parent>
     <groupId>org.apache.camel</groupId>
     <artifactId>components</artifactId>
-    <version>2.23.0-SNAPSHOT</version>
+    <version>2.24.0-SNAPSHOT</version>
   </parent>
 
   <artifactId>camel-grape</artifactId>
diff --git a/components/camel-groovy-dsl/pom.xml b/components/camel-groovy-dsl/pom.xml
index 62ac12aef9c..5f52616e206 100644
--- a/components/camel-groovy-dsl/pom.xml
+++ b/components/camel-groovy-dsl/pom.xml
@@ -23,7 +23,7 @@
   <parent>
     <groupId>org.apache.camel</groupId>
     <artifactId>components</artifactId>
-    <version>2.23.0-SNAPSHOT</version>
+    <version>2.24.0-SNAPSHOT</version>
   </parent>
 
   <artifactId>camel-groovy-dsl</artifactId>
diff --git a/components/camel-groovy/pom.xml b/components/camel-groovy/pom.xml
index b80b2b94977..2f15443c14c 100644
--- a/components/camel-groovy/pom.xml
+++ b/components/camel-groovy/pom.xml
@@ -23,7 +23,7 @@
   <parent>
     <groupId>org.apache.camel</groupId>
     <artifactId>components</artifactId>
-    <version>2.23.0-SNAPSHOT</version>
+    <version>2.24.0-SNAPSHOT</version>
   </parent>
 
   <artifactId>camel-groovy</artifactId>
diff --git a/components/camel-grpc/pom.xml b/components/camel-grpc/pom.xml
index 18028687981..5cca9a968fd 100644
--- a/components/camel-grpc/pom.xml
+++ b/components/camel-grpc/pom.xml
@@ -25,7 +25,7 @@
   <parent>
     <groupId>org.apache.camel</groupId>
     <artifactId>components</artifactId>
-    <version>2.23.0-SNAPSHOT</version>
+    <version>2.24.0-SNAPSHOT</version>
   </parent>
 
   <artifactId>camel-grpc</artifactId>
diff --git a/components/camel-gson/pom.xml b/components/camel-gson/pom.xml
index ff3104b7cd9..7fda1797aab 100644
--- a/components/camel-gson/pom.xml
+++ b/components/camel-gson/pom.xml
@@ -23,7 +23,7 @@
     <parent>
         <groupId>org.apache.camel</groupId>
         <artifactId>components</artifactId>
-        <version>2.23.0-SNAPSHOT</version>
+        <version>2.24.0-SNAPSHOT</version>
     </parent>
 
     <artifactId>camel-gson</artifactId>
diff --git a/components/camel-guava-eventbus/pom.xml b/components/camel-guava-eventbus/pom.xml
index 55c7a4bdc30..d3294c6b078 100644
--- a/components/camel-guava-eventbus/pom.xml
+++ b/components/camel-guava-eventbus/pom.xml
@@ -23,7 +23,7 @@
     <parent>
         <groupId>org.apache.camel</groupId>
         <artifactId>components</artifactId>
-        <version>2.23.0-SNAPSHOT</version>
+        <version>2.24.0-SNAPSHOT</version>
     </parent>
 
     <artifactId>camel-guava-eventbus</artifactId>
diff --git a/components/camel-guice/pom.xml b/components/camel-guice/pom.xml
index dcda484dfbe..33e4e5fec11 100644
--- a/components/camel-guice/pom.xml
+++ b/components/camel-guice/pom.xml
@@ -23,7 +23,7 @@
   <parent>
     <groupId>org.apache.camel</groupId>
     <artifactId>components</artifactId>
-    <version>2.23.0-SNAPSHOT</version>
+    <version>2.24.0-SNAPSHOT</version>
   </parent>
 
   <artifactId>camel-guice</artifactId>
diff --git a/components/camel-hawtdb/pom.xml b/components/camel-hawtdb/pom.xml
index 51d2a06d15a..ae285b38cac 100644
--- a/components/camel-hawtdb/pom.xml
+++ b/components/camel-hawtdb/pom.xml
@@ -23,7 +23,7 @@
     <parent>
         <groupId>org.apache.camel</groupId>
         <artifactId>components</artifactId>
-        <version>2.23.0-SNAPSHOT</version>
+        <version>2.24.0-SNAPSHOT</version>
     </parent>
 
     <artifactId>camel-hawtdb</artifactId>
diff --git a/components/camel-hazelcast/pom.xml b/components/camel-hazelcast/pom.xml
index 2640a37d035..b1e5a622ea7 100644
--- a/components/camel-hazelcast/pom.xml
+++ b/components/camel-hazelcast/pom.xml
@@ -23,7 +23,7 @@
   <parent>
     <groupId>org.apache.camel</groupId>
     <artifactId>components</artifactId>
-    <version>2.23.0-SNAPSHOT</version>
+    <version>2.24.0-SNAPSHOT</version>
   </parent>
 
   <artifactId>camel-hazelcast</artifactId>
diff --git a/components/camel-hbase/pom.xml b/components/camel-hbase/pom.xml
index fd91cc8c4d3..3728b76667e 100644
--- a/components/camel-hbase/pom.xml
+++ b/components/camel-hbase/pom.xml
@@ -23,7 +23,7 @@
     <parent>
         <groupId>org.apache.camel</groupId>
         <artifactId>components</artifactId>
-        <version>2.23.0-SNAPSHOT</version>
+        <version>2.24.0-SNAPSHOT</version>
     </parent>
 
     <artifactId>camel-hbase</artifactId>
diff --git a/components/camel-hdfs/pom.xml b/components/camel-hdfs/pom.xml
index 5e04790bb30..6998423a5f8 100644
--- a/components/camel-hdfs/pom.xml
+++ b/components/camel-hdfs/pom.xml
@@ -23,7 +23,7 @@
     <parent>
         <groupId>org.apache.camel</groupId>
         <artifactId>components</artifactId>
-        <version>2.23.0-SNAPSHOT</version>
+        <version>2.24.0-SNAPSHOT</version>
     </parent>
 
     <artifactId>camel-hdfs</artifactId>
diff --git a/components/camel-hdfs2/pom.xml b/components/camel-hdfs2/pom.xml
index 0425af44ffe..513c8f2ce6e 100644
--- a/components/camel-hdfs2/pom.xml
+++ b/components/camel-hdfs2/pom.xml
@@ -23,7 +23,7 @@
   <parent>
     <groupId>org.apache.camel</groupId>
     <artifactId>components</artifactId>
-    <version>2.23.0-SNAPSHOT</version>
+    <version>2.24.0-SNAPSHOT</version>
   </parent>
 
   <artifactId>camel-hdfs2</artifactId>
diff --git a/components/camel-hdfs2/src/test/resources/hdfs-default.xml b/components/camel-hdfs2/src/test/resources/hdfs-default.xml
index 4143e0844d9..53af074450d 100644
--- a/components/camel-hdfs2/src/test/resources/hdfs-default.xml
+++ b/components/camel-hdfs2/src/test/resources/hdfs-default.xml
@@ -690,8 +690,8 @@
   <value>${dfs.namenode.checkpoint.dir}</value>
   <description>Determines where on the local filesystem the DFS secondary
       name node should store the temporary edits to merge.
-      If this is a comma-delimited list of directoires then teh edits is
-      replicated in all of the directoires for redundancy.
+      If this is a comma-delimited list of directories then the edits is
+      replicated in all of the directories for redundancy.
       Default value is same as dfs.namenode.checkpoint.dir
   </description>
 </property>
diff --git a/components/camel-hdfs2/src/test/resources/hdfs-test.xml b/components/camel-hdfs2/src/test/resources/hdfs-test.xml
index 5462dbeaf96..931556ea8a0 100644
--- a/components/camel-hdfs2/src/test/resources/hdfs-test.xml
+++ b/components/camel-hdfs2/src/test/resources/hdfs-test.xml
@@ -690,8 +690,8 @@
   <value>${dfs.namenode.checkpoint.dir}</value>
   <description>Determines where on the local filesystem the DFS secondary
       name node should store the temporary edits to merge.
-      If this is a comma-delimited list of directoires then teh edits is
-      replicated in all of the directoires for redundancy.
+      If this is a comma-delimited list of directories then the edits is
+      replicated in all of the directories for redundancy.
       Default value is same as dfs.namenode.checkpoint.dir
   </description>
 </property>
diff --git a/components/camel-headersmap/pom.xml b/components/camel-headersmap/pom.xml
index 1fc42a2a775..6021ac81e88 100644
--- a/components/camel-headersmap/pom.xml
+++ b/components/camel-headersmap/pom.xml
@@ -23,7 +23,7 @@
   <parent>
     <groupId>org.apache.camel</groupId>
     <artifactId>components</artifactId>
-    <version>2.23.0-SNAPSHOT</version>
+    <version>2.24.0-SNAPSHOT</version>
   </parent>
 
   <artifactId>camel-headersmap</artifactId>
diff --git a/components/camel-hessian/pom.xml b/components/camel-hessian/pom.xml
index 3a59df2b950..178dfbda4ff 100644
--- a/components/camel-hessian/pom.xml
+++ b/components/camel-hessian/pom.xml
@@ -26,7 +26,7 @@
     <parent>
         <groupId>org.apache.camel</groupId>
         <artifactId>components</artifactId>
-        <version>2.23.0-SNAPSHOT</version>
+        <version>2.24.0-SNAPSHOT</version>
     </parent>
 
     <artifactId>camel-hessian</artifactId>
diff --git a/components/camel-hipchat/pom.xml b/components/camel-hipchat/pom.xml
index 78b1613360a..fdb0867e0b2 100644
--- a/components/camel-hipchat/pom.xml
+++ b/components/camel-hipchat/pom.xml
@@ -24,7 +24,7 @@
   <parent>
     <groupId>org.apache.camel</groupId>
     <artifactId>components</artifactId>
-    <version>2.23.0-SNAPSHOT</version>
+    <version>2.24.0-SNAPSHOT</version>
   </parent>
 
   <artifactId>camel-hipchat</artifactId>
diff --git a/components/camel-hl7/pom.xml b/components/camel-hl7/pom.xml
index 6982cd36d6e..4433eccaa14 100644
--- a/components/camel-hl7/pom.xml
+++ b/components/camel-hl7/pom.xml
@@ -23,7 +23,7 @@
     <parent>
         <groupId>org.apache.camel</groupId>
         <artifactId>components</artifactId>
-        <version>2.23.0-SNAPSHOT</version>
+        <version>2.24.0-SNAPSHOT</version>
     </parent>
 
     <artifactId>camel-hl7</artifactId>
diff --git a/components/camel-http-common/pom.xml b/components/camel-http-common/pom.xml
index 90ee926c415..9d78644dc22 100644
--- a/components/camel-http-common/pom.xml
+++ b/components/camel-http-common/pom.xml
@@ -23,7 +23,7 @@
   <parent>
     <groupId>org.apache.camel</groupId>
     <artifactId>components</artifactId>
-    <version>2.23.0-SNAPSHOT</version>
+    <version>2.24.0-SNAPSHOT</version>
   </parent>
 
   <artifactId>camel-http-common</artifactId>
diff --git a/components/camel-http/pom.xml b/components/camel-http/pom.xml
index 73816ec099c..b1c167ce40d 100644
--- a/components/camel-http/pom.xml
+++ b/components/camel-http/pom.xml
@@ -23,7 +23,7 @@
   <parent>
     <groupId>org.apache.camel</groupId>
     <artifactId>components</artifactId>
-    <version>2.23.0-SNAPSHOT</version>
+    <version>2.24.0-SNAPSHOT</version>
   </parent>
 
   <artifactId>camel-http</artifactId>
diff --git a/components/camel-http4/pom.xml b/components/camel-http4/pom.xml
index 573d9f51056..32db9888762 100644
--- a/components/camel-http4/pom.xml
+++ b/components/camel-http4/pom.xml
@@ -23,7 +23,7 @@
   <parent>
     <groupId>org.apache.camel</groupId>
     <artifactId>components</artifactId>
-    <version>2.23.0-SNAPSHOT</version>
+    <version>2.24.0-SNAPSHOT</version>
   </parent>
 
   <artifactId>camel-http4</artifactId>
diff --git a/components/camel-hystrix/pom.xml b/components/camel-hystrix/pom.xml
index 932ae2ddd53..40804646b52 100644
--- a/components/camel-hystrix/pom.xml
+++ b/components/camel-hystrix/pom.xml
@@ -24,7 +24,7 @@
   <parent>
     <groupId>org.apache.camel</groupId>
     <artifactId>components</artifactId>
-    <version>2.23.0-SNAPSHOT</version>
+    <version>2.24.0-SNAPSHOT</version>
   </parent>
 
   <artifactId>camel-hystrix</artifactId>
diff --git a/components/camel-ibatis/pom.xml b/components/camel-ibatis/pom.xml
index 45ce4c1cd9d..d283bef98aa 100644
--- a/components/camel-ibatis/pom.xml
+++ b/components/camel-ibatis/pom.xml
@@ -23,7 +23,7 @@
   <parent>
     <groupId>org.apache.camel</groupId>
     <artifactId>components</artifactId>
-    <version>2.23.0-SNAPSHOT</version>
+    <version>2.24.0-SNAPSHOT</version>
   </parent>
 
   <artifactId>camel-ibatis</artifactId>
diff --git a/components/camel-ical/pom.xml b/components/camel-ical/pom.xml
index a8e7c486aad..472851911e6 100644
--- a/components/camel-ical/pom.xml
+++ b/components/camel-ical/pom.xml
@@ -24,7 +24,7 @@
   <parent>
     <groupId>org.apache.camel</groupId>
     <artifactId>components</artifactId>
-    <version>2.23.0-SNAPSHOT</version>
+    <version>2.24.0-SNAPSHOT</version>
   </parent>
 
   <artifactId>camel-ical</artifactId>
diff --git a/components/camel-iec60870/pom.xml b/components/camel-iec60870/pom.xml
index 222067c8f56..07012b1b20a 100644
--- a/components/camel-iec60870/pom.xml
+++ b/components/camel-iec60870/pom.xml
@@ -24,7 +24,7 @@
   <parent>
     <groupId>org.apache.camel</groupId>
     <artifactId>components</artifactId>
-    <version>2.23.0-SNAPSHOT</version>
+    <version>2.24.0-SNAPSHOT</version>
   </parent>
 
   <artifactId>camel-iec60870</artifactId>
diff --git a/components/camel-ignite/pom.xml b/components/camel-ignite/pom.xml
index d99a91e2c95..8d423a15094 100644
--- a/components/camel-ignite/pom.xml
+++ b/components/camel-ignite/pom.xml
@@ -23,7 +23,7 @@
   <parent>
     <groupId>org.apache.camel</groupId>
     <artifactId>components</artifactId>
-    <version>2.23.0-SNAPSHOT</version>
+    <version>2.24.0-SNAPSHOT</version>
   </parent>
 
   <artifactId>camel-ignite</artifactId>
diff --git a/components/camel-infinispan/pom.xml b/components/camel-infinispan/pom.xml
index ada6170a3e8..b0ba90701e9 100644
--- a/components/camel-infinispan/pom.xml
+++ b/components/camel-infinispan/pom.xml
@@ -24,7 +24,7 @@
     <parent>
         <groupId>org.apache.camel</groupId>
         <artifactId>components</artifactId>
-        <version>2.23.0-SNAPSHOT</version>
+        <version>2.24.0-SNAPSHOT</version>
     </parent>
 
     <artifactId>camel-infinispan</artifactId>
diff --git a/components/camel-influxdb/pom.xml b/components/camel-influxdb/pom.xml
index 466790a3049..5a79c1e7e78 100644
--- a/components/camel-influxdb/pom.xml
+++ b/components/camel-influxdb/pom.xml
@@ -16,7 +16,7 @@
 	<parent>
 		<groupId>org.apache.camel</groupId>
 		<artifactId>components</artifactId>
-		<version>2.23.0-SNAPSHOT</version>
+		<version>2.24.0-SNAPSHOT</version>
 	</parent>
 
 	<artifactId>camel-influxdb</artifactId>
diff --git a/components/camel-ipfs/pom.xml b/components/camel-ipfs/pom.xml
new file mode 100644
index 00000000000..ad9519417b5
--- /dev/null
+++ b/components/camel-ipfs/pom.xml
@@ -0,0 +1,76 @@
+<?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>
+    <artifactId>components</artifactId>
+    <groupId>org.apache.camel</groupId>
+    <version>2.24.0-SNAPSHOT</version>
+  </parent>
+
+  <artifactId>camel-ipfs</artifactId>
+  <packaging>jar</packaging>
+  <name>Camel :: IPFS</name>
+  <description>Camel IPFS support</description>
+
+  <properties>
+    <camel.osgi.export.pkg>org.apache.camel.component.ipfs.*</camel.osgi.export.pkg>
+    <camel.osgi.export.service>org.apache.camel.spi.ComponentResolver;component=ipfs</camel.osgi.export.service>
+  </properties>
+
+  <repositories>
+    <repository>
+      <id>jboss.thirdparty</id>
+      <name>JBoss Repository</name>
+      <url>https://repository.jboss.org/nexus/service/local/repositories/thirdparty-releases/content/</url>
+      <snapshots>
+        <enabled>false</enabled>
+      </snapshots>
+      <releases>
+        <enabled>true</enabled>
+      </releases>
+    </repository>
+  </repositories>
+
+  <dependencies>
+    <dependency>
+      <groupId>org.apache.camel</groupId>
+      <artifactId>camel-core</artifactId>
+    </dependency>
+    <dependency>
+      <groupId>io.nessus</groupId>
+      <artifactId>nessus-ipfs</artifactId>
+    </dependency>
+
+    <!-- Test -->
+    <dependency>
+      <groupId>junit</groupId>
+      <artifactId>junit</artifactId>
+      <scope>test</scope>
+    </dependency>
+    <dependency>
+      <groupId>org.apache.logging.log4j</groupId>
+      <artifactId>log4j-slf4j-impl</artifactId>
+      <scope>test</scope>
+    </dependency>
+  </dependencies>
+
+</project>
diff --git a/components/camel-ipfs/src/main/docs/ipfs-component.adoc b/components/camel-ipfs/src/main/docs/ipfs-component.adoc
new file mode 100644
index 00000000000..78f6742a3c4
--- /dev/null
+++ b/components/camel-ipfs/src/main/docs/ipfs-component.adoc
@@ -0,0 +1,96 @@
+[[ipfs-component]]
+== IPFS Component
+
+*Available as of Camel version 2.23*
+
+The *ipfs:* component provides access to the Interplanetary File System https://ipfs.io/[(IPFS)].
+
+Maven users will need to add the following dependency to their `pom.xml`
+for this component:
+
+[source,xml]
+------------------------------------------------------------
+<dependency>
+    <groupId>org.apache.camel</groupId>
+    <artifactId>camel-ipfs</artifactId>
+    <version>x.x.x</version>
+    <!-- use the same version as your Camel core version -->
+</dependency>
+------------------------------------------------------------
+
+### URI format
+
+[source,java]
+---------------------------------
+ipfs://cmd?options
+---------------------------------
+
+### Options
+
+// component options: START
+The IPFS component has no options.
+// component options: END
+
+// endpoint options: START
+The IPFS endpoint is configured using URI syntax:
+
+----
+ipfs:host:port/cmd
+----
+
+with the following path and query parameters:
+
+==== Path Parameters (1 parameters):
+
+
+[width="100%",cols="2,5,^1,2",options="header"]
+|===
+| Name | Description | Default | Type
+| *ipfsCmd* | The ipfs command |  | String
+|===
+
+
+==== Query Parameters (2 parameters):
+
+
+[width="100%",cols="2,5,^1,2",options="header"]
+|===
+| Name | Description | Default | Type
+| *outdir* (producer) | The ipfs output directory |  | Path
+| *synchronous* (advanced) | Sets whether synchronous processing should be strictly used, or Camel is allowed to use asynchronous processing (if supported). | false | boolean
+|===
+// endpoint options: END
+// spring-boot-auto-configure options: START
+=== Spring Boot Auto-Configuration
+
+
+The component supports 2 options, which are listed below.
+
+
+
+[width="100%",cols="2,5,^1,2",options="header"]
+|===
+| Name | Description | Default | Type
+| *camel.component.ipfs.enabled* | Whether to enable auto configuration of the ipfs component. This is enabled by default. |  | Boolean
+| *camel.component.ipfs.resolve-property-placeholders* | Whether the component should resolve property placeholders on itself when starting. Only properties which are of String type can use property placeholders. | true | Boolean
+|===
+// spring-boot-auto-configure options: END
+
+### Karaf support
+
+Actually this component is not supported in Karaf
+
+### Message Headers
+
+[TODO]
+
+### Samples
+
+In this sample we add a file to IPFS, get a file from IPFS and finally access the content of an IPFS file. 
+
+[source,java]
+---------------------------------------------------------------------------------------------
+from("direct:start").to("ipfs:add")
+from("direct:start").to("ipfs:get?outdir=target")
+from("direct:start").to("ipfs:cat");
+---------------------------------------------------------------------------------------------
diff --git a/components/camel-ipfs/src/main/java/org/apache/camel/component/ipfs/IPFSComponent.java b/components/camel-ipfs/src/main/java/org/apache/camel/component/ipfs/IPFSComponent.java
new file mode 100644
index 00000000000..f6cb6f85e3f
--- /dev/null
+++ b/components/camel-ipfs/src/main/java/org/apache/camel/component/ipfs/IPFSComponent.java
@@ -0,0 +1,68 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.camel.component.ipfs;
+
+import java.net.URI;
+import java.util.Map;
+
+import io.nessus.ipfs.IPFSClient;
+import io.nessus.ipfs.impl.DefaultIPFSClient;
+
+import org.apache.camel.Endpoint;
+import org.apache.camel.impl.DefaultComponent;
+
+public class IPFSComponent extends DefaultComponent {
+
+    private IPFSClient client;
+
+    @Override
+    protected Endpoint createEndpoint(String urispec, String remaining, Map<String, Object> params) throws Exception {
+
+        // Init the configuration
+        IPFSConfiguration config = new IPFSConfiguration(this);
+        setProperties(config, params);
+
+        // Derive host:port and cmd from the give uri
+        URI uri = new URI(urispec);
+        String host = uri.getHost();
+        int port = uri.getPort();
+        String cmd = remaining;
+        if (!cmd.equals(host)) {
+            if (host != null) {
+                config.setIpfsHost(host);
+            }
+            if (port > 0) {
+                config.setIpfsPort(port);
+            }
+            int idx = cmd.indexOf('/');
+            cmd = cmd.substring(idx + 1);
+        }
+        config.setIpfsCmd(cmd);
+
+        client = createClient(config);
+
+        return new IPFSEndpoint(urispec, this, config);
+    }
+
+    public IPFSClient getIPFSClient() {
+        return client;
+    }
+
+    private synchronized IPFSClient createClient(IPFSConfiguration config) {
+        return new DefaultIPFSClient(config.getIpfsHost(), config.getIpfsPort());
+    }
+}
diff --git a/components/camel-ipfs/src/main/java/org/apache/camel/component/ipfs/IPFSConfiguration.java b/components/camel-ipfs/src/main/java/org/apache/camel/component/ipfs/IPFSConfiguration.java
new file mode 100644
index 00000000000..5a78d647854
--- /dev/null
+++ b/components/camel-ipfs/src/main/java/org/apache/camel/component/ipfs/IPFSConfiguration.java
@@ -0,0 +1,79 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.camel.component.ipfs;
+
+
+import java.nio.file.Path;
+import java.nio.file.Paths;
+
+import org.apache.camel.spi.UriParam;
+import org.apache.camel.spi.UriParams;
+import org.apache.camel.spi.UriPath;
+import org.apache.camel.util.ObjectHelper;
+
+@UriParams
+public class IPFSConfiguration {
+
+    // Available commands
+    public enum IPFSCommand {
+        add, cat, get, version 
+    }
+    
+    @UriPath(description = "The ipfs command")
+    private String ipfsCmd;
+    @UriParam(description = "The ipfs output directory")
+    private Path outdir;
+
+    private String ipfsHost = "127.0.0.1";
+    private int ipfsPort = 5001;
+    
+    public IPFSConfiguration(IPFSComponent component) {
+        ObjectHelper.notNull(component, "component");
+    }
+
+    public String getIpfsCmd() {
+        return ipfsCmd;
+    }
+
+    public void setIpfsCmd(String cmd) {
+        this.ipfsCmd = cmd;
+    }
+
+    public String getIpfsHost() {
+        return ipfsHost;
+    }
+
+    public void setIpfsHost(String ipfsHost) {
+        this.ipfsHost = ipfsHost;
+    }
+
+    public int getIpfsPort() {
+        return ipfsPort;
+    }
+
+    public void setIpfsPort(int ipfsPort) {
+        this.ipfsPort = ipfsPort;
+    }
+
+    public Path getOutdir() {
+        return outdir;
+    }
+
+    public void setOutdir(String outdir) {
+        this.outdir = Paths.get(outdir);
+    }
+}
diff --git a/components/camel-ipfs/src/main/java/org/apache/camel/component/ipfs/IPFSEndpoint.java b/components/camel-ipfs/src/main/java/org/apache/camel/component/ipfs/IPFSEndpoint.java
new file mode 100644
index 00000000000..049415185ff
--- /dev/null
+++ b/components/camel-ipfs/src/main/java/org/apache/camel/component/ipfs/IPFSEndpoint.java
@@ -0,0 +1,108 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.camel.component.ipfs;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.nio.file.Path;
+import java.util.List;
+import java.util.concurrent.ExecutionException;
+import java.util.concurrent.Future;
+
+import io.nessus.ipfs.IPFSClient;
+
+import org.apache.camel.Consumer;
+import org.apache.camel.Processor;
+import org.apache.camel.Producer;
+import org.apache.camel.component.ipfs.IPFSConfiguration.IPFSCommand;
+import org.apache.camel.impl.DefaultEndpoint;
+import org.apache.camel.spi.UriEndpoint;
+import org.apache.camel.spi.UriParam;
+
+/**
+ * The camel-ipfs component provides access to the Interplanetary File System
+ * (IPFS).
+ */
+@UriEndpoint(firstVersion = "2.23.0", scheme = "ipfs", title = "IPFS", syntax = "ipfs:host:port/cmd", producerOnly = true, label = "file,ipfs")
+public class IPFSEndpoint extends DefaultEndpoint {
+
+    @UriParam
+    private final IPFSConfiguration configuration;
+
+    public IPFSEndpoint(String uri, IPFSComponent component, IPFSConfiguration configuration) {
+        super(uri, component);
+        this.configuration = configuration;
+    }
+
+    @Override
+    public IPFSComponent getComponent() {
+        return (IPFSComponent)super.getComponent();
+    }
+
+    @Override
+    public Consumer createConsumer(Processor processor) throws Exception {
+        throw new UnsupportedOperationException();
+    }
+
+    @Override
+    public Producer createProducer() throws Exception {
+        return new IPFSProducer(this);
+    }
+
+    @Override
+    public boolean isSingleton() {
+        return false;
+    }
+
+    IPFSConfiguration getConfiguration() {
+        return configuration;
+    }
+
+    IPFSCommand getCommand() {
+        String cmd = configuration.getIpfsCmd();
+        try {
+            return IPFSCommand.valueOf(cmd);
+        } catch (IllegalArgumentException ex) {
+            throw new IllegalArgumentException("Unsupported command: " + cmd);
+        }
+    }
+
+    String ipfsVersion() throws IOException {
+        return ipfs().version();
+    }
+
+    List<String> ipfsAdd(Path path) throws IOException {
+        return ipfs().add(path);
+    }
+
+    InputStream ipfsCat(String cid) throws IOException {
+        return ipfs().cat(cid);
+    }
+
+    Path ipfsGet(String cid, Path outdir) throws IOException {
+        Future<Path> future = ipfs().get(cid, outdir);
+        try {
+            return future.get();
+        } catch (InterruptedException | ExecutionException ex) {
+            throw new IOException("Cannot obtain: " + cid, ex);
+        }
+    }
+
+    private IPFSClient ipfs() {
+        return getComponent().getIPFSClient();
+    }
+}
diff --git a/components/camel-ipfs/src/main/java/org/apache/camel/component/ipfs/IPFSProducer.java b/components/camel-ipfs/src/main/java/org/apache/camel/component/ipfs/IPFSProducer.java
new file mode 100644
index 00000000000..155492769f5
--- /dev/null
+++ b/components/camel-ipfs/src/main/java/org/apache/camel/component/ipfs/IPFSProducer.java
@@ -0,0 +1,92 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.camel.component.ipfs;
+
+import java.io.File;
+import java.io.InputStream;
+import java.nio.file.Path;
+import java.nio.file.Paths;
+import java.util.List;
+
+import org.apache.camel.Exchange;
+import org.apache.camel.component.ipfs.IPFSConfiguration.IPFSCommand;
+import org.apache.camel.impl.DefaultProducer;
+
+public class IPFSProducer extends DefaultProducer {
+
+    public IPFSProducer(IPFSEndpoint endpoint) {
+        super(endpoint);
+    }
+
+    @Override
+    public IPFSEndpoint getEndpoint() {
+        return (IPFSEndpoint)super.getEndpoint();
+    }
+
+    @Override
+    public void process(Exchange exchange) throws Exception {
+
+        IPFSEndpoint endpoint = getEndpoint();
+        IPFSCommand cmd = endpoint.getCommand();
+
+        if (IPFSCommand.version == cmd) {
+
+            String resp = endpoint.ipfsVersion();
+            exchange.getMessage().setBody(resp);
+
+        } else if (IPFSCommand.add == cmd) {
+
+            Path path = pathFromBody(exchange);
+            List<String> cids = endpoint.ipfsAdd(path);
+            Object resp = cids;
+            if (path.toFile().isFile()) {
+                resp = cids.size() > 0 ? cids.get(0) : null;
+            }
+            exchange.getMessage().setBody(resp);
+
+        } else if (IPFSCommand.cat == cmd) {
+
+            String cid = exchange.getMessage().getBody(String.class);
+            InputStream resp = endpoint.ipfsCat(cid);
+            exchange.getMessage().setBody(resp);
+
+        } else if (IPFSCommand.get == cmd) {
+
+            Path outdir = endpoint.getConfiguration().getOutdir();
+            String cid = exchange.getMessage().getBody(String.class);
+            Path resp = endpoint.ipfsGet(cid, outdir);
+            exchange.getMessage().setBody(resp);
+
+        } else {
+            throw new UnsupportedOperationException(cmd.toString());
+        }
+    }
+
+    private Path pathFromBody(Exchange exchange) {
+        Object body = exchange.getMessage().getBody();
+        if (body instanceof Path) {
+            return (Path)body;
+        }
+        if (body instanceof String) {
+            return Paths.get((String)body);
+        }
+        if (body instanceof File) {
+            return ((File)body).toPath();
+        }
+        throw new IllegalArgumentException("Invalid path: " + body);
+    }
+}
diff --git a/components/camel-ipfs/src/main/resources/META-INF/LICENSE.txt b/components/camel-ipfs/src/main/resources/META-INF/LICENSE.txt
new file mode 100644
index 00000000000..6b0b1270ff0
--- /dev/null
+++ b/components/camel-ipfs/src/main/resources/META-INF/LICENSE.txt
@@ -0,0 +1,203 @@
+
+                                 Apache License
+                           Version 2.0, January 2004
+                        http://www.apache.org/licenses/
+
+   TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
+
+   1. Definitions.
+
+      "License" shall mean the terms and conditions for use, reproduction,
+      and distribution as defined by Sections 1 through 9 of this document.
+
+      "Licensor" shall mean the copyright owner or entity authorized by
+      the copyright owner that is granting the License.
+
+      "Legal Entity" shall mean the union of the acting entity and all
+      other entities that control, are controlled by, or are under common
+      control with that entity. For the purposes of this definition,
+      "control" means (i) the power, direct or indirect, to cause the
+      direction or management of such entity, whether by contract or
+      otherwise, or (ii) ownership of fifty percent (50%) or more of the
+      outstanding shares, or (iii) beneficial ownership of such entity.
+
+      "You" (or "Your") shall mean an individual or Legal Entity
+      exercising permissions granted by this License.
+
+      "Source" form shall mean the preferred form for making modifications,
+      including but not limited to software source code, documentation
+      source, and configuration files.
+
+      "Object" form shall mean any form resulting from mechanical
+      transformation or translation of a Source form, including but
+      not limited to compiled object code, generated documentation,
+      and conversions to other media types.
+
+      "Work" shall mean the work of authorship, whether in Source or
+      Object form, made available under the License, as indicated by a
+      copyright notice that is included in or attached to the work
+      (an example is provided in the Appendix below).
+
+      "Derivative Works" shall mean any work, whether in Source or Object
+      form, that is based on (or derived from) the Work and for which the
+      editorial revisions, annotations, elaborations, or other modifications
+      represent, as a whole, an original work of authorship. For the purposes
+      of this License, Derivative Works shall not include works that remain
+      separable from, or merely link (or bind by name) to the interfaces of,
+      the Work and Derivative Works thereof.
+
+      "Contribution" shall mean any work of authorship, including
+      the original version of the Work and any modifications or additions
+      to that Work or Derivative Works thereof, that is intentionally
+      submitted to Licensor for inclusion in the Work by the copyright owner
+      or by an individual or Legal Entity authorized to submit on behalf of
+      the copyright owner. For the purposes of this definition, "submitted"
+      means any form of electronic, verbal, or written communication sent
+      to the Licensor or its representatives, including but not limited to
+      communication on electronic mailing lists, source code control systems,
+      and issue tracking systems that are managed by, or on behalf of, the
+      Licensor for the purpose of discussing and improving the Work, but
+      excluding communication that is conspicuously marked or otherwise
+      designated in writing by the copyright owner as "Not a Contribution."
+
+      "Contributor" shall mean Licensor and any individual or Legal Entity
+      on behalf of whom a Contribution has been received by Licensor and
+      subsequently incorporated within the Work.
+
+   2. Grant of Copyright License. Subject to the terms and conditions of
+      this License, each Contributor hereby grants to You a perpetual,
+      worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+      copyright license to reproduce, prepare Derivative Works of,
+      publicly display, publicly perform, sublicense, and distribute the
+      Work and such Derivative Works in Source or Object form.
+
+   3. Grant of Patent License. Subject to the terms and conditions of
+      this License, each Contributor hereby grants to You a perpetual,
+      worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+      (except as stated in this section) patent license to make, have made,
+      use, offer to sell, sell, import, and otherwise transfer the Work,
+      where such license applies only to those patent claims licensable
+      by such Contributor that are necessarily infringed by their
+      Contribution(s) alone or by combination of their Contribution(s)
+      with the Work to which such Contribution(s) was submitted. If You
+      institute patent litigation against any entity (including a
+      cross-claim or counterclaim in a lawsuit) alleging that the Work
+      or a Contribution incorporated within the Work constitutes direct
+      or contributory patent infringement, then any patent licenses
+      granted to You under this License for that Work shall terminate
+      as of the date such litigation is filed.
+
+   4. Redistribution. You may reproduce and distribute copies of the
+      Work or Derivative Works thereof in any medium, with or without
+      modifications, and in Source or Object form, provided that You
+      meet the following conditions:
+
+      (a) You must give any other recipients of the Work or
+          Derivative Works a copy of this License; and
+
+      (b) You must cause any modified files to carry prominent notices
+          stating that You changed the files; and
+
+      (c) You must retain, in the Source form of any Derivative Works
+          that You distribute, all copyright, patent, trademark, and
+          attribution notices from the Source form of the Work,
+          excluding those notices that do not pertain to any part of
+          the Derivative Works; and
+
+      (d) If the Work includes a "NOTICE" text file as part of its
+          distribution, then any Derivative Works that You distribute must
+          include a readable copy of the attribution notices contained
+          within such NOTICE file, excluding those notices that do not
+          pertain to any part of the Derivative Works, in at least one
+          of the following places: within a NOTICE text file distributed
+          as part of the Derivative Works; within the Source form or
+          documentation, if provided along with the Derivative Works; or,
+          within a display generated by the Derivative Works, if and
+          wherever such third-party notices normally appear. The contents
+          of the NOTICE file are for informational purposes only and
+          do not modify the License. You may add Your own attribution
+          notices within Derivative Works that You distribute, alongside
+          or as an addendum to the NOTICE text from the Work, provided
+          that such additional attribution notices cannot be construed
+          as modifying the License.
+
+      You may add Your own copyright statement to Your modifications and
+      may provide additional or different license terms and conditions
+      for use, reproduction, or distribution of Your modifications, or
+      for any such Derivative Works as a whole, provided Your use,
+      reproduction, and distribution of the Work otherwise complies with
+      the conditions stated in this License.
+
+   5. Submission of Contributions. Unless You explicitly state otherwise,
+      any Contribution intentionally submitted for inclusion in the Work
+      by You to the Licensor shall be under the terms and conditions of
+      this License, without any additional terms or conditions.
+      Notwithstanding the above, nothing herein shall supersede or modify
+      the terms of any separate license agreement you may have executed
+      with Licensor regarding such Contributions.
+
+   6. Trademarks. This License does not grant permission to use the trade
+      names, trademarks, service marks, or product names of the Licensor,
+      except as required for reasonable and customary use in describing the
+      origin of the Work and reproducing the content of the NOTICE file.
+
+   7. Disclaimer of Warranty. Unless required by applicable law or
+      agreed to in writing, Licensor provides the Work (and each
+      Contributor provides its Contributions) on an "AS IS" BASIS,
+      WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
+      implied, including, without limitation, any warranties or conditions
+      of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
+      PARTICULAR PURPOSE. You are solely responsible for determining the
+      appropriateness of using or redistributing the Work and assume any
+      risks associated with Your exercise of permissions under this License.
+
+   8. Limitation of Liability. In no event and under no legal theory,
+      whether in tort (including negligence), contract, or otherwise,
+      unless required by applicable law (such as deliberate and grossly
+      negligent acts) or agreed to in writing, shall any Contributor be
+      liable to You for damages, including any direct, indirect, special,
+      incidental, or consequential damages of any character arising as a
+      result of this License or out of the use or inability to use the
+      Work (including but not limited to damages for loss of goodwill,
+      work stoppage, computer failure or malfunction, or any and all
+      other commercial damages or losses), even if such Contributor
+      has been advised of the possibility of such damages.
+
+   9. Accepting Warranty or Additional Liability. While redistributing
+      the Work or Derivative Works thereof, You may choose to offer,
+      and charge a fee for, acceptance of support, warranty, indemnity,
+      or other liability obligations and/or rights consistent with this
+      License. However, in accepting such obligations, You may act only
+      on Your own behalf and on Your sole responsibility, not on behalf
+      of any other Contributor, and only if You agree to indemnify,
+      defend, and hold each Contributor harmless for any liability
+      incurred by, or claims asserted against, such Contributor by reason
+      of your accepting any such warranty or additional liability.
+
+   END OF TERMS AND CONDITIONS
+
+   APPENDIX: How to apply the Apache License to your work.
+
+      To apply the Apache License to your work, attach the following
+      boilerplate notice, with the fields enclosed by brackets "[]"
+      replaced with your own identifying information. (Don't include
+      the brackets!)  The text should be enclosed in the appropriate
+      comment syntax for the file format. We also recommend that a
+      file or class name and description of purpose be included on the
+      same "printed page" as the copyright notice for easier
+      identification within third-party archives.
+
+   Copyright [yyyy] [name of copyright owner]
+
+   Licensed 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.
+
diff --git a/components/camel-ipfs/src/main/resources/META-INF/NOTICE.txt b/components/camel-ipfs/src/main/resources/META-INF/NOTICE.txt
new file mode 100644
index 00000000000..2e215bf2e6b
--- /dev/null
+++ b/components/camel-ipfs/src/main/resources/META-INF/NOTICE.txt
@@ -0,0 +1,11 @@
+   =========================================================================
+   ==  NOTICE file corresponding to the section 4 d of                    ==
+   ==  the Apache License, Version 2.0,                                   ==
+   ==  in this case for the Apache Camel distribution.                    ==
+   =========================================================================
+
+   This product includes software developed by
+   The Apache Software Foundation (http://www.apache.org/).
+
+   Please read the different LICENSE files present in the licenses directory of
+   this distribution.
diff --git a/components/camel-ipfs/src/main/resources/META-INF/services/org/apache/camel/component/ipfs b/components/camel-ipfs/src/main/resources/META-INF/services/org/apache/camel/component/ipfs
new file mode 100644
index 00000000000..179ce43a3be
--- /dev/null
+++ b/components/camel-ipfs/src/main/resources/META-INF/services/org/apache/camel/component/ipfs
@@ -0,0 +1,18 @@
+#
+# 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.
+#
+
+class=org.apache.camel.component.ipfs.IPFSComponent
diff --git a/components/camel-ipfs/src/test/java/org/apache/camel/component/ipfs/SimpleIPFSTest.java b/components/camel-ipfs/src/test/java/org/apache/camel/component/ipfs/SimpleIPFSTest.java
new file mode 100644
index 00000000000..07aec74ccb3
--- /dev/null
+++ b/components/camel-ipfs/src/test/java/org/apache/camel/component/ipfs/SimpleIPFSTest.java
@@ -0,0 +1,213 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.camel.component.ipfs;
+
+import java.io.ByteArrayOutputStream;
+import java.io.FileInputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.nio.file.Path;
+import java.nio.file.Paths;
+import java.util.Arrays;
+import java.util.List;
+
+import io.nessus.utils.StreamUtils;
+
+import org.apache.camel.CamelContext;
+import org.apache.camel.ProducerTemplate;
+import org.apache.camel.builder.RouteBuilder;
+import org.apache.camel.impl.DefaultCamelContext;
+import org.junit.Assert;
+import org.junit.Assume;
+import org.junit.Test;
+
+public class SimpleIPFSTest {
+
+    @Test
+    public void ipfsVersion() throws Exception {
+
+        CamelContext camelctx = new DefaultCamelContext();
+        camelctx.addRoutes(new RouteBuilder() {
+            @Override
+            public void configure() throws Exception {
+                from("direct:startA").to("ipfs:version");
+                from("direct:startB").to("ipfs:127.0.0.1/version");
+                from("direct:startC").to("ipfs:127.0.0.1:5001/version");
+            }
+        });
+
+        camelctx.start();
+        assumeIPFS(camelctx);
+
+        try {
+            ProducerTemplate producer = camelctx.createProducerTemplate();
+            String resA = producer.requestBody("direct:startA", null, String.class);
+            String resB = producer.requestBody("direct:startB", null, String.class);
+            String resC = producer.requestBody("direct:startC", null, String.class);
+            Arrays.asList(resA, resB, resC).forEach(res -> {
+                Assert.assertTrue("Expecting 0.4 in: " + resA, resA.startsWith("0.4"));
+            });
+        } finally {
+            camelctx.stop();
+        }
+    }
+
+    @Test
+    public void ipfsAddSingle() throws Exception {
+
+        String hash = "QmYgjSRbXFPdPYKqQSnUjmXLYLudVahEJQotMaAJKt6Lbd";
+
+        CamelContext camelctx = new DefaultCamelContext();
+        camelctx.addRoutes(new RouteBuilder() {
+            @Override
+            public void configure() throws Exception {
+                from("direct:start").to("ipfs:add");
+            }
+        });
+
+        Path path = Paths.get("src/test/resources/html/index.html");
+
+        camelctx.start();
+        assumeIPFS(camelctx);
+
+        try {
+            ProducerTemplate producer = camelctx.createProducerTemplate();
+            String res = producer.requestBody("direct:start", path, String.class);
+            Assert.assertEquals(hash, res);
+        } finally {
+            camelctx.stop();
+        }
+    }
+
+    @Test
+    @SuppressWarnings("unchecked")
+    public void ipfsAddRecursive() throws Exception {
+
+        String hash = "Qme6hd6tYXTFb7bb7L3JZ5U6ygktpAHKxbaeffYyQN85mW";
+
+        CamelContext camelctx = new DefaultCamelContext();
+        camelctx.addRoutes(new RouteBuilder() {
+            @Override
+            public void configure() throws Exception {
+                from("direct:start").to("ipfs:add");
+            }
+        });
+
+        Path path = Paths.get("src/test/resources/html");
+
+        camelctx.start();
+        assumeIPFS(camelctx);
+
+        try {
+            ProducerTemplate producer = camelctx.createProducerTemplate();
+            List<String> res = producer.requestBody("direct:start", path, List.class);
+            Assert.assertEquals(10, res.size());
+            Assert.assertEquals(hash, res.get(9));
+        } finally {
+            camelctx.stop();
+        }
+    }
+
+    @Test
+    public void ipfsCat() throws Exception {
+
+        String hash = "QmUD7uG5prAMHbcCfp4x1G1mMSpywcSMHTGpq62sbpDAg6";
+
+        CamelContext camelctx = new DefaultCamelContext();
+        camelctx.addRoutes(new RouteBuilder() {
+            @Override
+            public void configure() throws Exception {
+                from("direct:start").to("ipfs:cat");
+            }
+        });
+
+        camelctx.start();
+        assumeIPFS(camelctx);
+
+        try {
+            ProducerTemplate producer = camelctx.createProducerTemplate();
+            InputStream res = producer.requestBody("direct:start", hash, InputStream.class);
+            verifyFileContent(res);
+        } finally {
+            camelctx.stop();
+        }
+    }
+
+    @Test
+    public void ipfsGetSingle() throws Exception {
+
+        String hash = "QmUD7uG5prAMHbcCfp4x1G1mMSpywcSMHTGpq62sbpDAg6";
+
+        CamelContext camelctx = new DefaultCamelContext();
+        camelctx.addRoutes(new RouteBuilder() {
+            @Override
+            public void configure() throws Exception {
+                from("direct:start").to("ipfs:get?outdir=target");
+            }
+        });
+
+        camelctx.start();
+        assumeIPFS(camelctx);
+
+        try {
+            ProducerTemplate producer = camelctx.createProducerTemplate();
+            Path res = producer.requestBody("direct:start", hash, Path.class);
+            Assert.assertEquals(Paths.get("target", hash), res);
+            verifyFileContent(new FileInputStream(res.toFile()));
+        } finally {
+            camelctx.stop();
+        }
+    }
+
+    @Test
+    public void ipfsGetRecursive() throws Exception {
+
+        String hash = "Qme6hd6tYXTFb7bb7L3JZ5U6ygktpAHKxbaeffYyQN85mW";
+
+        CamelContext camelctx = new DefaultCamelContext();
+        camelctx.addRoutes(new RouteBuilder() {
+            @Override
+            public void configure() throws Exception {
+                from("direct:start").to("ipfs:get?outdir=target");
+            }
+        });
+
+        camelctx.start();
+        assumeIPFS(camelctx);
+
+        try {
+            ProducerTemplate producer = camelctx.createProducerTemplate();
+            Path res = producer.requestBody("direct:start", hash, Path.class);
+            Assert.assertEquals(Paths.get("target", hash), res);
+            Assert.assertTrue(res.toFile().isDirectory());
+            Assert.assertTrue(res.resolve("index.html").toFile().exists());
+        } finally {
+            camelctx.stop();
+        }
+    }
+
+    private void verifyFileContent(InputStream ins) throws IOException {
+        ByteArrayOutputStream baos = new ByteArrayOutputStream();
+        StreamUtils.copyStream(ins, baos);
+        Assert.assertEquals("The quick brown fox jumps over the lazy dog.", new String(baos.toByteArray()));
+    }
+
+    private void assumeIPFS(CamelContext camelctx) {
+        IPFSComponent comp = camelctx.getComponent("ipfs", IPFSComponent.class);
+        Assume.assumeTrue(comp.getIPFSClient().hasConnection());
+    }
+}
diff --git a/components/camel-ipfs/src/test/resources/html/chap/ch01.html b/components/camel-ipfs/src/test/resources/html/chap/ch01.html
new file mode 100644
index 00000000000..4edc3fd6b87
--- /dev/null
+++ b/components/camel-ipfs/src/test/resources/html/chap/ch01.html
@@ -0,0 +1,13 @@
+<!DOCTYPE html>
+<html lang="en">
+<head>
+    <title>IPFS</title>
+    <meta charset="utf-8" />
+    <link rel="stylesheet" href="./../css/default.css">
+</head>
+<body>
+<p><a href="../index.html">Home</a></p>
+<h2>Chapter 01</h2>
+<p><img src="../img/logo.png" alt="logo" /></p>
+</body>
+</html>
diff --git a/components/camel-ipfs/src/test/resources/html/css/default.css b/components/camel-ipfs/src/test/resources/html/css/default.css
new file mode 100644
index 00000000000..8c0b2d558f3
--- /dev/null
+++ b/components/camel-ipfs/src/test/resources/html/css/default.css
@@ -0,0 +1,38 @@
+body {
+    font-family: "Verdana";
+    color: #137cb9
+}
+
+a {
+    #text-decoration: none;
+    color: #137cb9
+}
+
+a.gray {
+    color: gray;
+}
+
+h1 {
+	font-weight: normal;
+    font-size: 20px;
+}
+
+h2 {
+    font-weight: normal;
+	font-size: 15px;
+}
+
+th {
+	text-align: left;
+    font-weight: normal;
+    font-size: 14px;
+    color: gray;
+}
+
+td.gray {
+    color: gray;
+}
+tr.gray {
+    color: gray;
+}
+
diff --git a/components/camel-ipfs/src/test/resources/html/etc/userfile.txt b/components/camel-ipfs/src/test/resources/html/etc/userfile.txt
new file mode 100644
index 00000000000..8fe2a4b5ad1
--- /dev/null
+++ b/components/camel-ipfs/src/test/resources/html/etc/userfile.txt
@@ -0,0 +1 @@
+The quick brown fox jumps over the lazy dog.
\ No newline at end of file
diff --git a/components/camel-ipfs/src/test/resources/html/img/logo.png b/components/camel-ipfs/src/test/resources/html/img/logo.png
new file mode 100644
index 00000000000..ddda52e086e
Binary files /dev/null and b/components/camel-ipfs/src/test/resources/html/img/logo.png differ
diff --git a/components/camel-ipfs/src/test/resources/html/index.html b/components/camel-ipfs/src/test/resources/html/index.html
new file mode 100644
index 00000000000..37813002970
--- /dev/null
+++ b/components/camel-ipfs/src/test/resources/html/index.html
@@ -0,0 +1,13 @@
+<!DOCTYPE html>
+<html lang="en">
+<head>
+    <title>IPFS</title>
+    <meta charset="utf-8" />
+    <link rel="stylesheet" href="./css/default.css">
+</head>
+<body>
+<p><a href="index.html">Home</a></p>
+<p><a href="chap/ch01.html">chapter one</a></p>
+<p><img src="img/logo.png" alt="logo" /></p>
+</body>
+</html>
diff --git a/components/camel-ipfs/src/test/resources/log4j2.properties b/components/camel-ipfs/src/test/resources/log4j2.properties
new file mode 100644
index 00000000000..081914f91a3
--- /dev/null
+++ b/components/camel-ipfs/src/test/resources/log4j2.properties
@@ -0,0 +1,30 @@
+## ---------------------------------------------------------------------------
+## 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.
+## ---------------------------------------------------------------------------
+
+rootLogger.level = DEBUG
+rootLogger.appenderRef.file.ref = file
+
+appender.file.name = file
+appender.file.type = File
+appender.file.fileName = target/camel-test.log
+appender.file.layout.type = PatternLayout
+appender.file.layout.pattern = %d [%-15.15t] %-5p %-30.30c{1} - %m%n
+
+appender.out.name = out
+appender.out.type = Console
+appender.out.layout.type = PatternLayout
+appender.out.layout.pattern = %d [%-15.15t] %-5p %-30.30c{1} - %m%n
diff --git a/components/camel-irc/pom.xml b/components/camel-irc/pom.xml
index 85b7e179039..614eaccce6a 100644
--- a/components/camel-irc/pom.xml
+++ b/components/camel-irc/pom.xml
@@ -23,7 +23,7 @@
   <parent>
     <groupId>org.apache.camel</groupId>
     <artifactId>components</artifactId>
-    <version>2.23.0-SNAPSHOT</version>
+    <version>2.24.0-SNAPSHOT</version>
   </parent>
 
   <artifactId>camel-irc</artifactId>
@@ -39,6 +39,43 @@
     </camel.osgi.export.service>
   </properties>
 
+
+  <build>
+    <plugins>
+      <plugin>
+        <groupId>org.apache.maven.plugins</groupId>
+        <artifactId>maven-surefire-plugin</artifactId>
+        <configuration>
+          <excludes>
+            <exclude>
+              **/it/**
+            </exclude>
+          </excludes>
+        </configuration>
+      </plugin>
+    </plugins>
+  </build>
+
+  <profiles>
+    <profile>
+      <id>it-tests</id>
+      <build>
+        <plugins>
+          <plugin>
+            <groupId>org.apache.maven.plugins</groupId>
+            <artifactId>maven-surefire-plugin</artifactId>
+            <configuration combine.self="override">
+              <includes>
+                <include>**/*Test.java</include>
+              </includes>
+            </configuration>
+          </plugin>
+        </plugins>
+      </build>
+
+    </profile>
+  </profiles>
+
   <dependencies>
 
     <dependency>
diff --git a/components/camel-irc/src/test/java/org/apache/camel/component/irc/it/IrcIntegrationTestSupport.java b/components/camel-irc/src/test/java/org/apache/camel/component/irc/it/IrcIntegrationTestSupport.java
new file mode 100644
index 00000000000..b459749310d
--- /dev/null
+++ b/components/camel-irc/src/test/java/org/apache/camel/component/irc/it/IrcIntegrationTestSupport.java
@@ -0,0 +1,68 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.camel.component.irc.it;
+
+import java.io.IOException;
+import java.util.Properties;
+import java.util.concurrent.TimeUnit;
+import org.apache.camel.EndpointInject;
+import org.apache.camel.component.mock.MockEndpoint;
+import org.apache.camel.test.junit4.CamelTestSupport;
+import org.junit.Before;
+
+public class IrcIntegrationTestSupport extends CamelTestSupport {
+
+    @EndpointInject(uri = "mock:result")
+    protected MockEndpoint resultEndpoint;
+
+    protected Properties properties;
+
+    @Before
+    public void doBefore() throws IOException {
+        properties = loadProperties();
+        resetMock(resultEndpoint);
+    }
+
+    protected void resetMock(MockEndpoint mock) {
+        mock.reset();
+        mock.setResultWaitTime(TimeUnit.MINUTES.toMillis(1));
+    }
+
+    private Properties loadProperties() throws IOException {
+        Properties p = new Properties();
+        p.load(this.getClass().getResourceAsStream("/it-tests.properties"));
+        return p;
+    }
+
+    @Override
+    protected Properties useOverridePropertiesWithPropertiesComponent() {
+        try {
+            return loadProperties();
+        } catch (IOException e) {
+            log.error("Can't load configuration properties");
+            return null;
+        }
+    }
+
+    protected String sendUri() {
+        return "ircs://{{camelTo}}@{{server}}?channels={{channel1}}";
+    }
+
+    protected String fromUri() {
+        return "ircs://{{camelFrom}}@{{server}}?&channels={{channel1}}";
+    }
+}
diff --git a/components/camel-irc/src/test/java/org/apache/camel/component/irc/IrcMultiChannelRouteTest.java b/components/camel-irc/src/test/java/org/apache/camel/component/irc/it/IrcMultiChannelRouteTest.java
similarity index 59%
rename from components/camel-irc/src/test/java/org/apache/camel/component/irc/IrcMultiChannelRouteTest.java
rename to components/camel-irc/src/test/java/org/apache/camel/component/irc/it/IrcMultiChannelRouteTest.java
index dd1dd73e9d4..51f62b20703 100644
--- a/components/camel-irc/src/test/java/org/apache/camel/component/irc/IrcMultiChannelRouteTest.java
+++ b/components/camel-irc/src/test/java/org/apache/camel/component/irc/it/IrcMultiChannelRouteTest.java
@@ -14,34 +14,40 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
-package org.apache.camel.component.irc;
+package org.apache.camel.component.irc.it;
 
 import java.util.List;
-
+import java.util.concurrent.TimeUnit;
+import org.apache.camel.EndpointInject;
 import org.apache.camel.Exchange;
-import org.apache.camel.Processor;
 import org.apache.camel.builder.RouteBuilder;
+import org.apache.camel.component.irc.IrcConstants;
 import org.apache.camel.component.mock.MockEndpoint;
-import org.apache.camel.test.junit4.CamelTestSupport;
-import org.junit.Ignore;
 import org.junit.Test;
 
 /**
  * @version 
  */
-public class IrcMultiChannelRouteTest extends CamelTestSupport {
-    protected MockEndpoint resultEndpoint;
+public class IrcMultiChannelRouteTest extends IrcIntegrationTestSupport {
     protected String body1 = "Message One";
     protected String body2 = "Message Two";
     protected String body3 = "Message Three";
-    private boolean sentMessages;    
 
-    @Ignore("test manual, irc.codehaus.org has been closed")
+    @EndpointInject(uri = "mock:joined")
+    private MockEndpoint joined;
+
+
     @Test
     public void testIrcMessages() throws Exception {
-        resultEndpoint = context.getEndpoint("mock:result", MockEndpoint.class);
+        resetMock(joined);
+        joined.expectedMessageCount(2);
+        joined.expectedHeaderValuesReceivedInAnyOrder(IrcConstants.IRC_TARGET, properties.get("channel1"), properties.get("channel2"));
+        joined.assertIsSatisfied();
+
+        sendMessages();
+
         //consumer is going to receive two copies of body3
-        resultEndpoint.expectedBodiesReceived(body1, body2, body3, body3);
+        resultEndpoint.expectedBodiesReceivedInAnyOrder(body1, body2, body3, body3);
 
         resultEndpoint.assertIsSatisfied();
 
@@ -56,38 +62,31 @@ protected RouteBuilder createRouteBuilder() throws Exception {
             public void configure() throws Exception {
                 from(fromUri()).
                         choice().
-                        when(header(IrcConstants.IRC_MESSAGE_TYPE).isEqualTo("PRIVMSG")).to("mock:result").
-                        when(header(IrcConstants.IRC_MESSAGE_TYPE).isEqualTo("JOIN")).to("seda:consumerJoined");
+                        when(header(IrcConstants.IRC_MESSAGE_TYPE).isEqualTo("PRIVMSG")).to("direct:mock").
+                        when(header(IrcConstants.IRC_MESSAGE_TYPE).isEqualTo("JOIN")).to(joined);
 
-                from("seda:consumerJoined").process(new Processor() {
-                    public void process(Exchange exchange) throws Exception {
-                        sendMessages();
-                    }
-                });
+                from("direct:mock").filter(e -> !e.getIn().getBody(String.class).contains("VERSION")).to(resultEndpoint);
             }
         };
     }
 
-    protected String sendUri() {
-        return "irc://camel-prd@irc.codehaus.org:6667?nickname=camel-prd&channels=#camel-test1,#camel-test2";
-    }
 
-    protected String fromUri() {
-        return "irc://camel-con@irc.codehaus.org:6667?nickname=camel-con&channels=#camel-test1,#camel-test2";
-    }    
-    
     /**
      * Lets send messages once the consumer has joined
      */
     protected void sendMessages() {
-        if (!sentMessages) {
-            sentMessages = true;
+        template.sendBodyAndHeader(sendUri(), body1, "irc.target", properties.get("channel1"));
+        template.sendBodyAndHeader(sendUri(), body2, "irc.target", properties.get("channel2"));
+        template.sendBody(sendUri(), body3);
+    }
 
-            // now the consumer has joined, lets send some messages
+    @Override
+    protected String sendUri() {
+        return "ircs://camel-prd@{{server}}?nickname=camel-prd&channels={{channel1}},{{channel2}}";
+    }
 
-            template.sendBodyAndHeader(sendUri(), body1, "irc.target", "#camel-test1");
-            template.sendBodyAndHeader(sendUri(), body2, "irc.target", "#camel-test2");
-            template.sendBody(sendUri(), body3);
-        }
+    @Override
+    protected String fromUri() {
+        return "ircs://camel-con@{{server}}??nickname=camel-con&channels={{channel1}},{{channel2}}";
     }
 }
diff --git a/components/camel-irc/src/test/java/org/apache/camel/component/irc/IrcOnReplyTest.java b/components/camel-irc/src/test/java/org/apache/camel/component/irc/it/IrcOnReplyTest.java
similarity index 81%
rename from components/camel-irc/src/test/java/org/apache/camel/component/irc/IrcOnReplyTest.java
rename to components/camel-irc/src/test/java/org/apache/camel/component/irc/it/IrcOnReplyTest.java
index 7f7b076eaf0..6a80301fd8d 100644
--- a/components/camel-irc/src/test/java/org/apache/camel/component/irc/IrcOnReplyTest.java
+++ b/components/camel-irc/src/test/java/org/apache/camel/component/irc/it/IrcOnReplyTest.java
@@ -14,31 +14,26 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
-package org.apache.camel.component.irc;
+package org.apache.camel.component.irc.it;
 
 import java.util.List;
-
 import org.apache.camel.Exchange;
 import org.apache.camel.Processor;
 import org.apache.camel.builder.RouteBuilder;
+import org.apache.camel.component.irc.IrcConstants;
 import org.apache.camel.component.mock.MockEndpoint;
-import org.apache.camel.test.junit4.CamelTestSupport;
-import org.junit.Ignore;
 import org.junit.Test;
 
 /**
  * @version 
  */
-public class IrcOnReplyTest extends CamelTestSupport {
-    protected MockEndpoint resultEndpoint;
+public class IrcOnReplyTest extends IrcIntegrationTestSupport {
     protected String command = "WHO #camel-test";
-    protected String resultEnd = "End of WHO list";
-    private boolean sentMessages;    
+    protected String resultEnd = "End of /WHO list.";
+    private boolean sentMessages;
 
-    @Ignore("test manual, irc.codehaus.org has been closed")
     @Test
     public void testIrcMessages() throws Exception {
-        resultEndpoint = context.getEndpoint("mock:result", MockEndpoint.class);
         resultEndpoint.expectedBodiesReceived(resultEnd);
 
         resultEndpoint.assertIsSatisfied();
@@ -67,7 +62,8 @@ public void process(Exchange exchange) throws Exception {
     }
 
     protected String fromUri() {
-        return "irc://camel-con@irc.codehaus.org:6667?nickname=camel-con&channels=#camel-test&onReply=true";
+        StringBuilder sb = new StringBuilder(super.fromUri());
+        return sb.append("&onReply=true").toString();
     }    
     
     /**
diff --git a/components/camel-irc/src/test/java/org/apache/camel/component/irc/IrcPrivmsgTest.java b/components/camel-irc/src/test/java/org/apache/camel/component/irc/it/IrcPrivmsgTest.java
similarity index 80%
rename from components/camel-irc/src/test/java/org/apache/camel/component/irc/IrcPrivmsgTest.java
rename to components/camel-irc/src/test/java/org/apache/camel/component/irc/it/IrcPrivmsgTest.java
index 22716a27835..9c06081afe7 100644
--- a/components/camel-irc/src/test/java/org/apache/camel/component/irc/IrcPrivmsgTest.java
+++ b/components/camel-irc/src/test/java/org/apache/camel/component/irc/it/IrcPrivmsgTest.java
@@ -14,13 +14,14 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
-package org.apache.camel.component.irc;
+package org.apache.camel.component.irc.it;
 
 import java.util.List;
 
 import org.apache.camel.Exchange;
 import org.apache.camel.Processor;
 import org.apache.camel.builder.RouteBuilder;
+import org.apache.camel.component.irc.IrcConstants;
 import org.apache.camel.component.mock.MockEndpoint;
 import org.apache.camel.test.junit4.CamelTestSupport;
 import org.junit.Ignore;
@@ -29,9 +30,7 @@
 /**
  * @version 
  */
-public class IrcPrivmsgTest extends CamelTestSupport {
-    protected MockEndpoint resultEndpoint;
-
+public class IrcPrivmsgTest extends IrcIntegrationTestSupport {
     protected String expectedBody1 = "Message One";
     protected String expectedBody2 = "Message Two";
 
@@ -40,10 +39,8 @@
 
     private boolean sentMessages;    
 
-    @Ignore("test manual, irc.codehaus.org has been closed")
     @Test
     public void testIrcPrivateMessages() throws Exception {
-        resultEndpoint = context.getEndpoint("mock:result", MockEndpoint.class);
         resultEndpoint.expectedBodiesReceived(expectedBody1, expectedBody2);
 
         resultEndpoint.assertIsSatisfied();
@@ -59,7 +56,7 @@ protected RouteBuilder createRouteBuilder() throws Exception {
             public void configure() throws Exception {
                 from(fromUri()).
                         choice().
-                        when(header(IrcConstants.IRC_MESSAGE_TYPE).isEqualTo("PRIVMSG")).to("mock:result").
+                        when(header(IrcConstants.IRC_MESSAGE_TYPE).isEqualTo("PRIVMSG")).to("direct:mock").
                         when(header(IrcConstants.IRC_MESSAGE_TYPE).isEqualTo("JOIN")).to("seda:consumerJoined");
 
                 from("seda:consumerJoined")
@@ -68,28 +65,26 @@ public void process(Exchange exchange) throws Exception {
                             sendMessages();
                         }
                     });
+
+                from("direct:mock").filter(e -> !e.getIn().getBody(String.class).contains("VERSION")).to(resultEndpoint);
             }
         };
     }
 
+    @Override
     protected String sendUri() {
-        return "irc://camel-prd@irc.codehaus.org:6667/#camel-test?nickname=camel-prd";
+        return "ircs://{{camelTo}}@{{server}}?channels={{channel1}}&username={{username}}&password={{password}}";
     }
 
-    protected String fromUri() {
-        return "irc://camel-con@irc.codehaus.org:6667/#camel-test?nickname=camel-con";
-    }    
-    
     /**
      * Lets send messages once the consumer has joined
      */
-    protected void sendMessages() {
+    protected void sendMessages() throws InterruptedException {
         if (!sentMessages) {
             sentMessages = true;
 
-            // now the consumer has joined, lets send some messages
-            template.sendBodyAndHeader(sendUri(), body1, "irc.target", "camel-con");
-            template.sendBodyAndHeader(sendUri(), body2, "irc.target", "camel-con");
+            template.sendBodyAndHeader(sendUri(), body1, "irc.target", properties.get("camelFrom"));
+            template.sendBodyAndHeader(sendUri(), body2, "irc.target", properties.get("camelFrom"));
         }
     }
 }
diff --git a/components/camel-irc/src/test/java/org/apache/camel/component/irc/IrcRouteTest.java b/components/camel-irc/src/test/java/org/apache/camel/component/irc/it/IrcRouteTest.java
similarity index 81%
rename from components/camel-irc/src/test/java/org/apache/camel/component/irc/IrcRouteTest.java
rename to components/camel-irc/src/test/java/org/apache/camel/component/irc/it/IrcRouteTest.java
index 7b3d60ff814..43d6ce0895a 100644
--- a/components/camel-irc/src/test/java/org/apache/camel/component/irc/IrcRouteTest.java
+++ b/components/camel-irc/src/test/java/org/apache/camel/component/irc/it/IrcRouteTest.java
@@ -14,13 +14,14 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
-package org.apache.camel.component.irc;
+package org.apache.camel.component.irc.it;
 
 import java.util.List;
 
 import org.apache.camel.Exchange;
 import org.apache.camel.Processor;
 import org.apache.camel.builder.RouteBuilder;
+import org.apache.camel.component.irc.IrcConstants;
 import org.apache.camel.component.mock.MockEndpoint;
 import org.apache.camel.test.junit4.CamelTestSupport;
 import org.junit.Ignore;
@@ -29,32 +30,37 @@
 /**
  * @version 
  */
-public class IrcRouteTest extends CamelTestSupport {
-    protected MockEndpoint resultEndpoint;
+public class IrcRouteTest extends IrcIntegrationTestSupport {
     protected String body1 = "Message One";
     protected String body2 = "Message Two";
     private boolean sentMessages;    
 
-    @Ignore("test manual, irc.codehaus.org has been closed")   
     @Test
     public void testIrcMessages() throws Exception {
-        resultEndpoint = context.getEndpoint("mock:result", MockEndpoint.class);
-        resultEndpoint.expectedBodiesReceived(body1, body2);
-
+        resultEndpoint.expectedBodiesReceivedInAnyOrder(body1, body2);
         resultEndpoint.assertIsSatisfied();
 
         List<Exchange> list = resultEndpoint.getReceivedExchanges();
         for (Exchange exchange : list) {
             log.info("Received exchange: " + exchange + " headers: " + exchange.getIn().getHeaders());
         }
-    }   
+    }
+
+    protected String sendUri() {
+        return "irc://{{camelTo}}@{{non.ssl.server}}?channels={{channel1}}";
+    }
+
+    protected String fromUri() {
+        return "irc://{{camelFrom}}@{{non.ssl.server}}?&channels={{channel1}}";
+    }
     
     protected RouteBuilder createRouteBuilder() throws Exception {
         return new RouteBuilder() {
             public void configure() throws Exception {
                 from(fromUri()).
                         choice().
-                        when(header(IrcConstants.IRC_MESSAGE_TYPE).isEqualTo("PRIVMSG")).to("mock:result").
+                        when(header(IrcConstants.IRC_MESSAGE_TYPE).isEqualTo("PRIVMSG"))
+                        .to("direct:mock").
                         when(header(IrcConstants.IRC_MESSAGE_TYPE).isEqualTo("JOIN")).to("seda:consumerJoined");
 
                 from("seda:consumerJoined").process(new Processor() {
@@ -62,17 +68,11 @@ public void process(Exchange exchange) throws Exception {
                         sendMessages();
                     }
                 });
+
+                from("direct:mock").filter(e -> !e.getIn().getBody(String.class).contains("VERSION")).to(resultEndpoint);
             }
         };
     }
-
-    protected String sendUri() {
-        return "irc://camel-prd-user@irc.codehaus.org:6667/#camel-test?nickname=camel-prd";
-    }
-
-    protected String fromUri() {
-        return "irc://camel-con-user@irc.codehaus.org:6667/#camel-test?nickname=camel-con";
-    }    
     
     /**
      * Lets send messages once the consumer has joined
diff --git a/components/camel-irc/src/test/java/org/apache/camel/component/irc/IrcsListUsersIntegrationTest.java b/components/camel-irc/src/test/java/org/apache/camel/component/irc/it/IrcsListUsersTest.java
similarity index 74%
rename from components/camel-irc/src/test/java/org/apache/camel/component/irc/IrcsListUsersIntegrationTest.java
rename to components/camel-irc/src/test/java/org/apache/camel/component/irc/it/IrcsListUsersTest.java
index 7e629ee294f..29569015c60 100644
--- a/components/camel-irc/src/test/java/org/apache/camel/component/irc/IrcsListUsersIntegrationTest.java
+++ b/components/camel-irc/src/test/java/org/apache/camel/component/irc/it/IrcsListUsersTest.java
@@ -14,17 +14,20 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
-package org.apache.camel.component.irc;
+package org.apache.camel.component.irc.it;
 
 import java.io.IOException;
 import java.io.InputStream;
 import java.util.Properties;
+import java.util.concurrent.TimeUnit;
 
 import org.apache.camel.EndpointInject;
 import org.apache.camel.RoutesBuilder;
 import org.apache.camel.builder.RouteBuilder;
+import org.apache.camel.component.irc.IrcConfiguration;
 import org.apache.camel.component.mock.MockEndpoint;
 import org.apache.camel.test.junit4.CamelTestSupport;
+import org.junit.Before;
 import org.junit.Test;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
@@ -34,27 +37,15 @@
  * Joins a channel and asserts that the username of the current test user is
  * listed for the channel.
  */
-public class IrcsListUsersIntegrationTest extends CamelTestSupport {
+public class IrcsListUsersTest extends IrcIntegrationTestSupport {
 
-    private static final Logger LOGGER = LoggerFactory.getLogger(IrcsListUsersIntegrationTest.class);
+    private static final Logger LOGGER = LoggerFactory.getLogger(IrcsListUsersTest.class);
 
     /** message code for a reply to a <code>NAMES</code> command. */
     private static final String IRC_RPL_NAMREPLY = "353";
 
     /** irc component uri. configured by properties */
-    private static final String PRODUCER_URI = "ircs:{{test.user}}@{{test.server}}/{{test.room}}";
-
-    @EndpointInject(uri = "mock:result")
-    protected MockEndpoint resultEndpoint;
-
-    protected Properties properties;
-
-    public IrcsListUsersIntegrationTest() throws IOException {
-        super();
-        properties = new Properties();
-        InputStream resourceAsStream = this.getClass().getResourceAsStream("/it-list-users.properties");
-        properties.load(resourceAsStream);
-    }
+    private static final String PRODUCER_URI = "ircs:{{camelFrom}}@{{server}}/{{channel1}}";
 
     @Override
     protected RoutesBuilder createRouteBuilder() throws Exception {
@@ -76,17 +67,12 @@ public void configure() throws Exception {
 
     @Test
     public void test() throws Exception {
-        resultEndpoint.setMinimumExpectedMessageCount(1);
+        resultEndpoint.expectedMessageCount(1);
         resultEndpoint.assertIsSatisfied();
         String body = resultEndpoint.getExchanges().get(0).getIn().getBody(String.class);
         LOGGER.debug("Received usernames: [{}]", body);
-        String username = properties.getProperty("test.user");
+        String username = properties.getProperty("camelFrom");
         assertTrue("userlist does not contain test user", body.contains(username));
     }
 
-    @Override
-    protected Properties useOverridePropertiesWithPropertiesComponent() {
-        return properties;
-    }
-
 }
diff --git a/components/camel-irc/src/test/java/org/apache/camel/component/irc/IrcsRouteTest.java b/components/camel-irc/src/test/java/org/apache/camel/component/irc/it/IrcsRouteTest.java
similarity index 64%
rename from components/camel-irc/src/test/java/org/apache/camel/component/irc/IrcsRouteTest.java
rename to components/camel-irc/src/test/java/org/apache/camel/component/irc/it/IrcsRouteTest.java
index d79e5ae21d0..466a9c5a1da 100644
--- a/components/camel-irc/src/test/java/org/apache/camel/component/irc/IrcsRouteTest.java
+++ b/components/camel-irc/src/test/java/org/apache/camel/component/irc/it/IrcsRouteTest.java
@@ -14,25 +14,18 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
-package org.apache.camel.component.irc;
+package org.apache.camel.component.irc.it;
 
-import org.junit.Ignore;
-
-@Ignore
 public class IrcsRouteTest extends IrcRouteTest {
 
-    // TODO This test is disabled until we can find a public SSL enabled IRC 
-    // server to test against. To use this you'll need to change the server 
-    // information below and the username/password. 
-
     @Override
     protected String sendUri() {
-        return "ircs://camel-prd@irc.codehaus.org:6667/#camel-test?nickname=camel-prd&password=blah";
+        return "ircs://{{camelTo}}@{{server}}?channels={{channel1}}";
     }
 
-    @Override    
+    @Override
     protected String fromUri() {
-        return "ircs://camel-con@irc.codehaus.org:6667/#camel-test?nickname=camel-con&password=blah";
-    }    
+        return "ircs://{{camelFrom}}@{{server}}?channels={{channel1}}";
+    }
 
 }
\ No newline at end of file
diff --git a/components/camel-irc/src/test/java/org/apache/camel/component/irc/IrcsWithSslContextParamsRouteTest.java b/components/camel-irc/src/test/java/org/apache/camel/component/irc/it/IrcsWithSslContextParamsRouteTest.java
similarity index 98%
rename from components/camel-irc/src/test/java/org/apache/camel/component/irc/IrcsWithSslContextParamsRouteTest.java
rename to components/camel-irc/src/test/java/org/apache/camel/component/irc/it/IrcsWithSslContextParamsRouteTest.java
index 8faab1a89ca..819771a9c99 100644
--- a/components/camel-irc/src/test/java/org/apache/camel/component/irc/IrcsWithSslContextParamsRouteTest.java
+++ b/components/camel-irc/src/test/java/org/apache/camel/component/irc/it/IrcsWithSslContextParamsRouteTest.java
@@ -14,7 +14,7 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
-package org.apache.camel.component.irc;
+package org.apache.camel.component.irc.it;
 
 import org.apache.camel.impl.JndiRegistry;
 import org.apache.camel.util.jsse.KeyStoreParameters;
diff --git a/components/camel-irc/src/test/resources/it-tests.properties b/components/camel-irc/src/test/resources/it-tests.properties
new file mode 100644
index 00000000000..81bc728649c
--- /dev/null
+++ b/components/camel-irc/src/test/resources/it-tests.properties
@@ -0,0 +1,26 @@
+## ---------------------------------------------------------------------------
+## 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.
+## ---------------------------------------------------------------------------
+
+server=chat.freenode.net:6697
+non.ssl.server=chat.freenode.net:8002
+channel1=#camel-test1
+channel2=#testroom2
+username=
+password=
+camelFrom=camel-irc-ituser
+camelTo=camel-prod
+
diff --git a/components/camel-ironmq/pom.xml b/components/camel-ironmq/pom.xml
index fb7c742aa64..572b48a6fa2 100644
--- a/components/camel-ironmq/pom.xml
+++ b/components/camel-ironmq/pom.xml
@@ -23,7 +23,7 @@
   <parent>
     <groupId>org.apache.camel</groupId>
     <artifactId>components</artifactId>
-    <version>2.23.0-SNAPSHOT</version>
+    <version>2.24.0-SNAPSHOT</version>
   </parent>
 
   <artifactId>camel-ironmq</artifactId>
diff --git a/components/camel-jackson/pom.xml b/components/camel-jackson/pom.xml
index 1607a0616e7..8c7a3a72a7e 100644
--- a/components/camel-jackson/pom.xml
+++ b/components/camel-jackson/pom.xml
@@ -23,7 +23,7 @@
     <parent>
         <groupId>org.apache.camel</groupId>
         <artifactId>components</artifactId>
-        <version>2.23.0-SNAPSHOT</version>
+        <version>2.24.0-SNAPSHOT</version>
     </parent>
 
     <artifactId>camel-jackson</artifactId>
diff --git a/components/camel-jacksonxml/pom.xml b/components/camel-jacksonxml/pom.xml
index 4e8656dd396..07d986e005d 100644
--- a/components/camel-jacksonxml/pom.xml
+++ b/components/camel-jacksonxml/pom.xml
@@ -23,7 +23,7 @@
   <parent>
     <groupId>org.apache.camel</groupId>
     <artifactId>components</artifactId>
-    <version>2.23.0-SNAPSHOT</version>
+    <version>2.24.0-SNAPSHOT</version>
   </parent>
 
   <artifactId>camel-jacksonxml</artifactId>
diff --git a/components/camel-jasypt/pom.xml b/components/camel-jasypt/pom.xml
index fb777b10380..c2248047956 100644
--- a/components/camel-jasypt/pom.xml
+++ b/components/camel-jasypt/pom.xml
@@ -23,7 +23,7 @@
     <parent>
         <groupId>org.apache.camel</groupId>
         <artifactId>components</artifactId>
-        <version>2.23.0-SNAPSHOT</version>
+        <version>2.24.0-SNAPSHOT</version>
     </parent>
 
     <artifactId>camel-jasypt</artifactId>
diff --git a/components/camel-javaspace/pom.xml b/components/camel-javaspace/pom.xml
index d09c2f925b8..27c9f208b2a 100644
--- a/components/camel-javaspace/pom.xml
+++ b/components/camel-javaspace/pom.xml
@@ -23,7 +23,7 @@
     <parent>
         <groupId>org.apache.camel</groupId>
         <artifactId>components</artifactId>
-        <version>2.23.0-SNAPSHOT</version>
+        <version>2.24.0-SNAPSHOT</version>
     </parent>
 
     <artifactId>camel-javaspace</artifactId>
diff --git a/components/camel-jaxb/pom.xml b/components/camel-jaxb/pom.xml
index f415811dec1..5b702f9c514 100644
--- a/components/camel-jaxb/pom.xml
+++ b/components/camel-jaxb/pom.xml
@@ -23,7 +23,7 @@
     <parent>
         <groupId>org.apache.camel</groupId>
         <artifactId>components</artifactId>
-        <version>2.23.0-SNAPSHOT</version>
+        <version>2.24.0-SNAPSHOT</version>
     </parent>
 
     <artifactId>camel-jaxb</artifactId>
diff --git a/components/camel-jbpm/pom.xml b/components/camel-jbpm/pom.xml
index 6c197d48b95..7927c7c2347 100644
--- a/components/camel-jbpm/pom.xml
+++ b/components/camel-jbpm/pom.xml
@@ -24,7 +24,7 @@
     <parent>
         <groupId>org.apache.camel</groupId>
         <artifactId>components</artifactId>
-        <version>2.23.0-SNAPSHOT</version>
+        <version>2.24.0-SNAPSHOT</version>
     </parent>
 
     <artifactId>camel-jbpm</artifactId>
@@ -43,32 +43,64 @@
             <artifactId>camel-core</artifactId>
         </dependency>
         <dependency>
-            <groupId>org.kie.remote</groupId>
-            <artifactId>kie-remote-client</artifactId>
+            <groupId>org.kie.server</groupId>
+            <artifactId>kie-server-client</artifactId>
             <version>${jbpm-version}</version>
-            <exclusions>
-                <exclusion>
-                    <groupId>org.hornetq</groupId>
-                    <artifactId>hornetq-core-client</artifactId>
-                </exclusion>
-                <exclusion>
-                    <groupId>org.hornetq</groupId>
-                    <artifactId>hornetq-jms-client</artifactId>
-                </exclusion>
-                <exclusion>
-                    <groupId>org.jboss.spec.javax.jms</groupId>
-                    <artifactId>jboss-jms-api_1.1_spec</artifactId>
-                </exclusion>
-                <exclusion>
-                    <groupId>org.jboss.spec.javax.xml.ws</groupId>
-                    <artifactId>jboss-jaxws-api_2.2_spec</artifactId>
-                </exclusion>
-                <exclusion>
-                    <groupId>org.jboss.logging</groupId>
-                    <artifactId>jboss-logging</artifactId>
-                </exclusion>
-            </exclusions>
+        </dependency>
+        
+        <!-- jBPM consumer -->
+        <dependency>
+            <groupId>org.kie</groupId>
+            <artifactId>kie-api</artifactId>
+            <version>${jbpm-version}</version>
+            <scope>provided</scope>
+            <optional>true</optional>
+        </dependency>
+        <dependency>
+            <groupId>org.kie</groupId>
+            <artifactId>kie-internal</artifactId>
+            <version>${jbpm-version}</version>
+            <scope>provided</scope>
+            <optional>true</optional>
+        </dependency>
+        <dependency>
+            <groupId>org.jbpm</groupId>
+            <artifactId>jbpm-services-api</artifactId>
+            <version>${jbpm-version}</version>
+            <scope>provided</scope>
+            <optional>true</optional>
+        </dependency>
+        <dependency>
+            <groupId>org.jbpm</groupId>
+            <artifactId>jbpm-case-mgmt-api</artifactId>
+            <version>${jbpm-version}</version>
+            <scope>provided</scope>
+            <optional>true</optional>
         </dependency>
+        <dependency>
+            <groupId>org.kie.server</groupId>
+            <artifactId>kie-server-services-common</artifactId>
+            <version>${jbpm-version}</version>
+            <scope>provided</scope>
+            <optional>true</optional>
+        </dependency>
+        <dependency>
+            <groupId>org.jbpm</groupId>
+            <artifactId>jbpm-persistence-api</artifactId>
+            <version>${jbpm-version}</version>
+            <scope>provided</scope>
+            <optional>true</optional>
+        </dependency>
+        
+        <!-- jBPM WorkItems -->
+        <dependency>
+        	<groupId>org.jbpm</groupId>
+        	<artifactId>jbpm-workitems-core</artifactId>
+        	<version>${jbpm-version}</version>
+        	<scope>provided</scope>
+        	<optional>true</optional>
+        </dependency>
+        
         <dependency>
             <groupId>org.jboss.logging</groupId>
             <artifactId>jboss-logging</artifactId>
@@ -105,6 +137,24 @@
             <artifactId>camel-test</artifactId>
             <scope>test</scope>
         </dependency>
+        <dependency>
+        	<groupId>org.mockito</groupId>
+        	<artifactId>mockito-core</artifactId>
+        	<scope>test</scope>
+        </dependency>
+        <dependency>
+            <groupId>org.jbpm</groupId>
+            <artifactId>jbpm-workitems-core</artifactId>
+            <version>${jbpm-version}</version>
+            <type>test-jar</type>
+            <scope>test</scope>
+            <exclusions>
+               <exclusion>
+                   <groupId>xml-apis</groupId>
+                   <artifactId>xml-apis</artifactId>
+               </exclusion>
+            </exclusions>
+        </dependency>
     </dependencies>
 
 </project>
diff --git a/components/camel-jbpm/src/main/docs/jbpm-component.adoc b/components/camel-jbpm/src/main/docs/jbpm-component.adoc
index 70e7796cdde..46928d21565 100644
--- a/components/camel-jbpm/src/main/docs/jbpm-component.adoc
+++ b/components/camel-jbpm/src/main/docs/jbpm-component.adoc
@@ -4,9 +4,9 @@
 *Available as of Camel version 2.6*
 
 The *jbpm* component provides integration with Business Process
-Management (BPM) Suit http://www.jbpm.org/[jBPM]. It uses
-kie-remote-client API to interact with jBPM instance over REST. The
-component supports only producer.
+Management http://www.jbpm.org/[jBPM]. It uses
+kie-server-client API to interact with jBPM instance over REST. The
+component supports both producer and consumer.
 
 Maven users will need to add the following dependency to their `pom.xml`
 for this component:
@@ -20,6 +20,111 @@ for this component:
 </dependency>
 ------------------------------------------------------------------------------------
 
+## Consumer
+
+jBPM Consumer allows to attach routes to 
+
+* ProcessEventListeners
+* TaskEventListners
+* CaseEventListeners
+
+### URI format
+
+[source,java]
+---------------------------------------------
+jbpm::events:type:[classifier][?options]
+---------------------------------------------
+
+==== Path Parameters (3 parameters):
+
+
+[width="100%",cols="2,5,^1,2",options="header"]
+|===
+| Name | Description | Default | Type
+| *events* | Classifier for the consumer to know which type of data it should attach to |  | URL
+| *type* | Type of event listener - supports: process, task, case |  | String
+| *classifier* | Used to distinguish routes for same event type|  | String
+|===
+
+Each route would then receive events when they are being produced by jBPM engine.
+
+Routes can be defined either in global way - on application level or deployed 
+together with business assets projects also knows as KJARs.
+
+Consumers are configured via KieServerExtension that is a pluggable interface to enhance
+jBPM with additional capabilities. It reacts to different life cycle phases of the KIE Server
+and by that is able to configure individual endpoints properly.
+
+### KJAR routes
+
+Create file named `camel-routes.xml` in the root folder of your KJAR (src/main/resources) so it will be automatically 
+discovered and Camel Context for given KJAR will be created.
+
+### Global routes
+
+Create file name `global-camel-routes` in the root of the class path of KIE Server. It will be automatically found and registered
+on every KJAR deployed to KIE Server.
+
+
+Example camel-routes.xml file that can be placed in the KJAR
+
+[source, xml]
+----
+<routes xmlns="http://camel.apache.org/schema/spring">
+    
+    <route id="processes">
+        <from uri="jbpm:events:process:test"/>
+        <filter>
+          <simple>${in.header.EventType} == 'beforeProcessStarted'</simple>
+          <to uri="log:kjar.processes?level=INFO&amp;showBody=true&amp;showHeaders=true"/>
+        </filter>
+    </route>
+    
+    <route id="tasks">
+        <from uri="jbpm:events:task:test"/>
+        <filter>
+          <simple>${in.header.EventType} starts with 'before'</simple>
+          <to uri="log:kjar.tasks?level=INFO&amp;showBody=true&amp;showHeaders=true"/>
+        </filter>
+    </route>
+</routes>
+----
+
+
+### Use of jBPM Component in KIE Server
+
+To make use of camel-jbpm component in a KIE Server it is as simple as just adding two jars into KIE Server application
+
+* camel-core
+* camel-jbpm
+
+then start KIE Server and you will see once booted following information in logs
+
+[source, plain]
+----
+Camel KIE Server extension has been successfully registered as server extension
+....
+
+Route: tasks started and consuming from: jbpm://events:task:test?deploymentId=form-rendering_1.0.0
+Total 2 routes, of which 2 are started
+Apache Camel 2.23.0-SNAPSHOT (CamelContext: KIE Server Camel context for container evaluation_1.0.0) started in 0.378 seconds
+o.k.server.services.impl.KieServerImpl   : Container evaluation_1.0.0 (for release id evaluation:evaluation:1.0.0) successfully started
+----
+
+To make use of jBPM Consumer jBPM deployment descriptor must also define camel specific event listeners of following types
+
+* `new org.apache.camel.component.jbpm.listeners.CamelProcessEventListener()`
+* `new org.apache.camel.component.jbpm.listeners.CamelTaskEventListener()`
+* `new org.apache.camel.component.jbpm.listeners.CamelCaseEventListener()`
+
+These must be set in either server level of kjar deployment descriptor (use MVEL as resolver type) - see jbpm docs for more details about
+deployment descriptors.
+
+## Producer
+
+Producer is dedicated to interact with jBPM via kie-server-client that uses exposed REST api of 
+jBPM (KIE Server).
+
 ### URI format
 
 [source,java]
@@ -47,40 +152,46 @@ jbpm:connectionURL
 
 with the following path and query parameters:
 
-==== Path Parameters (1 parameters):
+==== Path Parameters (2 parameters):
 
 
 [width="100%",cols="2,5,^1,2",options="header"]
 |===
 | Name | Description | Default | Type
 | *connectionURL* | *Required* The URL to the jBPM server. |  | URL
+| *eventListenerType* | Sets the event listener type to attach to |  | String
 |===
 
 
-==== Query Parameters (25 parameters):
+==== Query Parameters (30 parameters):
 
 
 [width="100%",cols="2,5,^1,2",options="header"]
 |===
 | Name | Description | Default | Type
-| *attachmentId* (producer) | attachId to use when retrieving attachments |  | Long
-| *contentId* (producer) | contentId to use when retrieving attachments |  | Long
-| *deploymentId* (producer) | *Required* The id of the deployment |  | String
-| *event* (producer) | the data associated with this event when signalEvent operation is performed |  | Object
-| *eventType* (producer) | the type of event to use when signalEvent operation is performed |  | String
-| *identifier* (producer) | identifier the global identifier |  | String
-| *language* (producer) | The language to use when filtering user tasks |  | String
-| *maxNumber* (producer) | the maximum number of rules that should be fired |  | Integer
+| *attachmentId* (common) | attachId to use when retrieving attachments |  | Long
+| *contentId* (common) | contentId to use when retrieving attachments |  | Long
+| *deploymentId* (common) | *Required* The id of the deployment |  | String
+| *emitterSendItems* (common) | Sets if event produced by emitter should be sent as single items or complete collection |  | Boolean
+| *event* (common) | the data associated with this event when signalEvent operation is performed |  | Object
+| *eventType* (common) | the type of event to use when signalEvent operation is performed |  | String
+| *identifier* (common) | identifier the global identifier |  | String
+| *maxNumber* (common) | the maximum number of rules that should be fired |  | Integer
+| *page* (common) | The page to use when retrieving user tasks |  | Integer
+| *pageSize* (common) | The page size to use when retrieving user tasks |  | Integer
+| *processId* (common) | the id of the process that should be acted upon |  | String
+| *processInstanceId* (common) | the id of the process instance |  | Long
+| *targetUserId* (common) | The targetUserId used when delegating a task |  | String
+| *task* (common) | The task instance to use with task operations |  | Task
+| *taskId* (common) | the id of the task |  | Long
+| *timeout* (common) | A timeout value |  | Integer
+| *userId* (common) | userId to use with task operations |  | String
+| *value* (common) | the value to assign to the global identifier |  | Object
+| *workItemId* (common) | the id of the work item |  | Long
+| *bridgeErrorHandler* (consumer) | Allows for bridging the consumer to the Camel routing Error Handler, which mean any exceptions occurred while the consumer is trying to pickup incoming messages, or the likes, will now be processed as a message and handled by the routing Error Handler. By default the consumer will use the org.apache.camel.spi.ExceptionHandler to deal with exceptions, that will be logged at WARN or ERROR level and ignored. | false | boolean
+| *exceptionHandler* (consumer) | To let the consumer use a custom ExceptionHandler. Notice if the option bridgeErrorHandler is enabled then this option is not in use. By default the consumer will deal with exceptions, that will be logged at WARN or ERROR level and ignored. |  | ExceptionHandler
+| *exchangePattern* (consumer) | Sets the exchange pattern when the consumer creates an exchange. |  | ExchangePattern
 | *operation* (producer) | The operation to perform | startProcess | String
-| *processId* (producer) | the id of the process that should be acted upon |  | String
-| *processInstanceId* (producer) | the id of the process instance |  | Long
-| *targetUserId* (producer) | The targetUserId used when delegating a task |  | String
-| *task* (producer) | The task instance to use with task operations |  | Task
-| *taskId* (producer) | the id of the task |  | Long
-| *timeout* (producer) | A timeout value |  | Integer
-| *userId* (producer) | userId to use with task operations |  | String
-| *value* (producer) | the value to assign to the global identifier |  | Object
-| *workItemId* (producer) | the id of the work item |  | Long
 | *entities* (advanced) | The potentialOwners when nominateTask operation is performed |  | List
 | *extraJaxbClasses* (advanced) | To load additional classes when working with XML |  | Class[]
 | *parameters* (advanced) | the variables that should be set for various operations |  | Map
@@ -153,23 +264,29 @@ org.infinispan.notifications.cachelistener.event.Event.Type
 
 |CamelJBPMContentId |0 |Long |contentId to use when retrieving attachments
 
-|CamelJBPMEntityList |null |List<OrganizationalEntity> |The potentialOwners when nominateTask operation is performed
+|CamelJBPMEntityList |null |List<String> |The potentialOwners when nominateTask operation is performed
 
-|CamelJBPMStatusList |null |List<Status> |The list of status to use when filtering tasks
+|CamelJBPMStatusList |null |List<String> |The list of status to use when filtering tasks
 |=======================================================================
 
 ### Example
 
 Below is an example route that starts a business process with id
-project1.integration-test and deploymentId
-org.kie.example:project1:1.0.0-SNAPSHOT
+evaluation. To run this example you need jBPM to run locally, easiest is to use single zip 
+distribution - downloaded from jbpm.org. Next, start it and import Evaluation sample project, build and deploy.
+Once done this test can be ran out of the box.
 
 [source,java]
 ----------------------------------------------------------------------------------------------
+Map<String, Object> params = new HashMap<>();
+params.put("employee", "wbadmin");
+params.put("reason", "Camel asks for it");
+
 from("direct:start")
-        .setHeader(JBPMConstants.PROCESS_ID, constant("project1.integration-test"))
-        .to("jbpm:http://localhost:8080/business-central?userName=bpmsAdmin&password=pa$word1"
- + "&deploymentId=org.kie.example:project1:1.0.0-SNAPSHOT");
+        .setHeader(JBPMConstants.PROCESS_ID, constant("evaluation"))
+        .setHeader((JBPMConstants.PARAMETERS, params))
+        .to("jbpm:http://localhost:8080/kie-server/services/rest/server?userName=wbadmin&password=wbadmin
+        &deploymentId=evaluation");
 ----------------------------------------------------------------------------------------------
 
 ### See Also
diff --git a/components/camel-jbpm/src/main/java/org/apache/camel/component/jbpm/JBPMCamelConsumerAware.java b/components/camel-jbpm/src/main/java/org/apache/camel/component/jbpm/JBPMCamelConsumerAware.java
new file mode 100644
index 00000000000..85b4df2a626
--- /dev/null
+++ b/components/camel-jbpm/src/main/java/org/apache/camel/component/jbpm/JBPMCamelConsumerAware.java
@@ -0,0 +1,29 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.camel.component.jbpm;
+
+/**
+ * Indicates that class implementing this interface should receive (at some point)
+ * JBPMConsumer instance that is required to operate.
+ */
+public interface JBPMCamelConsumerAware {
+
+    void addConsumer(JBPMConsumer consumer);
+    
+    void removeConsumer(JBPMConsumer consumer);
+}
diff --git a/components/camel-jbpm/src/main/java/org/apache/camel/component/jbpm/JBPMComponent.java b/components/camel-jbpm/src/main/java/org/apache/camel/component/jbpm/JBPMComponent.java
index f562234ed47..ed03b515f17 100644
--- a/components/camel-jbpm/src/main/java/org/apache/camel/component/jbpm/JBPMComponent.java
+++ b/components/camel-jbpm/src/main/java/org/apache/camel/component/jbpm/JBPMComponent.java
@@ -26,7 +26,11 @@
 
     protected Endpoint createEndpoint(String uri, String remaining, Map<String, Object> parameters) throws Exception {
         JBPMConfiguration configuration = new JBPMConfiguration();
-        configuration.setConnectionURL(new URL(remaining));
+        if (remaining.startsWith("events")) {
+            configuration.setEventListenerType(remaining.split(":")[1]);
+        } else {        
+            configuration.setConnectionURL(new URL(remaining));
+        }
         setProperties(configuration, parameters);
         return new JBPMEndpoint(uri, this, configuration);
     }
diff --git a/components/camel-jbpm/src/main/java/org/apache/camel/component/jbpm/JBPMConfiguration.java b/components/camel-jbpm/src/main/java/org/apache/camel/component/jbpm/JBPMConfiguration.java
index c4a30c70690..b415bfea305 100644
--- a/components/camel-jbpm/src/main/java/org/apache/camel/component/jbpm/JBPMConfiguration.java
+++ b/components/camel-jbpm/src/main/java/org/apache/camel/component/jbpm/JBPMConfiguration.java
@@ -17,6 +17,7 @@
 package org.apache.camel.component.jbpm;
 
 import java.net.URL;
+import java.util.Arrays;
 import java.util.List;
 import java.util.Map;
 
@@ -24,18 +25,18 @@
 import org.apache.camel.spi.UriParam;
 import org.apache.camel.spi.UriParams;
 import org.apache.camel.spi.UriPath;
-import org.kie.api.task.model.OrganizationalEntity;
-import org.kie.api.task.model.Status;
 import org.kie.api.task.model.Task;
 
 @UriParams
 public class JBPMConfiguration {
 
-    @UriPath @Metadata(required = "true")
+    @UriPath
+    @Metadata(required = "true")
     private URL connectionURL;
     @UriParam(label = "producer", defaultValue = "startProcess")
     private String operation;
-    @UriParam @Metadata(required = "true")
+    @UriParam
+    @Metadata(required = "true")
     private String deploymentId;
     @UriParam
     private Long processInstanceId;
@@ -58,7 +59,9 @@
     @UriParam
     private String userId;
     @UriParam
-    private String language;
+    private Integer page = 0;
+    @UriParam
+    private Integer pageSize = 10;
     @UriParam
     private String targetUserId;
     @UriParam
@@ -68,9 +71,9 @@
     @UriParam
     private Task task;
     @UriParam(label = "advanced")
-    private List<OrganizationalEntity> entities;
+    private List<String> entities;
     @UriParam(label = "filter")
-    private List<Status> statuses;
+    private List<String> statuses;
     @UriParam(label = "security", secret = true)
     private String userName;
     @UriParam(label = "security", secret = true)
@@ -81,6 +84,11 @@
     private Map<String, Object> parameters;
     @UriParam(label = "advanced")
     private Class[] extraJaxbClasses;
+    @UriParam
+    private Boolean emitterSendItems;
+
+    @UriPath
+    private String eventListenerType;
 
     public String getOperation() {
         return operation;
@@ -153,7 +161,8 @@ public Object getEvent() {
     }
 
     /**
-     * the data associated with this event when signalEvent operation is performed
+     * the data associated with this event when signalEvent operation is
+     * performed
      */
     public void setEvent(Object event) {
         this.event = event;
@@ -197,7 +206,7 @@ public Long getTaskId() {
     }
 
     /**
-     *the id of the task
+     * the id of the task
      */
     public void setTaskId(Long taskId) {
         this.taskId = taskId;
@@ -225,15 +234,26 @@ public void setTask(Task task) {
         this.task = task;
     }
 
-    public String getLanguage() {
-        return language;
+    public Integer getPage() {
+        return page;
     }
 
     /**
-     * The language to use when filtering user tasks
+     * The page to use when retrieving user tasks
      */
-    public void setLanguage(String language) {
-        this.language = language;
+    public void setPage(Integer page) {
+        this.page = page;
+    }
+
+    public Integer getPageSize() {
+        return pageSize;
+    }
+
+    /**
+     * The page size to use when retrieving user tasks
+     */
+    public void setPageSize(Integer pageSize) {
+        this.pageSize = pageSize;
     }
 
     public String getTargetUserId() {
@@ -269,25 +289,25 @@ public void setContentId(Long contentId) {
         this.contentId = contentId;
     }
 
-    public List<OrganizationalEntity> getEntities() {
+    public List<String> getEntities() {
         return entities;
     }
 
     /**
      * The potentialOwners when nominateTask operation is performed
      */
-    public void setEntities(List<OrganizationalEntity> entities) {
+    public void setEntities(List<String> entities) {
         this.entities = entities;
     }
 
-    public List<Status> getStatuses() {
+    public List<String> getStatuses() {
         return statuses;
     }
 
     /**
      * The list of status to use when filtering tasks
      */
-    public void setStatuses(List<Status> statuses) {
+    public void setStatuses(List<String> statuses) {
         this.statuses = statuses;
     }
 
@@ -356,4 +376,37 @@ public void setTimeout(Integer timeout) {
     public void setExtraJaxbClasses(Class[] extraJaxbClasses) {
         this.extraJaxbClasses = extraJaxbClasses;
     }
+
+    public String getEventListenerType() {
+        return eventListenerType;
+    }
+
+    /**
+     * Sets the event listener type to attach to
+     */
+    public void setEventListenerType(String eventListenerType) {
+        this.eventListenerType = eventListenerType;
+    }
+
+    public Boolean getEmitterSendItems() {
+        return emitterSendItems;
+    }
+
+    /**
+     * Sets if event produced by emitter should be sent as single items or
+     * complete collection
+     */
+    public void setEmitterSendItems(Boolean emiterSendItems) {
+        this.emitterSendItems = emiterSendItems;
+    }
+
+    @Override
+    public String toString() {
+        return "JBPMConfiguration [connectionURL=" + connectionURL + ", operation=" + operation + ", deploymentId=" + deploymentId + ", processInstanceId=" + processInstanceId
+               + ", value=" + value + ", processId=" + processId + ", eventType=" + eventType + ", event=" + event + ", maxNumber=" + maxNumber + ", identifier=" + identifier
+               + ", workItemId=" + workItemId + ", taskId=" + taskId + ", userId=" + userId + ", page=" + page + ", pageSize=" + pageSize + ", targetUserId=" + targetUserId
+               + ", attachmentId=" + attachmentId + ", contentId=" + contentId + ", task=" + task + ", entities=" + entities + ", statuses=" + statuses + ", userName=" + userName
+               + ", password=" + password + ", timeout=" + timeout + ", parameters=" + parameters + ", extraJaxbClasses=" + Arrays.toString(extraJaxbClasses)
+               + ", eventListenerType=" + eventListenerType + "]";
+    }
 }
diff --git a/components/camel-jbpm/src/main/java/org/apache/camel/component/jbpm/JBPMConstants.java b/components/camel-jbpm/src/main/java/org/apache/camel/component/jbpm/JBPMConstants.java
index 6b00d02598a..94ff0ca77ba 100644
--- a/components/camel-jbpm/src/main/java/org/apache/camel/component/jbpm/JBPMConstants.java
+++ b/components/camel-jbpm/src/main/java/org/apache/camel/component/jbpm/JBPMConstants.java
@@ -30,10 +30,25 @@
     String TASK_ID = "CamelJBPMTaskId";
     String TASK = "CamelJBPMTask";
     String USER_ID = "CamelJBPMUserId";
-    String TARGET_USER_ID = "CamelJBPMTargetUserId";
-    String LANGUAGE = "CamelJBPMLanguage";
+    String TARGET_USER_ID = "CamelJBPMTargetUserId";    
     String ATTACHMENT_ID = "CamelJBPMAttachmentId";
     String CONTENT_ID = "CamelJBPMContentId";
     String ENTITY_LIST = "CamelJBPMEntityList";
     String STATUS_LIST = "CamelJBPMStatusList";
+    String RESULT_PAGE = "CamelJBPMResultPage";
+    String RESULT_PAGE_SIZE = "CamelJBPMResultPageSize";
+    
+    
+    String JBPM_PROCESS_EVENT_LISTENER = "process";
+    String JBPM_TASK_EVENT_LISTENER = "task";
+    String JBPM_CASE_EVENT_LISTENER = "case";
+    String JBPM_EVENT_EMITTER = "emitter";
+    
+    String GLOBAL_CAMEL_CONTEXT_SERVICE_KEY = "GlobalCamelService";
+    String DEPLOYMENT_CAMEL_CONTEXT_SERVICE_KEY_POSTFIX = "_CamelService";
+    String CAMEL_ENDPOINT_ID_WI_PARAM = "CamelEndpointId";
+    String RESPONSE_WI_PARAM = "Response";
+    String MESSAGE_WI_PARAM = "Message";
+
+    
 }
diff --git a/components/camel-jbpm/src/main/java/org/apache/camel/component/jbpm/JBPMConsumer.java b/components/camel-jbpm/src/main/java/org/apache/camel/component/jbpm/JBPMConsumer.java
new file mode 100644
index 00000000000..6c5c6f90647
--- /dev/null
+++ b/components/camel-jbpm/src/main/java/org/apache/camel/component/jbpm/JBPMConsumer.java
@@ -0,0 +1,208 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.camel.component.jbpm;
+
+import org.apache.camel.AsyncCallback;
+import org.apache.camel.Endpoint;
+import org.apache.camel.Exchange;
+import org.apache.camel.ExchangePattern;
+import org.apache.camel.Processor;
+import org.apache.camel.component.jbpm.emitters.CamelEventEmitter;
+import org.apache.camel.component.jbpm.listeners.CamelCaseEventListener;
+import org.apache.camel.component.jbpm.listeners.CamelProcessEventListener;
+import org.apache.camel.component.jbpm.listeners.CamelTaskEventListener;
+import org.apache.camel.impl.DefaultConsumer;
+import org.jbpm.services.api.DeploymentEvent;
+import org.jbpm.services.api.DeploymentEventListener;
+import org.jbpm.services.api.DeploymentService;
+import org.jbpm.services.api.ListenerSupport;
+import org.jbpm.services.api.model.DeployedUnit;
+import org.jbpm.services.api.service.ServiceRegistry;
+import org.kie.internal.runtime.manager.CacheManager;
+import org.kie.internal.runtime.manager.InternalRuntimeManager;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+
+public class JBPMConsumer extends DefaultConsumer implements DeploymentEventListener {
+    
+    private static final transient Logger LOGGER = LoggerFactory.getLogger(JBPMConsumer.class);
+   
+    private JBPMEndpoint endpoint;
+    private JBPMConfiguration configuration;
+    
+    public JBPMConsumer(Endpoint endpoint, Processor processor) {
+        super(endpoint, processor);
+        
+        this.endpoint = (JBPMEndpoint) endpoint;
+        this.configuration = ((JBPMEndpoint) getEndpoint()).getConfiguration();
+    }
+
+    @Override
+    protected void doStart() throws Exception {
+        super.doStart();
+        
+        DeploymentService deploymentService = (DeploymentService) ServiceRegistry.get().service(ServiceRegistry.DEPLOYMENT_SERVICE);        
+        
+        if (configuration.getDeploymentId() != null) {
+            InternalRuntimeManager manager = (InternalRuntimeManager) deploymentService.getRuntimeManager(configuration.getDeploymentId());
+            configure(manager, this);
+            
+            LOGGER.debug("JBPM Camel Consumer configured and started for deployment id {}", configuration.getDeploymentId());
+        } else {
+            
+            ((ListenerSupport) deploymentService).addListener(this);
+            
+            for (DeployedUnit deployed : deploymentService.getDeployedUnits()) {
+                InternalRuntimeManager manager = (InternalRuntimeManager) deployed.getRuntimeManager();
+                configure(manager, this); 
+            }
+            
+            LOGGER.debug("JBPM Camel Consumer configured and started on all available deployments");
+        }
+        
+        
+    }
+
+    @Override
+    protected void doStop() throws Exception {
+        super.doStop();
+        DeploymentService deploymentService = (DeploymentService) ServiceRegistry.get().service(ServiceRegistry.DEPLOYMENT_SERVICE);        
+        if (configuration.getDeploymentId() != null) {
+            LOGGER.debug("JBPM Camel Consumer unconfigured and stopped for deployment id {}", configuration.getDeploymentId());
+        } else {
+            ((ListenerSupport) deploymentService).removeListener(this);
+            
+            LOGGER.debug("JBPM Camel Consumer unconfigured and stopped on all available deployments");
+        }
+        
+        if (JBPMConstants.JBPM_EVENT_EMITTER.equals(configuration.getEventListenerType())) {
+            ServiceRegistry.get().remove("CamelEventEmitter");
+        }
+        
+    }
+
+    public void sendMessage(String eventType, Object body) {
+        Exchange exchange = getEndpoint().createExchange(ExchangePattern.InOnly);
+        exchange.getIn().setHeader("EventType", eventType);
+        
+        exchange.getIn().setBody(body);
+
+        if (!endpoint.isSynchronous()) {
+            getAsyncProcessor().process(exchange, new AsyncCallback() {
+                @Override
+                public void done(boolean doneSync) {
+                    // handle any thrown exception
+                    if (exchange.getException() != null) {
+                        getExceptionHandler().handleException("Error processing exchange", exchange, exchange.getException());
+                    }
+                }
+            });
+        } else {
+            try {
+                getProcessor().process(exchange);
+            } catch (Exception e) {
+                exchange.setException(e);
+            }
+
+            // handle any thrown exception
+            if (exchange.getException() != null) {
+                getExceptionHandler().handleException("Error processing exchange", exchange, exchange.getException());
+            }
+        }
+    }
+    
+    @Override
+    public void onDeploy(DeploymentEvent event) {
+        InternalRuntimeManager manager = (InternalRuntimeManager) event.getDeployedUnit().getRuntimeManager();
+        configure(manager, this);       
+
+    }
+
+    @Override
+    public void onUnDeploy(DeploymentEvent event) {  
+        // no-op
+    }
+
+    @Override
+    public void onActivate(DeploymentEvent event) {
+        // no-op
+        
+    }
+
+    @Override
+    public void onDeactivate(DeploymentEvent event) {
+        // no-op
+        
+    }
+
+    
+    protected void configure(InternalRuntimeManager manager, JBPMConsumer consumer) {
+        String eventListenerType = configuration.getEventListenerType();
+        if (eventListenerType == null) {
+            return;
+        }
+        
+       
+        configureConsumer(eventListenerType, manager, consumer);
+        
+    }
+    
+    protected void configureConsumer(String eventListenerType, InternalRuntimeManager manager, JBPMConsumer consumer) {
+        LOGGER.debug("Configuring Camel JBPM Consumer for {} on runtime manager {}", eventListenerType, manager);
+       
+        CacheManager cacheManager = manager.getCacheManager();
+        JBPMCamelConsumerAware consumerAware = null;
+        if (JBPMConstants.JBPM_PROCESS_EVENT_LISTENER.equals(eventListenerType)) {
+            consumerAware = (JBPMCamelConsumerAware) cacheManager.get("new org.apache.camel.component.jbpm.listeners.CamelProcessEventListener()");
+            if (consumerAware == null) {
+                consumerAware = new CamelProcessEventListener();
+                cacheManager.add("new org.apache.camel.component.jbpm.listeners.CamelProcessEventListener()", consumerAware);
+            }
+            LOGGER.debug("Configuring JBPMConsumer on process event listener {}", consumerAware);
+        } else if (JBPMConstants.JBPM_TASK_EVENT_LISTENER.equals(eventListenerType)) {
+            consumerAware = (JBPMCamelConsumerAware) cacheManager.get("new org.apache.camel.component.jbpm.listeners.CamelTaskEventListener()");
+            if (consumerAware == null) {
+                consumerAware = new CamelTaskEventListener();
+                cacheManager.add("new org.apache.camel.component.jbpm.listeners.CamelTaskEventListener()", consumerAware);
+            }
+            LOGGER.debug("Configuring JBPMConsumer on task event listener {}", consumerAware);
+        } else if (JBPMConstants.JBPM_CASE_EVENT_LISTENER.equals(eventListenerType)) {
+            consumerAware = (JBPMCamelConsumerAware) cacheManager.get("new org.apache.camel.component.jbpm.listeners.CamelCaseEventListener()");
+            if (consumerAware == null) {
+                consumerAware = new CamelCaseEventListener();
+                cacheManager.add("new org.apache.camel.component.jbpm.listeners.CamelCaseEventListener()", consumerAware);
+            }
+            LOGGER.debug("Configuring JBPMConsumer on case event listener {}", consumerAware);
+        } else if (JBPMConstants.JBPM_EVENT_EMITTER.equals(eventListenerType)) {
+            LOGGER.debug("Configuring JBPMConsumer for event emitter");
+            ServiceRegistry.get().register("CamelEventEmitter", new CamelEventEmitter(this, configuration.getEmitterSendItems()));
+            
+            return;
+        }        
+  
+        LOGGER.debug("Adding consumer {} on {}", consumer, consumerAware);
+        consumerAware.addConsumer(consumer);    
+        
+    }
+
+    @Override
+    public String toString() {
+        return "JBPMConsumer [endpoint=" + endpoint + ", configuration=" + configuration + "]";
+    }
+}
diff --git a/components/camel-jbpm/src/main/java/org/apache/camel/component/jbpm/JBPMEndpoint.java b/components/camel-jbpm/src/main/java/org/apache/camel/component/jbpm/JBPMEndpoint.java
index 1a5d5e5e0d6..a8af4eeff64 100644
--- a/components/camel-jbpm/src/main/java/org/apache/camel/component/jbpm/JBPMEndpoint.java
+++ b/components/camel-jbpm/src/main/java/org/apache/camel/component/jbpm/JBPMEndpoint.java
@@ -18,6 +18,9 @@
 
 import java.net.MalformedURLException;
 import java.net.URISyntaxException;
+import java.util.Arrays;
+import java.util.LinkedHashSet;
+import java.util.List;
 
 import org.apache.camel.Consumer;
 import org.apache.camel.Processor;
@@ -25,16 +28,17 @@
 import org.apache.camel.impl.DefaultEndpoint;
 import org.apache.camel.spi.UriEndpoint;
 import org.apache.camel.spi.UriParam;
-import org.kie.api.runtime.manager.RuntimeEngine;
-import org.kie.remote.client.api.RemoteRestRuntimeEngineBuilder;
-import org.kie.services.client.api.RemoteRuntimeEngineFactory;
+import org.kie.server.client.KieServicesClient;
+import org.kie.server.client.KieServicesConfiguration;
+import org.kie.server.client.KieServicesFactory;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
 /**
- * The jbpm component provides integration with jBPM (Business Process Management).
+ * The jbpm component provides integration with jBPM (Business Process
+ * Management).
  */
-@UriEndpoint(firstVersion = "2.6.0", scheme = "jbpm", title = "JBPM", syntax = "jbpm:connectionURL", producerOnly = true, label = "process")
+@UriEndpoint(firstVersion = "2.6.0", scheme = "jbpm", title = "JBPM", syntax = "jbpm:connectionURL", label = "process")
 public class JBPMEndpoint extends DefaultEndpoint {
     private static final transient Logger LOGGER = LoggerFactory.getLogger(JBPMEndpoint.class);
 
@@ -47,35 +51,25 @@ public JBPMEndpoint(String uri, JBPMComponent component, JBPMConfiguration confi
     }
 
     public Producer createProducer() throws Exception {
-        RemoteRestRuntimeEngineBuilder engineBuilder = RemoteRuntimeEngineFactory.newRestBuilder();
-        if (configuration.getUserName() != null) {
-            engineBuilder.addUserName(configuration.getUserName());
-        }
-        if (configuration.getPassword() != null) {
-            engineBuilder.addPassword(configuration.getPassword());
-        }
-        if (configuration.getDeploymentId() != null) {
-            engineBuilder.addDeploymentId(configuration.getDeploymentId());
-        }
-        if (configuration.getConnectionURL() != null) {
-            engineBuilder.addUrl(configuration.getConnectionURL());
-        }
-        if (configuration.getProcessInstanceId() != null) {
-            engineBuilder.addProcessInstanceId(configuration.getProcessInstanceId());
-        }
+        KieServicesConfiguration kieConfiguration = KieServicesFactory.newRestConfiguration(configuration.getConnectionURL().toExternalForm(), configuration.getUserName(),
+                                                                                            configuration.getPassword());
+
         if (configuration.getTimeout() != null) {
-            engineBuilder.addTimeout(configuration.getTimeout());
+            kieConfiguration.setTimeout(configuration.getTimeout());
         }
         if (configuration.getExtraJaxbClasses() != null) {
-            engineBuilder.addExtraJaxbClasses(configuration.getExtraJaxbClasses());
+            List<Class<?>> classes = Arrays.asList(configuration.getExtraJaxbClasses());
+            kieConfiguration.addExtraClasses(new LinkedHashSet<>(classes));
         }
-        RuntimeEngine runtimeEngine = engineBuilder.build();
 
-        return new JBPMProducer(this, runtimeEngine);
+        KieServicesClient kieServerClient = KieServicesFactory.newKieServicesClient(kieConfiguration);
+        LOGGER.debug("JBPM Producer created with KieServerClient configured for {}", configuration.getConnectionURL());
+        return new JBPMProducer(this, kieServerClient);
     }
 
     public Consumer createConsumer(Processor processor) throws Exception {
-        throw new UnsupportedOperationException("Consumer not supported for " + getClass().getSimpleName() + " endpoint");
+        LOGGER.debug("JBPM Consumer created and configured for deployment {}", configuration.getDeploymentId());
+        return new JBPMConsumer(this, processor);
     }
 
     public boolean isSingleton() {
diff --git a/components/camel-jbpm/src/main/java/org/apache/camel/component/jbpm/JBPMProducer.java b/components/camel-jbpm/src/main/java/org/apache/camel/component/jbpm/JBPMProducer.java
index 8fc9fc4fdb4..9688a40ff2e 100644
--- a/components/camel-jbpm/src/main/java/org/apache/camel/component/jbpm/JBPMProducer.java
+++ b/components/camel-jbpm/src/main/java/org/apache/camel/component/jbpm/JBPMProducer.java
@@ -16,7 +16,9 @@
  */
 package org.apache.camel.component.jbpm;
 
+import java.util.ArrayList;
 import java.util.Collection;
+import java.util.Collections;
 import java.util.List;
 import java.util.Map;
 
@@ -24,37 +26,42 @@
 import org.apache.camel.Message;
 import org.apache.camel.impl.DefaultProducer;
 import org.apache.camel.util.ExchangeHelper;
-import org.kie.api.runtime.KieSession;
-import org.kie.api.runtime.manager.RuntimeEngine;
-import org.kie.api.runtime.process.ProcessInstance;
-import org.kie.api.task.TaskService;
-import org.kie.api.task.model.Attachment;
-import org.kie.api.task.model.Content;
-import org.kie.api.task.model.OrganizationalEntity;
-import org.kie.api.task.model.Status;
+import org.kie.api.KieServices;
+import org.kie.api.command.BatchExecutionCommand;
+import org.kie.api.command.Command;
+import org.kie.api.command.KieCommands;
+import org.kie.api.runtime.ExecutionResults;
 import org.kie.api.task.model.Task;
-import org.kie.api.task.model.TaskSummary;
+import org.kie.server.api.model.ServiceResponse;
+import org.kie.server.api.model.instance.ProcessInstance;
+import org.kie.server.api.model.instance.TaskAttachment;
+import org.kie.server.api.model.instance.TaskInstance;
+import org.kie.server.api.model.instance.TaskSummary;
+import org.kie.server.client.KieServicesClient;
+import org.kie.server.client.ProcessServicesClient;
+import org.kie.server.client.QueryServicesClient;
+import org.kie.server.client.RuleServicesClient;
+import org.kie.server.client.UserTaskServicesClient;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
 public class JBPMProducer extends DefaultProducer {
     private static final transient Logger LOGGER = LoggerFactory.getLogger(JBPMProducer.class);
-    private KieSession kieSession;
-    private TaskService taskService;
+
+    private static KieCommands commandsFactory = KieServices.get().getCommands();
+
     private JBPMConfiguration configuration;
-    private RuntimeEngine runtimeEngine;
+    private KieServicesClient kieServicesClient;
 
-    public JBPMProducer(JBPMEndpoint endpoint, RuntimeEngine runtimeEngine) {
+    public JBPMProducer(JBPMEndpoint endpoint, KieServicesClient kieServicesClient) {
         super(endpoint);
         this.configuration = endpoint.getConfiguration();
-        this.runtimeEngine = runtimeEngine;
+        this.kieServicesClient = kieServicesClient;
     }
 
     @Override
     protected void doStart() throws Exception {
         LOGGER.trace("starting producer");
-        kieSession = runtimeEngine.getKieSession();
-        taskService = runtimeEngine.getTaskService();
         super.doStart();
         LOGGER.trace("started producer");
     }
@@ -62,17 +69,10 @@ protected void doStart() throws Exception {
     @Override
     protected void doStop() throws Exception {
         super.doStop();
-        if (kieSession != null) {
-            kieSession = null;
-        }
-
-        if (taskService != null) {
-            taskService = null;
-        }
     }
 
     public void process(Exchange exchange) throws Exception {
-        getOperation(exchange).execute(kieSession, taskService, configuration, exchange);
+        getOperation(exchange).execute(kieServicesClient, configuration, exchange);
     }
 
     Operation getOperation(Exchange exchange) {
@@ -89,237 +89,299 @@ Operation getOperation(Exchange exchange) {
 
     enum Operation {
 
-        //PROCESS OPERATIONS
+        // PROCESS OPERATIONS
         startProcess {
             @Override
-            void execute(KieSession kieSession, TaskService taskService, JBPMConfiguration configuration, Exchange exchange) {
-                ProcessInstance processInstance = kieSession.startProcess(getProcessId(configuration, exchange), getParameters(configuration, exchange));
+            void execute(KieServicesClient kieServicesClient, JBPMConfiguration configuration, Exchange exchange) {
+                ProcessServicesClient processClient = kieServicesClient.getServicesClient(ProcessServicesClient.class);
+                Long processInstance = processClient.startProcess(configuration.getDeploymentId(), getProcessId(configuration, exchange), getParameters(configuration, exchange));
                 setResult(exchange, processInstance);
             }
-        }, abortProcessInstance {
+        },
+        abortProcessInstance {
             @Override
-            void execute(KieSession kieSession, TaskService taskService, JBPMConfiguration configuration, Exchange exchange) {
-                kieSession.abortProcessInstance(safe(getProcessInstanceId(configuration, exchange)));
+            void execute(KieServicesClient kieServicesClient, JBPMConfiguration configuration, Exchange exchange) {
+                ProcessServicesClient processClient = kieServicesClient.getServicesClient(ProcessServicesClient.class);
+                processClient.abortProcessInstance(configuration.getDeploymentId(), safe(getProcessInstanceId(configuration, exchange)));
             }
-        }, signalEvent {
+        },
+        signalEvent {
             @Override
-            void execute(KieSession kieSession, TaskService taskService, JBPMConfiguration configuration, Exchange exchange) {
+            void execute(KieServicesClient kieServicesClient, JBPMConfiguration configuration, Exchange exchange) {
+                ProcessServicesClient processClient = kieServicesClient.getServicesClient(ProcessServicesClient.class);
                 Long processInstanceId = getProcessInstanceId(configuration, exchange);
                 if (processInstanceId != null) {
-                    kieSession.signalEvent(getEventType(configuration, exchange), getEvent(configuration, exchange), processInstanceId);
+                    processClient.signalProcessInstance(configuration.getDeploymentId(), processInstanceId, getEventType(configuration, exchange),
+                                                        getEvent(configuration, exchange));
                 } else {
-                    kieSession.signalEvent(getEventType(configuration, exchange), getEvent(configuration, exchange));
+                    processClient.signal(configuration.getDeploymentId(), getEventType(configuration, exchange), getEvent(configuration, exchange));
                 }
             }
-        }, getProcessInstance {
+        },
+        getProcessInstance {
             @Override
-            void execute(KieSession kieSession, TaskService taskService, JBPMConfiguration configuration, Exchange exchange) {
-                ProcessInstance processInstance = kieSession.getProcessInstance(safe(getProcessInstanceId(configuration, exchange)));
+            void execute(KieServicesClient kieServicesClient, JBPMConfiguration configuration, Exchange exchange) {
+                ProcessServicesClient processClient = kieServicesClient.getServicesClient(ProcessServicesClient.class);
+                ProcessInstance processInstance = processClient.getProcessInstance(configuration.getDeploymentId(), safe(getProcessInstanceId(configuration, exchange)));
                 setResult(exchange, processInstance);
             }
-        }, getProcessInstances {
+        },
+        getProcessInstances {
             @Override
-            void execute(KieSession kieSession, TaskService taskService, JBPMConfiguration configuration, Exchange exchange) {
-                Collection<ProcessInstance> processInstances = kieSession.getProcessInstances();
+            void execute(KieServicesClient kieServicesClient, JBPMConfiguration configuration, Exchange exchange) {
+                QueryServicesClient queryClient = kieServicesClient.getServicesClient(QueryServicesClient.class);
+                Collection<ProcessInstance> processInstances = queryClient.findProcessInstances(getPage(configuration, exchange), getPageSize(configuration, exchange));
                 setResult(exchange, processInstances);
             }
         },
 
-        //RULE OPERATIONS
+        // RULE OPERATIONS
         fireAllRules {
             @Override
-            void execute(KieSession kieSession, TaskService taskService, JBPMConfiguration configuration, Exchange exchange) {
+            void execute(KieServicesClient kieServicesClient, JBPMConfiguration configuration, Exchange exchange) {
+                RuleServicesClient ruleClient = kieServicesClient.getServicesClient(RuleServicesClient.class);
+                List<Command<?>> commands = new ArrayList<Command<?>>();
+                BatchExecutionCommand executionCommand = commandsFactory.newBatchExecution(commands);
+
                 Integer max = getMaxNumber(configuration, exchange);
-                int rulesFired;
                 if (max != null) {
-                    rulesFired = kieSession.fireAllRules(max);
+                    commands.add(commandsFactory.newFireAllRules(max));
                 } else {
-                    rulesFired = kieSession.fireAllRules();
+                    commands.add(commandsFactory.newFireAllRules());
                 }
-                setResult(exchange, rulesFired);
+                ServiceResponse<ExecutionResults> reply = ruleClient.executeCommandsWithResults(configuration.getDeploymentId(), executionCommand);
+                setResult(exchange, reply.getResult());
             }
-        }, getFactCount {
-            @Override
-            void execute(KieSession kieSession, TaskService taskService, JBPMConfiguration configuration, Exchange exchange) {
-                long factCount = kieSession.getFactCount();
-                setResult(exchange, factCount);
-            }
-        }, getGlobal {
+        },
+        getGlobal {
             @Override
-            void execute(KieSession kieSession, TaskService taskService, JBPMConfiguration configuration, Exchange exchange) {
-                Object global = kieSession.getGlobal(getIdentifier(configuration, exchange));
-                setResult(exchange, global);
+            void execute(KieServicesClient kieServicesClient, JBPMConfiguration configuration, Exchange exchange) {
+                RuleServicesClient ruleClient = kieServicesClient.getServicesClient(RuleServicesClient.class);
+                List<Command<?>> commands = new ArrayList<Command<?>>();
+                BatchExecutionCommand executionCommand = commandsFactory.newBatchExecution(commands);
+                String identifier = getIdentifier(configuration, exchange);
+                commands.add(commandsFactory.newGetGlobal(identifier, identifier));
+
+                ServiceResponse<ExecutionResults> reply = ruleClient.executeCommandsWithResults(configuration.getDeploymentId(), executionCommand);
+                setResult(exchange, reply.getResult().getValue(identifier));
             }
-        }, setGlobal {
+        },
+        setGlobal {
             @Override
-            void execute(KieSession kieSession, TaskService taskService, JBPMConfiguration configuration, Exchange exchange) {
-                kieSession.setGlobal(getIdentifier(configuration, exchange), getValue(configuration, exchange));
+            void execute(KieServicesClient kieServicesClient, JBPMConfiguration configuration, Exchange exchange) {
+                RuleServicesClient ruleClient = kieServicesClient.getServicesClient(RuleServicesClient.class);
+                List<Command<?>> commands = new ArrayList<Command<?>>();
+                BatchExecutionCommand executionCommand = commandsFactory.newBatchExecution(commands);
+
+                commands.add(commandsFactory.newSetGlobal(getIdentifier(configuration, exchange), getValue(configuration, exchange)));
+
+                ruleClient.executeCommandsWithResults(configuration.getDeploymentId(), executionCommand);
             }
         },
 
-        //WORK ITEM OPERATIONS
+        // WORK ITEM OPERATIONS
         abortWorkItem {
             @Override
-            void execute(KieSession kieSession, TaskService taskService, JBPMConfiguration configuration, Exchange exchange) {
-                kieSession.getWorkItemManager().abortWorkItem(safe(getWorkItemId(configuration, exchange)));
+            void execute(KieServicesClient kieServicesClient, JBPMConfiguration configuration, Exchange exchange) {
+                ProcessServicesClient processClient = kieServicesClient.getServicesClient(ProcessServicesClient.class);
+                processClient.abortWorkItem(configuration.getDeploymentId(), safe(getProcessInstanceId(configuration, exchange)), safe(getWorkItemId(configuration, exchange)));
             }
-        }, completeWorkItem {
+        },
+        completeWorkItem {
             @Override
-            void execute(KieSession kieSession, TaskService taskService, JBPMConfiguration configuration, Exchange exchange) {
-                kieSession.getWorkItemManager().completeWorkItem(safe(getWorkItemId(configuration, exchange)), getParameters(configuration, exchange));
+            void execute(KieServicesClient kieServicesClient, JBPMConfiguration configuration, Exchange exchange) {
+                ProcessServicesClient processClient = kieServicesClient.getServicesClient(ProcessServicesClient.class);
+                processClient.completeWorkItem(configuration.getDeploymentId(), safe(getProcessInstanceId(configuration, exchange)), safe(getWorkItemId(configuration, exchange)),
+                                               getParameters(configuration, exchange));
             }
         },
 
-        //TASK OPERATIONS
+        // TASK OPERATIONS
         activateTask {
             @Override
-            void execute(KieSession kieSession, TaskService taskService, JBPMConfiguration configuration, Exchange exchange) {
-                taskService.activate(safe(getTaskId(configuration, exchange)), getUserId(configuration, exchange));
-            }
-        }, addTask {
-            @Override
-            void execute(KieSession kieSession, TaskService taskService, JBPMConfiguration configuration, Exchange exchange) {
-                long taskId = taskService.addTask(getTask(configuration, exchange), getParameters(configuration, exchange));
-                setResult(exchange, taskId);
+            void execute(KieServicesClient kieServicesClient, JBPMConfiguration configuration, Exchange exchange) {
+                UserTaskServicesClient taskClient = kieServicesClient.getServicesClient(UserTaskServicesClient.class);
+                taskClient.activateTask(configuration.getDeploymentId(), safe(getTaskId(configuration, exchange)), getUserId(configuration, exchange));
             }
-        }, claimNextAvailableTask {
-            @Override
-            void execute(KieSession kieSession, TaskService taskService, JBPMConfiguration configuration, Exchange exchange) {
-                taskService.claimNextAvailable(getUserId(configuration, exchange), getLanguage(configuration, exchange));
-            }
-        }, claimTask {
+        },
+        claimTask {
             @Override
-            void execute(KieSession kieSession, TaskService taskService, JBPMConfiguration configuration, Exchange exchange) {
-                taskService.claim(safe(getTaskId(configuration, exchange)), getUserId(configuration, exchange));
+            void execute(KieServicesClient kieServicesClient, JBPMConfiguration configuration, Exchange exchange) {
+                UserTaskServicesClient taskClient = kieServicesClient.getServicesClient(UserTaskServicesClient.class);
+                taskClient.claimTask(configuration.getDeploymentId(), safe(getTaskId(configuration, exchange)), getUserId(configuration, exchange));
             }
-        }, completeTask {
+        },
+        completeTask {
             @Override
-            void execute(KieSession kieSession, TaskService taskService, JBPMConfiguration configuration, Exchange exchange) {
-                taskService.complete(safe(getTaskId(configuration, exchange)), getUserId(configuration, exchange), getParameters(configuration, exchange));
+            void execute(KieServicesClient kieServicesClient, JBPMConfiguration configuration, Exchange exchange) {
+                UserTaskServicesClient taskClient = kieServicesClient.getServicesClient(UserTaskServicesClient.class);
+                taskClient.completeAutoProgress(configuration.getDeploymentId(), safe(getTaskId(configuration, exchange)), getUserId(configuration, exchange),
+                                                getParameters(configuration, exchange));
             }
-        }, delegateTask {
+        },
+        delegateTask {
             @Override
-            void execute(KieSession kieSession, TaskService taskService, JBPMConfiguration configuration, Exchange exchange) {
-                taskService.delegate(safe(getTaskId(configuration, exchange)), getUserId(configuration, exchange), getTargetUserId(configuration, exchange));
+            void execute(KieServicesClient kieServicesClient, JBPMConfiguration configuration, Exchange exchange) {
+                UserTaskServicesClient taskClient = kieServicesClient.getServicesClient(UserTaskServicesClient.class);
+                taskClient.delegateTask(configuration.getDeploymentId(), safe(getTaskId(configuration, exchange)), getUserId(configuration, exchange),
+                                        getTargetUserId(configuration, exchange));
             }
-        }, exitTask {
+        },
+        exitTask {
             @Override
-            void execute(KieSession kieSession, TaskService taskService, JBPMConfiguration configuration, Exchange exchange) {
-                taskService.exit(safe(getTaskId(configuration, exchange)), getUserId(configuration, exchange));
+            void execute(KieServicesClient kieServicesClient, JBPMConfiguration configuration, Exchange exchange) {
+                UserTaskServicesClient taskClient = kieServicesClient.getServicesClient(UserTaskServicesClient.class);
+                taskClient.exitTask(configuration.getDeploymentId(), safe(getTaskId(configuration, exchange)), getUserId(configuration, exchange));
             }
-        }, failTask {
+        },
+        failTask {
             @Override
-            void execute(KieSession kieSession, TaskService taskService, JBPMConfiguration configuration, Exchange exchange) {
-                taskService.fail(safe(getTaskId(configuration, exchange)), getUserId(configuration, exchange), getParameters(configuration, exchange));
+            void execute(KieServicesClient kieServicesClient, JBPMConfiguration configuration, Exchange exchange) {
+                UserTaskServicesClient taskClient = kieServicesClient.getServicesClient(UserTaskServicesClient.class);
+                taskClient.failTask(configuration.getDeploymentId(), safe(getTaskId(configuration, exchange)), getUserId(configuration, exchange),
+                                    getParameters(configuration, exchange));
             }
-        }, getAttachment {
+        },
+        getAttachment {
             @Override
-            void execute(KieSession kieSession, TaskService taskService, JBPMConfiguration configuration, Exchange exchange) {
-                Attachment attachment = taskService.getAttachmentById(safe(getAttachmentId(configuration, exchange)));
+            void execute(KieServicesClient kieServicesClient, JBPMConfiguration configuration, Exchange exchange) {
+                UserTaskServicesClient taskClient = kieServicesClient.getServicesClient(UserTaskServicesClient.class);
+                TaskAttachment attachment = taskClient.getTaskAttachmentById(configuration.getDeploymentId(), safe(getTaskId(configuration, exchange)),
+                                                                             safe(getAttachmentId(configuration, exchange)));
                 setResult(exchange, attachment);
             }
-        }, getContent {
-            @Override
-            void execute(KieSession kieSession, TaskService taskService, JBPMConfiguration configuration, Exchange exchange) {
-                Content content = taskService.getContentById(safe(getContentId(configuration, exchange)));
-                setResult(exchange, content);
-            }
-        }, getTasksAssignedAsBusinessAdministrator {
+        },
+        getTasksAssignedAsBusinessAdministrator {
             @Override
-            void execute(KieSession kieSession, TaskService taskService, JBPMConfiguration configuration, Exchange exchange) {
-                List<TaskSummary> taskSummaries = taskService.getTasksAssignedAsBusinessAdministrator(getUserId(configuration, exchange), getLanguage(configuration, exchange));
+            void execute(KieServicesClient kieServicesClient, JBPMConfiguration configuration, Exchange exchange) {
+                UserTaskServicesClient taskClient = kieServicesClient.getServicesClient(UserTaskServicesClient.class);
+                List<TaskSummary> taskSummaries = taskClient.findTasksAssignedAsBusinessAdministrator(getUserId(configuration, exchange), getPage(configuration, exchange),
+                                                                                                      getPageSize(configuration, exchange));
                 setResult(exchange, taskSummaries);
             }
-        }, getTasksAssignedAsPotentialOwnerByStatus {
+        },
+        getTasksAssignedAsPotentialOwnerByStatus {
             @Override
-            void execute(KieSession kieSession, TaskService taskService, JBPMConfiguration configuration, Exchange exchange) {
-                taskService.getTasksAssignedAsPotentialOwnerByStatus(getUserId(configuration, exchange), getStatuses(configuration, exchange), getLanguage(configuration, exchange));
+            void execute(KieServicesClient kieServicesClient, JBPMConfiguration configuration, Exchange exchange) {
+                UserTaskServicesClient taskClient = kieServicesClient.getServicesClient(UserTaskServicesClient.class);
+                List<TaskSummary> taskSummaries = taskClient.findTasksAssignedAsPotentialOwner(getUserId(configuration, exchange), getStatuses(configuration, exchange),
+                                                                                               getPage(configuration, exchange), getPageSize(configuration, exchange));
+                setResult(exchange, taskSummaries);
             }
-        }, getTaskByWorkItem {
+        },
+        getTaskByWorkItem {
             @Override
-            void execute(KieSession kieSession, TaskService taskService, JBPMConfiguration configuration, Exchange exchange) {
-                Task task = taskService.getTaskByWorkItemId(safe(getWorkItemId(configuration, exchange)));
+            void execute(KieServicesClient kieServicesClient, JBPMConfiguration configuration, Exchange exchange) {
+                UserTaskServicesClient taskClient = kieServicesClient.getServicesClient(UserTaskServicesClient.class);
+                TaskInstance task = taskClient.findTaskByWorkItemId(safe(getWorkItemId(configuration, exchange)));
                 setResult(exchange, task);
             }
-        }, getTaskBy {
+        },
+        getTaskBy {
             @Override
-            void execute(KieSession kieSession, TaskService taskService, JBPMConfiguration configuration, Exchange exchange) {
-                Task task = taskService.getTaskById(safe(getTaskId(configuration, exchange)));
+            void execute(KieServicesClient kieServicesClient, JBPMConfiguration configuration, Exchange exchange) {
+                UserTaskServicesClient taskClient = kieServicesClient.getServicesClient(UserTaskServicesClient.class);
+                TaskInstance task = taskClient.findTaskById(safe(getTaskId(configuration, exchange)));
                 setResult(exchange, task);
             }
-        }, getTaskContent {
+        },
+        getTaskContent {
             @Override
-            void execute(KieSession kieSession, TaskService taskService, JBPMConfiguration configuration, Exchange exchange) {
-                Map<String, Object> taskContent = taskService.getTaskContent(safe(getTaskId(configuration, exchange)));
-                setResult(exchange, taskContent);
+            void execute(KieServicesClient kieServicesClient, JBPMConfiguration configuration, Exchange exchange) {
+                UserTaskServicesClient taskClient = kieServicesClient.getServicesClient(UserTaskServicesClient.class);
+                Map<String, Object> content = taskClient.getTaskOutputContentByTaskId(configuration.getDeploymentId(), safe(getTaskId(configuration, exchange)));
+                setResult(exchange, content);
             }
-        }, getTasksByProcessInstance {
+        },
+        getTasksByProcessInstance {
             @Override
-            void execute(KieSession kieSession, TaskService taskService, JBPMConfiguration configuration, Exchange exchange) {
-                List<Long> processInstanceIds = taskService.getTasksByProcessInstanceId(safe(getProcessInstanceId(configuration, exchange)));
+            void execute(KieServicesClient kieServicesClient, JBPMConfiguration configuration, Exchange exchange) {
+                UserTaskServicesClient taskClient = kieServicesClient.getServicesClient(UserTaskServicesClient.class);
+                List<TaskSummary> processInstanceIds = taskClient.findTasksByStatusByProcessInstanceId(safe(getProcessInstanceId(configuration, exchange)), Collections.emptyList(),
+                                                                                                       getPage(configuration, exchange), getPageSize(configuration, exchange));
                 setResult(exchange, processInstanceIds);
             }
-        }, getTasksByStatusByProcessInstance {
+        },
+        getTasksByStatusByProcessInstance {
             @Override
-            void execute(KieSession kieSession, TaskService taskService, JBPMConfiguration configuration, Exchange exchange) {
-                List<TaskSummary> taskSummaryList = taskService.getTasksByStatusByProcessInstanceId(
-                        safe(getProcessInstanceId(configuration, exchange)), getStatuses(configuration, exchange),
-                        getLanguage(configuration, exchange));
+            void execute(KieServicesClient kieServicesClient, JBPMConfiguration configuration, Exchange exchange) {
+                UserTaskServicesClient taskClient = kieServicesClient.getServicesClient(UserTaskServicesClient.class);
+                List<TaskSummary> taskSummaryList = taskClient.findTasksByStatusByProcessInstanceId(safe(getProcessInstanceId(configuration, exchange)),
+                                                                                                    getStatuses(configuration, exchange), getPage(configuration, exchange),
+                                                                                                    getPageSize(configuration, exchange));
                 setResult(exchange, taskSummaryList);
             }
-        }, getTasksOwned {
+        },
+        getTasksOwned {
             @Override
-            void execute(KieSession kieSession, TaskService taskService, JBPMConfiguration configuration, Exchange exchange) {
-                List<TaskSummary> summaryList = taskService.getTasksOwned(getUserId(configuration, exchange), getLanguage(configuration, exchange));
+            void execute(KieServicesClient kieServicesClient, JBPMConfiguration configuration, Exchange exchange) {
+                UserTaskServicesClient taskClient = kieServicesClient.getServicesClient(UserTaskServicesClient.class);
+                List<TaskSummary> summaryList = taskClient.findTasksOwned(getUserId(configuration, exchange), getPage(configuration, exchange),
+                                                                          getPageSize(configuration, exchange));
                 setResult(exchange, summaryList);
             }
-        }, nominateTask {
+        },
+        nominateTask {
             @Override
-            void execute(KieSession kieSession, TaskService taskService, JBPMConfiguration configuration, Exchange exchange) {
-                taskService.nominate(safe(getTaskId(configuration, exchange)), getUserId(configuration, exchange), getEntities(configuration, exchange));
+            void execute(KieServicesClient kieServicesClient, JBPMConfiguration configuration, Exchange exchange) {
+                UserTaskServicesClient taskClient = kieServicesClient.getServicesClient(UserTaskServicesClient.class);
+                taskClient.nominateTask(configuration.getDeploymentId(), safe(getTaskId(configuration, exchange)), getUserId(configuration, exchange),
+                                        getEntities(configuration, exchange));
             }
-        }, releaseTask {
+        },
+        releaseTask {
             @Override
-            void execute(KieSession kieSession, TaskService taskService, JBPMConfiguration configuration, Exchange exchange) {
-                taskService.release(safe(getTaskId(configuration, exchange)), getUserId(configuration, exchange));
+            void execute(KieServicesClient kieServicesClient, JBPMConfiguration configuration, Exchange exchange) {
+                UserTaskServicesClient taskClient = kieServicesClient.getServicesClient(UserTaskServicesClient.class);
+                taskClient.releaseTask(configuration.getDeploymentId(), safe(getTaskId(configuration, exchange)), getUserId(configuration, exchange));
             }
-        }, resumeTask {
+        },
+        resumeTask {
             @Override
-            void execute(KieSession kieSession, TaskService taskService, JBPMConfiguration configuration, Exchange exchange) {
-                taskService.resume(safe(getTaskId(configuration, exchange)), getUserId(configuration, exchange));
+            void execute(KieServicesClient kieServicesClient, JBPMConfiguration configuration, Exchange exchange) {
+                UserTaskServicesClient taskClient = kieServicesClient.getServicesClient(UserTaskServicesClient.class);
+                taskClient.resumeTask(configuration.getDeploymentId(), safe(getTaskId(configuration, exchange)), getUserId(configuration, exchange));
             }
-        }, skipTask {
+        },
+        skipTask {
             @Override
-            void execute(KieSession kieSession, TaskService taskService, JBPMConfiguration configuration, Exchange exchange) {
-                taskService.skip(safe(getTaskId(configuration, exchange)), getUserId(configuration, exchange));
+            void execute(KieServicesClient kieServicesClient, JBPMConfiguration configuration, Exchange exchange) {
+                UserTaskServicesClient taskClient = kieServicesClient.getServicesClient(UserTaskServicesClient.class);
+                taskClient.skipTask(configuration.getDeploymentId(), safe(getTaskId(configuration, exchange)), getUserId(configuration, exchange));
             }
-        }, startTask {
+        },
+        startTask {
             @Override
-            void execute(KieSession kieSession, TaskService taskService, JBPMConfiguration configuration, Exchange exchange) {
-                taskService.start(safe(getTaskId(configuration, exchange)), getUserId(configuration, exchange));
+            void execute(KieServicesClient kieServicesClient, JBPMConfiguration configuration, Exchange exchange) {
+                UserTaskServicesClient taskClient = kieServicesClient.getServicesClient(UserTaskServicesClient.class);
+                taskClient.startTask(configuration.getDeploymentId(), safe(getTaskId(configuration, exchange)), getUserId(configuration, exchange));
             }
-        }, stopTask {
+        },
+        stopTask {
             @Override
-            void execute(KieSession kieSession, TaskService taskService, JBPMConfiguration configuration, Exchange exchange) {
-                taskService.stop(safe(getTaskId(configuration, exchange)), getUserId(configuration, exchange));
+            void execute(KieServicesClient kieServicesClient, JBPMConfiguration configuration, Exchange exchange) {
+                UserTaskServicesClient taskClient = kieServicesClient.getServicesClient(UserTaskServicesClient.class);
+                taskClient.stopTask(configuration.getDeploymentId(), safe(getTaskId(configuration, exchange)), getUserId(configuration, exchange));
             }
-        }, suspendTask {
+        },
+        suspendTask {
             @Override
-            void execute(KieSession kieSession, TaskService taskService, JBPMConfiguration configuration, Exchange exchange) {
-                taskService.suspend(safe(getTaskId(configuration, exchange)), getUserId(configuration, exchange));
+            void execute(KieServicesClient kieServicesClient, JBPMConfiguration configuration, Exchange exchange) {
+                UserTaskServicesClient taskClient = kieServicesClient.getServicesClient(UserTaskServicesClient.class);
+                taskClient.suspendTask(configuration.getDeploymentId(), safe(getTaskId(configuration, exchange)), getUserId(configuration, exchange));
             }
         };
 
-        List<Status> getStatuses(JBPMConfiguration configuration, Exchange exchange) {
-            List<Status> statusList = exchange.getIn().getHeader(JBPMConstants.STATUS_LIST, List.class);
+        List<String> getStatuses(JBPMConfiguration configuration, Exchange exchange) {
+            List<String> statusList = exchange.getIn().getHeader(JBPMConstants.STATUS_LIST, List.class);
             if (statusList == null) {
                 statusList = configuration.getStatuses();
             }
             return statusList;
         }
 
-        List<OrganizationalEntity> getEntities(JBPMConfiguration configuration, Exchange exchange) {
-            List<OrganizationalEntity> entityList = exchange.getIn().getHeader(JBPMConstants.ENTITY_LIST, List.class);
+        List<String> getEntities(JBPMConfiguration configuration, Exchange exchange) {
+            List<String> entityList = exchange.getIn().getHeader(JBPMConstants.ENTITY_LIST, List.class);
             if (entityList == null) {
                 entityList = configuration.getEntities();
             }
@@ -350,12 +412,20 @@ String getTargetUserId(JBPMConfiguration configuration, Exchange exchange) {
             return userId;
         }
 
-        String getLanguage(JBPMConfiguration configuration, Exchange exchange) {
-            String language = exchange.getIn().getHeader(JBPMConstants.LANGUAGE, String.class);
-            if (language == null) {
-                language = configuration.getLanguage();
+        Integer getPage(JBPMConfiguration configuration, Exchange exchange) {
+            Integer page = exchange.getIn().getHeader(JBPMConstants.RESULT_PAGE, Integer.class);
+            if (page == null) {
+                page = configuration.getPage();
+            }
+            return page;
+        }
+
+        Integer getPageSize(JBPMConfiguration configuration, Exchange exchange) {
+            Integer pageSize = exchange.getIn().getHeader(JBPMConstants.RESULT_PAGE_SIZE, Integer.class);
+            if (pageSize == null) {
+                pageSize = configuration.getPageSize();
             }
-            return language;
+            return pageSize;
         }
 
         Task getTask(JBPMConfiguration configuration, Exchange exchange) {
@@ -466,7 +536,6 @@ void setResult(Exchange exchange, Object result) {
             getResultMessage(exchange).setBody(result);
         }
 
-        abstract void execute(KieSession kieSession, TaskService taskService, JBPMConfiguration configuration, Exchange exchange);
+        abstract void execute(KieServicesClient kieServicesClient, JBPMConfiguration configuration, Exchange exchange);
     }
 }
-
diff --git a/components/camel-jbpm/src/main/java/org/apache/camel/component/jbpm/emitters/CamelEventEmitter.java b/components/camel-jbpm/src/main/java/org/apache/camel/component/jbpm/emitters/CamelEventEmitter.java
new file mode 100644
index 00000000000..0886466f0f8
--- /dev/null
+++ b/components/camel-jbpm/src/main/java/org/apache/camel/component/jbpm/emitters/CamelEventEmitter.java
@@ -0,0 +1,75 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.camel.component.jbpm.emitters;
+
+import java.util.Collection;
+
+import org.apache.camel.component.jbpm.JBPMConsumer;
+import org.jbpm.persistence.api.integration.EventCollection;
+import org.jbpm.persistence.api.integration.EventEmitter;
+import org.jbpm.persistence.api.integration.InstanceView;
+import org.jbpm.persistence.api.integration.base.BaseEventCollection;
+
+public class CamelEventEmitter implements EventEmitter {
+    
+    private JBPMConsumer consumer;
+    private boolean sendItems;
+    
+    public CamelEventEmitter(JBPMConsumer consumer, boolean sendItems) {
+        this.consumer = consumer; 
+        this.sendItems = sendItems;
+    }
+
+    @Override
+    public void deliver(Collection<InstanceView<?>> data) {
+        // no-op
+        
+    }
+
+    @Override
+    public void apply(Collection<InstanceView<?>> data) {
+        if (consumer == null || data.isEmpty()) {
+            return;
+        }
+        
+        if (sendItems) {
+            
+            data.forEach(item -> consumer.sendMessage("Emitter", item));
+        } else {
+        
+            consumer.sendMessage("Emitter", data);
+        }
+    }
+
+    @Override
+    public void drop(Collection<InstanceView<?>> data) {
+        // no-op
+        
+    }
+
+    @Override
+    public EventCollection newCollection() {
+        return new BaseEventCollection();
+    }
+
+    @Override
+    public void close() {
+
+    }
+
+}
diff --git a/components/camel-jbpm/src/main/java/org/apache/camel/component/jbpm/emitters/ServiceRegistryBoundEventEmitter.java b/components/camel-jbpm/src/main/java/org/apache/camel/component/jbpm/emitters/ServiceRegistryBoundEventEmitter.java
new file mode 100644
index 00000000000..c531aa783d7
--- /dev/null
+++ b/components/camel-jbpm/src/main/java/org/apache/camel/component/jbpm/emitters/ServiceRegistryBoundEventEmitter.java
@@ -0,0 +1,62 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.camel.component.jbpm.emitters;
+
+import java.util.Collection;
+
+import org.jbpm.persistence.api.integration.EventCollection;
+import org.jbpm.persistence.api.integration.EventEmitter;
+import org.jbpm.persistence.api.integration.InstanceView;
+import org.jbpm.services.api.service.ServiceRegistry;
+
+public class ServiceRegistryBoundEventEmitter implements EventEmitter {
+    
+    private EventEmitter delegate;
+    
+    public ServiceRegistryBoundEventEmitter() {
+        this.delegate = (EventEmitter) ServiceRegistry.get().service("CamelEventEmitter");
+    }
+
+    @Override
+    public void deliver(Collection<InstanceView<?>> data) {
+        delegate.deliver(data);
+        
+    }
+
+    @Override
+    public void apply(Collection<InstanceView<?>> data) {
+        delegate.apply(data);
+    }
+
+    @Override
+    public void drop(Collection<InstanceView<?>> data) {
+        delegate.drop(data);
+        
+    }
+
+    @Override
+    public EventCollection newCollection() {
+        return delegate.newCollection();
+    }
+
+    @Override
+    public void close() {
+ 
+    }
+
+}
diff --git a/components/camel-jbpm/src/main/java/org/apache/camel/component/jbpm/listeners/CamelCaseEventListener.java b/components/camel-jbpm/src/main/java/org/apache/camel/component/jbpm/listeners/CamelCaseEventListener.java
new file mode 100644
index 00000000000..4906b5b9b87
--- /dev/null
+++ b/components/camel-jbpm/src/main/java/org/apache/camel/component/jbpm/listeners/CamelCaseEventListener.java
@@ -0,0 +1,286 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.camel.component.jbpm.listeners;
+
+import java.util.LinkedHashSet;
+import java.util.Set;
+
+import org.apache.camel.component.jbpm.JBPMCamelConsumerAware;
+import org.apache.camel.component.jbpm.JBPMConsumer;
+import org.jbpm.casemgmt.api.event.CaseCancelEvent;
+import org.jbpm.casemgmt.api.event.CaseCloseEvent;
+import org.jbpm.casemgmt.api.event.CaseCommentEvent;
+import org.jbpm.casemgmt.api.event.CaseDataEvent;
+import org.jbpm.casemgmt.api.event.CaseDestroyEvent;
+import org.jbpm.casemgmt.api.event.CaseDynamicSubprocessEvent;
+import org.jbpm.casemgmt.api.event.CaseDynamicTaskEvent;
+import org.jbpm.casemgmt.api.event.CaseEventListener;
+import org.jbpm.casemgmt.api.event.CaseReopenEvent;
+import org.jbpm.casemgmt.api.event.CaseRoleAssignmentEvent;
+import org.jbpm.casemgmt.api.event.CaseStartEvent;
+import org.kie.internal.runtime.Cacheable;
+
+
+public class CamelCaseEventListener implements CaseEventListener, Cacheable, JBPMCamelConsumerAware {    
+    
+    private Set<JBPMConsumer> consumers = new LinkedHashSet<>();
+    
+    @Override
+    public void beforeCaseStarted(CaseStartEvent event) {
+        if (consumers.isEmpty()) {
+            return;
+        }
+        sendMessage("beforeCaseStarted", event);
+    }
+
+    @Override
+    public void afterCaseStarted(CaseStartEvent event) {
+        if (consumers.isEmpty()) {
+            return;
+        }
+        sendMessage("afterCaseStarted", event);
+    }
+
+    @Override
+    public void beforeCaseClosed(CaseCloseEvent event) {
+        if (consumers.isEmpty()) {
+            return;
+        }
+        sendMessage("beforeCaseClosed", event);
+    }
+
+    @Override
+    public void afterCaseClosed(CaseCloseEvent event) {
+        if (consumers.isEmpty()) {
+            return;
+        }
+        sendMessage("afterCaseClosed", event);
+    }
+
+    @Override
+    public void beforeCaseCancelled(CaseCancelEvent event) {
+        if (consumers.isEmpty()) {
+            return;
+        }
+        sendMessage("beforeCaseCancelled", event);
+    }
+
+    @Override
+    public void afterCaseCancelled(CaseCancelEvent event) {
+        if (consumers.isEmpty()) {
+            return;
+        }
+        sendMessage("afterCaseCancelled", event);
+    }
+
+    @Override
+    public void beforeCaseDestroyed(CaseDestroyEvent event) {
+        if (consumers.isEmpty()) {
+            return;
+        }
+        sendMessage("beforeCaseDestroyed", event);
+    }
+
+    @Override
+    public void afterCaseDestroyed(CaseDestroyEvent event) {
+        if (consumers.isEmpty()) {
+            return;
+        }
+        sendMessage("afterCaseDestroyed", event);
+    }
+
+    @Override
+    public void beforeCaseReopen(CaseReopenEvent event) {
+        if (consumers.isEmpty()) {
+            return;
+        }
+        sendMessage("beforeCaseReopen", event);
+    }
+
+    @Override
+    public void afterCaseReopen(CaseReopenEvent event) {
+        if (consumers.isEmpty()) {
+            return;
+        }
+        sendMessage("afterCaseReopen", event);
+    }
+
+    @Override
+    public void beforeCaseCommentAdded(CaseCommentEvent event) {
+        if (consumers.isEmpty()) {
+            return;
+        }
+        sendMessage("beforeCaseCommentAdded", event);
+    }
+
+    @Override
+    public void afterCaseCommentAdded(CaseCommentEvent event) {
+        if (consumers.isEmpty()) {
+            return;
+        }
+        sendMessage("afterCaseCommentAdded", event);
+    }
+
+    @Override
+    public void beforeCaseCommentUpdated(CaseCommentEvent event) {
+        if (consumers.isEmpty()) {
+            return;
+        }
+        sendMessage("beforeCaseCommentUpdated", event);
+    }
+
+    @Override
+    public void afterCaseCommentUpdated(CaseCommentEvent event) {
+        if (consumers.isEmpty()) {
+            return;
+        }
+        sendMessage("afterCaseCommentUpdated", event);
+    }
+
+    @Override
+    public void beforeCaseCommentRemoved(CaseCommentEvent event) {
+        if (consumers.isEmpty()) {
+            return;
+        }
+        sendMessage("beforeCaseCommentRemoved", event);
+    }
+
+    @Override
+    public void afterCaseCommentRemoved(CaseCommentEvent event) {
+        if (consumers.isEmpty()) {
+            return;
+        }
+        sendMessage("afterCaseCommentRemoved", event);
+    }
+
+    @Override
+    public void beforeCaseRoleAssignmentAdded(CaseRoleAssignmentEvent event) {
+        if (consumers.isEmpty()) {
+            return;
+        }
+        sendMessage("beforeCaseRoleAssignmentAdded", event);
+    }
+
+    @Override
+    public void afterCaseRoleAssignmentAdded(CaseRoleAssignmentEvent event) {
+        if (consumers.isEmpty()) {
+            return;
+        }
+        sendMessage("afterCaseRoleAssignmentAdded", event);
+    }
+
+    @Override
+    public void beforeCaseRoleAssignmentRemoved(CaseRoleAssignmentEvent event) {
+        if (consumers.isEmpty()) {
+            return;
+        }
+        sendMessage("beforeCaseRoleAssignmentRemoved", event);
+    }
+
+    @Override
+    public void afterCaseRoleAssignmentRemoved(CaseRoleAssignmentEvent event) {
+        if (consumers.isEmpty()) {
+            return;
+        }
+        sendMessage("afterCaseRoleAssignmentRemoved", event);
+    }
+
+    @Override
+    public void beforeCaseDataAdded(CaseDataEvent event) {
+        if (consumers.isEmpty()) {
+            return;
+        }
+        sendMessage("beforeCaseDataAdded", event);
+    }
+
+    @Override
+    public void afterCaseDataAdded(CaseDataEvent event) {
+        if (consumers.isEmpty()) {
+            return;
+        }
+        sendMessage("afterCaseDataAdded", event);
+    }
+
+    @Override
+    public void beforeCaseDataRemoved(CaseDataEvent event) {
+        if (consumers.isEmpty()) {
+            return;
+        }
+        sendMessage("beforeCaseDataRemoved", event);
+    }
+
+    @Override
+    public void afterCaseDataRemoved(CaseDataEvent event) {
+        if (consumers.isEmpty()) {
+            return;
+        }
+        sendMessage("afterCaseDataRemoved", event);
+    }
+
+    @Override
+    public void beforeDynamicTaskAdded(CaseDynamicTaskEvent event) {
+        if (consumers.isEmpty()) {
+            return;
+        }
+        sendMessage("beforeDynamicTaskAdded", event);
+    }
+
+    @Override
+    public void afterDynamicTaskAdded(CaseDynamicTaskEvent event) {
+        if (consumers.isEmpty()) {
+            return;
+        }
+        sendMessage("afterDynamicTaskAdded", event);
+    }
+
+    @Override
+    public void beforeDynamicProcessAdded(CaseDynamicSubprocessEvent event) {
+        if (consumers.isEmpty()) {
+            return;
+        }
+        sendMessage("beforeDynamicProcessAdded", event);
+    }
+
+    @Override
+    public void afterDynamicProcessAdded(CaseDynamicSubprocessEvent event) {
+        if (consumers.isEmpty()) {
+            return;
+        }
+        sendMessage("afterDynamicProcessAdded", event);
+    }
+
+    @Override
+    public void close() {
+
+    }
+
+    @Override
+    public void addConsumer(JBPMConsumer consumer) {
+        this.consumers.add(consumer);
+    }
+
+    @Override
+    public void removeConsumer(JBPMConsumer consumer) {
+        this.consumers.remove(consumer);
+    }
+    
+    protected void sendMessage(String eventType, Object event) {
+        this.consumers.stream().filter(c -> c.getStatus().isStarted()).forEach(c -> c.sendMessage(eventType, event));
+    }
+
+}
diff --git a/components/camel-jbpm/src/main/java/org/apache/camel/component/jbpm/listeners/CamelProcessEventListener.java b/components/camel-jbpm/src/main/java/org/apache/camel/component/jbpm/listeners/CamelProcessEventListener.java
new file mode 100644
index 00000000000..2e6ff08af69
--- /dev/null
+++ b/components/camel-jbpm/src/main/java/org/apache/camel/component/jbpm/listeners/CamelProcessEventListener.java
@@ -0,0 +1,138 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.camel.component.jbpm.listeners;
+
+import java.util.LinkedHashSet;
+import java.util.Set;
+
+import org.apache.camel.component.jbpm.JBPMCamelConsumerAware;
+import org.apache.camel.component.jbpm.JBPMConsumer;
+import org.kie.api.event.process.ProcessCompletedEvent;
+import org.kie.api.event.process.ProcessEventListener;
+import org.kie.api.event.process.ProcessNodeLeftEvent;
+import org.kie.api.event.process.ProcessNodeTriggeredEvent;
+import org.kie.api.event.process.ProcessStartedEvent;
+import org.kie.api.event.process.ProcessVariableChangedEvent;
+import org.kie.internal.runtime.Cacheable;
+
+
+public class CamelProcessEventListener implements ProcessEventListener, Cacheable, JBPMCamelConsumerAware {
+
+    private Set<JBPMConsumer> consumers = new LinkedHashSet<>();
+
+    @Override
+    public void beforeProcessStarted(ProcessStartedEvent event) {
+        if (consumers.isEmpty()) {
+            return;
+        }
+
+        sendMessage("beforeProcessStarted", event);
+    }
+
+    @Override
+    public void afterProcessStarted(ProcessStartedEvent event) {
+        if (consumers.isEmpty()) {
+            return;
+        }
+        
+        sendMessage("afterProcessStarted", event);
+    }
+
+    @Override
+    public void beforeProcessCompleted(ProcessCompletedEvent event) {
+        if (consumers.isEmpty()) {
+            return;
+        }
+        sendMessage("beforeProcessCompleted", event);
+    }
+
+    @Override
+    public void afterProcessCompleted(ProcessCompletedEvent event) {
+        if (consumers.isEmpty()) {
+            return;
+        }
+        sendMessage("afterProcessCompleted", event);
+    }
+
+    @Override
+    public void beforeNodeTriggered(ProcessNodeTriggeredEvent event) {
+        if (consumers.isEmpty()) {
+            return;
+        }
+        sendMessage("beforeNodeTriggered", event);
+    }
+
+    @Override
+    public void afterNodeTriggered(ProcessNodeTriggeredEvent event) {
+        if (consumers.isEmpty()) {
+            return;
+        }
+        sendMessage("afterNodeTriggered", event);
+    }
+
+    @Override
+    public void beforeNodeLeft(ProcessNodeLeftEvent event) {
+        if (consumers.isEmpty()) {
+            return;
+        }
+        sendMessage("beforeNodeLeft", event);
+    }
+
+    @Override
+    public void afterNodeLeft(ProcessNodeLeftEvent event) {
+        if (consumers.isEmpty()) {
+            return;
+        }
+        sendMessage("afterNodeLeft", event);
+    }
+
+    @Override
+    public void beforeVariableChanged(ProcessVariableChangedEvent event) {
+        if (consumers.isEmpty()) {
+            return;
+        }
+        sendMessage("beforeVariableChanged", event);
+    }
+
+    @Override
+    public void afterVariableChanged(ProcessVariableChangedEvent event) {
+        if (consumers.isEmpty()) {
+            return;
+        }
+        sendMessage("afterVariableChanged", event);
+    }
+
+    @Override
+    public void close() {
+
+    }
+
+    @Override
+    public void addConsumer(JBPMConsumer consumer) {
+        this.consumers.add(consumer);
+    }
+
+    @Override
+    public void removeConsumer(JBPMConsumer consumer) {
+        this.consumers.remove(consumer);
+    }
+    
+    protected void sendMessage(String eventType, Object event) {
+        this.consumers.stream().filter(c -> c.getStatus().isStarted()).forEach(c -> c.sendMessage(eventType, event));
+    }
+}
diff --git a/components/camel-jbpm/src/main/java/org/apache/camel/component/jbpm/listeners/CamelTaskEventListener.java b/components/camel-jbpm/src/main/java/org/apache/camel/component/jbpm/listeners/CamelTaskEventListener.java
new file mode 100644
index 00000000000..67a93b7d2e5
--- /dev/null
+++ b/components/camel-jbpm/src/main/java/org/apache/camel/component/jbpm/listeners/CamelTaskEventListener.java
@@ -0,0 +1,321 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.camel.component.jbpm.listeners;
+
+import java.util.LinkedHashSet;
+import java.util.Set;
+
+import org.apache.camel.component.jbpm.JBPMCamelConsumerAware;
+import org.apache.camel.component.jbpm.JBPMConsumer;
+import org.kie.api.task.TaskEvent;
+import org.kie.api.task.TaskLifeCycleEventListener;
+import org.kie.internal.runtime.Cacheable;
+
+
+public class CamelTaskEventListener implements Cacheable, TaskLifeCycleEventListener, JBPMCamelConsumerAware {
+
+    private Set<JBPMConsumer> consumers = new LinkedHashSet<>();
+    
+    @Override
+    public void beforeTaskActivatedEvent(TaskEvent event) {
+        if (consumers.isEmpty()) {
+            return;
+        }
+        sendMessage("beforeTaskActivatedEvent", event);
+    }
+
+    @Override
+    public void beforeTaskClaimedEvent(TaskEvent event) {
+        if (consumers.isEmpty()) {
+            return;
+        }
+        sendMessage("beforeTaskClaimedEvent", event);
+    }
+
+    @Override
+    public void beforeTaskSkippedEvent(TaskEvent event) {
+        if (consumers.isEmpty()) {
+            return;
+        }
+        sendMessage("beforeTaskSkippedEvent", event);
+    }
+
+    @Override
+    public void beforeTaskStartedEvent(TaskEvent event) {
+        if (consumers.isEmpty()) {
+            return;
+        }
+        sendMessage("beforeTaskStartedEvent", event);
+
+    }
+
+    @Override
+    public void beforeTaskStoppedEvent(TaskEvent event) {
+        if (consumers.isEmpty()) {
+            return;
+        }
+        sendMessage("beforeTaskStoppedEvent", event);
+
+    }
+
+    @Override
+    public void beforeTaskCompletedEvent(TaskEvent event) {
+        if (consumers.isEmpty()) {
+            return;
+        }
+        sendMessage("beforeTaskCompletedEvent", event);
+
+    }
+
+    @Override
+    public void beforeTaskFailedEvent(TaskEvent event) {
+        if (consumers.isEmpty()) {
+            return;
+        }
+        sendMessage("beforeTaskFailedEvent", event);
+
+    }
+
+    @Override
+    public void beforeTaskAddedEvent(TaskEvent event) {
+        if (consumers.isEmpty()) {
+            return;
+        }
+        sendMessage("beforeTaskAddedEvent", event);
+
+    }
+
+    @Override
+    public void beforeTaskExitedEvent(TaskEvent event) {
+        if (consumers.isEmpty()) {
+            return;
+        }
+        sendMessage("beforeTaskExitedEvent", event);
+
+    }
+
+    @Override
+    public void beforeTaskReleasedEvent(TaskEvent event) {
+        if (consumers.isEmpty()) {
+            return;
+        }
+        sendMessage("beforeTaskReleasedEvent", event);
+
+    }
+
+    @Override
+    public void beforeTaskResumedEvent(TaskEvent event) {
+        if (consumers.isEmpty()) {
+            return;
+        }
+        sendMessage("beforeTaskResumedEvent", event);
+
+    }
+
+    @Override
+    public void beforeTaskSuspendedEvent(TaskEvent event) {
+        if (consumers.isEmpty()) {
+            return;
+        }
+        sendMessage("beforeTaskSuspendedEvent", event);
+
+    }
+
+    @Override
+    public void beforeTaskForwardedEvent(TaskEvent event) {
+        if (consumers.isEmpty()) {
+            return;
+        }
+        sendMessage("beforeTaskForwardedEvent", event);
+
+    }
+
+    @Override
+    public void beforeTaskDelegatedEvent(TaskEvent event) {
+        if (consumers.isEmpty()) {
+            return;
+        }
+        sendMessage("beforeTaskDelegatedEvent", event);
+
+    }
+
+    @Override
+    public void beforeTaskNominatedEvent(TaskEvent event) {
+        if (consumers.isEmpty()) {
+            return;
+        }
+        sendMessage("beforeTaskNominatedEvent", event);
+
+    }
+
+    @Override
+    public void afterTaskActivatedEvent(TaskEvent event) {
+        if (consumers.isEmpty()) {
+            return;
+        }
+        sendMessage("afterTaskActivatedEvent", event);
+
+    }
+
+    @Override
+    public void afterTaskClaimedEvent(TaskEvent event) {
+        if (consumers.isEmpty()) {
+            return;
+        }
+        sendMessage("afterTaskClaimedEvent", event);
+
+    }
+
+    @Override
+    public void afterTaskSkippedEvent(TaskEvent event) {
+        if (consumers.isEmpty()) {
+            return;
+        }
+        sendMessage("afterTaskSkippedEvent", event);
+
+    }
+
+    @Override
+    public void afterTaskStartedEvent(TaskEvent event) {
+        if (consumers.isEmpty()) {
+            return;
+        }
+        sendMessage("afterTaskStartedEvent", event);
+
+    }
+
+    @Override
+    public void afterTaskStoppedEvent(TaskEvent event) {
+        if (consumers.isEmpty()) {
+            return;
+        }
+        sendMessage("afterTaskStoppedEvent", event);
+
+    }
+
+    @Override
+    public void afterTaskCompletedEvent(TaskEvent event) {
+        if (consumers.isEmpty()) {
+            return;
+        }
+        sendMessage("afterTaskCompletedEvent", event);
+
+    }
+
+    @Override
+    public void afterTaskFailedEvent(TaskEvent event) {
+        if (consumers.isEmpty()) {
+            return;
+        }
+        sendMessage("afterTaskFailedEvent", event);
+
+    }
+
+    @Override
+    public void afterTaskAddedEvent(TaskEvent event) {
+        if (consumers.isEmpty()) {
+            return;
+        }
+        sendMessage("afterTaskAddedEvent", event);
+
+    }
+
+    @Override
+    public void afterTaskExitedEvent(TaskEvent event) {
+        if (consumers.isEmpty()) {
+            return;
+        }
+        sendMessage("afterTaskExitedEvent", event);
+
+    }
+
+    @Override
+    public void afterTaskReleasedEvent(TaskEvent event) {
+        if (consumers.isEmpty()) {
+            return;
+        }
+        sendMessage("afterTaskReleasedEvent", event);
+
+    }
+
+    @Override
+    public void afterTaskResumedEvent(TaskEvent event) {
+        if (consumers.isEmpty()) {
+            return;
+        }
+        sendMessage("afterTaskResumedEvent", event);
+
+    }
+
+    @Override
+    public void afterTaskSuspendedEvent(TaskEvent event) {
+        if (consumers.isEmpty()) {
+            return;
+        }
+        sendMessage("afterTaskSuspendedEvent", event);
+
+    }
+
+    @Override
+    public void afterTaskForwardedEvent(TaskEvent event) {
+        if (consumers.isEmpty()) {
+            return;
+        }
+        sendMessage("afterTaskForwardedEvent", event);
+
+    }
+
+    @Override
+    public void afterTaskDelegatedEvent(TaskEvent event) {
+        if (consumers.isEmpty()) {
+            return;
+        }
+        sendMessage("afterTaskDelegatedEvent", event);
+
+    }
+
+    @Override
+    public void afterTaskNominatedEvent(TaskEvent event) {
+        if (consumers.isEmpty()) {
+            return;
+        }
+        sendMessage("afterTaskNominatedEvent", event);
+
+    }
+
+    @Override
+    public void close() {        
+
+    }
+
+    @Override
+    public void addConsumer(JBPMConsumer consumer) {
+        this.consumers.add(consumer);        
+    }
+
+    @Override
+    public void removeConsumer(JBPMConsumer consumer) {
+        this.consumers.remove(consumer);
+    }
+    
+    protected void sendMessage(String eventType, Object event) {
+        this.consumers.stream().filter(c -> c.getStatus().isStarted()).forEach(c -> c.sendMessage(eventType, event));
+    }
+
+
+}
diff --git a/components/camel-jbpm/src/main/java/org/apache/camel/component/jbpm/server/CamelKieServerExtension.java b/components/camel-jbpm/src/main/java/org/apache/camel/component/jbpm/server/CamelKieServerExtension.java
new file mode 100644
index 00000000000..1783b04898b
--- /dev/null
+++ b/components/camel-jbpm/src/main/java/org/apache/camel/component/jbpm/server/CamelKieServerExtension.java
@@ -0,0 +1,224 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.camel.component.jbpm.server;
+
+import java.io.InputStream;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+import org.apache.camel.component.jbpm.JBPMConstants;
+import org.apache.camel.impl.DefaultCamelContext;
+import org.apache.camel.model.FromDefinition;
+import org.apache.camel.model.RouteDefinition;
+import org.apache.camel.model.RoutesDefinition;
+import org.jbpm.services.api.service.ServiceRegistry;
+import org.kie.server.services.api.KieContainerInstance;
+import org.kie.server.services.api.KieServerExtension;
+import org.kie.server.services.api.KieServerRegistry;
+import org.kie.server.services.api.SupportedTransports;
+import org.kie.server.services.impl.KieServerImpl;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+public class CamelKieServerExtension implements KieServerExtension {
+    public static final String EXTENSION_NAME = "Camel";
+
+    private static final Logger LOGGER = LoggerFactory.getLogger(CamelKieServerExtension.class);
+
+    private static final Boolean DISABLED = Boolean.parseBoolean(System.getProperty("org.camel.server.ext.disabled", "false"));
+
+    protected DefaultCamelContext camelContext;
+
+    protected boolean managedCamel;
+
+    protected Map<String, DefaultCamelContext> camelContexts = new HashMap<>();
+
+    public CamelKieServerExtension() {
+        this.managedCamel = true;
+    }
+
+    public CamelKieServerExtension(DefaultCamelContext camelContext) {
+        this.camelContext = camelContext;
+        this.managedCamel = false;
+    }
+
+    @Override
+    public boolean isInitialized() {
+        return camelContext != null;
+    }
+
+    @Override
+    public boolean isActive() {
+        return !DISABLED;
+    }
+
+    @Override
+    public void init(KieServerImpl kieServer, KieServerRegistry registry) {
+        if (this.managedCamel && this.camelContext == null) {
+            this.camelContext = new DefaultCamelContext();
+            this.camelContext.setName("KIE Server Camel context");
+
+            try (InputStream is = this.getClass().getResourceAsStream("/global-camel-routes.xml")) {
+                if (is != null) {
+
+                    RoutesDefinition routes = camelContext.loadRoutesDefinition(is);
+                    camelContext.addRouteDefinitions(routes.getRoutes());
+                }
+            } catch (Exception e) {
+                LOGGER.error("Error while adding Camel context for KIE Server", e);
+            }
+        }
+
+        ServiceRegistry.get().register(JBPMConstants.GLOBAL_CAMEL_CONTEXT_SERVICE_KEY, this.camelContext);
+    }
+
+    @Override
+    public void destroy(KieServerImpl kieServer, KieServerRegistry registry) {
+        ServiceRegistry.get().remove("GlobalCamelService");
+
+        if (this.managedCamel && this.camelContext != null) {
+            try {
+                this.camelContext.stop();
+            } catch (Exception e) {
+                LOGGER.error("Failed at stopping KIE Server extension {}", EXTENSION_NAME);
+            }
+        }
+    }
+
+    @Override
+    public void createContainer(String id, KieContainerInstance kieContainerInstance, Map<String, Object> parameters) {
+
+        ClassLoader classloader = kieContainerInstance.getKieContainer().getClassLoader();
+        try (InputStream is = classloader.getResourceAsStream("camel-routes.xml")) {
+            if (is != null) {
+
+                DefaultCamelContext context = new DefaultCamelContext();
+                context.setName("KIE Server Camel context for container " + kieContainerInstance.getContainerId());
+
+                RoutesDefinition routes = context.loadRoutesDefinition(is);
+                annotateKJarRoutes(routes, id);
+                context.addRouteDefinitions(routes.getRoutes());
+                context.start();
+                camelContexts.put(id, context);
+
+                ServiceRegistry.get().register(id + JBPMConstants.DEPLOYMENT_CAMEL_CONTEXT_SERVICE_KEY_POSTFIX, context);
+
+            }
+        } catch (Exception e) {
+            LOGGER.error("Error while adding Camel context for {}", kieContainerInstance.getContainerId(), e);
+        }
+    }
+
+    @Override
+    public void updateContainer(String id, KieContainerInstance kieContainerInstance, Map<String, Object> parameters) {
+        disposeContainer(id, kieContainerInstance, parameters);
+        createContainer(id, kieContainerInstance, parameters);
+    }
+
+    @Override
+    public boolean isUpdateContainerAllowed(String id, KieContainerInstance kieContainerInstance, Map<String, Object> parameters) {
+        return true;
+    }
+
+    @Override
+    public void disposeContainer(String id, KieContainerInstance kieContainerInstance, Map<String, Object> parameters) {
+        DefaultCamelContext context = camelContexts.get(id);
+
+        if (context != null) {
+
+            ServiceRegistry.get().remove(id + "_CamelService");
+            try {
+                context.stop();
+            } catch (Exception e) {
+                LOGGER.error("Error while removing Camel context for container {}", id, e);
+            }
+        }
+    }
+
+    @Override
+    public List<Object> getAppComponents(SupportedTransports type) {
+        return Collections.emptyList();
+    }
+
+    @Override
+    public <T> T getAppComponents(Class<T> serviceType) {
+        return null;
+    }
+
+    @Override
+    public String getImplementedCapability() {
+        return "Integration";
+    }
+
+    @Override
+    public List<Object> getServices() {
+        return Collections.emptyList();
+    }
+
+    @Override
+    public String getExtensionName() {
+        return EXTENSION_NAME;
+    }
+
+    @Override
+    public Integer getStartOrder() {
+        return 50;
+    }
+
+    @Override
+    public void serverStarted() {
+        if (this.managedCamel && this.camelContext != null && !this.camelContext.isStarted()) {
+            try {
+                this.camelContext.start();
+            } catch (Exception e) {
+                LOGGER.error("Failed at start Camel context", e);
+            }
+        }
+    }
+
+    @Override
+    public String toString() {
+        return EXTENSION_NAME + " KIE Server extension";
+    }
+
+    protected void annotateKJarRoutes(RoutesDefinition routes, String deploymentId) {
+        for (RouteDefinition route : routes.getRoutes()) {
+
+            for (FromDefinition from : route.getInputs()) {
+
+                if (from.getUri().startsWith("jbpm:events") && !from.getUri().contains("deploymentId")) {
+                    StringBuilder uri = new StringBuilder(from.getUri());
+
+                    String[] split = from.getUri().split("\\?");
+                    if (split.length == 1) {
+                        // no query given
+                        uri.append("?");
+                    } else {
+                        // already query params exist
+                        uri.append("&");
+                    }
+                    uri.append("deploymentId=").append(deploymentId);
+                    from.setUri(uri.toString());
+                }
+
+                System.out.println(from.getUri());
+            }
+        }
+    }
+}
diff --git a/components/camel-jbpm/src/main/java/org/apache/camel/component/jbpm/workitem/AbstractCamelCommand.java b/components/camel-jbpm/src/main/java/org/apache/camel/component/jbpm/workitem/AbstractCamelCommand.java
new file mode 100644
index 00000000000..1900960ed2b
--- /dev/null
+++ b/components/camel-jbpm/src/main/java/org/apache/camel/component/jbpm/workitem/AbstractCamelCommand.java
@@ -0,0 +1,81 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.camel.component.jbpm.workitem;
+
+import org.apache.camel.Exchange;
+import org.apache.camel.Message;
+import org.apache.camel.ProducerTemplate;
+import org.apache.camel.builder.ExchangeBuilder;
+import org.apache.camel.component.jbpm.JBPMConstants;
+import org.kie.api.executor.Command;
+import org.kie.api.executor.CommandContext;
+import org.kie.api.executor.ExecutionResults;
+import org.kie.api.runtime.process.WorkItem;
+import org.kie.internal.runtime.Cacheable;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+/**
+ * Camel jBPM {@link Command} which allows to call Camel routes with a <code>direct</code> endpoint.
+ * <p/>
+ * The command passes the {@WorkItem} retrieved from the {@link CommandContext} to the route that has a consumer on the endpoint-id 
+ * that can be passed with the <code>camel-endpoint-id</code> {@link WorkItem} parameter. E.g. when a the value "myCamelEndpoint" is passed to the 
+ * {link WorkItem} via the <code>camel-endpoint-id</code> parameter, this {@link Command} will send the {@link WorkItem} to 
+ * the Camel URI <code>direct://myCamelEndpoint</code>.  
+ * <p/>
+ * The body of the result {@link Message} of the invocation is returned via the <code>Response</code> parameter. Access to the raw response 
+ * {@link Message} is provided via the <code>Message</code> parameter. This gives the user access to more advanced fields like message headers 
+ * and attachments.
+ */
+public abstract class AbstractCamelCommand implements Command, Cacheable {
+    private static final Logger LOGGER = LoggerFactory.getLogger(AbstractCamelCommand.class);
+
+    public AbstractCamelCommand() {
+    }
+    
+    @Override
+    public ExecutionResults execute(CommandContext ctx) throws Exception {
+        
+        WorkItem workItem = (WorkItem) ctx.getData("workItem");
+      
+        String camelEndpointId = (String) workItem.getParameter(JBPMConstants.CAMEL_ENDPOINT_ID_WI_PARAM);
+
+        // We only support direct. We don't need to support more, as direct simply gives us the entrypoint into the actual Camel Routes.
+        String camelUri = "direct://" + camelEndpointId;
+        
+        ProducerTemplate producerTemplate = getProducerTemplate(ctx);
+        Exchange inExchange = ExchangeBuilder.anExchange(producerTemplate.getCamelContext()).withBody(workItem).build();
+        Exchange outExchange = producerTemplate.send(camelUri, inExchange);
+
+        // producerTemplate.send does not throw exceptions, instead they are set on the returned Exchange.
+        if (outExchange.getException() != null) {
+            throw outExchange.getException();
+        }
+
+        Message outMessage = outExchange.getOut();
+
+        ExecutionResults results = new ExecutionResults();
+        Object response = outMessage.getBody();
+        results.setData(JBPMConstants.RESPONSE_WI_PARAM, response);
+        results.setData(JBPMConstants.MESSAGE_WI_PARAM, outMessage);
+
+        return results;
+    }
+
+    protected abstract ProducerTemplate getProducerTemplate(CommandContext ctx);
+
+}
\ No newline at end of file
diff --git a/components/camel-jbpm/src/main/java/org/apache/camel/component/jbpm/workitem/AbstractCamelWorkItemHandler.java b/components/camel-jbpm/src/main/java/org/apache/camel/component/jbpm/workitem/AbstractCamelWorkItemHandler.java
new file mode 100644
index 00000000000..d5ea7df9092
--- /dev/null
+++ b/components/camel-jbpm/src/main/java/org/apache/camel/component/jbpm/workitem/AbstractCamelWorkItemHandler.java
@@ -0,0 +1,152 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.camel.component.jbpm.workitem;
+
+import org.apache.camel.CamelContext;
+import org.apache.camel.Exchange;
+import org.apache.camel.Message;
+import org.apache.camel.ProducerTemplate;
+import org.apache.camel.component.jbpm.JBPMConstants;
+import org.jbpm.process.workitem.core.AbstractLogOrThrowWorkItemHandler;
+import org.jbpm.services.api.service.ServiceRegistry;
+import org.kie.api.runtime.manager.RuntimeManager;
+import org.kie.api.runtime.process.WorkItem;
+import org.kie.api.runtime.process.WorkItemHandler;
+import org.kie.api.runtime.process.WorkItemManager;
+import org.kie.internal.runtime.Cacheable;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+/**
+ * Camel jBPM {@link WorkItemHandler} which allows to call Camel routes with a <code>direct</code> endpoint.
+ * <p/>
+ * The handler passes the {@WorkItem} to the route that has a consumer on the endpoint-id that can be passed with the
+ * <code>CamelEndpointId</code>{@link WorkItem} parameter. E.g. when a the value "myCamelEndpoint" is passed to the {link WorkItem} via
+ * the <code>CamelEndpointId</code> parameter, this command will send the {@link WorkItem} to the Camel URI
+ * <code>direct://myCamelEndpoint</code>.
+ * <p/>
+ * The body of the result {@link Message} of the invocation is returned via the <code>Response</code> parameter. Access to the raw response
+ * {@link Message} is provided via the <code>Message</code> parameter. This gives the user access to more advanced fields like message
+ * headers and attachments.
+ * <p/>
+ * This handler can be constructed in multiple ways. When you don't pass a {@link RuntimeManager} to the constructor, the handler will try
+ * to find the global KIE {@link CamelContext} from the <code>jBPM</code> {@link ServiceRegistry}. When the {@link RuntimeManager} is passed
+ * to the constructor, the handler will retrieve and use the {@link CamelContext} bound to the {@link RuntimeManage} from the
+ * {@link ServiceRegistry}. When a <code>CamelEndpointId</code> is passed to the constructor, the handler will send all requests to the
+ * Camel route that is consuming from that endpoint, unless the endpoint is overridden by passing a the <code>CamelEndpointId</code> in
+ * the {@link WorkItem} parameters.
+ * 
+ */
+public abstract class AbstractCamelWorkItemHandler extends AbstractLogOrThrowWorkItemHandler implements Cacheable {
+
+    private static Logger logger = LoggerFactory.getLogger(AbstractCamelWorkItemHandler.class);
+
+    private final ProducerTemplate producerTemplate;
+
+    private final String camelEndpointId;
+
+    /**
+     * Default Constructor. This creates a {@link ProducerTemplate} for the global {@link CamelContext}.
+     */
+    public AbstractCamelWorkItemHandler() {
+        this("");
+    }
+
+    public AbstractCamelWorkItemHandler(String camelEndointId) {
+        CamelContext globalCamelContext = (CamelContext) ServiceRegistry.get().service(JBPMConstants.GLOBAL_CAMEL_CONTEXT_SERVICE_KEY);
+        this.producerTemplate = globalCamelContext.createProducerTemplate();
+        this.camelEndpointId = camelEndointId;
+    }
+
+    /**
+     * Constructor which accepts {@link RuntimeManager}. This causes this WorkItemHanlder to create a {@link ProducerTemplate} for the
+     * runtime specific {@link CamelContext}.
+     */
+    public AbstractCamelWorkItemHandler(RuntimeManager runtimeManager) {
+        this(runtimeManager, "");
+    }
+
+    public AbstractCamelWorkItemHandler(RuntimeManager runtimeManager, String camelEndpointId) {
+        String runtimeCamelContextKey = runtimeManager.getIdentifier() + JBPMConstants.DEPLOYMENT_CAMEL_CONTEXT_SERVICE_KEY_POSTFIX;
+        CamelContext runtimeCamelContext = (CamelContext) ServiceRegistry.get().service(runtimeCamelContextKey);
+        this.producerTemplate = runtimeCamelContext.createProducerTemplate();
+        this.camelEndpointId = camelEndpointId;
+    }
+
+    public void executeWorkItem(WorkItem workItem, final WorkItemManager manager) {
+
+        String workItemCamelEndpointId = getCamelEndpointId(workItem);
+
+        // We only support direct. We don't need to support more, as direct simply gives us the entrypoint into the actual Camel Routes.
+        String camelUri = "direct://" + workItemCamelEndpointId;
+
+        try {
+            Exchange requestExchange = buildExchange(producerTemplate, workItem);
+            logger.debug("Sending Camel Exchange to: " + camelUri);
+            Exchange responseExchange = producerTemplate.send(camelUri, requestExchange);
+            // producerTemplate.send does not throw exceptions, instead they are set on the returned Exchange.
+            if (responseExchange.getException() != null) {
+                throw responseExchange.getException();
+            }
+            handleResponse(responseExchange, workItem, manager);
+        } catch (Exception e) {
+            handleException(e);
+        }
+    }
+
+    protected String getCamelEndpointId(WorkItem workItem) {
+        String workItemCamelEndpointId = (String) workItem.getParameter(JBPMConstants.CAMEL_ENDPOINT_ID_WI_PARAM);
+
+        if (camelEndpointId != null && !camelEndpointId.isEmpty()) {
+            if (workItemCamelEndpointId != null && !workItemCamelEndpointId.isEmpty()) {
+                logger.debug(
+                        "The Camel Endpoint ID has been set on both the WorkItemHanlder and WorkItem. The '"
+                                + JBPMConstants.CAMEL_ENDPOINT_ID_WI_PARAM
+                                + "' configured on the WorkItem overrides the global configuation.");
+            } else {
+                workItemCamelEndpointId = camelEndpointId;
+            }
+        }
+
+        if (workItemCamelEndpointId == null || workItemCamelEndpointId.isEmpty()) {
+            throw new IllegalArgumentException(
+                    "No Camel Endpoint ID specified. Please configure the '" + JBPMConstants.CAMEL_ENDPOINT_ID_WI_PARAM
+                            + "' in either the constructor of this WorkItemHandler, or pass it via the "
+                            + JBPMConstants.CAMEL_ENDPOINT_ID_WI_PARAM + "' WorkItem parameter.");
+        }
+        return workItemCamelEndpointId;
+    }
+
+    protected abstract void handleResponse(Exchange responseExchange, WorkItem workItem, WorkItemManager manager);
+
+    protected abstract Exchange buildExchange(ProducerTemplate template, WorkItem workItem);
+
+    public void abortWorkItem(WorkItem workItem, WorkItemManager manager) {
+        // Do nothing, cannot be aborted
+    }
+
+    @Override
+    public void close() {
+        try {
+            this.producerTemplate.stop();
+        } catch (Exception e) {
+            logger.warn("Error encountered while closing the Camel Producer Template.", e);
+            // Not much we can do here, so swallowing exception.
+        }
+    }
+
+}
\ No newline at end of file
diff --git a/components/camel-jbpm/src/main/java/org/apache/camel/component/jbpm/workitem/DeploymentContextCamelCommand.java b/components/camel-jbpm/src/main/java/org/apache/camel/component/jbpm/workitem/DeploymentContextCamelCommand.java
new file mode 100644
index 00000000000..69c74ad211d
--- /dev/null
+++ b/components/camel-jbpm/src/main/java/org/apache/camel/component/jbpm/workitem/DeploymentContextCamelCommand.java
@@ -0,0 +1,71 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.camel.component.jbpm.workitem;
+
+import java.util.Map;
+import java.util.concurrent.ConcurrentHashMap;
+
+import org.apache.camel.CamelContext;
+import org.apache.camel.ProducerTemplate;
+import org.apache.camel.component.jbpm.JBPMConstants;
+import org.jbpm.services.api.service.ServiceRegistry;
+import org.kie.api.executor.CommandContext;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+/**
+ * CamelCommand that uses the {@link CamelContext} registered on the {@link ServiceRegistry} for this specific deployment.
+ */
+public class DeploymentContextCamelCommand extends AbstractCamelCommand {
+    private static final Logger LOGGER = LoggerFactory.getLogger(DeploymentContextCamelCommand.class);
+
+    private final Map<String, ProducerTemplate> templates = new ConcurrentHashMap<>();
+
+    @Override
+    protected ProducerTemplate getProducerTemplate(CommandContext ctx) {
+        String deploymentId = (String) ctx.getData("deploymentId");
+        ProducerTemplate template = templates.get(deploymentId);
+
+        if (template == null) {
+            synchronized (this) {
+                template = templates.get(deploymentId);
+                if (template == null) {
+                    CamelContext deploymentCamelContext = (CamelContext) ServiceRegistry.get()
+                            .service(deploymentId + JBPMConstants.DEPLOYMENT_CAMEL_CONTEXT_SERVICE_KEY_POSTFIX);
+                    template = deploymentCamelContext.createProducerTemplate();
+                    templates.put(deploymentId, template);
+                }
+            }
+        }
+        return template;
+    }
+
+    @Override
+    public void close() {
+        for (ProducerTemplate nextTemplate : templates.values()) {
+            try {
+                nextTemplate.stop();
+            } catch (Exception e) {
+                LOGGER.warn("Error encountered while closing the Camel Producer Template.", e);
+                // Not much we can do here, so swallowing exception.
+            }
+        }
+
+    }
+
+}
diff --git a/components/camel-jbpm/src/main/java/org/apache/camel/component/jbpm/workitem/GlobalContextCamelCommand.java b/components/camel-jbpm/src/main/java/org/apache/camel/component/jbpm/workitem/GlobalContextCamelCommand.java
new file mode 100644
index 00000000000..aa46014e818
--- /dev/null

  (This diff was longer than 20,000 lines, and has been truncated...)


 

----------------------------------------------------------------
This is an automated message from the Apache Git Service.
To respond to the message, please log on GitHub and use the
URL above to go to the specific comment.
 
For queries about this service, please contact Infrastructure at:
users@infra.apache.org


Issue Time Tracking
-------------------

            Worklog Id:     (was: 177415)
            Time Spent: 10m
    Remaining Estimate: 0h

> Create a Camel-ChatScript component
> -----------------------------------
>
>                 Key: CAMEL-12955
>                 URL: https://issues.apache.org/jira/browse/CAMEL-12955
>             Project: Camel
>          Issue Type: New Feature
>            Reporter: Varun Krish
>            Assignee: Andrea Cosentino
>            Priority: Major
>             Fix For: 3.0.0
>
>          Time Spent: 10m
>  Remaining Estimate: 0h
>
> Create new component to interact with ChatScript BOTs.
> Chat Script: [https://github.com/bwilcox-1234/ChatScript]
>  



--
This message was sent by Atlassian JIRA
(v7.6.3#76005)