camel-commits mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From zregv...@apache.org
Subject [4/4] camel git commit: CAMEL-10846 Handle 404 situations more gracefully
Date Mon, 27 Mar 2017 17:27:36 GMT
CAMEL-10846 Handle 404 situations more gracefully


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

Branch: refs/heads/master
Commit: 87dc6fc295c697d3d0c35dd37aa9742264863017
Parents: 285bea2
Author: Zoran Regvart <zregvart@apache.org>
Authored: Mon Mar 27 19:02:38 2017 +0200
Committer: Zoran Regvart <zregvart@apache.org>
Committed: Mon Mar 27 19:25:03 2017 +0200

----------------------------------------------------------------------
 .../src/main/docs/salesforce-component.adoc     |  3 +-
 .../component/salesforce/NotFoundBehaviour.java | 21 +++++++
 .../salesforce/SalesforceEndpointConfig.java    | 21 +++++++
 .../salesforce/api/NoSuchSObjectException.java  | 29 +++++++++
 .../api/SalesforceMultipleChoicesException.java |  6 --
 .../internal/client/AbstractClientBase.java     | 33 ++++++++---
 .../client/DefaultAnalyticsApiClient.java       | 10 +++-
 .../client/DefaultCompositeApiClient.java       | 31 +++++++---
 .../internal/client/DefaultRestClient.java      | 19 +++---
 .../processor/AbstractRestProcessor.java        | 13 +++-
 .../internal/processor/JsonRestProcessor.java   | 23 +++++---
 .../internal/processor/XmlRestProcessor.java    | 23 ++++----
 .../salesforce/NotFoundIntegrationTest.java     | 62 ++++++++++++++++++++
 .../salesforce/RestApiIntegrationTest.java      | 34 +++++------
 .../SalesforceComponentConfiguration.java       | 16 +++++
 15 files changed, 274 insertions(+), 70 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/camel/blob/87dc6fc2/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 322950f..5c856ee 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
@@ -519,7 +519,7 @@ with the following path and query parameters:
 | **topicName** | The name of the topic to use |  | String
 |=======================================================================
 
-#### Query Parameters (41 parameters):
+#### Query Parameters (42 parameters):
 
 [width="100%",cols="2,5,^1,2",options="header"]
 |=======================================================================
@@ -540,6 +540,7 @@ with the following path and query parameters:
 | **jobId** (common) | Bulk API Job ID |  | String
 | **limit** (common) | Limit on number of returned records. Applicable to some of the API
check the Salesforce documentation. |  | Integer
 | **maxBackoff** (common) | Maximum backoff interval for Streaming connection restart attempts
for failures beyond CometD auto-reconnect. |  | long
+| **notFoundBehaviour** (common) | Sets the behaviour of 404 not found status received from
Salesforce API. Should the body be set to NULL link NotFoundBehaviourNULL or should a exception
be signaled on the exchange link NotFoundBehaviourEXCEPTION - the default. |  | NotFoundBehaviour
 | **notifyForFields** (common) | Notify for fields options are ALL REFERENCED SELECT WHERE
|  | NotifyForFieldsEnum
 | **notifyForOperationCreate** (common) | Notify for create operation defaults to false (API
version = 29.0) |  | Boolean
 | **notifyForOperationDelete** (common) | Notify for delete operation defaults to false (API
version = 29.0) |  | Boolean

http://git-wip-us.apache.org/repos/asf/camel/blob/87dc6fc2/components/camel-salesforce/camel-salesforce-component/src/main/java/org/apache/camel/component/salesforce/NotFoundBehaviour.java
----------------------------------------------------------------------
diff --git a/components/camel-salesforce/camel-salesforce-component/src/main/java/org/apache/camel/component/salesforce/NotFoundBehaviour.java
b/components/camel-salesforce/camel-salesforce-component/src/main/java/org/apache/camel/component/salesforce/NotFoundBehaviour.java
new file mode 100644
index 0000000..8f7feec
--- /dev/null
+++ b/components/camel-salesforce/camel-salesforce-component/src/main/java/org/apache/camel/component/salesforce/NotFoundBehaviour.java
@@ -0,0 +1,21 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.camel.component.salesforce;
+
+public enum NotFoundBehaviour {
+    EXCEPTION, NULL
+}

