You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@camel.apache.org by da...@apache.org on 2016/11/24 08:31:56 UTC

[1/3] camel git commit: Source code generated.

Repository: camel
Updated Branches:
  refs/heads/master 6d1f54234 -> 11e3bbf84


Source code generated.


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

Branch: refs/heads/master
Commit: 11e3bbf84ede874edc7afe1c9e60eb9b5dd2226e
Parents: b47de2b
Author: Claus Ibsen <da...@apache.org>
Authored: Thu Nov 24 09:31:37 2016 +0100
Committer: Claus Ibsen <da...@apache.org>
Committed: Thu Nov 24 09:31:45 2016 +0100

----------------------------------------------------------------------
 .../bindy/csv/springboot/BindyCsvDataFormatConfiguration.java       | 1 +
 .../fixed/springboot/BindyFixedLengthDataFormatConfiguration.java   | 1 +
 .../kvp/springboot/BindyKeyValuePairDataFormatConfiguration.java    | 1 +
 .../component/ganglia/springboot/GangliaComponentConfiguration.java | 1 +
 .../component/gson/springboot/GsonDataFormatConfiguration.java      | 1 +
 .../jackson/springboot/JacksonDataFormatConfiguration.java          | 1 +
 .../camel/component/jms/springboot/JmsComponentConfiguration.java   | 1 +
 .../johnzon/springboot/JohnzonDataFormatConfiguration.java          | 1 +
 .../component/mina2/springboot/Mina2ComponentConfiguration.java     | 1 +
 .../component/netty/springboot/NettyComponentConfiguration.java     | 1 +
 .../component/netty4/springboot/NettyComponentConfiguration.java    | 1 +
 .../servicenow/springboot/ServiceNowComponentConfiguration.java     | 1 +
 .../camel/component/smpp/springboot/SmppComponentConfiguration.java | 1 +
 .../snakeyaml/springboot/SnakeYAMLDataFormatConfiguration.java      | 1 +
 .../dataformat/xstream/springboot/JsonDataFormatConfiguration.java  | 1 +
 15 files changed, 15 insertions(+)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/camel/blob/11e3bbf8/components-starter/camel-bindy-starter/src/main/java/org/apache/camel/dataformat/bindy/csv/springboot/BindyCsvDataFormatConfiguration.java
----------------------------------------------------------------------
diff --git a/components-starter/camel-bindy-starter/src/main/java/org/apache/camel/dataformat/bindy/csv/springboot/BindyCsvDataFormatConfiguration.java b/components-starter/camel-bindy-starter/src/main/java/org/apache/camel/dataformat/bindy/csv/springboot/BindyCsvDataFormatConfiguration.java
index eda9046..b249e17 100644
--- a/components-starter/camel-bindy-starter/src/main/java/org/apache/camel/dataformat/bindy/csv/springboot/BindyCsvDataFormatConfiguration.java
+++ b/components-starter/camel-bindy-starter/src/main/java/org/apache/camel/dataformat/bindy/csv/springboot/BindyCsvDataFormatConfiguration.java
@@ -16,6 +16,7 @@
  */
 package org.apache.camel.dataformat.bindy.csv.springboot;
 
+import org.apache.camel.dataformat.bindy.csv.BindyCsvDataFormat;
 import org.apache.camel.model.dataformat.BindyType;
 import org.springframework.boot.context.properties.ConfigurationProperties;
 

http://git-wip-us.apache.org/repos/asf/camel/blob/11e3bbf8/components-starter/camel-bindy-starter/src/main/java/org/apache/camel/dataformat/bindy/fixed/springboot/BindyFixedLengthDataFormatConfiguration.java
----------------------------------------------------------------------
diff --git a/components-starter/camel-bindy-starter/src/main/java/org/apache/camel/dataformat/bindy/fixed/springboot/BindyFixedLengthDataFormatConfiguration.java b/components-starter/camel-bindy-starter/src/main/java/org/apache/camel/dataformat/bindy/fixed/springboot/BindyFixedLengthDataFormatConfiguration.java
index 9a6bed6..8931068 100644
--- a/components-starter/camel-bindy-starter/src/main/java/org/apache/camel/dataformat/bindy/fixed/springboot/BindyFixedLengthDataFormatConfiguration.java
+++ b/components-starter/camel-bindy-starter/src/main/java/org/apache/camel/dataformat/bindy/fixed/springboot/BindyFixedLengthDataFormatConfiguration.java
@@ -16,6 +16,7 @@
  */
 package org.apache.camel.dataformat.bindy.fixed.springboot;
 
+import org.apache.camel.dataformat.bindy.fixed.BindyFixedLengthDataFormat;
 import org.apache.camel.model.dataformat.BindyType;
 import org.springframework.boot.context.properties.ConfigurationProperties;
 

http://git-wip-us.apache.org/repos/asf/camel/blob/11e3bbf8/components-starter/camel-bindy-starter/src/main/java/org/apache/camel/dataformat/bindy/kvp/springboot/BindyKeyValuePairDataFormatConfiguration.java
----------------------------------------------------------------------
diff --git a/components-starter/camel-bindy-starter/src/main/java/org/apache/camel/dataformat/bindy/kvp/springboot/BindyKeyValuePairDataFormatConfiguration.java b/components-starter/camel-bindy-starter/src/main/java/org/apache/camel/dataformat/bindy/kvp/springboot/BindyKeyValuePairDataFormatConfiguration.java
index 77d1326..b30ed96 100644
--- a/components-starter/camel-bindy-starter/src/main/java/org/apache/camel/dataformat/bindy/kvp/springboot/BindyKeyValuePairDataFormatConfiguration.java
+++ b/components-starter/camel-bindy-starter/src/main/java/org/apache/camel/dataformat/bindy/kvp/springboot/BindyKeyValuePairDataFormatConfiguration.java
@@ -16,6 +16,7 @@
  */
 package org.apache.camel.dataformat.bindy.kvp.springboot;
 
+import org.apache.camel.dataformat.bindy.kvp.BindyKeyValuePairDataFormat;
 import org.apache.camel.model.dataformat.BindyType;
 import org.springframework.boot.context.properties.ConfigurationProperties;
 

http://git-wip-us.apache.org/repos/asf/camel/blob/11e3bbf8/components-starter/camel-ganglia-starter/src/main/java/org/apache/camel/component/ganglia/springboot/GangliaComponentConfiguration.java
----------------------------------------------------------------------
diff --git a/components-starter/camel-ganglia-starter/src/main/java/org/apache/camel/component/ganglia/springboot/GangliaComponentConfiguration.java b/components-starter/camel-ganglia-starter/src/main/java/org/apache/camel/component/ganglia/springboot/GangliaComponentConfiguration.java
index 0044529..98fa94a 100644
--- a/components-starter/camel-ganglia-starter/src/main/java/org/apache/camel/component/ganglia/springboot/GangliaComponentConfiguration.java
+++ b/components-starter/camel-ganglia-starter/src/main/java/org/apache/camel/component/ganglia/springboot/GangliaComponentConfiguration.java
@@ -19,6 +19,7 @@ package org.apache.camel.component.ganglia.springboot;
 import info.ganglia.gmetric4j.gmetric.GMetric.UDPAddressingMode;
 import info.ganglia.gmetric4j.gmetric.GMetricSlope;
 import info.ganglia.gmetric4j.gmetric.GMetricType;
+import org.apache.camel.component.ganglia.GangliaComponent;
 import org.springframework.boot.context.properties.ConfigurationProperties;
 
 /**

http://git-wip-us.apache.org/repos/asf/camel/blob/11e3bbf8/components-starter/camel-gson-starter/src/main/java/org/apache/camel/component/gson/springboot/GsonDataFormatConfiguration.java
----------------------------------------------------------------------
diff --git a/components-starter/camel-gson-starter/src/main/java/org/apache/camel/component/gson/springboot/GsonDataFormatConfiguration.java b/components-starter/camel-gson-starter/src/main/java/org/apache/camel/component/gson/springboot/GsonDataFormatConfiguration.java
index d415c29..c4324a6 100644
--- a/components-starter/camel-gson-starter/src/main/java/org/apache/camel/component/gson/springboot/GsonDataFormatConfiguration.java
+++ b/components-starter/camel-gson-starter/src/main/java/org/apache/camel/component/gson/springboot/GsonDataFormatConfiguration.java
@@ -16,6 +16,7 @@
  */
 package org.apache.camel.component.gson.springboot;
 
+import org.apache.camel.component.gson.GsonDataFormat;
 import org.apache.camel.model.dataformat.JsonLibrary;
 import org.springframework.boot.context.properties.ConfigurationProperties;
 

http://git-wip-us.apache.org/repos/asf/camel/blob/11e3bbf8/components-starter/camel-jackson-starter/src/main/java/org/apache/camel/component/jackson/springboot/JacksonDataFormatConfiguration.java
----------------------------------------------------------------------
diff --git a/components-starter/camel-jackson-starter/src/main/java/org/apache/camel/component/jackson/springboot/JacksonDataFormatConfiguration.java b/components-starter/camel-jackson-starter/src/main/java/org/apache/camel/component/jackson/springboot/JacksonDataFormatConfiguration.java
index f325c42..57d06c4 100644
--- a/components-starter/camel-jackson-starter/src/main/java/org/apache/camel/component/jackson/springboot/JacksonDataFormatConfiguration.java
+++ b/components-starter/camel-jackson-starter/src/main/java/org/apache/camel/component/jackson/springboot/JacksonDataFormatConfiguration.java
@@ -16,6 +16,7 @@
  */
 package org.apache.camel.component.jackson.springboot;
 
+import org.apache.camel.component.jackson.JacksonDataFormat;
 import org.apache.camel.model.dataformat.JsonLibrary;
 import org.springframework.boot.context.properties.ConfigurationProperties;
 

http://git-wip-us.apache.org/repos/asf/camel/blob/11e3bbf8/components-starter/camel-jms-starter/src/main/java/org/apache/camel/component/jms/springboot/JmsComponentConfiguration.java
----------------------------------------------------------------------
diff --git a/components-starter/camel-jms-starter/src/main/java/org/apache/camel/component/jms/springboot/JmsComponentConfiguration.java b/components-starter/camel-jms-starter/src/main/java/org/apache/camel/component/jms/springboot/JmsComponentConfiguration.java
index 7e3f629..bc77edf 100644
--- a/components-starter/camel-jms-starter/src/main/java/org/apache/camel/component/jms/springboot/JmsComponentConfiguration.java
+++ b/components-starter/camel-jms-starter/src/main/java/org/apache/camel/component/jms/springboot/JmsComponentConfiguration.java
@@ -21,6 +21,7 @@ import javax.jms.ExceptionListener;
 import org.apache.camel.LoggingLevel;
 import org.apache.camel.component.jms.ConsumerType;
 import org.apache.camel.component.jms.DefaultTaskExecutorType;
+import org.apache.camel.component.jms.JmsComponent;
 import org.apache.camel.component.jms.JmsKeyFormatStrategy;
 import org.apache.camel.component.jms.JmsMessageType;
 import org.apache.camel.component.jms.JmsProviderMetadata;

http://git-wip-us.apache.org/repos/asf/camel/blob/11e3bbf8/components-starter/camel-johnzon-starter/src/main/java/org/apache/camel/component/johnzon/springboot/JohnzonDataFormatConfiguration.java
----------------------------------------------------------------------
diff --git a/components-starter/camel-johnzon-starter/src/main/java/org/apache/camel/component/johnzon/springboot/JohnzonDataFormatConfiguration.java b/components-starter/camel-johnzon-starter/src/main/java/org/apache/camel/component/johnzon/springboot/JohnzonDataFormatConfiguration.java
index 5206598..e3719c9 100644
--- a/components-starter/camel-johnzon-starter/src/main/java/org/apache/camel/component/johnzon/springboot/JohnzonDataFormatConfiguration.java
+++ b/components-starter/camel-johnzon-starter/src/main/java/org/apache/camel/component/johnzon/springboot/JohnzonDataFormatConfiguration.java
@@ -16,6 +16,7 @@
  */
 package org.apache.camel.component.johnzon.springboot;
 
+import org.apache.camel.component.johnzon.JohnzonDataFormat;
 import org.apache.camel.model.dataformat.JsonLibrary;
 import org.springframework.boot.context.properties.ConfigurationProperties;
 

http://git-wip-us.apache.org/repos/asf/camel/blob/11e3bbf8/components-starter/camel-mina2-starter/src/main/java/org/apache/camel/component/mina2/springboot/Mina2ComponentConfiguration.java
----------------------------------------------------------------------
diff --git a/components-starter/camel-mina2-starter/src/main/java/org/apache/camel/component/mina2/springboot/Mina2ComponentConfiguration.java b/components-starter/camel-mina2-starter/src/main/java/org/apache/camel/component/mina2/springboot/Mina2ComponentConfiguration.java
index 7c794ba..9ebc627 100644
--- a/components-starter/camel-mina2-starter/src/main/java/org/apache/camel/component/mina2/springboot/Mina2ComponentConfiguration.java
+++ b/components-starter/camel-mina2-starter/src/main/java/org/apache/camel/component/mina2/springboot/Mina2ComponentConfiguration.java
@@ -18,6 +18,7 @@ package org.apache.camel.component.mina2.springboot;
 
 import java.util.List;
 import org.apache.camel.LoggingLevel;
+import org.apache.camel.component.mina2.Mina2Component;
 import org.apache.camel.component.mina2.Mina2TextLineDelimiter;
 import org.apache.camel.util.jsse.SSLContextParameters;
 import org.apache.mina.filter.codec.ProtocolCodecFactory;

http://git-wip-us.apache.org/repos/asf/camel/blob/11e3bbf8/components-starter/camel-netty-starter/src/main/java/org/apache/camel/component/netty/springboot/NettyComponentConfiguration.java
----------------------------------------------------------------------
diff --git a/components-starter/camel-netty-starter/src/main/java/org/apache/camel/component/netty/springboot/NettyComponentConfiguration.java b/components-starter/camel-netty-starter/src/main/java/org/apache/camel/component/netty/springboot/NettyComponentConfiguration.java
index 2e4d644..8720056 100644
--- a/components-starter/camel-netty-starter/src/main/java/org/apache/camel/component/netty/springboot/NettyComponentConfiguration.java
+++ b/components-starter/camel-netty-starter/src/main/java/org/apache/camel/component/netty/springboot/NettyComponentConfiguration.java
@@ -21,6 +21,7 @@ import java.util.List;
 import java.util.Map;
 import org.apache.camel.LoggingLevel;
 import org.apache.camel.component.netty.ClientPipelineFactory;
+import org.apache.camel.component.netty.NettyComponent;
 import org.apache.camel.component.netty.NettyServerBootstrapFactory;
 import org.apache.camel.component.netty.ServerPipelineFactory;
 import org.apache.camel.component.netty.TextLineDelimiter;

http://git-wip-us.apache.org/repos/asf/camel/blob/11e3bbf8/components-starter/camel-netty4-starter/src/main/java/org/apache/camel/component/netty4/springboot/NettyComponentConfiguration.java
----------------------------------------------------------------------
diff --git a/components-starter/camel-netty4-starter/src/main/java/org/apache/camel/component/netty4/springboot/NettyComponentConfiguration.java b/components-starter/camel-netty4-starter/src/main/java/org/apache/camel/component/netty4/springboot/NettyComponentConfiguration.java
index 37657e7..fb5f59d 100644
--- a/components-starter/camel-netty4-starter/src/main/java/org/apache/camel/component/netty4/springboot/NettyComponentConfiguration.java
+++ b/components-starter/camel-netty4-starter/src/main/java/org/apache/camel/component/netty4/springboot/NettyComponentConfiguration.java
@@ -26,6 +26,7 @@ import io.netty.handler.ssl.SslHandler;
 import io.netty.util.concurrent.EventExecutorGroup;
 import org.apache.camel.LoggingLevel;
 import org.apache.camel.component.netty4.ClientInitializerFactory;
+import org.apache.camel.component.netty4.NettyComponent;
 import org.apache.camel.component.netty4.NettyServerBootstrapFactory;
 import org.apache.camel.component.netty4.ServerInitializerFactory;
 import org.apache.camel.component.netty4.TextLineDelimiter;

http://git-wip-us.apache.org/repos/asf/camel/blob/11e3bbf8/components-starter/camel-servicenow-starter/src/main/java/org/apache/camel/component/servicenow/springboot/ServiceNowComponentConfiguration.java
----------------------------------------------------------------------
diff --git a/components-starter/camel-servicenow-starter/src/main/java/org/apache/camel/component/servicenow/springboot/ServiceNowComponentConfiguration.java b/components-starter/camel-servicenow-starter/src/main/java/org/apache/camel/component/servicenow/springboot/ServiceNowComponentConfiguration.java
index f8f20c5..1a41297 100644
--- a/components-starter/camel-servicenow-starter/src/main/java/org/apache/camel/component/servicenow/springboot/ServiceNowComponentConfiguration.java
+++ b/components-starter/camel-servicenow-starter/src/main/java/org/apache/camel/component/servicenow/springboot/ServiceNowComponentConfiguration.java
@@ -18,6 +18,7 @@ package org.apache.camel.component.servicenow.springboot;
 
 import java.util.Map;
 import com.fasterxml.jackson.databind.ObjectMapper;
