Repository: camel
Updated Branches:
  refs/heads/master 34a7afbf6 -> 4d6e8f187


CAMEL-11667: Support Metadata component extension

This simplifies and unifies the two modes of metadata gathering. Now if
`sObjectName` is specified a (very simple) JSON schema is returned
rather than custom JSON object.


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

Branch: refs/heads/master
Commit: 4d6e8f187110a44558df06774453c8f4441590b0
Parents: 34a7afb
Author: Zoran Regvart <zregv...@apache.org>
Authored: Fri Sep 8 17:33:11 2017 +0200
Committer: Zoran Regvart <zregv...@apache.org>
Committed: Fri Sep 8 17:33:32 2017 +0200

----------------------------------------------------------------------
 .../salesforce/SalesforceMetaDataExtension.java | 127 ++++++-------------
 .../salesforce/api/utils/JsonUtils.java         |  17 +++
 .../SalesforceMetaDataExtensionTest.java        |  61 +++++----
 3 files changed, 93 insertions(+), 112 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/camel/blob/4d6e8f18/components/camel-salesforce/camel-salesforce-component/src/main/java/org/apache/camel/component/salesforce/SalesforceMetaDataExtension.java
----------------------------------------------------------------------
diff --git 
a/components/camel-salesforce/camel-salesforce-component/src/main/java/org/apache/camel/component/salesforce/SalesforceMetaDataExtension.java
 
b/components/camel-salesforce/camel-salesforce-component/src/main/java/org/apache/camel/component/salesforce/SalesforceMetaDataExtension.java
index abf5201..8c46e14 100644
--- 
a/components/camel-salesforce/camel-salesforce-component/src/main/java/org/apache/camel/component/salesforce/SalesforceMetaDataExtension.java
+++ 
b/components/camel-salesforce/camel-salesforce-component/src/main/java/org/apache/camel/component/salesforce/SalesforceMetaDataExtension.java
@@ -18,119 +18,77 @@ package org.apache.camel.component.salesforce;
 
 import java.io.IOException;
 import java.io.InputStream;
-import java.util.HashMap;
 import java.util.Map;
 import java.util.Optional;
 import java.util.concurrent.CompletableFuture;
 import java.util.concurrent.ExecutionException;
-import java.util.function.BiFunction;
 import java.util.function.Consumer;
 
 import com.fasterxml.jackson.databind.JsonNode;
 import com.fasterxml.jackson.databind.ObjectMapper;
 import com.fasterxml.jackson.module.jsonSchema.JsonSchema;
 
-import org.apache.camel.CamelContext;
 import org.apache.camel.component.extension.metadata.AbstractMetaDataExtension;
 import org.apache.camel.component.extension.metadata.MetaDataBuilder;
+import org.apache.camel.component.salesforce.api.dto.GlobalObjects;
 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.RestClient.ResponseCallback;
 import org.apache.camel.util.ObjectHelper;
 