http://git-wip-us.apache.org/repos/asf/camel/blob/87dc6fc2/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 f035449..5363c0c 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
@@ -91,6 +91,8 @@ public class SalesforceEndpointConfig implements Cloneable {
     public static final long DEFAULT_BACKOFF_INCREMENT = 1000L;
     public static final long DEFAULT_MAX_BACKOFF = 30000L;
 
+    public static final String NOT_FOUND_BEHAVIOUR = "notFoundBehaviour";
+
     // general properties
     @UriParam
     private String apiVersion = DEFAULT_VERSION;
@@ -187,6 +189,9 @@ public class SalesforceEndpointConfig implements Cloneable {
     @UriParam
     private Integer limit;
 
+    @UriParam
+    private NotFoundBehaviour notFoundBehaviour = NotFoundBehaviour.EXCEPTION;
+
     public SalesforceEndpointConfig copy() {
         try {
             final SalesforceEndpointConfig copy = (SalesforceEndpointConfig) super.clone();
@@ -614,6 +619,8 @@ public class SalesforceEndpointConfig implements Cloneable {
         valueMap.put(DEFAULT_REPLAY_ID, defaultReplayId);
         valueMap.put(INITIAL_REPLAY_ID_MAP, initialReplayIdMap);
 
+        valueMap.put(NOT_FOUND_BEHAVIOUR, notFoundBehaviour);
+
         return Collections.unmodifiableMap(valueMap);
     }
 
@@ -816,4 +823,18 @@ public class SalesforceEndpointConfig implements Cloneable {
 
         approval.setSkipEntryCriteria(skipEntryCriteria);
     }
+
+    public NotFoundBehaviour getNotFoundBehaviour() {
+        return notFoundBehaviour;
+    }
+
+    /**
+     * Sets the behaviour of 404 not found status received from Salesforce API.
+     * Should the body be set to NULL {@link NotFoundBehaviour#NULL} or should a
+     * exception be signaled on the exchange {@link NotFoundBehaviour#EXCEPTION}
+     * - the default.
+     */
+    public void setNotFoundBehaviour(final NotFoundBehaviour notFoundBehaviour) {
+        this.notFoundBehaviour = notFoundBehaviour;
+    }
 }

http://git-wip-us.apache.org/repos/asf/camel/blob/87dc6fc2/components/camel-salesforce/camel-salesforce-component/src/main/java/org/apache/camel/component/salesforce/api/NoSuchSObjectException.java
----------------------------------------------------------------------
diff --git a/components/camel-salesforce/camel-salesforce-component/src/main/java/org/apache/camel/component/salesforce/api/NoSuchSObjectException.java
b/components/camel-salesforce/camel-salesforce-component/src/main/java/org/apache/camel/component/salesforce/api/NoSuchSObjectException.java
new file mode 100644
index 0000000..2096569
--- /dev/null
+++ b/components/camel-salesforce/camel-salesforce-component/src/main/java/org/apache/camel/component/salesforce/api/NoSuchSObjectException.java
@@ -0,0 +1,29 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.camel.component.salesforce.api;
+
+import java.util.List;
+
+import org.apache.camel.component.salesforce.api.dto.RestError;
+
+public final class NoSuchSObjectException extends SalesforceException {
+
+    public NoSuchSObjectException(final List<RestError> restErrors) {
+        super(restErrors, 404);
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/camel/blob/87dc6fc2/components/camel-salesforce/camel-salesforce-component/src/main/java/org/apache/camel/component/salesforce/api/SalesforceMultipleChoicesException.java
----------------------------------------------------------------------
diff --git a/components/camel-salesforce/camel-salesforce-component/src/main/java/org/apache/camel/component/salesforce/api/SalesforceMultipleChoicesException.java
b/components/camel-salesforce/camel-salesforce-component/src/main/java/org/apache/camel/component/salesforce/api/SalesforceMultipleChoicesException.java
index 8330e5e..b6614ef 100644
--- a/components/camel-salesforce/camel-salesforce-component/src/main/java/org/apache/camel/component/salesforce/api/SalesforceMultipleChoicesException.java
+++ b/components/camel-salesforce/camel-salesforce-component/src/main/java/org/apache/camel/component/salesforce/api/SalesforceMultipleChoicesException.java
@@ -32,10 +32,4 @@ public class SalesforceMultipleChoicesException extends SalesforceException
{
         return choices;
     }
 
-    @Override
-    public void appendFields(StringBuilder builder) {
-        super.appendFields(builder);
-        builder.append(",choices=");
-        builder.append(choices.toString());
-    }
 }

http://git-wip-us.apache.org/repos/asf/camel/blob/87dc6fc2/components/camel-salesforce/camel-salesforce-component/src/main/java/org/apache/camel/component/salesforce/internal/client/AbstractClientBase.java
----------------------------------------------------------------------
diff --git a/components/camel-salesforce/camel-salesforce-component/src/main/java/org/apache/camel/component/salesforce/internal/client/AbstractClientBase.java
b/components/camel-salesforce/camel-salesforce-component/src/main/java/org/apache/camel/component/salesforce/internal/client/AbstractClientBase.java
index 10799f6..af96dcd 100644
--- a/components/camel-salesforce/camel-salesforce-component/src/main/java/org/apache/camel/component/salesforce/internal/client/AbstractClientBase.java
+++ b/components/camel-salesforce/camel-salesforce-component/src/main/java/org/apache/camel/component/salesforce/internal/client/AbstractClientBase.java
@@ -16,16 +16,26 @@
  */
 package org.apache.camel.component.salesforce.internal.client;
 
+import java.io.IOException;
 import java.io.InputStream;
 import java.nio.ByteBuffer;
 import java.util.ArrayList;
 import java.util.List;
 import java.util.concurrent.TimeUnit;
 
+import com.fasterxml.jackson.core.JsonParseException;
+import com.fasterxml.jackson.databind.JsonMappingException;
+import com.fasterxml.jackson.databind.ObjectMapper;
+import com.thoughtworks.xstream.XStream;
+
 import org.apache.camel.Service;
 import org.apache.camel.component.salesforce.SalesforceHttpClient;
 import org.apache.camel.component.salesforce.api.SalesforceException;
+import org.apache.camel.component.salesforce.api.TypeReferences;
+import org.apache.camel.component.salesforce.api.dto.RestError;
+import org.apache.camel.component.salesforce.internal.PayloadFormat;
 import org.apache.camel.component.salesforce.internal.SalesforceSession;
+import org.apache.camel.component.salesforce.internal.dto.RestErrors;
 import org.eclipse.jetty.client.HttpContentResponse;
 import org.eclipse.jetty.client.api.ContentProvider;
 import org.eclipse.jetty.client.api.ContentResponse;
@@ -167,16 +177,11 @@ public abstract class AbstractClientBase implements SalesforceSession.Salesforce
 
                         }
                     } else if (status < HttpStatus.OK_200 || status >= HttpStatus.MULTIPLE_CHOICES_300)
{
-
                         // Salesforce HTTP failure!
-                        request = (SalesforceHttpRequest) result.getRequest();
-                        final String msg = String.format("Error {%s:%s} executing {%s:%s}",
-                            status, response.getReason(), request.getMethod(), request.getURI());
-                        final SalesforceException cause = createRestException(response, getContentAsInputStream());
+                        final SalesforceException exception = createRestException(response,
getContentAsInputStream());
 
                         // for APIs that return body on status 400, such as Composite API
we need content as well
-                        callback.onResponse(getContentAsInputStream(), new SalesforceException(msg,
response.getStatus(), cause));
-
+                        callback.onResponse(getContentAsInputStream(), exception);
                     } else {
 
                         // Success!!!
@@ -203,6 +208,20 @@ public abstract class AbstractClientBase implements SalesforceSession.Salesforce
         this.instanceUrl = instanceUrl;
     }
 
+    final List<RestError> readErrorsFrom(final InputStream responseContent, final PayloadFormat
format,
+        final ObjectMapper objectMapper, final XStream xStream)
+        throws IOException, JsonParseException, JsonMappingException {
+        final List<RestError> restErrors;
+        if (PayloadFormat.JSON.equals(format)) {
+            restErrors = objectMapper.readValue(responseContent, TypeReferences.REST_ERROR_LIST_TYPE);
+        } else {
+            RestErrors errors = new RestErrors();
+            xStream.fromXML(responseContent, errors);
+            restErrors = errors.getErrors();
+        }
+        return restErrors;
+    }
+
     protected abstract void setAccessToken(Request request);
 
     protected abstract SalesforceException createRestException(Response response, InputStream
responseContent);

http://git-wip-us.apache.org/repos/asf/camel/blob/87dc6fc2/components/camel-salesforce/camel-salesforce-component/src/main/java/org/apache/camel/component/salesforce/internal/client/DefaultAnalyticsApiClient.java
----------------------------------------------------------------------
diff --git a/components/camel-salesforce/camel-salesforce-component/src/main/java/org/apache/camel/component/salesforce/internal/client/DefaultAnalyticsApiClient.java
b/components/camel-salesforce/camel-salesforce-component/src/main/java/org/apache/camel/component/salesforce/internal/client/DefaultAnalyticsApiClient.java
index 96396f8..daf624b 100644
--- a/components/camel-salesforce/camel-salesforce-component/src/main/java/org/apache/camel/component/salesforce/internal/client/DefaultAnalyticsApiClient.java
+++ b/components/camel-salesforce/camel-salesforce-component/src/main/java/org/apache/camel/component/salesforce/internal/client/DefaultAnalyticsApiClient.java
@@ -26,6 +26,7 @@ import com.fasterxml.jackson.core.type.TypeReference;
 import com.fasterxml.jackson.databind.ObjectMapper;
 
 import org.apache.camel.component.salesforce.SalesforceHttpClient;
+import org.apache.camel.component.salesforce.api.NoSuchSObjectException;
 import org.apache.camel.component.salesforce.api.SalesforceException;
 import org.apache.camel.component.salesforce.api.TypeReferences;
 import org.apache.camel.component.salesforce.api.dto.RestError;
@@ -36,12 +37,14 @@ import org.apache.camel.component.salesforce.api.dto.analytics.reports.ReportIns
 import org.apache.camel.component.salesforce.api.dto.analytics.reports.ReportMetadata;
 import org.apache.camel.component.salesforce.api.dto.analytics.reports.SyncReportResults;
 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.eclipse.jetty.client.api.Request;
 import org.eclipse.jetty.client.api.Response;
 import org.eclipse.jetty.client.util.BytesContentProvider;
 import org.eclipse.jetty.http.HttpHeader;
 import org.eclipse.jetty.http.HttpMethod;
+import org.eclipse.jetty.http.HttpStatus;
 import org.eclipse.jetty.util.StringUtil;
 
 /**
@@ -254,7 +257,12 @@ public class DefaultAnalyticsApiClient extends AbstractClientBase implements
Ana
         try {
             if (responseContent != null) {
                 // unmarshal RestError
-                final List<RestError> errors = objectMapper.readValue(responseContent,
TypeReferences.REST_ERROR_LIST_TYPE);
+                final List<RestError> errors = readErrorsFrom(responseContent, PayloadFormat.JSON,
objectMapper, null);
+
+                if (statusCode == HttpStatus.NOT_FOUND_404) {
+                    return new NoSuchSObjectException(errors);
+                }
+
                 return new SalesforceException(errors, statusCode);
             }
         } catch (UnsupportedEncodingException e) {

http://git-wip-us.apache.org/repos/asf/camel/blob/87dc6fc2/components/camel-salesforce/camel-salesforce-component/src/main/java/org/apache/camel/component/salesforce/internal/client/DefaultCompositeApiClient.java
----------------------------------------------------------------------
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 cd85671..1945064 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
@@ -22,6 +22,7 @@ import java.io.IOException;
 import java.io.InputStream;
 import java.io.Writer;
 import java.util.HashMap;
+import java.util.List;
 import java.util.Map;
 import java.util.Optional;
 
@@ -41,8 +42,10 @@ import com.thoughtworks.xstream.io.xml.XppDriver;
 
 import org.apache.camel.component.salesforce.SalesforceEndpointConfig;
 import org.apache.camel.component.salesforce.SalesforceHttpClient;
+import org.apache.camel.component.salesforce.api.NoSuchSObjectException;
 import org.apache.camel.component.salesforce.api.SalesforceException;
 import org.apache.camel.component.salesforce.api.dto.AnnotationFieldKeySorter;
+import org.apache.camel.component.salesforce.api.dto.RestError;
 import org.apache.camel.component.salesforce.api.dto.composite.SObjectBatch;
 import org.apache.camel.component.salesforce.api.dto.composite.SObjectBatchResponse;
 import org.apache.camel.component.salesforce.api.dto.composite.SObjectTree;
@@ -59,6 +62,7 @@ import org.eclipse.jetty.client.api.Response;
 import org.eclipse.jetty.client.util.InputStreamContentProvider;
 import org.eclipse.jetty.http.HttpHeader;
 import org.eclipse.jetty.http.HttpMethod;
+import org.eclipse.jetty.http.HttpStatus;
 import org.eclipse.jetty.util.StringUtil;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
@@ -81,8 +85,8 @@ public class DefaultCompositeApiClient extends AbstractClientBase implements
Com
     private final XStream xStream;
 
     public DefaultCompositeApiClient(final SalesforceEndpointConfig configuration, final
PayloadFormat format,
-            final String version, final SalesforceSession session, final SalesforceHttpClient
httpClient)
-            throws SalesforceException {
+        final String version, final SalesforceSession session, final SalesforceHttpClient
httpClient)
+        throws SalesforceException {
         super(version, session, httpClient);
         this.format = format;
 
@@ -120,7 +124,7 @@ public class DefaultCompositeApiClient extends AbstractClientBase implements
Com
 
     @Override
     public void submitCompositeBatch(final SObjectBatch batch, final ResponseCallback<SObjectBatchResponse>
callback)
-            throws SalesforceException {
+        throws SalesforceException {
         checkCompositeBatchVersion(version, batch.getVersion());
 
         final String url = versionUrl() + "composite/batch";
@@ -136,7 +140,7 @@ public class DefaultCompositeApiClient extends AbstractClientBase implements
Com
 
     @Override
     public void submitCompositeTree(final SObjectTree tree, final ResponseCallback<SObjectTreeResponse>
callback)
-            throws SalesforceException {
+        throws SalesforceException {
         final String url = versionUrl() + "composite/tree/" + tree.getObjectType();
 
         final Request post = createRequest(HttpMethod.POST, url);
@@ -151,10 +155,8 @@ public class DefaultCompositeApiClient extends AbstractClientBase implements
Com
     static void checkCompositeBatchVersion(final String configuredVersion, final Version
batchVersion)
         throws SalesforceException {
         if (Version.create(configuredVersion).compareTo(batchVersion) < 0) {
-            throw new SalesforceException("Component is configured with Salesforce API version
"
-                                          + configuredVersion
-                                          + ", but the payload of the Composite API batch
operation requires at least "
-                                          + batchVersion, 0);
+            throw new SalesforceException("Component is configured with Salesforce API version
" + configuredVersion
+                + ", but the payload of the Composite API batch operation requires at least
" + batchVersion, 0);
         }
     }
 
@@ -263,8 +265,19 @@ public class DefaultCompositeApiClient extends AbstractClientBase implements
Com
 
     @Override
     protected SalesforceException createRestException(final Response response, final InputStream
responseContent) {
-        final String reason = response.getReason();
+        final List<RestError> errors;
+        try {
+            errors = readErrorsFrom(responseContent, format, mapper, xStream);
+        } catch (IOException e) {
+            return new SalesforceException("Unable to read error response", e);
+        }
+
         final int status = response.getStatus();
+        if (status == HttpStatus.NOT_FOUND_404) {
+            return new NoSuchSObjectException(errors);
+        }
+
+        final String reason = response.getReason();
 
         return new SalesforceException("Unexpected error: " + reason, status);
     }

http://git-wip-us.apache.org/repos/asf/camel/blob/87dc6fc2/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 9e190be..e8e38e0 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
@@ -25,10 +25,14 @@ import java.util.List;
 import java.util.Map;
 import java.util.Optional;
 
+import com.fasterxml.jackson.core.JsonParseException;
+import com.fasterxml.jackson.databind.JsonMappingException;
 import com.fasterxml.jackson.databind.ObjectMapper;
 import com.thoughtworks.xstream.XStream;
 
+import org.apache.camel.component.salesforce.NotFoundBehaviour;
 import org.apache.camel.component.salesforce.SalesforceHttpClient;
+import org.apache.camel.component.salesforce.api.NoSuchSObjectException;
 import org.apache.camel.component.salesforce.api.SalesforceException;
 import org.apache.camel.component.salesforce.api.SalesforceMultipleChoicesException;
 import org.apache.camel.component.salesforce.api.TypeReferences;
@@ -59,8 +63,8 @@ public class DefaultRestClient extends AbstractClientBase implements RestClient
     private ObjectMapper objectMapper;
     private XStream xStream;
 
-    public DefaultRestClient(SalesforceHttpClient httpClient, String version, PayloadFormat
format, SalesforceSession session)
-            throws SalesforceException {
+    public DefaultRestClient(final SalesforceHttpClient httpClient, final String version,
final PayloadFormat format,
+        final SalesforceSession session) throws SalesforceException {
         super(version, session, httpClient);
 
         this.format = format;
@@ -109,14 +113,11 @@ public class DefaultRestClient extends AbstractClientBase implements
RestClient
                     }
                     return new SalesforceMultipleChoicesException(reason, statusCode, choices);
                 } else {
-                    final List<RestError> restErrors;
-                    if (PayloadFormat.JSON.equals(format)) {
-                        restErrors = objectMapper.readValue(responseContent, TypeReferences.REST_ERROR_LIST_TYPE);
-                    } else {
-                        RestErrors errors = new RestErrors();
-                        xStream.fromXML(responseContent, errors);
-                        restErrors = errors.getErrors();
+                    final List<RestError> restErrors = readErrorsFrom(responseContent,
format, objectMapper, xStream);
+                    if (statusCode == HttpStatus.NOT_FOUND_404) {
+                        return new NoSuchSObjectException(restErrors);
                     }
+
                     return new SalesforceException(restErrors, statusCode);
                 }
             }

http://git-wip-us.apache.org/repos/asf/camel/blob/87dc6fc2/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 7f4ccea..758cc57 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
@@ -34,8 +34,10 @@ 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.NotFoundBehaviour;
 import org.apache.camel.component.salesforce.SalesforceEndpoint;
 import org.apache.camel.component.salesforce.SalesforceEndpointConfig;
+import org.apache.camel.component.salesforce.api.NoSuchSObjectException;
 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;
@@ -67,10 +69,14 @@ public abstract class AbstractRestProcessor extends AbstractSalesforceProcessor
     private RestClient restClient;
     private Map<String, Class<?>> classMap;
 
+    private final NotFoundBehaviour notFoundBehaviour;
+
     public AbstractRestProcessor(SalesforceEndpoint endpoint) throws SalesforceException
{
         super(endpoint);
 
-        final PayloadFormat payloadFormat = endpoint.getConfiguration().getFormat();
+        final SalesforceEndpointConfig configuration = endpoint.getConfiguration();
+        final PayloadFormat payloadFormat = configuration.getFormat();
+        notFoundBehaviour = configuration.getNotFoundBehaviour();
 
         this.restClient = new DefaultRestClient(httpClient, (String) endpointConfigMap.get(API_VERSION),
                 payloadFormat, session);
@@ -84,6 +90,8 @@ public abstract class AbstractRestProcessor extends AbstractSalesforceProcessor
         super(endpoint);
         this.restClient = restClient;
         this.classMap = classMap;
+        final SalesforceEndpointConfig configuration = endpoint.getConfiguration();
+        notFoundBehaviour = configuration.getNotFoundBehaviour();
     }
 
     @Override
@@ -831,4 +839,7 @@ public abstract class AbstractRestProcessor extends AbstractSalesforceProcessor
     // process response entity and set out message in exchange
     protected abstract void processResponse(Exchange exchange, InputStream responseEntity,
SalesforceException ex, AsyncCallback callback);
 
+    final boolean shouldReport(SalesforceException ex) {
+        return !(ex instanceof NoSuchSObjectException && notFoundBehaviour == NotFoundBehaviour.NULL);
+    }
 }

http://git-wip-us.apache.org/repos/asf/camel/blob/87dc6fc2/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 67a973c..d52601f 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
@@ -27,7 +27,9 @@ import com.fasterxml.jackson.databind.ObjectMapper;
 import org.apache.camel.AsyncCallback;
 import org.apache.camel.Exchange;
 import org.apache.camel.Message;
+import org.apache.camel.component.salesforce.NotFoundBehaviour;
 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.TypeReferences;
 import org.apache.camel.component.salesforce.api.dto.AbstractDTOBase;
@@ -171,8 +173,17 @@ public class JsonRestProcessor extends AbstractRestProcessor {
 
         // process JSON response for TypeReference
         try {
-            // do we need to un-marshal a response
-            if (responseEntity != null) {
+            final Message out = exchange.getOut();
+            final Message in = exchange.getIn();
+            out.copyFromWithNewBody(in, null);
+
+            if (ex != null) {
+                // if an exception is reported we should not loose it
+                if (shouldReport(ex)) {
+                    exchange.setException(ex);
+                }
+            } else if (responseEntity != null) {
+                // do we need to un-marshal a response
                 Object response = null;
                 Class<?> responseClass = exchange.getProperty(RESPONSE_CLASS, Class.class);
                 if (responseClass != null) {
@@ -186,13 +197,8 @@ public class JsonRestProcessor extends AbstractRestProcessor {
                         response = responseEntity;
                     }
                 }
-                exchange.getOut().setBody(response);
-            } else {
-                exchange.setException(ex);
+                out.setBody(response);
             }
-            // copy headers and attachments
-            exchange.getOut().getHeaders().putAll(exchange.getIn().getHeaders());
-            exchange.getOut().getAttachmentObjects().putAll(exchange.getIn().getAttachmentObjects());
         } catch (IOException e) {
             String msg = "Error parsing JSON response: " + e.getMessage();
             exchange.setException(new SalesforceException(msg, e));
@@ -214,5 +220,4 @@ public class JsonRestProcessor extends AbstractRestProcessor {
         }
 
     }
-
 }

http://git-wip-us.apache.org/repos/asf/camel/blob/87dc6fc2/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 2bbc190..6650ff0 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
@@ -220,12 +220,20 @@ public class XmlRestProcessor extends AbstractRestProcessor {
     }
 
     @Override
-    protected void processResponse(Exchange exchange, InputStream responseEntity,
-                                   SalesforceException exception, AsyncCallback callback)
{
+    protected void processResponse(final Exchange exchange, final InputStream responseEntity,
+        final SalesforceException exception, final AsyncCallback callback) {
         final XStream localXStream = xStream.get();
         try {
-            // do we need to un-marshal a response
-            if (responseEntity != null) {
+            final Message out = exchange.getOut();
+            final Message in = exchange.getIn();
+            out.copyFromWithNewBody(in, null);
+
+            if (exception != null) {
+                if (shouldReport(exception)) {
+                    exchange.setException(exception);
+                }
+            } else if (responseEntity != null) {
+                // do we need to un-marshal a response
                 final Class<?> responseClass = exchange.getProperty(RESPONSE_CLASS,
Class.class);
                 Object response;
                 if (responseClass != null) {
@@ -251,13 +259,8 @@ public class XmlRestProcessor extends AbstractRestProcessor {
                     // return the response as a stream, for getBlobField
                     response = responseEntity;
                 }
-                exchange.getOut().setBody(response);
-            } else {
-                exchange.setException(exception);
+                out.setBody(response);
             }
-            // copy headers and attachments
-            exchange.getOut().getHeaders().putAll(exchange.getIn().getHeaders());
-            exchange.getOut().getAttachmentObjects().putAll(exchange.getIn().getAttachmentObjects());
         } catch (XStreamException e) {
             String msg = "Error parsing XML response: " + e.getMessage();
             exchange.setException(new SalesforceException(msg, e));

http://git-wip-us.apache.org/repos/asf/camel/blob/87dc6fc2/components/camel-salesforce/camel-salesforce-component/src/test/java/org/apache/camel/component/salesforce/NotFoundIntegrationTest.java
----------------------------------------------------------------------
diff --git a/components/camel-salesforce/camel-salesforce-component/src/test/java/org/apache/camel/component/salesforce/NotFoundIntegrationTest.java
b/components/camel-salesforce/camel-salesforce-component/src/test/java/org/apache/camel/component/salesforce/NotFoundIntegrationTest.java
new file mode 100644
index 0000000..8ffd8b4
--- /dev/null
+++ b/components/camel-salesforce/camel-salesforce-component/src/test/java/org/apache/camel/component/salesforce/NotFoundIntegrationTest.java
@@ -0,0 +1,62 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.camel.component.salesforce;
+
+import java.util.Arrays;
+
+import com.googlecode.junittoolbox.ParallelParameterized;
+
+import org.apache.camel.CamelExecutionException;
+import org.apache.camel.component.salesforce.api.NoSuchSObjectException;
+import org.apache.camel.component.salesforce.dto.generated.Account;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.Parameterized.Parameter;
+import org.junit.runners.Parameterized.Parameters;
+
+@RunWith(ParallelParameterized.class)
+public class NotFoundIntegrationTest extends AbstractSalesforceTestBase {
+
+    @Parameter
+    public String format;
+
+    @Test
+    public void shouldNotReportNotFoundExceptionFromRestApiIfConfiguredNotTo() {
+        final Account got = template
+            .requestBody("salesforce:getSObjectWithId?sObjectName=Account&sObjectIdName=Name&format="
+ format
+                + "&notFoundBehaviour=NULL", "NonExistant", Account.class);
+
+        assertNull("Expecting null when `notFoundBehaviour` is set to NULL", got);
+    }
+
+    @Test
+    public void shouldReportNotFoundExceptionFromRestApi() {
+        try {
+            template.requestBody("salesforce:getSObjectWithId?sObjectName=Account&sObjectIdName=Name&format="
+ format,
+                "NonExistant", Account.class);
+            fail("Expecting CamelExecutionException");
+        } catch (final CamelExecutionException e) {
+            assertTrue("Expecting the cause of CamelExecutionException to be NoSuchSObjectException",
+                e.getCause() instanceof NoSuchSObjectException);
+        }
+    }
+
+    @Parameters(name = "{0}")
+    public static Iterable<String> formats() {
+        return Arrays.asList("XML", "JSON");
+    }
+}

http://git-wip-us.apache.org/repos/asf/camel/blob/87dc6fc2/components/camel-salesforce/camel-salesforce-component/src/test/java/org/apache/camel/component/salesforce/RestApiIntegrationTest.java
----------------------------------------------------------------------
diff --git a/components/camel-salesforce/camel-salesforce-component/src/test/java/org/apache/camel/component/salesforce/RestApiIntegrationTest.java
b/components/camel-salesforce/camel-salesforce-component/src/test/java/org/apache/camel/component/salesforce/RestApiIntegrationTest.java
index 716fda1..ccd09d9 100644
--- a/components/camel-salesforce/camel-salesforce-component/src/test/java/org/apache/camel/component/salesforce/RestApiIntegrationTest.java
+++ b/components/camel-salesforce/camel-salesforce-component/src/test/java/org/apache/camel/component/salesforce/RestApiIntegrationTest.java
@@ -30,6 +30,7 @@ import com.thoughtworks.xstream.annotations.XStreamAlias;
 import org.apache.camel.CamelExecutionException;
 import org.apache.camel.Processor;
 import org.apache.camel.builder.RouteBuilder;
+import org.apache.camel.component.salesforce.api.NoSuchSObjectException;
 import org.apache.camel.component.salesforce.api.SalesforceException;
 import org.apache.camel.component.salesforce.api.SalesforceMultipleChoicesException;
 import org.apache.camel.component.salesforce.api.dto.AbstractDTOBase;
@@ -442,12 +443,11 @@ public class RestApiIntegrationTest extends AbstractSalesforceTestBase
{
                 template().requestBody("direct:getSObjectWithId", merchandise, Merchandise__c.class);
                 fail("Expected SalesforceException with statusCode 300");
             } catch (final CamelExecutionException e) {
-                assertTrue(e.getCause() instanceof SalesforceException);
-                assertTrue(e.getCause().getCause() instanceof SalesforceMultipleChoicesException);
-                final SalesforceMultipleChoicesException cause = (SalesforceMultipleChoicesException)
e.getCause()
-                    .getCause();
-                assertEquals(300, cause.getStatusCode());
-                final List<String> choices = cause.getChoices();
+                final Throwable cause = e.getCause();
+                assertTrue(cause instanceof SalesforceMultipleChoicesException);
+                final SalesforceMultipleChoicesException multipleChoices = (SalesforceMultipleChoicesException)
cause;
+                assertEquals(300, multipleChoices.getStatusCode());
+                final List<String> choices = multipleChoices.getChoices();
                 assertNotNull(choices);
                 assertFalse(choices.isEmpty());
             }
@@ -476,12 +476,12 @@ public class RestApiIntegrationTest extends AbstractSalesforceTestBase
{
             result = template().requestBody("direct:createSObject", merchandise, CreateSObjectResult.class);
             fail("Expected SalesforceException with statusCode 400");
         } catch (final CamelExecutionException e) {
-            assertTrue(e.getCause() instanceof SalesforceException);
-            assertTrue(e.getCause().getCause() instanceof SalesforceException);
-            final SalesforceException cause = (SalesforceException) e.getCause().getCause();
-            assertEquals(400, cause.getStatusCode());
-            assertEquals(1, cause.getErrors().size());
-            assertEquals("[Total_Inventory__c]", cause.getErrors().get(0).getFields().toString());
+            final Throwable cause = e.getCause();
+            assertTrue(cause instanceof SalesforceException);
+            final SalesforceException badRequest = (SalesforceException) cause;
+            assertEquals(400, badRequest.getStatusCode());
+            assertEquals(1, badRequest.getErrors().size());
+            assertEquals("[Total_Inventory__c]", badRequest.getErrors().get(0).getFields().toString());
         } finally {
             // delete the clone if created
             if (result != null) {
@@ -497,11 +497,11 @@ public class RestApiIntegrationTest extends AbstractSalesforceTestBase
{
             template().requestBody("direct:getSObject", "ILLEGAL_ID", Merchandise__c.class);
             fail("Expected SalesforceException");
         } catch (final CamelExecutionException e) {
-            assertTrue(e.getCause() instanceof SalesforceException);
-            assertTrue(e.getCause().getCause() instanceof SalesforceException);
-            final SalesforceException cause = (SalesforceException) e.getCause().getCause();
-            assertEquals(404, cause.getStatusCode());
-            assertEquals(1, cause.getErrors().size());
+            final Throwable cause = e.getCause();
+            assertTrue(cause instanceof NoSuchSObjectException);
+            final NoSuchSObjectException noSuchObject = (NoSuchSObjectException) cause;
+            assertEquals(404, noSuchObject.getStatusCode());
+            assertEquals(1, noSuchObject.getErrors().size());
         }
     }
 

http://git-wip-us.apache.org/repos/asf/camel/blob/87dc6fc2/platforms/spring-boot/components-starter/camel-salesforce-starter/src/main/java/org/apache/camel/component/salesforce/springboot/SalesforceComponentConfiguration.java
----------------------------------------------------------------------
diff --git a/platforms/spring-boot/components-starter/camel-salesforce-starter/src/main/java/org/apache/camel/component/salesforce/springboot/SalesforceComponentConfiguration.java
b/platforms/spring-boot/components-starter/camel-salesforce-starter/src/main/java/org/apache/camel/component/salesforce/springboot/SalesforceComponentConfiguration.java
index 5ae2470..5d6ee52 100644
--- a/platforms/spring-boot/components-starter/camel-salesforce-starter/src/main/java/org/apache/camel/component/salesforce/springboot/SalesforceComponentConfiguration.java
+++ b/platforms/spring-boot/components-starter/camel-salesforce-starter/src/main/java/org/apache/camel/component/salesforce/springboot/SalesforceComponentConfiguration.java
@@ -21,6 +21,7 @@ import java.util.Map;
 import java.util.Set;
 import com.fasterxml.jackson.databind.ObjectMapper;
 import org.apache.camel.component.salesforce.AuthenticationType;
+import org.apache.camel.component.salesforce.NotFoundBehaviour;
 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;
@@ -622,6 +623,13 @@ public class SalesforceComponentConfiguration {
          * @param skipEntryCriteria
          */
         private Boolean approvalSkipEntryCriteria;
+        /**
+         * Sets the behaviour of 404 not found status received from Salesforce
+         * API. Should the body be set to NULL {@link NotFoundBehaviour#NULL} or
+         * should a exception be signaled on the exchange
+         * {@link NotFoundBehaviour#EXCEPTION} - the default.
+         */
+        private NotFoundBehaviour notFoundBehaviour;
 
         public PayloadFormat getFormat() {
             return format;
@@ -978,6 +986,14 @@ public class SalesforceComponentConfiguration {
                 Boolean approvalSkipEntryCriteria) {
             this.approvalSkipEntryCriteria = approvalSkipEntryCriteria;
         }
+
+        public NotFoundBehaviour getNotFoundBehaviour() {
+            return notFoundBehaviour;
+        }
+
+        public void setNotFoundBehaviour(NotFoundBehaviour notFoundBehaviour) {
+            this.notFoundBehaviour = notFoundBehaviour;
+        }
     }
 
     public static class SalesforceLoginConfigNestedConfiguration {


Mime
View raw message