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/12/14 08:56:54 UTC

camel git commit: SObjectDescription metadata in DTOs

Repository: camel
Updated Branches:
  refs/heads/master 212a8219d -> e1f3de664


SObjectDescription metadata in DTOs

This commit adds SObjectDescription by making the DTOs extend
AbstractDescribedSObjectBase (new class) instead of AbstractSObjectBase.

The code generation is performed in Velocity template by recursing the
bean SObjectDescription properties. Helper methods are added to
GeneratorUtility that help track the stack of the recursive invocation.

To prevent hitting Java method length restriction (64K) some properties
are blacklisted: PicklistValues and ChildRelationships which most likely
would not be needed in the component operation anyways.

(cherry picked from commit 2d14fd8caa58f4520cf70801a27a0a57b023f492)


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

Branch: refs/heads/master
Commit: e1f3de6644dd1533c1cc80853ef479106a6cb5a8
Parents: 212a821
Author: Zoran Regvart <zo...@regvart.com>
Authored: Thu Dec 8 11:27:28 2016 +0100
Committer: Claus Ibsen <da...@apache.org>
Committed: Wed Dec 14 09:55:22 2016 +0100

----------------------------------------------------------------------
 .../api/dto/AbstractDescribedSObjectBase.java   | 36 ++++++++++
 .../apache/camel/maven/CamelSalesforceMojo.java | 65 +++++++++++++++++
 .../src/main/resources/sobject-pojo.vm          | 76 +++++++++++++++++++-
 3 files changed, 175 insertions(+), 2 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/camel/blob/e1f3de66/components/camel-salesforce/camel-salesforce-component/src/main/java/org/apache/camel/component/salesforce/api/dto/AbstractDescribedSObjectBase.java
----------------------------------------------------------------------
diff --git a/components/camel-salesforce/camel-salesforce-component/src/main/java/org/apache/camel/component/salesforce/api/dto/AbstractDescribedSObjectBase.java b/components/camel-salesforce/camel-salesforce-component/src/main/java/org/apache/camel/component/salesforce/api/dto/AbstractDescribedSObjectBase.java
new file mode 100644
index 0000000..cfcd260
--- /dev/null
+++ b/components/camel-salesforce/camel-salesforce-component/src/main/java/org/apache/camel/component/salesforce/api/dto/AbstractDescribedSObjectBase.java
@@ -0,0 +1,36 @@
+/**
+ * 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;
+
+/**
+ * Subclass of {@link AbstractSObjectBase} that contains additional metadata about SObject. The
+ * {@code camel-salesforce-maven-plugin} generates Data Transfer Objects (DTO) by subclassing this class and
+ * implementing the {@link AbstractDescribedSObjectBase#description()} method from the metadata received from
+ * Salesforce. Note that there are no guarantees about all fields in the {@link SObjectDescription} being set. This is
+ * to prevent unnecessary memory usage, and to prevent running into Java method length limit.
+ */
+public abstract class AbstractDescribedSObjectBase extends AbstractSObjectBase {
+
+    /**
+     * Additional metadata about this SObject. There are no guarantees that all of the fields of
+     * {@link SObjectDescription} will be set.
+     *
+     * @return metadata description of this SObject
+     */
+    public abstract SObjectDescription description();
+
+}

http://git-wip-us.apache.org/repos/asf/camel/blob/e1f3de66/components/camel-salesforce/camel-salesforce-maven-plugin/src/main/java/org/apache/camel/maven/CamelSalesforceMojo.java
----------------------------------------------------------------------
diff --git a/components/camel-salesforce/camel-salesforce-maven-plugin/src/main/java/org/apache/camel/maven/CamelSalesforceMojo.java b/components/camel-salesforce/camel-salesforce-maven-plugin/src/main/java/org/apache/camel/maven/CamelSalesforceMojo.java
index 811f5d0..39ce43a 100644
--- a/components/camel-salesforce/camel-salesforce-maven-plugin/src/main/java/org/apache/camel/maven/CamelSalesforceMojo.java
+++ b/components/camel-salesforce/camel-salesforce-maven-plugin/src/main/java/org/apache/camel/maven/CamelSalesforceMojo.java
@@ -16,6 +16,7 @@
  */
 package org.apache.camel.maven;
 
+import java.beans.PropertyDescriptor;
 import java.io.BufferedWriter;
 import java.io.File;
 import java.io.FileWriter;
@@ -24,18 +25,24 @@ import java.lang.reflect.Field;
 import java.net.URI;
 import java.security.GeneralSecurityException;
 import java.util.ArrayList;
+import java.util.Arrays;
 import java.util.Collections;
 import java.util.Comparator;
 import java.util.Date;
 import java.util.HashMap;
 import java.util.HashSet;
+import java.util.LinkedList;
 import java.util.List;
 import java.util.Map;
 import java.util.Properties;
