This is an automated email from the ASF dual-hosted git repository.

davsclaus pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/camel.git


The following commit(s) were added to refs/heads/master by this push:
     new f4bd41a  [CAMEL-15757] Add rawPayload support on camel-salesforce 
composite (#4514)
f4bd41a is described below

commit f4bd41a360fc29b0472a8936e041ddf67cbb7edc
Author: Jean-Baptiste Onofré <[email protected]>
AuthorDate: Wed Dec 9 18:07:44 2020 +0100

    [CAMEL-15757] Add rawPayload support on camel-salesforce composite (#4514)
---
 .../camel/catalog/docs/salesforce-component.adoc   |  6 ++-
 .../salesforce/SalesforceComponentConfigurer.java  |  6 +++
 .../salesforce/SalesforceEndpointConfigurer.java   |  6 +++
 .../salesforce/SalesforceEndpointUriFactory.java   |  3 +-
 .../camel/component/salesforce/salesforce.json     |  2 +
 .../src/main/docs/salesforce-component.adoc        | 35 ++++++++++++--
 .../salesforce/SalesforceEndpointConfig.java       | 17 ++++++-
 .../internal/client/CompositeApiClient.java        |  6 +++
 .../internal/client/DefaultCompositeApiClient.java | 35 ++++++++++++++
 .../internal/processor/CompositeApiProcessor.java  | 56 +++++++++++++++++++++-
 .../camel/component/salesforce/RawPayloadTest.java | 11 ++++-
 .../dsl/SalesforceComponentBuilderFactory.java     | 13 +++++
 .../dsl/SalesforceEndpointBuilderFactory.java      | 35 ++++++++++++++
 .../modules/ROOT/pages/salesforce-component.adoc   |  6 ++-
 14 files changed, 224 insertions(+), 13 deletions(-)

diff --git 
a/catalog/camel-catalog/src/generated/resources/org/apache/camel/catalog/docs/salesforce-component.adoc
 
b/catalog/camel-catalog/src/generated/resources/org/apache/camel/catalog/docs/salesforce-component.adoc
index 6747737..7d048fe 100644
--- 
a/catalog/camel-catalog/src/generated/resources/org/apache/camel/catalog/docs/salesforce-component.adoc
+++ 
b/catalog/camel-catalog/src/generated/resources/org/apache/camel/catalog/docs/salesforce-component.adoc
@@ -656,7 +656,7 @@ for details on how to generate the DTO.
 
 
 // component options: START
-The Salesforce component supports 73 options, which are listed below.
+The Salesforce component supports 74 options, which are listed below.
 
 
 
@@ -669,6 +669,7 @@ The Salesforce component supports 73 options, which are 
listed below.
 | *apiVersion* (common) | Salesforce API version. | 50.0 | String
 | *backoffIncrement* (common) | Backoff interval increment for Streaming 
connection restart attempts for failures beyond CometD auto-reconnect. | 1000 | 
long
 | *batchId* (common) | Bulk API Batch ID |  | String
+| *compositeMethod* (common) | Composite (raw) method. |  | String
 | *contentType* (common) | Bulk API content type, one of XML, CSV, ZIP_XML, 
ZIP_CSV. There are 6 enums and the value can be one of: XML, CSV, JSON, 
ZIP_XML, ZIP_CSV, ZIP_JSON |  | ContentType
 | *defaultReplayId* (common) | Default replayId setting if no value is found 
in initialReplayIdMap | -1 | Long
 | *format* (common) | Payload format to use for Salesforce API calls, either 
JSON or XML, defaults to JSON. There are 2 enums and the value can be one of: 
JSON, XML |  | PayloadFormat
@@ -768,7 +769,7 @@ with the following path and query parameters:
 |===
 
 
-=== Query Parameters (44 parameters):
+=== Query Parameters (45 parameters):
 
 
 [width="100%",cols="2,5,^1,2",options="header"]
@@ -780,6 +781,7 @@ with the following path and query parameters:
 | *apiVersion* (common) | Salesforce API version. | 50.0 | String
 | *backoffIncrement* (common) | Backoff interval increment for Streaming 
connection restart attempts for failures beyond CometD auto-reconnect. | 1000 | 
long
 | *batchId* (common) | Bulk API Batch ID |  | String
+| *compositeMethod* (common) | Composite (raw) method. |  | String
 | *contentType* (common) | Bulk API content type, one of XML, CSV, ZIP_XML, 
ZIP_CSV. There are 6 enums and the value can be one of: XML, CSV, JSON, 
ZIP_XML, ZIP_CSV, ZIP_JSON |  | ContentType
 | *defaultReplayId* (common) | Default replayId setting if no value is found 
in initialReplayIdMap | -1 | Long
 | *format* (common) | Payload format to use for Salesforce API calls, either 
JSON or XML, defaults to JSON. There are 2 enums and the value can be one of: 
JSON, XML |  | PayloadFormat
diff --git 
a/components/camel-salesforce/camel-salesforce-component/src/generated/java/org/apache/camel/component/salesforce/SalesforceComponentConfigurer.java
 
b/components/camel-salesforce/camel-salesforce-component/src/generated/java/org/apache/camel/component/salesforce/SalesforceComponentConfigurer.java
index c912d1d..440be38 100644
--- 
a/components/camel-salesforce/camel-salesforce-component/src/generated/java/org/apache/camel/component/salesforce/SalesforceComponentConfigurer.java
+++ 
b/components/camel-salesforce/camel-salesforce-component/src/generated/java/org/apache/camel/component/salesforce/SalesforceComponentConfigurer.java
@@ -50,6 +50,8 @@ public class SalesforceComponentConfigurer extends 
PropertyConfigurerSupport imp
         case "clientId": target.setClientId(property(camelContext, 
java.lang.String.class, value)); return true;
         case "clientsecret":
         case "clientSecret": target.setClientSecret(property(camelContext, 
java.lang.String.class, value)); return true;
+        case "compositemethod":
+        case "compositeMethod": 
getOrCreateConfig(target).setCompositeMethod(property(camelContext, 
java.lang.String.class, value)); return true;
         case "config": target.setConfig(property(camelContext, 
org.apache.camel.component.salesforce.SalesforceEndpointConfig.class, value)); 
return true;
         case "contenttype":
         case "contentType": 
getOrCreateConfig(target).setContentType(property(camelContext, 
org.apache.camel.component.salesforce.api.dto.bulk.ContentType.class, value)); 
return true;
@@ -197,6 +199,8 @@ public class SalesforceComponentConfigurer extends 
PropertyConfigurerSupport imp
         case "clientId": return java.lang.String.class;
         case "clientsecret":
         case "clientSecret": return java.lang.String.class;
+        case "compositemethod":
+        case "compositeMethod": return java.lang.String.class;
         case "config": return 
org.apache.camel.component.salesforce.SalesforceEndpointConfig.class;
         case "contenttype":
         case "contentType": return 
org.apache.camel.component.salesforce.api.dto.bulk.ContentType.class;
@@ -345,6 +349,8 @@ public class SalesforceComponentConfigurer extends 
PropertyConfigurerSupport imp
         case "clientId": return target.getClientId();
         case "clientsecret":
         case "clientSecret": return target.getClientSecret();
+        case "compositemethod":
+        case "compositeMethod": return 
getOrCreateConfig(target).getCompositeMethod();
         case "config": return target.getConfig();
         case "contenttype":
         case "contentType": return getOrCreateConfig(target).getContentType();
diff --git 
a/components/camel-salesforce/camel-salesforce-component/src/generated/java/org/apache/camel/component/salesforce/SalesforceEndpointConfigurer.java
 
b/components/camel-salesforce/camel-salesforce-component/src/generated/java/org/apache/camel/component/salesforce/SalesforceEndpointConfigurer.java
index 92c3e28..5487a30 100644
--- 
a/components/camel-salesforce/camel-salesforce-component/src/generated/java/org/apache/camel/component/salesforce/SalesforceEndpointConfigurer.java
+++ 
b/components/camel-salesforce/camel-salesforce-component/src/generated/java/org/apache/camel/component/salesforce/SalesforceEndpointConfigurer.java
@@ -35,6 +35,8 @@ public class SalesforceEndpointConfigurer extends 
PropertyConfigurerSupport impl
         case "batchId": 
target.getConfiguration().setBatchId(property(camelContext, 
java.lang.String.class, value)); return true;
         case "bridgeerrorhandler":
         case "bridgeErrorHandler": 
target.setBridgeErrorHandler(property(camelContext, boolean.class, value)); 
return true;
+        case "compositemethod":
+        case "compositeMethod": 
target.getConfiguration().setCompositeMethod(property(camelContext, 
java.lang.String.class, value)); return true;
         case "contenttype":
         case "contentType": 
target.getConfiguration().setContentType(property(camelContext, 
org.apache.camel.component.salesforce.api.dto.bulk.ContentType.class, value)); 
return true;
         case "defaultreplayid":
@@ -127,6 +129,8 @@ public class SalesforceEndpointConfigurer extends 
PropertyConfigurerSupport impl
         case "batchId": return java.lang.String.class;
         case "bridgeerrorhandler":
         case "bridgeErrorHandler": return boolean.class;
+        case "compositemethod":
+        case "compositeMethod": return java.lang.String.class;
         case "contenttype":
         case "contentType": return 
org.apache.camel.component.salesforce.api.dto.bulk.ContentType.class;
         case "defaultreplayid":
@@ -220,6 +224,8 @@ public class SalesforceEndpointConfigurer extends 
PropertyConfigurerSupport impl
         case "batchId": return target.getConfiguration().getBatchId();
         case "bridgeerrorhandler":
         case "bridgeErrorHandler": return target.isBridgeErrorHandler();
+        case "compositemethod":
+        case "compositeMethod": return 
target.getConfiguration().getCompositeMethod();
         case "contenttype":
         case "contentType": return target.getConfiguration().getContentType();
         case "defaultreplayid":
diff --git 
a/components/camel-salesforce/camel-salesforce-component/src/generated/java/org/apache/camel/component/salesforce/SalesforceEndpointUriFactory.java
 
b/components/camel-salesforce/camel-salesforce-component/src/generated/java/org/apache/camel/component/salesforce/SalesforceEndpointUriFactory.java
index 475d102..5d39399 100644
--- 
a/components/camel-salesforce/camel-salesforce-component/src/generated/java/org/apache/camel/component/salesforce/SalesforceEndpointUriFactory.java
+++ 
b/components/camel-salesforce/camel-salesforce-component/src/generated/java/org/apache/camel/component/salesforce/SalesforceEndpointUriFactory.java
@@ -20,7 +20,7 @@ public class SalesforceEndpointUriFactory extends 
org.apache.camel.support.compo
     private static final Set<String> PROPERTY_NAMES;
     private static final Set<String> SECRET_PROPERTY_NAMES;
     static {
-        Set<String> props = new HashSet<>(46);
+        Set<String> props = new HashSet<>(47);
         props.add("initialReplayIdMap");
         props.add("notifyForOperations");
         props.add("synchronous");
@@ -30,6 +30,7 @@ public class SalesforceEndpointUriFactory extends 
org.apache.camel.support.compo
         props.add("notifyForOperationUndelete");
         props.add("sObjectClass");
         props.add("apexUrl");
+        props.add("compositeMethod");
         props.add("apexMethod");
         props.add("updateTopic");
         props.add("apiVersion");
diff --git 
a/components/camel-salesforce/camel-salesforce-component/src/generated/resources/org/apache/camel/component/salesforce/salesforce.json
 
b/components/camel-salesforce/camel-salesforce-component/src/generated/resources/org/apache/camel/component/salesforce/salesforce.json
index 3963932..0374e20 100644
--- 
a/components/camel-salesforce/camel-salesforce-component/src/generated/resources/org/apache/camel/component/salesforce/salesforce.json
+++ 
b/components/camel-salesforce/camel-salesforce-component/src/generated/resources/org/apache/camel/component/salesforce/salesforce.json
@@ -29,6 +29,7 @@
     "apiVersion": { "kind": "property", "displayName": "Api Version", "group": 
"common", "label": "", "required": false, "type": "string", "javaType": 
"java.lang.String", "deprecated": false, "autowired": false, "secret": false, 
"defaultValue": "50.0", "configurationClass": 
"org.apache.camel.component.salesforce.SalesforceEndpointConfig", 
"configurationField": "config", "description": "Salesforce API version." },
     "backoffIncrement": { "kind": "property", "displayName": "Backoff 
Increment", "group": "common", "label": "", "required": false, "type": 
"duration", "javaType": "long", "deprecated": false, "autowired": false, 
"secret": false, "defaultValue": "1000", "configurationClass": 
"org.apache.camel.component.salesforce.SalesforceEndpointConfig", 
"configurationField": "config", "description": "Backoff interval increment for 
Streaming connection restart attempts for failures beyond CometD auto- [...]
     "batchId": { "kind": "property", "displayName": "Batch Id", "group": 
"common", "label": "", "required": false, "type": "string", "javaType": 
"java.lang.String", "deprecated": false, "autowired": false, "secret": false, 
"configurationClass": 
"org.apache.camel.component.salesforce.SalesforceEndpointConfig", 
"configurationField": "config", "description": "Bulk API Batch ID" },
+    "compositeMethod": { "kind": "property", "displayName": "Composite 
Method", "group": "common", "label": "", "required": false, "type": "string", 
"javaType": "java.lang.String", "deprecated": false, "autowired": false, 
"secret": false, "configurationClass": 
"org.apache.camel.component.salesforce.SalesforceEndpointConfig", 
"configurationField": "config", "description": "Composite (raw) method." },
     "contentType": { "kind": "property", "displayName": "Content Type", 
"group": "common", "label": "", "required": false, "type": "object", 
"javaType": "org.apache.camel.component.salesforce.api.dto.bulk.ContentType", 
"enum": [ "XML", "CSV", "JSON", "ZIP_XML", "ZIP_CSV", "ZIP_JSON" ], 
"deprecated": false, "autowired": false, "secret": false, "configurationClass": 
"org.apache.camel.component.salesforce.SalesforceEndpointConfig", 
"configurationField": "config", "description": "Bulk API co [...]
     "defaultReplayId": { "kind": "property", "displayName": "Default Replay 
Id", "group": "common", "label": "", "required": false, "type": "integer", 
"javaType": "java.lang.Long", "deprecated": false, "autowired": false, 
"secret": false, "defaultValue": "-1", "configurationClass": 
"org.apache.camel.component.salesforce.SalesforceEndpointConfig", 
"configurationField": "config", "description": "Default replayId setting if no 
value is found in initialReplayIdMap" },
     "format": { "kind": "property", "displayName": "Format", "group": 
"common", "label": "", "required": false, "type": "object", "javaType": 
"org.apache.camel.component.salesforce.internal.PayloadFormat", "enum": [ 
"JSON", "XML" ], "deprecated": false, "autowired": false, "secret": false, 
"configurationClass": 
"org.apache.camel.component.salesforce.SalesforceEndpointConfig", 
"configurationField": "config", "description": "Payload format to use for 
Salesforce API calls, either JSON or XM [...]
@@ -106,6 +107,7 @@
     "apiVersion": { "kind": "parameter", "displayName": "Api Version", 
"group": "common", "label": "", "required": false, "type": "string", 
"javaType": "java.lang.String", "deprecated": false, "autowired": false, 
"secret": false, "defaultValue": "50.0", "configurationClass": 
"org.apache.camel.component.salesforce.SalesforceEndpointConfig", 
"configurationField": "configuration", "description": "Salesforce API version." 
},
     "backoffIncrement": { "kind": "parameter", "displayName": "Backoff 
Increment", "group": "common", "label": "", "required": false, "type": 
"duration", "javaType": "long", "deprecated": false, "autowired": false, 
"secret": false, "defaultValue": "1000", "configurationClass": 
"org.apache.camel.component.salesforce.SalesforceEndpointConfig", 
"configurationField": "configuration", "description": "Backoff interval 
increment for Streaming connection restart attempts for failures beyond Come 
[...]
     "batchId": { "kind": "parameter", "displayName": "Batch Id", "group": 
"common", "label": "", "required": false, "type": "string", "javaType": 
"java.lang.String", "deprecated": false, "autowired": false, "secret": false, 
"configurationClass": 
"org.apache.camel.component.salesforce.SalesforceEndpointConfig", 
"configurationField": "configuration", "description": "Bulk API Batch ID" },
+    "compositeMethod": { "kind": "parameter", "displayName": "Composite 
Method", "group": "common", "label": "", "required": false, "type": "string", 
"javaType": "java.lang.String", "deprecated": false, "autowired": false, 
"secret": false, "configurationClass": 
"org.apache.camel.component.salesforce.SalesforceEndpointConfig", 
"configurationField": "configuration", "description": "Composite (raw) method." 
},
     "contentType": { "kind": "parameter", "displayName": "Content Type", 
"group": "common", "label": "", "required": false, "type": "object", 
"javaType": "org.apache.camel.component.salesforce.api.dto.bulk.ContentType", 
"enum": [ "XML", "CSV", "JSON", "ZIP_XML", "ZIP_CSV", "ZIP_JSON" ], 
"deprecated": false, "autowired": false, "secret": false, "configurationClass": 
"org.apache.camel.component.salesforce.SalesforceEndpointConfig", 
"configurationField": "configuration", "description": "Bul [...]
     "defaultReplayId": { "kind": "parameter", "displayName": "Default Replay 
Id", "group": "common", "label": "", "required": false, "type": "integer", 
"javaType": "java.lang.Long", "deprecated": false, "autowired": false, 
"secret": false, "defaultValue": "-1", "configurationClass": 
"org.apache.camel.component.salesforce.SalesforceEndpointConfig", 
"configurationField": "configuration", "description": "Default replayId setting 
if no value is found in initialReplayIdMap" },
     "format": { "kind": "parameter", "displayName": "Format", "group": 
"common", "label": "", "required": false, "type": "object", "javaType": 
"org.apache.camel.component.salesforce.internal.PayloadFormat", "enum": [ 
"JSON", "XML" ], "deprecated": false, "autowired": false, "secret": false, 
"configurationClass": 
"org.apache.camel.component.salesforce.SalesforceEndpointConfig", 
"configurationField": "configuration", "description": "Payload format to use 
for Salesforce API calls, either JS [...]
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 6747737..05e92bb 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
@@ -155,7 +155,7 @@ results) using result link returned from the 'query' API
 * recent - fetching recent items
 * approval - submit a record or records (batch) for approval process
 * approvals - fetch a list of all approval processes
-* composite - submit up to 25 possibly related REST requests and receive 
individual responses
+* composite - submit up to 25 possibly related REST requests and receive 
individual responses. It's also possible to use "raw" composite without 
limitation.
 * composite-tree - create up to 200 records with parent-child relationships 
(up to 5 levels) in one go
 * composite-batch - submit a composition of requests in batch
 * queryAll - Runs a SOQL query. It returns the results that are deleted 
because of a merge or delete. Also returns the  information about archived Task 
and Event records.
@@ -602,6 +602,33 @@ final Map<String, ?> accountUpdateBody = 
accountUpdateResult.getBody();
 final SObjectCompositeResult contactCreationResult = results.stream().filter(r 
-> "JunctionRecord".equals(r.getReferenceId())).findFirst().get()
 ----
 
+== Using "raw" Salesforce composite
+
+It's possible to directly call Salesforce composite by preparing the 
Salesforce JSON request in the route thanks to the `rawPayload` option.
+
+For instance, you can have the following route:
+
+----
+from("timer:fire?period=2000").setBody(constant("{\n" +
+     " \"allOrNone\" : true,\n" +
+     " \"records\" : [ { \n" +
+     "   \"attributes\" : {\"type\" : \"FOO\"},\n" +
+     "   \"Name\" : \"123456789\",\n" +
+     "   \"FOO\" : \"XXXX\",\n" +
+     "   \"ACCOUNT\" : 2100.0\n" +
+     "   \"ExternalID\" : \"EXTERNAL\"\n"
+     " }]\n" +
+     "}")
+   
.to("salesforce:composite?rawPayload=true&sObjectName=FOO&sObjectIdName=EXTERNAL&compositeMethod=PATCH")
+   .log("${body}");
+----
+
+The route directly creates the body as JSON and directly submit to salesforce 
endpoint using `rawPayload=true` option.
+
+With this approach, you have the complete control on the Salesforce request.
+
+The `compositeMethod` option allows you to define the Salesforce client method 
style (PATCH, PUT, POST, ...).
+
 ==  Sending null values to salesforce
 
 By default, SObject fields with null values are not sent to salesforce. In 
order to
@@ -656,7 +683,7 @@ for details on how to generate the DTO.
 
 
 // component options: START
-The Salesforce component supports 73 options, which are listed below.
+The Salesforce component supports 74 options, which are listed below.
 
 
 
@@ -669,6 +696,7 @@ The Salesforce component supports 73 options, which are 
listed below.
 | *apiVersion* (common) | Salesforce API version. | 50.0 | String
 | *backoffIncrement* (common) | Backoff interval increment for Streaming 
connection restart attempts for failures beyond CometD auto-reconnect. | 1000 | 
long
 | *batchId* (common) | Bulk API Batch ID |  | String
+| *compositeMethod* (common) | Composite (raw) method. |  | String
 | *contentType* (common) | Bulk API content type, one of XML, CSV, ZIP_XML, 
ZIP_CSV. There are 6 enums and the value can be one of: XML, CSV, JSON, 
ZIP_XML, ZIP_CSV, ZIP_JSON |  | ContentType
 | *defaultReplayId* (common) | Default replayId setting if no value is found 
in initialReplayIdMap | -1 | Long
 | *format* (common) | Payload format to use for Salesforce API calls, either 
JSON or XML, defaults to JSON. There are 2 enums and the value can be one of: 
JSON, XML |  | PayloadFormat
@@ -768,7 +796,7 @@ with the following path and query parameters:
 |===
 
 
-=== Query Parameters (44 parameters):
+=== Query Parameters (45 parameters):
 
 
 [width="100%",cols="2,5,^1,2",options="header"]
@@ -780,6 +808,7 @@ with the following path and query parameters:
 | *apiVersion* (common) | Salesforce API version. | 50.0 | String
 | *backoffIncrement* (common) | Backoff interval increment for Streaming 
connection restart attempts for failures beyond CometD auto-reconnect. | 1000 | 
long
 | *batchId* (common) | Bulk API Batch ID |  | String
+| *compositeMethod* (common) | Composite (raw) method. |  | String
 | *contentType* (common) | Bulk API content type, one of XML, CSV, ZIP_XML, 
ZIP_CSV. There are 6 enums and the value can be one of: XML, CSV, JSON, 
ZIP_XML, ZIP_CSV, ZIP_JSON |  | ContentType
 | *defaultReplayId* (common) | Default replayId setting if no value is found 
in initialReplayIdMap | -1 | Long
 | *format* (common) | Payload format to use for Salesforce API calls, either 
JSON or XML, defaults to JSON. There are 2 enums and the value can be one of: 
JSON, XML |  | PayloadFormat
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 b3a7578..49603f2 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
@@ -61,6 +61,7 @@ public class SalesforceEndpointConfig implements Cloneable {
     public static final String SOBJECT_SEARCH = "sObjectSearch";
     public static final String APEX_METHOD = "apexMethod";
     public static final String APEX_URL = "apexUrl";
+    public static final String COMPOSITE_METHOD = "compositeMethod";
     public static final String LIMIT = "limit";
 
     // prefix for parameters in headers
@@ -125,7 +126,9 @@ public class SalesforceEndpointConfig implements Cloneable {
     private String sObjectSearch;
     @UriParam
     private String apexMethod;
-    @UriParam
+    @UriParam(label = "producer")
+    private String compositeMethod;
+    @UriParam(label = "producer")
     private String apexUrl;
     @UriParam
     private Map<String, Object> apexQueryParams;
@@ -377,6 +380,17 @@ public class SalesforceEndpointConfig implements Cloneable 
{
         this.apexQueryParams = apexQueryParams;
     }
 
+    public String getCompositeMethod() {
+        return compositeMethod;
+    }
+
+    /**
+     * Composite (raw) method.
+     */
+    public void setCompositeMethod(String compositeMethod) {
+        this.compositeMethod = compositeMethod;
+    }
+
     public ApprovalRequest getApproval() {
         return approval;
     }
@@ -616,6 +630,7 @@ public class SalesforceEndpointConfig implements Cloneable {
         valueMap.put(SOBJECT_SEARCH, sObjectSearch);
         valueMap.put(APEX_METHOD, apexMethod);
         valueMap.put(APEX_URL, apexUrl);
+        valueMap.put(COMPOSITE_METHOD, compositeMethod);
         valueMap.put(LIMIT, limit);
         valueMap.put(APPROVAL, approval);
         // apexQueryParams are handled explicitly in AbstractRestProcessor
diff --git 
a/components/camel-salesforce/camel-salesforce-component/src/main/java/org/apache/camel/component/salesforce/internal/client/CompositeApiClient.java
 
b/components/camel-salesforce/camel-salesforce-component/src/main/java/org/apache/camel/component/salesforce/internal/client/CompositeApiClient.java
index 3ca7a18..4621bf9 100644
--- 
a/components/camel-salesforce/camel-salesforce-component/src/main/java/org/apache/camel/component/salesforce/internal/client/CompositeApiClient.java
+++ 
b/components/camel-salesforce/camel-salesforce-component/src/main/java/org/apache/camel/component/salesforce/internal/client/CompositeApiClient.java
@@ -16,6 +16,7 @@
  */
 package org.apache.camel.component.salesforce.internal.client;
 
+import java.io.InputStream;
 import java.util.List;
 import java.util.Map;
 import java.util.Optional;
@@ -42,6 +43,11 @@ public interface CompositeApiClient {
         void onResponse(Optional<T> body, Map<String, String> headers, 
SalesforceException exception);
     }
 
+    void submitCompositeRaw(
+            InputStream raw, Map<String, List<String>> headers, 
ResponseCallback<InputStream> callback,
+            String sObjectName, String extId, String method)
+            throws SalesforceException;
+
     void submitComposite(
             SObjectComposite composite, Map<String, List<String>> headers, 
ResponseCallback<SObjectCompositeResponse> callback)
             throws SalesforceException;
diff --git 
a/components/camel-salesforce/camel-salesforce-component/src/main/java/org/apache/camel/component/salesforce/internal/client/DefaultCompositeApiClient.java
 
b/components/camel-salesforce/camel-salesforce-component/src/main/java/org/apache/camel/component/salesforce/internal/client/DefaultCompositeApiClient.java
index b040875f..530f0ec 100644
--- 
a/components/camel-salesforce/camel-salesforce-component/src/main/java/org/apache/camel/component/salesforce/internal/client/DefaultCompositeApiClient.java
+++ 
b/components/camel-salesforce/camel-salesforce-component/src/main/java/org/apache/camel/component/salesforce/internal/client/DefaultCompositeApiClient.java
@@ -93,6 +93,33 @@ public class DefaultCompositeApiClient extends 
AbstractClientBase implements Com
         xStreamCompositeTree.alias("SObjectTreeResponse", 
SObjectTreeResponse.class);
     }
 
+    public void submitCompositeRaw(
+            final InputStream raw, final Map<String, List<String>> headers,
+            final ResponseCallback<InputStream> callback,
+            final String sObjectName, final String extId, String 
compositeMethod)
+            throws SalesforceException {
+        checkCompositeFormat(format, SObjectComposite.REQUIRED_PAYLOAD_FORMAT);
+
+        final String url = String.format("%s%s/%s/%s/%s", versionUrl(), 
"composite", "sobjects", sObjectName, extId);
+
+        Request request;
+        if (compositeMethod != null) {
+            request = createRequest(compositeMethod, url, headers);
+        } else {
+            request = createRequest(HttpMethod.POST, url, headers);
+        }
+
+        final ContentProvider content = new InputStreamContentProvider(raw);
+        request.content(content);
+
+        doHttpRequest(request, new ClientResponseCallback() {
+            @Override
+            public void onResponse(InputStream response, Map<String, String> 
headers, SalesforceException ex) {
+                callback.onResponse(Optional.of(response), headers, ex);
+            }
+        });
+    }
+
     @Override
     public void submitComposite(
             final SObjectComposite composite, final Map<String, List<String>> 
headers,
@@ -152,9 +179,17 @@ public class DefaultCompositeApiClient extends 
AbstractClientBase implements Com
                         responseHeaders, exception));
     }
 
+    Request createRequest(final String method, final String url, final 
Map<String, List<String>> headers) {
+        final Request request = getRequest(method, url, headers);
+        return populateRequest(request);
+    }
+
     Request createRequest(final HttpMethod method, final String url, final 
Map<String, List<String>> headers) {
         final Request request = getRequest(method, url, headers);
+        return populateRequest(request);
+    }
 
+    private Request populateRequest(Request request) {
         // setup authorization
         setAccessToken(request);
 
diff --git 
a/components/camel-salesforce/camel-salesforce-component/src/main/java/org/apache/camel/component/salesforce/internal/processor/CompositeApiProcessor.java
 
b/components/camel-salesforce/camel-salesforce-component/src/main/java/org/apache/camel/component/salesforce/internal/processor/CompositeApiProcessor.java
index 1d6f00c..1493a47 100644
--- 
a/components/camel-salesforce/camel-salesforce-component/src/main/java/org/apache/camel/component/salesforce/internal/processor/CompositeApiProcessor.java
+++ 
b/components/camel-salesforce/camel-salesforce-component/src/main/java/org/apache/camel/component/salesforce/internal/processor/CompositeApiProcessor.java
@@ -16,6 +16,7 @@
  */
 package org.apache.camel.component.salesforce.internal.processor;
 
+import java.io.InputStream;
 import java.util.EnumSet;
 import java.util.Map;
 import java.util.Optional;
@@ -89,8 +90,13 @@ public final class CompositeApiProcessor extends 
AbstractSalesforceProcessor {
                     return processInternal(SObjectBatch.class, exchange, 
compositeClient::submitCompositeBatch,
                             this::processCompositeBatchResponse, callback);
                 case COMPOSITE:
-                    return processInternal(SObjectComposite.class, exchange, 
compositeClient::submitComposite,
-                            this::processCompositeResponse, callback);
+                    if (rawPayload) {
+                        return processRaw(exchange, compositeClient,
+                                this::processCompositeResponseRaw, callback);
+                    } else {
+                        return processInternal(SObjectComposite.class, 
exchange, compositeClient::submitComposite,
+                                this::processCompositeResponse, callback);
+                    }
                 default:
                     throw new SalesforceException("Unknown operation name: " + 
operationName.value(), null);
             }
@@ -124,6 +130,27 @@ public final class CompositeApiProcessor extends 
AbstractSalesforceProcessor {
         }
     }
 
+    void processCompositeResponseRaw(
+            final Exchange exchange, final Optional<InputStream> responseBody, 
final Map<String, String> headers,
+            final SalesforceException exception, final AsyncCallback callback) 
{
+        try {
+            if (!responseBody.isPresent()) {
+                exchange.setException(exception);
+            } else {
+                final Message in = exchange.getIn();
+                final Message out = exchange.getOut();
+
+                final InputStream response = responseBody.get();
+
+                out.copyFromWithNewBody(in, response);
+                out.getHeaders().putAll(headers);
+            }
+        } finally {
+            // notify callback that exchange is done
+            callback.done(false);
+        }
+    }
+
     void processCompositeResponse(
             final Exchange exchange, final Optional<SObjectCompositeResponse> 
responseBody, final Map<String, String> headers,
             final SalesforceException exception, final AsyncCallback callback) 
{
@@ -207,6 +234,31 @@ public final class CompositeApiProcessor extends 
AbstractSalesforceProcessor {
         return false;
     }
 
+    boolean processRaw(
+            final Exchange exchange, final CompositeApiClient compositeClient,
+            final ResponseHandler<InputStream> responseHandler, final 
AsyncCallback callback)
+            throws SalesforceException {
+        final InputStream body;
+
+        final Message in = exchange.getIn();
+        try {
+            body = in.getMandatoryBody(InputStream.class);
+        } catch (final InvalidPayloadException e) {
+            throw new SalesforceException(e);
+        }
+
+        String sObjectName = 
getParameter(SalesforceEndpointConfig.SOBJECT_NAME, exchange, IGNORE_BODY, 
NOT_OPTIONAL);
+        String extId = 
getParameter(SalesforceEndpointConfig.SOBJECT_EXT_ID_NAME, exchange, 
IGNORE_BODY, NOT_OPTIONAL);
+        String method = 
getParameter(SalesforceEndpointConfig.COMPOSITE_METHOD, exchange, IGNORE_BODY, 
NOT_OPTIONAL);
+
+        compositeClient.submitCompositeRaw(body, determineHeaders(exchange),
+                (response, responseHeaders, exception) -> 
responseHandler.handleResponse(exchange, response, responseHeaders,
+                        exception, callback),
+                sObjectName, extId, method);
+
+        return false;
+    }
+
     static boolean processException(final Exchange exchange, final 
AsyncCallback callback, final Exception e) {
         exchange.setException(e);
         callback.done(true);
diff --git 
a/components/camel-salesforce/camel-salesforce-component/src/test/java/org/apache/camel/component/salesforce/RawPayloadTest.java
 
b/components/camel-salesforce/camel-salesforce-component/src/test/java/org/apache/camel/component/salesforce/RawPayloadTest.java
index 741ef2d6..5d50007 100644
--- 
a/components/camel-salesforce/camel-salesforce-component/src/test/java/org/apache/camel/component/salesforce/RawPayloadTest.java
+++ 
b/components/camel-salesforce/camel-salesforce-component/src/test/java/org/apache/camel/component/salesforce/RawPayloadTest.java
@@ -228,6 +228,13 @@ public class RawPayloadTest extends 
AbstractSalesforceTestBase {
 
                 from("direct:apexCallPatch")
                         
.to("salesforce:apexCall/Merchandise/?rawPayload=true&format=" + format + 
"&apexMethod=PATCH");
+
+                // testComposite (only JSON format is supported)
+                if (format.equalsIgnoreCase("json")) {
+                    from("direct:composite").to(
+                            "salesforce:composite?rawPayload=true&format=" + 
format
+                                                + 
"&sObjectName=foo&sObjectIdName=bar&compositeMethod=PATCH");
+                }
             }
         };
     }
@@ -240,8 +247,8 @@ public class RawPayloadTest extends 
AbstractSalesforceTestBase {
                 "direct:createSObject", "direct:updateSObject", 
"direct:deleteSObject", "direct:getSObjectWithId",
                 "direct:upsertSObject",
                 "direct:deleteSObjectWithId", "direct:getBlobField", 
"direct:query", "direct:queryAll", "direct:search",
-                "direct:apexCallGet",
-                "direct:apexCallGetWithId", "direct:apexCallPatch" };
+                "direct:apexCallGet", "direct:apexCallGetWithId", 
"direct:apexCallPatch",
+                "direct:composite" };
 
         final String[] formats = { "XML", "JSON" };
 
diff --git 
a/core/camel-componentdsl/src/generated/java/org/apache/camel/builder/component/dsl/SalesforceComponentBuilderFactory.java
 
b/core/camel-componentdsl/src/generated/java/org/apache/camel/builder/component/dsl/SalesforceComponentBuilderFactory.java
index ef9c814..218e4f0 100644
--- 
a/core/camel-componentdsl/src/generated/java/org/apache/camel/builder/component/dsl/SalesforceComponentBuilderFactory.java
+++ 
b/core/camel-componentdsl/src/generated/java/org/apache/camel/builder/component/dsl/SalesforceComponentBuilderFactory.java
@@ -123,6 +123,18 @@ public interface SalesforceComponentBuilderFactory {
             return this;
         }
         /**
+         * Composite (raw) method.
+         * 
+         * The option is a: <code>java.lang.String</code> type.
+         * 
+         * Group: common
+         */
+        default SalesforceComponentBuilder compositeMethod(
+                java.lang.String compositeMethod) {
+            doSetProperty("compositeMethod", compositeMethod);
+            return this;
+        }
+        /**
          * Bulk API content type, one of XML, CSV, ZIP_XML, ZIP_CSV.
          * 
          * The option is a:
@@ -1055,6 +1067,7 @@ public interface SalesforceComponentBuilderFactory {
             case "apiVersion": getOrCreateConfiguration((SalesforceComponent) 
component).setApiVersion((java.lang.String) value); return true;
             case "backoffIncrement": 
getOrCreateConfiguration((SalesforceComponent) 
component).setBackoffIncrement((long) value); return true;
             case "batchId": getOrCreateConfiguration((SalesforceComponent) 
component).setBatchId((java.lang.String) value); return true;
+            case "compositeMethod": 
getOrCreateConfiguration((SalesforceComponent) 
component).setCompositeMethod((java.lang.String) value); return true;
             case "contentType": getOrCreateConfiguration((SalesforceComponent) 
component).setContentType((org.apache.camel.component.salesforce.api.dto.bulk.ContentType)
 value); return true;
             case "defaultReplayId": 
getOrCreateConfiguration((SalesforceComponent) 
component).setDefaultReplayId((java.lang.Long) value); return true;
             case "format": getOrCreateConfiguration((SalesforceComponent) 
component).setFormat((org.apache.camel.component.salesforce.internal.PayloadFormat)
 value); return true;
diff --git 
a/core/camel-endpointdsl/src/generated/java/org/apache/camel/builder/endpoint/dsl/SalesforceEndpointBuilderFactory.java
 
b/core/camel-endpointdsl/src/generated/java/org/apache/camel/builder/endpoint/dsl/SalesforceEndpointBuilderFactory.java
index 85dcf69..4921261 100644
--- 
a/core/camel-endpointdsl/src/generated/java/org/apache/camel/builder/endpoint/dsl/SalesforceEndpointBuilderFactory.java
+++ 
b/core/camel-endpointdsl/src/generated/java/org/apache/camel/builder/endpoint/dsl/SalesforceEndpointBuilderFactory.java
@@ -143,6 +143,18 @@ public interface SalesforceEndpointBuilderFactory {
             return this;
         }
         /**
+         * Composite (raw) method.
+         * 
+         * The option is a: <code>java.lang.String</code> type.
+         * 
+         * Group: common
+         */
+        default SalesforceEndpointConsumerBuilder compositeMethod(
+                String compositeMethod) {
+            doSetProperty("compositeMethod", compositeMethod);
+            return this;
+        }
+        /**
          * Bulk API content type, one of XML, CSV, ZIP_XML, ZIP_CSV.
          * 
          * The option is a:
@@ -1064,6 +1076,18 @@ public interface SalesforceEndpointBuilderFactory {
             return this;
         }
         /**
+         * Composite (raw) method.
+         * 
+         * The option is a: <code>java.lang.String</code> type.
+         * 
+         * Group: common
+         */
+        default SalesforceEndpointProducerBuilder compositeMethod(
+                String compositeMethod) {
+            doSetProperty("compositeMethod", compositeMethod);
+            return this;
+        }
+        /**
          * Bulk API content type, one of XML, CSV, ZIP_XML, ZIP_CSV.
          * 
          * The option is a:
@@ -1909,6 +1933,17 @@ public interface SalesforceEndpointBuilderFactory {
             return this;
         }
         /**
+         * Composite (raw) method.
+         * 
+         * The option is a: <code>java.lang.String</code> type.
+         * 
+         * Group: common
+         */
+        default SalesforceEndpointBuilder compositeMethod(String 
compositeMethod) {
+            doSetProperty("compositeMethod", compositeMethod);
+            return this;
+        }
+        /**
          * Bulk API content type, one of XML, CSV, ZIP_XML, ZIP_CSV.
          * 
          * The option is a:
diff --git a/docs/components/modules/ROOT/pages/salesforce-component.adoc 
b/docs/components/modules/ROOT/pages/salesforce-component.adoc
index 34e3bdf9..f93a840 100644
--- a/docs/components/modules/ROOT/pages/salesforce-component.adoc
+++ b/docs/components/modules/ROOT/pages/salesforce-component.adoc
@@ -658,7 +658,7 @@ for details on how to generate the DTO.
 
 
 // component options: START
-The Salesforce component supports 73 options, which are listed below.
+The Salesforce component supports 74 options, which are listed below.
 
 
 
@@ -671,6 +671,7 @@ The Salesforce component supports 73 options, which are 
listed below.
 | *apiVersion* (common) | Salesforce API version. | 50.0 | String
 | *backoffIncrement* (common) | Backoff interval increment for Streaming 
connection restart attempts for failures beyond CometD auto-reconnect. | 1000 | 
long
 | *batchId* (common) | Bulk API Batch ID |  | String
+| *compositeMethod* (common) | Composite (raw) method. |  | String
 | *contentType* (common) | Bulk API content type, one of XML, CSV, ZIP_XML, 
ZIP_CSV. There are 6 enums and the value can be one of: XML, CSV, JSON, 
ZIP_XML, ZIP_CSV, ZIP_JSON |  | ContentType
 | *defaultReplayId* (common) | Default replayId setting if no value is found 
in initialReplayIdMap | -1 | Long
 | *format* (common) | Payload format to use for Salesforce API calls, either 
JSON or XML, defaults to JSON. There are 2 enums and the value can be one of: 
JSON, XML |  | PayloadFormat
@@ -770,7 +771,7 @@ with the following path and query parameters:
 |===
 
 
-=== Query Parameters (44 parameters):
+=== Query Parameters (45 parameters):
 
 
 [width="100%",cols="2,5,^1,2",options="header"]
@@ -782,6 +783,7 @@ with the following path and query parameters:
 | *apiVersion* (common) | Salesforce API version. | 50.0 | String
 | *backoffIncrement* (common) | Backoff interval increment for Streaming 
connection restart attempts for failures beyond CometD auto-reconnect. | 1000 | 
long
 | *batchId* (common) | Bulk API Batch ID |  | String
+| *compositeMethod* (common) | Composite (raw) method. |  | String
 | *contentType* (common) | Bulk API content type, one of XML, CSV, ZIP_XML, 
ZIP_CSV. There are 6 enums and the value can be one of: XML, CSV, JSON, 
ZIP_XML, ZIP_CSV, ZIP_JSON |  | ContentType
 | *defaultReplayId* (common) | Default replayId setting if no value is found 
in initialReplayIdMap | -1 | Long
 | *format* (common) | Payload format to use for Salesforce API calls, either 
JSON or XML, defaults to JSON. There are 2 enums and the value can be one of: 
JSON, XML |  | PayloadFormat

Reply via email to