You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@sling.apache.org by bd...@apache.org on 2021/05/04 17:21:22 UTC

[sling-whiteboard] branch master updated: GraphQL sample uses DocumentMapper

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

bdelacretaz pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/sling-whiteboard.git


The following commit(s) were added to refs/heads/master by this push:
     new 26221a9  GraphQL sample uses DocumentMapper
26221a9 is described below

commit 26221a95cda09987d8ad29d1c45c34a87e12bbdc
Author: Bertrand Delacretaz <bd...@apache.org>
AuthorDate: Tue May 4 19:21:07 2021 +0200

    GraphQL sample uses DocumentMapper
---
 .../documentmapper/impl/MapMappingTarget.java}     |  24 ++--
 .../sling/documentmapper/impl/MapTargetNode.java   |  65 ++++++++++
 remote-content-api/sample-graphql-api/README.md    |  20 +++-
 .../graphql/DocumentDataFetcher.java               |  32 ++++-
 .../graphql/RandomStructureMap.java                |  75 ------------
 .../AnnotationImpl.java}                           |  38 +++---
 .../sling/remotecontentapi/typesystem/Builder.java |  77 ++++++++++++
 .../typesystem/HardcodedTypeSystem.java            | 131 +++++++++++++++++++++
 .../remotecontentapi/typesystem/PropertyImpl.java  |  73 ++++++++++++
 .../generated-diagrams/client-side-rendering.png   | Bin 12970 -> 14623 bytes
 .../generated-diagrams/edge-side-rendering.png     | Bin 20778 -> 23622 bytes
 11 files changed, 423 insertions(+), 112 deletions(-)

diff --git a/remote-content-api/sample-graphql-api/src/main/java/org/apache/sling/remotecontentapi/graphql/DocumentDataFetcher.java b/remote-content-api/document-mapper/src/main/java/org/apache/sling/documentmapper/impl/MapMappingTarget.java
similarity index 55%
copy from remote-content-api/sample-graphql-api/src/main/java/org/apache/sling/remotecontentapi/graphql/DocumentDataFetcher.java
copy to remote-content-api/document-mapper/src/main/java/org/apache/sling/documentmapper/impl/MapMappingTarget.java
index e01d5c3..26d643f 100644
--- a/remote-content-api/sample-graphql-api/src/main/java/org/apache/sling/remotecontentapi/graphql/DocumentDataFetcher.java
+++ b/remote-content-api/document-mapper/src/main/java/org/apache/sling/documentmapper/impl/MapMappingTarget.java
@@ -17,27 +17,19 @@
  * under the License.
  */
 
-package org.apache.sling.remotecontentapi.graphql;
+package org.apache.sling.documentmapper.impl;
 
-import java.util.HashMap;
-import java.util.Map;
+import org.apache.sling.documentmapper.api.MappingTarget;
 
-import org.apache.sling.graphql.api.SlingDataFetcher;
-import org.apache.sling.graphql.api.SlingDataFetcherEnvironment;
 import org.jetbrains.annotations.NotNull;
-import org.jetbrains.annotations.Nullable;
 import org.osgi.service.component.annotations.Component;
 
