You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@camel.apache.org by dh...@apache.org on 2017/08/03 08:35:50 UTC
[2/8] camel git commit: CAMEL-10744: Added utility APIs in Salesforce
JsonUtils to generate JSON schema from SObjectDescription,
added required modules to Karaf camel-salesforce feature
CAMEL-10744: Added utility APIs in Salesforce JsonUtils to generate JSON schema from SObjectDescription, added required modules to Karaf camel-salesforce feature
Project: http://git-wip-us.apache.org/repos/asf/camel/repo
Commit: http://git-wip-us.apache.org/repos/asf/camel/commit/e0fe1df7
Tree: http://git-wip-us.apache.org/repos/asf/camel/tree/e0fe1df7
Diff: http://git-wip-us.apache.org/repos/asf/camel/diff/e0fe1df7
Branch: refs/heads/camel-2.19.x
Commit: e0fe1df75a383ebea78a40125d0d55654ce4f31e
Parents: 6f9ed73
Author: Dhiraj Bokde <dh...@yahoo.com>
Authored: Thu Aug 3 00:12:19 2017 -0700
Committer: Dhiraj Bokde <dh...@yahoo.com>
Committed: Thu Aug 3 01:13:01 2017 -0700
----------------------------------------------------------------------
.../camel-salesforce-component/pom.xml | 15 ++
.../salesforce/api/utils/JsonUtils.java | 225 +++++++++++++++++++
.../salesforce/api/utils/JsonUtilsTest.java | 56 +++++
parent/pom.xml | 6 +
.../features/src/main/resources/features.xml | 2 +
5 files changed, 304 insertions(+)
----------------------------------------------------------------------
http://git-wip-us.apache.org/repos/asf/camel/blob/e0fe1df7/components/camel-salesforce/camel-salesforce-component/pom.xml
----------------------------------------------------------------------
diff --git a/components/camel-salesforce/camel-salesforce-component/pom.xml b/components/camel-salesforce/camel-salesforce-component/pom.xml
index b3b0214..f258da5 100644
--- a/components/camel-salesforce/camel-salesforce-component/pom.xml
+++ b/components/camel-salesforce/camel-salesforce-component/pom.xml
@@ -88,6 +88,15 @@
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-databind</artifactId>
</dependency>
+ <!-- json schema -->
+ <dependency>
+ <groupId>com.fasterxml.jackson.jaxrs</groupId>
+ <artifactId>jackson-jaxrs-json-provider</artifactId>
+ </dependency>
+ <dependency>
+ <groupId>com.fasterxml.jackson.module</groupId>
+ <artifactId>jackson-module-jsonSchema</artifactId>
+ </dependency>
<dependency>
<groupId>com.thoughtworks.xstream</groupId>
<artifactId>xstream</artifactId>
@@ -169,6 +178,12 @@
<version>2.2</version>
<scope>test</scope>
</dependency>
+ <dependency>
+ <groupId>com.squareup.okhttp3</groupId>
+ <artifactId>mockwebserver</artifactId>
+ <version>${squareup-okhttp3-version}</version>
+ <scope>test</scope>
+ </dependency>
</dependencies>
<build>
http://git-wip-us.apache.org/repos/asf/camel/blob/e0fe1df7/components/camel-salesforce/camel-salesforce-component/src/main/java/org/apache/camel/component/salesforce/api/utils/JsonUtils.java
----------------------------------------------------------------------
diff --git a/components/camel-salesforce/camel-salesforce-component/src/main/java/org/apache/camel/component/salesforce/api/utils/JsonUtils.java b/components/camel-salesforce/camel-salesforce-component/src/main/java/org/apache/camel/component/salesforce/api/utils/JsonUtils.java
index 2c3a04f..959e00b 100644
--- a/components/camel-salesforce/camel-salesforce-component/src/main/java/org/apache/camel/component/salesforce/api/utils/JsonUtils.java
+++ b/components/camel-salesforce/camel-salesforce-component/src/main/java/org/apache/camel/component/salesforce/api/utils/JsonUtils.java
@@ -16,13 +16,50 @@
*/
package org.apache.camel.component.salesforce.api.utils;
+import java.lang.reflect.Modifier;
+import java.util.Collections;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Set;
+import java.util.stream.Collectors;
+
+import static java.util.stream.Collectors.joining;
+
+import com.fasterxml.jackson.core.JsonProcessingException;
+import com.fasterxml.jackson.databind.JsonMappingException;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.SerializationFeature;
+import com.fasterxml.jackson.databind.jsonFormatVisitors.JsonValueFormat;
+import com.fasterxml.jackson.module.jsonSchema.JsonSchema;
+import com.fasterxml.jackson.module.jsonSchema.JsonSchemaGenerator;
+import com.fasterxml.jackson.module.jsonSchema.types.ArraySchema;
+import com.fasterxml.jackson.module.jsonSchema.types.BooleanSchema;
+import com.fasterxml.jackson.module.jsonSchema.types.IntegerSchema;
+import com.fasterxml.jackson.module.jsonSchema.types.NullSchema;
+import com.fasterxml.jackson.module.jsonSchema.types.NumberSchema;
+import com.fasterxml.jackson.module.jsonSchema.types.ObjectSchema;
+import com.fasterxml.jackson.module.jsonSchema.types.SimpleTypeSchema;
+import com.fasterxml.jackson.module.jsonSchema.types.StringSchema;
+
+import org.apache.camel.component.salesforce.api.dto.AbstractDTOBase;
+import org.apache.camel.component.salesforce.api.dto.AbstractQueryRecordsBase;
+import org.apache.camel.component.salesforce.api.dto.Address;
+import org.apache.camel.component.salesforce.api.dto.GeoLocation;
+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.impl.DefaultPackageScanClassResolver;
/**
* Factory class for creating {@linkplain com.fasterxml.jackson.databind.ObjectMapper}
*/
public abstract class JsonUtils {
+
+ public static final String SCHEMA4 = "http://json-schema.org/draft-04/schema#";
+ public static final String DEFAULT_ID_PREFIX = "urn:jsonschema:org:apache:camel:component:salesforce:dto";
+
+ private static final String API_DTO_ID = "org:urn:jsonschema:org:apache:camel:component:salesforce:api:dto";
+
public static ObjectMapper createObjectMapper() {
// enable date time support including Java 1.8 ZonedDateTime
ObjectMapper objectMapper = new ObjectMapper();
@@ -31,4 +68,192 @@ public abstract class JsonUtils {
return objectMapper;
}
+ public static String getBasicApiJsonSchema() throws JsonProcessingException {
+ ObjectMapper mapper = createSchemaObjectMapper();
+ JsonSchemaGenerator schemaGen = new JsonSchemaGenerator(mapper);
+
+ DefaultPackageScanClassResolver packageScanClassResolver = new DefaultPackageScanClassResolver();
+
+ Set<Class<?>> schemaClasses = new HashSet<>();
+
+ // get non-abstract extensions of AbstractDTOBase
+ schemaClasses.addAll(packageScanClassResolver.findByFilter(
+ type -> !Modifier.isAbstract(type.getModifiers())
+ && AbstractDTOBase.class.isAssignableFrom(type),
+ "org.apache.camel.component.salesforce.api.dto"));
+
+ // get non-abstract extensions of AbstractDTOBase
+ schemaClasses.addAll(packageScanClassResolver.findByFilter(
+ type -> !Modifier.isAbstract(type.getModifiers())
+ && AbstractDTOBase.class.isAssignableFrom(type),
+ "org.apache.camel.component.salesforce.api.dto"));
+
+ Set<Object> allSchemas = new HashSet<>();
+ for (Class<?> aClass : schemaClasses) {
+ JsonSchema jsonSchema = schemaGen.generateSchema(aClass);
+ allSchemas.add(jsonSchema);
+ }
+
+ return getJsonSchemaString(mapper, allSchemas, API_DTO_ID);
+ }
+
+ public static String getJsonSchemaString(ObjectMapper mapper, Set<Object> allSchemas, String id) throws JsonProcessingException {
+ ObjectSchema rootSchema = new ObjectSchema();
+ rootSchema.set$schema(SCHEMA4);
+ rootSchema.setId(id);
+ rootSchema.setOneOf(allSchemas);
+
+ return mapper.writeValueAsString(rootSchema);
+ }
+
+ public static String getSObjectJsonSchema(SObjectDescription description) throws JsonProcessingException {
+ return getSObjectJsonSchema(description, true);
+ }
+
+ public static String getSObjectJsonSchema(SObjectDescription description, boolean addQuerySchema) throws JsonProcessingException {
+ ObjectMapper schemaObjectMapper = createSchemaObjectMapper();
+ return getJsonSchemaString(schemaObjectMapper, getSObjectJsonSchema(schemaObjectMapper, description, DEFAULT_ID_PREFIX, addQuerySchema), DEFAULT_ID_PREFIX);
+ }
+
+ public static Set<Object> getSObjectJsonSchema(ObjectMapper objectMapper, SObjectDescription description, String idPrefix, boolean addQuerySchema) throws JsonProcessingException {
+ Set<Object> allSchemas = new HashSet<>();
+
+ // generate SObject schema from description
+ ObjectSchema sobjectSchema = new ObjectSchema();
+ sobjectSchema.setId(idPrefix + ":" + description.getName());
+ sobjectSchema.setTitle(description.getLabel());
+
+ SimpleTypeSchema addressSchema = null;
+ SimpleTypeSchema geoLocationSchema = null;
+
+ for (SObjectField field : description.getFields()) {
+
+ SimpleTypeSchema fieldSchema = new NullSchema();
+ String soapType = field.getSoapType();
+
+ switch (soapType.substring(soapType.indexOf(':') + 1)) {
+ case "ID": // mapping for tns:ID SOAP type
+ case "string":
+ case "base64Binary":
+ // Salesforce maps any types like string, picklist, reference, etc. to string
+ case "anyType":
+ fieldSchema = new StringSchema();
+ break;
+
+ case "integer":
+ case "int":
+ case "long":
+ case "short":
+ case "byte":
+ case "unsignedInt":
+ case "unsignedShort":
+ case "unsignedByte":
+ fieldSchema = new IntegerSchema();
+ break;
+
+ case "decimal":
+ case "float":
+ case "double":
+ fieldSchema = new NumberSchema();
+ break;
+
+ case "boolean":
+ fieldSchema = new BooleanSchema();
+ break;
+
+ case "dateTime":
+ case "time":
+ case "date":
+ case "g":
+ fieldSchema = new StringSchema();
+ ((StringSchema) fieldSchema).setFormat(JsonValueFormat.DATE_TIME);
+ break;
+
+ case "address":
+ if (addressSchema == null) {
+ addressSchema = getSchemaFromClass(objectMapper, Address.class);
+ }
+ fieldSchema = addressSchema;
+ break;
+
+ case "location":
+ if (geoLocationSchema == null) {
+ geoLocationSchema = getSchemaFromClass(objectMapper, GeoLocation.class);
+ }
+ fieldSchema = geoLocationSchema;
+ break;
+
+ default:
+ throw new IllegalArgumentException("Unsupported type " + soapType);
+ }
+
+ List<PickListValue> picklistValues = field.getPicklistValues();
+ switch (field.getType()) {
+ case "picklist":
+ fieldSchema.asStringSchema().setEnums(
+ picklistValues == null ? Collections.EMPTY_SET : picklistValues.stream()
+ .map(PickListValue::getValue)
+ .distinct()
+ .collect(Collectors.toSet()));
+ break;
+
+ case "multipicklist":
+ // TODO regex needs more work to not allow values not separated by ','
+ fieldSchema.asStringSchema().setPattern(picklistValues == null ? "" : picklistValues.stream()
+ .map(val -> "(,?(" + val.getValue() + "))")
+ .distinct()
+ .collect(joining("|", "(", ")")));
+ break;
+
+ default:
+ // nothing to fix
+ }
+
+ // additional field properties
+ fieldSchema.setTitle(field.getLabel());
+ fieldSchema.setDefault(field.getDefaultValue());
+ if (field.isUpdateable() != null) {
+ fieldSchema.setReadonly(!field.isUpdateable());
+ }
+
+ // add property to sobject schema
+ if (field.isNillable()) {
+ sobjectSchema.putOptionalProperty(field.getName(), fieldSchema);
+ } else {
+ sobjectSchema.putProperty(field.getName(), fieldSchema);
+ }
+ }
+
+ // add sobject schema to root schema
+ allSchemas.add(sobjectSchema);
+
+ if (addQuerySchema) {
+ // add a simple query schema for this sobject for lookups, etc.
+ ObjectSchema queryRecords = getSchemaFromClass(objectMapper, AbstractQueryRecordsBase.class);
+ queryRecords.setId(idPrefix + ":QueryRecords" + description.getName());
+
+ ObjectSchema refSchema = new ObjectSchema();
+ refSchema.set$ref(sobjectSchema.getId());
+
+ ArraySchema recordsProperty = new ArraySchema();
+ recordsProperty.setItems(new ArraySchema.SingleItems(refSchema));
+ queryRecords.putProperty("records", recordsProperty);
+
+ allSchemas.add(queryRecords);
+ }
+
+ return allSchemas;
+ }
+
+ public static ObjectMapper createSchemaObjectMapper() {
+ ObjectMapper objectMapper = createObjectMapper();
+ objectMapper.configure(SerializationFeature.WRITE_ENUMS_USING_TO_STRING, true);
+ objectMapper.configure(SerializationFeature.INDENT_OUTPUT, true);
+ return objectMapper;
+ }
+
+ private static ObjectSchema getSchemaFromClass(ObjectMapper objectMapper, Class<?> type) throws JsonMappingException {
+ return new JsonSchemaGenerator(objectMapper).generateSchema(type).asObjectSchema();
+ }
+
}
http://git-wip-us.apache.org/repos/asf/camel/blob/e0fe1df7/components/camel-salesforce/camel-salesforce-component/src/test/java/org/apache/camel/component/salesforce/api/utils/JsonUtilsTest.java
----------------------------------------------------------------------
diff --git a/components/camel-salesforce/camel-salesforce-component/src/test/java/org/apache/camel/component/salesforce/api/utils/JsonUtilsTest.java b/components/camel-salesforce/camel-salesforce-component/src/test/java/org/apache/camel/component/salesforce/api/utils/JsonUtilsTest.java
new file mode 100644
index 0000000..cd59a9e
--- /dev/null
+++ b/components/camel-salesforce/camel-salesforce-component/src/test/java/org/apache/camel/component/salesforce/api/utils/JsonUtilsTest.java
@@ -0,0 +1,56 @@
+package org.apache.camel.component.salesforce.api.utils;
+
+import org.apache.camel.component.salesforce.api.dto.SObjectDescription;
+import org.apache.camel.component.salesforce.dto.generated.Account;
+import org.junit.Test;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import com.fasterxml.jackson.databind.ObjectMapper;
+import com.fasterxml.jackson.module.jsonSchema.JsonSchema;
+import com.fasterxml.jackson.module.jsonSchema.types.ObjectSchema;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertTrue;
+
+/**
+ * Unit test for {@link JsonUtils}
+ */
+public class JsonUtilsTest {
+
+ public static final Logger LOG = LoggerFactory.getLogger(JsonUtilsTest.class);
+
+ @Test
+ public void getBasicApiJsonSchema() throws Exception {
+
+ // create basic api dto schema
+ LOG.info("Basic Api Schema...");
+ String basicApiJsonSchema = JsonUtils.getBasicApiJsonSchema();
+ LOG.info(basicApiJsonSchema);
+
+ // parse schema to validate
+ ObjectMapper objectMapper = JsonUtils.createObjectMapper();
+ JsonSchema jsonSchema = objectMapper.readValue(basicApiJsonSchema, JsonSchema.class);
+ assertTrue(jsonSchema.isObjectSchema());
+ assertFalse(((ObjectSchema)jsonSchema).getOneOf().isEmpty());
+ }
+
+ @Test
+ public void getSObjectJsonSchema() throws Exception {
+
+ // create sobject dto schema
+ SObjectDescription description = new Account().description();
+
+ LOG.info("SObject Schema...");
+ String sObjectJsonSchema = JsonUtils.getSObjectJsonSchema(description);
+ LOG.info(sObjectJsonSchema);
+
+ // parse schema to validate
+ ObjectMapper objectMapper = JsonUtils.createObjectMapper();
+ JsonSchema jsonSchema = objectMapper.readValue(sObjectJsonSchema, JsonSchema.class);
+ assertTrue(jsonSchema.isObjectSchema());
+ assertEquals(2, ((ObjectSchema)jsonSchema).getOneOf().size());
+ }
+
+}
\ No newline at end of file
http://git-wip-us.apache.org/repos/asf/camel/blob/e0fe1df7/parent/pom.xml
----------------------------------------------------------------------
diff --git a/parent/pom.xml b/parent/pom.xml
index 6714d0d..cfbc5e4 100644
--- a/parent/pom.xml
+++ b/parent/pom.xml
@@ -622,6 +622,7 @@
<spymemcached-bundle-version>2.5_2</spymemcached-bundle-version> <!-- FIXME cmueller: not in sync! -->
<spymemcached-version>2.12.0</spymemcached-version>
<squareup-okhttp-version>2.7.5</squareup-okhttp-version>
+ <squareup-okhttp3-version>3.8.1</squareup-okhttp3-version>
<squareup-okhttp-bundle-version>2.7.5_1</squareup-okhttp-bundle-version>
<squareup-okio-version>1.11.0</squareup-okio-version>
<squareup-okio-bundle-version>1.11.0_1</squareup-okio-bundle-version>
@@ -3457,6 +3458,11 @@
<artifactId>jackson-module-jaxb-annotations</artifactId>
<version>${jackson2-version}</version>
</dependency>
+ <dependency>
+ <groupId>com.fasterxml.jackson.module</groupId>
+ <artifactId>jackson-module-jsonSchema</artifactId>
+ <version>${jackson2-version}</version>
+ </dependency>
<dependency>
<groupId>io.netty</groupId>
http://git-wip-us.apache.org/repos/asf/camel/blob/e0fe1df7/platforms/karaf/features/src/main/resources/features.xml
----------------------------------------------------------------------
diff --git a/platforms/karaf/features/src/main/resources/features.xml b/platforms/karaf/features/src/main/resources/features.xml
index a6e2213..1f23fda 100644
--- a/platforms/karaf/features/src/main/resources/features.xml
+++ b/platforms/karaf/features/src/main/resources/features.xml
@@ -1574,6 +1574,8 @@
<bundle dependency='true'>mvn:com.fasterxml.jackson.core/jackson-core/${jackson2-version}</bundle>
<bundle dependency='true'>mvn:com.fasterxml.jackson.core/jackson-annotations/${jackson2-version}</bundle>
<bundle dependency='true'>mvn:com.fasterxml.jackson.core/jackson-databind/${jackson2-version}</bundle>
+ <bundle dependency='true'>mvn:com.fasterxml.jackson.core/jackson-jaxrs-json-provider/${jackson2-version}</bundle>
+ <bundle dependency='true'>mvn:com.fasterxml.jackson.core/jackson-module-jsonSchema/${jackson2-version}</bundle>
<bundle dependency='true'>mvn:org.apache.servicemix.bundles/org.apache.servicemix.bundles.xstream/${xstream-bundle-version}</bundle>
<bundle dependency='true'>mvn:org.apache.servicemix.bundles/org.apache.servicemix.bundles.xpp3/${xpp3-bundle-version}</bundle>
<bundle dependency='true'>mvn:javax.servlet/javax.servlet-api/${javax.servlet-api-version}</bundle>