+import org.apache.camel.component.servicenow.ServiceNowComponent;
 import org.apache.camel.component.servicenow.ServiceNowRelease;
 import org.springframework.boot.context.properties.ConfigurationProperties;
 import org.springframework.boot.context.properties.NestedConfigurationProperty;

http://git-wip-us.apache.org/repos/asf/camel/blob/11e3bbf8/components-starter/camel-smpp-starter/src/main/java/org/apache/camel/component/smpp/springboot/SmppComponentConfiguration.java
----------------------------------------------------------------------
diff --git a/components-starter/camel-smpp-starter/src/main/java/org/apache/camel/component/smpp/springboot/SmppComponentConfiguration.java b/components-starter/camel-smpp-starter/src/main/java/org/apache/camel/component/smpp/springboot/SmppComponentConfiguration.java
index baf5d11..6768a31 100644
--- a/components-starter/camel-smpp-starter/src/main/java/org/apache/camel/component/smpp/springboot/SmppComponentConfiguration.java
+++ b/components-starter/camel-smpp-starter/src/main/java/org/apache/camel/component/smpp/springboot/SmppComponentConfiguration.java
@@ -17,6 +17,7 @@
 package org.apache.camel.component.smpp.springboot;
 
 import java.util.Map;
+import org.apache.camel.component.smpp.SmppComponent;
 import org.apache.camel.component.smpp.SmppSplittingPolicy;
 import org.jsmpp.session.SessionStateListener;
 import org.springframework.boot.context.properties.ConfigurationProperties;

http://git-wip-us.apache.org/repos/asf/camel/blob/11e3bbf8/components-starter/camel-snakeyaml-starter/src/main/java/org/apache/camel/component/snakeyaml/springboot/SnakeYAMLDataFormatConfiguration.java
----------------------------------------------------------------------
diff --git a/components-starter/camel-snakeyaml-starter/src/main/java/org/apache/camel/component/snakeyaml/springboot/SnakeYAMLDataFormatConfiguration.java b/components-starter/camel-snakeyaml-starter/src/main/java/org/apache/camel/component/snakeyaml/springboot/SnakeYAMLDataFormatConfiguration.java
index 3ad82c8..ce78189 100644
--- a/components-starter/camel-snakeyaml-starter/src/main/java/org/apache/camel/component/snakeyaml/springboot/SnakeYAMLDataFormatConfiguration.java
+++ b/components-starter/camel-snakeyaml-starter/src/main/java/org/apache/camel/component/snakeyaml/springboot/SnakeYAMLDataFormatConfiguration.java
@@ -16,6 +16,7 @@
  */
 package org.apache.camel.component.snakeyaml.springboot;
 
+import org.apache.camel.component.snakeyaml.SnakeYAMLDataFormat;
 import org.apache.camel.model.dataformat.YAMLLibrary;
 import org.springframework.boot.context.properties.ConfigurationProperties;
 

http://git-wip-us.apache.org/repos/asf/camel/blob/11e3bbf8/components-starter/camel-xstream-starter/src/main/java/org/apache/camel/dataformat/xstream/springboot/JsonDataFormatConfiguration.java
----------------------------------------------------------------------
diff --git a/components-starter/camel-xstream-starter/src/main/java/org/apache/camel/dataformat/xstream/springboot/JsonDataFormatConfiguration.java b/components-starter/camel-xstream-starter/src/main/java/org/apache/camel/dataformat/xstream/springboot/JsonDataFormatConfiguration.java
index 808c6ba..153dbc5 100644
--- a/components-starter/camel-xstream-starter/src/main/java/org/apache/camel/dataformat/xstream/springboot/JsonDataFormatConfiguration.java
+++ b/components-starter/camel-xstream-starter/src/main/java/org/apache/camel/dataformat/xstream/springboot/JsonDataFormatConfiguration.java
@@ -16,6 +16,7 @@
  */
 package org.apache.camel.dataformat.xstream.springboot;
 
+import org.apache.camel.dataformat.xstream.JsonDataFormat;
 import org.apache.camel.model.dataformat.JsonLibrary;
 import org.springframework.boot.context.properties.ConfigurationProperties;
 


[3/3] camel git commit: CAMEL-8396 Update Salesforce component to support new REST APIs in Sa...

Posted by da...@apache.org.
CAMEL-8396 Update Salesforce component to support new REST APIs in Sa...

...lesforce API V33.0

This commit adds support for getting and sending approvals for
processing via Salesforce REST API[1].

Two new operations were added `approvals` to fetch any approvals already
in progress, and `approval` to initiate approval process on the supplied
record or records (batch).

For instance, `approvals` can be simply used as:

    ...to("salesforce:approvals")
        .split().body()
        .log("${body.entityId} - ${body.instanceStatus}")

And to send a record for approval you can use:

    ...to("salesforce:approval?approval.actionType=Submit&...")
        .log("${body.id} - ${body.instanceStatus}")

