This is an automated email from the ASF dual-hosted git repository.

zregvart pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/camel.git


The following commit(s) were added to refs/heads/master by this push:
     new e2068e1  CAMEL-12043: Refactor Salesforce Maven plugin
e2068e1 is described below

commit e2068e166a040567dce4400fd601ad86f955c7dc
Author: Zoran Regvart <[email protected]>
AuthorDate: Sun Dec 10 16:37:55 2017 +0100

    CAMEL-12043: Refactor Salesforce Maven plugin
    
    Splits Java and JSON schema code generation into two Maven goals, the
    current `generate` remains as is, there is a new goal `schema` for JSON
    schema generation. Also splits fetching Salesforce object descriptions
    into separate class, introduces a base class for Salesforce mojos and
    cleans up tests.
---
 .../camel-salesforce-maven-plugin/pom.xml          |  32 +-
 .../apache/camel/maven/AbstractSalesforceMojo.java | 317 +++++++
 .../apache/camel/maven/CamelSalesforceMojo.java    | 954 ---------------------
 .../main/java/org/apache/camel/maven/Defaults.java |  35 +
 .../java/org/apache/camel/maven/GenerateMojo.java  | 497 +++++++++++
 .../org/apache/camel/maven/ObjectDescriptions.java | 202 +++++
 .../java/org/apache/camel/maven/SchemaMojo.java    | 118 +++
 .../AbstractSalesforceMojoIntegrationTest.java     |  80 ++
 .../maven/CamelSalesforceMojoIntegrationTest.java  | 119 +--
 .../camel/maven/CamelSalesforceMojoOutputTest.java |  66 +-
 .../camel/maven/HttpProxyMojoIntegrationTest.java  | 119 +--
 .../camel/maven/SchemaMojoIntegrationTest.java     |  60 ++
 12 files changed, 1447 insertions(+), 1152 deletions(-)

diff --git a/components/camel-salesforce/camel-salesforce-maven-plugin/pom.xml 
b/components/camel-salesforce/camel-salesforce-maven-plugin/pom.xml
index ccb8091..5715861 100644
--- a/components/camel-salesforce/camel-salesforce-maven-plugin/pom.xml
+++ b/components/camel-salesforce/camel-salesforce-maven-plugin/pom.xml
@@ -18,7 +18,7 @@
 
 -->
 <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";>
+  xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 
http://maven.apache.org/maven-v4_0_0.xsd";>
 
   <modelVersion>4.0.0</modelVersion>
 
@@ -89,6 +89,12 @@
     <dependency>
       <groupId>org.codehaus.plexus</groupId>
       <artifactId>plexus-container-default</artifactId>
+      <exclusions>
+        <exclusion>
+          <groupId>com.google.collections</groupId>
+          <artifactId>google-collections</artifactId>
+        </exclusion>
+      </exclusions>
     </dependency>
     <dependency>
       <groupId>org.codehaus.plexus</groupId>
@@ -131,7 +137,7 @@
       <groupId>org.slf4j</groupId>
       <artifactId>slf4j-api</artifactId>
     </dependency>
-      
+
     <dependency>
       <groupId>org.apache.logging.log4j</groupId>
       <artifactId>log4j-api</artifactId>
@@ -189,6 +195,24 @@
       <artifactId>camel-test</artifactId>
       <scope>test</scope>
     </dependency>
+    <dependency>
+      <groupId>org.assertj</groupId>
+      <artifactId>assertj-core</artifactId>
+      <version>${assertj-version}</version>
+      <scope>test</scope>
+    </dependency>
+    <dependency>
+      <groupId>com.google.testing.compile</groupId>
+      <artifactId>compile-testing</artifactId>
+      <version>0.13</version>
+      <scope>test</scope>
+    </dependency>
+    <dependency>
+      <groupId>org.littleshoot</groupId>
+      <artifactId>littleproxy</artifactId>
+      <version>1.1.2</version>
+      <scope>test</scope>
+    </dependency>
   </dependencies>
 
   <build>
@@ -198,7 +222,7 @@
         <artifactId>maven-jar-plugin</artifactId>
         <configuration>
           <archive combine.self="override">
-            <manifestFile/>
+            <manifestFile />
             <manifest>
               
<addDefaultSpecificationEntries>true</addDefaultSpecificationEntries>
               
<addDefaultImplementationEntries>true</addDefaultImplementationEntries>
@@ -248,7 +272,7 @@
         <artifactId>maven-plugin-plugin</artifactId>
         <version>3.5</version>
         <configuration>
-          <goalPrefix>camel-salesforce</goalPrefix>         
+          <goalPrefix>camel-salesforce</goalPrefix>
         </configuration>
         <executions>
           <execution>
diff --git 
a/components/camel-salesforce/camel-salesforce-maven-plugin/src/main/java/org/apache/camel/maven/AbstractSalesforceMojo.java
 
