Skip to content
Browse files

Initial commit, master branch

  • Loading branch information...
0 parents commit ec626481f36d1192fbcd5c098b5174f8579cf3c0 @tkral tkral committed May 27, 2011
Showing with 9,842 additions and 0 deletions.
  1. +13 −0 .gitignore
  2. +15 −0 build-tools/pom.xml
  3. +224 −0 build-tools/src/main/resources/checkstyle/force-sdk-checks.xml
  4. +56 −0 build-tools/src/main/resources/checkstyle/force-sdk-suppressions.xml
  5. +23 −0 build-tools/src/main/resources/license/header.txt
  6. +40 −0 build-tools/src/main/resources/license/stringtemplatedefinition.xml
  7. +88 −0 codegen/pom.xml
  8. +237 −0 codegen/src/main/java/com/force/sdk/codegen/CodeGenerator.java
  9. +214 −0 codegen/src/main/java/com/force/sdk/codegen/ForceJPAClassGenerator.java
  10. +199 −0 codegen/src/main/java/com/force/sdk/codegen/ForceJPAClassGeneratorUtils.java
  11. +80 −0 codegen/src/main/java/com/force/sdk/codegen/builder/BaseBuilder.java
  12. +106 −0 codegen/src/main/java/com/force/sdk/codegen/builder/ForcePicklistEnumBuilder.java
  13. +104 −0 codegen/src/main/java/com/force/sdk/codegen/builder/JPAAnnotationBuilder.java
  14. +56 −0 codegen/src/main/java/com/force/sdk/codegen/builder/JavaCommentBuilder.java
  15. +48 −0 codegen/src/main/java/com/force/sdk/codegen/filter/DataFilter.java
  16. +49 −0 codegen/src/main/java/com/force/sdk/codegen/filter/NoOpDataFilter.java
  17. +98 −0 codegen/src/main/java/com/force/sdk/codegen/filter/ObjectNameDataFilter.java
  18. +129 −0 codegen/src/main/java/com/force/sdk/codegen/filter/ObjectNameWithRefDataFilter.java
  19. +102 −0 codegen/src/main/java/com/force/sdk/codegen/renderer/ForceJPAClassRenderer.java
  20. +259 −0 codegen/src/main/java/com/force/sdk/codegen/renderer/ForceJPAFieldRenderer.java
  21. +52 −0 codegen/src/main/java/com/force/sdk/codegen/selector/DataSelector.java
  22. +50 −0 codegen/src/main/java/com/force/sdk/codegen/selector/DefaultDataSelector.java
  23. +134 −0 codegen/src/main/java/com/force/sdk/codegen/selector/ForceJPAClassDataSelector.java
  24. +82 −0 codegen/src/main/java/com/force/sdk/codegen/template/StringTemplateWrapper.java
  25. +69 −0 codegen/src/main/java/com/force/sdk/codegen/template/Template.java
  26. +61 −0 codegen/src/main/java/com/force/sdk/codegen/writer/BasicWriterProvider.java
  27. +152 −0 codegen/src/main/java/com/force/sdk/codegen/writer/ForceJPAFileWriterProvider.java
  28. +55 −0 codegen/src/main/java/com/force/sdk/codegen/writer/WriterProvider.java
  29. +76 −0 codegen/src/main/resources/templates/ForceObject.st
  30. +76 −0 codegen/src/main/resources/templates/PicklistValueEnum.st
  31. +105 −0 codegen/src/test/java/com/force/sdk/codegen/CodeGeneratorTest.java
  32. +85 −0 codegen/src/test/java/com/force/sdk/codegen/ForceJPAClassGeneratorTest.java
  33. +62 −0 codegen/src/test/java/com/force/sdk/codegen/ForceJPAClassGeneratorUtilsTest.java
  34. +100 −0 codegen/src/test/java/com/force/sdk/codegen/builder/ForcePicklistEnumBuilderTest.java
  35. +84 −0 codegen/src/test/java/com/force/sdk/codegen/builder/JPAAnnotationBuilderTest.java
  36. +47 −0 codegen/src/test/java/com/force/sdk/codegen/builder/JavaCommentBuilderTest.java
  37. +62 −0 codegen/src/test/java/com/force/sdk/codegen/filter/NoOpDataFilterTest.java
  38. +61 −0 codegen/src/test/java/com/force/sdk/codegen/filter/ObjectNameDataFilterTest.java
  39. +157 −0 codegen/src/test/java/com/force/sdk/codegen/filter/ObjectNameWithRefDataFilterTest.java
  40. +157 −0 codegen/src/test/java/com/force/sdk/codegen/renderer/ForceJPAClassRendererTest.java
  41. +384 −0 codegen/src/test/java/com/force/sdk/codegen/renderer/ForceJPAFieldRendererTest.java
  42. +58 −0 codegen/src/test/java/com/force/sdk/codegen/selector/DefaultDataSelectorTest.java
  43. +215 −0 codegen/src/test/java/com/force/sdk/codegen/selector/ForceJPAClassDataSelectorTest.java
  44. +39 −0 codegen/src/test/resources/findbugs-exclude.xml
  45. +157 −0 connector/doc/connection-url.md
  46. +59 −0 connector/doc/native-api.md
  47. +66 −0 connector/pom.xml
  48. +3 −0 connector/src/main/java/META-INF/MANIFEST.MF
  49. +181 −0 connector/src/main/java/com/force/sdk/connector/ForceConnectionProperty.java
  50. +49 −0 connector/src/main/java/com/force/sdk/connector/ForceConnector.java
  51. +330 −0 connector/src/main/java/com/force/sdk/connector/ForceConnectorConfig.java
  52. +317 −0 connector/src/main/java/com/force/sdk/connector/ForceConnectorUtils.java
  53. +623 −0 connector/src/main/java/com/force/sdk/connector/ForceServiceConnector.java
  54. +116 −0 connector/src/main/java/com/force/sdk/connector/logger/ForceLoggerStream.java
  55. +110 −0 connector/src/main/java/com/force/sdk/connector/threadlocal/ForceThreadLocalStore.java
  56. +299 −0 connector/src/test/java/com/force/sdk/connector/ForceConnectorConfigTest.java
  57. +66 −0 connector/src/test/java/com/force/sdk/connector/ForceConnectorUtilsTest.java
  58. +38 −0 connector/src/test/resources/findbugs-exclude.xml
  59. +27 −0 connector/src/test/resources/unitconnurl.properties
  60. +32 −0 connector/src/test/resources/unitconnuserinfo.properties
  61. +28 −0 doc/_config.yml
  62. +115 −0 doc/_includes/toc.html
  63. +56 −0 doc/_layouts/doc.html
  64. +97 −0 doc/_plugins/toc.rb
  65. +56 −0 doc/force-sdk-overview.md
  66. +61 −0 doc/java-database-terminology.md
  67. +85 −0 doc/quick-start.md
  68. +66 −0 doc/sts.md
  69. +170 −0 doc/stylesheets/coderay.css
  70. +311 −0 doc/stylesheets/docs.css
  71. +83 −0 doc/stylesheets/header.css
  72. +13 −0 javasdk-test/.gitignore
  73. +149 −0 javasdk-test/codegen-test/pom.xml
  74. +88 −0 javasdk-test/codegen-test/src/main/java/com/force/sdk/codegen/JPATestClassGenerator.java
  75. +28 −0 javasdk-test/codegen-test/src/main/resources/codegen-test.properties
  76. +225 −0 javasdk-test/codegen-test/src/test/java/com/force/sdk/codegen/BaseGeneratedClassFTest.java
  77. +241 −0 javasdk-test/codegen-test/src/test/java/com/force/sdk/codegen/CreatedClassCRUDFTest.java
  78. +267 −0 javasdk-test/codegen-test/src/test/java/com/force/sdk/codegen/GeneratedClassCUDFTest.java
  79. +254 −0 javasdk-test/codegen-test/src/test/java/com/force/sdk/codegen/GeneratedClassReadFTest.java
  80. +112 −0 javasdk-test/codegen-test/src/test/java/com/force/sdk/codegen/GeneratedClassScrutinyFTest.java
  81. +126 −0 javasdk-test/codegen-test/src/test/java/com/force/sdk/codegen/JPAClassGeneratorFTest.java
  82. +65 −0 javasdk-test/codegen-test/src/test/java/com/force/sdk/codegen/entities/AccountCustomFields.java
  83. +59 −0 javasdk-test/codegen-test/src/test/java/com/force/sdk/codegen/entities/AccountEntity.java
  84. +51 −0 javasdk-test/codegen-test/src/test/java/com/force/sdk/codegen/entities/NewCustomObject.java
