CAMEL-8269: added support for APEX REST calls, also updated Salesforce API version to 33.0
Project: http://git-wip-us.apache.org/repos/asf/camel/repo Commit: http://git-wip-us.apache.org/repos/asf/camel/commit/65cd95c5 Tree: http://git-wip-us.apache.org/repos/asf/camel/tree/65cd95c5 Diff: http://git-wip-us.apache.org/repos/asf/camel/diff/65cd95c5 Branch: refs/heads/camel-2.12.x Commit: 65cd95c5ec6c531a58621dd206d69a35532045c9 Parents: 2dc15fa Author: Dhiraj Bokde <dhira...@yahoo.com> Authored: Mon Feb 23 13:38:37 2015 -0800 Committer: Dhiraj Bokde <dhira...@yahoo.com> Committed: Fri Mar 20 14:24:45 2015 -0700 ---------------------------------------------------------------------- .../MerchandiseRestResource.apxc | 44 +++++ .../salesforce/SalesforceComponent.java | 21 ++ .../salesforce/SalesforceEndpointConfig.java | 80 +++++++- .../salesforce/api/dto/AbstractSObjectBase.java | 22 +++ .../salesforce/api/dto/ActionOverride.java | 75 ++++++++ .../api/dto/ActionOverrideTypeEnum.java | 57 ++++++ .../salesforce/api/dto/ChildRelationShip.java | 20 ++ .../salesforce/api/dto/FilteredLookupInfo.java | 48 +++++ .../component/salesforce/api/dto/InfoUrls.java | 30 +++ .../salesforce/api/dto/NamedLayoutInfo.java | 39 ++++ .../salesforce/api/dto/RecordTypeInfo.java | 9 + .../salesforce/api/dto/RestResources.java | 99 ++++++++++ .../component/salesforce/api/dto/SObject.java | 8 + .../salesforce/api/dto/SObjectDescription.java | 20 ++ .../salesforce/api/dto/SObjectField.java | 63 ++++++ .../salesforce/api/dto/SObjectUrls.java | 81 ++++++++ .../salesforce/internal/OperationName.java | 1 + .../internal/client/DefaultRestClient.java | 60 +++++- .../salesforce/internal/client/RestClient.java | 13 ++ .../internal/dto/NotifyForFieldsEnum.java | 10 +- .../internal/dto/NotifyForOperationsEnum.java | 10 +- .../salesforce/internal/dto/PushTopic.java | 49 ++++- .../processor/AbstractRestProcessor.java | 190 +++++++++++++++---- .../internal/processor/JsonRestProcessor.java | 10 +- .../internal/processor/XmlRestProcessor.java | 17 +- .../internal/streaming/PushTopicHelper.java | 74 ++++++-- .../salesforce/RestApiIntegrationTest.java | 113 +++++++++++ .../salesforce/StreamingApiIntegrationTest.java | 4 +- .../salesforce/dto/generated/Document.java | 26 ++- .../src/test/resources/log4j.properties | 1 + 30 files changed, 1194 insertions(+), 100 deletions(-) ---------------------------------------------------------------------- http://git-wip-us.apache.org/repos/asf/camel/blob/65cd95c5/components/camel-salesforce/camel-salesforce-component/MerchandiseRestResource.apxc ---------------------------------------------------------------------- diff --git a/components/camel-salesforce/camel-salesforce-component/MerchandiseRestResource.apxc b/components/camel-salesforce/camel-salesforce-component/MerchandiseRestResource.apxc new file mode 100644 index 0000000..91ce5ce --- /dev/null +++ b/components/camel-salesforce/camel-salesforce-component/MerchandiseRestResource.apxc @@ -0,0 +1,44 @@ +@RestResource(urlMapping='/Merchandise/*') +global with sharing class MerchandiseRestResource { + + @HttpGet + global static Merchandise__c doGet() { + RestRequest req = RestContext.request; + String merchandiseId = null; + if (!req.requestURI.endsWith('/')) { + merchandiseId = req.requestURI.substring(req.requestURI.lastIndexOf('/')+1); + } else if (req.params.get('id') != null) { + merchandiseId = req.params.get('id'); + } + if (merchandiseId != null) { + Merchandise__c merchandise = [SELECT Id, Name, Description__c, Price__c, Total_Inventory__c FROM Merchandise__c WHERE Id = :merchandiseId]; + return merchandise; + } else { + throw new InvalidParamException('Missing merchandise id in URL and query params'); + } + } + + @HttpPatch + global static Merchandise__c doPatch(Merchandise__c merchandise) { + // lookup merchandise + Merchandise__c current = [SELECT Id, Name, Description__c, Price__c, Total_Inventory__c FROM Merchandise__c WHERE Id = :merchandise.Id]; + if (current == null) { + throw new InvalidParamException('Missing merchandise for id ' + merchandise.Id); + } + if (merchandise.Description__c != null) { + current.Description__c = merchandise.Description__c; + } + if (merchandise.Price__c != null) { + current.Price__c = merchandise.Price__c; + } + if (merchandise.Total_Inventory__c != null) { + current.Total_Inventory__c = merchandise.Total_Inventory__c; + } + + update current; + return current; + } + + // Invalid Merchandise Id exception + public class InvalidParamException extends Exception {} +} \ No newline at end of file http://git-wip-us.apache.org/repos/asf/camel/blob/65cd95c5/components/camel-salesforce/camel-salesforce-component/src/main/java/org/apache/camel/component/salesforce/SalesforceComponent.java ---------------------------------------------------------------------- diff --git a/components/camel-salesforce/camel-salesforce-component/src/main/java/org/apache/camel/component/salesforce/SalesforceComponent.java b/components/camel-salesforce/camel-salesforce-component/src/main/java/org/apache/camel/component/salesforce/SalesforceComponent.java index 8a38bec..c12edc2 100644 --- a/components/camel-salesforce/camel-salesforce-component/src/main/java/org/apache/camel/component/salesforce/SalesforceComponent.java +++ b/components/camel-salesforce/camel-salesforce-component/src/main/java/org/apache/camel/component/salesforce/SalesforceComponent.java @@ -59,6 +59,7 @@ public class SalesforceComponent extends UriEndpointComponent implements Endpoin private static final int CONNECTION_TIMEOUT = 60000; private static final int RESPONSE_TIMEOUT = 60000; private static final Pattern SOBJECT_NAME_PATTERN = Pattern.compile("^.*[\\?&]sObjectName=([^&,]+).*$"); + private static final String APEX_CALL_PREFIX = OperationName.APEX_CALL.value() + "/"; private SalesforceLoginConfig loginConfig; private SalesforceEndpointConfig config; @@ -86,8 +87,14 @@ public class SalesforceComponent extends UriEndpointComponent implements Endpoin // get Operation from remaining URI OperationName operationName = null; String topicName = null; + String apexUrl = null; try { LOG.debug("Creating endpoint for: {}", remaining); + if (remaining.startsWith(APEX_CALL_PREFIX)) { + // extract APEX URL + apexUrl = remaining.substring(APEX_CALL_PREFIX.length()); + remaining = OperationName.APEX_CALL.value(); + } operationName = OperationName.fromValue(remaining); } catch (IllegalArgumentException ex) { // if its not an operation name, treat is as topic name for consumer endpoints @@ -107,12 +114,26 @@ public class SalesforceComponent extends UriEndpointComponent implements Endpoin final SalesforceEndpointConfig copy = config.copy(); setProperties(copy, parameters); + // set apexUrl in endpoint config + if (apexUrl != null) { + copy.setApexUrl(apexUrl); + } + final SalesforceEndpoint endpoint = new SalesforceEndpoint(uri, this, copy, operationName, topicName); // map remaining parameters to endpoint (specifically, synchronous) setProperties(endpoint, parameters); + // if operation is APEX call, map remaining parameters to query params + if (operationName == OperationName.APEX_CALL && !parameters.isEmpty()) { + Map<String, Object> queryParams = new HashMap<String, Object>(parameters); + parameters.clear(); + + queryParams.putAll(copy.getApexQueryParams()); + copy.setApexQueryParams(queryParams); + } + return endpoint; } http://git-wip-us.apache.org/repos/asf/camel/blob/65cd95c5/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 353ed30..9af05b9 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 @@ -36,7 +36,7 @@ import org.eclipse.jetty.client.HttpClient; public class SalesforceEndpointConfig implements Cloneable { // default API version - public static final String DEFAULT_VERSION = "27.0"; + public static final String DEFAULT_VERSION = "33.0"; // general parameter public static final String API_VERSION = "apiVersion"; @@ -52,6 +52,11 @@ public class SalesforceEndpointConfig implements Cloneable { public static final String SOBJECT_CLASS = "sObjectClass"; public static final String SOBJECT_QUERY = "sObjectQuery"; public static final String SOBJECT_SEARCH = "sObjectSearch"; + public static final String APEX_METHOD = "apexMethod"; + public static final String APEX_URL = "apexUrl"; + + // prefix for parameters in headers + public static final String APEX_QUERY_PARAM_PREFIX = "apexQueryParam."; // parameters for Bulk API public static final String CONTENT_TYPE = "contentType"; @@ -84,6 +89,12 @@ public class SalesforceEndpointConfig implements Cloneable { private String sObjectQuery; @UriParam private String sObjectSearch; + @UriParam + private String apexMethod; + @UriParam + private String apexUrl; + @UriParam + private Map<String, Object> apexQueryParams; // Bulk API properties @UriParam @@ -102,6 +113,14 @@ public class SalesforceEndpointConfig implements Cloneable { private NotifyForFieldsEnum notifyForFields; @UriParam private NotifyForOperationsEnum notifyForOperations; + @UriParam + private Boolean notifyForOperationCreate; + @UriParam + private Boolean notifyForOperationUpdate; + @UriParam + private Boolean notifyForOperationDelete; + @UriParam + private Boolean notifyForOperationUndelete; // Jetty HttpClient, set using reference @UriParam @@ -205,6 +224,30 @@ public class SalesforceEndpointConfig implements Cloneable { this.sObjectSearch = sObjectSearch; } + public String getApexMethod() { + return apexMethod; + } + + public void setApexMethod(String apexMethod) { + this.apexMethod = apexMethod; + } + + public String getApexUrl() { + return apexUrl; + } + + public void setApexUrl(String apexUrl) { + this.apexUrl = apexUrl; + } + + public Map<String, Object> getApexQueryParams() { + return apexQueryParams == null ? Collections.EMPTY_MAP : Collections.unmodifiableMap(apexQueryParams); + } + + public void setApexQueryParams(Map<String, Object> apexQueryParams) { + this.apexQueryParams = apexQueryParams; + } + public ContentType getContentType() { return contentType; } @@ -261,6 +304,38 @@ public class SalesforceEndpointConfig implements Cloneable { this.notifyForOperations = notifyForOperations; } + public Boolean getNotifyForOperationCreate() { + return notifyForOperationCreate; + } + + public void setNotifyForOperationCreate(Boolean notifyForOperationCreate) { + this.notifyForOperationCreate = notifyForOperationCreate; + } + + public Boolean getNotifyForOperationUpdate() { + return notifyForOperationUpdate; + } + + public void setNotifyForOperationUpdate(Boolean notifyForOperationUpdate) { + this.notifyForOperationUpdate = notifyForOperationUpdate; + } + + public Boolean getNotifyForOperationDelete() { + return notifyForOperationDelete; + } + + public void setNotifyForOperationDelete(Boolean notifyForOperationDelete) { + this.notifyForOperationDelete = notifyForOperationDelete; + } + + public Boolean getNotifyForOperationUndelete() { + return notifyForOperationUndelete; + } + + public void setNotifyForOperationUndelete(Boolean notifyForOperationUndelete) { + this.notifyForOperationUndelete = notifyForOperationUndelete; + } + public void setHttpClient(HttpClient httpClient) { this.httpClient = httpClient; } @@ -284,6 +359,9 @@ public class SalesforceEndpointConfig implements Cloneable { valueMap.put(SOBJECT_CLASS, sObjectClass); valueMap.put(SOBJECT_QUERY, sObjectQuery); valueMap.put(SOBJECT_SEARCH, sObjectSearch); + valueMap.put(APEX_METHOD, apexMethod); + valueMap.put(APEX_URL, apexUrl); + // apexQueryParams are handled explicitly in AbstractRestProcessor // add bulk API properties if (contentType != null) { http://git-wip-us.apache.org/repos/asf/camel/blob/65cd95c5/components/camel-salesforce/camel-salesforce-component/src/main/java/org/apache/camel/component/salesforce/api/dto/AbstractSObjectBase.java ---------------------------------------------------------------------- diff --git a/components/camel-salesforce/camel-salesforce-component/src/main/java/org/apache/camel/component/salesforce/api/dto/AbstractSObjectBase.java b/components/camel-salesforce/camel-salesforce-component/src/main/java/org/apache/camel/component/salesforce/api/dto/AbstractSObjectBase.java index fa20827..7337a52 100644 --- a/components/camel-salesforce/camel-salesforce-component/src/main/java/org/apache/camel/component/salesforce/api/dto/AbstractSObjectBase.java +++ b/components/camel-salesforce/camel-salesforce-component/src/main/java/org/apache/camel/component/salesforce/api/dto/AbstractSObjectBase.java @@ -35,6 +35,8 @@ public class AbstractSObjectBase extends AbstractDTOBase { private String LastModifiedById; private DateTime SystemModstamp; private String LastActivityDate; + private DateTime LastViewedDate; + private DateTime LastReferencedDate; /** * Utility method to clear all system {@link AbstractSObjectBase} fields. @@ -161,5 +163,25 @@ public class AbstractSObjectBase extends AbstractDTOBase { public void setLastActivityDate(String lastActivityDate) { this.LastActivityDate = lastActivityDate; } + + @JsonProperty("LastViewedDate") + public DateTime getLastViewedDate() { + return LastViewedDate; + } + + @JsonProperty("LastViewedDate") + public void setLastViewedDate(DateTime lastViewedDate) { + LastViewedDate = lastViewedDate; + } + + @JsonProperty("LastReferencedDate") + public DateTime getLastReferencedDate() { + return LastReferencedDate; + } + + @JsonProperty("LastReferencedDate") + public void setLastReferencedDate(DateTime lastReferencedDate) { + LastReferencedDate = lastReferencedDate; + } } //CHECKSTYLE:ON http://git-wip-us.apache.org/repos/asf/camel/blob/65cd95c5/components/camel-salesforce/camel-salesforce-component/src/main/java/org/apache/camel/component/salesforce/api/dto/ActionOverride.java ---------------------------------------------------------------------- diff --git a/components/camel-salesforce/camel-salesforce-component/src/main/java/org/apache/camel/component/salesforce/api/dto/ActionOverride.java b/components/camel-salesforce/camel-salesforce-component/src/main/java/org/apache/camel/component/salesforce/api/dto/ActionOverride.java new file mode 100644 index 0000000..eff26df --- /dev/null +++ b/components/camel-salesforce/camel-salesforce-component/src/main/java/org/apache/camel/component/salesforce/api/dto/ActionOverride.java @@ -0,0 +1,75 @@ +/** + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.camel.component.salesforce.api.dto; + +import com.thoughtworks.xstream.annotations.XStreamConverter; + +import org.apache.camel.component.salesforce.api.PicklistEnumConverter; + +public class ActionOverride extends AbstractDTOBase { + + private String actionName; + + private String comment; + + private String content; + + private Boolean skipRecordTypeSelect; + + @XStreamConverter(PicklistEnumConverter.class) + private ActionOverrideTypeEnum type; + + public String getActionName() { + return actionName; + } + + public void setActionName(String actionName) { + this.actionName = actionName; + } + + public String getComment() { + return comment; + } + + public void setComment(String comment) { + this.comment = comment; + } + + public String getContent() { + return content; + } + + public void setContent(String content) { + this.content = content; + } + + public Boolean getSkipRecordTypeSelect() { + return skipRecordTypeSelect; + } + + public void setSkipRecordTypeSelect(Boolean skipRecordTypeSelect) { + this.skipRecordTypeSelect = skipRecordTypeSelect; + } + + public ActionOverrideTypeEnum getType() { + return type; + } + + public void setType(ActionOverrideTypeEnum type) { + this.type = type; + } +} http://git-wip-us.apache.org/repos/asf/camel/blob/65cd95c5/components/camel-salesforce/camel-salesforce-component/src/main/java/org/apache/camel/component/salesforce/api/dto/ActionOverrideTypeEnum.java ---------------------------------------------------------------------- diff --git a/components/camel-salesforce/camel-salesforce-component/src/main/java/org/apache/camel/component/salesforce/api/dto/ActionOverrideTypeEnum.java b/components/camel-salesforce/camel-salesforce-component/src/main/java/org/apache/camel/component/salesforce/api/dto/ActionOverrideTypeEnum.java new file mode 100644 index 0000000..967b0a8 --- /dev/null +++ b/components/camel-salesforce/camel-salesforce-component/src/main/java/org/apache/camel/component/salesforce/api/dto/ActionOverrideTypeEnum.java @@ -0,0 +1,57 @@ +/** + * 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 org.codehaus.jackson.annotate.JsonCreator; +import org.codehaus.jackson.annotate.JsonValue; +import org.codehaus.jackson.map.annotate.JsonDeserialize; + +@JsonDeserialize +public enum ActionOverrideTypeEnum { + + // The override uses a custom override provided by an installed package. + // If there isnât one available, the standard Salesforce behavior is used. + DEFAULT("default"), + // The override uses behavior from an s-control. + SCONTROL("scontrol"), + // The override uses regular Salesforce behavior. + STANDARD("standard"), + // The override uses behavior from a Visualforce page. + VISUALFORCE("visualforce"); + + final String value; + + private ActionOverrideTypeEnum(String value) { + this.value = value; + } + + @JsonValue + public String value() { + return this.value; + } + + @JsonCreator + public static ActionOverrideTypeEnum fromValue(String value) { + for (ActionOverrideTypeEnum e : ActionOverrideTypeEnum.values()) { + if (e.value.equals(value)) { + return e; + } + } + throw new IllegalArgumentException(value); + } + +} http://git-wip-us.apache.org/repos/asf/camel/blob/65cd95c5/components/camel-salesforce/camel-salesforce-component/src/main/java/org/apache/camel/component/salesforce/api/dto/ChildRelationShip.java ---------------------------------------------------------------------- diff --git a/components/camel-salesforce/camel-salesforce-component/src/main/java/org/apache/camel/component/salesforce/api/dto/ChildRelationShip.java b/components/camel-salesforce/camel-salesforce-component/src/main/java/org/apache/camel/component/salesforce/api/dto/ChildRelationShip.java index 9b89923..7a674e7 100644 --- a/components/camel-salesforce/camel-salesforce-component/src/main/java/org/apache/camel/component/salesforce/api/dto/ChildRelationShip.java +++ b/components/camel-salesforce/camel-salesforce-component/src/main/java/org/apache/camel/component/salesforce/api/dto/ChildRelationShip.java @@ -16,6 +16,8 @@ */ package org.apache.camel.component.salesforce.api.dto; +import java.util.List; + public class ChildRelationShip extends AbstractDTOBase { private String field; @@ -24,6 +26,8 @@ public class ChildRelationShip extends AbstractDTOBase { private Boolean cascadeDelete; private Boolean restrictedDelete; private String childSObject; + private String junctionIdListName; + private List<String> junctionReferenceTo; public String getField() { return field; @@ -72,4 +76,20 @@ public class ChildRelationShip extends AbstractDTOBase { public void setChildSObject(String childSObject) { this.childSObject = childSObject; } + + public String getJunctionIdListName() { + return junctionIdListName; + } + + public void setJunctionIdListName(String junctionIdListName) { + this.junctionIdListName = junctionIdListName; + } + + public List<String> getJunctionReferenceTo() { + return junctionReferenceTo; + } + + public void setJunctionReferenceTo(List<String> junctionReferenceTo) { + this.junctionReferenceTo = junctionReferenceTo; + } } http://git-wip-us.apache.org/repos/asf/camel/blob/65cd95c5/components/camel-salesforce/camel-salesforce-component/src/main/java/org/apache/camel/component/salesforce/api/dto/FilteredLookupInfo.java ---------------------------------------------------------------------- diff --git a/components/camel-salesforce/camel-salesforce-component/src/main/java/org/apache/camel/component/salesforce/api/dto/FilteredLookupInfo.java b/components/camel-salesforce/camel-salesforce-component/src/main/java/org/apache/camel/component/salesforce/api/dto/FilteredLookupInfo.java new file mode 100644 index 0000000..182efd6 --- /dev/null +++ b/components/camel-salesforce/camel-salesforce-component/src/main/java/org/apache/camel/component/salesforce/api/dto/FilteredLookupInfo.java @@ -0,0 +1,48 @@ +/** + * 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; + +public class FilteredLookupInfo extends AbstractDTOBase { + + private String controllingFields; + private Boolean dependent; + private Boolean optionalFilter; + + public String getControllingFields() { + return controllingFields; + } + + public void setControllingFields(String controllingFields) { + this.controllingFields = controllingFields; + } + + public Boolean getDependent() { + return dependent; + } + + public void setDependent(Boolean dependent) { + this.dependent = dependent; + } + + public Boolean getOptionalFilter() { + return optionalFilter; + } + + public void setOptionalFilter(Boolean optionalFilter) { + this.optionalFilter = optionalFilter; + } +} http://git-wip-us.apache.org/repos/asf/camel/blob/65cd95c5/components/camel-salesforce/camel-salesforce-component/src/main/java/org/apache/camel/component/salesforce/api/dto/InfoUrls.java ---------------------------------------------------------------------- diff --git a/components/camel-salesforce/camel-salesforce-component/src/main/java/org/apache/camel/component/salesforce/api/dto/InfoUrls.java b/components/camel-salesforce/camel-salesforce-component/src/main/java/org/apache/camel/component/salesforce/api/dto/InfoUrls.java new file mode 100644 index 0000000..51da519 --- /dev/null +++ b/components/camel-salesforce/camel-salesforce-component/src/main/java/org/apache/camel/component/salesforce/api/dto/InfoUrls.java @@ -0,0 +1,30 @@ +/** + * 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; + +public class InfoUrls extends AbstractDTOBase { + + private String layout; + + public String getLayout() { + return layout; + } + + public void setLayout(String layout) { + this.layout = layout; + } +} http://git-wip-us.apache.org/repos/asf/camel/blob/65cd95c5/components/camel-salesforce/camel-salesforce-component/src/main/java/org/apache/camel/component/salesforce/api/dto/NamedLayoutInfo.java ---------------------------------------------------------------------- diff --git a/components/camel-salesforce/camel-salesforce-component/src/main/java/org/apache/camel/component/salesforce/api/dto/NamedLayoutInfo.java b/components/camel-salesforce/camel-salesforce-component/src/main/java/org/apache/camel/component/salesforce/api/dto/NamedLayoutInfo.java new file mode 100644 index 0000000..7dc1d00 --- /dev/null +++ b/components/camel-salesforce/camel-salesforce-component/src/main/java/org/apache/camel/component/salesforce/api/dto/NamedLayoutInfo.java @@ -0,0 +1,39 @@ +/** + * 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; + +public class NamedLayoutInfo extends AbstractDTOBase { + + private String name; + private InfoUrls urls; + + public String getName() { + return name; + } + + public void setName(String name) { + this.name = name; + } + + public InfoUrls getUrls() { + return urls; + } + + public void setUrls(InfoUrls urls) { + this.urls = urls; + } +} http://git-wip-us.apache.org/repos/asf/camel/blob/65cd95c5/components/camel-salesforce/camel-salesforce-component/src/main/java/org/apache/camel/component/salesforce/api/dto/RecordTypeInfo.java ---------------------------------------------------------------------- diff --git a/components/camel-salesforce/camel-salesforce-component/src/main/java/org/apache/camel/component/salesforce/api/dto/RecordTypeInfo.java b/components/camel-salesforce/camel-salesforce-component/src/main/java/org/apache/camel/component/salesforce/api/dto/RecordTypeInfo.java index 392ddb4..92eda59 100644 --- a/components/camel-salesforce/camel-salesforce-component/src/main/java/org/apache/camel/component/salesforce/api/dto/RecordTypeInfo.java +++ b/components/camel-salesforce/camel-salesforce-component/src/main/java/org/apache/camel/component/salesforce/api/dto/RecordTypeInfo.java @@ -22,6 +22,7 @@ public class RecordTypeInfo extends AbstractDTOBase { private Boolean available; private String recordTypeId; private Boolean defaultRecordTypeMapping; + private InfoUrls urls; public String getName() { return name; @@ -54,4 +55,12 @@ public class RecordTypeInfo extends AbstractDTOBase { public void setDefaultRecordTypeMapping(Boolean defaultRecordTypeMapping) { this.defaultRecordTypeMapping = defaultRecordTypeMapping; } + + public InfoUrls getUrls() { + return urls; + } + + public void setUrls(InfoUrls urls) { + this.urls = urls; + } } http://git-wip-us.apache.org/repos/asf/camel/blob/65cd95c5/components/camel-salesforce/camel-salesforce-component/src/main/java/org/apache/camel/component/salesforce/api/dto/RestResources.java ---------------------------------------------------------------------- diff --git a/components/camel-salesforce/camel-salesforce-component/src/main/java/org/apache/camel/component/salesforce/api/dto/RestResources.java b/components/camel-salesforce/camel-salesforce-component/src/main/java/org/apache/camel/component/salesforce/api/dto/RestResources.java index ce108b1..b37aa13 100644 --- a/components/camel-salesforce/camel-salesforce-component/src/main/java/org/apache/camel/component/salesforce/api/dto/RestResources.java +++ b/components/camel-salesforce/camel-salesforce-component/src/main/java/org/apache/camel/component/salesforce/api/dto/RestResources.java @@ -34,6 +34,17 @@ public class RestResources extends AbstractDTOBase { private String tooling; private String licensing; private String analytics; + private String limits; + private String theme; + private String queryAll; + private String knowledgeManagement; + private String process; + private String flexiPage; + private String quickActions; + private String appMenu; + private String compactLayouts; + private String actions; + private String tabs; public String getSobjects() { return sobjects; @@ -114,4 +125,92 @@ public class RestResources extends AbstractDTOBase { public void setAnalytics(String analytics) { this.analytics = analytics; } + + public String getLimits() { + return limits; + } + + public void setLimits(String limits) { + this.limits = limits; + } + + public String getTheme() { + return theme; + } + + public void setTheme(String theme) { + this.theme = theme; + } + + public String getQueryAll() { + return queryAll; + } + + public void setQueryAll(String queryAll) { + this.queryAll = queryAll; + } + + public String getKnowledgeManagement() { + return knowledgeManagement; + } + + public void setKnowledgeManagement(String knowledgeManagement) { + this.knowledgeManagement = knowledgeManagement; + } + + public String getProcess() { + return process; + } + + public void setProcess(String process) { + this.process = process; + } + + public String getFlexiPage() { + return flexiPage; + } + + public void setFlexiPage(String flexiPage) { + this.flexiPage = flexiPage; + } + + public String getQuickActions() { + return quickActions; + } + + public void setQuickActions(String quickActions) { + this.quickActions = quickActions; + } + + public String getAppMenu() { + return appMenu; + } + + public void setAppMenu(String appMenu) { + this.appMenu = appMenu; + } + + public String getCompactLayouts() { + return compactLayouts; + } + + public void setCompactLayouts(String compactLayouts) { + this.compactLayouts = compactLayouts; + } + + public String getActions() { + return actions; + } + + public void setActions(String actions) { + this.actions = actions; + } + + public String getTabs() { + return tabs; + } + + public void setTabs(String tabs) { + this.tabs = tabs; + } } http://git-wip-us.apache.org/repos/asf/camel/blob/65cd95c5/components/camel-salesforce/camel-salesforce-component/src/main/java/org/apache/camel/component/salesforce/api/dto/SObject.java ---------------------------------------------------------------------- diff --git a/components/camel-salesforce/camel-salesforce-component/src/main/java/org/apache/camel/component/salesforce/api/dto/SObject.java b/components/camel-salesforce/camel-salesforce-component/src/main/java/org/apache/camel/component/salesforce/api/dto/SObject.java index 97fa39d..d390595 100644 --- a/components/camel-salesforce/camel-salesforce-component/src/main/java/org/apache/camel/component/salesforce/api/dto/SObject.java +++ b/components/camel-salesforce/camel-salesforce-component/src/main/java/org/apache/camel/component/salesforce/api/dto/SObject.java @@ -42,6 +42,7 @@ public class SObject extends AbstractDTOBase { private String searchLayoutable; private Boolean undeletable; private Boolean triggerable; + private Boolean compactLayoutable; public String getName() { return name; @@ -235,4 +236,11 @@ public class SObject extends AbstractDTOBase { this.triggerable = triggerable; } + public Boolean getCompactLayoutable() { + return compactLayoutable; + } + + public void setCompactLayoutable(Boolean compactLayoutable) { + this.compactLayoutable = compactLayoutable; + } } http://git-wip-us.apache.org/repos/asf/camel/blob/65cd95c5/components/camel-salesforce/camel-salesforce-component/src/main/java/org/apache/camel/component/salesforce/api/dto/SObjectDescription.java ---------------------------------------------------------------------- diff --git a/components/camel-salesforce/camel-salesforce-component/src/main/java/org/apache/camel/component/salesforce/api/dto/SObjectDescription.java b/components/camel-salesforce/camel-salesforce-component/src/main/java/org/apache/camel/component/salesforce/api/dto/SObjectDescription.java index 9096c1e..4fb5a29 100644 --- a/components/camel-salesforce/camel-salesforce-component/src/main/java/org/apache/camel/component/salesforce/api/dto/SObjectDescription.java +++ b/components/camel-salesforce/camel-salesforce-component/src/main/java/org/apache/camel/component/salesforce/api/dto/SObjectDescription.java @@ -23,12 +23,24 @@ import com.thoughtworks.xstream.annotations.XStreamImplicit; public class SObjectDescription extends SObject { @XStreamImplicit + private List<ActionOverride> actionOverrides; + @XStreamImplicit private List<SObjectField> fields; private SObjectDescriptionUrls urls; @XStreamImplicit private List<ChildRelationShip> childRelationships; @XStreamImplicit private List<RecordTypeInfo> recordTypeInfos; + @XStreamImplicit + private List<NamedLayoutInfo> namedLayoutInfos; + + public List<ActionOverride> getActionOverrides() { + return actionOverrides; + } + + public void setActionOverrides(List<ActionOverride> actionOverrides) { + this.actionOverrides = actionOverrides; + } public List<SObjectField> getFields() { return fields; @@ -61,4 +73,12 @@ public class SObjectDescription extends SObject { public void setRecordTypeInfos(List<RecordTypeInfo> recordTypeInfos) { this.recordTypeInfos = recordTypeInfos; } + + public List<NamedLayoutInfo> getNamedLayoutInfos() { + return namedLayoutInfos; + } + + public void setNamedLayoutInfos(List<NamedLayoutInfo> namedLayoutInfos) { + this.namedLayoutInfos = namedLayoutInfos; + } } http://git-wip-us.apache.org/repos/asf/camel/blob/65cd95c5/components/camel-salesforce/camel-salesforce-component/src/main/java/org/apache/camel/component/salesforce/api/dto/SObjectField.java ---------------------------------------------------------------------- diff --git a/components/camel-salesforce/camel-salesforce-component/src/main/java/org/apache/camel/component/salesforce/api/dto/SObjectField.java b/components/camel-salesforce/camel-salesforce-component/src/main/java/org/apache/camel/component/salesforce/api/dto/SObjectField.java index 8664c19..312e6c3 100644 --- a/components/camel-salesforce/camel-salesforce-component/src/main/java/org/apache/camel/component/salesforce/api/dto/SObjectField.java +++ b/components/camel-salesforce/camel-salesforce-component/src/main/java/org/apache/camel/component/salesforce/api/dto/SObjectField.java @@ -67,6 +67,13 @@ public class SObjectField extends AbstractDTOBase { private Boolean groupable; private Boolean permissionable; private Boolean displayLocationInDecimal; + private String extraTypeInfo; + private FilteredLookupInfo filteredLookupInfo; + private Boolean highScaleNumber; + private String mask; + private String maskType; + private Boolean queryByDistance; + private String referenceTargetField; public Integer getLength() { return length; @@ -411,4 +418,60 @@ public class SObjectField extends AbstractDTOBase { public void setDisplayLocationInDecimal(Boolean displayLocationInDecimal) { this.displayLocationInDecimal = displayLocationInDecimal; } + + public String getExtraTypeInfo() { + return extraTypeInfo; + } + + public void setExtraTypeInfo(String extraTypeInfo) { + this.extraTypeInfo = extraTypeInfo; + } + + public FilteredLookupInfo getFilteredLookupInfo() { + return filteredLookupInfo; + } + + public void setFilteredLookupInfo(FilteredLookupInfo filteredLookupInfo) { + this.filteredLookupInfo = filteredLookupInfo; + } + + public Boolean getHighScaleNumber() { + return highScaleNumber; + } + + public void setHighScaleNumber(Boolean highScaleNumber) { + this.highScaleNumber = highScaleNumber; + } + + public String getMask() { + return mask; + } + + public void setMask(String mask) { + this.mask = mask; + } + + public String getMaskType() { + return maskType; + } + + public void setMaskType(String maskType) { + this.maskType = maskType; + } + + public Boolean getQueryByDistance() { + return queryByDistance; + } + + public void setQueryByDistance(Boolean queryByDistance) { + this.queryByDistance = queryByDistance; + } + + public String getReferenceTargetField() { + return referenceTargetField; + } + + public void setReferenceTargetField(String referenceTargetField) { + this.referenceTargetField = referenceTargetField; + } } http://git-wip-us.apache.org/repos/asf/camel/blob/65cd95c5/components/camel-salesforce/camel-salesforce-component/src/main/java/org/apache/camel/component/salesforce/api/dto/SObjectUrls.java ---------------------------------------------------------------------- diff --git a/components/camel-salesforce/camel-salesforce-component/src/main/java/org/apache/camel/component/salesforce/api/dto/SObjectUrls.java b/components/camel-salesforce/camel-salesforce-component/src/main/java/org/apache/camel/component/salesforce/api/dto/SObjectUrls.java index b1abd74..85115d1 100644 --- a/components/camel-salesforce/camel-salesforce-component/src/main/java/org/apache/camel/component/salesforce/api/dto/SObjectUrls.java +++ b/components/camel-salesforce/camel-salesforce-component/src/main/java/org/apache/camel/component/salesforce/api/dto/SObjectUrls.java @@ -22,6 +22,15 @@ public class SObjectUrls extends AbstractDTOBase { private String describe; private String rowTemplate; private String passwordUtilities; + private String approvalLayouts; + private String quickActions; + private String caseArticleSuggestions; + private String listviews; + private String layouts; + private String namedLayouts; + private String compactLayouts; + private String caseRowArticleSuggestions; + private String push; public String getSobject() { return sobject; @@ -54,4 +63,76 @@ public class SObjectUrls extends AbstractDTOBase { public void setPasswordUtilities(String passwordUtilities) { this.passwordUtilities = passwordUtilities; } + + public String getApprovalLayouts() { + return approvalLayouts; + } + + public void setApprovalLayouts(String approvalLayouts) { + this.approvalLayouts = approvalLayouts; + } + + public String getQuickActions() { + return quickActions; + } + + public void setQuickActions(String quickActions) { + this.quickActions = quickActions; + } + + public String getCaseArticleSuggestions() { + return caseArticleSuggestions; + } + + public void setCaseArticleSuggestions(String caseArticleSuggestions) { + this.caseArticleSuggestions = caseArticleSuggestions; + } + + public String getListviews() { + return listviews; + } + + public void setListviews(String listviews) { + this.listviews = listviews; + } + + public String getLayouts() { + return layouts; + } + + public void setLayouts(String layouts) { + this.layouts = layouts; + } + + public String getNamedLayouts() { + return namedLayouts; + } + + public void setNamedLayouts(String namedLayouts) { + this.namedLayouts = namedLayouts; + } + + public String getCompactLayouts() { + return compactLayouts; + } + + public void setCompactLayouts(String compactLayouts) { + this.compactLayouts = compactLayouts; + } + + public String getCaseRowArticleSuggestions() { + return caseRowArticleSuggestions; + } + + public void setCaseRowArticleSuggestions(String caseRowArticleSuggestions) { + this.caseRowArticleSuggestions = caseRowArticleSuggestions; + } + + public String getPush() { + return push; + } + + public void setPush(String push) { + this.push = push; + } } http://git-wip-us.apache.org/repos/asf/camel/blob/65cd95c5/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 50141f1..a5b7893 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 @@ -35,6 +35,7 @@ public enum OperationName { QUERY("query"), QUERY_MORE("queryMore"), SEARCH("search"), + APEX_CALL("apexCall"), // bulk API CREATE_JOB("createJob"), http://git-wip-us.apache.org/repos/asf/camel/blob/65cd95c5/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 1edfed7..0b06289 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 @@ -19,8 +19,10 @@ package org.apache.camel.component.salesforce.internal.client; import java.io.IOException; import java.io.InputStream; import java.io.UnsupportedEncodingException; +import java.net.URISyntaxException; import java.net.URLEncoder; import java.util.List; +import java.util.Map; import com.thoughtworks.xstream.XStream; import org.apache.camel.component.salesforce.api.SalesforceException; @@ -28,6 +30,7 @@ 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.apache.camel.util.URISupport; import org.codehaus.jackson.map.ObjectMapper; import org.codehaus.jackson.type.TypeReference; import org.eclipse.jetty.client.ContentExchange; @@ -42,6 +45,7 @@ public class DefaultRestClient extends AbstractClientBase implements RestClient private static final String SERVICES_DATA = "/services/data/"; private static final String TOKEN_HEADER = "Authorization"; private static final String TOKEN_PREFIX = "Bearer "; + private static final String SERVICES_APEXREST = "/services/apexrest/"; protected PayloadFormat format; private ObjectMapper objectMapper; @@ -267,9 +271,7 @@ public class DefaultRestClient extends AbstractClientBase implements RestClient public void query(String soqlQuery, ResponseCallback callback) { try { - String encodedQuery = URLEncoder.encode(soqlQuery, StringUtil.__UTF8_CHARSET.toString()); - // URLEncoder likes to use '+' for spaces - encodedQuery = encodedQuery.replace("+", "%20"); + String encodedQuery = urlEncode(soqlQuery); final ContentExchange get = getContentExchange(HttpMethods.GET, versionUrl() + "query/?q=" + encodedQuery); // requires authorization token @@ -297,9 +299,7 @@ public class DefaultRestClient extends AbstractClientBase implements RestClient public void search(String soslQuery, ResponseCallback callback) { try { - String encodedQuery = URLEncoder.encode(soslQuery, StringUtil.__UTF8_CHARSET.toString()); - // URLEncoder likes to use '+' for spaces - encodedQuery = encodedQuery.replace("+", "%20"); + String encodedQuery = urlEncode(soslQuery); final ContentExchange get = getContentExchange(HttpMethods.GET, versionUrl() + "search/?q=" + encodedQuery); // requires authorization token @@ -313,6 +313,43 @@ public class DefaultRestClient extends AbstractClientBase implements RestClient } } + @Override + public void apexCall(String httpMethod, String apexUrl, + Map<String, Object> queryParams, InputStream requestDto, ResponseCallback callback) { + // create APEX call exchange + final ContentExchange exchange; + try { + exchange = getContentExchange(httpMethod, apexCallUrl(apexUrl, queryParams)); + // set request SObject and content type + if (requestDto != null) { + exchange.setRequestContentSource(requestDto); + exchange.setRequestContentType( + PayloadFormat.JSON.equals(format) ? APPLICATION_JSON_UTF8 : APPLICATION_XML_UTF8); + } + + // requires authorization token + setAccessToken(exchange); + + doHttpRequest(exchange, new DelegatingClientCallback(callback)); + } catch (UnsupportedEncodingException e) { + String msg = "Unexpected error: " + e.getMessage(); + callback.onResponse(null, new SalesforceException(msg, e)); + } catch (URISyntaxException e) { + String msg = "Unexpected error: " + e.getMessage(); + callback.onResponse(null, new SalesforceException(msg, e)); + } + } + + private String apexCallUrl(String apexUrl, Map<String, Object> queryParams) + throws UnsupportedEncodingException, URISyntaxException { + + if (queryParams != null && !queryParams.isEmpty()) { + apexUrl = URISupport.appendParametersToURI(apexUrl, queryParams); + } + + return instanceUrl + SERVICES_APEXREST + apexUrl; + } + private String servicesDataUrl() { return instanceUrl + SERVICES_DATA; } @@ -336,9 +373,7 @@ public class DefaultRestClient extends AbstractClientBase implements RestClient throw new IllegalArgumentException("External field name and value cannot be NULL"); } try { - String encodedValue = URLEncoder.encode(fieldValue, StringUtil.__UTF8_CHARSET.toString()); - // URLEncoder likes to use '+' for spaces - encodedValue = encodedValue.replace("+", "%20"); + String encodedValue = urlEncode(fieldValue); return sobjectsUrl(sObjectName + "/" + fieldName + "/" + encodedValue); } catch (UnsupportedEncodingException e) { String msg = "Unexpected error: " + e.getMessage(); @@ -350,6 +385,13 @@ public class DefaultRestClient extends AbstractClientBase implements RestClient httpExchange.setRequestHeader(TOKEN_HEADER, TOKEN_PREFIX + accessToken); } + private String urlEncode(String query) throws UnsupportedEncodingException { + String encodedQuery = URLEncoder.encode(query, StringUtil.__UTF8_CHARSET.toString()); + // URLEncoder likes to use '+' for spaces + encodedQuery = encodedQuery.replace("+", "%20"); + return encodedQuery; + } + private static class DelegatingClientCallback implements ClientResponseCallback { private final ResponseCallback callback; http://git-wip-us.apache.org/repos/asf/camel/blob/65cd95c5/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 a28f8b8..5747976 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 @@ -17,6 +17,7 @@ package org.apache.camel.component.salesforce.internal.client; import java.io.InputStream; +import java.util.Map; import org.apache.camel.component.salesforce.api.SalesforceException; @@ -173,4 +174,16 @@ public interface RestClient { */ void search(String soslQuery, ResponseCallback callback); + /** + * Executes a user defined APEX REST API call. + * + * @param httpMethod HTTP method to execute. + * @param apexUrl APEX api url. + * @param queryParams optional query parameters for GET methods, may be empty. + * @param requestDto optional input DTO for POST, etc. may be null. + * @param callback {@link ResponseCallback} to handle response or exception + */ + void apexCall(String httpMethod, String apexUrl, Map<String, Object> queryParams, InputStream requestDto, + ResponseCallback callback); + } http://git-wip-us.apache.org/repos/asf/camel/blob/65cd95c5/components/camel-salesforce/camel-salesforce-component/src/main/java/org/apache/camel/component/salesforce/internal/dto/NotifyForFieldsEnum.java ---------------------------------------------------------------------- diff --git a/components/camel-salesforce/camel-salesforce-component/src/main/java/org/apache/camel/component/salesforce/internal/dto/NotifyForFieldsEnum.java b/components/camel-salesforce/camel-salesforce-component/src/main/java/org/apache/camel/component/salesforce/internal/dto/NotifyForFieldsEnum.java index 970b9aa..0385be3 100644 --- a/components/camel-salesforce/camel-salesforce-component/src/main/java/org/apache/camel/component/salesforce/internal/dto/NotifyForFieldsEnum.java +++ b/components/camel-salesforce/camel-salesforce-component/src/main/java/org/apache/camel/component/salesforce/internal/dto/NotifyForFieldsEnum.java @@ -24,10 +24,14 @@ import org.codehaus.jackson.annotate.JsonValue; */ public enum NotifyForFieldsEnum { - SELECT("Select"), - WHERE("Where"), + // All + ALL("All"), + // Referenced REFERENCED("Referenced"), - ALL("All"); + // Select + SELECT("Select"), + // Where + WHERE("Where"); final String value; http://git-wip-us.apache.org/repos/asf/camel/blob/65cd95c5/components/camel-salesforce/camel-salesforce-component/src/main/java/org/apache/camel/component/salesforce/internal/dto/NotifyForOperationsEnum.java ---------------------------------------------------------------------- diff --git a/components/camel-salesforce/camel-salesforce-component/src/main/java/org/apache/camel/component/salesforce/internal/dto/NotifyForOperationsEnum.java b/components/camel-salesforce/camel-salesforce-component/src/main/java/org/apache/camel/component/salesforce/internal/dto/NotifyForOperationsEnum.java index f75839c..6ac2b87 100644 --- a/components/camel-salesforce/camel-salesforce-component/src/main/java/org/apache/camel/component/salesforce/internal/dto/NotifyForOperationsEnum.java +++ b/components/camel-salesforce/camel-salesforce-component/src/main/java/org/apache/camel/component/salesforce/internal/dto/NotifyForOperationsEnum.java @@ -24,10 +24,14 @@ import org.codehaus.jackson.annotate.JsonValue; */ public enum NotifyForOperationsEnum { - CREATE("Create"), - UPDATE("Update"), + // All ALL("All"), - EXTENDED("Extended"); + // Create + CREATE("Create"), + // Extended + EXTENDED("Extended"), + // Update + UPDATE("Update"); final String value; http://git-wip-us.apache.org/repos/asf/camel/blob/65cd95c5/components/camel-salesforce/camel-salesforce-component/src/main/java/org/apache/camel/component/salesforce/internal/dto/PushTopic.java ---------------------------------------------------------------------- diff --git a/components/camel-salesforce/camel-salesforce-component/src/main/java/org/apache/camel/component/salesforce/internal/dto/PushTopic.java b/components/camel-salesforce/camel-salesforce-component/src/main/java/org/apache/camel/component/salesforce/internal/dto/PushTopic.java index 17dbd98..4274dc1 100644 --- a/components/camel-salesforce/camel-salesforce-component/src/main/java/org/apache/camel/component/salesforce/internal/dto/PushTopic.java +++ b/components/camel-salesforce/camel-salesforce-component/src/main/java/org/apache/camel/component/salesforce/internal/dto/PushTopic.java @@ -47,6 +47,14 @@ public class PushTopic extends AbstractSObjectBase { private String Description; + private Boolean NotifyForOperationCreate; + + private Boolean NotifyForOperationUpdate; + + private Boolean NotifyForOperationDelete; + + private Boolean NotifyForOperationUndelete; + @JsonProperty("Query") public String getQuery() { return this.Query; @@ -106,6 +114,45 @@ public class PushTopic extends AbstractSObjectBase { public void setDescription(String description) { this.Description = description; } + + @JsonProperty("NotifyForOperationCreate") + public Boolean getNotifyForOperationCreate() { + return this.NotifyForOperationCreate; + } + + @JsonProperty("NotifyForOperationCreate") + public void setNotifyForOperationCreate(Boolean notifyForOperationCreate) { + this.NotifyForOperationCreate = notifyForOperationCreate; + } + + @JsonProperty("NotifyForOperationUpdate") + public Boolean getNotifyForOperationUpdate() { + return this.NotifyForOperationUpdate; + } + + @JsonProperty("NotifyForOperationUpdate") + public void setNotifyForOperationUpdate(Boolean notifyForOperationUpdate) { + this.NotifyForOperationUpdate = notifyForOperationUpdate; + } + + @JsonProperty("NotifyForOperationDelete") + public Boolean getNotifyForOperationDelete() { + return this.NotifyForOperationDelete; + } + + @JsonProperty("NotifyForOperationDelete") + public void setNotifyForOperationDelete(Boolean notifyForOperationDelete) { + this.NotifyForOperationDelete = notifyForOperationDelete; + } + + @JsonProperty("NotifyForOperationUndelete") + public Boolean getNotifyForOperationUndelete() { + return this.NotifyForOperationUndelete; + } + + @JsonProperty("NotifyForOperationUndelete") + public void setNotifyForOperationUndelete(Boolean notifyForOperationUndelete) { + this.NotifyForOperationUndelete = notifyForOperationUndelete; + } } //CHECKSTYLE:ON - http://git-wip-us.apache.org/repos/asf/camel/blob/65cd95c5/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 661a896..834ea51 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 @@ -17,9 +17,14 @@ package org.apache.camel.component.salesforce.internal.processor; import java.io.InputStream; +import java.io.UnsupportedEncodingException; import java.lang.reflect.InvocationTargetException; import java.lang.reflect.Method; +import java.net.URLEncoder; +import java.util.HashMap; import java.util.Map; +import java.util.regex.Matcher; +import java.util.regex.Pattern; import org.apache.camel.AsyncCallback; import org.apache.camel.Exchange; @@ -30,12 +35,26 @@ import org.apache.camel.component.salesforce.internal.PayloadFormat; import org.apache.camel.component.salesforce.internal.client.DefaultRestClient; import org.apache.camel.component.salesforce.internal.client.RestClient; import org.apache.camel.util.ServiceHelper; - -import static org.apache.camel.component.salesforce.SalesforceEndpointConfig.*; +import org.eclipse.jetty.http.HttpMethods; + +import static org.apache.camel.component.salesforce.SalesforceEndpointConfig.APEX_METHOD; +import static org.apache.camel.component.salesforce.SalesforceEndpointConfig.APEX_QUERY_PARAM_PREFIX; +import static org.apache.camel.component.salesforce.SalesforceEndpointConfig.APEX_URL; +import static org.apache.camel.component.salesforce.SalesforceEndpointConfig.API_VERSION; +import static org.apache.camel.component.salesforce.SalesforceEndpointConfig.SOBJECT_BLOB_FIELD_NAME; +import static org.apache.camel.component.salesforce.SalesforceEndpointConfig.SOBJECT_CLASS; +import static org.apache.camel.component.salesforce.SalesforceEndpointConfig.SOBJECT_EXT_ID_NAME; +import static org.apache.camel.component.salesforce.SalesforceEndpointConfig.SOBJECT_EXT_ID_VALUE; +import static org.apache.camel.component.salesforce.SalesforceEndpointConfig.SOBJECT_FIELDS; +import static org.apache.camel.component.salesforce.SalesforceEndpointConfig.SOBJECT_ID; +import static org.apache.camel.component.salesforce.SalesforceEndpointConfig.SOBJECT_NAME; +import static org.apache.camel.component.salesforce.SalesforceEndpointConfig.SOBJECT_QUERY; +import static org.apache.camel.component.salesforce.SalesforceEndpointConfig.SOBJECT_SEARCH; public abstract class AbstractRestProcessor extends AbstractSalesforceProcessor { protected static final String RESPONSE_CLASS = AbstractRestProcessor.class.getName() + ".responseClass"; + private static final Pattern URL_TEMPLATE = Pattern.compile("\\{([^\\{\\}]+)\\}"); private RestClient restClient; private Map<String, Class<?>> classMap; @@ -128,6 +147,9 @@ public abstract class AbstractRestProcessor extends AbstractSalesforceProcessor case SEARCH: processSearch(exchange, callback); break; + case APEX_CALL: + processApexCall(exchange, callback); + break; default: throw new SalesforceException("Unknow operation name: " + operationName, null); } @@ -244,12 +266,12 @@ public abstract class AbstractRestProcessor extends AbstractSalesforceProcessor } restClient.createSObject(sObjectName, getRequestStream(exchange), - new RestClient.ResponseCallback() { - @Override - public void onResponse(InputStream response, SalesforceException exception) { - processResponse(exchange, response, exception, callback); - } - }); + new RestClient.ResponseCallback() { + @Override + public void onResponse(InputStream response, SalesforceException exception) { + processResponse(exchange, response, exception, callback); + } + }); } private void processUpdateSobject(final Exchange exchange, final AsyncCallback callback) throws SalesforceException { @@ -270,13 +292,13 @@ public abstract class AbstractRestProcessor extends AbstractSalesforceProcessor final String finalsObjectId = sObjectId; restClient.updateSObject(sObjectName, sObjectId, getRequestStream(exchange), - new RestClient.ResponseCallback() { - @Override - public void onResponse(InputStream response, SalesforceException exception) { - processResponse(exchange, response, exception, callback); - restoreFields(exchange, sObjectBase, finalsObjectId, null, null); - } - }); + new RestClient.ResponseCallback() { + @Override + public void onResponse(InputStream response, SalesforceException exception) { + processResponse(exchange, response, exception, callback); + restoreFields(exchange, sObjectBase, finalsObjectId, null, null); + } + }); } private void processDeleteSobject(final Exchange exchange, final AsyncCallback callback) throws SalesforceException { @@ -325,13 +347,13 @@ public abstract class AbstractRestProcessor extends AbstractSalesforceProcessor final Object finalOldValue = oldValue; restClient.getSObjectWithId(sObjectName, sObjectExtIdName, sObjectExtIdValue, - new RestClient.ResponseCallback() { - @Override - public void onResponse(InputStream response, SalesforceException exception) { - processResponse(exchange, response, exception, callback); - restoreFields(exchange, sObjectBase, null, sObjectExtIdName, finalOldValue); - } - }); + new RestClient.ResponseCallback() { + @Override + public void onResponse(InputStream response, SalesforceException exception) { + processResponse(exchange, response, exception, callback); + restoreFields(exchange, sObjectBase, null, sObjectExtIdName, finalOldValue); + } + }); } private void processUpsertSobject(final Exchange exchange, final AsyncCallback callback) throws SalesforceException { @@ -357,12 +379,12 @@ public abstract class AbstractRestProcessor extends AbstractSalesforceProcessor final Object finalOldValue = oldValue; restClient.upsertSObject(sObjectName, sObjectExtIdName, sObjectExtIdValue, getRequestStream(exchange), new RestClient.ResponseCallback() { - @Override - public void onResponse(InputStream response, SalesforceException exception) { - processResponse(exchange, response, exception, callback); - restoreFields(exchange, sObjectBase, null, sObjectExtIdName, finalOldValue); - } - }); + @Override + public void onResponse(InputStream response, SalesforceException exception) { + processResponse(exchange, response, exception, callback); + restoreFields(exchange, sObjectBase, null, sObjectExtIdName, finalOldValue); + } + }); } private void processDeleteSobjectWithId(final Exchange exchange, final AsyncCallback callback) throws SalesforceException { @@ -384,13 +406,13 @@ public abstract class AbstractRestProcessor extends AbstractSalesforceProcessor final Object finalOldValue = oldValue; restClient.deleteSObjectWithId(sObjectName, sObjectExtIdName, sObjectExtIdValue, - new RestClient.ResponseCallback() { - @Override - public void onResponse(InputStream response, SalesforceException exception) { - processResponse(exchange, response, exception, callback); - restoreFields(exchange, sObjectBase, null, sObjectExtIdName, finalOldValue); - } - }); + new RestClient.ResponseCallback() { + @Override + public void onResponse(InputStream response, SalesforceException exception) { + processResponse(exchange, response, exception, callback); + restoreFields(exchange, sObjectBase, null, sObjectExtIdName, finalOldValue); + } + }); } private void processGetBlobField(final Exchange exchange, final AsyncCallback callback) throws SalesforceException { @@ -412,13 +434,13 @@ public abstract class AbstractRestProcessor extends AbstractSalesforceProcessor final String sObjectId = sObjectIdValue; restClient.getBlobField(sObjectName, sObjectId, sObjectBlobFieldName, - new RestClient.ResponseCallback() { - @Override - public void onResponse(InputStream response, SalesforceException exception) { - processResponse(exchange, response, exception, callback); - restoreFields(exchange, sObjectBase, sObjectId, null, null); - } - }); + new RestClient.ResponseCallback() { + @Override + public void onResponse(InputStream response, SalesforceException exception) { + processResponse(exchange, response, exception, callback); + restoreFields(exchange, sObjectBase, sObjectId, null, null); + } + }); } private void processQuery(final Exchange exchange, final AsyncCallback callback) throws SalesforceException { @@ -461,6 +483,90 @@ public abstract class AbstractRestProcessor extends AbstractSalesforceProcessor }); } + private void processApexCall(final Exchange exchange, final AsyncCallback callback) throws SalesforceException { + + // HTTP method, URL and query params for APEX call + final String apexUrl = getApexUrl(exchange); + String apexMethod = getParameter(APEX_METHOD, exchange, IGNORE_BODY, IS_OPTIONAL); + // default to GET + if (apexMethod == null) { + apexMethod = HttpMethods.GET; + log.debug("Using HTTP GET method by default for APEX REST call for {}", apexUrl); + } + final Map<String, Object> queryParams = getQueryParams(exchange); + + // set response class + setResponseClass(exchange, getParameter(SOBJECT_NAME, exchange, IGNORE_BODY, IS_OPTIONAL)); + + // set request stream + final Object requestBody = exchange.getIn().getBody(); + final InputStream requestDto = + (requestBody != null && !(requestBody instanceof Map)) ? getRequestStream(exchange) : null; + + restClient.apexCall(apexMethod, apexUrl, queryParams, requestDto, + new RestClient.ResponseCallback() { + @Override + public void onResponse(InputStream response, SalesforceException exception) { + processResponse(exchange, response, exception, callback); + } + }); + } + + private String getApexUrl(Exchange exchange) throws SalesforceException { + final String apexUrl = getParameter(APEX_URL, exchange, IGNORE_BODY, NOT_OPTIONAL); + + final Matcher matcher = URL_TEMPLATE.matcher(apexUrl); + StringBuilder result = new StringBuilder(); + int start = 0; + while (matcher.find()) { + // append part before parameter template + result.append(apexUrl.substring(start, matcher.start())); + start = matcher.end(); + + // append template value from exchange header + final String parameterName = matcher.group(1); + final Object value = exchange.getIn().getHeader(parameterName); + if (value == null) { + throw new IllegalArgumentException("Missing APEX URL template header " + parameterName); + } + try { + result.append(URLEncoder.encode(String.valueOf(value), "UTF-8").replaceAll("\\+", "%20")); + } catch (UnsupportedEncodingException e) { + throw new SalesforceException("Unexpected error: " + e.getMessage(), e); + } + } + if (start != 0) { + // append remaining URL + result.append(apexUrl.substring(start)); + final String resolvedUrl = result.toString(); + log.debug("Resolved APEX URL {} to {}", apexUrl, resolvedUrl); + return resolvedUrl; + } + return apexUrl; + } + + @SuppressWarnings("unchecked") + private Map<String, Object> getQueryParams(Exchange exchange) { + + // use endpoint map + Map<String, Object> queryParams = new HashMap<String, Object>(endpoint.getConfiguration().getApexQueryParams()); + + // look for individual properties, allowing endpoint properties to be overridden + for (Map.Entry<String, Object> entry : exchange.getIn().getHeaders().entrySet()) { + if (entry.getKey().startsWith(APEX_QUERY_PARAM_PREFIX)) { + queryParams.put(entry.getKey().substring(APEX_QUERY_PARAM_PREFIX.length()), entry.getValue()); + } + } + // add params from body if it's a map + final Object body = exchange.getIn().getBody(); + if (body instanceof Map) { + queryParams.putAll((Map<String, Object>) body); + } + + log.debug("Using APEX query params {}", queryParams); + return queryParams; + } + private void restoreFields(Exchange exchange, AbstractSObjectBase sObjectBase, String sObjectId, String sObjectExtIdName, Object oldValue) { // restore fields http://git-wip-us.apache.org/repos/asf/camel/blob/65cd95c5/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 b29f36b..f3c8b4d 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,7 @@ import org.apache.camel.Exchange; import org.apache.camel.Message; import org.apache.camel.component.salesforce.SalesforceEndpoint; 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.AbstractDTOBase; import org.apache.camel.component.salesforce.api.dto.CreateSObjectResult; import org.apache.camel.component.salesforce.api.dto.GlobalObjects; import org.apache.camel.component.salesforce.api.dto.RestResources; @@ -113,11 +113,11 @@ public class JsonRestProcessor extends AbstractRestProcessor { Message in = exchange.getIn(); request = in.getBody(InputStream.class); if (request == null) { - AbstractSObjectBase sObject = in.getBody(AbstractSObjectBase.class); - if (sObject != null) { - // marshall the SObject + AbstractDTOBase dto = in.getBody(AbstractDTOBase.class); + if (dto != null) { + // marshall the DTO ByteArrayOutputStream out = new ByteArrayOutputStream(); - objectMapper.writeValue(out, sObject); + objectMapper.writeValue(out, dto); request = new ByteArrayInputStream(out.toByteArray()); } else { // if all else fails, get body as String http://git-wip-us.apache.org/repos/asf/camel/blob/65cd95c5/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 a10de93..f11bc2f 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 @@ -37,7 +37,7 @@ import org.apache.camel.Message; import org.apache.camel.component.salesforce.SalesforceEndpoint; import org.apache.camel.component.salesforce.api.JodaTimeConverter; 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.AbstractDTOBase; import org.apache.camel.component.salesforce.api.dto.CreateSObjectResult; import org.apache.camel.component.salesforce.api.dto.GlobalObjects; import org.apache.camel.component.salesforce.api.dto.RestResources; @@ -144,6 +144,11 @@ public class XmlRestProcessor extends AbstractRestProcessor { exchange.setProperty(RESPONSE_CLASS, SearchResults.class); break; + case APEX_CALL: + // need to add alias for Salesforce XML that uses SObject name as root element + exchange.setProperty(RESPONSE_ALIAS, "response"); + break; + default: // ignore, some operations do not require alias or class exchange properties } @@ -156,14 +161,14 @@ public class XmlRestProcessor extends AbstractRestProcessor { Message in = exchange.getIn(); InputStream request = in.getBody(InputStream.class); if (request == null) { - AbstractSObjectBase sObject = in.getBody(AbstractSObjectBase.class); - if (sObject != null) { - // marshall the SObject + AbstractDTOBase dto = in.getBody(AbstractDTOBase.class); + if (dto != null) { + // marshall the DTO // first process annotations on the class, for things like alias, etc. - localXStream.processAnnotations(sObject.getClass()); + localXStream.processAnnotations(dto.getClass()); ByteArrayOutputStream out = new ByteArrayOutputStream(); // make sure we write the XML with the right encoding - localXStream.toXML(sObject, new OutputStreamWriter(out, StringUtil.__UTF8_CHARSET)); + localXStream.toXML(dto, new OutputStreamWriter(out, StringUtil.__UTF8_CHARSET)); request = new ByteArrayInputStream(out.toByteArray()); } else { // if all else fails, get body as String http://git-wip-us.apache.org/repos/asf/camel/blob/65cd95c5/components/camel-salesforce/camel-salesforce-component/src/main/java/org/apache/camel/component/salesforce/internal/streaming/PushTopicHelper.java ---------------------------------------------------------------------- diff --git a/components/camel-salesforce/camel-salesforce-component/src/main/java/org/apache/camel/component/salesforce/internal/streaming/PushTopicHelper.java b/components/camel-salesforce/camel-salesforce-component/src/main/java/org/apache/camel/component/salesforce/internal/streaming/PushTopicHelper.java index 4924aad..7423064 100644 --- a/components/camel-salesforce/camel-salesforce-component/src/main/java/org/apache/camel/component/salesforce/internal/streaming/PushTopicHelper.java +++ b/components/camel-salesforce/camel-salesforce-component/src/main/java/org/apache/camel/component/salesforce/internal/streaming/PushTopicHelper.java @@ -41,11 +41,28 @@ public class PushTopicHelper { private final SalesforceEndpointConfig config; private final String topicName; private final RestClient restClient; + private final boolean preApi29; public PushTopicHelper(SalesforceEndpointConfig config, String topicName, RestClient restClient) { this.config = config; this.topicName = topicName; this.restClient = restClient; + this.preApi29 = Double.valueOf(config.getApiVersion()) < 29.0; + + // validate notify fields right away + if (preApi29 && (config.getNotifyForOperationCreate() != null + || config.getNotifyForOperationDelete() != null + || config.getNotifyForOperationUndelete() != null + || config.getNotifyForOperationUpdate() != null)) { + throw new IllegalArgumentException("NotifyForOperationCreate, NotifyForOperationDelete" + + ", NotifyForOperationUndelete, and NotifyForOperationUpdate" + + " are only supported since API version 29.0" + + ", instead use NotifyForOperations"); + } else if (!preApi29 && config.getNotifyForOperations() != null) { + throw new IllegalArgumentException("NotifyForOperations is readonly since API version 29.0" + + ", instead use NotifyForOperationCreate, NotifyForOperationDelete" + + ", NotifyForOperationUndelete, and NotifyForOperationUpdate"); + } } public void createOrUpdateTopic() throws CamelException { @@ -63,8 +80,9 @@ public class PushTopicHelper { if (!callback.await(API_TIMEOUT, TimeUnit.SECONDS)) { throw new SalesforceException("API call timeout!", null); } - if (callback.getException() != null) { - throw callback.getException(); + final SalesforceException callbackException = callback.getException(); + if (callbackException != null) { + throw callbackException; } QueryRecordsPushTopic records = OBJECT_MAPPER.readValue(callback.getResponse(), QueryRecordsPushTopic.class); @@ -73,13 +91,21 @@ public class PushTopicHelper { PushTopic topic = records.getRecords().get(0); LOG.info("Found existing topic {}: {}", topicName, topic); - // check if we need to update topic query, notifyForFields or notifyForOperations + // check if we need to update topic + final boolean notifyOperationsChanged; + if (preApi29) { + notifyOperationsChanged = + notEquals(config.getNotifyForOperations(), topic.getNotifyForOperations()); + } else { + notifyOperationsChanged = + notEquals(config.getNotifyForOperationCreate(), topic.getNotifyForOperationCreate()) + || notEquals(config.getNotifyForOperationDelete(), topic.getNotifyForOperationDelete()) + || notEquals(config.getNotifyForOperationUndelete(), topic.getNotifyForOperationUndelete()) + || notEquals(config.getNotifyForOperationUpdate(), topic.getNotifyForOperationUpdate()); + } if (!query.equals(topic.getQuery()) - || (config.getNotifyForFields() != null - && !config.getNotifyForFields().equals(topic.getNotifyForFields())) - || (config.getNotifyForOperations() != null - && !config.getNotifyForOperations().equals(topic.getNotifyForOperations())) - ) { + || notEquals(config.getNotifyForFields(), topic.getNotifyForFields()) + || notifyOperationsChanged) { if (!config.isUpdateTopic()) { String msg = "Query doesn't match existing Topic and updateTopic is set to false"; @@ -126,7 +152,14 @@ public class PushTopicHelper { topic.setQuery(config.getSObjectQuery()); topic.setDescription("Topic created by Camel Salesforce component"); topic.setNotifyForFields(config.getNotifyForFields()); - topic.setNotifyForOperations(config.getNotifyForOperations()); + if (preApi29) { + topic.setNotifyForOperations(config.getNotifyForOperations()); + } else { + topic.setNotifyForOperationCreate(config.getNotifyForOperationCreate()); + topic.setNotifyForOperationDelete(config.getNotifyForOperationDelete()); + topic.setNotifyForOperationUndelete(config.getNotifyForOperationUndelete()); + topic.setNotifyForOperationUpdate(config.getNotifyForOperationUpdate()); + } LOG.info("Creating Topic {}: {}", topicName, topic); final SyncResponseCallback callback = new SyncResponseCallback(); @@ -137,8 +170,9 @@ public class PushTopicHelper { if (!callback.await(API_TIMEOUT, TimeUnit.SECONDS)) { throw new SalesforceException("API call timeout!", null); } - if (callback.getException() != null) { - throw callback.getException(); + final SalesforceException callbackException = callback.getException(); + if (callbackException != null) { + throw callbackException; } CreateSObjectResult result = OBJECT_MAPPER.readValue(callback.getResponse(), CreateSObjectResult.class); @@ -182,7 +216,14 @@ public class PushTopicHelper { final PushTopic topic = new PushTopic(); topic.setQuery(query); topic.setNotifyForFields(config.getNotifyForFields()); - topic.setNotifyForOperations(config.getNotifyForOperations()); + if (preApi29) { + topic.setNotifyForOperations(config.getNotifyForOperations()); + } else { + topic.setNotifyForOperationCreate(config.getNotifyForOperationCreate()); + topic.setNotifyForOperationDelete(config.getNotifyForOperationDelete()); + topic.setNotifyForOperationUndelete(config.getNotifyForOperationUndelete()); + topic.setNotifyForOperationUpdate(config.getNotifyForOperationUpdate()); + } restClient.updateSObject("PushTopic", topicId, new ByteArrayInputStream(OBJECT_MAPPER.writeValueAsBytes(topic)), @@ -191,8 +232,9 @@ public class PushTopicHelper { if (!callback.await(API_TIMEOUT, TimeUnit.SECONDS)) { throw new SalesforceException("API call timeout!", null); } - if (callback.getException() != null) { - throw callback.getException(); + final SalesforceException callbackException = callback.getException(); + if (callbackException != null) { + throw callbackException; } } catch (SalesforceException e) { @@ -219,4 +261,8 @@ public class PushTopicHelper { } } + private static <T> boolean notEquals(T o1, T o2) { + return o1 != null && !o1.equals(o2); + } + } \ No newline at end of file