+import java.util.Queue;
 import java.util.Set;
+import java.util.Stack;
 import java.util.TreeSet;
 import java.util.concurrent.TimeUnit;
+import java.util.concurrent.atomic.AtomicInteger;
 import java.util.regex.Pattern;
+import java.util.stream.Collectors;
 
 import com.fasterxml.jackson.databind.ObjectMapper;
 
@@ -58,6 +65,8 @@ import org.apache.camel.component.salesforce.internal.client.SyncResponseCallbac
 import org.apache.camel.util.IntrospectionSupport;
 import org.apache.camel.util.ObjectHelper;
 import org.apache.camel.util.jsse.SSLContextParameters;
+import org.apache.commons.lang.ClassUtils;
+import org.apache.commons.lang.StringUtils;
 import org.apache.log4j.Logger;
 import org.apache.maven.plugin.AbstractMojo;
 import org.apache.maven.plugin.MojoExecutionException;
@@ -734,7 +743,10 @@ public class CamelSalesforceMojo extends AbstractMojo {
         private static final String BASE64BINARY = "base64Binary";
         private static final String MULTIPICKLIST = "multipicklist";
         private static final String PICKLIST = "picklist";
+        private static final List<String> BLACKLISTED_PROPERTIES = Arrays.asList("PicklistValues", "ChildRelationships");
         private boolean useStringsForPicklists;
+        private final Map<String, AtomicInteger> varNames = new HashMap<>();
+        private Stack<String> stack;
 
         public GeneratorUtility(Boolean useStringsForPicklists) {
             this.useStringsForPicklists = Boolean.TRUE.equals(useStringsForPicklists);
@@ -852,6 +864,59 @@ public class CamelSalesforceMojo extends AbstractMojo {
 
             return changed ? result.toString().toUpperCase() : value.toUpperCase();
         }
+
+        public boolean includeList(final List<?> list, final String propertyName) {
+            return !list.isEmpty() && !BLACKLISTED_PROPERTIES.contains(propertyName);
+        }
+        public boolean notNull(final Object val) {
+            return val != null;
+        }
+
+        public Set<Map.Entry<String, Object>> propertiesOf(final Object object) {
+            final Map<String, Object> properties = new HashMap<>();
+            IntrospectionSupport.getProperties(object, properties, null, false);
+
+            return properties.entrySet().stream()
+                .collect(Collectors.toMap(e -> StringUtils.capitalize(e.getKey()), Map.Entry::getValue)).entrySet();
+        }
+
+        public String variableName(final String given) {
+            final String base = StringUtils.uncapitalize(given);
+
+            AtomicInteger counter = varNames.get(base);
+            if (counter == null) {
+                counter = new AtomicInteger(0);
+                varNames.put(base, counter);
+            }
+
+            return base + counter.incrementAndGet();
+        }
+
+        public boolean isPrimitiveOrBoxed(final Object object) {
+            final Class<?> clazz = object.getClass();
+
+            return clazz.isPrimitive() || Boolean.class.equals(clazz) || Byte.class.equals(clazz)
+                || Character.class.equals(clazz) || Short.class.equals(clazz) || Integer.class.equals(clazz)
+                || Long.class.equals(clazz) || Double.class.equals(clazz) || Float.class.equals(clazz);
+        }
+
+        public void start(final String initial) {
+            stack = new Stack<>();
+            stack.push(initial);
+            varNames.clear();
+        }
+
+        public String current() {
+            return stack.peek();
+        }
+
+        public void push(final String additional) {
+            stack.push(additional);
+        }
+
+        public void pop() {
+            stack.pop();
+        }
     }
 
 }

http://git-wip-us.apache.org/repos/asf/camel/blob/e1f3de66/components/camel-salesforce/camel-salesforce-maven-plugin/src/main/resources/sobject-pojo.vm
----------------------------------------------------------------------
diff --git a/components/camel-salesforce/camel-salesforce-maven-plugin/src/main/resources/sobject-pojo.vm b/components/camel-salesforce/camel-salesforce-maven-plugin/src/main/resources/sobject-pojo.vm
index 5711fb3..fd5f133 100644
--- a/components/camel-salesforce/camel-salesforce-maven-plugin/src/main/resources/sobject-pojo.vm
+++ b/components/camel-salesforce/camel-salesforce-maven-plugin/src/main/resources/sobject-pojo.vm
@@ -21,6 +21,9 @@
  */
 package $packageName;
 
+import java.util.ArrayList;
+import java.util.List;
+
 ## add imports for XStreamConverter and PicklistEnumConverter if needed
 #set ( $hasPicklists = $utility.hasPicklists($desc) )
 #set ( $hasMultiSelectPicklists = $utility.hasMultiSelectPicklists($desc) )
@@ -28,6 +31,7 @@ import com.thoughtworks.xstream.annotations.XStreamAlias;
 #if ( ($hasPicklists && !$useStringsForPicklists) || $hasMultiSelectPicklists )
 import com.thoughtworks.xstream.annotations.XStreamConverter;
 #end