The `approval` operation has the ability to set properties on the
endpoint (let's call that template), via message headers and message
body. These can be combined, to place default values on the endpoint
(template), and runtime values trough headers or message body.

If the message body is an `Iterable` of `ApprovalRequest` objects then
they will be submitted in a batch.

The auto complete options were not up to date, added values for recent,
limit and the new approval and approvals operations.

[1]
https://developer.salesforce.com/docs/atlas.en-us.api_rest.meta/api_rest/resources_process_approvals.htm


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

Branch: refs/heads/master
Commit: b47de2b4bdc2136e6eed5f218f93fc714dd23c7d
Parents: 6d1f542
Author: Zoran Regvart <zo...@regvart.com>
Authored: Wed Nov 23 15:33:41 2016 +0100
Committer: Claus Ibsen <da...@apache.org>
Committed: Thu Nov 24 09:31:45 2016 +0100

----------------------------------------------------------------------
 .../SalesforceComponentConfiguration.java       | 124 +++++++++
 .../camel-salesforce-component/.gitignore       |   1 +
 .../camel-salesforce-component/pom.xml          |   5 +
 .../src/main/docs/salesforce-component.adoc     |  96 ++++++-
 .../salesforce/SalesforceComponent.java         |   1 +
 .../salesforce/SalesforceEndpointConfig.java    | 194 ++++++++++++-
 .../api/dto/approval/ApprovalRequest.java       | 247 +++++++++++++++++
 .../api/dto/approval/ApprovalRequests.java      |  68 +++++
 .../api/dto/approval/ApprovalResult.java        | 148 ++++++++++
 .../salesforce/api/dto/approval/Approvals.java  | 142 ++++++++++
 .../salesforce/internal/OperationName.java      |   6 +-
 .../internal/client/DefaultRestClient.java      |  23 ++
 .../salesforce/internal/client/RestClient.java  |  17 ++
 .../processor/AbstractRestProcessor.java        | 125 ++++++++-
 .../internal/processor/JsonRestProcessor.java   |  64 +++--
 .../internal/processor/XmlRestProcessor.java    |  36 ++-
 .../AbstractApprovalIntegrationTest.java        |  85 ++++++
 .../ApprovalExamplesIntegrationTest.java        | 101 +++++++
 .../salesforce/ApprovalIntegrationTest.java     | 112 ++++++++
 ...ceComponentConfigurationIntegrationTest.java |   4 +-
 .../api/dto/approval/ApprovalRequestTest.java   | 117 ++++++++
 .../api/dto/approval/ApprovalRequestsTest.java  | 133 +++++++++
 .../api/dto/approval/ApprovalResultTest.java    |  95 +++++++
 .../api/dto/approval/ApprovalsTest.java         |  75 +++++
 .../AbstractRestProcessorApprovalTest.java      | 271 +++++++++++++++++++
 25 files changed, 2254 insertions(+), 36 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/camel/blob/b47de2b4/components-starter/camel-salesforce-starter/src/main/java/org/apache/camel/component/salesforce/springboot/SalesforceComponentConfiguration.java
----------------------------------------------------------------------
diff --git a/components-starter/camel-salesforce-starter/src/main/java/org/apache/camel/component/salesforce/springboot/SalesforceComponentConfiguration.java b/components-starter/camel-salesforce-starter/src/main/java/org/apache/camel/component/salesforce/springboot/SalesforceComponentConfiguration.java
index 91f478c..1b7826b 100644
--- a/components-starter/camel-salesforce-starter/src/main/java/org/apache/camel/component/salesforce/springboot/SalesforceComponentConfiguration.java
+++ b/components-starter/camel-salesforce-starter/src/main/java/org/apache/camel/component/salesforce/springboot/SalesforceComponentConfiguration.java
@@ -16,11 +16,14 @@
  */
 package org.apache.camel.component.salesforce.springboot;
 
+import java.util.List;
 import java.util.Map;
 import java.util.Set;
 import com.fasterxml.jackson.databind.ObjectMapper;
 import org.apache.camel.component.salesforce.SalesforceHttpClient;
 import org.apache.camel.component.salesforce.api.dto.analytics.reports.ReportMetadata;
+import org.apache.camel.component.salesforce.api.dto.approval.ApprovalRequest;
+import org.apache.camel.component.salesforce.api.dto.approval.ApprovalRequest.Action;
 import org.apache.camel.component.salesforce.api.dto.bulk.ContentType;
 import org.apache.camel.component.salesforce.internal.PayloadFormat;
 import org.apache.camel.component.salesforce.internal.dto.NotifyForFieldsEnum;
@@ -299,6 +302,13 @@ public class SalesforceComponentConfiguration {
          */
         private Map apexQueryParams;
         /**
+         * The approval request for Approval API.
+         * 
+         * @param approval
+         */
+        @NestedConfigurationProperty
+        private ApprovalRequest approval;
+        /**
          * Bulk API content type, one of XML, CSV, ZIP_XML, ZIP_CSV
          */
         private ContentType contentType;
@@ -401,6 +411,54 @@ public class SalesforceComponentConfiguration {
          * @param limit
          */
         private Integer limit;
+        /**
+         * Represents the kind of action to take: Submit, Approve, or Reject.
+         * 
+         * @param actionType
+         */
+        private Action approvalActionType;
+        /**
+         * The comment to add to the history step associated with this request.
+         * 
+         * @param comments
+         */
+        private String approvalComments;
+        /**
+         * The ID of the submitter who\u2019s requesting the approval record.
+         * 
+         * @param contextActorId
+         */
+        private String approvalContextActorId;
+        /**
+         * The ID of the item that is being acted upon.
+         * 
+         * @param contextId
+         */
+        private String approvalContextId;
+        /**
+         * If the process requires specification of the next approval, the ID of
+         * the user to be assigned the next request.
+         * 
+         * @param nextApproverIds
+         */
+        private List approvalNextApproverIds;
+        /**
+         * The developer name or ID of the process definition.
+         * 
+         * @param processDefinitionNameOrId
+         */
+        private String approvalProcessDefinitionNameOrId;
+        /**
+         * Determines whether to evaluate the entry criteria for the process
+         * (true) or not (false) if the process definition name or ID isn\u2019t
+         * null. If the process definition name or ID isn\u2019t specified, this
+         * argument is ignored, and standard evaluation is followed based on
+         * process order. By default, the entry criteria isn\u2019t skipped if it\u2019s
+         * not set by this request.
+         * 
+         * @param skipEntryCriteria
+         */
+        private Boolean approvalSkipEntryCriteria;
 
         public PayloadFormat getFormat() {
             return format;
@@ -514,6 +572,14 @@ public class SalesforceComponentConfiguration {
             this.apexQueryParams = apexQueryParams;
         }
 
+        public ApprovalRequest getApproval() {
+            return approval;
+        }
+
+        public void setApproval(ApprovalRequest approval) {
+            this.approval = approval;
+        }
+
         public ContentType getContentType() {
             return contentType;
         }
@@ -691,6 +757,64 @@ public class SalesforceComponentConfiguration {
         public void setLimit(Integer limit) {
             this.limit = limit;
         }
+
+        public Action getApprovalActionType() {
+            return approvalActionType;
+        }
+
+        public void setApprovalActionType(Action approvalActionType) {
+            this.approvalActionType = approvalActionType;
+        }
+
+        public String getApprovalComments() {
+            return approvalComments;
+        }
+
+        public void setApprovalComments(String approvalComments) {
+            this.approvalComments = approvalComments;
+        }
+
+        public String getApprovalContextActorId() {
+            return approvalContextActorId;
+        }
+
+        public void setApprovalContextActorId(String approvalContextActorId) {
+            this.approvalContextActorId = approvalContextActorId;
+        }
+
+        public String getApprovalContextId() {
+            return approvalContextId;
+        }
+
+        public void setApprovalContextId(String approvalContextId) {
+            this.approvalContextId = approvalContextId;
+        }
+
+        public List getApprovalNextApproverIds() {
+            return approvalNextApproverIds;
+        }
+
+        public void setApprovalNextApproverIds(List approvalNextApproverIds) {
+            this.approvalNextApproverIds = approvalNextApproverIds;
+        }
+
+        public String getApprovalProcessDefinitionNameOrId() {
+            return approvalProcessDefinitionNameOrId;
+        }
+
+        public void setApprovalProcessDefinitionNameOrId(
+                String approvalProcessDefinitionNameOrId) {
+            this.approvalProcessDefinitionNameOrId = approvalProcessDefinitionNameOrId;
+        }
+
+        public Boolean getApprovalSkipEntryCriteria() {
+            return approvalSkipEntryCriteria;
+        }
+
+        public void setApprovalSkipEntryCriteria(
+                Boolean approvalSkipEntryCriteria) {
+            this.approvalSkipEntryCriteria = approvalSkipEntryCriteria;
+        }
     }
 
     public static class SalesforceLoginConfigNestedConfiguration {

http://git-wip-us.apache.org/repos/asf/camel/blob/b47de2b4/components/camel-salesforce/camel-salesforce-component/.gitignore
----------------------------------------------------------------------
diff --git a/components/camel-salesforce/camel-salesforce-component/.gitignore b/components/camel-salesforce/camel-salesforce-component/.gitignore
new file mode 100644
index 0000000..b79718e
--- /dev/null
+++ b/components/camel-salesforce/camel-salesforce-component/.gitignore
@@ -0,0 +1 @@
+/infinitest.filters

http://git-wip-us.apache.org/repos/asf/camel/blob/b47de2b4/components/camel-salesforce/camel-salesforce-component/pom.xml
----------------------------------------------------------------------
diff --git a/components/camel-salesforce/camel-salesforce-component/pom.xml b/components/camel-salesforce/camel-salesforce-component/pom.xml
index a97d1a1..58f65d2 100644
--- a/components/camel-salesforce/camel-salesforce-component/pom.xml
+++ b/components/camel-salesforce/camel-salesforce-component/pom.xml
@@ -157,6 +157,11 @@
       <version>${jetty9-version}</version>
       <scope>test</scope>
     </dependency>
+    <dependency>
+      <groupId>org.mockito</groupId>
+      <artifactId>mockito-core</artifactId>
+      <scope>test</scope>
+    </dependency>
   </dependencies>
 
   <build>

http://git-wip-us.apache.org/repos/asf/camel/blob/b47de2b4/components/camel-salesforce/camel-salesforce-component/src/main/docs/salesforce-component.adoc
----------------------------------------------------------------------
diff --git a/components/camel-salesforce/camel-salesforce-component/src/main/docs/salesforce-component.adoc b/components/camel-salesforce/camel-salesforce-component/src/main/docs/salesforce-component.adoc
index 089ca7c..53f0f81 100644
--- a/components/camel-salesforce/camel-salesforce-component/src/main/docs/salesforce-component.adoc
+++ b/components/camel-salesforce/camel-salesforce-component/src/main/docs/salesforce-component.adoc
@@ -69,6 +69,8 @@ results) using result link returned from the 'query' API
 * search - Runs a Salesforce SOSL query
 * limits - fetching organization API usage limits
 * recent - fetching recent items
+* approval - submit a record or records (batch) for approval process
+* approvals - fetch a list of all approval processes
 
 For example, the following producer endpoint uses the upsertSObject API,
 with the sObjectIdName parameter specifying 'Name' as the external id
@@ -217,6 +219,52 @@ from("direct:querySalesforce")
     .otherwise()
         .setBody(constant("Used up Salesforce API limits, leaving 10% for critical routes"))
     .endChoice()
+
+[[Salesforce-Approval]]
+Working with approvals
+^^^^^^^^^^^^^^^^^^^^^^
+
+All the properties are named exactly the same as in the Salesforce REST API prefixed with `approval.`. You can set
+approval properties by setting `approval.PropertyName` of the Endpoint these will be used as template -- meaning
+that any property not present in either body or header will be taken from the Endpoint configuration. Or you can set
+the approval template on the Endpoint by assigning `approval` property to a reference onto a bean in the Registry.
+
+You can also provide header values using the same `approval.PropertyName` in the incoming message headers.
+
+And finally body can contain one `AprovalRequest` or an `Iterable` of `ApprovalRequest` objects to process as
+a batch.
+
+The important thing to remember is the priority of the values specified in these three mechanisms:
+
+. value in body takes precedence before any other
+. value in message header takes precedence before template value
+. value in template is set if no other value in header or body was given
+
+For example to send one record for approval using values in headers use:
+
+Given a route:
+
+[source,java]
+-----------------------------------------------------------------------------------------------------
+from("direct:example1")//
+        .setHeader("approval.ContextId", simple("${body['contextId']}"))
+        .setHeader("approval.NextApproverIds", simple("${body['nextApproverIds']}"))
+        .to("salesforce:approval?"//
+            + "approval.actionType=Submit"//
+            + "&approval.comments=this is a test"//
+            + "&approval.processDefinitionNameOrId=Test_Account_Process"//
+            + "&approval.skipEntryCriteria=true");
+-----------------------------------------------------------------------------------------------------
+
+You could send a record for approval using:
+
+[source,java]
+-----------------------------------------------------------------------------------------------------
+final Map<String, String> body = new HashMap<>();
+body.put("contextId", accountIds.iterator().next());
+body.put("nextApproverIds", userId);
+
+final ApprovalResult result = template.requestBody("direct:example1", body, ApprovalResult.class);
 -----------------------------------------------------------------------------------------------------
 
 [[Salesforce-RecentItems]]
@@ -236,6 +284,52 @@ from("direct:fetchRecentItems")
             .log("${body.name} at ${body.attributes.url}");
 -----------------------------------------------------------------------------------------------------
 
+Working with approvals
+^^^^^^^^^^^^^^^^^^^^^^
+
+All the properties are named exactly the same as in the Salesforce REST API prefixed with `approval.`. You can set
+approval properties by setting `approval.PropertyName` of the Endpoint these will be used as template -- meaning
+that any property not present in either body or header will be taken from the Endpoint configuration. Or you can set
+the approval template on the Endpoint by assigning `approval` property to a reference onto a bean in the Registry.
+
+You can also provide header values using the same `approval.PropertyName` in the incoming message headers.
+
+And finally body can contain one `AprovalRequest` or an `Iterable` of `ApprovalRequest` objects to process as
+a batch.
+
+The important thing to remember is the priority of the values specified in these three mechanisms:
+
+. value in body takes precedence before any other
+. value in message header takes precedence before template value
+. value in template is set if no other value in header or body was given
+
+For example to send one record for approval using values in headers use:
+
+Given a route:
+
+[source,java]
+-----------------------------------------------------------------------------------------------------
+from("direct:example1")//
+        .setHeader("approval.ContextId", simple("${body['contextId']}"))
+        .setHeader("approval.NextApproverIds", simple("${body['nextApproverIds']}"))
+        .to("salesforce:approval?"//
+            + "approvalActionType=Submit"//
+            + "&approvalComments=this is a test"//
+            + "&approvalProcessDefinitionNameOrId=Test_Account_Process"//
+            + "&approvalSkipEntryCriteria=true");
+-----------------------------------------------------------------------------------------------------
+
+You could send a record for approval using:
+
+[source,java]
+-----------------------------------------------------------------------------------------------------
+final Map<String, String> body = new HashMap<>();
+body.put("contextId", accountIds.iterator().next());
+body.put("nextApproverIds", userId);
+
+final ApprovalResult result = template.requestBody("direct:example1", body, ApprovalResult.class);
+-----------------------------------------------------------------------------------------------------
+
 [[Salesforce-CamelSalesforceMavenPlugin]]
 Camel Salesforce Maven Plugin
 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
@@ -354,7 +448,7 @@ be executed using the following command:
 
 [source,java]
 ---------------------------------------------------------------------------------------------------------------------------------
-    mvn camel-salesforce:generate -DcamelSalesforce.clientId=<clientid> -DcamelSalesforce.clientSecret=<clientsecret> \
+mvn camel-salesforce:generate -DcamelSalesforce.clientId=<clientid> -DcamelSalesforce.clientSecret=<clientsecret> \
     -DcamelSalesforce.userName=<username> -DcamelSalesforce.password=<password>
 ---------------------------------------------------------------------------------------------------------------------------------
 

http://git-wip-us.apache.org/repos/asf/camel/blob/b47de2b4/components/camel-salesforce/camel-salesforce-component/src/main/java/org/apache/camel/component/salesforce/SalesforceComponent.java
----------------------------------------------------------------------
diff --git a/components/camel-salesforce/camel-salesforce-component/src/main/java/org/apache/camel/component/salesforce/SalesforceComponent.java b/components/camel-salesforce/camel-salesforce-component/src/main/java/org/apache/camel/component/salesforce/SalesforceComponent.java
index 61357ea..806a642 100644
--- a/components/camel-salesforce/camel-salesforce-component/src/main/java/org/apache/camel/component/salesforce/SalesforceComponent.java
+++ b/components/camel-salesforce/camel-salesforce-component/src/main/java/org/apache/camel/component/salesforce/SalesforceComponent.java
@@ -34,6 +34,7 @@ import org.apache.camel.Endpoint;
 import org.apache.camel.component.salesforce.api.SalesforceException;
 import org.apache.camel.component.salesforce.api.dto.AbstractQueryRecordsBase;
 import org.apache.camel.component.salesforce.api.dto.AbstractSObjectBase;
+import org.apache.camel.component.salesforce.api.dto.approval.ApprovalRequest;
 import org.apache.camel.component.salesforce.internal.OperationName;
 import org.apache.camel.component.salesforce.internal.SalesforceSession;
 import org.apache.camel.component.salesforce.internal.streaming.SubscriptionHelper;

http://git-wip-us.apache.org/repos/asf/camel/blob/b47de2b4/components/camel-salesforce/camel-salesforce-component/src/main/java/org/apache/camel/component/salesforce/SalesforceEndpointConfig.java
----------------------------------------------------------------------
diff --git a/components/camel-salesforce/camel-salesforce-component/src/main/java/org/apache/camel/component/salesforce/SalesforceEndpointConfig.java b/components/camel-salesforce/camel-salesforce-component/src/main/java/org/apache/camel/component/salesforce/SalesforceEndpointConfig.java
index 3d59a19..51556f2 100644
--- a/components/camel-salesforce/camel-salesforce-component/src/main/java/org/apache/camel/component/salesforce/SalesforceEndpointConfig.java
+++ b/components/camel-salesforce/camel-salesforce-component/src/main/java/org/apache/camel/component/salesforce/SalesforceEndpointConfig.java
@@ -16,18 +16,23 @@
  */
 package org.apache.camel.component.salesforce;
 
+import java.util.ArrayList;
 import java.util.Collections;
 import java.util.HashMap;
+import java.util.List;
 import java.util.Map;
 
 import com.fasterxml.jackson.databind.ObjectMapper;
 
 import org.apache.camel.RuntimeCamelException;
 import org.apache.camel.component.salesforce.api.dto.analytics.reports.ReportMetadata;
+import org.apache.camel.component.salesforce.api.dto.approval.ApprovalRequest;
+import org.apache.camel.component.salesforce.api.dto.approval.ApprovalRequest.Action;
 import org.apache.camel.component.salesforce.api.dto.bulk.ContentType;
 import org.apache.camel.component.salesforce.internal.PayloadFormat;
 import org.apache.camel.component.salesforce.internal.dto.NotifyForFieldsEnum;
 import org.apache.camel.component.salesforce.internal.dto.NotifyForOperationsEnum;
+import org.apache.camel.spi.Metadata;
 import org.apache.camel.spi.UriParam;
 import org.apache.camel.spi.UriParams;
 
@@ -66,7 +71,7 @@ public class SalesforceEndpointConfig implements Cloneable {
     public static final String JOB_ID = "jobId";
     public static final String BATCH_ID = "batchId";
     public static final String RESULT_ID = "resultId";
-    
+
     // parameters for Analytics API
     public static final String REPORT_ID = "reportId";
     public static final String INCLUDE_DETAILS = "includeDetails";
@@ -77,6 +82,9 @@ public class SalesforceEndpointConfig implements Cloneable {
     public static final String DEFAULT_REPLAY_ID = "defaultReplayId";
     public static final String INITIAL_REPLAY_ID_MAP = "initialReplayIdMap";
 
+    // parameters for Approval API
+    public static final String APPROVAL = "approval";
+
     // default maximum authentication retries on failed authentication or expired session
     public static final int DEFAULT_MAX_AUTHENTICATION_RETRIES = 4;
 
@@ -141,7 +149,7 @@ public class SalesforceEndpointConfig implements Cloneable {
     private Boolean notifyForOperationDelete;
     @UriParam
     private Boolean notifyForOperationUndelete;
-    
+
     // Analytics API properties
     @UriParam
     private String reportId;
@@ -158,6 +166,9 @@ public class SalesforceEndpointConfig implements Cloneable {
     @UriParam
     private Map<String, Integer> initialReplayIdMap;
 
+    // Approval API properties
+    private ApprovalRequest approval;
+
     // Salesforce Jetty9 HttpClient, set using reference
     @UriParam
     private SalesforceHttpClient httpClient;
@@ -341,6 +352,19 @@ public class SalesforceEndpointConfig implements Cloneable {
         this.apexQueryParams = apexQueryParams;
     }
 
+    public ApprovalRequest getApproval() {
+        return approval;
+    }
+
+    /**
+     * The approval request for Approval API.
+     *
+     * @param approval
+     */
+    public void setApproval(final ApprovalRequest approval) {
+        this.approval = approval;
+    }
+
     public ContentType getContentType() {
         return contentType;
     }
@@ -568,6 +592,7 @@ public class SalesforceEndpointConfig implements Cloneable {
         valueMap.put(APEX_METHOD, apexMethod);
         valueMap.put(APEX_URL, apexUrl);
         valueMap.put(LIMIT, limit);
+        valueMap.put(APPROVAL, approval);
         // apexQueryParams are handled explicitly in AbstractRestProcessor
 
         // add bulk API properties
@@ -597,6 +622,7 @@ public class SalesforceEndpointConfig implements Cloneable {
 
     /**
      * Default replayId setting if no value is found in {@link #initialReplayIdMap}
+     * 
      * @param defaultReplayId
      */
     public void setDefaultReplayId(Integer defaultReplayId) {
@@ -620,9 +646,173 @@ public class SalesforceEndpointConfig implements Cloneable {
 
     /**
      * Limit on number of returned records. Applicable to some of the API, check the Salesforce documentation.
+     * 
      * @param limit
      */
     public void setLimit(final Integer limit) {
         this.limit = limit;
     }
+
+    public Action getApprovalActionType() {
+        if (approval == null) {
+            return null;
+        }
+
+        return approval.getActionType();
+    }
+
+    public String getApprovalComments() {
+        if (approval == null) {
+            return null;
+        }
+
+        return approval.getComments();
+    }
+
+    public String getApprovalContextActorId() {
+        if (approval == null) {
+            return null;
+        }
+
+        return approval.getContextActorId();
+    }
+
+    public String getApprovalContextId() {
+        if (approval == null) {
+            return null;
+        }
+
+        return approval.getContextId();
+    }
+
+    public List<String> getApprovalNextApproverIds() {
+        if (approval == null) {
+            return null;
+        }
+
+        return approval.getNextApproverIds();
+    }
+
+    public String getApprovalProcessDefinitionNameOrId() {
+        if (approval == null) {
+            return null;
+        }
+
+        return approval.getProcessDefinitionNameOrId();
+    }
+
+    public boolean isApprovalSkipEntryCriteria() {
+        if (approval == null) {
+            return false;
+        }
+
+        return approval.isSkipEntryCriteria();
+    }
+
+    /**
+     * Represents the kind of action to take: Submit, Approve, or Reject.
+     *
+     * @param actionType
+     */
+    public void setApprovalActionType(final Action actionType) {
+        if (approval == null) {
+            approval = new ApprovalRequest();
+        }
+
+        approval.setActionType(actionType);
+    }
+
+    /**
+     * The comment to add to the history step associated with this request.
+     *
+     * @param comments
+     */
+    public void setApprovalComments(final String comments) {
+        if (approval == null) {
+            approval = new ApprovalRequest();
+        }
+
+        approval.setComments(comments);
+    }
+
+    /**
+     * The ID of the submitter who\u2019s requesting the approval record. 
+     *
+     * @param contextActorId
+     */
+    public void setApprovalContextActorId(final String contextActorId) {
+        if (approval == null) {
+            approval = new ApprovalRequest();
+        }
+
+        approval.setContextActorId(contextActorId);
+    }
+
+    /**
+     * The ID of the item that is being acted upon.
+     *
+     * @param contextId
+     */
+    public void setApprovalContextId(final String contextId) {
+        if (approval == null) {
+            approval = new ApprovalRequest();
+        }
+
+        approval.setContextId(contextId);
+    }
+
+    /**
+     * If the process requires specification of the next approval, the ID of the user to be assigned the next request.
+     *
+     * @param nextApproverIds
+     */
+    public void setApprovalNextApproverIds(final List<String> nextApproverIds) {
+        if (approval == null) {
+            approval = new ApprovalRequest();
+        }
+
+        approval.setNextApproverIds(nextApproverIds);
+    }
+
+    /**
+     * If the process requires specification of the next approval, the ID of the user to be assigned the next request.
+     *
+     * @param nextApproverIds
+     */
+    public void setApprovalNextApproverIds(String nextApproverId) {
+        if (approval == null) {
+            approval = new ApprovalRequest();
+        }
+
+        approval.setNextApproverIds(nextApproverId);
+    }
+
+    /**
+     * The developer name or ID of the process definition.
+     *
+     * @param processDefinitionNameOrId
+     */
+    public void setApprovalProcessDefinitionNameOrId(final String processDefinitionNameOrId) {
+        if (approval == null) {
+            approval = new ApprovalRequest();
+        }
+
+        approval.setProcessDefinitionNameOrId(processDefinitionNameOrId);
+    }
+
+    /**
+     * Determines whether to evaluate the entry criteria for the process (true) or not (false) if the process definition
+     * name or ID isn\u2019t null. If the process definition name or ID isn\u2019t specified, this argument is ignored, and 
+     * standard evaluation is followed based on process order. By default, the entry criteria isn\u2019t skipped if it\u2019s not
+     * set by this request.
+     *
+     * @param skipEntryCriteria
+     */
+    public void setApprovalSkipEntryCriteria(final boolean skipEntryCriteria) {
+        if (approval == null) {
+            approval = new ApprovalRequest();
+        }
+
+        approval.setSkipEntryCriteria(skipEntryCriteria);
+    }
 }

http://git-wip-us.apache.org/repos/asf/camel/blob/b47de2b4/components/camel-salesforce/camel-salesforce-component/src/main/java/org/apache/camel/component/salesforce/api/dto/approval/ApprovalRequest.java
----------------------------------------------------------------------
diff --git a/components/camel-salesforce/camel-salesforce-component/src/main/java/org/apache/camel/component/salesforce/api/dto/approval/ApprovalRequest.java b/components/camel-salesforce/camel-salesforce-component/src/main/java/org/apache/camel/component/salesforce/api/dto/approval/ApprovalRequest.java
new file mode 100644
index 0000000..e4b24e5
--- /dev/null
+++ b/components/camel-salesforce/camel-salesforce-component/src/main/java/org/apache/camel/component/salesforce/api/dto/approval/ApprovalRequest.java
@@ -0,0 +1,247 @@
+/**
+ * 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.salesforce.api.dto.approval;
+
+import java.io.Serializable;
+import java.lang.reflect.Field;
+import java.lang.reflect.Modifier;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.List;
+import java.util.Objects;
+import java.util.Optional;
+import java.util.stream.Collectors;
+
+import com.thoughtworks.xstream.annotations.XStreamAlias;
+import com.thoughtworks.xstream.annotations.XStreamImplicit;
+
+import org.apache.camel.spi.Metadata;
+import org.apache.camel.spi.UriParam;
+import org.apache.camel.spi.UriParams;
+import org.apache.camel.spi.UriPath;
+
+/**
+ * Represents approval request sent to submit, approve or reject record.
+ *
+ * @see <a href=
+ *      "https://developer.salesforce.com/docs/atlas.en-us.api_rest.meta/api_rest/resources_process_approvals.htm">
+ *      https://developer.salesforce.com/docs/atlas.en-us.api_rest.meta/api_rest/resources_process_approvals.htm</a>
+ */
+@UriParams
+@XStreamAlias("requests")
+public final class ApprovalRequest implements Serializable {
+
+    public enum Action {
+        Submit, Approve, Reject
+    }
+
+    /**
+     * Lazy holder of fields defined in {@link ApprovalRequest}.
+     */
+    private static final class FieldHolder {
+        public static final FieldHolder INSTANCE = new FieldHolder();
+
+        public final List<Field> fields;
+
+        private FieldHolder() {
+            fields = Arrays.stream(ApprovalRequest.class.getDeclaredFields())
+                    .filter(f -> !Modifier.isFinal(f.getModifiers())).collect(Collectors.toList());
+        }
+    }
+
+    /**
+     *
+     */
+    private static final long serialVersionUID = 1L;
+
+    @UriParam
+    @Metadata(required = "true")
+    private Action actionType;
+
+    @UriParam
+    @Metadata(required = "true")
+    private String contextActorId;
+
+    @UriParam
+    @Metadata(required = "true")
+    private String contextId;
+
+    @UriParam
+    private String comments;
+
+    @UriParam
+    @Metadata(required = "true")
+    @XStreamImplicit(itemFieldName = "nextApproverIds")
+    private List<String> nextApproverIds;
+
+    @UriParam
+    @Metadata(required = "true")
+    private String processDefinitionNameOrId;
+
+    @UriParam
+    private boolean skipEntryCriteria;
+
+    public void addNextApproverId(final String nextApproverId) {
+        nextApproverIds = Optional.ofNullable(nextApproverIds).orElse(new ArrayList<>());
+        nextApproverIds.add(nextApproverId);
+    }
+
+    /**
+     * Creates new {@link ApprovalRequest} by combining values from the given template with the values currently
+     * present. If the value is not present and the template has the corresponding value, then the template value is
+     * set. The net result is that all set values of an {@link ApprovalRequest} are preserved, while the values set on
+     * template are used for undefined ( <code>null</code>) values.
+     *
+     * @param template
+     *            template to apply
+     * @return newly created object with applied template
+     */
+    public ApprovalRequest applyTemplate(final ApprovalRequest template) {
+        if (template == null) {
+            return this;
+        }
+
+        final ApprovalRequest withTemplateValues = new ApprovalRequest();
+
+        for (final Field field : FieldHolder.INSTANCE.fields) {
+            try {
+                final Object currentValue = field.get(this);
+
+                // if a field has not been set, and the template has it set use
+                // the template value
+                if (currentValue == null) {
+                    final Object templateValue = field.get(template);
+
+                    if (templateValue != null) {
+                        field.set(withTemplateValues, templateValue);
+                    }
+                } else {
+                    field.set(withTemplateValues, currentValue);
+                }
+            } catch (IllegalArgumentException | IllegalAccessException e) {
+                throw new IllegalStateException("Unable to apply values from template", e);
+            }
+        }
+
+        return withTemplateValues;
+    }
+
+    @Override
+    public boolean equals(final Object obj) {
+        if (obj == this) {
+            return true;
+        }
+
+        if (!(obj instanceof ApprovalRequest)) {
+            return false;
+        }
+
+        final ApprovalRequest other = (ApprovalRequest) obj;
+
+        return Objects.equals(actionType, other.actionType) && Objects.equals(contextActorId, other.contextActorId)
+            && Objects.equals(contextId, other.contextId) && Objects.equals(comments, other.comments)
+            && Objects.equals(nextApproverIds, other.nextApproverIds)
+            && Objects.equals(processDefinitionNameOrId, other.processDefinitionNameOrId)
+            && Objects.equals(skipEntryCriteria, other.skipEntryCriteria);
+    }
+
+    public Action getActionType() {
+        return actionType;
+    }
+
+    public String getComments() {
+        return comments;
+    }
+
+    public String getContextActorId() {
+        return contextActorId;
+    }
+
+    public String getContextId() {
+        return contextId;
+    }
+
+    public List<String> getNextApproverIds() {
+        return listFromNullable(nextApproverIds);
+    }
+
+    public String getProcessDefinitionNameOrId() {
+        return processDefinitionNameOrId;
+    }
+
+    @Override
+    public int hashCode() {
+        return Arrays.hashCode(new Object[] {actionType, contextActorId, contextId, comments, nextApproverIds,
+            processDefinitionNameOrId, skipEntryCriteria});
+    }
+
+    public boolean isSkipEntryCriteria() {
+        return skipEntryCriteria;
+    }
+
+    public void setActionType(final Action actionType) {
+        this.actionType = actionType;
+    }
+
+    public void setComments(final String comments) {
+        this.comments = comments;
+    }
+
+    public void setContextActorId(final String contextActorId) {
+        this.contextActorId = contextActorId;
+    }
+
+    public void setContextId(final String contextId) {
+        this.contextId = contextId;
+    }
+
+    public void setNextApproverIds(final List<String> nextApproverIds) {
+        this.nextApproverIds = new ArrayList<>(listFromNullable(nextApproverIds));
+    }
+
+    public void setNextApproverIds(final String nextApproverId) {
+        // set single approver id
+        this.nextApproverIds = Collections.singletonList(nextApproverId);
+    }
+
+    public void setProcessDefinitionNameOrId(final String processDefinitionNameOrId) {
+        this.processDefinitionNameOrId = processDefinitionNameOrId;
+    }
+
+    public void setSkipEntryCriteria(final boolean skipEntryCriteria) {
+        this.skipEntryCriteria = skipEntryCriteria;
+    }
+
+    @Override
+    public String toString() {
+        final StringBuilder buildy = new StringBuilder("ApprovalRequest: ");
+        buildy.append("actionType: ").append(actionType);
+        buildy.append(", contextActorId: ").append(contextActorId);
+        buildy.append(", contextId: ").append(contextId);
+        buildy.append(", comments: ").append(comments);
+        buildy.append(", nextApproverIds: ").append(nextApproverIds);
+        buildy.append(", processDefinitionNameOrId: ").append(processDefinitionNameOrId);
+        buildy.append(", skipEntryCriteria: ").append(skipEntryCriteria);
+
+        return buildy.toString();
+    }
+
+    private List<String> listFromNullable(final List<String> nullable) {
+        return Optional.ofNullable(nullable).orElse(Collections.emptyList());
+    }
+}

http://git-wip-us.apache.org/repos/asf/camel/blob/b47de2b4/components/camel-salesforce/camel-salesforce-component/src/main/java/org/apache/camel/component/salesforce/api/dto/approval/ApprovalRequests.java
----------------------------------------------------------------------
diff --git a/components/camel-salesforce/camel-salesforce-component/src/main/java/org/apache/camel/component/salesforce/api/dto/approval/ApprovalRequests.java b/components/camel-salesforce/camel-salesforce-component/src/main/java/org/apache/camel/component/salesforce/api/dto/approval/ApprovalRequests.java
new file mode 100644
index 0000000..e8ca701
--- /dev/null
+++ b/components/camel-salesforce/camel-salesforce-component/src/main/java/org/apache/camel/component/salesforce/api/dto/approval/ApprovalRequests.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.salesforce.api.dto.approval;
+
+import java.io.Serializable;
+import java.util.Collections;
+import java.util.List;
+
+import com.thoughtworks.xstream.annotations.XStreamAlias;
+import com.thoughtworks.xstream.annotations.XStreamImplicit;
+
+@XStreamAlias("ProcessApprovalRequest")
+public final class ApprovalRequests implements Serializable {
+
+    private static final long serialVersionUID = 1L;
+
+    @XStreamImplicit
+    private final List<ApprovalRequest> requests;
+
+    public ApprovalRequests(final ApprovalRequest singleRequest) {
+        this(Collections.singletonList(singleRequest));
+    }
+
+    public ApprovalRequests(final List<ApprovalRequest> requests) {
+        this.requests = requests;
+    }
+
+    @Override
+    public boolean equals(final Object obj) {
+        if (obj == this) {
+            return true;
+        }
+
+        if (!(obj instanceof ApprovalRequests)) {
+            return false;
+        }
+
+        return ((ApprovalRequests) obj).requests.equals(requests);
+    }
+
+    public List<ApprovalRequest> getRequests() {
+        return requests;
+    }
+
+    @Override
+    public int hashCode() {
+        return requests.hashCode();
+    }
+
+    @Override
+    public String toString() {
+        return requests.toString();
+    }
+}

http://git-wip-us.apache.org/repos/asf/camel/blob/b47de2b4/components/camel-salesforce/camel-salesforce-component/src/main/java/org/apache/camel/component/salesforce/api/dto/approval/ApprovalResult.java
----------------------------------------------------------------------
diff --git a/components/camel-salesforce/camel-salesforce-component/src/main/java/org/apache/camel/component/salesforce/api/dto/approval/ApprovalResult.java b/components/camel-salesforce/camel-salesforce-component/src/main/java/org/apache/camel/component/salesforce/api/dto/approval/ApprovalResult.java
new file mode 100644
index 0000000..3d719b5
--- /dev/null
+++ b/components/camel-salesforce/camel-salesforce-component/src/main/java/org/apache/camel/component/salesforce/api/dto/approval/ApprovalResult.java
@@ -0,0 +1,148 @@
+/**
+ * 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.salesforce.api.dto.approval;
+
+import java.io.IOException;
+import java.io.Serializable;
+import java.util.ArrayList;
+import java.util.Iterator;
+import java.util.List;
+
+import com.fasterxml.jackson.annotation.JsonCreator;
+import com.fasterxml.jackson.annotation.JsonProperty;
+import com.fasterxml.jackson.core.JsonParser;
+import com.fasterxml.jackson.core.JsonProcessingException;
+import com.fasterxml.jackson.core.type.TypeReference;
+import com.fasterxml.jackson.databind.DeserializationContext;
+import com.fasterxml.jackson.databind.JsonDeserializer;
+import com.fasterxml.jackson.databind.annotation.JsonDeserialize;
+import com.thoughtworks.xstream.annotations.XStreamAlias;
+import com.thoughtworks.xstream.annotations.XStreamImplicit;
+
+import org.apache.camel.component.salesforce.api.dto.RestError;
+import org.apache.camel.component.salesforce.api.dto.approval.ApprovalResult.ApprovalResultDeserializer;
+import org.apache.camel.component.salesforce.api.dto.approval.ApprovalResult.Result;
+
+@XStreamAlias("ProcessApprovalResult")
+@JsonDeserialize(using = ApprovalResultDeserializer.class)
+public final class ApprovalResult implements Serializable, Iterable<Result> {
+
+    public static final class ApprovalResultDeserializer extends JsonDeserializer {
+
+        private static final TypeReference<List<Result>> RESULTS_TYPE = new TypeReference<List<Result>>() {
+        };
+
+        @Override
+        public Object deserialize(final JsonParser parser, final DeserializationContext context)
+                throws IOException, JsonProcessingException {
+            final List<Result> results = parser.readValueAs(RESULTS_TYPE);
+
+            return new ApprovalResult(results);
+        }
+
+    }
+
+    @XStreamAlias("ProcessApprovalResult")
+    public static final class Result implements Serializable {
+
+        private static final long serialVersionUID = 1L;
+
+        @XStreamImplicit(itemFieldName = "actorIds")
+        private final List<String> actorIds;
+
+        private final String entityId;
+
+        @XStreamImplicit(itemFieldName = "errors")
+        private final List<RestError> errors;
+
+        private final String instanceId;
+
+        private final String instanceStatus;
+
+        @XStreamImplicit(itemFieldName = "newWorkitemIds")
+        private final List<String> newWorkitemIds;
+
+        private final boolean success;
+
+        @JsonCreator
+        Result(@JsonProperty("actorIds") final List<String> actorIds, @JsonProperty("entityId") final String entityId,
+                @JsonProperty("errors") final List<RestError> errors,
+                @JsonProperty("instanceId") final String instanceId,
+                @JsonProperty("instanceStatus") final String instanceStatus,
+                @JsonProperty("newWorkitemIds") final List<String> newWorkitemIds,
+                @JsonProperty("success") final boolean success) {
+            this.actorIds = actorIds;
+            this.entityId = entityId;
+            this.errors = errors;
+            this.instanceId = instanceId;
+            this.instanceStatus = instanceStatus;
+            this.newWorkitemIds = newWorkitemIds;
+            this.success = success;
+        }
+
+        public List<String> getActorIds() {
+            return actorIds;
+        }
+
+        public String getEntityId() {
+            return entityId;
+        }
+
+        public List<RestError> getErrors() {
+            return errors;
+        }
+
+        public String getInstanceId() {
+            return instanceId;
+        }
+
+        public String getInstanceStatus() {
+            return instanceStatus;
+        }
+
+        public List<String> getNewWorkitemIds() {
+            return newWorkitemIds;
+        }
+
+        public boolean isSuccess() {
+            return success;
+        }
+
+    }
+
+    private static final long serialVersionUID = 1L;
+
+    @XStreamImplicit(itemFieldName = "ProcessApprovalResult")
+    private final List<Result> results;
+
+    public ApprovalResult() {
+        this(new ArrayList<>());
+    }
+
+    private ApprovalResult(final List<Result> results) {
+        this.results = results;
+    }
+
+    @Override
+    public Iterator<Result> iterator() {
+        return results.listIterator();
+    }
+
+    public int size() {
+        return results.size();
+    }
+}

http://git-wip-us.apache.org/repos/asf/camel/blob/b47de2b4/components/camel-salesforce/camel-salesforce-component/src/main/java/org/apache/camel/component/salesforce/api/dto/approval/Approvals.java
----------------------------------------------------------------------
diff --git a/components/camel-salesforce/camel-salesforce-component/src/main/java/org/apache/camel/component/salesforce/api/dto/approval/Approvals.java b/components/camel-salesforce/camel-salesforce-component/src/main/java/org/apache/camel/component/salesforce/api/dto/approval/Approvals.java
new file mode 100644
index 0000000..9b908a8
--- /dev/null
+++ b/components/camel-salesforce/camel-salesforce-component/src/main/java/org/apache/camel/component/salesforce/api/dto/approval/Approvals.java
@@ -0,0 +1,142 @@
+/**
+ * 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.salesforce.api.dto.approval;
+
+import java.io.Serializable;
+import java.util.Collections;
+import java.util.List;
+import java.util.Map;
+import java.util.Optional;
+
+import com.fasterxml.jackson.annotation.JsonCreator;
+import com.fasterxml.jackson.annotation.JsonProperty;
+
+/**
+ * Holds approvals resource data.
+ *
+ * @see <a href="https://developer.salesforce.com/docs/atlas.en-us.api_rest.meta/api_rest/dome_process_approvals.htm">
+ *      https://developer.salesforce.com/docs/atlas.en-us.api_rest.meta/api_rest/dome_process_approvals.htm</a>
+ */
+public final class Approvals implements Serializable {
+
+    /**
+     * Information about approval tied to specific Salesforce object.
+     */
+    public static final class Info implements Serializable {
+
+        private static final long serialVersionUID = 1L;
+
+        private final String description;
+
+        private final String id;
+
+        private final String name;
+
+        private final String object;
+
+        private final int sortOrder;
+
+        @JsonCreator
+        Info(@JsonProperty("id") final String id, @JsonProperty("description") final String description,
+                @JsonProperty("name") final String name, @JsonProperty("object") final String object,
+                @JsonProperty("sortOrder") final int sortOrder) {
+            this.description = description;
+            this.id = id;
+            this.name = name;
+            this.object = object;
+            this.sortOrder = sortOrder;
+        }
+
+        public String getDescription() {
+            return description;
+        }
+
+        public String getId() {
+            return id;
+        }
+
+        public String getName() {
+            return name;
+        }
+
+        public String getObject() {
+            return object;
+        }
+
+        public int getSortOrder() {
+            return sortOrder;
+        }
+
+        @Override
+        public String toString() {
+            final StringBuilder buildy = new StringBuilder();
+
+            buildy.append("Id: ").append(id);
+
+            buildy.append(", Name: ").append(name);
+
+            buildy.append(", Object: ").append(object);
+
+            buildy.append(", Description: ").append(description);
+
+            buildy.append(", SortOrder: ").append(sortOrder);
+
+            return buildy.toString();
+        }
+    }
+
+    private static final long serialVersionUID = 1L;
+
+    private final Map<String, List<Info>> approvals;
+
+    @JsonCreator
+    Approvals(@JsonProperty("approvals") final Map<String, List<Info>> approvals) {
+        this.approvals = Optional.ofNullable(approvals).orElse(Collections.emptyMap());
+    }
+
+    /**
+     * Returns approvals for specific Salesforce object type.
+     *
+     * @param object
+     *            type
+     * @return approvals of specified type
+     */
+    public List<Info> approvalsFor(final String object) {
+        return approvals.getOrDefault(object, Collections.emptyList());
+    };
+
+    /**
+     * Returns approvals by Salesforce object type. You might have approvals for "Account" and "Case" Salesforce
+     * objects, then the resulting map would hold a list of {@link Info} objects keyed by the object type, i.e.:
+     *
+     * <pre>
+     * Approvals approvals = ...;
+     * List<Info> accountApprovals = approvals.getApprovals("Account");
+     * List<Info> caseApprovals = approvals.getApprovals("Case");
+     * </pre>
+     *
+     * @return approval info by object type
+     */
+    public Map<String, List<Info>> getApprovals() {
+        return approvals;
+    }
+
+    @Override
+    public String toString() {
+        return approvals.toString();
+    }
+}

http://git-wip-us.apache.org/repos/asf/camel/blob/b47de2b4/components/camel-salesforce/camel-salesforce-component/src/main/java/org/apache/camel/component/salesforce/internal/OperationName.java
----------------------------------------------------------------------
diff --git a/components/camel-salesforce/camel-salesforce-component/src/main/java/org/apache/camel/component/salesforce/internal/OperationName.java b/components/camel-salesforce/camel-salesforce-component/src/main/java/org/apache/camel/component/salesforce/internal/OperationName.java
index 7570374..b1ffeda 100644
--- a/components/camel-salesforce/camel-salesforce-component/src/main/java/org/apache/camel/component/salesforce/internal/OperationName.java
+++ b/components/camel-salesforce/camel-salesforce-component/src/main/java/org/apache/camel/component/salesforce/internal/OperationName.java
@@ -62,7 +62,11 @@ public enum OperationName {
     GET_REPORT_RESULTS("getReportResults"),
 
     // limits API
-    LIMITS("limits");
+    LIMITS("limits"),
+
+    // Approval Processes and Process Rules API
+    APPROVAL("approval"),
+    APPROVALS("approvals");
 
     private final String value;
 

http://git-wip-us.apache.org/repos/asf/camel/blob/b47de2b4/components/camel-salesforce/camel-salesforce-component/src/main/java/org/apache/camel/component/salesforce/internal/client/DefaultRestClient.java
----------------------------------------------------------------------
diff --git a/components/camel-salesforce/camel-salesforce-component/src/main/java/org/apache/camel/component/salesforce/internal/client/DefaultRestClient.java b/components/camel-salesforce/camel-salesforce-component/src/main/java/org/apache/camel/component/salesforce/internal/client/DefaultRestClient.java
index 6fee06d..71ab942 100644
--- a/components/camel-salesforce/camel-salesforce-component/src/main/java/org/apache/camel/component/salesforce/internal/client/DefaultRestClient.java
+++ b/components/camel-salesforce/camel-salesforce-component/src/main/java/org/apache/camel/component/salesforce/internal/client/DefaultRestClient.java
@@ -33,9 +33,11 @@ import org.apache.camel.component.salesforce.api.SalesforceException;
 import org.apache.camel.component.salesforce.api.SalesforceMultipleChoicesException;
 import org.apache.camel.component.salesforce.api.TypeReferences;
 import org.apache.camel.component.salesforce.api.dto.RestError;
+import org.apache.camel.component.salesforce.api.dto.approval.ApprovalRequest;
 import org.apache.camel.component.salesforce.api.utils.JsonUtils;
 import org.apache.camel.component.salesforce.internal.PayloadFormat;
 import org.apache.camel.component.salesforce.internal.SalesforceSession;
+import org.apache.camel.component.salesforce.internal.client.RestClient.ResponseCallback;
 import org.apache.camel.component.salesforce.internal.dto.RestChoices;
 import org.apache.camel.component.salesforce.internal.dto.RestErrors;
 import org.apache.camel.util.ObjectHelper;
@@ -138,6 +140,27 @@ public class DefaultRestClient extends AbstractClientBase implements RestClient
     }
 
     @Override
+    public void approval(final InputStream request, final ResponseCallback callback) {
+        final Request post = getRequest(HttpMethod.POST, versionUrl() + "process/approvals/");
+
+        // authorization
+        setAccessToken(post);
+
+        // input stream as entity content
+        post.content(new InputStreamContentProvider(request));
+        post.header(HttpHeader.CONTENT_TYPE, PayloadFormat.JSON.equals(format) ? APPLICATION_JSON_UTF8 : APPLICATION_XML_UTF8);
+
+        doHttpRequest(post, new DelegatingClientCallback(callback));
+    }
+
+    @Override
+    public void approvals(final ResponseCallback callback) {
+        final Request get = getRequest(HttpMethod.GET, versionUrl() + "process/approvals/");
+
+        doHttpRequest(get, new DelegatingClientCallback(callback));
+    }
+
+    @Override
     public void getVersions(final ResponseCallback callback) {
         Request get = getRequest(HttpMethod.GET, servicesDataUrl());
         // does not require authorization token

http://git-wip-us.apache.org/repos/asf/camel/blob/b47de2b4/components/camel-salesforce/camel-salesforce-component/src/main/java/org/apache/camel/component/salesforce/internal/client/RestClient.java
----------------------------------------------------------------------
diff --git a/components/camel-salesforce/camel-salesforce-component/src/main/java/org/apache/camel/component/salesforce/internal/client/RestClient.java b/components/camel-salesforce/camel-salesforce-component/src/main/java/org/apache/camel/component/salesforce/internal/client/RestClient.java
index 55764d0..d8bf761 100644
--- a/components/camel-salesforce/camel-salesforce-component/src/main/java/org/apache/camel/component/salesforce/internal/client/RestClient.java
+++ b/components/camel-salesforce/camel-salesforce-component/src/main/java/org/apache/camel/component/salesforce/internal/client/RestClient.java
@@ -20,6 +20,7 @@ import java.io.InputStream;
 import java.util.Map;
 
 import org.apache.camel.component.salesforce.api.SalesforceException;
+import org.apache.camel.component.salesforce.api.dto.approval.ApprovalRequest;
 
 public interface RestClient {
 
@@ -212,4 +213,20 @@ public interface RestClient {
      * @param responseCallback {@link ResponseCallback} to handle response or exception
      */
     void limits(ResponseCallback responseCallback);
+
+    /**
+     * Submits, approves or rejects particular record.
+     *
+     * @param callback
+     *            {@link ResponseCallback} to handle response or exception
+     */
+    void approval(InputStream request, ResponseCallback callback);
+
+    /**
+     * Returns a list of all approval processes.
+     *
+     * @param callback
+     *            {@link ResponseCallback} to handle response or exception
+     */
+    void approvals(ResponseCallback callback);
 }

http://git-wip-us.apache.org/repos/asf/camel/blob/b47de2b4/components/camel-salesforce/camel-salesforce-component/src/main/java/org/apache/camel/component/salesforce/internal/processor/AbstractRestProcessor.java
----------------------------------------------------------------------
diff --git a/components/camel-salesforce/camel-salesforce-component/src/main/java/org/apache/camel/component/salesforce/internal/processor/AbstractRestProcessor.java b/components/camel-salesforce/camel-salesforce-component/src/main/java/org/apache/camel/component/salesforce/internal/processor/AbstractRestProcessor.java
index 6636ada..7f4ccea 100644
--- a/components/camel-salesforce/camel-salesforce-component/src/main/java/org/apache/camel/component/salesforce/internal/processor/AbstractRestProcessor.java
+++ b/components/camel-salesforce/camel-salesforce-component/src/main/java/org/apache/camel/component/salesforce/internal/processor/AbstractRestProcessor.java
@@ -22,16 +22,24 @@ import java.lang.reflect.InvocationTargetException;
 import java.lang.reflect.Method;
 import java.net.URLEncoder;
 import java.util.HashMap;
+import java.util.List;
 import java.util.Map;
+import java.util.Optional;
 import java.util.regex.Matcher;
 import java.util.regex.Pattern;
+import java.util.stream.Collectors;
+import java.util.stream.StreamSupport;
 
 import org.apache.camel.AsyncCallback;
 import org.apache.camel.Exchange;
+import org.apache.camel.Message;
+import org.apache.camel.TypeConverter;
 import org.apache.camel.component.salesforce.SalesforceEndpoint;
 import org.apache.camel.component.salesforce.SalesforceEndpointConfig;
 import org.apache.camel.component.salesforce.api.SalesforceException;
 import org.apache.camel.component.salesforce.api.dto.AbstractSObjectBase;
+import org.apache.camel.component.salesforce.api.dto.approval.ApprovalRequest;
+import org.apache.camel.component.salesforce.api.dto.approval.ApprovalRequests;
 import org.apache.camel.component.salesforce.internal.PayloadFormat;
 import org.apache.camel.component.salesforce.internal.client.DefaultRestClient;
 import org.apache.camel.component.salesforce.internal.client.RestClient;
@@ -70,6 +78,14 @@ public abstract class AbstractRestProcessor extends AbstractSalesforceProcessor
         this.classMap = endpoint.getComponent().getClassMap();
     }
 
+    // used in unit tests
+    AbstractRestProcessor(final SalesforceEndpoint endpoint, final RestClient restClient,
+            final Map<String, Class<?>> classMap) {
+        super(endpoint);
+        this.restClient = restClient;
+        this.classMap = classMap;
+    }
+
     @Override
     public void start() throws Exception {
         ServiceHelper.startService(restClient);
@@ -159,6 +175,12 @@ public abstract class AbstractRestProcessor extends AbstractSalesforceProcessor
             case LIMITS:
                 processLimits(exchange, callback);
                 break;
+            case APPROVAL:
+                processApproval(exchange, callback);
+                break;
+            case APPROVALS:
+                processApprovals(exchange, callback);
+                break;
             default:
                 throw new SalesforceException("Unknown operation name: " + operationName.value(), null);
             }
@@ -182,6 +204,98 @@ public abstract class AbstractRestProcessor extends AbstractSalesforceProcessor
         return false;
     }
 
+    final void processApproval(final Exchange exchange, final AsyncCallback callback) throws SalesforceException {
+        final TypeConverter converter = exchange.getContext().getTypeConverter();
+
+        final ApprovalRequest approvalRequestFromHeader = getParameter(SalesforceEndpointConfig.APPROVAL, exchange,
+                IGNORE_BODY, IS_OPTIONAL, ApprovalRequest.class);
+        final boolean requestGivenInHeader = approvalRequestFromHeader != null;
+
+        // find if there is a ApprovalRequest as `approval` in the message header
+        final ApprovalRequest approvalHeader = Optional.ofNullable(approvalRequestFromHeader)
+                .orElse(new ApprovalRequest());
+
+        final Message incomingMessage = exchange.getIn();
+
+        final Map<String, Object> incomingHeaders = incomingMessage.getHeaders();
+
+        final boolean requestGivenInParametersInHeader = processApprovalHeaderValues(approvalHeader, incomingHeaders);
+
+        final boolean nothingInheader = !requestGivenInHeader && !requestGivenInParametersInHeader;
+
+        final Object approvalBody = incomingMessage.getBody();
+
+        final boolean bodyIsIterable = approvalBody instanceof Iterable;
+        final boolean bodyIsIterableButEmpty = bodyIsIterable && !((Iterable) approvalBody).iterator().hasNext();
+
+        // body contains nothing of interest if it's null, holds an empty iterable or cannot be converted to
+        // ApprovalRequest
+        final boolean nothingInBody = !(approvalBody != null && !bodyIsIterableButEmpty);
+
+        // we found nothing in the headers or the body
+        if (nothingInheader && nothingInBody) {
+            throw new SalesforceException("Missing " + SalesforceEndpointConfig.APPROVAL
+                + " parameter in header or ApprovalRequest or List of ApprovalRequests body", 0);
+        }
+
+        // let's try to resolve the request body to send
+        final ApprovalRequests requestsBody;
+        if (nothingInBody) {
+            // nothing in body use the header values only
+            requestsBody = new ApprovalRequests(approvalHeader);
+        } else if (bodyIsIterable) {
+            // multiple ApprovalRequests are found
+            final Iterable<?> approvalRequests = (Iterable<?>) approvalBody;
+
+            // use header values as template and apply them to the body
+            final List<ApprovalRequest> requests = StreamSupport.stream(approvalRequests.spliterator(), false)
+                    .map(value -> converter.convertTo(ApprovalRequest.class, value))
+                    .map(request -> request.applyTemplate(approvalHeader)).collect(Collectors.toList());
+
+            requestsBody = new ApprovalRequests(requests);
+        } else {
+            // we've looked at the body, and are expecting to see something resembling ApprovalRequest in there
+            // but lets see if that is so
+            final ApprovalRequest given = converter.tryConvertTo(ApprovalRequest.class, approvalBody);
+
+            final ApprovalRequest request = Optional.ofNullable(given).orElse(new ApprovalRequest())
+                    .applyTemplate(approvalHeader);
+
+            requestsBody = new ApprovalRequests(request);
+        }
+
+        final InputStream request = getRequestStream(requestsBody);
+
+        restClient.approval(request, (response, exception) -> processResponse(exchange, response, exception, callback));
+    }
+
+    final boolean processApprovalHeaderValues(final ApprovalRequest approvalRequest,
+            final Map<String, Object> incomingHeaderValues) {
+        // loop trough all header values, find those that start with `approval.`
+        // set the property value to the given approvalRequest and return if
+        // any value was set
+        return incomingHeaderValues.entrySet().stream().filter(kv -> kv.getKey().startsWith("approval.")).map(kv -> {
+            final String property = kv.getKey().substring(9);
+            Object value = kv.getValue();
+
+            if (value != null) {
+                try {
+                    setPropertyValue(approvalRequest, property, value);
+
+                    return true;
+                } catch (SalesforceException e) {
+                    throw new IllegalArgumentException(e);
+                }
+            }
+
+            return false;
+        }).reduce(false, (a, b) -> a || b);
+    }
+
+    private void processApprovals(final Exchange exchange, final AsyncCallback callback) {
+        restClient.approvals((response, exception) -> processResponse(exchange, response, exception, callback));
+    }
+
     private void processGetVersions(final Exchange exchange, final AsyncCallback callback) {
         restClient.getVersions(new RestClient.ResponseCallback() {
             @Override
@@ -620,7 +734,7 @@ public abstract class AbstractRestProcessor extends AbstractSalesforceProcessor
         }
     }
 
-    private void setPropertyValue(AbstractSObjectBase sObjectBase, String name, Object value) throws SalesforceException {
+    private void setPropertyValue(Object sObjectBase, String name, Object value) throws SalesforceException {
         try {
             // set the value with the set method
             Method setMethod = sObjectBase.getClass().getMethod("set" + name, value.getClass());
@@ -678,6 +792,15 @@ public abstract class AbstractRestProcessor extends AbstractSalesforceProcessor
     // get request stream from In message
     protected abstract InputStream getRequestStream(Exchange exchange) throws SalesforceException;
 
+    /**
+     * Returns {@link InputStream} to serialized form of the given object.
+     * 
+     * @param object
+     *            object to serialize
+     * @return stream to read serialized object from
+     */
+    protected abstract InputStream getRequestStream(Object object) throws SalesforceException;
+
     private void setResponseClass(Exchange exchange, String sObjectName) throws SalesforceException {
         Class<?> sObjectClass;
 

http://git-wip-us.apache.org/repos/asf/camel/blob/b47de2b4/components/camel-salesforce/camel-salesforce-component/src/main/java/org/apache/camel/component/salesforce/internal/processor/JsonRestProcessor.java
----------------------------------------------------------------------
diff --git a/components/camel-salesforce/camel-salesforce-component/src/main/java/org/apache/camel/component/salesforce/internal/processor/JsonRestProcessor.java b/components/camel-salesforce/camel-salesforce-component/src/main/java/org/apache/camel/component/salesforce/internal/processor/JsonRestProcessor.java
index 03f674e..ec04651 100644
--- a/components/camel-salesforce/camel-salesforce-component/src/main/java/org/apache/camel/component/salesforce/internal/processor/JsonRestProcessor.java
+++ b/components/camel-salesforce/camel-salesforce-component/src/main/java/org/apache/camel/component/salesforce/internal/processor/JsonRestProcessor.java
@@ -20,6 +20,8 @@ import java.io.ByteArrayInputStream;
 import java.io.ByteArrayOutputStream;
 import java.io.IOException;
 import java.io.InputStream;
+import java.nio.charset.StandardCharsets;
+import java.util.List;
 import com.fasterxml.jackson.core.type.TypeReference;
 import com.fasterxml.jackson.databind.ObjectMapper;
 
@@ -36,6 +38,9 @@ import org.apache.camel.component.salesforce.api.dto.Limits;
 import org.apache.camel.component.salesforce.api.dto.RestResources;
 import org.apache.camel.component.salesforce.api.dto.SObjectBasicInfo;
 import org.apache.camel.component.salesforce.api.dto.SObjectDescription;
+import org.apache.camel.component.salesforce.api.dto.SearchResult;
+import org.apache.camel.component.salesforce.api.dto.approval.ApprovalResult;
+import org.apache.camel.component.salesforce.api.dto.approval.Approvals;
 import org.apache.camel.component.salesforce.api.utils.JsonUtils;
 import org.eclipse.jetty.util.StringUtil;
 
@@ -110,6 +115,16 @@ public class JsonRestProcessor extends AbstractRestProcessor {
             exchange.setProperty(RESPONSE_CLASS, Limits.class);
             break;
 
+        case APPROVAL:
+            // handle known response type
+            exchange.setProperty(RESPONSE_CLASS, ApprovalResult.class);
+            break;
+
+        case APPROVALS:
+            // handle known response type
+            exchange.setProperty(RESPONSE_CLASS, Approvals.class);
+            break;
+
         default:
             // ignore, some operations do not require response class or type
         }
@@ -117,36 +132,41 @@ public class JsonRestProcessor extends AbstractRestProcessor {
 
     @Override
     protected InputStream getRequestStream(Exchange exchange) throws SalesforceException {
-        try {
-            InputStream request;
-            Message in = exchange.getIn();
-            request = in.getBody(InputStream.class);
-            if (request == null) {
-                AbstractDTOBase dto = in.getBody(AbstractDTOBase.class);
-                if (dto != null) {
-                    // marshall the DTO
-                    ByteArrayOutputStream out = new ByteArrayOutputStream();
-                    objectMapper.writeValue(out, dto);
-                    request = new ByteArrayInputStream(out.toByteArray());
+        InputStream request;
+        Message in = exchange.getIn();
+        request = in.getBody(InputStream.class);
+        if (request == null) {
+            AbstractDTOBase dto = in.getBody(AbstractDTOBase.class);
+            if (dto != null) {
+                // marshall the DTO
+                request = getRequestStream(dto);
+            } else {
+                // if all else fails, get body as String
+                final String body = in.getBody(String.class);
+                if (null == body) {
+                    String msg = "Unsupported request message body "
+                        + (in.getBody() == null ? null : in.getBody().getClass());
+                    throw new SalesforceException(msg, null);
                 } else {
-                    // if all else fails, get body as String
-                    final String body = in.getBody(String.class);
-                    if (null == body) {
-                        String msg = "Unsupported request message body "
-                            + (in.getBody() == null ? null : in.getBody().getClass());
-                        throw new SalesforceException(msg, null);
-                    } else {
-                        request = new ByteArrayInputStream(body.getBytes(StringUtil.__UTF8_CHARSET));
-                    }
+                    request = new ByteArrayInputStream(body.getBytes(StandardCharsets.UTF_8));
                 }
             }
+        }
 
-            return request;
+        return request;
+    }
 
+    @Override
+    protected InputStream getRequestStream(final Object object) throws SalesforceException {
+        final ByteArrayOutputStream out = new ByteArrayOutputStream();
+        try {
+            objectMapper.writeValue(out, object);
         } catch (IOException e) {
-            String msg = "Error marshaling request: " + e.getMessage();
+            final String msg = "Error marshaling request: " + e.getMessage();
             throw new SalesforceException(msg, e);
         }
+
+        return new ByteArrayInputStream(out.toByteArray());
     }
 
     @Override

http://git-wip-us.apache.org/repos/asf/camel/blob/b47de2b4/components/camel-salesforce/camel-salesforce-component/src/main/java/org/apache/camel/component/salesforce/internal/processor/XmlRestProcessor.java
----------------------------------------------------------------------
diff --git a/components/camel-salesforce/camel-salesforce-component/src/main/java/org/apache/camel/component/salesforce/internal/processor/XmlRestProcessor.java b/components/camel-salesforce/camel-salesforce-component/src/main/java/org/apache/camel/component/salesforce/internal/processor/XmlRestProcessor.java
index 729649a..2bbc190 100644
--- a/components/camel-salesforce/camel-salesforce-component/src/main/java/org/apache/camel/component/salesforce/internal/processor/XmlRestProcessor.java
+++ b/components/camel-salesforce/camel-salesforce-component/src/main/java/org/apache/camel/component/salesforce/internal/processor/XmlRestProcessor.java
@@ -26,6 +26,7 @@ import java.io.Writer;
 
 import com.thoughtworks.xstream.XStream;
 import com.thoughtworks.xstream.XStreamException;
+import com.thoughtworks.xstream.core.TreeMarshallingStrategy;
 import com.thoughtworks.xstream.io.HierarchicalStreamWriter;
 import com.thoughtworks.xstream.io.naming.NoNameCoder;
 import com.thoughtworks.xstream.io.xml.CompactWriter;
@@ -45,6 +46,7 @@ import org.apache.camel.component.salesforce.api.dto.SObjectBasicInfo;
 import org.apache.camel.component.salesforce.api.dto.SObjectDescription;
 import org.apache.camel.component.salesforce.api.dto.SearchResults;
 import org.apache.camel.component.salesforce.api.dto.Versions;
+import org.apache.camel.component.salesforce.api.dto.approval.ApprovalResult;
 import org.apache.camel.component.salesforce.api.utils.DateTimeConverter;
 import org.apache.camel.component.salesforce.internal.client.XStreamUtils;
 import org.eclipse.jetty.util.StringUtil;
@@ -73,6 +75,7 @@ public class XmlRestProcessor extends AbstractRestProcessor {
                 result.ignoreUnknownElements();
                 XStreamUtils.addDefaultPermissions(result);
                 result.registerConverter(new DateTimeConverter());
+                result.setMarshallingStrategy(new TreeMarshallingStrategy());
                 return result;
             }
         };
@@ -154,13 +157,19 @@ public class XmlRestProcessor extends AbstractRestProcessor {
             exchange.setProperty(RESPONSE_ALIAS, "response");
             break;
 
+        case APPROVAL:
+            exchange.setProperty(RESPONSE_CLASS, ApprovalResult.class);
+            break;
+        case APPROVALS:
+            throw new SalesforceException("Fetching of approvals (as of 18.11.2016) with XML format results in HTTP status 500."
+                + " To fetch approvals please use JSON format.", 0);
+
         default:
             // ignore, some operations do not require alias or class exchange properties
         }
     }
 
     protected InputStream getRequestStream(Exchange exchange) throws SalesforceException {
-        final XStream localXStream = xStream.get();
         try {
             // get request stream from In message
             Message in = exchange.getIn();
@@ -169,12 +178,7 @@ public class XmlRestProcessor extends AbstractRestProcessor {
                 AbstractDTOBase dto = in.getBody(AbstractDTOBase.class);
                 if (dto != null) {
                     // marshall the DTO
-                    // first process annotations on the class, for things like alias, etc.
-                    localXStream.processAnnotations(dto.getClass());
-                    ByteArrayOutputStream out = new ByteArrayOutputStream();
-                    // make sure we write the XML with the right encoding
-                    localXStream.toXML(dto, new OutputStreamWriter(out, StringUtil.__UTF8));
-                    request = new ByteArrayInputStream(out.toByteArray());
+                    request = getRequestStream(dto);
                 } else {
                     // if all else fails, get body as String
                     final String body = in.getBody(String.class);
@@ -198,6 +202,24 @@ public class XmlRestProcessor extends AbstractRestProcessor {
     }
 
     @Override
+    protected InputStream getRequestStream(final Object object) throws SalesforceException {
+        final XStream localXStream = xStream.get();
+        // first process annotations on the class, for things like alias, etc.
+        localXStream.processAnnotations(object.getClass());
+
+        final ByteArrayOutputStream out = new ByteArrayOutputStream();
+        // make sure we write the XML with the right encoding
+        try {
+            localXStream.toXML(object, new OutputStreamWriter(out, StringUtil.__UTF8));
+        } catch (UnsupportedEncodingException e) {
+            String msg = "Error marshaling request: " + e.getMessage();
+            throw new SalesforceException(msg, e);
+        }
+
+        return new ByteArrayInputStream(out.toByteArray());
+    }
+
+    @Override
     protected void processResponse(Exchange exchange, InputStream responseEntity,
                                    SalesforceException exception, AsyncCallback callback) {
         final XStream localXStream = xStream.get();

http://git-wip-us.apache.org/repos/asf/camel/blob/b47de2b4/components/camel-salesforce/camel-salesforce-component/src/test/java/org/apache/camel/component/salesforce/AbstractApprovalIntegrationTest.java
----------------------------------------------------------------------
diff --git a/components/camel-salesforce/camel-salesforce-component/src/test/java/org/apache/camel/component/salesforce/AbstractApprovalIntegrationTest.java b/components/camel-salesforce/camel-salesforce-component/src/test/java/org/apache/camel/component/salesforce/AbstractApprovalIntegrationTest.java
new file mode 100644
index 0000000..0bf4638
--- /dev/null
+++ b/components/camel-salesforce/camel-salesforce-component/src/test/java/org/apache/camel/component/salesforce/AbstractApprovalIntegrationTest.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.salesforce;
+
+import java.io.IOException;
+import java.util.Collections;
+import java.util.List;
+import java.util.stream.Collectors;
+import java.util.stream.IntStream;
+
+import org.apache.camel.component.salesforce.api.dto.CreateSObjectResult;
+import org.apache.camel.component.salesforce.api.dto.analytics.reports.QueryRecordsReport;
+import org.apache.camel.component.salesforce.dto.generated.Account;
+import org.junit.After;
+import org.junit.Before;
+
+public abstract class AbstractApprovalIntegrationTest extends AbstractSalesforceTestBase {
+
+    protected static final Object NOT_USED = null;
+
+    protected List<String> accountIds = Collections.emptyList();
+
+    protected String userId;
+
+    private final int accountCount;
+
+    AbstractApprovalIntegrationTest(final int accountCount) {
+        this.accountCount = accountCount;
+    }
+
+    @Before
+    public void createAccounts() {
+        final List<Account> accountsToCreate = IntStream.range(0, accountCount + 1).mapToObj(idx -> {
+            final String name = "test-account-" + idx;
+            final Account account = new Account();
+            account.setName(name);
+
+            return account;
+        }).collect(Collectors.toList());
+
+        accountIds = accountsToCreate.stream().map(account -> template
+                .requestBody("salesforce:createSObject?sObjectName=Account", account, CreateSObjectResult.class))
+                .map(CreateSObjectResult::getId).collect(Collectors.toList());
+    }
+
+    @After
+    public void deleteAccounts() {
+        accountIds.forEach(id -> template.sendBody("salesforce:deleteSObject?sObjectName=Account", id));
+    }
+
+    @Before
+    public void setupUserId() throws IOException {
+        final SalesforceLoginConfig loginConfig = LoginConfigHelper.getLoginConfig();
+
+        final String userName = loginConfig.getUserName();
+
+        // I happen to have a username (e-mail address) with '+' sign in it,
+        // DefaultRestClient#urlEncode would encode '+' as '%20' and the query
+        // would not return any result, so replacing '+' with '%' and '=' with
+        // 'LIKE' makes sense in my case. It should also work for every other
+        // case where '+' is not used as a part of the username.
+        final String wildcardUsername = userName.replace('+', '%');
+
+        final QueryRecordsReport results = template.requestBody(
+                "salesforce:query?sObjectClass=" + QueryRecordsReport.class.getName()//
+                    + "&sObjectQuery=SELECT Id FROM User WHERE Username LIKE '" + wildcardUsername + "'",
+                NOT_USED, QueryRecordsReport.class);
+
+        userId = results.getRecords().get(0).getId();
+    }
+}

http://git-wip-us.apache.org/repos/asf/camel/blob/b47de2b4/components/camel-salesforce/camel-salesforce-component/src/test/java/org/apache/camel/component/salesforce/ApprovalExamplesIntegrationTest.java
----------------------------------------------------------------------
diff --git a/components/camel-salesforce/camel-salesforce-component/src/test/java/org/apache/camel/component/salesforce/ApprovalExamplesIntegrationTest.java b/components/camel-salesforce/camel-salesforce-component/src/test/java/org/apache/camel/component/salesforce/ApprovalExamplesIntegrationTest.java
new file mode 100644
index 0000000..d11299d
--- /dev/null
+++ b/components/camel-salesforce/camel-salesforce-component/src/test/java/org/apache/camel/component/salesforce/ApprovalExamplesIntegrationTest.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.salesforce;
+
+import java.util.HashMap;
+import java.util.Map;
+
+import org.apache.camel.builder.RouteBuilder;
+import org.apache.camel.component.salesforce.api.dto.approval.ApprovalRequest;
+import org.apache.camel.component.salesforce.api.dto.approval.ApprovalResult;
+import org.apache.camel.impl.JndiRegistry;
+import org.junit.Test;
+
+public class ApprovalExamplesIntegrationTest extends AbstractApprovalIntegrationTest {
+
+    public ApprovalExamplesIntegrationTest() {
+        super(3);
+    }
+
+    @Test
+    public void example1() {
+        // tag::example1Usage
+        final Map<String, String> body = new HashMap<>();
+        body.put("contextId", accountIds.iterator().next());
+        body.put("nextApproverIds", userId);
+
+        final ApprovalResult result = template.requestBody("direct:example1", body, ApprovalResult.class);
+        // end::example1Usage
+
+        assertNotNull("Result should be received", result);
+    }
+
+    @Test
+    public void example2() {
+        // tag::example2Usage
+        final Map<String, String> body = new HashMap<>();
+        body.put("contextId", accountIds.iterator().next());
+        body.put("nextApproverIds", userId);
+
+        final ApprovalResult result = template.requestBody("direct:example2", body, ApprovalResult.class);
+        // end::example2Usage
+
+        assertNotNull("Result should be received", result);
+    }
+
+    @Override
+    protected JndiRegistry createRegistry() throws Exception {
+        final JndiRegistry jndi = super.createRegistry();
+
+        final ApprovalRequest approvalTemplate = new ApprovalRequest();
+        approvalTemplate.setActionType(ApprovalRequest.Action.Submit);
+        approvalTemplate.setComments("Sample approval template");
+        approvalTemplate.setProcessDefinitionNameOrId("Test_Account_Process");
+        approvalTemplate.setSkipEntryCriteria(true);
+
+        jndi.bind("approvalTemplate", approvalTemplate);
+
+        return jndi;
+    }
+
+    @Override
+    protected RouteBuilder doCreateRouteBuilder() throws Exception {
+        return new RouteBuilder() {
+            @Override
+            public void configure() throws Exception {
+                // tag::example1Route[]
+                from("direct:example1")//
+                        .setHeader("approval.ContextId", simple("${body['contextId']}"))
+                        .setHeader("approval.NextApproverIds", simple("${body['nextApproverIds']}"))
+                        .to("salesforce:approval?"//
+                            + "approvalActionType=Submit"//
+                            + "&approvalComments=this is a test"//
+                            + "&approvalProcessDefinitionNameOrId=Test_Account_Process"//
+                            + "&approvalSkipEntryCriteria=true");
+                // end::example1Route[]
+
+                // tag::example2Route[]
+                from("direct:example2")//
+                        .setHeader("approval.ContextId", simple("${body['contextId']}"))
+                        .setHeader("approval.NextApproverIds", simple("${body['nextApproverIds']}"))
+                        .to("salesforce:approval?approval=#approvalTemplate");
+                // end::example2Route[]
+            }
+        };
+    }
+
+}


[2/3] camel git commit: CAMEL-8396 Update Salesforce component to support new REST APIs in Sa...

Posted by da...@apache.org.
http://git-wip-us.apache.org/repos/asf/camel/blob/b47de2b4/components/camel-salesforce/camel-salesforce-component/src/test/java/org/apache/camel/component/salesforce/ApprovalIntegrationTest.java
----------------------------------------------------------------------
diff --git a/components/camel-salesforce/camel-salesforce-component/src/test/java/org/apache/camel/component/salesforce/ApprovalIntegrationTest.java b/components/camel-salesforce/camel-salesforce-component/src/test/java/org/apache/camel/component/salesforce/ApprovalIntegrationTest.java
new file mode 100644
index 0000000..47d71d5
--- /dev/null
+++ b/components/camel-salesforce/camel-salesforce-component/src/test/java/org/apache/camel/component/salesforce/ApprovalIntegrationTest.java
@@ -0,0 +1,112 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.camel.component.salesforce;
+
+import java.util.Arrays;
+import java.util.List;
+import java.util.stream.Collectors;
+
+import org.apache.camel.builder.RouteBuilder;
+import org.apache.camel.component.salesforce.api.dto.approval.ApprovalRequest;
+import org.apache.camel.component.salesforce.api.dto.approval.ApprovalRequest.Action;
+import org.apache.camel.component.salesforce.api.dto.approval.ApprovalResult;
+import org.apache.camel.component.salesforce.api.dto.approval.Approvals;
+import org.apache.camel.component.salesforce.api.dto.approval.Approvals.Info;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.Parameterized;
+import org.junit.runners.Parameterized.Parameters;
+
+@RunWith(Parameterized.class)
+public class ApprovalIntegrationTest extends AbstractApprovalIntegrationTest {
+
+    private final String format;
+
+    public ApprovalIntegrationTest(final String format) {
+        super(5);
+        this.format = format;
+    }
+
+    @Parameters(name = "format = {0}")
+    public static Iterable<String> formats() {
+        return Arrays.asList("JSON", "XML");
+    }
+
+    @Test
+    public void shouldSubmitAndFetchApprovals() {
+        final ApprovalResult approvalResult = template.requestBody(
+                String.format(
+                        "salesforce:approval?"//
+                            + "format=%s"//
+                            + "&approvalActionType=Submit"//
+                            + "&approvalContextId=%s"//
+                            + "&approvalNextApproverIds=%s"//
+                            + "&approvalComments=Integration test"//
+                            + "&approvalProcessDefinitionNameOrId=Test_Account_Process",
+                        format, accountIds.get(0), userId),
+                NOT_USED, ApprovalResult.class);
+
+        assertNotNull("Approval should have resulted in value", approvalResult);
+
+        assertEquals("There should be one Account waiting approval", 1, approvalResult.size());
+
+        assertEquals("Instance status of the item in approval result should be `Pending`", "Pending",
+                approvalResult.iterator().next().getInstanceStatus());
+
+        // as it stands on 18.11.2016. the GET method on /vXX.X/process/approvals/ with Accept other than
+        // `application/json` results in HTTP status 500, so only JSON is supported
+        final Approvals approvals = template.requestBody("salesforce:approvals", NOT_USED, Approvals.class);
+
+        assertNotNull("Approvals should be fetched", approvals);
+
+        final List<Info> accountApprovals = approvals.approvalsFor("Account");
+        assertEquals("There should be one Account waiting approval", 1, accountApprovals.size());
+    }
+
+    @Test
+    public void shouldSubmitBulkApprovals() {
+        final List<ApprovalRequest> approvalRequests = accountIds.stream().map(id -> {
+            final ApprovalRequest request = new ApprovalRequest();
+            request.setContextId(id);
+            request.setComments("Approval for " + id);
+            request.setActionType(Action.Submit);
+
+            return request;
+        }).collect(Collectors.toList());
+
+        final ApprovalResult approvalResult = template.requestBody(
+                String.format("salesforce:approval?"//
+                    + "format=%s"//
+                    + "&approvalActionType=Submit"//
+                    + "&approvalNextApproverIds=%s"//
+                    + "&approvalProcessDefinitionNameOrId=Test_Account_Process", format, userId),
+                approvalRequests, ApprovalResult.class);
+
+        assertEquals("Should have same number of approval results as requests", approvalRequests.size(),
+                approvalResult.size());
+    }
+
+    @Override
+    protected RouteBuilder doCreateRouteBuilder() throws Exception {
+        return new RouteBuilder() {
+            @Override
+            public void configure() throws Exception {
+            }
+        };
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/camel/blob/b47de2b4/components/camel-salesforce/camel-salesforce-component/src/test/java/org/apache/camel/component/salesforce/SalesforceComponentConfigurationIntegrationTest.java
----------------------------------------------------------------------
diff --git a/components/camel-salesforce/camel-salesforce-component/src/test/java/org/apache/camel/component/salesforce/SalesforceComponentConfigurationIntegrationTest.java b/components/camel-salesforce/camel-salesforce-component/src/test/java/org/apache/camel/component/salesforce/SalesforceComponentConfigurationIntegrationTest.java
index db9acc8..92c353d 100644
--- a/components/camel-salesforce/camel-salesforce-component/src/test/java/org/apache/camel/component/salesforce/SalesforceComponentConfigurationIntegrationTest.java
+++ b/components/camel-salesforce/camel-salesforce-component/src/test/java/org/apache/camel/component/salesforce/SalesforceComponentConfigurationIntegrationTest.java
@@ -103,10 +103,10 @@ public class SalesforceComponentConfigurationIntegrationTest extends CamelTestSu
         assertCompletionOptions(configuration.completeEndpointPath(""),
             "getVersions", "getResources", "getGlobalObjects", "getBasicInfo", "getDescription", "getSObject", "createSObject",
             "updateSObject", "deleteSObject", "getSObjectWithId", "upsertSObject", "deleteSObjectWithId", "getBlobField",
-            "query", "queryMore", "queryAll", "search", "apexCall", "createJob", "getJob", "closeJob", "abortJob",
+            "query", "queryMore", "queryAll", "search", "apexCall", "recent", "createJob", "getJob", "closeJob", "abortJob",
             "createBatch", "getBatch", "getAllBatches", "getRequest", "getResults", "createBatchQuery", "getQueryResultIds",
             "getQueryResult", "getRecentReports", "getReportDescription", "executeSyncReport", "executeAsyncReport",
-            "getReportInstances", "getReportResults", "[PushTopicName]"
+            "getReportInstances", "getReportResults", "limits", "approval", "approvals", "[PushTopicName]"
         );
 
         // get filtered operation names

http://git-wip-us.apache.org/repos/asf/camel/blob/b47de2b4/components/camel-salesforce/camel-salesforce-component/src/test/java/org/apache/camel/component/salesforce/api/dto/approval/ApprovalRequestTest.java
----------------------------------------------------------------------
diff --git a/components/camel-salesforce/camel-salesforce-component/src/test/java/org/apache/camel/component/salesforce/api/dto/approval/ApprovalRequestTest.java b/components/camel-salesforce/camel-salesforce-component/src/test/java/org/apache/camel/component/salesforce/api/dto/approval/ApprovalRequestTest.java
new file mode 100644
index 0000000..b331952
--- /dev/null
+++ b/components/camel-salesforce/camel-salesforce-component/src/test/java/org/apache/camel/component/salesforce/api/dto/approval/ApprovalRequestTest.java
@@ -0,0 +1,117 @@
+/**
+ * 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.salesforce.api.dto.approval;
+
+import java.util.Collections;
+
+import com.fasterxml.jackson.core.JsonProcessingException;
+import com.fasterxml.jackson.databind.ObjectMapper;
+import com.thoughtworks.xstream.XStream;
+
+import org.apache.camel.component.salesforce.api.dto.approval.ApprovalRequest.Action;
+import org.junit.Test;
+
+import static org.hamcrest.CoreMatchers.sameInstance;
+import static org.hamcrest.core.CombinableMatcher.both;
+import static org.hamcrest.core.IsNot.not;
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertThat;
+
+public class ApprovalRequestTest {
+
+    private final ApprovalRequest sampleRequest;
+
+    public ApprovalRequestTest() {
+        sampleRequest = new ApprovalRequest();
+
+        sampleRequest.setActionType(Action.Submit);
+        sampleRequest.setContextId("001D000000I8mIm");
+        sampleRequest.addNextApproverId("005D00000015rY9");
+        sampleRequest.setComments("this is a test");
+        sampleRequest.setContextActorId("005D00000015rZy");
+        sampleRequest.setProcessDefinitionNameOrId("PTO_Request_Process");
+        sampleRequest.setSkipEntryCriteria(true);
+
+    }
+
+    @Test
+    public void shouldApplyValuesFromTemplate() {
+        final ApprovalRequest request = new ApprovalRequest();
+        request.setActionType(Action.Approve);
+        request.setComments("Comment");
+        request.setContextId("Context Id");
+
+        final ApprovalRequest template = new ApprovalRequest();
+        template.setActionType(Action.Reject);
+        template.setComments("Template comment");
+        template.setNextApproverIds(Collections.singletonList("Next approver "));
+
+        final ApprovalRequest combined = request.applyTemplate(template);
+
+        assertThat("Combined approval request should be a new instance", combined,
+                both(not(sameInstance(request))).and(not(sameInstance(template))));
+
+        assertEquals("Action type should not be overwriten", request.getActionType(), combined.getActionType());
+        assertEquals("Comment should not be overwriten", request.getComments(), combined.getComments());
+        assertEquals("Context id should not be overwriten", request.getContextId(), combined.getContextId());
+        assertEquals("Next approver id should be taken from template", template.getNextApproverIds(),
+                combined.getNextApproverIds());
+    }
+
+    @Test
+    public void shouldSerializeAsJson() throws JsonProcessingException {
+        final ObjectMapper mapper = new ObjectMapper();
+
+        final String json = mapper.writerFor(ApprovalRequest.class).writeValueAsString(sampleRequest);
+
+        assertEquals("ApprovalRequest should serialize as JSON from Salesforce examples",
+                "{\"actionType\":\"Submit\",\"contextActorId\":\"005D00000015rZy\",\"contextId\":\"001D000000I8mIm\""
+                    + ",\"comments\":\"this is a test\",\"nextApproverIds\":[\"005D00000015rY9\"],"
+                    + "\"processDefinitionNameOrId\":\"PTO_Request_Process\",\"skipEntryCriteria\":true}",
+                json);
+    }
+
+    @Test
+    public void shouldSerializeAsXml() {
+        final XStream xStream = new XStream();
+        xStream.processAnnotations(ApprovalRequest.class);
+
+        final String xml = xStream.toXML(sampleRequest);
+
+        assertEquals("ApprovalRequest should serialize as XML",
+                "<requests>\n"//
+                    + "  <actionType>Submit</actionType>\n"//
+                    + "  <contextActorId>005D00000015rZy</contextActorId>\n"//
+                    + "  <contextId>001D000000I8mIm</contextId>\n"//
+                    + "  <comments>this is a test</comments>\n"//
+                    + "  <nextApproverIds>005D00000015rY9</nextApproverIds>\n"//
+                    + "  <processDefinitionNameOrId>PTO_Request_Process</processDefinitionNameOrId>\n"//
+                    + "  <skipEntryCriteria>true</skipEntryCriteria>\n"//
+                    + "</requests>",
+                xml);
+    }
+
+    @Test
+    public void shouldTolerateNullTemplates() {
+        final ApprovalRequest request = new ApprovalRequest();
+
+        final ApprovalRequest appliedTo = request.applyTemplate(null);
+
+        assertThat("For null templates applyTemplate should return same object", appliedTo, sameInstance(request));
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/camel/blob/b47de2b4/components/camel-salesforce/camel-salesforce-component/src/test/java/org/apache/camel/component/salesforce/api/dto/approval/ApprovalRequestsTest.java
----------------------------------------------------------------------
diff --git a/components/camel-salesforce/camel-salesforce-component/src/test/java/org/apache/camel/component/salesforce/api/dto/approval/ApprovalRequestsTest.java b/components/camel-salesforce/camel-salesforce-component/src/test/java/org/apache/camel/component/salesforce/api/dto/approval/ApprovalRequestsTest.java
new file mode 100644
index 0000000..a63959b
--- /dev/null
+++ b/components/camel-salesforce/camel-salesforce-component/src/test/java/org/apache/camel/component/salesforce/api/dto/approval/ApprovalRequestsTest.java
@@ -0,0 +1,133 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.camel.component.salesforce.api.dto.approval;
+
+import java.io.Writer;
+import java.util.Arrays;
+
+import com.fasterxml.jackson.core.JsonProcessingException;
+import com.fasterxml.jackson.databind.ObjectMapper;
+import com.thoughtworks.xstream.XStream;
+import com.thoughtworks.xstream.io.HierarchicalStreamWriter;
+import com.thoughtworks.xstream.io.naming.NoNameCoder;
+import com.thoughtworks.xstream.io.xml.CompactWriter;
+import com.thoughtworks.xstream.io.xml.XppDriver;
+
+import org.apache.camel.component.salesforce.api.dto.approval.ApprovalRequest.Action;
+import org.apache.camel.component.salesforce.api.utils.DateTimeConverter;
+import org.apache.camel.component.salesforce.internal.client.XStreamUtils;
+import org.junit.Test;
+
+import static org.junit.Assert.assertEquals;
+
+public class ApprovalRequestsTest {
+
+    private final ApprovalRequests requests;
+
+    public ApprovalRequestsTest() {
+        final String actorId = "005D00000015rZy";
+
+        final ApprovalRequest request1 = new ApprovalRequest();
+        request1.setActionType(Action.Submit);
+        request1.setContextId("001D000000I8mIm");
+        request1.setNextApproverIds("005D00000015rY9");
+        request1.setComments("this is a test 1");
+        request1.setContextActorId(actorId);
+        request1.setProcessDefinitionNameOrId("PTO_Request_Process");
+        request1.setSkipEntryCriteria(true);
+
+        final ApprovalRequest request2 = new ApprovalRequest();
+        request2.setActionType(Action.Submit);
+        request2.setContextId("001D000000I8dIm");
+        request2.setNextApproverIds("005D00000015xY9");
+        request2.setComments("this is a test 2");
+        request2.setContextActorId(actorId);
+        request2.setProcessDefinitionNameOrId("PTO_Request_Process");
+        request2.setSkipEntryCriteria(true);
+
+        requests = new ApprovalRequests(Arrays.asList(request1, request2));
+    }
+
+    @Test
+    public void shouldSerializeAsJson() throws JsonProcessingException {
+        final String json = "{\"requests\":["//
+            + "{"//
+            + "\"actionType\":\"Submit\","//
+            + "\"contextActorId\":\"005D00000015rZy\","//
+            + "\"contextId\":\"001D000000I8mIm\","//
+            + "\"comments\":\"this is a test 1\","//
+            + "\"nextApproverIds\":[\"005D00000015rY9\"],"//
+            + "\"processDefinitionNameOrId\":\"PTO_Request_Process\","//
+            + "\"skipEntryCriteria\":true"//
+            + "},{"//
+            + "\"actionType\":\"Submit\","//
+            + "\"contextActorId\":\"005D00000015rZy\","//
+            + "\"contextId\":\"001D000000I8dIm\","//
+            + "\"comments\":\"this is a test 2\","//
+            + "\"nextApproverIds\":[\"005D00000015xY9\"],"//
+            + "\"processDefinitionNameOrId\":\"PTO_Request_Process\","//
+            + "\"skipEntryCriteria\":true"//
+            + "}"//
+            + "]}";
+
+        final ObjectMapper mapper = new ObjectMapper();
+
+        final String serialized = mapper.writerFor(ApprovalRequests.class).writeValueAsString(requests);
+
+        assertEquals("Approval requests should serialize as JSON", json, serialized);
+    }
+
+    @Test
+    public void shouldSerializeAsXml() {
+        final String xml = "<ProcessApprovalRequest>"//
+            + "<requests>"//
+            + "<actionType>Submit</actionType>"//
+            + "<contextActorId>005D00000015rZy</contextActorId>"//
+            + "<contextId>001D000000I8mIm</contextId>"//
+            + "<comments>this is a test 1</comments>"//
+            + "<nextApproverIds>005D00000015rY9</nextApproverIds>"//
+            + "<processDefinitionNameOrId>PTO_Request_Process</processDefinitionNameOrId>"//
+            + "<skipEntryCriteria>true</skipEntryCriteria>"//
+            + "</requests>"//
+            + "<requests>"//
+            + "<actionType>Submit</actionType>"//
+            + "<contextActorId>005D00000015rZy</contextActorId>"//
+            + "<contextId>001D000000I8dIm</contextId>"//
+            + "<comments>this is a test 2</comments>"//
+            + "<nextApproverIds>005D00000015xY9</nextApproverIds>"//
+            + "<processDefinitionNameOrId>PTO_Request_Process</processDefinitionNameOrId>"//
+            + "<skipEntryCriteria>true</skipEntryCriteria>"//
+            + "</requests>"//
+            + "</ProcessApprovalRequest>";
+
+        final XStream xStream = new XStream(new XppDriver(new NoNameCoder()) {
+            @Override
+            public HierarchicalStreamWriter createWriter(final Writer out) {
+                return new CompactWriter(out, getNameCoder());
+            }
+
+        });
+        xStream.ignoreUnknownElements();
+        XStreamUtils.addDefaultPermissions(xStream);
+        xStream.registerConverter(new DateTimeConverter());
+        xStream.processAnnotations(ApprovalRequests.class);
+
+        final String serialized = xStream.toXML(requests);
+
+        assertEquals("Approval requests should serialize as XML", xml, serialized);
+    }
+}

http://git-wip-us.apache.org/repos/asf/camel/blob/b47de2b4/components/camel-salesforce/camel-salesforce-component/src/test/java/org/apache/camel/component/salesforce/api/dto/approval/ApprovalResultTest.java
----------------------------------------------------------------------
diff --git a/components/camel-salesforce/camel-salesforce-component/src/test/java/org/apache/camel/component/salesforce/api/dto/approval/ApprovalResultTest.java b/components/camel-salesforce/camel-salesforce-component/src/test/java/org/apache/camel/component/salesforce/api/dto/approval/ApprovalResultTest.java
new file mode 100644
index 0000000..a1d315e
--- /dev/null
+++ b/components/camel-salesforce/camel-salesforce-component/src/test/java/org/apache/camel/component/salesforce/api/dto/approval/ApprovalResultTest.java
@@ -0,0 +1,95 @@
+/**
+ * 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.salesforce.api.dto.approval;
+
+import java.io.IOException;
+import java.util.Iterator;
+
+import com.fasterxml.jackson.core.JsonProcessingException;
+import com.fasterxml.jackson.databind.ObjectMapper;
+import com.thoughtworks.xstream.XStream;
+
+import org.apache.camel.component.salesforce.api.dto.approval.ApprovalResult.Result;
+import org.junit.Test;
+
+import static org.hamcrest.core.IsCollectionContaining.hasItems;
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertThat;
+import static org.junit.Assert.assertTrue;
+
+public class ApprovalResultTest {
+
+    private static void assertResponseReadCorrectly(final ApprovalResult results) {
+        final Iterator<Result> resultsIterator = results.iterator();
+        assertTrue("Should deserialize one approval result result", resultsIterator.hasNext());
+
+        final ApprovalResult.Result result = resultsIterator.next();
+
+        assertThat("Should deserialize actorIds", result.getActorIds(), hasItems("0050Y000000u5NOQAY"));
+        assertEquals("Should deserialize entityId", "0010Y000005BYrZQAW", result.getEntityId());
+        assertEquals("Should deserialize instanceId", "04g0Y000000PL53QAG", result.getInstanceId());
+        assertEquals("Should deserialize instanceStatus", "Pending", result.getInstanceStatus());
+        assertThat("Should deserialize newWorkitemIds", result.getNewWorkitemIds(), hasItems("04i0Y000000L0fkQAC"));
+        assertTrue("Should deserialize success", result.isSuccess());
+
+        assertFalse("Should be no more results", resultsIterator.hasNext());
+    }
+
+    @Test
+    public void shouldDeserializeFromJson() throws JsonProcessingException, IOException {
+        final String json = "["//
+            + "{"//
+            + "\"actorIds\":[\"0050Y000000u5NOQAY\"],"//
+            + "\"entityId\":\"0010Y000005BYrZQAW\","//
+            + "\"errors\":null,"//
+            + "\"instanceId\":\"04g0Y000000PL53QAG\","//
+            + "\"instanceStatus\":\"Pending\","//
+            + "\"newWorkitemIds\":[\"04i0Y000000L0fkQAC\"],"//
+            + "\"success\":true"//
+            + "}"//
+            + "]";
+
+        final ObjectMapper mapper = new ObjectMapper();
+
+        final ApprovalResult results = mapper.readerFor(ApprovalResult.class).readValue(json);
+
+        assertResponseReadCorrectly(results);
+    }
+
+    @Test
+    public void shouldDeserializeFromXml() throws InstantiationException, IllegalAccessException {
+        final ApprovalResult results = new ApprovalResult();
+
+        final XStream xStream = new XStream();
+        xStream.processAnnotations(ApprovalResult.class);
+
+        xStream.fromXML("<?xml version=\"1.0\" encoding=\"UTF-8\"?>"//
+            + "<ProcessApprovalResult>"//
+            + "<ProcessApprovalResult>"//
+            + "<actorIds>0050Y000000u5NOQAY</actorIds>"//
+            + "<entityId>0010Y000005BYrZQAW</entityId>"//
+            + "<instanceId>04g0Y000000PL53QAG</instanceId>"//
+            + "<instanceStatus>Pending</instanceStatus>"//
+            + "<newWorkitemIds>04i0Y000000L0fkQAC</newWorkitemIds>"//
+            + "<success>true</success>"//
+            + "</ProcessApprovalResult>"//
+            + "</ProcessApprovalResult>", results);
+
+        assertResponseReadCorrectly(results);
+    }
+}

http://git-wip-us.apache.org/repos/asf/camel/blob/b47de2b4/components/camel-salesforce/camel-salesforce-component/src/test/java/org/apache/camel/component/salesforce/api/dto/approval/ApprovalsTest.java
----------------------------------------------------------------------
diff --git a/components/camel-salesforce/camel-salesforce-component/src/test/java/org/apache/camel/component/salesforce/api/dto/approval/ApprovalsTest.java b/components/camel-salesforce/camel-salesforce-component/src/test/java/org/apache/camel/component/salesforce/api/dto/approval/ApprovalsTest.java
new file mode 100644
index 0000000..0943983
--- /dev/null
+++ b/components/camel-salesforce/camel-salesforce-component/src/test/java/org/apache/camel/component/salesforce/api/dto/approval/ApprovalsTest.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.salesforce.api.dto.approval;
+
+import java.io.IOException;
+import java.util.List;
+import java.util.Map;
+
+import com.fasterxml.jackson.core.JsonProcessingException;
+import com.fasterxml.jackson.databind.ObjectMapper;
+
+import org.apache.camel.component.salesforce.api.dto.approval.Approvals.Info;
+import org.junit.Test;
+
+import static org.hamcrest.core.IsInstanceOf.instanceOf;
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertNull;
+import static org.junit.Assert.assertThat;
+
+public class ApprovalsTest {
+
+    @Test
+    public void shouldDeserialize() throws JsonProcessingException, IOException {
+        final ObjectMapper mapper = new ObjectMapper();
+
+        final Object read = mapper.readerFor(Approvals.class)
+                .readValue("{\n" + //
+                    "  \"approvals\" : {\n" + //
+                    "   \"Account\" : [ {\n" + //
+                    "     \"description\" : null,\n" + //
+                    "     \"id\" : \"04aD00000008Py9\",\n" + //
+                    "     \"name\" : \"Account Approval Process\",\n" + //
+                    "     \"object\" : \"Account\",\n" + //
+                    "     \"sortOrder\" : 1\n" + //
+                    "   } ]\n" + //
+                    "  }\n" + //
+                    "}");
+
+        assertThat("Should deserialize Approvals", read, instanceOf(Approvals.class));
+
+        final Approvals approvals = (Approvals) read;
+
+        final Map<String, List<Info>> approvalsMap = approvals.getApprovals();
+        assertEquals("Deserialized approvals should have one entry", 1, approvalsMap.size());
+
+        final List<Info> accountApprovals = approvalsMap.get("Account");
+        assertNotNull("Deserialized approvals should contain list of `Account` type approvals", accountApprovals);
+
+        assertEquals("There should be one approval of `Account` type", 1, accountApprovals.size());
+
+        final Info accountInfo = accountApprovals.get(0);
+
+        assertNull("Deserialized `Account` approval should have null description", accountInfo.getDescription());
+        assertEquals("Deserialized `Account` approval should have defined id", "04aD00000008Py9", accountInfo.getId());
+        assertEquals("Deserialized `Account` approval should have defined name", "Account Approval Process",
+                accountInfo.getName());
+        assertEquals("Deserialized `Account` approval should have defined object", "Account", accountInfo.getObject());
+        assertEquals("Deserialized `Account` approval should have defined sortOrder", 1, accountInfo.getSortOrder());
+    }
+}

http://git-wip-us.apache.org/repos/asf/camel/blob/b47de2b4/components/camel-salesforce/camel-salesforce-component/src/test/java/org/apache/camel/component/salesforce/internal/processor/AbstractRestProcessorApprovalTest.java
----------------------------------------------------------------------
diff --git a/components/camel-salesforce/camel-salesforce-component/src/test/java/org/apache/camel/component/salesforce/internal/processor/AbstractRestProcessorApprovalTest.java b/components/camel-salesforce/camel-salesforce-component/src/test/java/org/apache/camel/component/salesforce/internal/processor/AbstractRestProcessorApprovalTest.java
new file mode 100644
index 0000000..30a7768
--- /dev/null
+++ b/components/camel-salesforce/camel-salesforce-component/src/test/java/org/apache/camel/component/salesforce/internal/processor/AbstractRestProcessorApprovalTest.java
@@ -0,0 +1,271 @@
+/**
+ * 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.salesforce.internal.processor;
+
+import java.io.InputStream;
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.Map;
+
+import org.apache.camel.AsyncCallback;
+import org.apache.camel.CamelContext;
+import org.apache.camel.Exchange;
+import org.apache.camel.Message;
+import org.apache.camel.component.salesforce.SalesforceComponent;
+import org.apache.camel.component.salesforce.SalesforceEndpoint;
+import org.apache.camel.component.salesforce.SalesforceEndpointConfig;
+import org.apache.camel.component.salesforce.api.SalesforceException;
+import org.apache.camel.component.salesforce.api.dto.approval.ApprovalRequest;
+import org.apache.camel.component.salesforce.api.dto.approval.ApprovalRequest.Action;
+import org.apache.camel.component.salesforce.api.dto.approval.ApprovalRequests;
+import org.apache.camel.component.salesforce.internal.client.RestClient;
+import org.apache.camel.impl.DefaultCamelContext;
+import org.apache.camel.impl.DefaultExchange;
+import org.apache.camel.impl.DefaultMessage;
+import org.junit.Test;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.fail;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.spy;
+import static org.mockito.Mockito.verify;
+
+public class AbstractRestProcessorApprovalTest {
+
+    static class TestRestProcessor extends AbstractRestProcessor {
+
+        RestClient client;
+
+        TestRestProcessor() throws SalesforceException {
+            this(endpoint(), mock(RestClient.class));
+        }
+
+        TestRestProcessor(final SalesforceEndpoint endpoint, final RestClient client) {
+            super(endpoint, client, Collections.emptyMap());
+            this.client = client;
+        }
+
+        static SalesforceComponent component() {
+            return new SalesforceComponent();
+        }
+
+        static SalesforceEndpointConfig configuration() {
+            return new SalesforceEndpointConfig();
+        }
+
+        static SalesforceEndpoint endpoint() {
+            return new SalesforceEndpoint(notUsed(), component(), configuration(), notUsed(), notUsed());
+        }
+
+        @Override
+        protected InputStream getRequestStream(final Exchange exchange) throws SalesforceException {
+            return null;
+        }
+
+        @Override
+        protected InputStream getRequestStream(final Object object) throws SalesforceException {
+            return null;
+        }
+
+        @Override
+        protected void processRequest(final Exchange exchange) throws SalesforceException {
+        }
+
+        @Override
+        protected void processResponse(final Exchange exchange, final InputStream responseEntity,
+                final SalesforceException ex, final AsyncCallback callback) {
+        }
+    }
+
+    private static <T> T notUsed() {
+        return null;
+    }
+
+    static ApprovalRequest requestWithComment(final String comment) {
+        final ApprovalRequest approvalRequest = new ApprovalRequest();
+        approvalRequest.setComments(comment);
+
+        return approvalRequest;
+    }
+
+    @Test
+    public void shouldApplyTemplateToRequestFromBody() throws SalesforceException {
+        final ApprovalRequest template = new ApprovalRequest();
+        template.setActionType(Action.Submit);
+
+        final ApprovalRequest approvalRequest = new ApprovalRequest();
+        approvalRequest.setComments("it should be me");
+
+        final TestRestProcessor processor = sendBodyAndHeader(approvalRequest, template);
+
+        verify(processor).getRequestStream(new ApprovalRequests(approvalRequest.applyTemplate(template)));
+    }
+
+    @Test
+    public void shouldApplyTemplateToRequestsFromBody() throws SalesforceException {
+        final ApprovalRequest template = new ApprovalRequest();
+        template.setActionType(Action.Submit);
+
+        final ApprovalRequest approvalRequest1 = new ApprovalRequest();
+        approvalRequest1.setComments("it should be me first");
+
+        final ApprovalRequest approvalRequest2 = new ApprovalRequest();
+        approvalRequest2.setComments("it should be me second");
+
+        final TestRestProcessor processor = sendBodyAndHeader(Arrays.asList(approvalRequest1, approvalRequest2),
+                template);
+
+        verify(processor).getRequestStream(new ApprovalRequests(
+                Arrays.asList(approvalRequest1.applyTemplate(template), approvalRequest2.applyTemplate(template))));
+    }
+
+    @Test
+    public void shouldComplainIfNoHeaderGivenOrBodyIsEmptyIterable() {
+        try {
+            sendBodyAndHeader(Collections.EMPTY_LIST, null);
+            fail("SalesforceException should be thrown");
+        } catch (final SalesforceException e) {
+            assertEquals("Exception should be about not giving a body or a header",
+                    "Missing approval parameter in header or ApprovalRequest or List of ApprovalRequests body",
+                    e.getMessage());
+        }
+    }
+
+    @Test
+    public void shouldComplainIfNoHeaderOrBodyIsGiven() {
+        try {
+            sendBodyAndHeader(null, null);
+            fail("SalesforceException should be thrown");
+        } catch (final SalesforceException e) {
+            assertEquals("Exception should be about not giving a body or a header",
+                    "Missing approval parameter in header or ApprovalRequest or List of ApprovalRequests body",
+                    e.getMessage());
+        }
+    }
+
+    @Test
+    public void shouldFetchApprovalRequestFromBody() throws SalesforceException {
+        final ApprovalRequest approvalRequest = new ApprovalRequest();
+        approvalRequest.setComments("it should be me");
+
+        final TestRestProcessor processor = sendBody(approvalRequest);
+
+        verify(processor).getRequestStream(new ApprovalRequests(approvalRequest));
+    }
+
+    @Test
+    public void shouldFetchApprovalRequestFromHeader() throws SalesforceException {
+        final ApprovalRequest request = new ApprovalRequest();
+        request.setComments("hi there");
+        final TestRestProcessor processor = sendBodyAndHeader(null, request);
+
+        verify(processor).getRequestStream(new ApprovalRequests(request));
+    }
+
+    @Test
+    public void shouldFetchApprovalRequestFromHeaderEvenIfBodyIsDefinedButNotConvertable() throws SalesforceException {
+        final ApprovalRequest request = new ApprovalRequest();
+        request.setComments("hi there");
+
+        final TestRestProcessor processor = sendBodyAndHeaders("Nothing to see here", request,
+                Collections.singletonMap("approval.ContextId", "context-id"));
+
+        final ApprovalRequest combined = new ApprovalRequest();
+        combined.setComments("hi there");
+        combined.setContextId("context-id");
+
+        verify(processor).getRequestStream(new ApprovalRequests(combined));
+    }
+
+    @Test
+    public void shouldFetchApprovalRequestsFromBody() throws SalesforceException {
+        final ApprovalRequest approvalRequest1 = new ApprovalRequest();
+        approvalRequest1.setComments("it should be me first");
+
+        final ApprovalRequest approvalRequest2 = new ApprovalRequest();
+        approvalRequest2.setComments("it should be me second");
+
+        final TestRestProcessor processor = sendBody(Arrays.asList(approvalRequest1, approvalRequest2));
+
+        verify(processor).getRequestStream(new ApprovalRequests(Arrays.asList(approvalRequest1, approvalRequest2)));
+    }
+
+    @Test
+    public void shouldFetchApprovalRequestsFromMultiplePropertiesInMessageHeaders() throws SalesforceException {
+        final Map<String, Object> headers = new HashMap<>();
+        headers.put("approval.ContextId", "contextId");
+
+        final TestRestProcessor processor = sendBodyAndHeaders(notUsed(), notUsed(), headers);
+
+        final ApprovalRequest request = new ApprovalRequest();
+        request.setContextId("contextId");
+
+        verify(processor).getRequestStream(new ApprovalRequests(request));
+    }
+
+    @Test
+    public void shouldHonorPriorities() throws SalesforceException {
+        final ApprovalRequest template = new ApprovalRequest();
+        template.setComments("third priority");
+
+        final ApprovalRequest body = new ApprovalRequest();
+        body.setComments("first priority");
+
+        final Map<String, Object> headers = Collections.singletonMap("approval.Comments", "second priority");
+
+        final TestRestProcessor processor1 = sendBodyAndHeaders(null, template, null);
+
+        verify(processor1).getRequestStream(new ApprovalRequests(requestWithComment("third priority")));
+
+        final TestRestProcessor processor2 = sendBodyAndHeaders(null, template, headers);
+        verify(processor2).getRequestStream(new ApprovalRequests(requestWithComment("second priority")));
+
+        final TestRestProcessor processor3 = sendBodyAndHeaders(body, template, headers);
+        verify(processor3).getRequestStream(new ApprovalRequests(requestWithComment("first priority")));
+    }
+
+    TestRestProcessor sendBody(final Object body) throws SalesforceException {
+        return sendBodyAndHeader(body, null);
+    }
+
+    TestRestProcessor sendBodyAndHeader(final Object body, final ApprovalRequest template) throws SalesforceException {
+        return sendBodyAndHeaders(body, template, Collections.emptyMap());
+    }
+
+    TestRestProcessor sendBodyAndHeaders(final Object body, final ApprovalRequest template,
+            final Map<String, Object> headers) throws SalesforceException {
+        final TestRestProcessor processor = spy(new TestRestProcessor());
+
+        final CamelContext context = new DefaultCamelContext();
+        final Exchange exchange = new DefaultExchange(context);
+
+        final Message message = new DefaultMessage();
+        if (headers != null) {
+            message.setHeaders(headers);
+        }
+        message.setHeader(SalesforceEndpointConfig.APPROVAL, template);
+
+        message.setBody(body);
+
+        exchange.setIn(message);
+
+        processor.processApproval(exchange, notUsed());
+
+        return processor;
+    }
+}