You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@camel.apache.org by da...@apache.org on 2016/11/23 08:45:26 UTC
[3/3] camel git commit: CAMEL-10472 Update Salesforce component to
support recent items REST API
CAMEL-10472 Update Salesforce component to support recent items REST API
This commit adds support for getting recent items via Salesforce REST API[1].
New operation `recent` was added and can be used like:
...to("salesforce:recent")
.split().body()
.log("${body.name} at ${body.attributes.url}");
Number of items returned can be limited by the `limit` parameter in URI,
body or headers.
[1] https://developer.salesforce.com/docs/atlas.en-us.api_rest.meta/api_rest/resources_recent_items.htm
Project: http://git-wip-us.apache.org/repos/asf/camel/repo
Commit: http://git-wip-us.apache.org/repos/asf/camel/commit/4e3b2f7a
Tree: http://git-wip-us.apache.org/repos/asf/camel/tree/4e3b2f7a
Diff: http://git-wip-us.apache.org/repos/asf/camel/diff/4e3b2f7a
Branch: refs/heads/master
Commit: 4e3b2f7af9ed3d7c99fcfd32f0c84c37838ea19f
Parents: a52ab3c
Author: Zoran Regvart <zo...@regvart.com>
Authored: Tue Nov 22 18:24:32 2016 +0100
Committer: Claus Ibsen <da...@apache.org>
Committed: Wed Nov 23 09:44:01 2016 +0100
----------------------------------------------------------------------
.../salesforce/SalesforceEndpointConfig.java | 17 +++
.../salesforce/api/TypeReferences.java | 4 +
.../salesforce/internal/OperationName.java | 1 +
.../internal/client/DefaultRestClient.java | 13 ++
.../salesforce/internal/client/RestClient.java | 12 ++
.../processor/AbstractRestProcessor.java | 10 ++
.../internal/processor/JsonRestProcessor.java | 5 +
.../salesforce/RecentIntegrationTest.java | 140 +++++++++++++++++++
.../salesforce/api/dto/RecentItemTest.java | 65 +++++++++
9 files changed, 267 insertions(+)
----------------------------------------------------------------------
http://git-wip-us.apache.org/repos/asf/camel/blob/4e3b2f7a/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 ad18aab..3d59a19 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
@@ -56,6 +56,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 LIMIT = "limit";
// prefix for parameters in headers
public static final String APEX_QUERY_PARAM_PREFIX = "apexQueryParam.";
@@ -173,6 +174,9 @@ public class SalesforceEndpointConfig implements Cloneable {
@UriParam
private long maxBackoff = DEFAULT_MAX_BACKOFF;
+ @UriParam
+ private Integer limit;
+
public SalesforceEndpointConfig copy() {
try {
final SalesforceEndpointConfig copy = (SalesforceEndpointConfig) super.clone();
@@ -563,6 +567,7 @@ public class SalesforceEndpointConfig implements Cloneable {
valueMap.put(SOBJECT_SEARCH, sObjectSearch);
valueMap.put(APEX_METHOD, apexMethod);
valueMap.put(APEX_URL, apexUrl);
+ valueMap.put(LIMIT, limit);
// apexQueryParams are handled explicitly in AbstractRestProcessor
// add bulk API properties
@@ -608,4 +613,16 @@ public class SalesforceEndpointConfig implements Cloneable {
public void setInitialReplayIdMap(Map<String, Integer> initialReplayIdMap) {
this.initialReplayIdMap = initialReplayIdMap;
}
+
+ public Integer getLimit() {
+ return limit;
+ }
+
+ /**
+ * Limit on number of returned records. Applicable to some of the API, check the Salesforce documentation.
+ * @param limit
+ */
+ public void setLimit(final Integer limit) {
+ this.limit = limit;
+ }
}
http://git-wip-us.apache.org/repos/asf/camel/blob/4e3b2f7a/components/camel-salesforce/camel-salesforce-component/src/main/java/org/apache/camel/component/salesforce/api/TypeReferences.java
----------------------------------------------------------------------
diff --git a/components/camel-salesforce/camel-salesforce-component/src/main/java/org/apache/camel/component/salesforce/api/TypeReferences.java b/components/camel-salesforce/camel-salesforce-component/src/main/java/org/apache/camel/component/salesforce/api/TypeReferences.java
index 42f022d..7128312 100644
--- a/components/camel-salesforce/camel-salesforce-component/src/main/java/org/apache/camel/component/salesforce/api/TypeReferences.java
+++ b/components/camel-salesforce/camel-salesforce-component/src/main/java/org/apache/camel/component/salesforce/api/TypeReferences.java
@@ -23,6 +23,7 @@ import com.fasterxml.jackson.core.type.TypeReference;
import org.apache.camel.component.salesforce.api.dto.Limits.Operation;
import org.apache.camel.component.salesforce.api.dto.Limits.Usage;
+import org.apache.camel.component.salesforce.api.dto.RecentItem;
import org.apache.camel.component.salesforce.api.dto.RestError;
import org.apache.camel.component.salesforce.api.dto.SearchResult;
import org.apache.camel.component.salesforce.api.dto.Version;
@@ -55,6 +56,9 @@ public final class TypeReferences {
public static final TypeReference<List<SearchResult>> SEARCH_RESULT_TYPE = new TypeReference<List<SearchResult>>() {
};
+ public static final TypeReference<List<RecentItem>> RECENT_ITEM_LIST_TYPE = new TypeReference<List<RecentItem>>() {
+ };
+
private TypeReferences() {
// not meant for instantiation, only for TypeReference constants
}
http://git-wip-us.apache.org/repos/asf/camel/blob/4e3b2f7a/components/camel-salesforce/camel-salesforce-component/src/main/java/org/apache/camel/component/salesforce/internal/OperationName.java
----------------------------------------------------------------------
diff --git a/components/camel-salesforce/camel-salesforce-component/src/main/java/org/apache/camel/component/salesforce/internal/OperationName.java b/components/camel-salesforce/camel-salesforce-component/src/main/java/org/apache/camel/component/salesforce/internal/OperationName.java
index 15fdf0b..7570374 100644
--- a/components/camel-salesforce/camel-salesforce-component/src/main/java/org/apache/camel/component/salesforce/internal/OperationName.java
+++ b/components/camel-salesforce/camel-salesforce-component/src/main/java/org/apache/camel/component/salesforce/internal/OperationName.java
@@ -37,6 +37,7 @@ public enum OperationName {
QUERY_ALL("queryAll"),
SEARCH("search"),
APEX_CALL("apexCall"),
+ RECENT("recent"),
// bulk API
CREATE_JOB("createJob"),
http://git-wip-us.apache.org/repos/asf/camel/blob/4e3b2f7a/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 d1a5394..f604312 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
@@ -23,6 +23,7 @@ import java.net.URISyntaxException;
import java.net.URLEncoder;
import java.util.List;
import java.util.Map;
+import java.util.Optional;
import com.fasterxml.jackson.core.type.TypeReference;
import com.fasterxml.jackson.databind.ObjectMapper;
@@ -403,6 +404,18 @@ public class DefaultRestClient extends AbstractClientBase implements RestClient
}
@Override
+ public void recent(final Integer limit, final ResponseCallback responseCallback) {
+ final String param = Optional.ofNullable(limit).map(v -> "?limit=" + v).orElse("");
+
+ final Request get = getRequest(HttpMethod.GET, versionUrl() + "recent/" + param);
+
+ // requires authorization token
+ setAccessToken(get);
+
+ doHttpRequest(get, new DelegatingClientCallback(responseCallback));
+ }
+
+ @Override
public void limits(final ResponseCallback responseCallback) {
final Request get = getRequest(HttpMethod.GET, versionUrl() + "limits/");
http://git-wip-us.apache.org/repos/asf/camel/blob/4e3b2f7a/components/camel-salesforce/camel-salesforce-component/src/main/java/org/apache/camel/component/salesforce/internal/client/RestClient.java
----------------------------------------------------------------------
diff --git a/components/camel-salesforce/camel-salesforce-component/src/main/java/org/apache/camel/component/salesforce/internal/client/RestClient.java b/components/camel-salesforce/camel-salesforce-component/src/main/java/org/apache/camel/component/salesforce/internal/client/RestClient.java
index 470aa33..55764d0 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
@@ -195,6 +195,18 @@ public interface RestClient {
ResponseCallback callback);
/**
+ * Fetches recently viewed records.
+ *
+ * @param limit
+ * optional limit that specifies the maximum number of records to be returned. If this parameter is not
+ * specified, the default maximum number of records returned is the maximum number of entries in
+ * RecentlyViewed, which is 200 records per object.
+ * @param responseCallback
+ * {@link ResponseCallback} to handle response or exception
+ */
+ void recent(Integer limit, ResponseCallback responseCallback);
+
+ /**
* Fetches Organization Limits.
*
* @param responseCallback {@link ResponseCallback} to handle response or exception
http://git-wip-us.apache.org/repos/asf/camel/blob/4e3b2f7a/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 35e0aff..6636ada 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
@@ -29,6 +29,7 @@ import java.util.regex.Pattern;
import org.apache.camel.AsyncCallback;
import org.apache.camel.Exchange;
import org.apache.camel.component.salesforce.SalesforceEndpoint;
+import org.apache.camel.component.salesforce.SalesforceEndpointConfig;
import org.apache.camel.component.salesforce.api.SalesforceException;
import org.apache.camel.component.salesforce.api.dto.AbstractSObjectBase;
import org.apache.camel.component.salesforce.internal.PayloadFormat;
@@ -152,6 +153,9 @@ public abstract class AbstractRestProcessor extends AbstractSalesforceProcessor
case APEX_CALL:
processApexCall(exchange, callback);
break;
+ case RECENT:
+ processRecent(exchange, callback);
+ break;
case LIMITS:
processLimits(exchange, callback);
break;
@@ -564,6 +568,12 @@ public abstract class AbstractRestProcessor extends AbstractSalesforceProcessor
return apexUrl;
}
+ private void processRecent(Exchange exchange, AsyncCallback callback) throws SalesforceException {
+ final Integer limit = getParameter(SalesforceEndpointConfig.LIMIT, exchange, true, true, Integer.class);
+
+ restClient.recent(limit, (response, exception) -> processResponse(exchange, response, exception, callback));
+ }
+
private void processLimits(Exchange exchange, AsyncCallback callback) {
restClient.limits((response, exception) -> processResponse(exchange, response, exception, callback));
}
http://git-wip-us.apache.org/repos/asf/camel/blob/4e3b2f7a/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 5fe991f..a0c50b3 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
@@ -103,6 +103,11 @@ public class JsonRestProcessor extends AbstractRestProcessor {
exchange.setProperty(RESPONSE_TYPE, TypeReferences.SEARCH_RESULT_TYPE);
break;
+ case RECENT:
+ // handle known response type
+ exchange.setProperty(RESPONSE_TYPE, TypeReferences.RECENT_ITEM_LIST_TYPE);
+ break;
+
case LIMITS:
// handle known response type
exchange.setProperty(RESPONSE_CLASS, Limits.class);
http://git-wip-us.apache.org/repos/asf/camel/blob/4e3b2f7a/components/camel-salesforce/camel-salesforce-component/src/test/java/org/apache/camel/component/salesforce/RecentIntegrationTest.java
----------------------------------------------------------------------
diff --git a/components/camel-salesforce/camel-salesforce-component/src/test/java/org/apache/camel/component/salesforce/RecentIntegrationTest.java b/components/camel-salesforce/camel-salesforce-component/src/test/java/org/apache/camel/component/salesforce/RecentIntegrationTest.java
new file mode 100644
index 0000000..3774295
--- /dev/null
+++ b/components/camel-salesforce/camel-salesforce-component/src/test/java/org/apache/camel/component/salesforce/RecentIntegrationTest.java
@@ -0,0 +1,140 @@
+/**
+ * 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.List;
+import java.util.stream.Collectors;
+import java.util.stream.IntStream;
+
+import com.thoughtworks.xstream.annotations.XStreamImplicit;
+
+import org.apache.camel.builder.RouteBuilder;
+import org.apache.camel.component.salesforce.api.dto.AbstractQueryRecordsBase;
+import org.apache.camel.component.salesforce.api.dto.RecentItem;
+import org.apache.camel.component.salesforce.dto.generated.Account;
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Test;
+
+public class RecentIntegrationTest extends AbstractSalesforceTestBase {
+
+ public static class Accounts extends AbstractQueryRecordsBase {
+ @XStreamImplicit
+ private List<Account> records;
+
+ public List<Account> getRecords() {
+ return records;
+ }
+
+ public void setRecords(final List<Account> records) {
+ this.records = records;
+ }
+
+ }
+
+ private static final Object NOT_USED = null;
+
+ static Account account(final int ord) {
+ final Account account = new Account();
+ account.setName("recent-" + ord);
+
+ return account;
+ }
+
+ static void assertRecentItemsSize(final List<RecentItem> items, final int expected) {
+ final List<RecentItem> recentItems = items.stream().filter(i -> i.getName().startsWith("recent-"))
+ .collect(Collectors.toList());
+
+ assertListSize("Expected " + expected + " items named `recent-N` in recent items", recentItems, expected);
+ }
+
+ @After
+ public void deleteRecords() {
+ template.sendBody("direct:delete-recent", NOT_USED);
+ }
+
+ @Before
+ public void setupTenRecentItems() {
+ final List<Account> accounts = IntStream.range(0, 10).mapToObj(RecentIntegrationTest::account)
+ .collect(Collectors.toList());
+
+ template.sendBody("direct:create-recent", accounts);
+ }
+
+ @Test
+ public void shouldFetchRecentItems() {
+ @SuppressWarnings("unchecked")
+ final List<RecentItem> items = template.requestBody("direct:test-recent", NOT_USED, List.class);
+
+ assertRecentItemsSize(items, 10);
+ }
+
+ @Test
+ public void shouldFetchRecentItemsLimitingByHeaderParam() {
+ @SuppressWarnings("unchecked")
+ final List<RecentItem> items = template.requestBody("direct:test-recent-with-header-limit-param", NOT_USED,
+ List.class);
+
+ assertRecentItemsSize(items, 5);
+ }
+
+ @Test
+ public void shouldFetchRecentItemsLimitingByParamInBody() {
+ @SuppressWarnings("unchecked")
+ final List<RecentItem> items = template.requestBody("direct:test-recent-with-body-limit-param", NOT_USED,
+ List.class);
+
+ assertRecentItemsSize(items, 5);
+ }
+
+ @Test
+ public void shouldFetchRecentItemsLimitingByUriParam() {
+ @SuppressWarnings("unchecked")
+ final List<RecentItem> items = template.requestBody("direct:test-recent-with-limit-uri-param", NOT_USED,
+ List.class);
+
+ assertRecentItemsSize(items, 5);
+ }
+
+ @Override
+ protected RouteBuilder doCreateRouteBuilder() throws Exception {
+ return new RouteBuilder() {
+ @Override
+ public void configure() throws Exception {
+ from("direct:create-recent").split().body().to("salesforce:createSObject?sObjectName=Account").end()
+ .to("salesforce:query?sObjectClass=" + Accounts.class.getName()
+ + "&sObjectQuery=SELECT Id FROM Account WHERE Name LIKE 'recent-%' FOR VIEW");
+
+ from("direct:delete-recent")
+ .to("salesforce:query?sObjectClass=" + Accounts.class.getName()
+ + "&sObjectQuery=SELECT Id FROM Account WHERE Name LIKE 'recent-%'")
+ .transform(simple("${body.records}")).split().body()
+ .setHeader(SalesforceEndpointConfig.SOBJECT_ID).simple("${body.id}")
+ .to("salesforce:deleteSObject?sObjectName=Account");
+
+ from("direct:test-recent").to("salesforce:recent");
+
+ from("direct:test-recent-with-limit-uri-param").to("salesforce:recent?limit=5");
+
+ from("direct:test-recent-with-header-limit-param").setHeader(SalesforceEndpointConfig.LIMIT).constant(5)
+ .to("salesforce:recent");
+
+ from("direct:test-recent-with-body-limit-param").setBody(constant(5)).to("salesforce:recent");
+ }
+ };
+ }
+}
http://git-wip-us.apache.org/repos/asf/camel/blob/4e3b2f7a/components/camel-salesforce/camel-salesforce-component/src/test/java/org/apache/camel/component/salesforce/api/dto/RecentItemTest.java
----------------------------------------------------------------------
diff --git a/components/camel-salesforce/camel-salesforce-component/src/test/java/org/apache/camel/component/salesforce/api/dto/RecentItemTest.java b/components/camel-salesforce/camel-salesforce-component/src/test/java/org/apache/camel/component/salesforce/api/dto/RecentItemTest.java
new file mode 100644
index 0000000..3fc16ee
--- /dev/null
+++ b/components/camel-salesforce/camel-salesforce-component/src/test/java/org/apache/camel/component/salesforce/api/dto/RecentItemTest.java
@@ -0,0 +1,65 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.camel.component.salesforce.api.dto;
+
+import java.io.IOException;
+
+import com.fasterxml.jackson.core.JsonProcessingException;
+import com.fasterxml.jackson.databind.ObjectMapper;
+
+import org.junit.Test;
+
+import static org.hamcrest.core.IsInstanceOf.instanceOf;
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertThat;
+
+public class RecentItemTest {
+
+ @Test
+ public void shouldDeserializeFromJSON() throws JsonProcessingException, IOException {
+ final ObjectMapper mapper = new ObjectMapper();
+
+ final Object read = mapper.readerFor(RecentItem.class)
+ .readValue("{ \n" + //
+ " \"attributes\" : \n" + //
+ " { \n" + //
+ " \"type\" : \"Account\", \n" + //
+ " \"url\" : \"/services/data/v28.0/sobjects/Account/a06U000000CelH0IAJ\" \n" + //
+ " }, \n" + //
+ " \"Id\" : \"a06U000000CelH0IAJ\", \n" + //
+ " \"Name\" : \"Acme\" \n" + //
+ "}");
+
+ assertThat("RecentItem should deserialize from JSON", read, instanceOf(RecentItem.class));
+
+ RecentItem recentItem = (RecentItem) read;
+
+ assertEquals("RecentItem.Id should be deserialized", recentItem.getId(), "a06U000000CelH0IAJ");
+
+ assertEquals("RecentItem.Name should be deserialized", recentItem.getName(), "Acme");
+
+ assertNotNull("RecentItem.attributes should be deserialized", recentItem.getAttributes());
+
+ assertEquals("RecentItem.attributes.type should be deserialized", recentItem.getAttributes().getType(),
+ "Account");
+
+ assertEquals("RecentItem.attributes.url should be deserialized", recentItem.getAttributes().getUrl(),
+ "/services/data/v28.0/sobjects/Account/a06U000000CelH0IAJ");
+
+ }
+}