-@Component(service = SlingDataFetcher.class, property = {"name=samples/document"})
-public class DocumentDataFetcher implements SlingDataFetcher<Object> {
+/** MappingTarget that outputs to a JSON document */
+@Component(service = MappingTarget.class, property = { MappingTarget.TARGET_TYPE + "=map" })
+public class MapMappingTarget implements MappingTarget {
 
     @Override
-    public @Nullable Object get(@NotNull SlingDataFetcherEnvironment e) throws Exception {
-        final Map<String, Object> data = new HashMap<>();
-        data.put("path", e.getArgument("path"));
-        data.put("selectors", e.getArgument("selectors"));
-        data.put("body", RandomStructureMap.get());
-        return data;
+    public @NotNull TargetNode newTargetNode() {
+        return new MapTargetNode("ROOT_THIS_NAME_SHOULD_NOT_APPEAR_IN_OUTPUT");
     }
-    
-}
+}
\ No newline at end of file
diff --git a/remote-content-api/document-mapper/src/main/java/org/apache/sling/documentmapper/impl/MapTargetNode.java b/remote-content-api/document-mapper/src/main/java/org/apache/sling/documentmapper/impl/MapTargetNode.java
new file mode 100644
index 0000000..ea1e18b
--- /dev/null
+++ b/remote-content-api/document-mapper/src/main/java/org/apache/sling/documentmapper/impl/MapTargetNode.java
@@ -0,0 +1,65 @@
+/*
+ * 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.sling.documentmapper.impl;
+
+import java.util.HashMap;
+import java.util.Map;
+
+import org.apache.sling.documentmapper.api.MappingTarget;
+import org.apache.sling.documentmapper.api.MappingTarget.TargetNode;
+
+/** A TargetNode that outputs to a Map document */
+public class MapTargetNode extends HashMap<String, Object> implements MappingTarget.TargetNode {
+
+    MapTargetNode(String name) {
+    }
+
+    @Override
+    public TargetNode addChild(String name) {
+        final MapTargetNode child = new MapTargetNode(name);
+        put(name, child);
+        return child;
+    }
+
+    @Override
+    public TargetNode addValue(String name, Object value) {
+        put(name, value);
+        return this;
+    }
+
+    @Override
+    public TargetNode addValue(String name, Object[] value) {
+        put(name, value);
+        return this;
+    }
+
+    @Override
+    public <AdapterType> AdapterType adaptTo(Class<AdapterType> type) {
+        if(type.equals(Map.class)) {
+            return (AdapterType)this;
+        }
+        throw new IllegalArgumentException("For now, can only adapt to a Map");
+    }
+
+    @Override
+    public void close() {
+        // nothing to close
+    }
+}
\ No newline at end of file
diff --git a/remote-content-api/sample-graphql-api/README.md b/remote-content-api/sample-graphql-api/README.md
index 49a4686..816273c 100644
--- a/remote-content-api/sample-graphql-api/README.md
+++ b/remote-content-api/sample-graphql-api/README.md
@@ -18,4 +18,22 @@ the Maven JVM.
 
 The test content uses `com.adobe.aem.guides:aem-guides-wknd.ui.content.sample` which is MIT
 licensed. Minimal "fake" JCR nodetype definitions are used to allow this content to load, as
-we don't really care about the details of these node types besides their names.
\ No newline at end of file
+we don't really care about the details of these node types besides their names.
+
+## Example GraphQL queries
+
+    { 
+      document(path:"/content/articles/music/eloy-hahn-on-the-system-of-1080p-et-corrupti-aka-xml", selectors: "not, used, sofar") {
+      	path
+        selectors
+        body
+      }
+    }
+    
+    {
+      document(path:"/content/wknd/us/en/adventures/riverside-camping-australia", selectors: "not,used,yet") {
+      	path
+        selectors
+        body
+      }
+    }
\ No newline at end of file
diff --git a/remote-content-api/sample-graphql-api/src/main/java/org/apache/sling/remotecontentapi/graphql/DocumentDataFetcher.java b/remote-content-api/sample-graphql-api/src/main/java/org/apache/sling/remotecontentapi/graphql/DocumentDataFetcher.java
index e01d5c3..4fe0beb 100644
--- a/remote-content-api/sample-graphql-api/src/main/java/org/apache/sling/remotecontentapi/graphql/DocumentDataFetcher.java
+++ b/remote-content-api/sample-graphql-api/src/main/java/org/apache/sling/remotecontentapi/graphql/DocumentDataFetcher.java
@@ -22,21 +22,49 @@ package org.apache.sling.remotecontentapi.graphql;
 import java.util.HashMap;
 import java.util.Map;
 
+import org.apache.sling.api.resource.Resource;
+import org.apache.sling.documentmapper.api.DocumentMapper;
+import org.apache.sling.documentmapper.api.MappingTarget;
+import org.apache.sling.documentmapper.api.DocumentMapper.UrlBuilder;
 import org.apache.sling.graphql.api.SlingDataFetcher;
 import org.apache.sling.graphql.api.SlingDataFetcherEnvironment;
 import org.jetbrains.annotations.NotNull;
 import org.jetbrains.annotations.Nullable;
 import org.osgi.service.component.annotations.Component;
+import org.osgi.service.component.annotations.Reference;
 
 @Component(service = SlingDataFetcher.class, property = {"name=samples/document"})
 public class DocumentDataFetcher implements SlingDataFetcher<Object> {
 
+    @Reference(target="(" + MappingTarget.TARGET_TYPE + "=map)")
+    private MappingTarget mappingTarget;
+
+    @Reference(target="(" + DocumentMapper.ROLE + "=content)")
+    private DocumentMapper documentMapper;
+
+    private static final UrlBuilder URL_BUILDER = new UrlBuilder() {
+        @Override
+        public String pathToUrl(String path) {
+            return getClass().getName();
+        }
+    };
+    
     @Override
     public @Nullable Object get(@NotNull SlingDataFetcherEnvironment e) throws Exception {
+        final String path = e.getArgument("path");
+
         final Map<String, Object> data = new HashMap<>();
-        data.put("path", e.getArgument("path"));
+        data.put("path", path);
         data.put("selectors", e.getArgument("selectors"));
-        data.put("body", RandomStructureMap.get());
+
+        // Get the target Resource
+        final Resource target = e.getCurrentResource().getResourceResolver().getResource(path);
+
+        // Use DocumentMapper to build the body
+        final MappingTarget.TargetNode body = mappingTarget.newTargetNode();
+        documentMapper.map(target, body, URL_BUILDER);
+        body.close();
+        data.put("body", body.adaptTo(Map.class));
         return data;
     }
     
diff --git a/remote-content-api/sample-graphql-api/src/main/java/org/apache/sling/remotecontentapi/graphql/RandomStructureMap.java b/remote-content-api/sample-graphql-api/src/main/java/org/apache/sling/remotecontentapi/graphql/RandomStructureMap.java
deleted file mode 100644
index ce73ec8..0000000
--- a/remote-content-api/sample-graphql-api/src/main/java/org/apache/sling/remotecontentapi/graphql/RandomStructureMap.java
+++ /dev/null
@@ -1,75 +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.sling.remotecontentapi.graphql;
-
-import java.util.Date;
-import java.util.HashMap;
-import java.util.Map;
-import java.util.Random;
-
-/** Return a nested Map of random data, for testing unpredictable structures */
-class RandomStructureMap {
-
-    private static final Random random = new Random(42);
-
-    private RandomStructureMap() {
-    }
-    
-    private static Object[] randomArray() {
-        final Object[] result = new Object[random.nextInt(3) + 1];
-        for(int i=0; i < result.length; i++) {
-            result[i] = randomValue();
-        }
-        return result;
-    }
-
-    private static Object randomValue() {
-        switch(random.nextInt(4)) {
-            case 0: return "It is now " + new Date();
-            case 1: return random.nextInt(2) > 0;
-            case 2: return randomArray();
-            default: return random.nextInt(451);
-        }
-    }
-
-    private static Map<String, Object> randomMap(int maxEntries) {
-        int counter=1;
-        final Map<String, Object> result = new HashMap<>();
-        while(maxEntries > 0) {
-            result.put("key" + counter++, randomValue());
-            if(random.nextInt(2) == 1) {
-                final int maxSub = random.nextInt(maxEntries) / (random.nextInt(2) + 1);
-                result.put("sub" + counter++, randomMap(maxSub));
-                maxEntries -= maxSub;
-            }
-            maxEntries--;
-        }
-        return result;
-    }
-
-    public static Map<String, Object> get() {
-        Map<String, Object> result = randomMap(random.nextInt(24));
-        result.put(
-            "info", 
-            "The contents of this map are random, to demonstrate unpredictable content structures"
-        );
-        return result;
-    }
-}
\ No newline at end of file
diff --git a/remote-content-api/sample-graphql-api/src/main/java/org/apache/sling/remotecontentapi/graphql/DocumentDataFetcher.java b/remote-content-api/sample-graphql-api/src/main/java/org/apache/sling/remotecontentapi/typesystem/AnnotationImpl.java
similarity index 52%
copy from remote-content-api/sample-graphql-api/src/main/java/org/apache/sling/remotecontentapi/graphql/DocumentDataFetcher.java
copy to remote-content-api/sample-graphql-api/src/main/java/org/apache/sling/remotecontentapi/typesystem/AnnotationImpl.java
index e01d5c3..60a9006 100644
--- a/remote-content-api/sample-graphql-api/src/main/java/org/apache/sling/remotecontentapi/graphql/DocumentDataFetcher.java
+++ b/remote-content-api/sample-graphql-api/src/main/java/org/apache/sling/remotecontentapi/typesystem/AnnotationImpl.java
@@ -17,27 +17,29 @@
  * under the License.
  */
 
-package org.apache.sling.remotecontentapi.graphql;
+package org.apache.sling.remotecontentapi.typesystem;
 
-import java.util.HashMap;
-import java.util.Map;
-
-import org.apache.sling.graphql.api.SlingDataFetcher;
-import org.apache.sling.graphql.api.SlingDataFetcherEnvironment;
+import org.apache.sling.experimental.typesystem.Annotation;
 import org.jetbrains.annotations.NotNull;
-import org.jetbrains.annotations.Nullable;
-import org.osgi.service.component.annotations.Component;
 
-@Component(service = SlingDataFetcher.class, property = {"name=samples/document"})
-public class DocumentDataFetcher implements SlingDataFetcher<Object> {
+class AnnotationImpl implements Annotation {
+
+    private final String name;
+    private final String value;
+
+    AnnotationImpl(String name, String value) {
+        this.name = name;
+        this.value = value;
+    }
+
+    @Override
+    public @NotNull String getName() {
+        return name;
+    }
 
     @Override
-    public @Nullable Object get(@NotNull SlingDataFetcherEnvironment e) throws Exception {
-        final Map<String, Object> data = new HashMap<>();
-        data.put("path", e.getArgument("path"));
-        data.put("selectors", e.getArgument("selectors"));
-        data.put("body", RandomStructureMap.get());
-        return data;
+    public @NotNull String getValue() {
+        return value;
     }
-    
-}
+
+}
\ No newline at end of file
diff --git a/remote-content-api/sample-graphql-api/src/main/java/org/apache/sling/remotecontentapi/typesystem/Builder.java b/remote-content-api/sample-graphql-api/src/main/java/org/apache/sling/remotecontentapi/typesystem/Builder.java
new file mode 100644
index 0000000..6874c49
--- /dev/null
+++ b/remote-content-api/sample-graphql-api/src/main/java/org/apache/sling/remotecontentapi/typesystem/Builder.java
@@ -0,0 +1,77 @@
+/*
+ * 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.sling.remotecontentapi.typesystem;
+
+import java.util.HashSet;
+import java.util.Set;
+
+import org.apache.sling.experimental.typesystem.Annotation;
+import org.apache.sling.experimental.typesystem.Property;
+import org.apache.sling.experimental.typesystem.Type;
+import org.jetbrains.annotations.NotNull;
+import org.jetbrains.annotations.Nullable;
+
+/** Temporary implementation for this prototype, until we
+ *  have the actual type system
+ */
+
+class Builder {
+    private final String resourceType;
+    private final Set<Property> properties = new HashSet<>();
+    private final Set<Annotation> annotations = new HashSet<>();
+
+    private Builder(String resourceType) {
+        this.resourceType = resourceType;
+    }
+
+    static Builder forResourceType(String resourceType) {
+        return new Builder(resourceType);
+    }
+
+    Builder withAnnotation(String name, String value) {
+        annotations.add(new AnnotationImpl(name, value));
+        return this;
+    }
+
+    Type build() {
+        return new Type() {
+
+            @Override
+            public @NotNull String getResourceType() {
+                return resourceType;
+            }
+
+            @Override
+            public @Nullable String getResourceSuperType() {
+                return null;
+            }
+
+            @Override
+            public @NotNull Set<Property> getProperties() {
+                return properties;
+            }
+
+            @Override
+            public @NotNull Set<Annotation> getAnnotations() {
+                return annotations;
+            }
+        };
+    }
+}
\ No newline at end of file
diff --git a/remote-content-api/sample-graphql-api/src/main/java/org/apache/sling/remotecontentapi/typesystem/HardcodedTypeSystem.java b/remote-content-api/sample-graphql-api/src/main/java/org/apache/sling/remotecontentapi/typesystem/HardcodedTypeSystem.java
new file mode 100644
index 0000000..ceedb1a
--- /dev/null
+++ b/remote-content-api/sample-graphql-api/src/main/java/org/apache/sling/remotecontentapi/typesystem/HardcodedTypeSystem.java
@@ -0,0 +1,131 @@
+/*
+ * 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.sling.remotecontentapi.typesystem;
+
+import java.util.HashMap;
+import java.util.Map;
+
+import org.apache.sling.api.resource.Resource;
+import org.apache.sling.experimental.typesystem.Type;
+import org.apache.sling.experimental.typesystem.service.TypeSystem;
+import org.jetbrains.annotations.NotNull;
+import org.jetbrains.annotations.Nullable;
+import org.osgi.service.component.annotations.Component;
+
+import static org.apache.sling.documentmapper.api.AnnotationNames.NAVIGABLE;
+import static org.apache.sling.documentmapper.api.AnnotationNames.VISIT_CONTENT;
+import static org.apache.sling.documentmapper.api.AnnotationNames.DOCUMENT_ROOT;
+import static org.apache.sling.documentmapper.api.AnnotationNames.VISIT_CONTENT_RESOURCE_NAME_PATTERN;
+import static org.apache.sling.documentmapper.api.AnnotationNames.CONTENT_EXCLUDE_PROPERTY_REGEXP;
+import static org.apache.sling.documentmapper.api.AnnotationNames.CONTENT_INCLUDE_PROPERTY_REGEXP;
+import static org.apache.sling.documentmapper.api.AnnotationNames.NAVIGATION_PROPERTIES_LIST;
+import static org.apache.sling.documentmapper.api.AnnotationNames.DEREFERENCE_BY_PATH;
+
+/** Temporary hardcoded type system for this prototype, until we
+ *  have the actual type system
+ *  NOTE that this is DUPLICATED from the http sample API module, we'll
+ *  need to refactor!
+ */
+
+@Component(service=TypeSystem.class)
+public class HardcodedTypeSystem implements TypeSystem {
+
+    private static final String SLING_DEFAULT_RESOURCE_TYPE = "sling/servlet/default";
+    private static final Type DEFAULT_TYPE;
+    private static final Map<String, Type> types = new HashMap<>();
+
+    // TODO in many cases we're just interested in the presence of an annotation, but
+    // not its value - refine this in the type system
+    private static final String TRUE = "true";
+
+    static {
+        // Although these definitions are in Java code for this early prototype, the
+        // plan is to move to a mini-language (DSL) to avoid having to use Java
+        // code for what is actually just declarative statements.
+        DEFAULT_TYPE = Builder
+            .forResourceType(SLING_DEFAULT_RESOURCE_TYPE)
+            .withAnnotation(VISIT_CONTENT, TRUE)
+            .build();
+
+        addType(
+            Builder.forResourceType("cq:Page")
+            .withAnnotation(DOCUMENT_ROOT, TRUE)
+            .withAnnotation(NAVIGABLE, TRUE)
+            .withAnnotation(VISIT_CONTENT, TRUE)
+            .withAnnotation(VISIT_CONTENT_RESOURCE_NAME_PATTERN, "jcr:content")
+            .withAnnotation(CONTENT_INCLUDE_PROPERTY_REGEXP, "sling:ResourceType|cq:tags")
+            .withAnnotation(CONTENT_EXCLUDE_PROPERTY_REGEXP, "jcr:.*|cq:.*")
+        );
+        addType(
+            Builder.forResourceType("sling:Folder")
+            .withAnnotation(NAVIGABLE, TRUE)
+        );
+        addType(
+            Builder.forResourceType("sling:OrderedFolder")
+            .withAnnotation(NAVIGABLE, TRUE)
+        );
+        addType(
+            Builder.forResourceType("sling:OrderedFolder")
+            .withAnnotation(NAVIGABLE, TRUE)
+        );
+        addType(
+            Builder.forResourceType("wknd/components/page")
+            .withAnnotation(VISIT_CONTENT, TRUE)
+        );
+        addType(
+            Builder.forResourceType("wknd/components/image")
+            .withAnnotation(VISIT_CONTENT, TRUE)
+            .withAnnotation(DEREFERENCE_BY_PATH, "fileReference")
+        );
+        addType(
+            Builder.forResourceType("wknd/components/carousel")
+            .withAnnotation(VISIT_CONTENT, TRUE)
+        );
+
+        // for /content/articles examples
+        addType(
+            Builder.forResourceType("samples/section")
+            .withAnnotation(NAVIGABLE, TRUE)
+            .withAnnotation(NAVIGATION_PROPERTIES_LIST, "name")
+        );
+        addType(
+            Builder.forResourceType("samples/article")
+            .withAnnotation(NAVIGABLE, TRUE)
+        );
+    }
+
+    static void addType(Builder b) {
+        final Type t = b.build();
+        types.put(t.getResourceType(), t);
+    }
+    
+    @Override
+    public @Nullable Type getType(@NotNull Resource resource) {
+        Type result = types.get(resource.getResourceType());
+        if(result == null) {
+            result = types.get(resource.getResourceSuperType());
+        }
+        if(result == null) {
+            result = DEFAULT_TYPE;
+        }
+        return result;
+    }
+
+}
\ No newline at end of file
diff --git a/remote-content-api/sample-graphql-api/src/main/java/org/apache/sling/remotecontentapi/typesystem/PropertyImpl.java b/remote-content-api/sample-graphql-api/src/main/java/org/apache/sling/remotecontentapi/typesystem/PropertyImpl.java
new file mode 100644
index 0000000..ed330df
--- /dev/null
+++ b/remote-content-api/sample-graphql-api/src/main/java/org/apache/sling/remotecontentapi/typesystem/PropertyImpl.java
@@ -0,0 +1,73 @@
+/*
+ * 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.sling.remotecontentapi.typesystem;
+
+import java.util.HashSet;
+import java.util.Set;
+
+import org.apache.sling.experimental.typesystem.Annotation;
+import org.apache.sling.experimental.typesystem.Property;
+import org.jetbrains.annotations.NotNull;
+import org.jetbrains.annotations.Nullable;
+
+/** Temporary implementation for this prototype, until we
+ *  have the actual type system
+ */
+class PropertyImpl<T> implements Property<T> {
+
+    private final String name;
+    private final T value;
+    private final Set<Annotation> annotations = new HashSet<>();
+
+    PropertyImpl(String name, T value) {
+        this.name = name;
+        this.value = value;
+    }
+
+    @Override
+    public @Nullable String getNamespace() {
+        return null;
+    }
+
+    @Override
+    public @NotNull String getName() {
+        return name;
+    }
+
+    @Override
+    public @NotNull Class<T> getType() {
+        return (Class<T>)value.getClass();
+    }
+
+    @Override
+    public @Nullable T getValue() {
+        return value;
+    }
+
+    @Override
+    public boolean isRequired() {
+        throw new UnsupportedOperationException("do we really need this method");
+    }
+
+    @Override
+    public @NotNull Set<Annotation> getAnnotations() {
+        return annotations;
+    }
+}
\ No newline at end of file
diff --git a/remote-content-api/src/docs/generated-diagrams/client-side-rendering.png b/remote-content-api/src/docs/generated-diagrams/client-side-rendering.png
index 70acdeb..c137d70 100644
Binary files a/remote-content-api/src/docs/generated-diagrams/client-side-rendering.png and b/remote-content-api/src/docs/generated-diagrams/client-side-rendering.png differ
diff --git a/remote-content-api/src/docs/generated-diagrams/edge-side-rendering.png b/remote-content-api/src/docs/generated-diagrams/edge-side-rendering.png
index aa53296..3b2c99f 100644
Binary files a/remote-content-api/src/docs/generated-diagrams/edge-side-rendering.png and b/remote-content-api/src/docs/generated-diagrams/edge-side-rendering.png differ