+
 #if ( $hasPicklists && !$useStringsForPicklists )
 import org.apache.camel.component.salesforce.api.PicklistEnumConverter;
 #end
@@ -42,7 +46,15 @@ import org.apache.camel.component.salesforce.api.MultiSelectPicklistDeserializer
 import org.apache.camel.component.salesforce.api.MultiSelectPicklistSerializer;
 #end
 #end
-import org.apache.camel.component.salesforce.api.dto.AbstractSObjectBase;
+import org.apache.camel.component.salesforce.api.dto.AbstractDescribedSObjectBase;
+import org.apache.camel.component.salesforce.api.dto.ChildRelationShip;
+import org.apache.camel.component.salesforce.api.dto.InfoUrls;
+import org.apache.camel.component.salesforce.api.dto.NamedLayoutInfo;
+import org.apache.camel.component.salesforce.api.dto.RecordTypeInfo;
+import org.apache.camel.component.salesforce.api.dto.SObjectDescription;
+import org.apache.camel.component.salesforce.api.dto.SObjectDescriptionUrls;
+import org.apache.camel.component.salesforce.api.dto.SObjectField;
+
 import com.fasterxml.jackson.annotation.JsonProperty;
 #if ( $hasMultiSelectPicklists )
 import com.fasterxml.jackson.databind.annotation.JsonDeserialize;
@@ -55,7 +67,9 @@ import com.fasterxml.jackson.annotation.JsonInclude.Include;
  * Salesforce DTO for SObject $desc.Name
  */
 @XStreamAlias("$desc.Name")
-public class $desc.Name extends AbstractSObjectBase {
+public class $desc.Name extends AbstractDescribedSObjectBase {
+
+    private static final SObjectDescription DESCRIPTION = createSObjectDescription();
 
 #foreach ( $field in $desc.Fields )
 #if ( $utility.notBaseField($field.Name) )
@@ -113,4 +127,62 @@ public class $desc.Name extends AbstractSObjectBase {
 
 #end
 #end
+
+##
+## macro to generate source code based on Java beans (supports SObjectDescription properties)
+##
+#macro( generateSource $obj )## MACRO
+#foreach ( $p in $utility.propertiesOf($obj) )## PROPERTY LOOP
+#if ( $utility.notNull(${p.value}) )## VALUE DEFINED CONDITION
+#if ( ${p.value.class.name} == "java.lang.String" )## STRING CONDITION
+        ${utility.current()}.set${p.key}("${p.value}");
+#elseif ( ${utility.isPrimitiveOrBoxed(${p.value})} )## PRIMITIVE OR BOXED CONDITION
+        ${utility.current()}.set${p.key}(${p.value});
+#elseif ( ${p.value.class.name} == "java.util.ArrayList" )## LIST CONDITION
+#if ( ${utility.includeList(${p.value}, ${p.key})} )## VALUE NOT EMPTY CONDITION
+#set ( $var = ${utility.variableName(${p.key})} )
+
+        final List<${p.value[0].class.simpleName}> ${var} = new ArrayList<>();
+        ${utility.current()}.set${p.key}(${var});
+${utility.push($var)}
+#if ( ${p.value[0].class.name} == "java.lang.String" )## STRING LIST ELEMENTS
+#foreach ( $i in ${p.value} )## STRING LIST LOOP
+        ${utility.current()}.add("${i}");
+#end## END STRING LIST LOOP
+${utility.pop()}
+#else
+#foreach ( $i in ${p.value} )## BEAN LIST LOOP
+#set ( $var = ${utility.variableName(${i.class.simpleName})} )
+        final ${i.class.simpleName} $var = new ${i.class.simpleName}();
+        ${utility.current()}.add(${var});
+${utility.push($var)}
+#generateSource( ${i} )
+${utility.pop()}
+#end## END BEAN LIST LOOP
+${utility.pop()}
+#end## END STRING LIST ELEMENTS
+#end## END VALUE NOT EMPTY CONDITION
+#else
+#set ( $var = ${utility.variableName(${p.value.class.simpleName})} )
+${utility.push($var)}
+        final ${p.value.class.simpleName} $var = new ${p.value.class.simpleName}();
+#generateSource( ${p.value} )
+${utility.pop()}        ${utility.current()}.set${p.key}(${var});
+#end## END TYPE CONDITION
+#end## VALUE DEFINED CONDITION
+#end## END PROPERTY LOOP
+#end## END MACRO
+    @Override
+    public final SObjectDescription description() {
+        return DESCRIPTION;
+    }
+
+    private static SObjectDescription createSObjectDescription() {
+        final SObjectDescription description = new SObjectDescription();
+
+$utility.start("description")
+#generateSource( $desc )
+
+        return description;
+    }
 }