Sorry, we could not display the entire diff because too many files (583) changed.
13 .gitignore
@@ -0,0 +1,13 @@
+.classpath
+.settings
+.project
+target
+test-output/
+*.ipr
+*.iml
+*.iws
+*.scala_dependencies
+deploy
+deploy.zip
+*.log
+
15 build-tools/pom.xml
@@ -0,0 +1,15 @@
+<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+ xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
+
+ <parent>
+ <groupId>com.force.sdk</groupId>
+ <artifactId>force-sdk</artifactId>
+ <version>22.0.0-BETA</version>
+ </parent>
+
+ <modelVersion>4.0.0</modelVersion>
+ <groupId>com.force.sdk</groupId>
+ <artifactId>force-build-tools</artifactId>
+ <name>force-build-tools</name>
+
+</project>
224 build-tools/src/main/resources/checkstyle/force-sdk-checks.xml
@@ -0,0 +1,224 @@
+<?xml version="1.0"?>
+<!--
+
+ Copyright (c) 2011, salesforce.com, inc.
+ All rights reserved.
+
+ Redistribution and use in source and binary forms, with or without modification, are permitted provided
+ that the following conditions are met:
+
+ Redistributions of source code must retain the above copyright notice, this list of conditions and the
+ following disclaimer.
+
+ Redistributions in binary form must reproduce the above copyright notice, this list of conditions and
+ the following disclaimer in the documentation and/or other materials provided with the distribution.
+
+ Neither the name of salesforce.com, inc. nor the names of its contributors may be used to endorse or
+ promote products derived from this software without specific prior written permission.
+
+ THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED
+ WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
+ PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
+ ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED
+ TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ POSSIBILITY OF SUCH DAMAGE.
+
+-->
+
+<!DOCTYPE module PUBLIC
+ "-//Puppy Crawl//DTD Check Configuration 1.3//EN"
+ "http://www.puppycrawl.com/dtds/configuration_1_3.dtd">
+
+<!--
+
+ Checkstyle configuration that checks coding conventions for the Force.com SDK.
+
+ These conventions are mostly based on the sun coding conventions from:
+
+ - the Java Language Specification at
+ http://java.sun.com/docs/books/jls/second_edition/html/index.html
+
+ - the Sun Code Conventions at http://java.sun.com/docs/codeconv/
+
+ - the Javadoc guidelines at
+ http://java.sun.com/j2se/javadoc/writingdoccomments/index.html
+
+ - the JDK Api documentation http://java.sun.com/j2se/docs/api/index.html
+
+ - some best practices
+
+-->
+
+<module name="Checker">
+
+ <!-- Set the default severity level to WARNING -->
+ <property name="severity" value="warning"/>
+
+ <!-- Load the suppressions in force-sdk-suppressions.xml -->
+ <module name="SuppressionFilter">
+ <property name="file" value="${checkstyle.suppressions.file}"/>
+ </module>
+
+ <!-- Checks that each Java package has a Javadoc file used for commenting. -->
+ <!-- See http://checkstyle.sf.net/config_javadoc.html#JavadocPackage
+ TODO: Should we require Javadoc on Packages?
+ <module name="JavadocPackage">
+ <property name="allowLegacy" value="true"/>
+ </module>
+ -->
+
+ <!-- Checks whether files end with a new line. -->
+ <!-- See http://checkstyle.sf.net/config_misc.html#NewlineAtEndOfFile -->
+ <module name="NewlineAtEndOfFile"/>
+
+ <!-- Checks that property files contain the same keys. -->
+ <!-- See http://checkstyle.sf.net/config_misc.html#Translation -->
+ <module name="Translation"/>
+
+ <module name="FileLength"/>
+
+ <!-- Following interprets the header file as regular expressions. -->
+ <!-- <module name="RegexpHeader"/> -->
+
+ <module name="FileTabCharacter">
+ <property name="eachLine" value="true"/>
+ </module>
+
+ <module name="TreeWalker">
+
+ <module name="RegexpSinglelineJava">
+ <!-- Check against trailing whitespace in Java code -->
+ <property name="format" value="[\S]+\s+$"/>
+ <property name="message" value="Line has trailing spaces."/>
+ <property name="ignoreComments" value="true"/>
+ </module>
+
+ <!-- Checks for Javadoc comments. -->
+ <!-- See http://checkstyle.sf.net/config_javadoc.html -->
+ <module name="JavadocMethod">
+ <property name="severity" value="error"/>
+ <property name="scope" value="public"/>
+ <!-- Allows Javadoc on undeclared RuntimeExceptions -->
+ <property name="allowUndeclaredRTE" value="true"/>
+ <property name="allowMissingPropertyJavadoc" value="true"/>
+ </module>
+ <module name="JavadocType">
+ <property name="id" value="typeJavadocExists"/>
+ <property name="severity" value="error"/>
+ <property name="scope" value="public"/>
+ </module>
+ <module name="JavadocType">
+ <property name="id" value="fullNameAuthor"/>
+ <!-- severity=warning -->
+ <property name="authorFormat" value="[A-Z][\S]+\s[A-Z][\S]+"/>
+ <message key="type.tagFormat" value="@author must be a full name (checked pattern ''{1}'')"/>
+ </module>
+ <module name="JavadocVariable">
+ <property name="severity" value="error"/>
+ <property name="scope" value="public"/>
+ </module>
+ <module name="JavadocStyle"/>
+
+ <!-- Checks for Naming Conventions. -->
+ <!-- See http://checkstyle.sf.net/config_naming.html -->
+ <module name="ConstantName"/>
+ <module name="LocalFinalVariableName"/>
+ <module name="LocalVariableName"/>
+ <module name="MemberName"/>
+ <module name="MethodName"/>
+ <module name="PackageName"/>
+ <module name="ParameterName"/>
+ <module name="StaticVariableName"/>
+ <module name="TypeName"/>
+
+ <!-- Checks for imports -->
+ <!-- See http://checkstyle.sf.net/config_import.html -->
+ <module name="IllegalImport"/> <!-- defaults to sun.* packages -->
+ <module name="RedundantImport"/>
+ <module name="UnusedImports"/>
+
+ <!-- Checks for Size Violations. -->
+ <!-- See http://checkstyle.sf.net/config_sizes.html -->
+ <module name="LineLength">
+ <property name="max" value="130"/>
+ </module>
+ <module name="MethodLength">
+ <property name="max" value="200"/>
+ </module>
+ <module name="ParameterNumber">
+ <property name="max" value="13"/>
+ </module>
+
+ <!-- Checks for whitespace -->
+ <!-- See http://checkstyle.sf.net/config_whitespace.html -->
+ <module name="EmptyForIteratorPad"/>
+ <module name="MethodParamPad"/>
+ <module name="NoWhitespaceAfter">
+ <!-- No ARRAY_INIT -->
+ <property name="tokens" value="BNOT, DEC, DOT, INC, LNOT, UNARY_MINUS, UNARY_PLUS"/>
+ </module>
+ <module name="NoWhitespaceBefore">
+ <property name="allowLineBreaks" value="true"/>
+ </module>
+ <module name="OperatorWrap"/>
+ <module name="ParenPad"/>
+ <module name="TypecastParenPad"/>
+ <module name="WhitespaceAfter"/>
+ <module name="WhitespaceAround"/>
+
+ <!-- Modifier Checks -->
+ <!-- See http://checkstyle.sf.net/config_modifiers.html -->
+ <module name="ModifierOrder"/>
+ <module name="RedundantModifier"/>
+
+ <!-- Checks for blocks. You know, those {}'s -->
+ <!-- See http://checkstyle.sf.net/config_blocks.html -->
+ <module name="AvoidNestedBlocks"/>
+ <module name="EmptyBlock">
+ <property name="option" value="text"/>
+ </module>
+ <module name="LeftCurly"/>
+ <module name="NeedBraces">
+ <property name="tokens" value="LITERAL_DO, LITERAL_ELSE, LITERAL_FOR, LITERAL_WHILE"/>
+ </module>
+ <module name="RightCurly"/>
+
+ <!-- Checks for common coding problems -->
+ <!-- See http://checkstyle.sf.net/config_coding.html -->
+ <module name="DoubleCheckedLocking"/>
+ <module name="EmptyStatement"/>
+ <module name="EqualsHashCode"/>
+ <module name="HiddenField">
+ <property name="ignoreConstructorParameter" value="true"/>
+ <property name="ignoreSetter" value="true"/>
+ </module>
+ <module name="IllegalInstantiation"/>
+ <module name="MissingSwitchDefault"/>
+ <module name="RedundantThrows">
+ <property name="allowUnchecked" value="true"/>
+ </module>
+ <module name="SimplifyBooleanExpression"/>
+ <module name="SimplifyBooleanReturn"/>
+
+ <!-- Checks for class design -->
+ <!-- See http://checkstyle.sf.net/config_design.html -->
+ <module name="FinalClass"/>
+ <module name="HideUtilityClassConstructor"/>
+ <module name="VisibilityModifier">
+ <property name="packageAllowed" value="true"/>
+ <property name="protectedAllowed" value="true"/>
+ </module>
+
+ <!-- Miscellaneous other checks. -->
+ <!-- See http://checkstyle.sf.net/config_misc.html -->
+ <module name="ArrayTypeStyle"/>
+ <module name="TodoComment">
+ <property name="severity" value="info"/>
+ </module>
+ <module name="UpperEll"/>
+
+ </module>
+
+</module>
56 build-tools/src/main/resources/checkstyle/force-sdk-suppressions.xml
@@ -0,0 +1,56 @@
+<?xml version="1.0"?>
+<!--
+
+ Copyright (c) 2011, salesforce.com, inc.
+ All rights reserved.
+
+ Redistribution and use in source and binary forms, with or without modification, are permitted provided
+ that the following conditions are met:
+
+ Redistributions of source code must retain the above copyright notice, this list of conditions and the
+ following disclaimer.
+
+ Redistributions in binary form must reproduce the above copyright notice, this list of conditions and
+ the following disclaimer in the documentation and/or other materials provided with the distribution.
+
+ Neither the name of salesforce.com, inc. nor the names of its contributors may be used to endorse or
+ promote products derived from this software without specific prior written permission.
+
+ THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED
+ WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
+ PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
+ ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED
+ TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ POSSIBILITY OF SUCH DAMAGE.
+
+-->
+
+<!DOCTYPE suppressions PUBLIC
+ "-//Puppy Crawl//DTD Suppressions 1.1//EN"
+ "http://www.puppycrawl.com/dtds/suppressions_1_1.dtd">
+
+<!--
+
+ Checkstyle checks to suppress for the Force.com SDK.
+
+ See Checkstyle documentation at:
+ http://checkstyle.sourceforge.net/config.html
+
+-->
+<suppressions>
+ <!-- Do not require method and variable Javadoc in test classes -->
+ <suppress checks="JavadocMethod" files="Test.java"/>
+ <suppress checks="JavadocMethod" files="[/\\]test[/\\]"/>
+ <suppress checks="JavadocVariable" files="Test.java"/>
+ <suppress checks="JavadocVariable" files="[/\\]test[/\\]"/>
+
+ <!-- Allow public class members in test classes -->
+ <suppress checks="VisibilityModifier" files="Test.java"/>
+ <suppress checks="VisibilityModifier" files="[/\\]test[/\\]"/>
+
+ <!-- Hidden fields are OK for the Builder pattern in CodeGenerator -->
+ <suppress checks="HiddenField" files="CodeGenerator.java"
+ lines="140-1000"/>
+</suppressions>
23 build-tools/src/main/resources/license/header.txt
@@ -0,0 +1,23 @@
+Copyright (c) 2011, salesforce.com, inc.
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without modification, are permitted provided
+that the following conditions are met:
+
+ Redistributions of source code must retain the above copyright notice, this list of conditions and the
+ following disclaimer.
+
+ Redistributions in binary form must reproduce the above copyright notice, this list of conditions and
+ the following disclaimer in the documentation and/or other materials provided with the distribution.
+
+ Neither the name of salesforce.com, inc. nor the names of its contributors may be used to endorse or
+ promote products derived from this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED
+WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
+PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
+ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED
+TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+POSSIBILITY OF SUCH DAMAGE.
40 build-tools/src/main/resources/license/stringtemplatedefinition.xml
@@ -0,0 +1,40 @@
+<?xml version="1.0" encoding="ISO-8859-1"?>
+<!--
+
+ Copyright (c) 2011, salesforce.com, inc.
+ All rights reserved.
+
+ Redistribution and use in source and binary forms, with or without modification, are permitted provided
+ that the following conditions are met:
+
+ Redistributions of source code must retain the above copyright notice, this list of conditions and the
+ following disclaimer.
+
+ Redistributions in binary form must reproduce the above copyright notice, this list of conditions and
+ the following disclaimer in the documentation and/or other materials provided with the distribution.
+
+ Neither the name of salesforce.com, inc. nor the names of its contributors may be used to endorse or
+ promote products derived from this software without specific prior written permission.
+
+ THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED
+ WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
+ PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
+ ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED
+ TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ POSSIBILITY OF SUCH DAMAGE.
+
+-->
+
+<additionalHeaders>
+ <stringtemplate_style>
+ <firstLine>$!EOL</firstLine>
+ <beforeEachLine> </beforeEachLine>
+ <endLine>EOL!$</endLine>
+ <firstLineDetectionPattern>\$!$</firstLineDetectionPattern>
+ <lastLineDetectionPattern>!\$$</lastLineDetectionPattern>
+ <allowBlankLines>true</allowBlankLines>
+ <isMultiline>true</isMultiline>
+ </stringtemplate_style>
+</additionalHeaders>
88 codegen/pom.xml
@@ -0,0 +1,88 @@
+<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+ xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
+
+ <parent>
+ <groupId>com.force.sdk</groupId>
+ <artifactId>force-sdk</artifactId>
+ <version>22.0.0-BETA</version>
+ </parent>
+
+ <modelVersion>4.0.0</modelVersion>
+ <groupId>com.force.sdk</groupId>
+ <artifactId>force-codegen</artifactId>
+ <name>force-codegen</name>
+
+ <properties>
+ <stringtemplate.version>3.2</stringtemplate.version>
+ </properties>
+
+ <repositories>
+ <repository>
+ <id>DataNucleus_Repos2</id>
+ <name>DataNucleus Repository</name>
+ <url>http://www.datanucleus.org/downloads/maven2</url>
+ </repository>
+ </repositories>
+
+ <build>
+ <plugins>
+
+ <plugin>
+ <artifactId>maven-assembly-plugin</artifactId>
+ </plugin>
+
+ <plugin>
+ <groupId>org.codehaus.mojo</groupId>
+ <artifactId>findbugs-maven-plugin</artifactId>
+ <configuration>
+ <!-- Use Findbugs exclude filter from test resources -->
+ <excludeFilterFile>${project.build.testOutputDirectory}/findbugs-exclude.xml</excludeFilterFile>
+ </configuration>
+ </plugin>
+
+ </plugins>
+ </build>
+
+
+ <dependencies>
+ <dependency>
+ <groupId>com.force.api</groupId>
+ <artifactId>force-wsc</artifactId>
+ </dependency>
+ <dependency>
+ <groupId>com.force.sdk</groupId>
+ <artifactId>force-connector</artifactId>
+ </dependency>
+ <dependency>
+ <groupId>com.force.sdk</groupId>
+ <artifactId>force-jpa</artifactId>
+ </dependency>
+ <dependency>
+ <groupId>com.google.collections</groupId>
+ <artifactId>google-collections</artifactId>
+ </dependency>
+ <dependency>
+ <groupId>commons-lang</groupId>
+ <artifactId>commons-lang</artifactId>
+ </dependency>
+ <dependency>
+ <groupId>mockit</groupId>
+ <artifactId>jmockit</artifactId>
+ </dependency>
+ <dependency>
+ <groupId>org.apache.geronimo.specs</groupId>
+ <artifactId>geronimo-jpa_2.0_spec</artifactId>
+ </dependency>
+ <dependency>
+ <groupId>org.antlr</groupId>
+ <artifactId>stringtemplate</artifactId>
+ <version>${stringtemplate.version}</version>
+ </dependency>
+ <dependency>
+ <groupId>org.testng</groupId>
+ <artifactId>testng</artifactId>
+ <scope>test</scope>
+ </dependency>
+ </dependencies>
+
+</project>
237 codegen/src/main/java/com/force/sdk/codegen/CodeGenerator.java
@@ -0,0 +1,237 @@
+/**
+ * Copyright (c) 2011, salesforce.com, inc.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without modification, are permitted provided
+ * that the following conditions are met:
+ *
+ * Redistributions of source code must retain the above copyright notice, this list of conditions and the
+ * following disclaimer.
+ *
+ * Redistributions in binary form must reproduce the above copyright notice, this list of conditions and
+ * the following disclaimer in the documentation and/or other materials provided with the distribution.
+ *
+ * Neither the name of salesforce.com, inc. nor the names of its contributors may be used to endorse or
+ * promote products derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
+ * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
+ * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED
+ * TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+
+package com.force.sdk.codegen;
+
+import java.io.IOException;
+import java.io.Writer;
+import java.util.*;
+
+import com.force.sdk.codegen.filter.DataFilter;
+import com.force.sdk.codegen.filter.NoOpDataFilter;
+import com.force.sdk.codegen.selector.DataSelector;
+import com.force.sdk.codegen.selector.DefaultDataSelector;
+import com.force.sdk.codegen.template.Template;
+import com.force.sdk.codegen.writer.WriterProvider;
+import com.sforce.soap.partner.*;
+import com.sforce.ws.ConnectionException;
+
+/**
+ * Basic Code Generator.
+ * <p>
+ * The generator will load up all Force.com schema object (SObject) information
+ * for a given Force.com store (organization). It then filters and selects
+ * the data that is necessary for code generation and writes
+ * this to a {@code Template}.
+ * <p>
+ * Notice that code generation is analogous to MVC (well, at
+ * least the MV parts):
+ * <p>
+ * <ol>
+ * <li>
+ * Model = {@code DataFilter}, {@code DataSelector}. This provides the data that will
+ * be used in the template.
+ * </li>
+ * <li>
+ * View = {@code Template}. This represents the physical layout of
+ * the code being generated.
+ * </li>
+ * <li>
+ * A {@code WriterProvider} provides Jave {@code Writer}s to the {@code CodeGenerator}
+ * to tell it where to write the generated code.
+ * </li>
+ * </ol>
+ *
+ * @author Tim Kral
+ */
+public final class CodeGenerator {
+
+ private static final int MAX_BATCH_DESCRIBE_SIZE = 100;
+
+ final DataFilter filter;
+ final DataSelector selector;
+ final Template template;
+ final WriterProvider writerProvider;
+
+ private CodeGenerator(Builder b) {
+ this.filter = b.filter == null ? new NoOpDataFilter() : b.filter;
+ this.selector = b.selector == null ? new DefaultDataSelector() : b.selector;
+
+ if (b.template == null)
+ throw new IllegalArgumentException("Cannot build a CodeGenerator with a null template");
+ this.template = b.template;
+
+ if (b.writerProvider == null)
+ throw new IllegalArgumentException("Cannot build a CodeGenerator with a null writer provider");
+ this.writerProvider = b.writerProvider;
+ }
+
+ /**
+ * Generates code based on a connection to a Force.com store (organization).
+ * <p>
+ * This will make various Force.com API calls to a Force.com store. First,
+ * it will run a global describe. Next, it will run full describes on the
+ * global describe results. These calls will be batched in the most efficient
+ * way possible (that is, making the least number of Force.com API calls).
+ * <p>
+ * The full describe results will be filtered and injected into a {@code Template}
+ * whose contents will then be written to a Java {@code Writer}.
+ *
+ * @param conn a Force.com API connection to the Force.com store (organization)
+ * that is to be described for code generation
+ * @return the number of Force.com objects for which code is generated
+ * @throws ConnectionException if an error occurs while connecting to the Force.com
+ * store (organization)
+ * @throws IOException if an error occurs while writing the generated code
+ */
+ public int generateCode(PartnerConnection conn) throws ConnectionException, IOException {
+
+ // Get all known SObjects in the org
+ List<String> allOrgObjectNames = new ArrayList<String>();
+ for (DescribeGlobalSObjectResult dgsr : conn.describeGlobal().getSobjects()) {
+ allOrgObjectNames.add(dgsr.getName());
+ }
+
+ // Describe all known SObjects in the org. Batch by the appropriate size.
+ // TODO: Is this ok to read entirely into memory?
+ List<DescribeSObjectResult> allOrgObjects = new ArrayList<DescribeSObjectResult>();
+ for (int i = 0; i < allOrgObjectNames.size(); i += MAX_BATCH_DESCRIBE_SIZE) {
+ // Ensure that our range only goes to the end of the allOrgObjectNames array
+ int endIndex = i + MAX_BATCH_DESCRIBE_SIZE;
+ if (endIndex > allOrgObjectNames.size()) endIndex = allOrgObjectNames.size();
+
+ List<String> objectNameBatch = allOrgObjectNames.subList(i, endIndex);
+ DescribeSObjectResult[] dsrs =
+ conn.describeSObjects(objectNameBatch.toArray(new String[objectNameBatch.size()]));
+
+ allOrgObjects.addAll(Arrays.<DescribeSObjectResult>asList(dsrs));
+ }
+
+ // Get the user information
+ GetUserInfoResult userInfo = conn.getUserInfo();
+
+ // Write filtered data to the template
+ int numGeneratedCode = 0;
+ for (DescribeSObjectResult dsr : filter.filter(allOrgObjects)) {
+ // Before we write a new source file, make sure the template is reset
+ template.reset();
+
+ // Select the data that we're interested in
+ selector.select(userInfo, dsr, template);
+
+ Writer writer = null;
+ try {
+ writer = writerProvider.getWriter(userInfo, dsr);
+ template.write(writer);
+ numGeneratedCode++;
+ } finally {
+ if (writer != null) writer.close();
+ }
+ }
+
+ return numGeneratedCode;
+ }
+
+ /**
+ * Builder pattern for {@code CodeGenerator}.
+ */
+ public static class Builder {
+ DataFilter filter;
+ DataSelector selector;
+ Template template;
+ WriterProvider writerProvider;
+
+ /**
+ * Injects a {@code DataFilter} into this {@code Builder}.
+ * <p>
+ * When this {@code Builder} builds a {@code CodeGenerator} object,
+ * that object will use the given {@code DataFilter}.
+ *
+ * @param filter the {@code DataFilter} to be used in the built
+ * {@code CodeGenerator} object
+ * @return instance of this {@code Builder}
+ */
+ public Builder filter(DataFilter filter) {
+ this.filter = filter;
+ return this;
+ }
+
+ /**
+ * Injects a {@code DataSelector} into this {@code Builder}.
+ * <p>
+ * When this {@code Builder} builds a {@code CodeGenerator} object,
+ * that object will use the given {@code DataSelector}.
+ *
+ * @param selector the {@code DataSelector} to be used in the built
+ * {@code CodeGenerator} object
+ * @return instance of this {@code Builder}
+ */
+ public Builder selector(DataSelector selector) {
+ this.selector = selector;
+ return this;
+ }
+
+ /**
+ * Injects a {@code Template} into this {@code Builder}.
+ * <p>
+ * When this {@code Builder} builds a {@code CodeGenerator} object,
+ * that object will use the given {@code Template}.
+ *
+ * @param template the {@code Template} to be used in the built
+ * {@code CodeGenerator} object
+ * @return instance of this {@code Builder}
+ */
+ public Builder template(Template template) {
+ this.template = template;
+ return this;
+ }
+
+ /**
+ * Injects a {@code WriterProvider} into this {@code Builder}.
+ * <p>
+ * When this {@code Builder} builds a {@code CodeGenerator} object,
+ * that object will use the given {@code WriterProvider}.
+ *
+ * @param writerProvider the {@code WriterProvider} to be used in the built
+ * {@code CodeGenerator} object
+ * @return instance of this {@code Builder}
+ */
+ public Builder writerProvider(WriterProvider writerProvider) {
+ this.writerProvider = writerProvider;
+ return this;
+ }
+
+ /**
+ * Builds a {@code CodeGenerator} object.
+ *
+ * @return a {@code CodeGenerator} object with the state
+ * contained in this {@code Builder}
+ */
+ public CodeGenerator build() {
+ return new CodeGenerator(this);
+ }
+ }
+}
214 codegen/src/main/java/com/force/sdk/codegen/ForceJPAClassGenerator.java
@@ -0,0 +1,214 @@
+/**
+ * Copyright (c) 2011, salesforce.com, inc.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without modification, are permitted provided
+ * that the following conditions are met:
+ *
+ * Redistributions of source code must retain the above copyright notice, this list of conditions and the
+ * following disclaimer.
+ *
+ * Redistributions in binary form must reproduce the above copyright notice, this list of conditions and
+ * the following disclaimer in the documentation and/or other materials provided with the distribution.
+ *
+ * Neither the name of salesforce.com, inc. nor the names of its contributors may be used to endorse or
+ * promote products derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
+ * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
+ * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED
+ * TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+
+package com.force.sdk.codegen;
+
+import java.io.File;
+import java.io.IOException;
+import java.util.*;
+
+import javax.lang.model.SourceVersion;
+
+import org.antlr.stringtemplate.AttributeRenderer;
+import org.antlr.stringtemplate.StringTemplateGroup;
+
+import com.force.sdk.codegen.filter.*;
+import com.force.sdk.codegen.renderer.ForceJPAClassRenderer;
+import com.force.sdk.codegen.renderer.ForceJPAFieldRenderer;
+import com.force.sdk.codegen.selector.ForceJPAClassDataSelector;
+import com.force.sdk.codegen.template.StringTemplateWrapper;
+import com.force.sdk.codegen.writer.ForceJPAFileWriterProvider;
+import com.force.sdk.connector.ForceConnectorConfig;
+import com.force.sdk.connector.ForceServiceConnector;
+import com.google.common.collect.ImmutableSet;
+import com.sforce.soap.partner.*;
+import com.sforce.ws.ConnectionException;
+
+/**
+ * Generator for Force.com JPA enabled Java classes.
+ * <p>
+ * This will generate a closed set of Force.com JPA enabled Java classes based on a list of
+ * Force.com schema object (SObject) names from a Force.com store (organization). For example,
+ * a caller wishing to generate a Java class for the Account object will get the Account Java
+ * class plus the all Java classes to which the Account class will refer (i.e. the Account
+ * object's references). If the first name in the list of schema object names is a single star
+ * ("*") then the generator will produce Java classes for all known objects in the Force.com
+ * store (organization).
+ * <p>
+ * A {@code ForceJPAClassGenerator} has a predetermined set of Force.com schema objects that
+ * will always be generated in addition to what is requested by the caller.
+ *
+ * @author Tim Kral
+ */
+public class ForceJPAClassGenerator {
+
+ // The set of standard objects that will always be generated (along with their dependencies)
+ /* package */ static final Set<String> STANDARD_OBJECTS = ImmutableSet.<String>of("User");
+
+ // The renderers for Force.com JPA object generation
+ private static final Map<Class<?>, AttributeRenderer> RENDERER_MAP =
+ new HashMap<Class<?>, AttributeRenderer>(2);
+
+ static {
+ RENDERER_MAP.put(DescribeSObjectResult.class, new ForceJPAClassRenderer());
+ RENDERER_MAP.put(Field.class, new ForceJPAFieldRenderer());
+ }
+
+ // Connection to the org that we're doing the generation for
+ private final PartnerConnection conn;
+
+ // The destination of the generated Java classes
+ private final File destDir;
+
+ // Allow a static package name (as opposed to a dynamically
+ // generated package name)
+ private String packageName;
+
+ /**
+ * Initializes a {@code ForceJPAClassGenerator} with a named {@link ForceConnectorConfig}
+ * source and a destination (project) directory.
+ * <p>
+ * The {@code ForceJPAClassGenerator} will obtain a connection to the Force.com service
+ * using the {@code ForceConnectorConfig} source. Generated Java classes will be written
+ * to the destination directory.
+ *
+ * @param connectionName a named {@code ForceConnectorConfig} source
+ * @param destDir the destination (project) directory to which the generated Java classes
+ * will be written
+ * @throws ConnectionException if there is an error connecting to the Force.com service
+ */
+ public ForceJPAClassGenerator(String connectionName, File destDir) throws ConnectionException {
+ ForceServiceConnector connector = new ForceServiceConnector(connectionName);
+ this.conn = connector.getConnection();
+ this.destDir = destDir;
+ }
+
+ /**
+ * Initializes a {@code ForceJPAClassGenerator} with a {@link ForceConnectorConfig}
+ * and a destination (project) directory.
+ * <p>
+ * The {@code ForceJPAClassGenerator} will obtain a connection to the Force.com service
+ * using the {@code ForceConnectorConfig}. Generated Java classes will be written
+ * to the destination directory.
+ *
+ * @param config a {@code ForceConnectorConfig}
+ * @param destDir the destination (project) directory to which the generated Java classes
+ * will be written
+ * @throws ConnectionException if there is an error connecting to the Force.com service
+ */
+ public ForceJPAClassGenerator(ForceConnectorConfig config, File destDir) throws ConnectionException {
+ ForceServiceConnector connector = new ForceServiceConnector(config);
+ this.conn = connector.getConnection();
+ this.destDir = destDir;
+ }
+
+ /**
+ * Initializes a {@code ForceJPAClassGenerator} with a connection to the Force.com
+ * service and a destination (project) directory.
+ * <p>
+ * Generated Java classes will be written to the destination directory.
+ *
+ * @param conn a {@code PartnerConnection} to the Force.com service
+ * @param destDir the destination (project) directory to which the generated Java classes
+ * will be written
+ */
+ public ForceJPAClassGenerator(PartnerConnection conn, File destDir) {
+ this.conn = conn;
+ this.destDir = destDir;
+ }
+
+ /**
+ * Sets the Java package name under which the Java classes
+ * will be generated.
+ *
+ * @param packageName a non {@code null} {@code String} which conforms
+ * to Java package naming standards
+ */
+ public void setPackageName(String packageName) {
+ this.packageName = packageName;
+ }
+
+ /**
+ * Execute the Java class generation.
+ *
+ * @param objectNames the Force.com schema objects that are to be generated as
+ * Java classes (along with their references)
+ * @return the number of Force.com JPA enabled Java classes generated
+ * @throws ConnectionException if an error occurs trying to connection to the Force.com service
+ * @throws IOException if an error occurs trying to write out the generated Java classes
+ */
+ public int generateJPAClasses(List<String> objectNames) throws ConnectionException, IOException {
+ // Generate objects (see ForceObject.st)
+ CodeGenerator codeGenerator = createClassGenerator(objectNames);
+ return codeGenerator.generateCode(conn);
+ }
+
+ private CodeGenerator createClassGenerator(List<String> objectNames) {
+ CodeGenerator.Builder builder = new CodeGenerator.Builder();
+
+ if (objectNames == null) {
+ throw new IllegalArgumentException("Object name list is null");
+ }
+
+ // If the first object name parameter a '*' then we'll
+ // generate source files for all the org's SObjects
+ DataFilter filter;
+ if (objectNames.size() > 0 && "*".equals(objectNames.get(0))) {
+ filter = new NoOpDataFilter();
+ } else {
+ Set<String> objectNameSet = new HashSet<String>(STANDARD_OBJECTS);
+ objectNameSet.addAll(objectNames);
+ filter = new ObjectNameWithRefDataFilter(objectNameSet);
+ }
+
+ ForceJPAClassDataSelector selector = new ForceJPAClassDataSelector();
+
+ StringTemplateWrapper template =
+ new StringTemplateWrapper(new StringTemplateGroup("JPA").getInstanceOf("templates/ForceObject"));
+ template.setAttributeRenderers(RENDERER_MAP);
+
+ ForceJPAFileWriterProvider writerProvider = new ForceJPAFileWriterProvider(destDir);
+
+ if (packageName != null) {
+ if (!isValidPackageName(packageName)) {
+ throw new IllegalArgumentException("Invalid package name: " + packageName);
+ }
+
+ selector.setPackageName(packageName);
+ writerProvider.setPackageName(packageName);
+ }
+
+ builder.filter(filter).selector(selector)
+ .template(template).writerProvider(writerProvider);
+
+ return builder.build();
+ }
+
+ static boolean isValidPackageName(String packageName) {
+ if (!SourceVersion.isName(packageName)) return false;
+ return true;
+ }
+}
199 codegen/src/main/java/com/force/sdk/codegen/ForceJPAClassGeneratorUtils.java
@@ -0,0 +1,199 @@
+/**
+ * Copyright (c) 2011, salesforce.com, inc.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without modification, are permitted provided
+ * that the following conditions are met:
+ *
+ * Redistributions of source code must retain the above copyright notice, this list of conditions and the
+ * following disclaimer.
+ *
+ * Redistributions in binary form must reproduce the above copyright notice, this list of conditions and
+ * the following disclaimer in the documentation and/or other materials provided with the distribution.
+ *
+ * Neither the name of salesforce.com, inc. nor the names of its contributors may be used to endorse or
+ * promote products derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
+ * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
+ * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED
+ * TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+
+package com.force.sdk.codegen;
+
+import java.util.HashSet;
+import java.util.Set;
+
+import javax.lang.model.SourceVersion;
+
+import org.apache.commons.lang.WordUtils;
+
+import com.force.sdk.jpa.table.ForceColumnMetaData;
+import com.google.common.collect.ImmutableSet;
+import com.google.common.collect.Sets;
+import com.sforce.soap.partner.*;
+
+/**
+ * Shared utilities for the Force.com JPA enabled Java class generator.
+ *
+ * @author Tim Kral
+ */
+public final class ForceJPAClassGeneratorUtils {
+
+ /**
+ * Represents a tab (consisting of spaces).
+ */
+ public static final String INDENT = " ";
+
+ /**
+ * Represents a system independent new line character.
+ */
+ public static final String NEWLINE = System.getProperty("line.separator");
+
+ // The number of characters in a custom postfix (e.g. __c)
+ private static final int CUSTOM_POSTFIX_LENGTH = 3;
+
+ /**
+ * The set of fields common to all Force.com objects.
+ */
+ public static final Set<String> ALL_OBJECT_COMMON_FIELDS =
+ ImmutableSet.<String>of("id");
+
+ /**
+ * The set of fields common to *most* Force.com standard objects.
+ */
+ public static final Set<String> STANDARD_OBJECT_COMMON_FIELDS =
+ ImmutableSet.<String>copyOf(Sets.difference(ForceColumnMetaData.STANDARD_FIELDS,
+ Sets.newHashSet("createdbyid", "lastmodifiedbyid", "isdeleted")));
+
+ /**
+ * The set of fields common to all Force.com custom objects.
+ */
+ public static final Set<String> CUSTOM_OBJECT_COMMON_FIELDS =
+ ImmutableSet.<String>copyOf(Sets.difference(ForceColumnMetaData.STANDARD_FIELDS,
+ Sets.newHashSet("createdbyid", "lastmodifiedbyid")));
+
+ private ForceJPAClassGeneratorUtils() { }
+
+ /**
+ * Constructs a Java package name based on a Force.com store name
+ * (Organization name).
+ *
+ * @param userInfo the Force.com user who is running the code generation
+ * @return a non {@code null} {@code String} which conforms
+ * to Java class naming standards
+ */
+ public static String constructPackageName(GetUserInfoResult userInfo) {
+ String orgName = userInfo.getOrganizationName();
+
+ if (orgName != null) {
+ String orgNameDenorm = userInfo.getOrganizationName().replaceAll("(,|\\.|\\s)", "").toLowerCase();
+ return "com." + orgNameDenorm + ".model";
+ }
+
+ return "com.force.model";
+ }
+
+ /**
+ * Determines if a Force.com object has all standard Force.com fields.
+ *
+ * @param dsr a Force.com {@code DescribeSObjectResult} of the object
+ * to be tested
+ * @return {@code true} if and only if the given object contains all
+ * common Force.com fields
+ * @see ForceJPAClassGeneratorUtils#STANDARD_OBJECT_COMMON_FIELDS
+ */
+ public static boolean hasAllCommonFields(DescribeSObjectResult dsr) {
+ // Custom object always have all common fields
+ if (dsr.isCustom()) return true;
+
+ // Gather up all the field names for this standard object
+ Set<String> fieldNameSet = new HashSet<String>();
+ for (Field field : dsr.getFields()) {
+ fieldNameSet.add(field.getName().toLowerCase());
+ }
+
+ return fieldNameSet.containsAll(STANDARD_OBJECT_COMMON_FIELDS);
+ }
+
+ /**
+ * Constructs a valid Java name from a Force.com {@code DescribeSObjectResult} object name.
+ *
+ * @param dsr a Force.com {@code DescribeSObjectResult} object whose name is to
+ * to converted to a Java name
+ * @param firstCharLowerCase indicates if the first character in the constructed Java
+ * name should be lower case
+ * @return a non {@code null} {@code String} which conforms
+ * to Java naming standards
+ */
+ public static String renderJavaName(DescribeSObjectResult dsr, boolean firstCharLowerCase) {
+ return renderJavaName(dsr.getName(), "Entity", firstCharLowerCase);
+ }
+
+ /**
+ * Determines if a Java name should be constructed from the given
+ * Force.com API {@code Field} object's relationship name.
+ *
+ * @param field the Force.com API {@code Field} object to test
+ * @return {@code true} if and only if the given {@code Field}
+ * object is a reference field and has a non {@code null} relationship
+ * name and only references exactly one other Force.com object
+ */
+ public static boolean useRelationshipName(Field field) {
+ return field.getType() == FieldType.reference && field.getRelationshipName() != null
+ // With more than one reference, we'll revert back to the field name (and String type)
+ && field.getReferenceTo().length == 1;
+ }
+
+ /**
+ * Constructs a valid Java name from a Force.com API {@code Field} object name.
+ *
+ * @param field a Force.com API {@code Field} object whose name is to
+ * to converted to a Java name
+ * @param firstCharLowerCase indicates if the first character in the constructed Java
+ * name should be lower case
+ * @return a non {@code null} {@code String} which conforms
+ * to Java naming standards
+ */
+ public static String renderJavaName(Field field, boolean firstCharLowerCase) {
+ if (useRelationshipName(field)) {
+ return renderJavaName(field.getRelationshipName(), "Field", firstCharLowerCase);
+ }
+
+ return renderJavaName(field.getName(), "Field", firstCharLowerCase);
+ }
+
+ // Convert the given name into a suitable Java name
+ private static String renderJavaName(String name, String keywordSuffix, boolean firstCharLowerCase) {
+ // First, strip off any custom suffix
+ if (name.endsWith("__c") || name.endsWith("__r")) {
+ name = name.substring(0, name.length() - CUSTOM_POSTFIX_LENGTH);
+ }
+
+ // Convert to camelCase
+ name = WordUtils.capitalize(name, new char[]{'_'});
+
+ //Remove all underscores ('_')
+ name = name.replace("_", "");
+
+ // If the name we're going to generate is a Java keyword
+ // then we'll tweak it with the suffix argument
+ if (SourceVersion.isKeyword(name.toLowerCase())) {
+ name = name + keywordSuffix;
+ }
+
+ // Enforce the desired case on the first character
+ if (firstCharLowerCase) {
+ name = WordUtils.uncapitalize(name);
+ } else {
+ name = WordUtils.capitalize(name);
+ }
+
+ return name;
+ }
+}
80 codegen/src/main/java/com/force/sdk/codegen/builder/BaseBuilder.java
@@ -0,0 +1,80 @@
+/**
+ * Copyright (c) 2011, salesforce.com, inc.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without modification, are permitted provided
+ * that the following conditions are met:
+ *
+ * Redistributions of source code must retain the above copyright notice, this list of conditions and the
+ * following disclaimer.
+ *
+ * Redistributions in binary form must reproduce the above copyright notice, this list of conditions and
+ * the following disclaimer in the documentation and/or other materials provided with the distribution.
+ *
+ * Neither the name of salesforce.com, inc. nor the names of its contributors may be used to endorse or
+ * promote products derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
+ * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
+ * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED
+ * TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+
+package com.force.sdk.codegen.builder;
+
+import static com.force.sdk.codegen.ForceJPAClassGeneratorUtils.INDENT;
+import static com.force.sdk.codegen.ForceJPAClassGeneratorUtils.NEWLINE;
+
+/**
+ * A base class for code generation builders.
+ * <p>
+ * Builders will build {@code String}s that can be included in
+ * generated source code.
+ *
+ * @param <T> the object type that is to be added to this builder
+ * (roughly, the object type to be converted into a {@code String}
+ * via this builder)
+ * @author Tim Kral
+ */
+public abstract class BaseBuilder<T> {
+
+ protected final StringBuffer builderString = new StringBuffer();
+ private final int numIndents;
+
+ BaseBuilder(int numIndents) {
+ this.numIndents = numIndents;
+ }
+
+ /**
+ * Adds an object to this builder.
+ * <p>
+ * Added objects will be converted into a {@code String} to be
+ * used in generated code according to the internal rules
+ * of the specific builder implementation.
+ *
+ * @param item the object to be added to this builder
+ */
+ public void add(T item) {
+ // Separate out multiple annotations with a newline
+ if (builderString.length() > 0) {
+ builderString.append(NEWLINE);
+ }
+
+ for (int i = 0; i < numIndents; i++) {
+ builderString.append(INDENT);
+ }
+
+ append(item);
+ }
+
+ abstract void append(T item);
+
+ @Override
+ public String toString() {
+ return this.builderString.toString();
+ }
+}
106 codegen/src/main/java/com/force/sdk/codegen/builder/ForcePicklistEnumBuilder.java
@@ -0,0 +1,106 @@
+/**
+ * Copyright (c) 2011, salesforce.com, inc.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without modification, are permitted provided
+ * that the following conditions are met:
+ *
+ * Redistributions of source code must retain the above copyright notice, this list of conditions and the
+ * following disclaimer.
+ *
+ * Redistributions in binary form must reproduce the above copyright notice, this list of conditions and
+ * the following disclaimer in the documentation and/or other materials provided with the distribution.
+ *
+ * Neither the name of salesforce.com, inc. nor the names of its contributors may be used to endorse or
+ * promote products derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
+ * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
+ * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED
+ * TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+
+package com.force.sdk.codegen.builder;
+
+import java.util.HashSet;
+import java.util.Set;
+import java.util.regex.Pattern;
+
+import com.sforce.soap.partner.PicklistEntry;
+
+/**
+ * Builds Java enums from Force.com {@code PicklistEntry}s that can be included
+ * in generated source code.
+ * <p>
+ * Force.com {@code PicklistEntry}s describe available values for a given Force.com
+ * schema field. Such values can be directly translated into Java enum values and
+ * included in generated Java code.
+ * <p>
+ * Built Java enum values will be in the form:
+ * <p>
+ * {@code ENUM_NAME(<active>,<defaultValue>,<label>,<value>),}
+ *
+ * @author Tim Kral
+ */
+public class ForcePicklistEnumBuilder extends BaseBuilder<PicklistEntry> {
+
+ private static final Pattern NUMBER_PATTERN = Pattern.compile("(\\d+).*");
+
+ private final Set<String> enumValueNameSet = new HashSet<String>();
+
+ /**
+ * Initializes a {@code ForcePicklistEnumBuilder} with the number
+ * of intentions that should proceed each Java enum value.
+ *
+ * @param numIndents the number of indentations that should
+ * proceed each Java enum value
+ */
+ public ForcePicklistEnumBuilder(int numIndents) {
+ super(numIndents);
+ }
+
+ @Override
+ void append(PicklistEntry picklistEntry) {
+ String label = picklistEntry.getLabel();
+ String value = picklistEntry.getValue();
+
+ // If the picklist value is only one character
+ // try using the (hopefully) more descriptive label
+ String enumValueName;
+ if (value.length() == 1 && label != null) {
+ enumValueName = label;
+ } else {
+ enumValueName = value;
+ }
+
+ // If the enum value name is only digits
+ // prepend a string to make the name valid
+ if (NUMBER_PATTERN.matcher(enumValueName).matches()) {
+ enumValueName = "VALUE_" + enumValueName;
+ }
+
+ // Replace all non-alphanumeric characters with underscores ('_')
+ enumValueName = enumValueName.replaceAll("\\W", "_").toUpperCase();
+
+ // We have a duplicate name, so comment out the dupliate
+ // (otherwise there's a Java compile error)
+ if (enumValueNameSet.contains(enumValueName)) {
+ builderString.append("//");
+ } else {
+ enumValueNameSet.add(enumValueName);
+ }
+
+ builderString.append(enumValueName);
+ builderString.append('(');
+ builderString.append(Boolean.toString(picklistEntry.getActive())).append(',');
+ builderString.append(Boolean.toString(picklistEntry.getDefaultValue())).append(',');
+ builderString.append(label == null ? "null" : "\"" + label + "\"").append(',');
+ builderString.append("\"" + picklistEntry.getValue() + "\"");
+ builderString.append("),");
+ }
+
+}
104 codegen/src/main/java/com/force/sdk/codegen/builder/JPAAnnotationBuilder.java
@@ -0,0 +1,104 @@
+/**
+ * Copyright (c) 2011, salesforce.com, inc.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without modification, are permitted provided
+ * that the following conditions are met:
+ *
+ * Redistributions of source code must retain the above copyright notice, this list of conditions and the
+ * following disclaimer.
+ *
+ * Redistributions in binary form must reproduce the above copyright notice, this list of conditions and
+ * the following disclaimer in the documentation and/or other materials provided with the distribution.
+ *
+ * Neither the name of salesforce.com, inc. nor the names of its contributors may be used to endorse or
+ * promote products derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
+ * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
+ * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED
+ * TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+
+package com.force.sdk.codegen.builder;
+
+import java.lang.annotation.Annotation;
+import java.util.Map;
+
+/**
+ * Builds JPA annotation {@code String}s that can be included in generated source code.
+ * <p>
+ * {@code JPAAnnotationBuilder} takes in {@code Annotation} classes and converts those
+ * into {@code String}s that can be added to Java source code.
+ * <p>
+ * Built annotations will be in the form:
+ * <p>
+ * {@code @<annotationName>}
+ *
+ * @author Tim Kral
+ */
+public class JPAAnnotationBuilder extends BaseBuilder<Class<? extends Annotation>> {
+
+ /**
+ * Initializes a {@code JPAAnnotationBuilder} with the number
+ * of intentions that should proceed each annotation.
+ *
+ * @param numIndents the number of indentations that should
+ * proceed each annotation
+ */
+ public JPAAnnotationBuilder(int numIndents) {
+ super(numIndents);
+ }
+
+ @Override
+ void append(Class<? extends Annotation> annotation) {
+ builderString.append('@');
+
+ // javax.persistence annotations will have an import (see ForceJPAObject.st)
+ // so these do not need to be fully qualified
+ if (annotation.getPackage().getName().equals("javax.persistence")) {
+ builderString.append(annotation.getSimpleName());
+ } else {
+ builderString.append(annotation.getName());
+ }
+ }
+
+ /**
+ * Adds an annotation with attributes to this {@code JPAAnnotationBuilder}.
+ * <p>
+ * Note that the attributes map has {@code String} values. This method
+ * will exactly copy the attribute map values into the annotation attribute
+ * list. Therefore callers must exactly write the attribute values as they
+ * appear in {@code String} form. For example, to add the attribute name="FooBar"
+ * the caller would do the following:
+ * <p>
+ * {@code map.put("name", "\"FooBar\"")}
+ * <p>
+ * Annotations with attributes will be built in the form:
+ * <p>
+ * {@code @<annotationName>(<attr1>=<attr1Value>,<attr2>=<attr2Value>,...)}
+ *
+ * @param annotation a subclass of {@code Annotation} that represents the annotation
+ * that is to be added to this builder
+ * @param attrs a {@code java.util.Map} of attribute keys and values in {@code String} form
+ */
+ public void add(Class<? extends Annotation> annotation, Map<String, String> attrs) {
+ add(annotation);
+
+ // Add all of the annotation's attributes in key=value pairs
+ if (attrs != null && !attrs.isEmpty()) {
+ builderString.append('(');
+ for (Map.Entry<String, String> attr : attrs.entrySet()) {
+ builderString.append(attr.getKey()).append('=').append(attr.getValue()).append(',');
+ }
+
+ // Get rid of the last comma (',')
+ builderString.deleteCharAt(builderString.lastIndexOf(","));
+ builderString.append(')');
+ }
+ }
+}
56 codegen/src/main/java/com/force/sdk/codegen/builder/JavaCommentBuilder.java
@@ -0,0 +1,56 @@
+/**
+ * Copyright (c) 2011, salesforce.com, inc.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without modification, are permitted provided
+ * that the following conditions are met:
+ *
+ * Redistributions of source code must retain the above copyright notice, this list of conditions and the
+ * following disclaimer.
+ *
+ * Redistributions in binary form must reproduce the above copyright notice, this list of conditions and
+ * the following disclaimer in the documentation and/or other materials provided with the distribution.
+ *
+ * Neither the name of salesforce.com, inc. nor the names of its contributors may be used to endorse or
+ * promote products derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
+ * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
+ * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED
+ * TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+
+package com.force.sdk.codegen.builder;
+
+/**
+ * Builds Java comments that can be included in generated source code.
+ * <p>
+ * Built comments will be in the form:
+ * <p>
+ * {@code // <comment String>}
+ *
+ * @author Tim Kral
+ */
+public class JavaCommentBuilder extends BaseBuilder<String> {
+
+ /**
+ * Initializes a {@code JavaCommentBuilder} with the number
+ * of intentions that should proceed each Java comment.
+ *
+ * @param numIndents the number of indentations that should
+ * proceed each Java comment
+ */
+ public JavaCommentBuilder(int numIndents) {
+ super(numIndents);
+ }
+
+ @Override
+ protected void append(String comment) {
+ builderString.append("// ").append(comment);
+ }
+
+}
48 codegen/src/main/java/com/force/sdk/codegen/filter/DataFilter.java
@@ -0,0 +1,48 @@
+/**
+ * Copyright (c) 2011, salesforce.com, inc.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without modification, are permitted provided
+ * that the following conditions are met:
+ *
+ * Redistributions of source code must retain the above copyright notice, this list of conditions and the
+ * following disclaimer.
+ *
+ * Redistributions in binary form must reproduce the above copyright notice, this list of conditions and
+ * the following disclaimer in the documentation and/or other materials provided with the distribution.
+ *
+ * Neither the name of salesforce.com, inc. nor the names of its contributors may be used to endorse or
+ * promote products derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
+ * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
+ * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED
+ * TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+
+package com.force.sdk.codegen.filter;
+
+import java.util.List;
+
+import com.sforce.soap.partner.DescribeSObjectResult;
+
+/**
+ * A filter which determines which Force.com {@code DescribeSObjectResult} objects
+ * are injected into a code generation {@link Template}.
+ *
+ * @author Tim Kral
+ */
+public interface DataFilter {
+
+ /**
+ * Filters a list of Force.com {@code DescribeSObjectResult} objects.
+ *
+ * @param dsrs the list of Force.com {@code DescribeSObjectResult} objects to be filtered
+ * @return the filtered list of Force.com {@code DescribeSObjectResult} objects
+ */
+ List<DescribeSObjectResult> filter(List<DescribeSObjectResult> dsrs);
+}
49 codegen/src/main/java/com/force/sdk/codegen/filter/NoOpDataFilter.java
@@ -0,0 +1,49 @@
+/**
+ * Copyright (c) 2011, salesforce.com, inc.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without modification, are permitted provided
+ * that the following conditions are met:
+ *
+ * Redistributions of source code must retain the above copyright notice, this list of conditions and the
+ * following disclaimer.
+ *
+ * Redistributions in binary form must reproduce the above copyright notice, this list of conditions and
+ * the following disclaimer in the documentation and/or other materials provided with the distribution.
+ *
+ * Neither the name of salesforce.com, inc. nor the names of its contributors may be used to endorse or
+ * promote products derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
+ * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
+ * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED
+ * TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+
+package com.force.sdk.codegen.filter;
+
+import java.util.List;
+
+import com.sforce.soap.partner.DescribeSObjectResult;
+
+/**
+ * A pass-through code generation {@link DataFilter}.
+ * <p>
+ * This {@code DataFilter} performs no filtering processing and
+ * simply returns any list of Force.com {@code DescribeSObjectResult} objects
+ * that it receives.
+ *
+ * @author Tim Kral
+ */
+public class NoOpDataFilter implements DataFilter {
+
+ @Override
+ public List<DescribeSObjectResult> filter(List<DescribeSObjectResult> dsrs) {
+ return dsrs;
+ }
+
+}
98 codegen/src/main/java/com/force/sdk/codegen/filter/ObjectNameDataFilter.java
@@ -0,0 +1,98 @@
+/**
+ * Copyright (c) 2011, salesforce.com, inc.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without modification, are permitted provided
+ * that the following conditions are met:
+ *
+ * Redistributions of source code must retain the above copyright notice, this list of conditions and the
+ * following disclaimer.
+ *
+ * Redistributions in binary form must reproduce the above copyright notice, this list of conditions and
+ * the following disclaimer in the documentation and/or other materials provided with the distribution.
+ *
+ * Neither the name of salesforce.com, inc. nor the names of its contributors may be used to endorse or
+ * promote products derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
+ * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
+ * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED
+ * TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+
+package com.force.sdk.codegen.filter;
+
+import java.util.*;
+
+import com.sforce.soap.partner.DescribeSObjectResult;
+
+/**
+ * A {@link DataFilter} which filters based on Force.com schema object (SObject)
+ * names.
+ * <p>
+ * This {@code DataFilter} will filter in a Force.com schema object if and only if
+ * its name exactly matches one in the {@code ObjectNameDataFilter} state. Names
+ * in the {@code ObjectNameDataFilter} state which match no schema objects are
+ * ignored.
+ *
+ * @author Tim Kral
+ */
+public class ObjectNameDataFilter implements DataFilter {
+
+ private final Set<String> objectNames;
+
+ /**
+ * Initializes a {@code ObjectNameDataFilter} with a set of
+ * Force.com schema object names that are to be filtered
+ * in.
+ *
+ * @param objectNames a {@code java.util.Set} of exact object
+ * names that are to be filtered in
+ */
+ public ObjectNameDataFilter(Set<String> objectNames) {
+ this.objectNames = objectNames;
+ }
+
+ /**
+ * Initializes a {@code ObjectNameDataFilter} with a set of
+ * Force.com schema object names that are to be filtered
+ * in.
+ * <p>
+ * Note that duplicates within the given array with be eliminated.
+ *
+ * @param objectNames an {@code Array} of exact object
+ * names that are to be filtered in
+ */
+ public ObjectNameDataFilter(String... objectNames) {
+ this.objectNames = new HashSet<String>();
+ this.objectNames.addAll(Arrays.asList(objectNames));
+ }
+
+ @Override
+ public List<DescribeSObjectResult> filter(List<DescribeSObjectResult> dsrs) {
+ List<DescribeSObjectResult> filteredResult = new ArrayList<DescribeSObjectResult>();
+ for (DescribeSObjectResult dsr : dsrs) {
+ if (objectNames.contains(dsr.getName())) {
+ filteredResult.add(dsr);
+ }
+ }
+
+ return filteredResult;
+ }
+
+ /**
+ * Returns the {@code java.util.Set} of schema object names
+ * on which this {@code ObjectNameDataFilter} will filter.
+ *
+ * @return a non {@code null} {@code java.util.Set} which
+ * contains the schema object names on which this
+ * {@code ObjectNameDataFilter} will filter
+ */
+ public Set<String> getObjectNames() {
+ return objectNames;
+ }
+}
129 codegen/src/main/java/com/force/sdk/codegen/filter/ObjectNameWithRefDataFilter.java
@@ -0,0 +1,129 @@
+/**
+ * Copyright (c) 2011, salesforce.com, inc.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without modification, are permitted provided
+ * that the following conditions are met:
+ *
+ * Redistributions of source code must retain the above copyright notice, this list of conditions and the
+ * following disclaimer.
+ *
+ * Redistributions in binary form must reproduce the above copyright notice, this list of conditions and
+ * the following disclaimer in the documentation and/or other materials provided with the distribution.
+ *
+ * Neither the name of salesforce.com, inc. nor the names of its contributors may be used to endorse or
+ * promote products derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
+ * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
+ * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED
+ * TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+
+package com.force.sdk.codegen.filter;
+
+import java.util.*;
+
+import com.sforce.soap.partner.*;
+
+/**
+ * A {@link DataFilter} which filters based on Force.com schema object (SObject)
+ * names and follows object references to produce a closed set of schema objects.
+ * <p>
+ * This {@code DataFilter} will filter in a Force.com schema object if and only if
+ * at least one of the two following conditions are met:
+ * <p>
+ * <ol>
+ * <li>Its name exactly matches one in the {@code ObjectNameWithRefDataFilter} state</li>
+ * <li>It is referenced by a schema object that has already been filtered in</li>
+ * </ol>
+ * Names in the {@code ObjectNameWithRefDataFilter} state which match no schema objects are
+ * ignored.
+ *
+ * @author Tim Kral
+ */
+public class ObjectNameWithRefDataFilter implements DataFilter {
+
+ // The object names that we want to filter for
+ private final Set<String> objectNames;
+
+ // Map from object name to object for all known objects
+ private final Map<String, DescribeSObjectResult> objectMap =
+ new HashMap<String, DescribeSObjectResult>();
+
+ // Since we're using recursion to filter in object references
+ // we'll need to know what we've filtered in already
+ private Set<String> filteredResultNames = new HashSet<String>();
+ private List<DescribeSObjectResult> filteredResult = new ArrayList<DescribeSObjectResult>();
+
+ /**
+ * Initializes a {@code ObjectNameWithRefDataFilter} with a set of
+ * Force.com schema object names that are to be filtered
+ * in along with their references.
+ *
+ * @param objectNames a {@code java.util.Set} of exact object
+ * names that are to be filtered in along with
+ * their references
+ */
+ public ObjectNameWithRefDataFilter(Set<String> objectNames) {
+ this.objectNames = objectNames;
+ }
+
+ /**
+ * Initializes a {@code ObjectNameWithRefDataFilter} with a set of
+ * Force.com schema object names that are to be filtered
+ * in along with their references.
+ * <p>
+ * Note that duplicates within the given array with be eliminated.
+ *
+ * @param objectNames an {@code Array} of exact object
+ * names that are to be filtered in along with
+ * their references
+ */
+ public ObjectNameWithRefDataFilter(String... objectNames) {
+ this.objectNames = new HashSet<String>();
+ this.objectNames.addAll(Arrays.asList(objectNames));
+ }
+
+ @Override
+ public List<DescribeSObjectResult> filter(List<DescribeSObjectResult> dsrs) {
+ for (DescribeSObjectResult dsr : dsrs) {
+ objectMap.put(dsr.getName(), dsr);
+ }
+
+ filterObjectAndReferences(objectNames);
+ return filteredResult;
+ }
+
+ private void filterObjectAndReferences(Set<String> objectNameSet) {
+
+ // Subtract any objects that we've already fetched
+ objectNameSet.removeAll(filteredResultNames);
+ if (objectNameSet.isEmpty()) return;
+
+ Set<String> objectReferencesSet = new HashSet<String>();
+
+ for (String objectName : objectNameSet) {
+ DescribeSObjectResult dsr;
+ if ((dsr = objectMap.get(objectName)) != null) {
+
+ // Gather all the references for this object
+ for (Field field : dsr.getFields()) {
+ if (field.getType() == FieldType.reference) {
+ objectReferencesSet.addAll(Arrays.asList(field.getReferenceTo()));
+ }
+ }
+
+ filteredResultNames.add(dsr.getName());
+ filteredResult.add(dsr);
+ }
+ }
+
+ // Here, we'll recursively fetch all the object references we found.
+ filterObjectAndReferences(objectReferencesSet);
+ }
+}
102 codegen/src/main/java/com/force/sdk/codegen/renderer/ForceJPAClassRenderer.java
@@ -0,0 +1,102 @@
+/**
+ * Copyright (c) 2011, salesforce.com, inc.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without modification, are permitted provided
+ * that the following conditions are met:
+ *
+ * Redistributions of source code must retain the above copyright notice, this list of conditions and the
+ * following disclaimer.
+ *
+ * Redistributions in binary form must reproduce the above copyright notice, this list of conditions and
+ * the following disclaimer in the documentation and/or other materials provided with the distribution.
+ *
+ * Neither the name of salesforce.com, inc. nor the names of its contributors may be used to endorse or
+ * promote products derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
+ * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
+ * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED
+ * TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+
+package com.force.sdk.codegen.renderer;
+
+import java.util.Collections;
+
+import javax.annotation.Generated;
+import javax.persistence.Entity;
+import javax.persistence.Table;
+
+import org.antlr.stringtemplate.AttributeRenderer;
+
+import com.force.sdk.codegen.ForceJPAClassGenerator;
+import com.force.sdk.codegen.ForceJPAClassGeneratorUtils;
+import com.force.sdk.codegen.builder.JPAAnnotationBuilder;
+import com.force.sdk.jpa.annotation.CustomObject;
+import com.force.sdk.jpa.model.*;
+import com.sforce.soap.partner.DescribeSObjectResult;
+
+/**
+ * A StringTemplate {@code AttributeRenderer} that renders Java class level {@code String}s.
+ * <p>
+ * This {@code AttributeRenderer} effectively translates between a Force.com {@code DescribeSObjectResult}
+ * object and Java class level code. Within StringTemplate, it is meant to be registered
+ * as an {@code AttributeRenderer} for a Force.com {@code DescribeSObjectResult} object.
+ *
+ * @author Tim Kral
+ */
+public class ForceJPAClassRenderer implements AttributeRenderer {
+
+ @Override
+ public String toString(Object o) {
+ return "";
+ }
+
+ @Override
+ public String toString(Object o, String format) {
+ DescribeSObjectResult dsr = (DescribeSObjectResult) o;
+ if ("classAnnotation".equals(format)) {
+ return renderClassAnnotation(dsr);
+ } else if ("className".equals(format)) {
+ return ForceJPAClassGeneratorUtils.renderJavaName(dsr, false /*firstCharLowerCase*/);
+ } else if ("superClassName".equals(format)) {
+ return renderSuperClassName(dsr);
+ }
+
+ return toString(o);
+ }
+
+ // Render annotations that are to be add to a JPA object
+ // at the class level
+ private String renderClassAnnotation(DescribeSObjectResult dsr) {
+ JPAAnnotationBuilder builder = new JPAAnnotationBuilder(0 /*numIndents*/);
+ builder.add(Generated.class,
+ Collections.<String, String>singletonMap("value", "\"" + ForceJPAClassGenerator.class.getName() + "\""));
+ builder.add(Table.class,
+ Collections.<String, String>singletonMap("name", "\"" + dsr.getName() + "\""));
+ builder.add(Entity.class,
+ Collections.<String, String>singletonMap("name", "\"" + toString(dsr, "className") + "\""));
+
+ // We're generating the class off of already existing schema
+ // so there won't be a need to create it.
+ builder.add(CustomObject.class,
+ Collections.<String, String>singletonMap("readOnlySchema", "true"));
+
+ return builder.toString();
+ }
+
+ private String renderSuperClassName(DescribeSObjectResult dsr) {
+ if (dsr.isCustom()) return BaseForceCustomObject.class.getName();
+
+ // If the standard object doesn't contain *all* the common
+ // standard object fields just extend the generic base class (e.g. User, UserLicense)
+ if (!ForceJPAClassGeneratorUtils.hasAllCommonFields(dsr)) return BaseForceObject.class.getName();
+ return BaseForceStandardObject.class.getName();
+ }
+
+}
259 codegen/src/main/java/com/force/sdk/codegen/renderer/ForceJPAFieldRenderer.java
@@ -0,0 +1,259 @@
+/**
+ * Copyright (c) 2011, salesforce.com, inc.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without modification, are permitted provided
+ * that the following conditions are met:
+ *
+ * Redistributions of source code must retain the above copyright notice, this list of conditions and the
+ * following disclaimer.
+ *
+ * Redistributions in binary form must reproduce the above copyright notice, this list of conditions and
+ * the following disclaimer in the documentation and/or other materials provided with the distribution.
+ *
+ * Neither the name of salesforce.com, inc. nor the names of its contributors may be used to endorse or
+ * promote products derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
+ * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
+ * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED
+ * TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+
+package com.force.sdk.codegen.renderer;
+
+import static com.force.sdk.codegen.ForceJPAClassGeneratorUtils.renderJavaName;
+
+import java.math.BigDecimal;
+import java.net.URL;
+import java.util.*;
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
+
+import javax.annotation.Generated;
+import javax.persistence.*;
+
+import org.antlr.stringtemplate.AttributeRenderer;
+
+import com.force.sdk.codegen.ForceJPAClassGenerator;
+import com.force.sdk.codegen.builder.*;
+import com.sforce.soap.partner.*;
+
+/**
+ * A StringTemplate {@code AttributeRenderer} that renders Java field level {@code String}s.
+ * <p>
+ * This {@code AttributeRenderer} effectively translates between a Force.com API {@code Field}
+ * object and Java field level code. Within StringTemplate, it is meant to be registered
+ * as an {@code AttributeRenderer} for a Force.com API {@code Field} object.
+ *
+ * @author Tim Kral
+ */
+public class ForceJPAFieldRenderer implements AttributeRenderer {
+
+ private static final Pattern ANNOTATION_PATTERN = Pattern.compile("^(enum|getter|setter)Annotation(\\d+)$");
+ private static final Pattern ENUM_VALUES_PATTERN = Pattern.compile("^enumValues(\\d+)$");
+ private static final Pattern FIELD_COMMENTS_PATTERN = Pattern.compile("^fieldComments(\\d+)$");
+
+ @Override
+ public String toString(Object o) {
+ return "";
+ }
+
+ @Override
+ public String toString(Object o, String format) {
+ Field field = (Field) o;
+ Matcher matcher;
+
+ if ("fieldName".equals(format)) {
+ return renderJavaName(field, true /*firstCharLowerCase*/);
+ } else if ("fieldType".equals(format)) {
+ return renderFieldType(field);
+ } else if ((matcher = FIELD_COMMENTS_PATTERN.matcher(format)).matches()) {
+ // The number at the end of an fieldComments format tells
+ // us the number of indents to add to the fieldComments
+ String numIndentsStr = matcher.group(1);
+ JavaCommentBuilder builder = new JavaCommentBuilder(Integer.valueOf(numIndentsStr));
+
+ return renderFieldComments(field, builder);
+ } else if (format != null && format.contains("fieldComments")) {
+ throw new IllegalArgumentException("Unrecognized format: " + format + ". "
+ + "fieldComments formats must end in the number of indents required (e.g. fieldComments1");
+ } else if ((matcher = ANNOTATION_PATTERN.matcher(format)).matches()) {
+ String annotationType = matcher.group(1);
+
+ // The number at the end of an annotation format tells
+ // us the number of indents to add to the annotations
+ String numIndentsStr = matcher.group(2);
+ JPAAnnotationBuilder builder = new JPAAnnotationBuilder(Integer.valueOf(numIndentsStr));
+
+ if ("enum".equals(annotationType)) {
+ return renderEnumAnnotation(field, builder);
+ } else if ("getter".equals(annotationType)) {
+ return renderGetterAnnotation(field, builder);
+ } else if ("setter".equals(annotationType)) {
+ return renderSetterAnnotation(field, builder);
+ }
+ } else if (format != null && format.contains("Annotation")) {
+ throw new IllegalArgumentException("Unrecognized annotation format: " + format + ". "
+ + "Annotation formats must be one of (enum, getter, setter) "
+ + "and must end in the number of indents required (e.g. getterAnnotation1");
+ } else if ("methodName".equals(format)) {
+ return renderJavaName(field, false /*firstCharLowerCase*/);
+ } else if ("enumName".equals(format)) {
+ return renderEnumName(field);
+ } else if ((matcher = ENUM_VALUES_PATTERN.matcher(format)).matches()) {
+ // The number at the end of an enumValues format tells
+ // us the number of indents to add to the enumValues
+ String numIndentsStr = matcher.group(1);
+ ForcePicklistEnumBuilder builder = new ForcePicklistEnumBuilder(Integer.valueOf(numIndentsStr));
+
+ return renderEnumValues(field, builder);
+ } else if (format != null && format.contains("enumValues")) {
+ throw new IllegalArgumentException("Unrecognized format: " + format + ". "
+ + "enumValues formats must end in the number of indents required (e.g. enumValues1");
+ }
+
+ return toString(o);
+ }
+
+ // Render the Java field type for a given API field
+ private String renderFieldType(Field field) {
+ FieldType type = field.getType();
+ if (type == FieldType._boolean
+ || type == FieldType.combobox) {
+ return boolean.class.getName();
+ } else if (type == FieldType._double
+ || type == FieldType.percent) {
+ return double.class.getName();
+ } else if (type == FieldType._int) {
+ return int.class.getName();
+ } else if (type == FieldType.currency) {
+ return BigDecimal.class.getName();
+ } else if (type == FieldType.date
+ || type == FieldType.time) {
+ return Date.class.getName();
+ } else if (type == FieldType.datetime) {
+ return Calendar.class.getName();
+ } else if (type == FieldType.url) {
+ return URL.class.getName();
+ } else if (type == FieldType.picklist) {
+ // Force the field type to be an enum for restricted picklists
+ // with API enabled picklist values
+ if (field.isRestrictedPicklist() && field.getPicklistValues().length > 0) return renderEnumName(field);
+
+ return String.class.getSimpleName();
+ } else if (type == FieldType.multipicklist) {
+ // Force the field type to be an enum array for restricted multipicklists
+ // with API enabled picklist values
+ if (field.isRestrictedPicklist() && field.getPicklistValues().length > 0) return renderEnumName(field) + "[]";
+
+ return String[].class.getSimpleName();
+ } else if (type == FieldType.reference) {
+ String[] referenceTo;
+ // Return the class name of the relationship if there's only one relationship object
+ // Otherwise, we'll just use a String
+ if ((referenceTo = field.getReferenceTo()).length == 1) {
+ DescribeSObjectResult dsr = new DescribeSObjectResult();
+ dsr.setName(referenceTo[0]);
+
+ return renderJavaName(dsr, false /*firstCharLowerCase*/);
+ }
+ }
+
+ return String.class.getSimpleName();
+ }
+
+ private String renderFieldComments(Field field, JavaCommentBuilder builder) {
+ if (field.getType() == FieldType.reference
+ && field.getReferenceTo().length > 1) {
+
+ builder.add(renderJavaName(field, true) + " possible references:");
+ for (String refTo : field.getReferenceTo()) {
+ builder.add(refTo);
+ }
+ }
+
+ return builder.toString();
+ }
+
+ private String renderEnumAnnotation(Field field, JPAAnnotationBuilder builder) {
+ builder.add(Generated.class,
+ Collections.<String, String>singletonMap("value", "\"" + ForceJPAClassGenerator.class.getName() + "\""));
+
+ return builder.toString();
+ }
+
+ // Render annotations that are to be add to a JPA object
+ // at the method level
+ private String renderGetterAnnotation(Field field, JPAAnnotationBuilder builder) {
+
+ String name = field.getName();
+ FieldType type = field.getType();
+ if (type == FieldType.id) {
+ builder.add(Id.class);
+ builder.add(GeneratedValue.class,
+ Collections.<String, String>singletonMap("strategy", "GenerationType.IDENTITY"));
+ } else if (type == FieldType.reference) {
+ builder.add(ManyToOne.class);
+
+ // Require reference fields to be lazily loaded.
+ // Developers may override this in subclasses.
+ builder.add(Basic.class,
+ Collections.<String, String>singletonMap("fetch", "FetchType.LAZY"));
+
+ // The LastModifiedDate field is used for versioning
+ // so add a @Version annotation
+ } else if (type == FieldType.datetime && name != null && "lastmodifieddate".equals(name.toLowerCase())) {
+ builder.add(Version.class);
+ } else if (type == FieldType.url) {
+ builder.add(Basic.class);
+
+ // Restricted picklists must conform to an Enum value
+ } else if (field.isRestrictedPicklist()) {
+ builder.add(Enumerated.class,
+ Collections.<String, String>singletonMap("value", "EnumType.STRING"));
+ }
+
+ // Add an @Column annotation to all custom fields
+ // so we know the proper Force.com name of the field
+ // Also, relationship fields will be named by their
+ // relationship name.
+ if (field.isCustom()
+ || (type == FieldType.reference && field.getRelationshipName() != null)) {
+ builder.add(Column.class,
+ Collections.<String, String>singletonMap("name", "\"" + name + "\""));
+ }
+
+ return builder.toString();
+ }
+
+ private String renderSetterAnnotation(Field field, JPAAnnotationBuilder builder) {
+
+ // Mark non nullable, non defaulted fields as required
+ if (!field.isNillable() && !field.isDefaultedOnCreate()) {
+ builder.add(Basic.class,
+ Collections.<String, String>singletonMap("optional", "false"));
+ }
+
+ return builder.toString();
+ }
+
+ private String renderEnumName(Field field) {
+ StringBuffer enumName = new StringBuffer(renderJavaName(field, false));
+ enumName.append("Enum");
+
+ return enumName.toString();
+ }
+
+ private String renderEnumValues(Field field, ForcePicklistEnumBuilder builder) {
+ for (PicklistEntry picklistEntry : field.getPicklistValues()) {
+ builder.add(picklistEntry);
+ }
+
+ return builder.toString();
+ }
+}
52 codegen/src/main/java/com/force/sdk/codegen/selector/DataSelector.java
@@ -0,0 +1,52 @@
+/**
+ * Copyright (c) 2011, salesforce.com, inc.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without modification, are permitted provided
+ * that the following conditions are met:
+ *
+ * Redistributions of source code must retain the above copyright notice, this list of conditions and the