[ https://issues.apache.org/jira/browse/CAMEL-11919?page=com.atlassian.jira.plugin.system.issuetabpanels:comment-tabpanel&focusedCommentId=16223315#comment-16223315 ]
ASF GitHub Bot commented on CAMEL-11919: ---------------------------------------- zregvart closed pull request #2047: CAMEL-11919 Adding new feature URL: https://github.com/apache/camel/pull/2047 This is a PR merged from a forked repository. As GitHub hides the original diff on merge, it is displayed below for the sake of provenance: As this is a foreign pull request (from a fork), the diff is supplied below (as it won't show otherwise due to GitHub magic): diff --git a/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 01a0f29303d..14f12db7326 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 @@ -226,7 +226,12 @@ public void getSObject(String sObjectName, String id, String[] fields, } @Override - public void createSObject(String sObjectName, InputStream sObject, + public void createSObject(String sObjectName, InputStream sObject, ResponseCallback callback) { + createSObject(sObjectName, null, sObject, callback); + } + + @Override + public void createSObject(String sObjectName, Map<String, Object> sfHeaders, InputStream sObject, ResponseCallback callback) { // post the sObject final Request post = getRequest(HttpMethod.POST, sobjectsUrl(sObjectName)); @@ -237,12 +242,22 @@ public void createSObject(String sObjectName, InputStream sObject, // input stream as entity content post.content(new InputStreamContentProvider(sObject)); post.header(HttpHeader.CONTENT_TYPE, PayloadFormat.JSON.equals(format) ? APPLICATION_JSON_UTF8 : APPLICATION_XML_UTF8); - + if (sfHeaders != null) { + sfHeaders.forEach((key, value) -> { + post.header(key, value.toString()); + }); + } doHttpRequest(post, new DelegatingClientCallback(callback)); } @Override public void updateSObject(String sObjectName, String id, InputStream sObject, + ResponseCallback callback) { + updateSObject(sObjectName, id, null, sObject, callback); + } + + @Override + public void updateSObject(String sObjectName, String id, Map<String, Object> sfHeaders, InputStream sObject, ResponseCallback callback) { final Request patch = getRequest("PATCH", sobjectsUrl(sObjectName + "/" + id)); // requires authorization token @@ -251,7 +266,11 @@ public void updateSObject(String sObjectName, String id, InputStream sObject, // input stream as entity content patch.content(new InputStreamContentProvider(sObject)); patch.header(HttpHeader.CONTENT_TYPE, PayloadFormat.JSON.equals(format) ? APPLICATION_JSON_UTF8 : APPLICATION_XML_UTF8); - + if (sfHeaders != null) { + sfHeaders.forEach((key, value) -> { + patch.header(key, value.toString()); + }); + } doHttpRequest(patch, new DelegatingClientCallback(callback)); } @@ -279,7 +298,7 @@ public void getSObjectWithId(String sObjectName, String fieldName, String fieldV } @Override - public void upsertSObject(String sObjectName, String fieldName, String fieldValue, InputStream sObject, + public void upsertSObject(String sObjectName, String fieldName, String fieldValue, Map<String, Object> sfHeaders, InputStream sObject, ResponseCallback callback) { final Request patch = getRequest("PATCH", sobjectsExternalIdUrl(sObjectName, fieldName, fieldValue)); @@ -291,7 +310,11 @@ public void upsertSObject(String sObjectName, String fieldName, String fieldValu patch.content(new InputStreamContentProvider(sObject)); // TODO will the encoding always be UTF-8?? patch.header(HttpHeader.CONTENT_TYPE, PayloadFormat.JSON.equals(format) ? APPLICATION_JSON_UTF8 : APPLICATION_XML_UTF8); - + if (sfHeaders != null) { + sfHeaders.forEach((key, value) -> { + patch.header(key, value.toString()); + }); + } doHttpRequest(patch, new DelegatingClientCallback(callback)); } @@ -319,9 +342,14 @@ public void getBlobField(String sObjectName, String id, String blobFieldName, Re doHttpRequest(get, new DelegatingClientCallback(callback)); } - + @Override public void query(String soqlQuery, ResponseCallback callback) { + query(soqlQuery, null, callback); + } + + @Override + public void query(String soqlQuery, Map<String, Object> sfHeaders, ResponseCallback callback) { try { String encodedQuery = urlEncode(soqlQuery); @@ -329,7 +357,13 @@ public void query(String soqlQuery, ResponseCallback callback) { // requires authorization token setAccessToken(get); - + + if (sfHeaders != null) { + sfHeaders.forEach((key, value) -> { + get.header(key, value.toString()); + }); + } + doHttpRequest(get, new DelegatingClientCallback(callback)); } catch (UnsupportedEncodingException e) { @@ -339,17 +373,23 @@ public void query(String soqlQuery, ResponseCallback callback) { } @Override - public void queryMore(String nextRecordsUrl, ResponseCallback callback) { + public void queryMore(String nextRecordsUrl, Map<String, Object> sfHeaders, ResponseCallback callback) { final Request get = getRequest(HttpMethod.GET, instanceUrl + nextRecordsUrl); // requires authorization token setAccessToken(get); + if (sfHeaders != null) { + sfHeaders.forEach((key, value) -> { + get.header(key, value.toString()); + }); + } + doHttpRequest(get, new DelegatingClientCallback(callback)); } @Override - public void queryAll(String soqlQuery, ResponseCallback callback) { + public void queryAll(String soqlQuery, Map<String, Object> sfHeaders, ResponseCallback callback) { try { String encodedQuery = urlEncode(soqlQuery); @@ -358,6 +398,12 @@ public void queryAll(String soqlQuery, ResponseCallback callback) { // requires authorization token setAccessToken(get); + if (sfHeaders != null) { + sfHeaders.forEach((key, value) -> { + get.header(key, value.toString()); + }); + } + doHttpRequest(get, new DelegatingClientCallback(callback)); } catch (UnsupportedEncodingException e) { 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 1304c4bc787..c404c4cba3f 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 @@ -81,6 +81,7 @@ * @param sObject request entity * @param callback {@link ResponseCallback} to handle response or exception */ + void createSObject(String sObjectName, Map<String, Object> sfHeaders, InputStream sObject, ResponseCallback callback); void createSObject(String sObjectName, InputStream sObject, ResponseCallback callback); /** @@ -91,6 +92,7 @@ * @param sObject request entity * @param callback {@link ResponseCallback} to handle response or exception */ + void updateSObject(String sObjectName, String id, Map<String, Object> sfHeaders, InputStream sObject, ResponseCallback callback); void updateSObject(String sObjectName, String id, InputStream sObject, ResponseCallback callback); /** @@ -121,8 +123,8 @@ * @param sObject input object to insert or update * @param callback {@link ResponseCallback} to handle response or exception */ - void upsertSObject(String sObjectName, - String fieldName, String fieldValue, InputStream sObject, ResponseCallback callback); + void upsertSObject(String sObjectName, String fieldName, String fieldValue, + Map<String, Object> sfHeaders, InputStream sObject, ResponseCallback callback); /** * Deletes a record based on the value of a specified external ID field. @@ -156,6 +158,7 @@ void deleteSObjectWithId(String sObjectName, * @param soqlQuery SOQL query * @param callback {@link ResponseCallback} to handle response or exception */ + void query(String soqlQuery, Map<String, Object> sfHeaders, ResponseCallback callback); void query(String soqlQuery, ResponseCallback callback); /** @@ -164,7 +167,7 @@ void deleteSObjectWithId(String sObjectName, * @param nextRecordsUrl URL for next records to fetch, returned by query() * @param callback {@link ResponseCallback} to handle response or exception */ - void queryMore(String nextRecordsUrl, ResponseCallback callback); + void queryMore(String nextRecordsUrl, Map<String, Object> sfHeaders, ResponseCallback callback); /** * Executes the specified SOQL query including deleted records. @@ -172,7 +175,7 @@ void deleteSObjectWithId(String sObjectName, * @param soqlQuery SOQL query * @param callback {@link ResponseCallback} to handle response or exception */ - void queryAll(String soqlQuery, ResponseCallback callback); + void queryAll(String soqlQuery, Map<String, Object> sfHeaders, ResponseCallback callback); /** * Executes the specified SOSL search. 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 0961b347bcb..6836bc4d5ca 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 @@ -388,13 +388,19 @@ private void processCreateSobject(final Exchange exchange, final AsyncCallback c String sObjectName; // determine parameters from input AbstractSObject AbstractSObjectBase sObjectBase = exchange.getIn().getBody(AbstractSObjectBase.class); + + // determine if there are headers set from the client + final Map<String, Object> sfHeaders; + if (sObjectBase != null) { sObjectName = sObjectBase.getClass().getSimpleName(); + sfHeaders = getHeaders(sObjectName, exchange, "CREATE"); } else { sObjectName = getParameter(SOBJECT_NAME, exchange, IGNORE_BODY, NOT_OPTIONAL); + sfHeaders = getHeaders(sObjectName, exchange, "CREATE"); } - restClient.createSObject(sObjectName, getRequestStream(exchange), + restClient.createSObject(sObjectName, sfHeaders, getRequestStream(exchange), new RestClient.ResponseCallback() { @Override public void onResponse(InputStream response, SalesforceException exception) { @@ -407,20 +413,27 @@ private void processUpdateSobject(final Exchange exchange, final AsyncCallback c String sObjectName; // determine parameters from input AbstractSObject final AbstractSObjectBase sObjectBase = exchange.getIn().getBody(AbstractSObjectBase.class); + + // determine if there are headers set from the client + final Map<String, Object> sfHeaders; + String sObjectId; if (sObjectBase != null) { sObjectName = sObjectBase.getClass().getSimpleName(); // remember the sObject Id sObjectId = sObjectBase.getId(); + // remember the client header values + sfHeaders = getHeaders(sObjectName, exchange, "UPDATE"); // clear base object fields, which cannot be updated sObjectBase.clearBaseFields(); } else { sObjectName = getParameter(SOBJECT_NAME, exchange, IGNORE_BODY, NOT_OPTIONAL); sObjectId = getParameter(SOBJECT_ID, exchange, IGNORE_BODY, NOT_OPTIONAL); + sfHeaders = getHeaders(sObjectName, exchange, "UPDATE"); } final String finalsObjectId = sObjectId; - restClient.updateSObject(sObjectName, sObjectId, getRequestStream(exchange), + restClient.updateSObject(sObjectName, sObjectId, sfHeaders, getRequestStream(exchange), new RestClient.ResponseCallback() { @Override public void onResponse(InputStream response, SalesforceException exception) { @@ -494,19 +507,26 @@ private void processUpsertSobject(final Exchange exchange, final AsyncCallback c // determine parameters from input AbstractSObject Object oldValue = null; final AbstractSObjectBase sObjectBase = exchange.getIn().getBody(AbstractSObjectBase.class); + + // determine if there are headers set from the client + final Map<String, Object> sfHeaders; + if (sObjectBase != null) { sObjectName = sObjectBase.getClass().getSimpleName(); oldValue = getAndClearPropertyValue(sObjectBase, sObjectExtIdName); sObjectExtIdValue = oldValue.toString(); + // remember the client header values + sfHeaders = getHeaders(sObjectName, exchange, "UPSERT"); // clear base object fields, which cannot be updated sObjectBase.clearBaseFields(); } else { sObjectName = getParameter(SOBJECT_NAME, exchange, IGNORE_BODY, NOT_OPTIONAL); sObjectExtIdValue = getParameter(SOBJECT_EXT_ID_VALUE, exchange, IGNORE_BODY, NOT_OPTIONAL); + sfHeaders = getHeaders(sObjectName, exchange, "UPSERT"); } final Object finalOldValue = oldValue; - restClient.upsertSObject(sObjectName, sObjectExtIdName, sObjectExtIdValue, getRequestStream(exchange), + restClient.upsertSObject(sObjectName, sObjectExtIdName, sObjectExtIdValue, sfHeaders, getRequestStream(exchange), new RestClient.ResponseCallback() { @Override public void onResponse(InputStream response, SalesforceException exception) { @@ -577,8 +597,14 @@ private void processQuery(final Exchange exchange, final AsyncCallback callback) // use custom response class property setResponseClass(exchange, null); - - restClient.query(sObjectQuery, new RestClient.ResponseCallback() { + + // determine if there are headers set from the client + final Map<String, Object> sfHeaders; + + //remember the client header values + sfHeaders = getHeaders(null, exchange, "QUERY"); + + restClient.query(sObjectQuery, sfHeaders, new RestClient.ResponseCallback() { @Override public void onResponse(InputStream response, SalesforceException exception) { processResponse(exchange, response, exception, callback); @@ -592,8 +618,14 @@ private void processQueryMore(final Exchange exchange, final AsyncCallback callb // use custom response class property setResponseClass(exchange, null); - - restClient.queryMore(nextRecordsUrl, new RestClient.ResponseCallback() { + + // determine if there are headers set from the client + final Map<String, Object> sfHeaders; + + //remember the client header values + sfHeaders = getHeaders(null, exchange, "QUERYMORE"); + + restClient.queryMore(nextRecordsUrl, sfHeaders, new RestClient.ResponseCallback() { @Override public void onResponse(InputStream response, SalesforceException exception) { processResponse(exchange, response, exception, callback); @@ -606,8 +638,14 @@ private void processQueryAll(final Exchange exchange, final AsyncCallback callba // use custom response class property setResponseClass(exchange, null); - - restClient.queryAll(sObjectQuery, new RestClient.ResponseCallback() { + + // determine if there are headers set from the client + final Map<String, Object> sfHeaders; + + //remember the client header values + sfHeaders = getHeaders(null, exchange, "QUERYMORE"); + + restClient.queryAll(sObjectQuery, sfHeaders, new RestClient.ResponseCallback() { @Override public void onResponse(InputStream response, SalesforceException exception) { processResponse(exchange, response, exception, callback); diff --git a/components/camel-salesforce/camel-salesforce-component/src/main/java/org/apache/camel/component/salesforce/internal/processor/AbstractSalesforceProcessor.java b/components/camel-salesforce/camel-salesforce-component/src/main/java/org/apache/camel/component/salesforce/internal/processor/AbstractSalesforceProcessor.java index 2b5119ec15e..dd4c08e5fdb 100644 --- a/components/camel-salesforce/camel-salesforce-component/src/main/java/org/apache/camel/component/salesforce/internal/processor/AbstractSalesforceProcessor.java +++ b/components/camel-salesforce/camel-salesforce-component/src/main/java/org/apache/camel/component/salesforce/internal/processor/AbstractSalesforceProcessor.java @@ -16,7 +16,12 @@ */ package org.apache.camel.component.salesforce.internal.processor; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.HashMap; +import java.util.List; import java.util.Map; +import java.util.stream.Collectors; import org.apache.camel.AsyncCallback; import org.apache.camel.Exchange; @@ -33,6 +38,25 @@ public abstract class AbstractSalesforceProcessor implements SalesforceProcessor { + public static final String ACCOUNT_OBJECT_NAME = "Account"; + public static final String CASE_OBJECT_NAME = "Case"; + public static final String LEAD_OBJECT_NAME = "Lead"; + // to be continued + + public static final String HEADER_SFORCE_AUTO_ASSIGN = "Sforce-Auto-Assign"; + public static final String HEADER_SFORCE_QUERY_OPTIONS = "Sforce-Query-Options"; + // to be continued + + public static final String OPERATION_CREATE = "CREATE"; + public static final String OPERATION_QUERY = "QUERY"; + public static final String OPERATION_QUERYALL = "QUERYALL"; + public static final String OPERATION_QUERYMORE = "QUERYMORE"; + public static final String OPERATION_UPDATE = "UPDATE"; + public static final String OPERATION_UPSERT = "UPSERT"; + // to be continued + + public static final HashMap<Object, String[]> HEADERMAP = new HashMap<Object, String[]>(); + protected static final boolean NOT_OPTIONAL = false; protected static final boolean IS_OPTIONAL = true; protected static final boolean USE_BODY = true; @@ -46,9 +70,25 @@ protected final OperationName operationName; protected final SalesforceSession session; protected final SalesforceHttpClient httpClient; - protected final boolean rawPayload; - - public AbstractSalesforceProcessor(SalesforceEndpoint endpoint) { + protected final boolean rawPayload; + + static { + HEADERMAP.put(OPERATION_UPSERT + "-" + ACCOUNT_OBJECT_NAME, new String[] {HEADER_SFORCE_AUTO_ASSIGN}); + HEADERMAP.put(OPERATION_UPSERT + "-" + CASE_OBJECT_NAME, new String[] {HEADER_SFORCE_AUTO_ASSIGN}); + HEADERMAP.put(OPERATION_UPSERT + "-" + LEAD_OBJECT_NAME, new String[] {HEADER_SFORCE_AUTO_ASSIGN}); + HEADERMAP.put(OPERATION_UPDATE + "-" + ACCOUNT_OBJECT_NAME, new String[] {HEADER_SFORCE_AUTO_ASSIGN}); + HEADERMAP.put(OPERATION_UPDATE + "-" + CASE_OBJECT_NAME, new String[] {HEADER_SFORCE_AUTO_ASSIGN}); + HEADERMAP.put(OPERATION_UPDATE + "-" + LEAD_OBJECT_NAME, new String[] {HEADER_SFORCE_AUTO_ASSIGN}); + HEADERMAP.put(OPERATION_CREATE + "-" + ACCOUNT_OBJECT_NAME, new String[] {HEADER_SFORCE_AUTO_ASSIGN}); + HEADERMAP.put(OPERATION_CREATE + "-" + CASE_OBJECT_NAME, new String[] {HEADER_SFORCE_AUTO_ASSIGN}); + HEADERMAP.put(OPERATION_CREATE + "-" + LEAD_OBJECT_NAME, new String[] {HEADER_SFORCE_AUTO_ASSIGN}); + HEADERMAP.put(OPERATION_QUERY, new String[] {HEADER_SFORCE_QUERY_OPTIONS}); + HEADERMAP.put(OPERATION_QUERYALL, new String[] {HEADER_SFORCE_QUERY_OPTIONS}); + HEADERMAP.put(OPERATION_QUERYMORE, new String[] {HEADER_SFORCE_QUERY_OPTIONS}); + // to be continued + } + + public AbstractSalesforceProcessor(SalesforceEndpoint endpoint) { this.endpoint = endpoint; this.operationName = endpoint.getOperationName(); this.endpointConfigMap = endpoint.getConfiguration().toValueMap(); @@ -57,7 +97,25 @@ public AbstractSalesforceProcessor(SalesforceEndpoint endpoint) { this.session = component.getSession(); this.httpClient = endpoint.getConfiguration().getHttpClient(); this.rawPayload = endpoint.getConfiguration().getRawPayload(); + } + + public static List<String> getHeaderKeys(String operation) { + return getHeaderKeys(operation, null); } + + public static List<String> getHeaderKeys(String operation, String sObject) { + List<String> sfHeaders = new ArrayList<String>(); + + if (operation != null) { + try { + sfHeaders = (sObject != null) ? Arrays.asList(HEADERMAP.get(operation + "-" + sObject)) : Arrays.asList(HEADERMAP.get(operation)); + } catch (Exception e) { + return new ArrayList<String>(); + } + } + + return sfHeaders; + } @Override public abstract boolean process(Exchange exchange, AsyncCallback callback); @@ -127,5 +185,14 @@ protected final String getParameter(String propName, Exchange exchange, boolean return propValue; } - + + protected final Map<String, Object> getHeaders(String sObjectName, Exchange exchange, String functionCall) { + Map<String, Object> sfHeader = new HashMap<String, Object>(); + for (String key : getHeaderKeys(functionCall, sObjectName)) { + sfHeader = exchange.getIn().getHeaders().entrySet().stream() + .filter(kv -> kv.getKey().equalsIgnoreCase(key)) + .collect(Collectors.toMap(kv -> key, kv -> kv.getValue())); + } + return sfHeader; + } } ---------------------------------------------------------------- This is an automated message from the Apache Git Service. To respond to the message, please log on GitHub and use the URL above to go to the specific comment. For queries about this service, please contact Infrastructure at: us...@infra.apache.org > Salesforce REST API request headers not included in update,upsert,create and > query operations > --------------------------------------------------------------------------------------------- > > Key: CAMEL-11919 > URL: https://issues.apache.org/jira/browse/CAMEL-11919 > Project: Camel > Issue Type: Improvement > Components: camel-salesforce > Affects Versions: 2.20.0 > Reporter: Dicken George > Assignee: Zoran Regvart > Fix For: 2.21.0 > > > There few Salesforce Rest API Http-Header parameters as decribed here. > https://developer.salesforce.com/docs/atlas.en-us.api_rest.meta/api_rest/headers.htm > Sforce-Auto-Assign > Sfore-Query-Options > Sforce-Call-Options > x-sfdc-packageversion-[namespace] > and > Sforce-Limit-Info : This is part of the SFDC response header. > Out of these four, the "Sforce-Auto-Assign" header perform am implicit chain > reaction in salesforce which causes unwanted repercussions which in certain > operations needs to be controlled. For example, one of the issues,we have > noticed, is that during an update operation if this header is not set to > "FALSE", salesforce automatically updates the ownerID of the record although > it was not included in the request. There are other side effects which we are > currently not aware of. Therefore, the client would need the possibility to > set this header parameter within their request to True or False manually. > However, currently only the approval requests accept these http headers from > the client request, and we have found that it needs to be included in the > update, upsert and create queries as well. > Sfore-Query-Options : this header is valid for query operations, in order to > set the batchsize of your query response. We have implemented this as well > since it could come in handy which performing batch / bulk queries. > For the time being we have implemented only these two header parameters in > the camel-salesforce project, however in the future the other two or all > three headers could also be include with camel-salesforce to customization. -- This message was sent by Atlassian JIRA (v6.4.14#64029)