-import static 
org.apache.camel.component.salesforce.SalesforceClientTemplate.invoke;
-
 public class SalesforceMetaDataExtension extends AbstractMetaDataExtension {
 
-    static final String OBJECT_TYPE = SalesforceEndpointConfig.SOBJECT_NAME;
-
-    public enum Scope implements MetaDataOperation {
-        OBJECT(
-            (client, params) -> callback -> 
client.getDescription(stringParam(params, OBJECT_TYPE).get(), callback)) {
-            @Override
-            public MetaData map(final CamelContext camelContext, final 
InputStream stream) throws IOException {
-                final SObjectDescription description = 
MAPPER.readerFor(SObjectDescription.class).readValue(stream);
-
-                final JsonSchema payload = 
JsonUtils.getSObjectJsonSchemaAsSchema(description, true);
-
-                return MetaDataBuilder.on(camelContext)//
-                    .withAttribute(MetaData.CONTENT_TYPE, 
"application/schema+json")//
-                    .withAttribute(MetaData.JAVA_TYPE, JsonNode.class)//
-                    .withAttribute("scope", 
"object").withPayload(payload).build();
-            }
-        },
-        OBJECT_TYPES((client, params) -> callback -> 
client.getGlobalObjects(callback)) {
-            @Override
-            public MetaData map(final CamelContext camelContext, final 
InputStream stream) throws IOException {
-                final JsonNode rawResponse = MAPPER.readTree(stream);
-                final JsonNode payload = rawResponse.get("sobjects");
-
-                return MetaDataBuilder.on(camelContext)//
-                    .withAttribute(MetaData.CONTENT_TYPE, "application/json")//
-                    .withAttribute(MetaData.JAVA_TYPE, JsonNode.class)//
-                    .withAttribute("scope", 
"object_types").withPayload(payload).build();
-            }
-        };
-
-        private final BiFunction<RestClient, Map<String, Object>, 
Consumer<ResponseCallback>> method;
-
-        private Scope(final BiFunction<RestClient, Map<String, Object>, 
Consumer<ResponseCallback>> method) {
-            this.method = method;
-        }
-
-        public static Scope valueOf(final Object given) {
-            if (given instanceof Scope) {
-                return (Scope) given;
-            }
-
-            if (given instanceof String) {
-                return Scope.valueOf((String) given);
-            }
-
-            return Scope.valueOf(String.valueOf(given));
-        }
-    }
-
-    interface MetaDataOperation {
-
-        MetaData map(CamelContext camelContext, InputStream stream) throws 
IOException;
+    @FunctionalInterface
+    interface SchemaMapper {
+        JsonSchema map(InputStream stream) throws IOException;
     }
 
     private static final ObjectMapper MAPPER = JsonUtils.createObjectMapper();
 
     @Override
     public Optional<MetaData> meta(final Map<String, Object> parameters) {
-        final Optional<String> objectType = stringParam(parameters, 
OBJECT_TYPE);
+        final JsonSchema schema = schemaFor(parameters);
 
-        final Scope scope = objectType.map(v -> 
Scope.OBJECT).orElse(Scope.OBJECT_TYPES);
-
-        final MetaData metaData = metaInternal(scope, parameters);
+        final MetaData metaData = MetaDataBuilder.on(getCamelContext())//
+            .withAttribute(MetaData.CONTENT_TYPE, "application/schema+json")//
+            .withAttribute(MetaData.JAVA_TYPE, JsonNode.class)//
+            .withPayload(schema).build();
 
         return Optional.ofNullable(metaData);
     }
 
-    MetaData metaInternal(final Scope scope, final Map<String, Object> 
parameters) {
-        final CamelContext camelContext = getCamelContext();
+    JsonSchema allObjectsSchema(final Map<String, Object> parameters) throws 
Exception {
+        return SalesforceClientTemplate.invoke(getCamelContext(), parameters, 
client -> fetchAllObjectsSchema(client));
+    }
 
+    JsonSchema schemaFor(final Map<String, Object> parameters) {
         try {
-            return invoke(camelContext, parameters,
-                client -> fetchMetadata(camelContext, 
scope.method.apply(client, parameters), scope::map));
+            if (parameters.containsKey(SalesforceEndpointConfig.SOBJECT_NAME)) 
{
+                return singleObjectSchema(parameters);
+            }
+
+            return allObjectsSchema(parameters);
         } catch (final Exception e) {
             throw ObjectHelper.wrapRuntimeCamelException(e);
         }
+
     }
 
-    static MetaData fetchMetadata(final CamelContext camelContext, final 
Consumer<ResponseCallback> restMethod,
-        final MetaDataOperation callback) {
-        final CompletableFuture<MetaData> ret = new CompletableFuture<>();
+    JsonSchema singleObjectSchema(final Map<String, Object> parameters) throws 
Exception {
+        return SalesforceClientTemplate.invoke(getCamelContext(), parameters,
+            client -> fetchSingleObjectSchema(client, (String) 
parameters.get(SalesforceEndpointConfig.SOBJECT_NAME)));
+    }
+
+    static JsonSchema fetch(final Consumer<ResponseCallback> restMethod, final 
SchemaMapper callback) {
+        final CompletableFuture<JsonSchema> ret = new CompletableFuture<>();
 
         restMethod.accept((response, exception) -> {
             if (exception != null) {
                 ret.completeExceptionally(exception);
             } else {
-                try {
-                    ret.complete(callback.map(camelContext, response));
+                try (final InputStream is = response) {
+                    ret.complete(callback.map(is));
                 } catch (final IOException e) {
                     ret.completeExceptionally(e);
                 }
@@ -144,26 +102,25 @@ public class SalesforceMetaDataExtension extends 
AbstractMetaDataExtension {
         }
     }
 
-    static Map<String, Object> mapOf(final String k1, final Object v1, final 
String k2, final Object v2) {
-        final Map<String, Object> ret = new HashMap<>(2);
-
-        ret.put(k1, v1);
-        ret.put(k2, v2);
+    static JsonSchema fetchAllObjectsSchema(final RestClient client) {
+        return fetch(callback -> client.getGlobalObjects(callback), 
SalesforceMetaDataExtension::mapAllObjectsSchema);
+    }
 
-        return ret;
+    static JsonSchema fetchSingleObjectSchema(final RestClient client, final 
String objectName) {
+        return fetch(callback -> client.getDescription(objectName, callback),
+            SalesforceMetaDataExtension::mapSingleObjectSchema);
     }
 
-    static Optional<String> stringParam(final Map<String, Object> params, 
final String name) {
-        final Object value = params.get(name);
+    static JsonSchema mapAllObjectsSchema(final InputStream stream) throws 
IOException {
+        final GlobalObjects globalObjects = 
MAPPER.readerFor(GlobalObjects.class).readValue(stream);
 
-        if (value == null) {
-            return Optional.empty();
-        }
+        return JsonUtils.getGlobalObjectsJsonSchemaAsSchema(globalObjects);
+    }
 
-        if (value instanceof String) {
-            return Optional.of((String) value);
-        }
+    static JsonSchema mapSingleObjectSchema(final InputStream stream) throws 
IOException {
+        final SObjectDescription description = 
MAPPER.readerFor(SObjectDescription.class).readValue(stream);
 
-        throw new IllegalArgumentException("Expecting parameter `" + name + "` 
to be of String type, got: " + value);
+        return JsonUtils.getSObjectJsonSchemaAsSchema(description, true);
     }
+
 }

http://git-wip-us.apache.org/repos/asf/camel/blob/4d6e8f18/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 cc3f7c1..415bb61 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
@@ -46,7 +46,9 @@ 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.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.impl.DefaultPackageScanClassResolver;
@@ -291,4 +293,19 @@ public abstract class JsonUtils {
         return new 
JsonSchemaGenerator(objectMapper).generateSchema(type).asObjectSchema();
     }
 
+    public static JsonSchema getGlobalObjectsJsonSchemaAsSchema(final 
GlobalObjects globalObjects) {
+        final Set<JsonSchema> allSchemas = new HashSet<>();
+
+        for (SObject sobject : globalObjects.getSobjects()) {
+            // generate SObject schema from description
+            ObjectSchema sobjectSchema = new ObjectSchema();
+            sobjectSchema.setId(DEFAULT_ID_PREFIX + ":" + sobject.getName());
+            sobjectSchema.setTitle(sobject.getLabel());
+
+            allSchemas.add(sobjectSchema);
+        }
+
+        return getJsonSchemaAsSchema(allSchemas, DEFAULT_ID_PREFIX + 
":GlobalObjects");
+    }
+
 }

http://git-wip-us.apache.org/repos/asf/camel/blob/4d6e8f18/components/camel-salesforce/camel-salesforce-component/src/test/java/org/apache/camel/component/salesforce/SalesforceMetaDataExtensionTest.java
----------------------------------------------------------------------
diff --git 
a/components/camel-salesforce/camel-salesforce-component/src/test/java/org/apache/camel/component/salesforce/SalesforceMetaDataExtensionTest.java
 
b/components/camel-salesforce/camel-salesforce-component/src/test/java/org/apache/camel/component/salesforce/SalesforceMetaDataExtensionTest.java
index e19f7cf..b0a86b8 100644
--- 
a/components/camel-salesforce/camel-salesforce-component/src/test/java/org/apache/camel/component/salesforce/SalesforceMetaDataExtensionTest.java
+++ 
b/components/camel-salesforce/camel-salesforce-component/src/test/java/org/apache/camel/component/salesforce/SalesforceMetaDataExtensionTest.java
@@ -31,6 +31,7 @@ import 
com.fasterxml.jackson.module.jsonSchema.types.ObjectSchema;
 
 import org.apache.camel.component.extension.MetaDataExtension;
 import org.apache.camel.component.extension.MetaDataExtension.MetaData;
+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.RestClient.ResponseCallback;
 import org.apache.camel.impl.DefaultCamelContext;
@@ -68,7 +69,7 @@ public class SalesforceMetaDataExtensionTest {
         try (InputStream stream = resource("/objectDescription.json")) {
             
doAnswer(provideStreamToCallback(stream)).when(restClient).getDescription(eq("Account"),
                 any(ResponseCallback.class));
-            maybeMeta = 
metadata.meta(Collections.singletonMap(SalesforceMetaDataExtension.OBJECT_TYPE, 
"Account"));
+            maybeMeta = 
metadata.meta(Collections.singletonMap(SalesforceEndpointConfig.SOBJECT_NAME, 
"Account"));
         }
 
         assertThat(maybeMeta).isPresent();
@@ -80,15 +81,8 @@ public class SalesforceMetaDataExtensionTest {
         final ObjectSchema payload = meta.getPayload(ObjectSchema.class);
         assertThat(payload).isNotNull();
 
-        @SuppressWarnings({"unchecked", "rawtypes"})
-        final Set<JsonSchema> oneOf = (Set) payload.getOneOf();
-        final Optional<JsonSchema> merchandiseSchema = 
StreamSupport.stream(oneOf.spliterator(), false)
-            
.filter(idMatches("urn:jsonschema:org:apache:camel:component:salesforce:dto:Merchandise__c")).findAny();
-        final Optional<JsonSchema> merchandiseQuerySchema = 
StreamSupport.stream(oneOf.spliterator(), false)
-            
.filter(idMatches("urn:jsonschema:org:apache:camel:component:salesforce:dto:QueryRecordsMerchandise__c"))
-            .findAny();
-        assertThat(merchandiseSchema).isPresent();
-        assertThat(merchandiseQuerySchema).isPresent();
+        assertThat(schemaFor(payload, "Merchandise__c")).isPresent();
+        assertThat(schemaFor(payload, 
"QueryRecordsMerchandise__c")).isPresent();
     }
 
     @Test
@@ -103,26 +97,23 @@ public class SalesforceMetaDataExtensionTest {
 
         final MetaData meta = maybeMeta.get();
         
assertThat(meta.getAttribute(MetaDataExtension.MetaData.JAVA_TYPE)).isEqualTo(JsonNode.class);
-        
assertThat(meta.getAttribute(MetaDataExtension.MetaData.CONTENT_TYPE)).isEqualTo("application/json");
+        
assertThat(meta.getAttribute(MetaDataExtension.MetaData.CONTENT_TYPE)).isEqualTo("application/schema+json");
 
-        final JsonNode payload = meta.getPayload(JsonNode.class);
+        final ObjectSchema payload = meta.getPayload(ObjectSchema.class);
         assertThat(payload).isNotNull();
-        assertThat(valueAt(payload, 0, 
"name")).isEqualTo("AcceptedEventRelation");
-        assertThat(valueAt(payload, 0, "label")).isEqualTo("Accepted Event 
Relation");
-        assertThat(valueAt(payload, 1, "name")).isEqualTo("Account");
-        assertThat(valueAt(payload, 1, "label")).isEqualTo("Account");
-        assertThat(valueAt(payload, 2, "name")).isEqualTo("AccountCleanInfo");
-        assertThat(valueAt(payload, 2, "label")).isEqualTo("Account Clean 
Info");
-        assertThat(valueAt(payload, 3, 
"name")).isEqualTo("AccountContactRole");
-        assertThat(valueAt(payload, 3, "label")).isEqualTo("Account Contact 
Role");
-    }
 
-    static InputStream resource(final String path) {
-        return SalesforceMetaDataExtensionTest.class.getResourceAsStream(path);
-    }
-
-    static String valueAt(final JsonNode payload, final int idx, final String 
name) {
-        return payload.get(idx).get(name).asText();
+        @SuppressWarnings({"unchecked", "rawtypes"})
+        final Set<JsonSchema> oneOf = (Set) payload.getOneOf();
+        assertThat(oneOf).hasSize(4);
+
+        assertThat(schemaFor(payload, "AcceptedEventRelation")).isPresent()
+            .hasValueSatisfying(schema -> 
assertThat(schema.getTitle()).isEqualTo("Accepted Event Relation"));
+        assertThat(schemaFor(payload, "Account")).isPresent()
+            .hasValueSatisfying(schema -> 
assertThat(schema.getTitle()).isEqualTo("Account"));
+        assertThat(schemaFor(payload, "AccountCleanInfo")).isPresent()
+            .hasValueSatisfying(schema -> 
assertThat(schema.getTitle()).isEqualTo("Account Clean Info"));
+        assertThat(schemaFor(payload, "AccountContactRole")).isPresent()
+            .hasValueSatisfying(schema -> 
assertThat(schema.getTitle()).isEqualTo("Account Contact Role"));
     }
 
     static Answer<Void> provideStreamToCallback(final InputStream stream) {
@@ -135,6 +126,22 @@ public class SalesforceMetaDataExtensionTest {
         };
     }
 
+    static InputStream resource(final String path) {
+        return SalesforceMetaDataExtensionTest.class.getResourceAsStream(path);
+    }
+
+    static Optional<ObjectSchema> schemaFor(final ObjectSchema schema, final 
String sObjectName) {
+        @SuppressWarnings({"unchecked", "rawtypes"})
+        final Set<ObjectSchema> oneOf = (Set) schema.getOneOf();
+
+        return StreamSupport.stream(oneOf.spliterator(), false)
+            .filter(idMatches(JsonUtils.DEFAULT_ID_PREFIX + ":" + 
sObjectName)).findAny();
+    }
+
+    static String valueAt(final JsonNode payload, final int idx, final String 
name) {
+        return payload.get(idx).get(name).asText();
+    }
+
     private static Predicate<JsonSchema> idMatches(final String wantedId) {
         return schema -> wantedId.equals(schema.getId());
     }

Reply via email to