b/components/camel-salesforce/camel-salesforce-maven-plugin/src/main/java/org/apache/camel/maven/AbstractSalesforceMojo.java
new file mode 100644
index 0000000..5289bcf
--- /dev/null
+++ 
b/components/camel-salesforce/camel-salesforce-maven-plugin/src/main/java/org/apache/camel/maven/AbstractSalesforceMojo.java
@@ -0,0 +1,317 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.camel.maven;
+
+import java.io.IOException;
+import java.net.URI;
+import java.security.GeneralSecurityException;
+import java.util.HashMap;
+import java.util.Map;
+import java.util.Set;
+
+import org.apache.camel.component.salesforce.SalesforceEndpointConfig;
+import org.apache.camel.component.salesforce.SalesforceHttpClient;
+import org.apache.camel.component.salesforce.SalesforceLoginConfig;
+import org.apache.camel.component.salesforce.api.SalesforceException;
+import org.apache.camel.component.salesforce.internal.PayloadFormat;
+import org.apache.camel.component.salesforce.internal.SalesforceSession;
+import org.apache.camel.component.salesforce.internal.client.DefaultRestClient;
+import org.apache.camel.component.salesforce.internal.client.RestClient;
+import org.apache.camel.impl.DefaultCamelContext;
+import org.apache.camel.util.IntrospectionSupport;
+import org.apache.camel.util.ServiceHelper;
+import org.apache.camel.util.StringHelper;
+import org.apache.camel.util.jsse.SSLContextParameters;
+import org.apache.maven.plugin.AbstractMojo;
+import org.apache.maven.plugin.MojoExecutionException;
+import org.apache.maven.plugin.MojoFailureException;
+import org.apache.maven.plugins.annotations.Parameter;
+import org.eclipse.jetty.client.HttpProxy;
+import org.eclipse.jetty.client.Origin;
+import org.eclipse.jetty.client.ProxyConfiguration;
+import org.eclipse.jetty.client.Socks4Proxy;
+import org.eclipse.jetty.client.api.Authentication;
+import org.eclipse.jetty.client.util.BasicAuthentication;
+import org.eclipse.jetty.client.util.DigestAuthentication;
+import org.eclipse.jetty.util.ssl.SslContextFactory;
+
+/**
+ * Base class for any Salesforce MOJO.
+ */
+abstract class AbstractSalesforceMojo extends AbstractMojo {
+
+    // default connect and call timeout
+    private static final int DEFAULT_TIMEOUT = 60000;
+
+    /**
+     * Salesforce client id.
+     */
+    @Parameter(property = "camelSalesforce.clientId", required = true)
+    String clientId;
+
+    /**
+     * Salesforce client secret.
+     */
+    @Parameter(property = "camelSalesforce.clientSecret", required = true)
+    String clientSecret;
+
+    /**
+     * HTTP client properties.
+     */
+    @Parameter
+    Map<String, Object> httpClientProperties;
+
+    /**
+     * Proxy authentication URI.
+     */
+    @Parameter(property = "camelSalesforce.httpProxyAuthUri")
+    String httpProxyAuthUri;
+
+    /**
+     * Addresses to NOT Proxy.
+     */
+    @Parameter(property = "camelSalesforce.httpProxyExcludedAddresses")
+    Set<String> httpProxyExcludedAddresses;
+
+    /**
+     * HTTP Proxy host.
+     */
+    @Parameter(property = "camelSalesforce.httpProxyHost")
+    String httpProxyHost;
+
+    /**
+     * Addresses to Proxy.
+     */
+    @Parameter(property = "camelSalesforce.httpProxyIncludedAddresses")
+    Set<String> httpProxyIncludedAddresses;
+
+    /**
+     * Proxy authentication password.
+     */
+    @Parameter(property = "camelSalesforce.httpProxyPassword")
+    String httpProxyPassword;
+
+    /**
+     * HTTP Proxy port.
+     */
+    @Parameter(property = "camelSalesforce.httpProxyPort")
+    Integer httpProxyPort;
+
+    /**
+     * Proxy authentication realm.
+     */
+    @Parameter(property = "camelSalesforce.httpProxyRealm")
+    String httpProxyRealm;
+
+    /**
+     * Proxy uses Digest authentication.
+     */
+    @Parameter(property = "camelSalesforce.httpProxyUseDigestAuth")
+    boolean httpProxyUseDigestAuth;
+
+    /**
+     * Proxy authentication username.
+     */
+    @Parameter(property = "camelSalesforce.httpProxyUsername")
+    String httpProxyUsername;
+
+    /**
+     * Is HTTP Proxy secure, i.e. using secure sockets, true by default.
+     */
+    @Parameter(property = "camelSalesforce.isHttpProxySecure")
+    boolean isHttpProxySecure = true;
+
+    /**
+     * Is it a SOCKS4 Proxy?
+     */
+    @Parameter(property = "camelSalesforce.isHttpProxySocks4")
+    boolean isHttpProxySocks4;
+
+    /**
+     * Salesforce login URL, defaults to https://login.salesforce.com.
+     */
+    @Parameter(property = "camelSalesforce.loginUrl", defaultValue = 
SalesforceLoginConfig.DEFAULT_LOGIN_URL)
+    String loginUrl;
+
+    /**
+     * Salesforce password.
+     */
+    @Parameter(property = "camelSalesforce.password", required = true)
+    String password;
+
+    /**
+     * SSL Context parameters.
+     */
+    @Parameter(property = "camelSalesforce.sslContextParameters")
+    final SSLContextParameters sslContextParameters = new 
SSLContextParameters();
+
+    /**
+     * Salesforce username.
+     */
+    @Parameter(property = "camelSalesforce.userName", required = true)
+    String userName;
+
+    /**
+     * Salesforce API version.
+     */
+    @Parameter(property = "camelSalesforce.version", defaultValue = 
SalesforceEndpointConfig.DEFAULT_VERSION)
+    String version;
+
+    private long responseTimeout;
+
+    @Override
+    public final void execute() throws MojoExecutionException, 
MojoFailureException {
+        final RestClient restClient = connectToSalesforce();
+        try {
+            executeWithClient(restClient);
+        } finally {
+            disconnectFromSalesforce(restClient);
+        }
+    }
+
+    public long getResponseTimeout() {
+        return responseTimeout;
+    }
+
+    private RestClient connectToSalesforce() throws MojoExecutionException {
+        RestClient restClient = null;
+        try {
+            final SalesforceHttpClient httpClient = createHttpClient();
+
+            // connect to Salesforce
+            getLog().info("Logging in to Salesforce");
+            final SalesforceSession session = httpClient.getSession();
+            try {
+                session.login(null);
+            } catch (final SalesforceException e) {
+                final String msg = "Salesforce login error " + e.getMessage();
+                throw new MojoExecutionException(msg, e);
+            }
+            getLog().info("Salesforce login successful");
+
+            // create rest client
+
+            restClient = new DefaultRestClient(httpClient, version, 
PayloadFormat.JSON, session);
+            // remember to start the active client object
+            ((DefaultRestClient) restClient).start();
+
+            return restClient;
+        } catch (final Exception e) {
+            final String msg = "Error connecting to Salesforce: " + 
e.getMessage();
+            disconnectFromSalesforce(restClient);
+            throw new MojoExecutionException(msg, e);
+        }
+    }
+
+    private SalesforceHttpClient createHttpClient() throws 
MojoExecutionException {
+        final SalesforceHttpClient httpClient;
+
+        // set ssl context parameters
+        try {
+            final SslContextFactory sslContextFactory = new 
SslContextFactory();
+            
sslContextFactory.setSslContext(sslContextParameters.createSSLContext(new 
DefaultCamelContext()));
+
+            httpClient = new SalesforceHttpClient(sslContextFactory);
+        } catch (final GeneralSecurityException e) {
+            throw new MojoExecutionException("Error creating default SSL 
context: " + e.getMessage(), e);
+        } catch (final IOException e) {
+            throw new MojoExecutionException("Error creating default SSL 
context: " + e.getMessage(), e);
+        }
+
+        // default settings
+        httpClient.setConnectTimeout(DEFAULT_TIMEOUT);
+        httpClient.setTimeout(DEFAULT_TIMEOUT);
+
+        // enable redirects, no need for a RedirectListener class in Jetty 9
+        httpClient.setFollowRedirects(true);
+
+        // set HTTP client parameters
+        if (httpClientProperties != null && !httpClientProperties.isEmpty()) {
+            try {
+                IntrospectionSupport.setProperties(httpClient, new 
HashMap<>(httpClientProperties));
+            } catch (final Exception e) {
+                throw new MojoExecutionException("Error setting HTTP client 
properties: " + e.getMessage(), e);
+            }
+        }
+
+        // wait for 1 second longer than the HTTP client response timeout
+        responseTimeout = httpClient.getTimeout() + 1000L;
+
+        // set http proxy settings
+        // set HTTP proxy settings
+        if (httpProxyHost != null && httpProxyPort != null) {
+            final Origin.Address proxyAddress = new 
Origin.Address(httpProxyHost, httpProxyPort);
+            ProxyConfiguration.Proxy proxy;
+            if (isHttpProxySocks4) {
+                proxy = new Socks4Proxy(proxyAddress, isHttpProxySecure);
+            } else {
+                proxy = new HttpProxy(proxyAddress, isHttpProxySecure);
+            }
+            if (httpProxyIncludedAddresses != null && 
!httpProxyIncludedAddresses.isEmpty()) {
+                
proxy.getIncludedAddresses().addAll(httpProxyIncludedAddresses);
+            }
+            if (httpProxyExcludedAddresses != null && 
!httpProxyExcludedAddresses.isEmpty()) {
+                
proxy.getExcludedAddresses().addAll(httpProxyExcludedAddresses);
+            }
+            httpClient.getProxyConfiguration().getProxies().add(proxy);
+        }
+        if (httpProxyUsername != null && httpProxyPassword != null) {
+            StringHelper.notEmpty(httpProxyAuthUri, "httpProxyAuthUri");
+            StringHelper.notEmpty(httpProxyRealm, "httpProxyRealm");
+
+            final Authentication authentication;
+            if (httpProxyUseDigestAuth) {
+                authentication = new 
DigestAuthentication(URI.create(httpProxyAuthUri), httpProxyRealm,
+                    httpProxyUsername, httpProxyPassword);
+            } else {
+                authentication = new 
BasicAuthentication(URI.create(httpProxyAuthUri), httpProxyRealm,
+                    httpProxyUsername, httpProxyPassword);
+            }
+            
httpClient.getAuthenticationStore().addAuthentication(authentication);
+        }
+
+        // set session before calling start()
+        final SalesforceSession session = new SalesforceSession(new 
DefaultCamelContext(), httpClient,
+            httpClient.getTimeout(),
+            new SalesforceLoginConfig(loginUrl, clientId, clientSecret, 
userName, password, false));
+        httpClient.setSession(session);
+
+        try {
+            httpClient.start();
+        } catch (final Exception e) {
+            throw new MojoExecutionException("Error creating HTTP client: " + 
e.getMessage(), e);
+        }
+
+        return httpClient;
+    }
+
+    private void disconnectFromSalesforce(final RestClient restClient) {
+        if (restClient == null) {
+            return;
+        }
+
+        try {
+            final SalesforceHttpClient httpClient = (SalesforceHttpClient) 
((DefaultRestClient) restClient)
+                .getHttpClient();
+            ServiceHelper.stopAndShutdownServices(restClient, 
httpClient.getSession(), httpClient);
+        } catch (final Exception e) {
+            getLog().error("Error stopping Salesforce HTTP client", e);
+        }
+    }
+
+    protected abstract void executeWithClient(RestClient client) throws 
MojoExecutionException;
+}
diff --git 
a/components/camel-salesforce/camel-salesforce-maven-plugin/src/main/java/org/apache/camel/maven/CamelSalesforceMojo.java
 
b/components/camel-salesforce/camel-salesforce-maven-plugin/src/main/java/org/apache/camel/maven/CamelSalesforceMojo.java
deleted file mode 100644
index ab02d6b..0000000
--- 
a/components/camel-salesforce/camel-salesforce-maven-plugin/src/main/java/org/apache/camel/maven/CamelSalesforceMojo.java
+++ /dev/null
@@ -1,954 +0,0 @@
-/**
- * Licensed to the Apache Software Foundation (ASF) under one or more
- * contributor license agreements.  See the NOTICE file distributed with
- * this work for additional information regarding copyright ownership.
- * The ASF licenses this file to You under the Apache License, Version 2.0
- * (the "License"); you may not use this file except in compliance with
- * the License.  You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package org.apache.camel.maven;
-
-import java.io.File;
-import java.io.FileOutputStream;
-import java.io.IOException;
-import java.io.OutputStreamWriter;
-import java.io.Writer;
-import java.lang.reflect.Field;
-import java.net.URI;
-import java.nio.charset.StandardCharsets;
-import java.nio.file.Files;
-import java.nio.file.Path;
-import java.security.GeneralSecurityException;
-import java.util.ArrayList;
-import java.util.Arrays;
-import java.util.Collections;
-import java.util.Comparator;
-import java.util.Date;
-import java.util.HashMap;
-import java.util.HashSet;
-import java.util.List;
-import java.util.Map;
-import java.util.Properties;
-import java.util.Set;
-import java.util.Stack;
-import java.util.TreeSet;
-import java.util.concurrent.TimeUnit;
-import java.util.concurrent.atomic.AtomicInteger;
-import java.util.regex.Pattern;
-import java.util.stream.Collectors;
-
-import com.fasterxml.jackson.databind.ObjectMapper;
-import com.fasterxml.jackson.module.jsonSchema.JsonSchema;
-
-import org.apache.camel.component.salesforce.SalesforceEndpointConfig;
-import org.apache.camel.component.salesforce.SalesforceHttpClient;
-import org.apache.camel.component.salesforce.SalesforceLoginConfig;
-import org.apache.camel.component.salesforce.api.SalesforceException;
-import org.apache.camel.component.salesforce.api.dto.AbstractSObjectBase;
-import org.apache.camel.component.salesforce.api.dto.GlobalObjects;
-import org.apache.camel.component.salesforce.api.dto.PickListValue;
-import org.apache.camel.component.salesforce.api.dto.SObject;
-import org.apache.camel.component.salesforce.api.dto.SObjectDescription;
-import org.apache.camel.component.salesforce.api.dto.SObjectField;
-import org.apache.camel.component.salesforce.api.utils.JsonUtils;
-import org.apache.camel.component.salesforce.internal.PayloadFormat;
-import org.apache.camel.component.salesforce.internal.SalesforceSession;
-import org.apache.camel.component.salesforce.internal.client.DefaultRestClient;
-import org.apache.camel.component.salesforce.internal.client.RestClient;
-import 
org.apache.camel.component.salesforce.internal.client.SyncResponseCallback;
-import org.apache.camel.impl.DefaultCamelContext;
-import org.apache.camel.util.IntrospectionSupport;
-import org.apache.camel.util.ObjectHelper;
-import org.apache.camel.util.jsse.SSLContextParameters;
-import org.apache.commons.lang3.StringEscapeUtils;
-import org.apache.commons.lang3.StringUtils;
-import org.apache.log4j.Logger;
-import org.apache.maven.plugin.AbstractMojo;
-import org.apache.maven.plugin.MojoExecutionException;
-import org.apache.maven.plugin.logging.Log;
-import org.apache.maven.plugins.annotations.LifecyclePhase;
-import org.apache.maven.plugins.annotations.Mojo;
-import org.apache.maven.plugins.annotations.Parameter;
-import org.apache.velocity.Template;
-import org.apache.velocity.VelocityContext;
-import org.apache.velocity.app.VelocityEngine;
-import org.apache.velocity.runtime.RuntimeConstants;
-import org.apache.velocity.runtime.resource.loader.ClasspathResourceLoader;
-import org.eclipse.jetty.client.HttpProxy;
-import org.eclipse.jetty.client.Origin;
-import org.eclipse.jetty.client.ProxyConfiguration;
-import org.eclipse.jetty.client.Socks4Proxy;
-import org.eclipse.jetty.client.api.Authentication;
-import org.eclipse.jetty.client.util.BasicAuthentication;
-import org.eclipse.jetty.client.util.DigestAuthentication;
-import org.eclipse.jetty.util.ssl.SslContextFactory;
-
-/**
- * Goal to generate DTOs for Salesforce SObjects
- */
-@Mojo(name = "generate", requiresProject = false, defaultPhase = 
LifecyclePhase.GENERATE_SOURCES)
-public class CamelSalesforceMojo extends AbstractMojo {
-    // default connect and call timeout
-    protected static final int DEFAULT_TIMEOUT = 60000;
-
-    private static final String UTF_8 = "UTF-8";
-
-    private static final String JAVA_EXT = ".java";
-    private static final String PACKAGE_NAME_PATTERN = 
"(\\p{javaJavaIdentifierStart}\\p{javaJavaIdentifierPart}*\\.)+\\p{javaJavaIdentifierStart}\\p{javaJavaIdentifierPart}*";
-
-    private static final Pattern MATCH_EVERYTHING_PATTERN = 
Pattern.compile(".*");
-    private static final Pattern MATCH_NOTHING_PATTERN = Pattern.compile("^$");
-
-    private static final String SOBJECT_POJO_VM = "/sobject-pojo.vm";
-    private static final String SOBJECT_POJO_OPTIONAL_VM = 
"/sobject-pojo-optional.vm";
-    private static final String SOBJECT_QUERY_RECORDS_VM = 
"/sobject-query-records.vm";
-    private static final String SOBJECT_QUERY_RECORDS_OPTIONAL_VM = 
"/sobject-query-records-optional.vm";
-    private static final String SOBJECT_PICKLIST_VM = "/sobject-picklist.vm";
-
-    private static final List<String> IGNORED_OBJECTS = 
Arrays.asList("FieldDefinition");
-
-    // used for velocity logging, to avoid creating velocity.log
-    private static final Logger LOG = 
Logger.getLogger(CamelSalesforceMojo.class.getName());
-
-    /**
-     * HTTP client properties.
-     */
-    @Parameter
-    protected Map<String, Object> httpClientProperties;
-
-    /**
-     * SSL Context parameters.
-     */
-    @Parameter(property = "camelSalesforce.sslContextParameters")
-    protected SSLContextParameters sslContextParameters;
-
-    /**
-     * HTTP Proxy host.
-     */
-    @Parameter(property = "camelSalesforce.httpProxyHost")
-    protected String httpProxyHost;
-
-    /**
-     * HTTP Proxy port.
-     */
-    @Parameter(property = "camelSalesforce.httpProxyPort")
-    protected Integer httpProxyPort;
-
-    /**
-     * Is it a SOCKS4 Proxy?
-     */
-    @Parameter(property = "camelSalesforce.isHttpProxySocks4")
-    protected boolean isHttpProxySocks4;
-
-    /**
-     * Is HTTP Proxy secure, i.e. using secure sockets, true by default.
-     */
-    @Parameter(property = "camelSalesforce.isHttpProxySecure")
-    protected boolean isHttpProxySecure = true;
-
-    /**
-     * Addresses to Proxy.
-     */
-    @Parameter(property = "camelSalesforce.httpProxyIncludedAddresses")
-    protected Set<String> httpProxyIncludedAddresses;
-
-    /**
-     * Addresses to NOT Proxy.
-     */
-    @Parameter(property = "camelSalesforce.httpProxyExcludedAddresses")
-    protected Set<String> httpProxyExcludedAddresses;
-
-    /**
-     * Proxy authentication username.
-     */
-    @Parameter(property = "camelSalesforce.httpProxyUsername")
-    protected String httpProxyUsername;
-
-    /**
-     * Proxy authentication password.
-     */
-    @Parameter(property = "camelSalesforce.httpProxyPassword")
-    protected String httpProxyPassword;
-
-    /**
-     * Proxy authentication URI.
-     */
-    @Parameter(property = "camelSalesforce.httpProxyAuthUri")
-    protected String httpProxyAuthUri;
-
-    /**
-     * Proxy authentication realm.
-     */
-    @Parameter(property = "camelSalesforce.httpProxyRealm")
-    protected String httpProxyRealm;
-
-    /**
-     * Proxy uses Digest authentication.
-     */
-    @Parameter(property = "camelSalesforce.httpProxyUseDigestAuth")
-    protected boolean httpProxyUseDigestAuth;
-
-    /**
-     * Salesforce client id.
-     */
-    @Parameter(property = "camelSalesforce.clientId", required = true)
-    protected String clientId;
-
-    /**
-     * Salesforce client secret.
-     */
-    @Parameter(property = "camelSalesforce.clientSecret", required = true)
-    protected String clientSecret;
-
-    /**
-     * Salesforce username.
-     */
-    @Parameter(property = "camelSalesforce.userName", required = true)
-    protected String userName;
-
-    /**
-     * Salesforce password.
-     */
-    @Parameter(property = "camelSalesforce.password", required = true)
-    protected String password;
-
-    /**
-     * Salesforce API version.
-     */
-    @Parameter(property = "camelSalesforce.version", defaultValue = 
SalesforceEndpointConfig.DEFAULT_VERSION)
-    protected String version;
-
-    /**
-     * Location of generated DTO files, defaults to 
target/generated-sources/camel-salesforce.
-     */
-    @Parameter(property = "camelSalesforce.outputDirectory",
-        defaultValue = 
"${project.build.directory}/generated-sources/camel-salesforce")
-    protected File outputDirectory;
-
-    /**
-     * Salesforce login URL, defaults to https://login.salesforce.com.
-     */
-    @Parameter(property = "camelSalesforce.loginUrl", defaultValue = 
SalesforceLoginConfig.DEFAULT_LOGIN_URL)
-    protected String loginUrl;
-
-    /**
-     * Names of Salesforce SObject for which DTOs must be generated.
-     */
-    @Parameter
-    protected String[] includes;
-
-    /**
-     * Do NOT generate DTOs for these Salesforce SObjects.
-     */
-    @Parameter
-    protected String[] excludes;
-
-    /**
-     * Include Salesforce SObjects that match pattern.
-     */
-    @Parameter(property = "camelSalesforce.includePattern")
-    protected String includePattern;
-
-    /**
-     * Exclude Salesforce SObjects that match pattern.
-     */
-    @Parameter(property = "camelSalesforce.excludePattern")
-    protected String excludePattern;
-
-    /**
-     * Java package name for generated DTOs.
-     */
-    @Parameter(property = "camelSalesforce.packageName", defaultValue = 
"org.apache.camel.salesforce.dto")
-    protected String packageName;
-
-    @Parameter(property = "camelSalesforce.useOptionals", defaultValue = 
"false")
-    protected boolean useOptionals;
-
-    @Parameter(property = "camelSalesforce.useStringsForPicklists", 
defaultValue = "false")
-    protected Boolean useStringsForPicklists;
-
-    /**
-     * Generate JSON Schema for DTOs, instead of Java Objects.
-     */
-    @Parameter(property = "camelSalesforce.jsonSchema")
-    protected boolean jsonSchema;
-
-    /**
-     * Schema ID for JSON Schema for DTOs.
-     */
-    @Parameter(property = "camelSalesforce.jsonSchemaId", defaultValue = 
JsonUtils.DEFAULT_ID_PREFIX)
-    protected String jsonSchemaId;
-
-    /**
-     * Schema ID for JSON Schema for DTOs.
-     */
-    @Parameter(property = "camelSalesforce.jsonSchemaFilename", defaultValue = 
"salesforce-dto-schema.json")
-    protected String jsonSchemaFilename;
-
-    VelocityEngine engine;
-
-    private long responseTimeout;
-
-    /**
-     * Execute the mojo to generate SObject DTOs
-     *
-     * @throws MojoExecutionException
-     */
-    public void execute() throws MojoExecutionException {
-        engine = createVelocityEngine();
-
-        // make sure we can load both templates
-        if (!engine.resourceExists(SOBJECT_POJO_VM)
-                || !engine.resourceExists(SOBJECT_QUERY_RECORDS_VM)
-                || !engine.resourceExists(SOBJECT_POJO_OPTIONAL_VM)
-                || !engine.resourceExists(SOBJECT_QUERY_RECORDS_OPTIONAL_VM)) {
-            throw new MojoExecutionException("Velocity templates not found");
-        }
-
-        // connect to Salesforce
-        final SalesforceHttpClient httpClient = createHttpClient();
-        final SalesforceSession session = httpClient.getSession();
-
-        getLog().info("Salesforce login...");
-        try {
-            session.login(null);
-        } catch (SalesforceException e) {
-            String msg = "Salesforce login error " + e.getMessage();
-            throw new MojoExecutionException(msg, e);
-        }
-        getLog().info("Salesforce login successful");
-
-        // create rest client
-        RestClient restClient;
-        try {
-            restClient = new DefaultRestClient(httpClient,
-                    version, PayloadFormat.JSON, session);
-            // remember to start the active client object
-            ((DefaultRestClient) restClient).start();
-        } catch (Exception e) {
-            final String msg = "Unexpected exception creating Rest client: " + 
e.getMessage();
-            throw new MojoExecutionException(msg, e);
-        }
-
-        try {
-            // use Jackson json
-            final ObjectMapper mapper = JsonUtils.createObjectMapper();
-
-            // call getGlobalObjects to get all SObjects
-            final Set<String> objectNames = new TreeSet<String>();
-            final SyncResponseCallback callback = new SyncResponseCallback();
-            try {
-                getLog().info("Getting Salesforce Objects...");
-                restClient.getGlobalObjects(Collections.emptyMap(), callback);
-                if (!callback.await(responseTimeout, TimeUnit.MILLISECONDS)) {
-                    throw new MojoExecutionException("Timeout waiting for 
getGlobalObjects!");
-                }
-                final SalesforceException ex = callback.getException();
-                if (ex != null) {
-                    throw ex;
-                }
-                final GlobalObjects globalObjects = 
mapper.readValue(callback.getResponse(),
-                        GlobalObjects.class);
-
-                // create a list of object names
-                for (SObject sObject : globalObjects.getSobjects()) {
-                    objectNames.add(sObject.getName());
-                }
-            } catch (Exception e) {
-                String msg = "Error getting global Objects: " + e.getMessage();
-                throw new MojoExecutionException(msg, e);
-            }
-
-            // check if we are generating POJOs for all objects or not
-            if ((includes != null && includes.length > 0)
-                    || (excludes != null && excludes.length > 0)
-                    || ObjectHelper.isNotEmpty(includePattern)
-                    || ObjectHelper.isNotEmpty(excludePattern)) {
-
-                filterObjectNames(objectNames);
-
-            } else {
-                getLog().warn(String.format("Generating Java classes for all 
%s Objects, this may take a while...", objectNames.size()));
-            }
-
-            // for every accepted name, get SObject description
-            final Set<SObjectDescription> descriptions = new 
HashSet<SObjectDescription>();
-
-            getLog().info("Retrieving Object descriptions...");
-            for (String name : objectNames) {
-                try {
-                    callback.reset();
-                    restClient.getDescription(name, Collections.emptyMap(), 
callback);
-                    if (!callback.await(responseTimeout, 
TimeUnit.MILLISECONDS)) {
-                        throw new MojoExecutionException("Timeout waiting for 
getDescription for sObject " + name);
-                    }
-                    final SalesforceException ex = callback.getException();
-                    if (ex != null) {
-                        throw ex;
-                    }
-                    final SObjectDescription description = 
mapper.readValue(callback.getResponse(), SObjectDescription.class);
-
-                    // remove some of the unused used metadata
-                    // properties in order to minimize the code size
-                    // for CAMEL-11310
-                    final SObjectDescription descriptionToAdd = 
description.prune();
-
-                    descriptions.add(descriptionToAdd);
-                } catch (Exception e) {
-                    String msg = "Error getting SObject description for '" + 
name + "': " + e.getMessage();
-                    throw new MojoExecutionException(msg, e);
-                }
-            }
-
-            // create package directory
-            // validate package name
-            if (!packageName.matches(PACKAGE_NAME_PATTERN)) {
-                throw new MojoExecutionException("Invalid package name " + 
packageName);
-            }
-            if (outputDirectory.getAbsolutePath().contains("$")) {
-                outputDirectory = new 
File("generated-sources/camel-salesforce");
-            }
-            final File pkgDir = new File(outputDirectory, 
packageName.trim().replace('.', File.separatorChar));
-            if (!pkgDir.exists()) {
-                if (!pkgDir.mkdirs()) {
-                    throw new MojoExecutionException("Unable to create " + 
pkgDir);
-                }
-            }
-
-            if (!jsonSchema) {
-
-                getLog().info("Generating Java Classes...");
-                // generate POJOs for every object description
-                final GeneratorUtility utility = new 
GeneratorUtility(useStringsForPicklists, getLog());
-                // should we provide a flag to control timestamp generation?
-                final String generatedDate = new Date().toString();
-                for (SObjectDescription description : descriptions) {
-                    if (IGNORED_OBJECTS.contains(description.getName())) {
-                        continue;
-                    }
-                    try {
-                        processDescription(pkgDir, description, utility, 
generatedDate);
-                    } catch (IOException e) {
-                        throw new MojoExecutionException("Unable to generate 
source files for: " + description.getName(), e);
-                    }
-                }
-
-                getLog().info(String.format("Successfully generated %s Java 
Classes", descriptions.size() * 2));
-
-            } else {
-
-                getLog().info("Generating JSON Schema...");
-                // generate JSON schema for every object description
-                final ObjectMapper schemaObjectMapper = 
JsonUtils.createSchemaObjectMapper();
-                final Set<JsonSchema> allSchemas = new HashSet<>();
-                for (SObjectDescription description : descriptions) {
-                    if (IGNORED_OBJECTS.contains(description.getName())) {
-                        continue;
-                    }
-                    try {
-                        
allSchemas.addAll(JsonUtils.getSObjectJsonSchema(schemaObjectMapper, 
description, jsonSchemaId, true));
-                    } catch (IOException e) {
-                        throw new MojoExecutionException("Unable to generate 
JSON Schema types for: " + description.getName(), e);
-                    }
-                }
-
-                final Path schemaFilePath = 
outputDirectory.toPath().resolve(jsonSchemaFilename);
-                try {
-                    Files.write(schemaFilePath, 
JsonUtils.getJsonSchemaString(schemaObjectMapper, allSchemas, 
jsonSchemaId).getBytes("UTF-8"));
-                } catch (IOException e) {
-                    throw new MojoExecutionException("Unable to generate JSON 
Schema source file: " + schemaFilePath, e);
-                }
-
-                getLog().info(String.format("Successfully generated %s JSON 
Types in file %s", descriptions.size() * 2, schemaFilePath));
-            }
-
-        } finally {
-            // remember to stop the client
-            try {
-                ((DefaultRestClient) restClient).stop();
-            } catch (Exception ignore) {
-            }
-
-            // Salesforce session stop
-            try {
-                session.stop();
-            } catch (Exception ignore) {
-            }
-
-            // release HttpConnections
-            try {
-                httpClient.stop();
-            } catch (Exception ignore) {
-            }
-        }
-    }
-
-    static VelocityEngine createVelocityEngine() {
-        // initialize velocity to load resources from class loader and use 
Log4J
-        final Properties velocityProperties = new Properties();
-        velocityProperties.setProperty(RuntimeConstants.RESOURCE_LOADER, 
"cloader");
-        velocityProperties.setProperty("cloader.resource.loader.class", 
ClasspathResourceLoader.class.getName());
-        velocityProperties.setProperty(RuntimeConstants.RUNTIME_LOG_NAME, 
LOG.getName());
-        final VelocityEngine engine = new VelocityEngine(velocityProperties);
-
-        return engine;
-    }
-
-    protected void filterObjectNames(Set<String> objectNames) throws 
MojoExecutionException {
-        getLog().info("Looking for matching Object names...");
-        // create a list of accepted names
-        final Set<String> includedNames = new HashSet<String>();
-        if (includes != null && includes.length > 0) {
-            for (String name : includes) {
-                name = name.trim();
-                if (name.isEmpty()) {
-                    throw new MojoExecutionException("Invalid empty name in 
includes");
-                }
-                includedNames.add(name);
-            }
-        }
-
-        final Set<String> excludedNames = new HashSet<String>();
-        if (excludes != null && excludes.length > 0) {
-            for (String name : excludes) {
-                name = name.trim();
-                if (name.isEmpty()) {
-                    throw new MojoExecutionException("Invalid empty name in 
excludes");
-                }
-                excludedNames.add(name);
-            }
-        }
-
-        // check whether a pattern is in effect
-        Pattern incPattern;
-        if (includePattern != null && !includePattern.trim().isEmpty()) {
-            incPattern = Pattern.compile(includePattern.trim());
-        } else if (includedNames.isEmpty()) {
-            // include everything by default if no include names are set
-            incPattern = MATCH_EVERYTHING_PATTERN;
-        } else {
-            // include nothing by default if include names are set
-            incPattern = MATCH_NOTHING_PATTERN;
-        }
-
-        // check whether a pattern is in effect
-        Pattern excPattern;
-        if (excludePattern != null && !excludePattern.trim().isEmpty()) {
-            excPattern = Pattern.compile(excludePattern.trim());
-        } else {
-            // exclude nothing by default
-            excPattern = MATCH_NOTHING_PATTERN;
-        }
-
-        final Set<String> acceptedNames = new HashSet<String>();
-        for (String name : objectNames) {
-            // name is included, or matches include pattern
-            // and is not excluded and does not match exclude pattern
-            if ((includedNames.contains(name) || 
incPattern.matcher(name).matches())
-                    && !excludedNames.contains(name) && 
!excPattern.matcher(name).matches()) {
-                acceptedNames.add(name);
-            }
-        }
-        objectNames.clear();
-        objectNames.addAll(acceptedNames);
-
-        getLog().info(String.format("Found %s matching Objects", 
objectNames.size()));
-    }
-
-    protected SalesforceHttpClient createHttpClient() throws 
MojoExecutionException {
-
-        final SalesforceHttpClient httpClient;
-
-        // set ssl context parameters
-        try {
-
-            final SSLContextParameters contextParameters = 
sslContextParameters != null
-                ? sslContextParameters : new SSLContextParameters();
-            final SslContextFactory sslContextFactory = new 
SslContextFactory();
-            
sslContextFactory.setSslContext(contextParameters.createSSLContext());
-
-            httpClient = new SalesforceHttpClient(sslContextFactory);
-
-        } catch (GeneralSecurityException e) {
-            throw new MojoExecutionException("Error creating default SSL 
context: " + e.getMessage(), e);
-        } catch (IOException e) {
-            throw new MojoExecutionException("Error creating default SSL 
context: " + e.getMessage(), e);
-        }
-
-        // default settings
-        httpClient.setConnectTimeout(DEFAULT_TIMEOUT);
-        httpClient.setTimeout(DEFAULT_TIMEOUT);
-
-        // enable redirects, no need for a RedirectListener class in Jetty 9
-        httpClient.setFollowRedirects(true);
-
-        // set HTTP client parameters
-        if (httpClientProperties != null && !httpClientProperties.isEmpty()) {
-            try {
-                IntrospectionSupport.setProperties(httpClient, new 
HashMap<String, Object>(httpClientProperties));
-            } catch (Exception e) {
-                throw new MojoExecutionException("Error setting HTTP client 
properties: " + e.getMessage(), e);
-            }
-        }
-
-        // wait for 1 second longer than the HTTP client response timeout
-        responseTimeout = httpClient.getTimeout() + 1000L;
-
-        // set http proxy settings
-        // set HTTP proxy settings
-        if (this.httpProxyHost != null && httpProxyPort != null) {
-            Origin.Address proxyAddress = new 
Origin.Address(this.httpProxyHost, this.httpProxyPort);
-            ProxyConfiguration.Proxy proxy;
-            if (isHttpProxySocks4) {
-                proxy = new Socks4Proxy(proxyAddress, isHttpProxySecure);
-            } else {
-                proxy = new HttpProxy(proxyAddress, isHttpProxySecure);
-            }
-            if (httpProxyIncludedAddresses != null && 
!httpProxyIncludedAddresses.isEmpty()) {
-                
proxy.getIncludedAddresses().addAll(httpProxyIncludedAddresses);
-            }
-            if (httpProxyExcludedAddresses != null && 
!httpProxyExcludedAddresses.isEmpty()) {
-                
proxy.getExcludedAddresses().addAll(httpProxyExcludedAddresses);
-            }
-            httpClient.getProxyConfiguration().getProxies().add(proxy);
-        }
-        if (this.httpProxyUsername != null && httpProxyPassword != null) {
-
-            ObjectHelper.notEmpty(httpProxyAuthUri, "httpProxyAuthUri");
-            ObjectHelper.notEmpty(httpProxyRealm, "httpProxyRealm");
-
-            final Authentication authentication;
-            if (httpProxyUseDigestAuth) {
-                authentication = new 
DigestAuthentication(URI.create(httpProxyAuthUri),
-                    httpProxyRealm, httpProxyUsername, httpProxyPassword);
-            } else {
-                authentication = new 
BasicAuthentication(URI.create(httpProxyAuthUri),
-                    httpProxyRealm, httpProxyUsername, httpProxyPassword);
-            }
-            
httpClient.getAuthenticationStore().addAuthentication(authentication);
-        }
-
-        // set session before calling start()
-        final SalesforceSession session = new SalesforceSession(new 
DefaultCamelContext(), httpClient,
-            httpClient.getTimeout(),
-            new SalesforceLoginConfig(loginUrl, clientId, clientSecret, 
userName, password, false));
-        httpClient.setSession(session);
-
-        try {
-            httpClient.start();
-        } catch (Exception e) {
-            throw new MojoExecutionException("Error creating HTTP client: " + 
e.getMessage(), e);
-        }
-        return httpClient;
-    }
-
-    void processDescription(File pkgDir, SObjectDescription description, 
GeneratorUtility utility, String generatedDate) throws IOException {
-        // generate a source file for SObject
-        final VelocityContext context = new VelocityContext();
-        context.put("packageName", packageName);
-        context.put("utility", utility);
-        context.put("esc", StringEscapeUtils.class);
-        context.put("desc", description);
-        context.put("generatedDate", generatedDate);
-        context.put("useStringsForPicklists", useStringsForPicklists);
-
-        final String pojoFileName = description.getName() + JAVA_EXT;
-        final File pojoFile = new File(pkgDir, pojoFileName);
-        try (final Writer writer = new OutputStreamWriter(new 
FileOutputStream(pojoFile), StandardCharsets.UTF_8)) {
-            final Template pojoTemplate = engine.getTemplate(SOBJECT_POJO_VM, 
UTF_8);
-            pojoTemplate.merge(context, writer);
-        }
-
-        if (useOptionals) {
-            final String optionalFileName = description.getName() + "Optional" 
+ JAVA_EXT;
-            final File optionalFile = new File(pkgDir, optionalFileName);
-            try (final Writer writer = new OutputStreamWriter(new 
FileOutputStream(optionalFile), StandardCharsets.UTF_8)) {
-                final Template optionalTemplate = 
engine.getTemplate(SOBJECT_POJO_OPTIONAL_VM, UTF_8);
-                optionalTemplate.merge(context, writer);
-            }
-        }
-
-        // write required Enumerations for any picklists
-        for (SObjectField field : description.getFields()) {
-            if (utility.isPicklist(field) || 
utility.isMultiSelectPicklist(field)) {
-                final String enumName = description.getName() + "_" + 
utility.enumTypeName(field.getName());
-                final String enumFileName = enumName + JAVA_EXT;
-                final File enumFile = new File(pkgDir, enumFileName);
-
-                context.put("field", field);
-                context.put("enumName", enumName);
-                final Template enumTemplate = 
engine.getTemplate(SOBJECT_PICKLIST_VM, UTF_8);
-
-                try (final Writer writer = new OutputStreamWriter(new 
FileOutputStream(enumFile), StandardCharsets.UTF_8)) {
-                    enumTemplate.merge(context, writer);
-                }
-            }
-        }
-
-        // write the QueryRecords class
-        final String queryRecordsFileName = "QueryRecords" + 
description.getName() + JAVA_EXT;
-        final File queryRecordsFile = new File(pkgDir, queryRecordsFileName);
-        final Template queryTemplate = 
engine.getTemplate(SOBJECT_QUERY_RECORDS_VM, UTF_8);
-        try (final Writer writer = new OutputStreamWriter(new 
FileOutputStream(queryRecordsFile), StandardCharsets.UTF_8)) {
-            queryTemplate.merge(context, writer);
-        }
-
-        if (useOptionals) {
-            // write the QueryRecords Optional class
-            final String queryRecordsOptionalFileName = "QueryRecords" + 
description.getName() + "Optional" + JAVA_EXT;
-            final File queryRecordsOptionalFile = new File(pkgDir, 
queryRecordsOptionalFileName);
-            final Template queryRecordsOptionalTemplate = 
engine.getTemplate(SOBJECT_QUERY_RECORDS_OPTIONAL_VM, UTF_8);
-            try (final Writer writer = new OutputStreamWriter(new 
FileOutputStream(queryRecordsOptionalFile), StandardCharsets.UTF_8)) {
-                queryRecordsOptionalTemplate.merge(context, writer);
-            }
-        }
-    }
-
-    public static class GeneratorUtility {
-
-        private static final Set<String> BASE_FIELDS;
-        private static final Map<String, String> LOOKUP_MAP;
-
-        static {
-            BASE_FIELDS = new HashSet<String>();
-            for (Field field : AbstractSObjectBase.class.getDeclaredFields()) {
-                BASE_FIELDS.add(field.getName());
-            }
-
-            // create a type map
-            // using JAXB mapping, for the most part
-            final String[][] typeMap = new String[][]{
-                {"ID", "String"}, // mapping for tns:ID SOAP type
-                {"string", "String"},
-                {"integer", "java.math.BigInteger"},
-                {"int", "Integer"},
-                {"long", "Long"},
-                {"short", "Short"},
-                {"decimal", "java.math.BigDecimal"},
-                {"float", "Float"},
-                {"double", "Double"},
-                {"boolean", "Boolean"},
-                {"byte", "Byte"},
-
-                {"dateTime", "java.time.ZonedDateTime"},
-
-                // the blob base64Binary type is mapped to String URL for 
retrieving the blob
-                {"base64Binary", "String"},
-
-                {"unsignedInt", "Long"},
-                {"unsignedShort", "Integer"},
-                {"unsignedByte", "Short"},
-
-                {"time", "java.time.ZonedDateTime"},
-                {"date", "java.time.ZonedDateTime"},
-                {"g", "java.time.ZonedDateTime"},
-
-                // Salesforce maps any types like string, picklist, reference, 
etc. to string
-                {"anyType", "String"},
-                {"address", 
"org.apache.camel.component.salesforce.api.dto.Address"},
-                {"location", 
"org.apache.camel.component.salesforce.api.dto.GeoLocation"},
-                {"RelationshipReferenceTo", "String"}
-            };
-            LOOKUP_MAP = new HashMap<String, String>();
-            for (String[] entry : typeMap) {
-                LOOKUP_MAP.put(entry[0], entry[1]);
-            }
-        }
-
-        private static final String BASE64BINARY = "base64Binary";
-        private static final String MULTIPICKLIST = "multipicklist";
-        private static final String PICKLIST = "picklist";
-        private static final List<String> BLACKLISTED_PROPERTIES = 
Arrays.asList("PicklistValues", "ChildRelationships");
-        private boolean useStringsForPicklists;
-        private final Map<String, AtomicInteger> varNames = new HashMap<>();
-        private Stack<String> stack;
-        private final Log log;
-
-        public GeneratorUtility(Boolean useStringsForPicklists, Log log) {
-            this.log = log;
-            this.useStringsForPicklists = 
Boolean.TRUE.equals(useStringsForPicklists);
-        }
-
-        public boolean isBlobField(SObjectField field) {
-            final String soapType = field.getSoapType();
-            return 
BASE64BINARY.equals(soapType.substring(soapType.indexOf(':') + 1));
-        }
-
-        public boolean notBaseField(String name) {
-            return !BASE_FIELDS.contains(name);
-        }
-
-        public String getFieldType(SObjectDescription description, 
SObjectField field) throws MojoExecutionException {
-            // check if this is a picklist
-            if (isPicklist(field)) {
-                if (useStringsForPicklists) {
-                    return String.class.getName();
-                } else {
-                    // use a pick list enum, which will be created after 
generating the SObject class
-                    return description.getName() + "_" + 
enumTypeName(field.getName());
-                }
-            } else if (isMultiSelectPicklist(field)) {
-                if (useStringsForPicklists) {
-                    return String.class.getName() + "[]";
-                } else {
-                    // use a pick list enum array, enum will be created after 
generating the SObject class
-                    return description.getName() + "_" + 
enumTypeName(field.getName()) + "[]";
-                }
-            } else {
-                // map field to Java type
-                final String soapType = field.getSoapType();
-                final String type = 
LOOKUP_MAP.get(soapType.substring(soapType.indexOf(':') + 1));
-                if (type == null) {
-                    log.warn(String.format("Unsupported field type %s in field 
%s of object %s", soapType, field.getName(), description.getName()));
-                }
-                return type;
-            }
-        }
-
-        public boolean isMultiSelectPicklist(SObjectField field) {
-            return MULTIPICKLIST.equals(field.getType());
-        }
-
-        public boolean hasPicklists(SObjectDescription desc) {
-            for (SObjectField field : desc.getFields()) {
-                if (isPicklist(field)) {
-                    return true;
-                }
-            }
-            return false;
-        }
-
-        public boolean hasMultiSelectPicklists(SObjectDescription desc) {
-            for (SObjectField field : desc.getFields()) {
-                if (isMultiSelectPicklist(field)) {
-                    return true;
-                }
-            }
-            return false;
-        }
-
-        public List<PickListValue> getUniqueValues(SObjectField field) {
-            if (field.getPicklistValues().isEmpty()) {
-                return field.getPicklistValues();
-            }
-            final List<PickListValue> result = new ArrayList<PickListValue>();
-            final Set<String> literals = new HashSet<String>();
-            for (PickListValue listValue : field.getPicklistValues()) {
-                final String value = listValue.getValue();
-                if (!literals.contains(value)) {
-                    literals.add(value);
-                    result.add(listValue);
-                }
-            }
-            literals.clear();
-            Collections.sort(result, new Comparator<PickListValue>() {
-                @Override
-                public int compare(PickListValue o1, PickListValue o2) {
-                    return o1.getValue().compareTo(o2.getValue());
-                }
-            });
-            return result;
-        }
-
-        public boolean isPicklist(SObjectField field) {
-            return PICKLIST.equals(field.getType());
-        }
-
-        public String enumTypeName(String name) {
-            name = name.endsWith("__c") ? name.substring(0, name.length() - 3) 
: name;
-            return name + "Enum";
-        }
-
-        public String getEnumConstant(String value) {
-
-            // TODO add support for supplementary characters
-            final StringBuilder result = new StringBuilder();
-            boolean changed = false;
-            if (!Character.isJavaIdentifierStart(value.charAt(0))) {
-                result.append("_");
-                changed = true;
-            }
-            for (char c : value.toCharArray()) {
-                if (Character.isJavaIdentifierPart(c)) {
-                    result.append(c);
-                } else {
-                    // replace non Java identifier character with '_'
-                    result.append('_');
-                    changed = true;
-                }
-            }
-
-            return changed ? result.toString().toUpperCase() : 
value.toUpperCase();
-        }
-
-        public boolean includeList(final List<?> list, final String 
propertyName) {
-            return !list.isEmpty() && 
!BLACKLISTED_PROPERTIES.contains(propertyName);
-        }
-        public boolean notNull(final Object val) {
-            return val != null;
-        }
-
-        public Set<Map.Entry<String, Object>> propertiesOf(final Object 
object) {
-            final Map<String, Object> properties = new HashMap<>();
-            IntrospectionSupport.getProperties(object, properties, null, 
false);
-
-            return properties.entrySet().stream()
-                .collect(Collectors.toMap(e -> 
StringUtils.capitalize(e.getKey()), Map.Entry::getValue)).entrySet();
-        }
-
-        public String variableName(final String given) {
-            final String base = StringUtils.uncapitalize(given);
-
-            AtomicInteger counter = varNames.get(base);
-            if (counter == null) {
-                counter = new AtomicInteger(0);
-                varNames.put(base, counter);
-            }
-
-            return base + counter.incrementAndGet();
-        }
-
-        public boolean isPrimitiveOrBoxed(final Object object) {
-            final Class<?> clazz = object.getClass();
-
-            final boolean isWholeNumberWrapper = Byte.class.equals(clazz) || 
Short.class.equals(clazz)
-                || Integer.class.equals(clazz) || Long.class.equals(clazz);
-
-            final boolean isFloatingPointWrapper = Double.class.equals(clazz) 
|| Float.class.equals(clazz);
-
-            final boolean isWrapper = isWholeNumberWrapper || 
isFloatingPointWrapper || Boolean.class.equals(clazz)
-                || Character.class.equals(clazz);
-
-            final boolean isPrimitive = clazz.isPrimitive();
-
-            return isPrimitive || isWrapper;
-        }
-
-        public void start(final String initial) {
-            stack = new Stack<>();
-            stack.push(initial);
-            varNames.clear();
-        }
-
-        public String current() {
-            return stack.peek();
-        }
-
-        public void push(final String additional) {
-            stack.push(additional);
-        }
-
-        public void pop() {
-            stack.pop();
-        }
-    }
-
-}
diff --git 
a/components/camel-salesforce/camel-salesforce-maven-plugin/src/main/java/org/apache/camel/maven/Defaults.java
 
b/components/camel-salesforce/camel-salesforce-maven-plugin/src/main/java/org/apache/camel/maven/Defaults.java
new file mode 100644
index 0000000..c384131
--- /dev/null
+++ 
b/components/camel-salesforce/camel-salesforce-maven-plugin/src/main/java/org/apache/camel/maven/Defaults.java
@@ -0,0 +1,35 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.camel.maven;
+
+import java.util.Arrays;
+import java.util.List;
+import java.util.regex.Pattern;
+
+final class Defaults {
+
+    static final List<String> IGNORED_OBJECTS = 
Arrays.asList("FieldDefinition");
+
+    static final Pattern MATCH_EVERYTHING_PATTERN = Pattern.compile(".*");
+
+    static final Pattern MATCH_NOTHING_PATTERN = Pattern.compile("^$");
+
+    private Defaults() {
+        // holds constant values
+    }
+
+}
diff --git 
a/components/camel-salesforce/camel-salesforce-maven-plugin/src/main/java/org/apache/camel/maven/GenerateMojo.java
 
b/components/camel-salesforce/camel-salesforce-maven-plugin/src/main/java/org/apache/camel/maven/GenerateMojo.java
new file mode 100644
index 0000000..7d1c452
--- /dev/null
+++ 
b/components/camel-salesforce/camel-salesforce-maven-plugin/src/main/java/org/apache/camel/maven/GenerateMojo.java
@@ -0,0 +1,497 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.camel.maven;
+
+import java.io.File;
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.io.OutputStreamWriter;
+import java.io.Writer;
+import java.lang.reflect.Field;
+import java.nio.charset.StandardCharsets;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.Date;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Map;
+import java.util.Properties;
+import java.util.Set;
+import java.util.Stack;
+import java.util.concurrent.atomic.AtomicInteger;
+import java.util.stream.Collectors;
+
+import org.apache.camel.component.salesforce.api.dto.AbstractSObjectBase;
+import org.apache.camel.component.salesforce.api.dto.PickListValue;
+import org.apache.camel.component.salesforce.api.dto.SObjectDescription;
+import org.apache.camel.component.salesforce.api.dto.SObjectField;
+import org.apache.camel.component.salesforce.internal.client.RestClient;
+import org.apache.camel.util.IntrospectionSupport;
+import org.apache.commons.lang3.StringEscapeUtils;
+import org.apache.commons.lang3.StringUtils;
+import org.apache.log4j.Logger;
+import org.apache.maven.plugin.MojoExecutionException;
+import org.apache.maven.plugins.annotations.LifecyclePhase;
+import org.apache.maven.plugins.annotations.Mojo;
+import org.apache.maven.plugins.annotations.Parameter;
+import org.apache.velocity.Template;
+import org.apache.velocity.VelocityContext;
+import org.apache.velocity.app.VelocityEngine;
+import org.apache.velocity.runtime.RuntimeConstants;
+import org.apache.velocity.runtime.resource.loader.ClasspathResourceLoader;
+
+/**
+ * Goal to generate DTOs for Salesforce SObjects
+ */
+@Mojo(name = "generate", requiresProject = false, defaultPhase = 
LifecyclePhase.GENERATE_SOURCES)
+public class GenerateMojo extends AbstractSalesforceMojo {
+    public class GeneratorUtility {
+
+        private Stack<String> stack;
+        private final Map<String, AtomicInteger> varNames = new HashMap<>();
+
+        public String current() {
+            return stack.peek();
+        }
+
+        public String enumTypeName(final String name) {
+            return (name.endsWith("__c") ? name.substring(0, name.length() - 
3) : name) + "Enum";
+        }
+
+        public String getEnumConstant(final String value) {
+
+            // TODO add support for supplementary characters
+            final StringBuilder result = new StringBuilder();
+            boolean changed = false;
+            if (!Character.isJavaIdentifierStart(value.charAt(0))) {
+                result.append("_");
+                changed = true;
+            }
+            for (final char c : value.toCharArray()) {
+                if (Character.isJavaIdentifierPart(c)) {
+                    result.append(c);
+                } else {
+                    // replace non Java identifier character with '_'
+                    result.append('_');
+                    changed = true;
+                }
+            }
+
+            return changed ? result.toString().toUpperCase() : 
value.toUpperCase();
+        }
+
+        public String getFieldType(final SObjectDescription description, final 
SObjectField field) {
+            // check if this is a picklist
+            if (isPicklist(field)) {
+                if (Boolean.TRUE.equals(useStringsForPicklists)) {
+                    return String.class.getName();
+                }
+
+                // use a pick list enum, which will be created after generating
+                // the SObject class
+                return description.getName() + "_" + 
enumTypeName(field.getName());
+            } else if (isMultiSelectPicklist(field)) {
+                if (useStringsForPicklists) {
+                    return String.class.getName() + "[]";
+                }
+
+                // use a pick list enum array, enum will be created after
+                // generating the SObject class
+                return description.getName() + "_" + 
enumTypeName(field.getName()) + "[]";
+            } else {
+                // map field to Java type
+                final String soapType = field.getSoapType();
+                final String type = 
LOOKUP_MAP.get(soapType.substring(soapType.indexOf(':') + 1));
+                if (type == null) {
+                    getLog().warn(String.format("Unsupported field type %s in 
field %s of object %s", soapType,
+                        field.getName(), description.getName()));
+                }
+                return type;
+            }
+        }
+
+        public List<PickListValue> getUniqueValues(final SObjectField field) {
+            if (field.getPicklistValues().isEmpty()) {
+                return field.getPicklistValues();
+            }
+            final List<PickListValue> result = new ArrayList<>();
+            final Set<String> literals = new HashSet<>();
+            for (final PickListValue listValue : field.getPicklistValues()) {
+                final String value = listValue.getValue();
+                if (!literals.contains(value)) {
+                    literals.add(value);
+                    result.add(listValue);
+                }
+            }
+            literals.clear();
+            Collections.sort(result, (o1, o2) -> 
o1.getValue().compareTo(o2.getValue()));
+            return result;
+        }
+
+        public boolean hasMultiSelectPicklists(final SObjectDescription desc) {
+            for (final SObjectField field : desc.getFields()) {
+                if (isMultiSelectPicklist(field)) {
+                    return true;
+                }
+            }
+            return false;
+        }
+
+        public boolean hasPicklists(final SObjectDescription desc) {
+            for (final SObjectField field : desc.getFields()) {
+                if (isPicklist(field)) {
+                    return true;
+                }
+            }
+            return false;
+        }
+
+        public boolean includeList(final List<?> list, final String 
propertyName) {
+            return !list.isEmpty() && 
!BLACKLISTED_PROPERTIES.contains(propertyName);
+        }
+
+        public boolean isBlobField(final SObjectField field) {
+            final String soapType = field.getSoapType();
+            return 
BASE64BINARY.equals(soapType.substring(soapType.indexOf(':') + 1));
+        }
+
+        public boolean isExternalId(final SObjectField field) {
+            return field.isExternalId();
+        }
+
+        public boolean isMultiSelectPicklist(final SObjectField field) {
+            return MULTIPICKLIST.equals(field.getType());
+        }
+
+        public boolean isPicklist(final SObjectField field) {
+            return PICKLIST.equals(field.getType());
+        }
+
+        public boolean isPrimitiveOrBoxed(final Object object) {
+            final Class<?> clazz = object.getClass();
+
+            final boolean isWholeNumberWrapper = Byte.class.equals(clazz) || 
Short.class.equals(clazz)
+                || Integer.class.equals(clazz) || Long.class.equals(clazz);
+
+            final boolean isFloatingPointWrapper = Double.class.equals(clazz) 
|| Float.class.equals(clazz);
+
+            final boolean isWrapper = isWholeNumberWrapper || 
isFloatingPointWrapper || Boolean.class.equals(clazz)
+                || Character.class.equals(clazz);
+
+            final boolean isPrimitive = clazz.isPrimitive();
+
+            return isPrimitive || isWrapper;
+        }
+
+        public boolean notBaseField(final String name) {
+            return !BASE_FIELDS.contains(name);
+        }
+
+        public boolean notNull(final Object val) {
+            return val != null;
+        }
+
+        public void pop() {
+            stack.pop();
+        }
+
+        public Set<Map.Entry<String, Object>> propertiesOf(final Object 
object) {
+            final Map<String, Object> properties = new HashMap<>();
+            IntrospectionSupport.getProperties(object, properties, null, 
false);
+
+            return properties.entrySet().stream()
+                .collect(Collectors.toMap(e -> 
StringUtils.capitalize(e.getKey()), Map.Entry::getValue)).entrySet();
+        }
+
+        public void push(final String additional) {
+            stack.push(additional);
+        }
+
+        public void start(final String initial) {
+            stack = new Stack<>();
+            stack.push(initial);
+            varNames.clear();
+        }
+
+        public String variableName(final String given) {
+            final String base = StringUtils.uncapitalize(given);
+
+            AtomicInteger counter = varNames.get(base);
+            if (counter == null) {
+                counter = new AtomicInteger(0);
+                varNames.put(base, counter);
+            }
+
+            return base + counter.incrementAndGet();
+        }
+    }
+
+    private static final Set<String> BASE_FIELDS = defineBaseFields();
+
+    private static final String BASE64BINARY = "base64Binary";
+
+    private static final List<String> BLACKLISTED_PROPERTIES = 
Arrays.asList("PicklistValues", "ChildRelationships");
+
+    private static final String JAVA_EXT = ".java";
+
+    // used for velocity logging, to avoid creating velocity.log
+    private static final Logger LOG = 
Logger.getLogger(GenerateMojo.class.getName());
+
+    private static final Map<String, String> LOOKUP_MAP = defineLookupMap();
+    private static final String MULTIPICKLIST = "multipicklist";
+
+    private static final String PACKAGE_NAME_PATTERN = 
"(\\p{javaJavaIdentifierStart}\\p{javaJavaIdentifierPart}*\\.)+\\p{javaJavaIdentifierStart}\\p{javaJavaIdentifierPart}*";
+    private static final String PICKLIST = "picklist";
+    private static final String SOBJECT_PICKLIST_VM = "/sobject-picklist.vm";
+    private static final String SOBJECT_POJO_OPTIONAL_VM = 
"/sobject-pojo-optional.vm";
+    private static final String SOBJECT_POJO_VM = "/sobject-pojo.vm";
+
+    private static final String SOBJECT_QUERY_RECORDS_OPTIONAL_VM = 
"/sobject-query-records-optional.vm";
+
+    private static final String SOBJECT_QUERY_RECORDS_VM = 
"/sobject-query-records.vm";
+
+    private static final String UTF_8 = "UTF-8";
+
+    VelocityEngine engine;
+
+    /**
+     * Include Salesforce SObjects that match pattern.
+     */
+    @Parameter(property = "camelSalesforce.includePattern")
+    String includePattern;
+
+    /**
+     * Location of generated DTO files, defaults to
+     * target/generated-sources/camel-salesforce.
+     */
+    @Parameter(property = "camelSalesforce.outputDirectory",
+        defaultValue = 
"${project.build.directory}/generated-sources/camel-salesforce")
+    File outputDirectory;
+
+    /**
+     * Java package name for generated DTOs.
+     */
+    @Parameter(property = "camelSalesforce.packageName", defaultValue = 
"org.apache.camel.salesforce.dto")
+    String packageName;
+
+    private ObjectDescriptions descriptions;
+
+    /**
+     * Exclude Salesforce SObjects that match pattern.
+     */
+    @Parameter(property = "camelSalesforce.excludePattern")
+    private String excludePattern;
+
+    /**
+     * Do NOT generate DTOs for these Salesforce SObjects.
+     */
+    @Parameter
+    private String[] excludes;
+
+    /**
+     * Names of Salesforce SObject for which DTOs must be generated.
+     */
+    @Parameter
+    private String[] includes;
+
+    @Parameter(property = "camelSalesforce.useOptionals", defaultValue = 
"false")
+    private boolean useOptionals;
+
+    @Parameter(property = "camelSalesforce.useStringsForPicklists", 
defaultValue = "false")
+    private Boolean useStringsForPicklists;
+
+    void processDescription(final File pkgDir, final SObjectDescription 
description, final GeneratorUtility utility,
+        final String generatedDate) throws IOException {
+        // generate a source file for SObject
+        final VelocityContext context = new VelocityContext();
+        context.put("packageName", packageName);
+        context.put("utility", utility);
+        context.put("esc", StringEscapeUtils.class);
+        context.put("desc", description);
+        context.put("generatedDate", generatedDate);
+        context.put("useStringsForPicklists", useStringsForPicklists);
+
+        final String pojoFileName = description.getName() + JAVA_EXT;
+        final File pojoFile = new File(pkgDir, pojoFileName);
+        context.put("descriptions", descriptions);
+        try (final Writer writer = new OutputStreamWriter(new 
FileOutputStream(pojoFile), StandardCharsets.UTF_8)) {
+            final Template pojoTemplate = engine.getTemplate(SOBJECT_POJO_VM, 
UTF_8);
+            pojoTemplate.merge(context, writer);
+        }
+
+        if (useOptionals) {
+            final String optionalFileName = description.getName() + "Optional" 
+ JAVA_EXT;
+            final File optionalFile = new File(pkgDir, optionalFileName);
+            try (final Writer writer = new OutputStreamWriter(new 
FileOutputStream(optionalFile),
+                StandardCharsets.UTF_8)) {
+                final Template optionalTemplate = 
engine.getTemplate(SOBJECT_POJO_OPTIONAL_VM, UTF_8);
+                optionalTemplate.merge(context, writer);
+            }
+        }
+
+        // write required Enumerations for any picklists
+        for (final SObjectField field : description.getFields()) {
+            if (utility.isPicklist(field) || 
utility.isMultiSelectPicklist(field)) {
+                final String enumName = description.getName() + "_" + 
utility.enumTypeName(field.getName());
+                final String enumFileName = enumName + JAVA_EXT;
+                final File enumFile = new File(pkgDir, enumFileName);
+
+                context.put("field", field);
+                context.put("enumName", enumName);
+                final Template enumTemplate = 
engine.getTemplate(SOBJECT_PICKLIST_VM, UTF_8);
+
+                try (final Writer writer = new OutputStreamWriter(new 
FileOutputStream(enumFile),
+                    StandardCharsets.UTF_8)) {
+                    enumTemplate.merge(context, writer);
+                }
+            }
+        }
+
+        // write the QueryRecords class
+        final String queryRecordsFileName = "QueryRecords" + 
description.getName() + JAVA_EXT;
+        final File queryRecordsFile = new File(pkgDir, queryRecordsFileName);
+        final Template queryTemplate = 
engine.getTemplate(SOBJECT_QUERY_RECORDS_VM, UTF_8);
+        try (final Writer writer = new OutputStreamWriter(new 
FileOutputStream(queryRecordsFile),
+            StandardCharsets.UTF_8)) {
+            queryTemplate.merge(context, writer);
+        }
+
+        if (useOptionals) {
+            // write the QueryRecords Optional class
+            final String queryRecordsOptionalFileName = "QueryRecords" + 
description.getName() + "Optional" + JAVA_EXT;
+            final File queryRecordsOptionalFile = new File(pkgDir, 
queryRecordsOptionalFileName);
+            final Template queryRecordsOptionalTemplate = 
engine.getTemplate(SOBJECT_QUERY_RECORDS_OPTIONAL_VM, UTF_8);
+            try (final Writer writer = new OutputStreamWriter(new 
FileOutputStream(queryRecordsOptionalFile),
+                StandardCharsets.UTF_8)) {
+                queryRecordsOptionalTemplate.merge(context, writer);
+            }
+        }
+    }
+
+    @Override
+    protected void executeWithClient(final RestClient client) throws 
MojoExecutionException {
+        descriptions = new ObjectDescriptions(client, getResponseTimeout(), 
includes, includePattern, excludes,
+            excludePattern, getLog());
+
+        engine = createVelocityEngine();
+
+        // make sure we can load both templates
+        if (!engine.resourceExists(SOBJECT_POJO_VM) || 
!engine.resourceExists(SOBJECT_QUERY_RECORDS_VM)
+            || !engine.resourceExists(SOBJECT_POJO_OPTIONAL_VM)
+            || !engine.resourceExists(SOBJECT_QUERY_RECORDS_OPTIONAL_VM)) {
+            throw new MojoExecutionException("Velocity templates not found");
+        }
+
+        // create package directory
+        // validate package name
+        if (!packageName.matches(PACKAGE_NAME_PATTERN)) {
+            throw new MojoExecutionException("Invalid package name " + 
packageName);
+        }
+        if (outputDirectory.getAbsolutePath().contains("$")) {
+            outputDirectory = new File("generated-sources/camel-salesforce");
+        }
+        final File pkgDir = new File(outputDirectory, 
packageName.trim().replace('.', File.separatorChar));
+        if (!pkgDir.exists()) {
+            if (!pkgDir.mkdirs()) {
+                throw new MojoExecutionException("Unable to create " + pkgDir);
+            }
+        }
+
+        getLog().info("Generating Java Classes...");
+        // generate POJOs for every object description
+        final GeneratorUtility utility = new GeneratorUtility();
+        // should we provide a flag to control timestamp generation?
+        final String generatedDate = new Date().toString();
+        for (final SObjectDescription description : descriptions.fetched()) {
+            if (Defaults.IGNORED_OBJECTS.contains(description.getName())) {
+                continue;
+            }
+            try {
+                processDescription(pkgDir, description, utility, 
generatedDate);
+            } catch (final IOException e) {
+                throw new MojoExecutionException("Unable to generate source 
files for: " + description.getName(), e);
+            }
+        }
+
+        getLog().info(String.format("Successfully generated %s Java Classes", 
descriptions.count() * 2));
+    }
+
+    static VelocityEngine createVelocityEngine() {
+        // initialize velocity to load resources from class loader and use 
Log4J
+        final Properties velocityProperties = new Properties();
+        velocityProperties.setProperty(RuntimeConstants.RESOURCE_LOADER, 
"cloader");
+        velocityProperties.setProperty("cloader.resource.loader.class", 
ClasspathResourceLoader.class.getName());
+        velocityProperties.setProperty(RuntimeConstants.RUNTIME_LOG_NAME, 
LOG.getName());
+        final VelocityEngine engine = new VelocityEngine(velocityProperties);
+
+        return engine;
+    }
+
+    private static Set<String> defineBaseFields() {
+        final Set<String> baseFields = new HashSet<>();
+        for (final Field field : 
AbstractSObjectBase.class.getDeclaredFields()) {
+            baseFields.add(field.getName());
+        }
+
+        return baseFields;
+    }
+
+    private static Map<String, String> defineLookupMap() {
+        // create a type map
+        // using JAXB mapping, for the most part
+        // mapping for tns:ID SOAPtype
+        final String[][] typeMap = new String[][] {//
+            {"ID", "String"}, //
+            {"string", "String"}, //
+            {"integer", "java.math.BigInteger"}, //
+            {"int", "Integer"}, //
+            {"long", "Long"}, //
+            {"short", "Short"}, //
+            {"decimal", "java.math.BigDecimal"}, //
+            {"float", "Float"}, //
+            {"double", "Double"}, //
+            {"boolean", "Boolean"}, //
+            {"byte", "Byte"}, //
+            {"dateTime", "java.time.ZonedDateTime"}, //
+            // the blob base64Binary type is mapped to String URL for 
retrieving
+            // the blob
+            {"base64Binary", "String"}, //
+            {"unsignedInt", "Long"}, //
+            {"unsignedShort", "Integer"}, //
+            {"unsignedByte", "Short"}, //
+            {"time", "java.time.ZonedDateTime"}, //
+            {"date", "java.time.ZonedDateTime"}, //
+            {"g", "java.time.ZonedDateTime"}, //
+            // Salesforce maps any types like string, picklist, reference, etc.
+            // to string
+            {"anyType", "String"}, //
+            {"address", 
"org.apache.camel.component.salesforce.api.dto.Address"}, //
+            {"location", 
"org.apache.camel.component.salesforce.api.dto.GeoLocation"}, //
+            {"RelationshipReferenceTo", "String"}//
+        };
+
+        final Map<String, String> lookupMap = new HashMap<>();
+        for (final String[] entry : typeMap) {
+            lookupMap.put(entry[0], entry[1]);
+        }
+
+        return lookupMap;
+    }
+
+}
diff --git 
a/components/camel-salesforce/camel-salesforce-maven-plugin/src/main/java/org/apache/camel/maven/ObjectDescriptions.java
 
b/components/camel-salesforce/camel-salesforce-maven-plugin/src/main/java/org/apache/camel/maven/ObjectDescriptions.java
new file mode 100644
index 0000000..5b67026
--- /dev/null
+++ 
b/components/camel-salesforce/camel-salesforce-maven-plugin/src/main/java/org/apache/camel/maven/ObjectDescriptions.java
@@ -0,0 +1,202 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.camel.maven;
+
+import java.util.Collections;
+import java.util.HashSet;
+import java.util.Map;
+import java.util.Set;
+import java.util.TreeSet;
+import java.util.concurrent.ConcurrentHashMap;
+import java.util.concurrent.TimeUnit;
+import java.util.regex.Pattern;
+
+import com.fasterxml.jackson.databind.ObjectMapper;
+
+import org.apache.camel.component.salesforce.api.SalesforceException;
+import org.apache.camel.component.salesforce.api.dto.GlobalObjects;
+import org.apache.camel.component.salesforce.api.dto.SObject;
+import org.apache.camel.component.salesforce.api.dto.SObjectDescription;
+import org.apache.camel.component.salesforce.api.utils.JsonUtils;
+import org.apache.camel.component.salesforce.internal.client.RestClient;
+import 
org.apache.camel.component.salesforce.internal.client.SyncResponseCallback;
+import org.apache.camel.util.ObjectHelper;
+import org.apache.maven.plugin.MojoExecutionException;
+import org.apache.maven.plugin.logging.Log;
+
+final class ObjectDescriptions {
+
+    private final RestClient client;
+
+    private final Map<String, SObjectDescription> descriptions = new 
ConcurrentHashMap<>();
+
+    private final long responseTimeout;
+
+    ObjectDescriptions(final RestClient client, final long responseTimeout, 
final String[] includes,
+        final String includePattern, final String[] excludes, final String 
excludePattern, final Log log)
+        throws MojoExecutionException {
+        this.client = client;
+        this.responseTimeout = responseTimeout;
+
+        fetchSpecifiedDescriptions(includes, includePattern, excludes, 
excludePattern, log);
+    }
+
+    int count() {
+        return descriptions.size();
+    }
+
+    SObjectDescription descriptionOf(final String name) {
+        return descriptions.computeIfAbsent(name, this::fetchDescriptionOf);
+    }
+
+    Iterable<SObjectDescription> fetched() {
+        return descriptions.values();
+    }
+
+    private SObjectDescription fetchDescriptionOf(final String name) {
+        try {
+            final ObjectMapper mapper = JsonUtils.createObjectMapper();
+            final SyncResponseCallback callback = new SyncResponseCallback();
+
+            client.getDescription(name, Collections.emptyMap(), callback);
+            if (!callback.await(responseTimeout, TimeUnit.MILLISECONDS)) {
+                throw new MojoExecutionException("Timeout waiting for 
getDescription for sObject " + name);
+            }
+            final SalesforceException ex = callback.getException();
+            if (ex != null) {
+                throw ex;
+            }
+            final SObjectDescription description = 
mapper.readValue(callback.getResponse(), SObjectDescription.class);
+
+            // remove some of the unused used metadata
+            // properties in order to minimize the code size
+            // for CAMEL-11310
+            return description.prune();
+        } catch (final Exception e) {
+            throw new IllegalStateException("Error getting SObject description 
for '" + name + "': " + e.getMessage(),
+                e);
+        }
+    }
+
+    private void fetchSpecifiedDescriptions(final String[] includes, final 
String includePattern,
+        final String[] excludes, final String excludePattern, final Log log) 
throws MojoExecutionException {
+        // use Jackson json
+        final ObjectMapper mapper = JsonUtils.createObjectMapper();
+
+        // call getGlobalObjects to get all SObjects
+        final Set<String> objectNames = new TreeSet<>();
+        final SyncResponseCallback callback = new SyncResponseCallback();
+        try {
+            log.info("Getting Salesforce Objects...");
+            client.getGlobalObjects(Collections.emptyMap(), callback);
+            if (!callback.await(responseTimeout, TimeUnit.MILLISECONDS)) {
+                throw new MojoExecutionException("Timeout waiting for 
getGlobalObjects!");
+            }
+            final SalesforceException ex = callback.getException();
+            if (ex != null) {
+                throw ex;
+            }
+            final GlobalObjects globalObjects = 
mapper.readValue(callback.getResponse(), GlobalObjects.class);
+
+            // create a list of object names
+            for (final SObject sObject : globalObjects.getSobjects()) {
+                objectNames.add(sObject.getName());
+            }
+        } catch (final Exception e) {
+            throw new MojoExecutionException("Error getting global Objects: " 
+ e.getMessage(), e);
+        }
+
+        // check if we are generating POJOs for all objects or not
+        if (includes != null && includes.length > 0 || excludes != null && 
excludes.length > 0
+            || ObjectHelper.isNotEmpty(includePattern) || 
ObjectHelper.isNotEmpty(excludePattern)) {
+
+            filterObjectNames(objectNames, includes, includePattern, excludes, 
excludePattern, log);
+
+        } else {
+            log.warn(String.format("Generating Java classes for all %s 
Objects, this may take a while...",
+                objectNames.size()));
+        }
+
+        log.info("Retrieving Object descriptions...");
+        for (final String name : objectNames) {
+            descriptionOf(name);
+        }
+    }
+
+    private static void filterObjectNames(final Set<String> objectNames, final 
String[] includes,
+        final String includePattern, final String[] excludes, final String 
excludePattern, final Log log)
+        throws MojoExecutionException {
+        log.info("Looking for matching Object names...");
+        // create a list of accepted names
+        final Set<String> includedNames = new HashSet<>();
+        if (includes != null && includes.length > 0) {
+            for (String name : includes) {
+                name = name.trim();
+                if (name.isEmpty()) {
+                    throw new MojoExecutionException("Invalid empty name in 
includes");
+                }
+                includedNames.add(name);
+            }
+        }
+
+        final Set<String> excludedNames = new HashSet<>();
+        if (excludes != null && excludes.length > 0) {
+            for (String name : excludes) {
+                name = name.trim();
+                if (name.isEmpty()) {
+                    throw new MojoExecutionException("Invalid empty name in 
excludes");
+                }
+                excludedNames.add(name);
+            }
+        }
+
+        // check whether a pattern is in effect
+        Pattern incPattern;
+        if (includePattern != null && !includePattern.trim().isEmpty()) {
+            incPattern = Pattern.compile(includePattern.trim());
+        } else if (includedNames.isEmpty()) {
+            // include everything by default if no include names are set
+            incPattern = Defaults.MATCH_EVERYTHING_PATTERN;
+        } else {
+            // include nothing by default if include names are set
+            incPattern = Defaults.MATCH_NOTHING_PATTERN;
+        }
+
+        // check whether a pattern is in effect
+        Pattern excPattern;
+        if (excludePattern != null && !excludePattern.trim().isEmpty()) {
+            excPattern = Pattern.compile(excludePattern.trim());
+        } else {
+            // exclude nothing by default
+            excPattern = Defaults.MATCH_NOTHING_PATTERN;
+        }
+
+        final Set<String> acceptedNames = new HashSet<>();
+        for (final String name : objectNames) {
+            // name is included, or matches include pattern
+            // and is not excluded and does not match exclude pattern
+            if ((includedNames.contains(name) || 
incPattern.matcher(name).matches()) && !excludedNames.contains(name)
+                && !excPattern.matcher(name).matches()) {
+                acceptedNames.add(name);
+            }
+        }
+        objectNames.clear();
+        objectNames.addAll(acceptedNames);
+
+        log.info(String.format("Found %s matching Objects", 
objectNames.size()));
+    }
+}
diff --git 
a/components/camel-salesforce/camel-salesforce-maven-plugin/src/main/java/org/apache/camel/maven/SchemaMojo.java
 
b/components/camel-salesforce/camel-salesforce-maven-plugin/src/main/java/org/apache/camel/maven/SchemaMojo.java
new file mode 100644
index 0000000..6686889
--- /dev/null
+++ 
b/components/camel-salesforce/camel-salesforce-maven-plugin/src/main/java/org/apache/camel/maven/SchemaMojo.java
@@ -0,0 +1,118 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.camel.maven;
+
+import java.io.File;
+import java.io.IOException;
+import java.nio.file.Files;
+import java.nio.file.Path;
+import java.util.HashSet;
+import java.util.Set;
+
+import com.fasterxml.jackson.databind.ObjectMapper;
+import com.fasterxml.jackson.module.jsonSchema.JsonSchema;
+
+import org.apache.camel.component.salesforce.api.dto.SObjectDescription;
+import org.apache.camel.component.salesforce.api.utils.JsonUtils;
+import org.apache.camel.component.salesforce.internal.client.RestClient;
+import org.apache.maven.plugin.MojoExecutionException;
+import org.apache.maven.plugins.annotations.LifecyclePhase;
+import org.apache.maven.plugins.annotations.Mojo;
+import org.apache.maven.plugins.annotations.Parameter;
+
+@Mojo(name = "schema", requiresProject = false, defaultPhase = 
LifecyclePhase.GENERATE_SOURCES)
+public class SchemaMojo extends AbstractSalesforceMojo {
+
+    /**
+     * Exclude Salesforce SObjects that match pattern.
+     */
+    @Parameter(property = "camelSalesforce.excludePattern")
+    String excludePattern;
+
+    /**
+     * Do NOT generate DTOs for these Salesforce SObjects.
+     */
+    @Parameter
+    String[] excludes;
+
+    /**
+     * Include Salesforce SObjects that match pattern.
+     */
+    @Parameter(property = "camelSalesforce.includePattern")
+    String includePattern;
+
+    /**
+     * Names of Salesforce SObject for which DTOs must be generated.
+     */
+    @Parameter
+    String[] includes;
+
+    /**
+     * Schema ID for JSON Schema for DTOs.
+     */
+    @Parameter(property = "camelSalesforce.jsonSchemaFilename", defaultValue = 
"salesforce-dto-schema.json")
+    String jsonSchemaFilename;
+
+    /**
+     * Schema ID for JSON Schema for DTOs.
+     */
+    @Parameter(property = "camelSalesforce.jsonSchemaId", defaultValue = 
JsonUtils.DEFAULT_ID_PREFIX)
+    String jsonSchemaId;
+
+    /**
+     * Location of generated JSON schema files, defaults to
+     * target/generated-sources/camel-salesforce.
+     */
+    @Parameter(property = "camelSalesforce.outputDirectory",
+        defaultValue = 
"${project.build.directory}/generated-sources/camel-salesforce")
+    File outputDirectory;
+
+    @Override
+    protected void executeWithClient(final RestClient client) throws 
MojoExecutionException {
+        getLog().info("Generating JSON Schema...");
+
+        final ObjectDescriptions descriptions = new ObjectDescriptions(client, 
getResponseTimeout(), includes,
+            includePattern, excludes, excludePattern, getLog());
+
+        // generate JSON schema for every object description
+        final ObjectMapper schemaObjectMapper = 
JsonUtils.createSchemaObjectMapper();
+        final Set<JsonSchema> allSchemas = new HashSet<>();
+        for (final SObjectDescription description : descriptions.fetched()) {
+            if (Defaults.IGNORED_OBJECTS.contains(description.getName())) {
+                continue;
+            }
+            try {
+                
allSchemas.addAll(JsonUtils.getSObjectJsonSchema(schemaObjectMapper, 
description, jsonSchemaId, true));
+            } catch (final IOException e) {
+                throw new MojoExecutionException("Unable to generate JSON 
Schema types for: " + description.getName(),
+                    e);
+            }
+        }
+
+        final Path schemaFilePath = 
outputDirectory.toPath().resolve(jsonSchemaFilename);
+        try {
+            Files.write(schemaFilePath,
+                JsonUtils.getJsonSchemaString(schemaObjectMapper, allSchemas, 
jsonSchemaId).getBytes("UTF-8"));
+        } catch (final IOException e) {
+            throw new MojoExecutionException("Unable to generate JSON Schema 
source file: " + schemaFilePath, e);
+        }
+
+        getLog().info(
+            String.format("Successfully generated %s JSON Types in file %s", 
descriptions.count() * 2, schemaFilePath));
+    }
+
+}
diff --git 
a/components/camel-salesforce/camel-salesforce-maven-plugin/src/test/java/org/apache/camel/maven/AbstractSalesforceMojoIntegrationTest.java
 
b/components/camel-salesforce/camel-salesforce-maven-plugin/src/test/java/org/apache/camel/maven/AbstractSalesforceMojoIntegrationTest.java
new file mode 100644
index 0000000..59239cc
--- /dev/null
+++ 
b/components/camel-salesforce/camel-salesforce-maven-plugin/src/test/java/org/apache/camel/maven/AbstractSalesforceMojoIntegrationTest.java
@@ -0,0 +1,80 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.camel.maven;
+
+import java.io.FileInputStream;
+import java.io.FileNotFoundException;
+import java.io.IOException;
+import java.io.InputStream;
+import java.util.Collections;
+import java.util.List;
+import java.util.Map;
+import java.util.Properties;
+
+import org.apache.camel.component.salesforce.SalesforceEndpointConfig;
+import org.apache.camel.component.salesforce.internal.client.RestClient;
+import org.apache.maven.plugin.MojoExecutionException;
+import org.apache.maven.plugin.MojoFailureException;
+import org.junit.Test;
+
+import static org.assertj.core.api.Assertions.assertThat;
+
+public class AbstractSalesforceMojoIntegrationTest {
+
+    private static final Map<String, List<String>> NO_HEADERS = 
Collections.emptyMap();
+
+    private static final String TEST_LOGIN_PROPERTIES = 
"../test-salesforce-login.properties";
+
+    @Test
+    public void shouldLoginAndProvideRestClient() throws IOException, 
MojoExecutionException, MojoFailureException {
+        final AbstractSalesforceMojo mojo = new AbstractSalesforceMojo() {
+            @Override
+            protected void executeWithClient(final RestClient client) throws 
MojoExecutionException {
+                assertThat(client).isNotNull();
+
+                client.getGlobalObjects(NO_HEADERS, (response, headers, 
exception) -> {
+                    assertThat(exception).isNull();
+                });
+            }
+        };
+
+        setup(mojo);
+
+        mojo.execute();
+    }
+
+    static void setup(final AbstractSalesforceMojo mojo) throws IOException {
+        // load test-salesforce-login properties
+        try (final InputStream stream = new 
FileInputStream(TEST_LOGIN_PROPERTIES)) {
+            final Properties properties = new Properties();
+            properties.load(stream);
+            mojo.clientId = properties.getProperty("salesforce.client.id");
+            mojo.clientSecret = 
properties.getProperty("salesforce.client.secret");
+            mojo.userName = properties.getProperty("salesforce.username");
+            mojo.password = properties.getProperty("salesforce.password");
+            mojo.loginUrl = properties.getProperty("salesforce.login.url");
+            mojo.version = SalesforceEndpointConfig.DEFAULT_VERSION;
+        } catch (final FileNotFoundException e) {
+            final FileNotFoundException exception = new 
FileNotFoundException("Create a properties file named "
+                + TEST_LOGIN_PROPERTIES + " with clientId, clientSecret, 
userName, password"
+                + " for a Salesforce account with Merchandise and Invoice 
objects from Salesforce Guides.");
+            exception.initCause(e);
+
+            throw exception;
+        }
+    }
+}
diff --git 
a/components/camel-salesforce/camel-salesforce-maven-plugin/src/test/java/org/apache/camel/maven/CamelSalesforceMojoIntegrationTest.java
 
b/components/camel-salesforce/camel-salesforce-maven-plugin/src/test/java/org/apache/camel/maven/CamelSalesforceMojoIntegrationTest.java
index 4d47e2f..b951449 100644
--- 
a/components/camel-salesforce/camel-salesforce-maven-plugin/src/test/java/org/apache/camel/maven/CamelSalesforceMojoIntegrationTest.java
+++ 
b/components/camel-salesforce/camel-salesforce-maven-plugin/src/test/java/org/apache/camel/maven/CamelSalesforceMojoIntegrationTest.java
@@ -16,114 +16,71 @@
  */
 package org.apache.camel.maven;
 
-import java.io.File;
-import java.io.FileInputStream;
-import java.io.FileNotFoundException;
 import java.io.IOException;
-import java.io.InputStream;
-import java.util.Properties;
+import java.net.MalformedURLException;
+import java.nio.file.Files;
+import java.nio.file.Path;
+import java.util.List;
+import java.util.stream.Collectors;
 
-import com.fasterxml.jackson.databind.ObjectMapper;
-import com.fasterxml.jackson.module.jsonSchema.JsonSchema;
-import com.fasterxml.jackson.module.jsonSchema.types.ObjectSchema;
+import javax.tools.JavaFileObject;
+
+import com.google.testing.compile.Compilation;
+import com.google.testing.compile.Compilation.Status;
+import com.google.testing.compile.Compiler;
+import com.google.testing.compile.JavaFileObjects;
 
 import org.apache.camel.component.salesforce.SalesforceEndpointConfig;
-import org.apache.camel.component.salesforce.SalesforceLoginConfig;
-import org.apache.camel.component.salesforce.api.utils.JsonUtils;
-import org.apache.maven.plugin.logging.SystemStreamLog;
-import org.junit.Assert;
+import org.junit.Rule;
 import org.junit.Test;
+import org.junit.rules.TemporaryFolder;
+
+import static 
org.apache.camel.maven.AbstractSalesforceMojoIntegrationTest.setup;
+import static org.assertj.core.api.Assertions.assertThat;
 
 public class CamelSalesforceMojoIntegrationTest {
 
-    private static final String TEST_LOGIN_PROPERTIES = 
"../test-salesforce-login.properties";
+    @Rule
+    public TemporaryFolder temp = new TemporaryFolder();
 
     @Test
     public void testExecute() throws Exception {
-        CamelSalesforceMojo mojo = createMojo();
+        final GenerateMojo mojo = createMojo();
 
         // generate code
         mojo.execute();
 
-        // validate generated code
-        // check that it was generated
-        Assert.assertTrue("Output directory was not created", 
mojo.outputDirectory.exists());
-
-        // TODO check that the generated code compiles
-    }
-
-    @Test
-    public void testExecuteJsonSchema() throws Exception {
-        CamelSalesforceMojo mojo = createMojo();
-        mojo.jsonSchema = true;
-        mojo.jsonSchemaFilename = "test-schema.json";
-        mojo.jsonSchemaId = JsonUtils.DEFAULT_ID_PREFIX;
+        // validate generated code check that it was generated
+        final Path packagePath = 
temp.getRoot().toPath().resolve("test").resolve("dto");
+        assertThat(packagePath).as("Package directory was not 
created").exists();
 
-        // generate code
-        mojo.execute();
-
-        // validate generated schema
-        File schemaFile = 
mojo.outputDirectory.toPath().resolve("test-schema.json").toFile();
-        Assert.assertTrue("Output file was not created",
-                schemaFile.exists());
-        ObjectMapper objectMapper = JsonUtils.createObjectMapper();
-        JsonSchema jsonSchema = objectMapper.readValue(schemaFile, 
JsonSchema.class);
-        Assert.assertTrue("Expected root JSON schema with oneOf element",
-                jsonSchema.isObjectSchema() && 
!((ObjectSchema)jsonSchema).getOneOf().isEmpty());
+        // test that the generated sources can be compiled
+        final List<JavaFileObject> sources = Files.list(packagePath).map(p -> {
+            try {
+                return JavaFileObjects.forResource(p.toUri().toURL());
+            } catch (final MalformedURLException e) {
+                throw new IllegalArgumentException(e);
+            }
+        }).collect(Collectors.toList());
+        final Compilation compilation = Compiler.javac().compile(sources);
+        assertThat(compilation.status()).isEqualTo(Status.SUCCESS);
     }
 
-    protected CamelSalesforceMojo createMojo() throws IOException {
-        CamelSalesforceMojo mojo = new CamelSalesforceMojo();
-
-        mojo.setLog(new SystemStreamLog());
+    GenerateMojo createMojo() throws IOException {
+        final GenerateMojo mojo = new GenerateMojo();
 
         // set login properties
-        setLoginProperties(mojo);
+        setup(mojo);
 
         // set defaults
-        mojo.version = System.getProperty("apiVersion", 
SalesforceEndpointConfig.DEFAULT_VERSION);
-        mojo.loginUrl = System.getProperty("loginUrl", 
SalesforceLoginConfig.DEFAULT_LOGIN_URL);
-        mojo.outputDirectory = new 
File("target/generated-sources/camel-salesforce");
-        mojo.packageName = "org.apache.camel.salesforce.dto";
+        mojo.version = SalesforceEndpointConfig.DEFAULT_VERSION;
+        mojo.outputDirectory = temp.getRoot();
+        mojo.packageName = "test.dto";
 
         // set code generation properties
         mojo.includePattern = "(.*__c)|(PushTopic)|(Document)|(Account)";
 
-        // remove generated code directory
-        if (mojo.outputDirectory.exists()) {
-            // remove old files
-            for (File file : mojo.outputDirectory.listFiles()) {
-                file.delete();
-            }
-            mojo.outputDirectory.delete();
-        }
         return mojo;
     }
 
-    private void setLoginProperties(CamelSalesforceMojo mojo) throws 
IOException {
-        // load test-salesforce-login properties
-        Properties properties = new Properties();
-        InputStream stream = null;
-        try {
-            stream = new FileInputStream(TEST_LOGIN_PROPERTIES);
-            properties.load(stream);
-            mojo.clientId = properties.getProperty("salesforce.client.id");
-            mojo.clientSecret = 
properties.getProperty("salesforce.client.secret");
-            mojo.userName = properties.getProperty("salesforce.username");
-            mojo.password = properties.getProperty("salesforce.password");
-        } catch (FileNotFoundException e) {
-            throw new FileNotFoundException("Create a properties file named "
-                    + TEST_LOGIN_PROPERTIES + " with clientId, clientSecret, 
userName, password"
-                    + " for a Salesforce account with Merchandise and Invoice 
objects from Salesforce Guides.");
-        } finally {
-            if (stream != null) {
-                try {
-                    stream.close();
-                } catch (IOException ignore) {
-                    // noop
-                }
-            }
-        }
-    }
-
 }
diff --git 
a/components/camel-salesforce/camel-salesforce-maven-plugin/src/test/java/org/apache/camel/maven/CamelSalesforceMojoOutputTest.java
 
b/components/camel-salesforce/camel-salesforce-maven-plugin/src/test/java/org/apache/camel/maven/CamelSalesforceMojoOutputTest.java
index ac300cf..8251684 100644
--- 
a/components/camel-salesforce/camel-salesforce-maven-plugin/src/test/java/org/apache/camel/maven/CamelSalesforceMojoOutputTest.java
+++ 
b/components/camel-salesforce/camel-salesforce-maven-plugin/src/test/java/org/apache/camel/maven/CamelSalesforceMojoOutputTest.java
@@ -29,7 +29,6 @@ import 
org.apache.camel.component.salesforce.api.utils.JsonUtils;
 import org.apache.camel.test.junit4.TestSupport;
 import org.apache.commons.io.FileUtils;
 import org.apache.commons.io.IOUtils;
-import org.apache.maven.plugin.testing.SilentLog;
 import org.junit.Assert;
 import org.junit.Before;
 import org.junit.Rule;
@@ -42,43 +41,29 @@ import org.junit.runners.Parameterized.Parameters;
 
 @RunWith(Parameterized.class)
 public class CamelSalesforceMojoOutputTest {
-    private static final String TEST_CASE_FILE = "case.json";
-    private static final String TEST_CALCULATED_FORMULA_FILE = 
"complex_calculated_formula.json";
     private static final String FIXED_DATE = "Thu Mar 09 16:15:49 ART 2017";
+    private static final String TEST_CALCULATED_FORMULA_FILE = 
"complex_calculated_formula.json";
+    private static final String TEST_CASE_FILE = "case.json";
 
-    @Rule
-    public TemporaryFolder temp = new TemporaryFolder();
+    @Parameter(1)
+    public SObjectDescription description;
 
     @Parameter(0)
     public String json;
 
-    @Parameter(1)
-    public SObjectDescription description;
-
     @Parameter(2)
     public String source;
 
-    private CamelSalesforceMojo mojo;
-    private CamelSalesforceMojo.GeneratorUtility utility = new 
CamelSalesforceMojo.GeneratorUtility(false, new SilentLog());
-
-    @Parameters(name = "json = {0}, source = {2}")
-    public static Iterable<Object[]> parameters() throws IOException {
-        return Arrays.asList(pair(TEST_CASE_FILE, "Case.java"),
-            pair(TEST_CASE_FILE, "Case_PickListAccentMarkEnum.java"),
-            pair(TEST_CASE_FILE, "Case_PickListQuotationMarkEnum.java"),
-            pair(TEST_CASE_FILE, "Case_PickListSlashEnum.java"), 
pair(TEST_CASE_FILE, "QueryRecordsCase.java"),
-            pair(TEST_CALCULATED_FORMULA_FILE, 
"ComplexCalculatedFormula.java"),
-            pair(TEST_CALCULATED_FORMULA_FILE, 
"QueryRecordsComplexCalculatedFormula.java"));
-    }
+    @Rule
+    public TemporaryFolder temp = new TemporaryFolder();
 
-    static Object[] pair(String json, String source) throws IOException {
-        return new Object[] {json, createSObjectDescription(json), source};
-    }
+    private GenerateMojo mojo;
+    private final GenerateMojo.GeneratorUtility utility = new 
GenerateMojo().new GeneratorUtility();
 
     @Before
     public void setUp() throws Exception {
-        mojo = new CamelSalesforceMojo();
-        mojo.engine = CamelSalesforceMojo.createVelocityEngine();
+        mojo = new GenerateMojo();
+        mojo.engine = GenerateMojo.createVelocityEngine();
     }
 
     @Test
@@ -86,15 +71,16 @@ public class CamelSalesforceMojoOutputTest {
         final File pkgDir = temp.newFolder();
 
         mojo.processDescription(pkgDir, description, utility, FIXED_DATE);
-        
-        File generatedFile = new File(pkgDir, source);
-        String generatedContent = FileUtils.readFileToString(generatedFile, 
StandardCharsets.UTF_8);
 
-        if (TestSupport.getJavaMajorVersion() >= 9 && 
(source.equals("Case.java") || source.equals("ComplexCalculatedFormula.java"))) 
{
-            //Content is the same, the ordering is a bit different.
+        final File generatedFile = new File(pkgDir, source);
+        final String generatedContent = 
FileUtils.readFileToString(generatedFile, StandardCharsets.UTF_8);
+
+        if (TestSupport.getJavaMajorVersion() >= 9
+            && (source.equals("Case.java") || 
source.equals("ComplexCalculatedFormula.java"))) {
+            // Content is the same, the ordering is a bit different.
             source += "-Java9";
         }
-        String expectedContent = IOUtils
+        final String expectedContent = IOUtils
             
.toString(CamelSalesforceMojoOutputTest.class.getResource("/generated/" + 
source), StandardCharsets.UTF_8);
 
         Assert.assertEquals(
@@ -102,11 +88,25 @@ public class CamelSalesforceMojoOutputTest {
             generatedContent, expectedContent);
     }
 
-    static SObjectDescription createSObjectDescription(String name) throws 
IOException {
+    @Parameters(name = "json = {0}, source = {2}")
+    public static Iterable<Object[]> parameters() throws IOException {
+        return Arrays.asList(pair(TEST_CASE_FILE, "Case.java"),
+            pair(TEST_CASE_FILE, "Case_PickListAccentMarkEnum.java"),
+            pair(TEST_CASE_FILE, "Case_PickListQuotationMarkEnum.java"),
+            pair(TEST_CASE_FILE, "Case_PickListSlashEnum.java"), 
pair(TEST_CASE_FILE, "QueryRecordsCase.java"),
+            pair(TEST_CALCULATED_FORMULA_FILE, 
"ComplexCalculatedFormula.java"),
+            pair(TEST_CALCULATED_FORMULA_FILE, 
"QueryRecordsComplexCalculatedFormula.java"));
+    }
+
+    static SObjectDescription createSObjectDescription(final String name) 
throws IOException {
         try (InputStream inputStream = 
CamelSalesforceMojoOutputTest.class.getResourceAsStream("/" + name)) {
-            ObjectMapper mapper = JsonUtils.createObjectMapper();
+            final ObjectMapper mapper = JsonUtils.createObjectMapper();
 
             return mapper.readValue(inputStream, SObjectDescription.class);
         }
     }
+
+    static Object[] pair(final String json, final String source) throws 
IOException {
+        return new Object[] {json, createSObjectDescription(json), source};
+    }
 }
diff --git 
a/components/camel-salesforce/camel-salesforce-maven-plugin/src/test/java/org/apache/camel/maven/HttpProxyMojoIntegrationTest.java
 
b/components/camel-salesforce/camel-salesforce-maven-plugin/src/test/java/org/apache/camel/maven/HttpProxyMojoIntegrationTest.java
index ba6a451..303d826 100644
--- 
a/components/camel-salesforce/camel-salesforce-maven-plugin/src/test/java/org/apache/camel/maven/HttpProxyMojoIntegrationTest.java
+++ 
b/components/camel-salesforce/camel-salesforce-maven-plugin/src/test/java/org/apache/camel/maven/HttpProxyMojoIntegrationTest.java
@@ -18,108 +18,67 @@ package org.apache.camel.maven;
 
 import java.io.IOException;
 import java.util.HashMap;
-import javax.servlet.http.HttpServletRequest;
-import javax.servlet.http.HttpServletResponse;
-
-import org.apache.camel.util.jsse.SSLContextParameters;
-import org.eclipse.jetty.proxy.ConnectHandler;
-import org.eclipse.jetty.server.Server;
-import org.eclipse.jetty.server.ServerConnector;
-import org.eclipse.jetty.util.B64Code;
-import org.eclipse.jetty.util.StringUtil;
-import org.junit.AfterClass;
-import org.junit.BeforeClass;
-import org.junit.Ignore;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-
-import static org.eclipse.jetty.http.HttpHeader.PROXY_AUTHENTICATE;
-import static org.eclipse.jetty.http.HttpHeader.PROXY_AUTHORIZATION;
-
-@Ignore("Bug in Jetty9 causes java.lang.IllegalArgumentException: Invalid 
protocol login.salesforce.com")
-public class HttpProxyMojoIntegrationTest extends 
CamelSalesforceMojoIntegrationTest {
 
-    private static final Logger LOG = 
LoggerFactory.getLogger(HttpProxyMojoIntegrationTest.class);
+import org.apache.camel.test.AvailablePortFinder;
+import org.junit.After;
+import org.junit.Before;
+import org.littleshoot.proxy.HttpProxyServer;
+import org.littleshoot.proxy.ProxyAuthenticator;
+import org.littleshoot.proxy.impl.DefaultHttpProxyServer;
+
+public class HttpProxyMojoIntegrationTest extends 
CamelSalesforceMojoIntegrationTest {
 
-    private static final String HTTP_PROXY_HOST = "localhost";
-    private static final String HTTP_PROXY_USER_NAME = "camel-user";
     private static final String HTTP_PROXY_PASSWORD = "camel-user-password";
+
     private static final String HTTP_PROXY_REALM = "proxy-realm";
 
-    private static Server server;
-    private static int httpProxyPort;
-
-    @BeforeClass
-    public static void setupServer() throws Exception {
-        // start a local HTTP proxy using Jetty server
-        server = new Server();
-
-/*
-        final SSLContextParameters contextParameters = new 
SSLContextParameters();
-        final SslContextFactory sslContextFactory = new SslContextFactory();
-        sslContextFactory.setSslContext(contextParameters.createSSLContext());
-        ServerConnector connector = new ServerConnector(server, 
sslContextFactory);
-*/
-        ServerConnector connector = new ServerConnector(server);
-
-        connector.setHost(HTTP_PROXY_HOST);
-        server.addConnector(connector);
-
-        final String authenticationString = "Basic "
-            + B64Code.encode(HTTP_PROXY_USER_NAME + ":" + HTTP_PROXY_PASSWORD, 
StringUtil.__ISO_8859_1);
-
-        ConnectHandler connectHandler = new ConnectHandler() {
-            @Override
-            protected boolean handleAuthentication(HttpServletRequest request, 
HttpServletResponse response, String address) {
-                // validate proxy-authentication header
-                final String header = 
request.getHeader(PROXY_AUTHORIZATION.toString());
-                if (!authenticationString.equals(header)) {
-                    LOG.warn("Missing header " + PROXY_AUTHORIZATION);
-                    // ask for authentication header
-                    response.setHeader(PROXY_AUTHENTICATE.toString(), 
String.format("Basic realm=\"%s\"", HTTP_PROXY_REALM));
-                    return false;
+    private static final String HTTP_PROXY_USER_NAME = "camel-user";
+
+    private int httpProxyPort;
+
+    private HttpProxyServer proxy;
+
+    @Before
+    public void startProxy() {
+        httpProxyPort = AvailablePortFinder.getNextAvailable();
+
+        proxy = DefaultHttpProxyServer.bootstrap().withPort(httpProxyPort)
+            .withProxyAuthenticator(new ProxyAuthenticator() {
+                @Override
+                public String getRealm() {
+                    return HTTP_PROXY_REALM;
                 }
-                LOG.info("Request contains required header " + 
PROXY_AUTHORIZATION);
-                return true;
-            }
-        };
-        server.setHandler(connectHandler);
 
-        LOG.info("Starting proxy server...");
-        server.start();
+                @Override
+                public boolean authenticate(String userName, String password) {
+                    return HTTP_PROXY_USER_NAME.equals(userName) && 
HTTP_PROXY_PASSWORD.equals(password);
+                }
+            }).start();
+    }
 
-        httpProxyPort = connector.getLocalPort();
-        LOG.info("Started proxy server on port {}", httpProxyPort);
+    @After
+    public void stopProxy() {
+        proxy.stop();
     }
 
     @Override
-    protected CamelSalesforceMojo createMojo() throws IOException {
-        final CamelSalesforceMojo mojo = super.createMojo();
-
-        // SSL context parameters
-        mojo.sslContextParameters = new SSLContextParameters();
+    protected GenerateMojo createMojo() throws IOException {
+        final GenerateMojo mojo = super.createMojo();
 
         // HTTP proxy properties
-        mojo.httpProxyHost = HTTP_PROXY_HOST;
+        mojo.httpProxyHost = "localhost";
         mojo.httpProxyPort = httpProxyPort;
         mojo.httpProxyUsername = HTTP_PROXY_USER_NAME;
         mojo.httpProxyPassword = HTTP_PROXY_PASSWORD;
         mojo.httpProxyRealm = HTTP_PROXY_REALM;
-        mojo.httpProxyAuthUri = String.format("https://%s:%s";, 
HTTP_PROXY_HOST, httpProxyPort);
+        mojo.isHttpProxySecure = false;
+        mojo.httpProxyAuthUri = String.format("http://localhost:%s";, 
httpProxyPort);
 
         // HTTP client properties
-        mojo.httpClientProperties = new HashMap<String, Object>();
+        mojo.httpClientProperties = new HashMap<>();
         mojo.httpClientProperties.put("timeout", "60000");
         mojo.httpClientProperties.put("removeIdleDestinations", "true");
 
         return mojo;
     }
-
-    @AfterClass
-    public static void tearDownAfterClass() throws Exception {
-        // stop the proxy server after component
-        LOG.info("Stopping proxy server...");
-        server.stop();
-        LOG.info("Stopped proxy server");
-    }
 }
diff --git 
a/components/camel-salesforce/camel-salesforce-maven-plugin/src/test/java/org/apache/camel/maven/SchemaMojoIntegrationTest.java
 
b/components/camel-salesforce/camel-salesforce-maven-plugin/src/test/java/org/apache/camel/maven/SchemaMojoIntegrationTest.java
new file mode 100644
index 0000000..c0e4480
--- /dev/null
+++ 
b/components/camel-salesforce/camel-salesforce-maven-plugin/src/test/java/org/apache/camel/maven/SchemaMojoIntegrationTest.java
@@ -0,0 +1,60 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.camel.maven;
+
+import java.io.File;
+
+import com.fasterxml.jackson.databind.ObjectMapper;
+import com.fasterxml.jackson.module.jsonSchema.JsonSchema;
+import com.fasterxml.jackson.module.jsonSchema.types.ObjectSchema;
+
+import org.apache.camel.component.salesforce.api.utils.JsonUtils;
+import org.junit.Assert;
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.rules.TemporaryFolder;
+
+import static 
org.apache.camel.maven.AbstractSalesforceMojoIntegrationTest.setup;
+
+public class SchemaMojoIntegrationTest {
+
+    @Rule
+    public TemporaryFolder temp = new TemporaryFolder();
+
+    @Test
+    public void testExecuteJsonSchema() throws Exception {
+        final SchemaMojo mojo = new SchemaMojo();
+        setup(mojo);
+
+        mojo.includes = new String[] {"Account"};
+        mojo.outputDirectory = temp.getRoot();
+        mojo.jsonSchemaFilename = "test-schema.json";
+        mojo.jsonSchemaId = JsonUtils.DEFAULT_ID_PREFIX;
+
+        // generate code
+        mojo.execute();
+
+        // validate generated schema
+        final File schemaFile = 
mojo.outputDirectory.toPath().resolve("test-schema.json").toFile();
+        Assert.assertTrue("Output file was not created", schemaFile.exists());
+        final ObjectMapper objectMapper = JsonUtils.createObjectMapper();
+        final JsonSchema jsonSchema = objectMapper.readValue(schemaFile, 
JsonSchema.class);
+        Assert.assertTrue("Expected root JSON schema with oneOf element",
+            jsonSchema.isObjectSchema() && !((ObjectSchema) 
jsonSchema).getOneOf().isEmpty());
+    }
+
+}

-- 
To stop receiving notification emails like this one, please contact
['"[email protected]" <[email protected]>'].

Reply via email to