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]>'].