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 2020/11/18 16:30:32 UTC

[sling-whiteboard] branch master updated: Switch to ContentMapper implementation (with the Java classes this time)

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 9b69bbd  Switch to ContentMapper implementation (with the Java classes this time)
9b69bbd is described below

commit 9b69bbd032e88e43379472e2f2ef2d53a3e229e4
Author: Bertrand Delacretaz <bd...@apache.org>
AuthorDate: Wed Nov 18 17:21:24 2020 +0100

    Switch to ContentMapper implementation (with the Java classes this time)
---
 .../apache/sling/contentmapper/ContentMapper.java  | 37 ++++++++++
 .../apache/sling/contentmapper/MappingTarget.java  | 40 +++++++++++
 .../sling/contentmapper/impl/ApiContentMapper.java | 46 ++++++++++++
 .../contentmapper/impl/ContentContentMapper.java   | 57 +++++++++++++++
 .../contentmapper/impl/JsonMappingTarget.java      | 34 +++++++++
 .../sling/contentmapper/impl/JsonTargetNode.java   | 84 ++++++++++++++++++++++
 .../impl/NavigationContentMapper.java              | 51 +++++++++++++
 .../org/apache/sling/testservlet/TestServlet.java  | 63 ++++++++++++++++
 .../org/apache/sling/testservlet/UrlBuilder.java   | 51 +++++++++++++
 9 files changed, 463 insertions(+)

diff --git a/remote-content-api/src/main/java/org/apache/sling/contentmapper/ContentMapper.java b/remote-content-api/src/main/java/org/apache/sling/contentmapper/ContentMapper.java
new file mode 100644
index 0000000..fd2eb14
--- /dev/null
+++ b/remote-content-api/src/main/java/org/apache/sling/contentmapper/ContentMapper.java
@@ -0,0 +1,37 @@
+/*
+ * 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.contentmapper;
+
+import org.apache.sling.api.resource.Resource;
+import org.jetbrains.annotations.NotNull;
+
+/**
+ * Maps Sling {@link Resource} to a {@link MappingTarget.TargetNode}
+ */
+public interface ContentMapper {
+
+    String ROLE = "sling.content.mapper.role";
+    
+    interface UrlBuilder {
+        String pathToUrl(String path);
+    }
+    
+    void map(@NotNull Resource r, @NotNull MappingTarget.TargetNode destination, UrlBuilder urlb);
+}
\ No newline at end of file
diff --git a/remote-content-api/src/main/java/org/apache/sling/contentmapper/MappingTarget.java b/remote-content-api/src/main/java/org/apache/sling/contentmapper/MappingTarget.java
new file mode 100644
index 0000000..33b0e2a
--- /dev/null
+++ b/remote-content-api/src/main/java/org/apache/sling/contentmapper/MappingTarget.java
@@ -0,0 +1,40 @@
+/*
+ * 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.contentmapper;
+
+import org.apache.sling.api.adapter.Adaptable;
+import org.jetbrains.annotations.NotNull;
+
+/**
+ * A target for content mapping, usually implemented by a Map of Maps, a JSON
+ * document tree, etc.
+ */
+public interface MappingTarget {
+    String TARGET_TYPE = "sling.mapping.target.type";
+
+    interface TargetNode extends Adaptable {
+        TargetNode addChild(String name);
+        TargetNode addValue(String name, Object value);
+        TargetNode addValue(String name, Object [] value);
+        void close();
+    }
+
+    @NotNull TargetNode newTargetNode();
+}
\ No newline at end of file
diff --git a/remote-content-api/src/main/java/org/apache/sling/contentmapper/impl/ApiContentMapper.java b/remote-content-api/src/main/java/org/apache/sling/contentmapper/impl/ApiContentMapper.java
new file mode 100644
index 0000000..7d5308f
--- /dev/null
+++ b/remote-content-api/src/main/java/org/apache/sling/contentmapper/impl/ApiContentMapper.java
@@ -0,0 +1,46 @@
+/*
+ * 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.contentmapper.impl;
+
+import org.apache.sling.api.resource.Resource;
+import org.apache.sling.contentmapper.ContentMapper;
+import org.apache.sling.contentmapper.MappingTarget;
+import org.jetbrains.annotations.NotNull;
+import org.osgi.service.component.annotations.Component;
+import org.osgi.service.component.annotations.Reference;
+
+@Component(service = ContentMapper.class, property = { ContentMapper.ROLE + "=api" })
+public class ApiContentMapper implements ContentMapper {
+
+    @Reference(target="(" + ContentMapper.ROLE + "=navigation)")
+    private ContentMapper navMapper;
+
+    @Reference(target="(" + ContentMapper.ROLE + "=content)")
+    private ContentMapper contentMapper;
+
+    @Override
+    public void map(@NotNull Resource r, @NotNull MappingTarget.TargetNode dest, UrlBuilder urlb) {
+        final MappingTarget.TargetNode n = dest.addChild("navigation");
+        navMapper.map(r, n, urlb);
+
+        final MappingTarget.TargetNode c = dest.addChild("content");
+        contentMapper.map(r, c, urlb);
+    }
+}
\ No newline at end of file
diff --git a/remote-content-api/src/main/java/org/apache/sling/contentmapper/impl/ContentContentMapper.java b/remote-content-api/src/main/java/org/apache/sling/contentmapper/impl/ContentContentMapper.java
new file mode 100644
index 0000000..d1f83e0
--- /dev/null
+++ b/remote-content-api/src/main/java/org/apache/sling/contentmapper/impl/ContentContentMapper.java
@@ -0,0 +1,57 @@
+/*
+ * 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.contentmapper.impl;
+
+import java.util.Arrays;
+import java.util.Map;
+
+import org.apache.sling.api.resource.Resource;
+import org.apache.sling.api.resource.ValueMap;
+import org.apache.sling.contentmapper.ContentMapper;
+import org.apache.sling.contentmapper.MappingTarget;
+import org.jetbrains.annotations.NotNull;
+import org.osgi.service.component.annotations.Component;
+
+@Component(service = ContentMapper.class, property = { ContentMapper.ROLE + "=content" })
+public class ContentContentMapper implements ContentMapper {
+
+    @Override
+    public void map(@NotNull Resource r, @NotNull MappingTarget.TargetNode dest, UrlBuilder urlb) {
+        dest
+            .addValue("source", getClass().getName())
+            .addValue("path", r.getPath())
+        ;
+        addValues(dest, r);
+    }
+
+    private static void addValues(MappingTarget.TargetNode dest, Resource r) {
+        final ValueMap vm = r.adaptTo(ValueMap.class);
+        if(vm != null) {
+            for(Map.Entry<String, Object> e : vm.entrySet()) {
+                final Object value = e.getValue();
+                if(value instanceof Object[]) {
+                    dest.addValue(e.getKey(), Arrays.asList((Object[])value));
+                } else {
+                    dest.addValue(e.getKey(), String.valueOf(value));
+                }
+            }
+        }
+    }
+}
\ No newline at end of file
diff --git a/remote-content-api/src/main/java/org/apache/sling/contentmapper/impl/JsonMappingTarget.java b/remote-content-api/src/main/java/org/apache/sling/contentmapper/impl/JsonMappingTarget.java
new file mode 100644
index 0000000..b85fdfb
--- /dev/null
+++ b/remote-content-api/src/main/java/org/apache/sling/contentmapper/impl/JsonMappingTarget.java
@@ -0,0 +1,34 @@
+/*
+ * 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.contentmapper.impl;
+
+import org.apache.sling.contentmapper.MappingTarget;
+import org.jetbrains.annotations.NotNull;
+import org.osgi.service.component.annotations.Component;
+
+/** MappingTarget that outputs to a JSON document */
+@Component(service = MappingTarget.class, property = { MappingTarget.TARGET_TYPE + "=json" })
+public class JsonMappingTarget implements MappingTarget {
+
+    @Override
+    public @NotNull TargetNode newTargetNode() {
+        return new JsonTargetNode("ROOT_THIS_NAME_SHOULD_NOT_APPEAR_IN_OUTPUT");
+    }
+}
\ No newline at end of file
diff --git a/remote-content-api/src/main/java/org/apache/sling/contentmapper/impl/JsonTargetNode.java b/remote-content-api/src/main/java/org/apache/sling/contentmapper/impl/JsonTargetNode.java
new file mode 100644
index 0000000..1d51c0c
--- /dev/null
+++ b/remote-content-api/src/main/java/org/apache/sling/contentmapper/impl/JsonTargetNode.java
@@ -0,0 +1,84 @@
+/*
+ * 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.contentmapper.impl;
+
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.List;
+
+import javax.json.Json;
+import javax.json.JsonObjectBuilder;
+
+import org.apache.sling.contentmapper.MappingTarget;
+import org.apache.sling.contentmapper.MappingTarget.TargetNode;
+
+/** A TargetNode that outputs to a JSON document */
+public class JsonTargetNode implements MappingTarget.TargetNode {
+
+    private final String name;
+    private final JsonObjectBuilder builder;
+    private List<JsonTargetNode> children;
+
+    JsonTargetNode(String name) {
+        this.name = name;
+        this.builder = Json.createObjectBuilder();
+    }
+
+    @Override
+    public TargetNode addChild(String name) {
+        if(children == null) {
+            children = new ArrayList<>();
+        }
+        final JsonTargetNode child = new JsonTargetNode(name);
+        children.add(child);
+        return child;
+    }
+
+    @Override
+    public TargetNode addValue(String name, Object value) {
+        builder.add(name, String.valueOf(value));
+        return this;
+    }
+
+    @Override
+    public TargetNode addValue(String name, Object[] value) {
+        builder.add(name, String.valueOf(Arrays.asList(value)));
+        return this;
+    }
+
+    @Override
+    public <AdapterType> AdapterType adaptTo(Class<AdapterType> type) {
+        if(type.equals(String.class)) {
+            close();
+            return (AdapterType)builder.build().toString();
+        }
+        throw new IllegalArgumentException("For now, can only adapt to a String");
+    }
+
+    @Override
+    public void close() {
+        if(children != null) {
+            children.stream().forEach(c -> {
+                c.close();
+                builder.add(c.name, c.builder);
+            });
+        }
+    }
+}
\ No newline at end of file
diff --git a/remote-content-api/src/main/java/org/apache/sling/contentmapper/impl/NavigationContentMapper.java b/remote-content-api/src/main/java/org/apache/sling/contentmapper/impl/NavigationContentMapper.java
new file mode 100644
index 0000000..22aa79a
--- /dev/null
+++ b/remote-content-api/src/main/java/org/apache/sling/contentmapper/impl/NavigationContentMapper.java
@@ -0,0 +1,51 @@
+/*
+ * 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.contentmapper.impl;
+
+import java.util.Map;
+
+import org.apache.sling.api.resource.Resource;
+import org.apache.sling.contentmapper.ContentMapper;
+import org.apache.sling.contentmapper.MappingTarget;
+import org.jetbrains.annotations.NotNull;
+import org.osgi.service.component.annotations.Component;
+
+@Component(service = ContentMapper.class, property = { ContentMapper.ROLE + "=navigation" })
+public class NavigationContentMapper implements ContentMapper {
+
+    @Override
+    public void map(@NotNull Resource r, @NotNull MappingTarget.TargetNode dest, UrlBuilder urlb) {
+        dest.addValue("self", urlb.pathToUrl(r.getPath()));
+        
+        final Resource parent = r.getParent();
+        if(parent != null) {
+            dest.addValue("parent", urlb.pathToUrl(parent.getPath()));
+        }
+
+        final MappingTarget.TargetNode children = dest.addChild("children");
+        for(Resource child : r.getChildren()) {
+            children
+                .addChild(child.getName())
+                .addValue("url", urlb.pathToUrl(child.getPath()))
+                .addValue("path", child.getPath())
+            ;
+        }
+    }
+}
\ No newline at end of file
diff --git a/remote-content-api/src/main/java/org/apache/sling/testservlet/TestServlet.java b/remote-content-api/src/main/java/org/apache/sling/testservlet/TestServlet.java
new file mode 100644
index 0000000..0462669
--- /dev/null
+++ b/remote-content-api/src/main/java/org/apache/sling/testservlet/TestServlet.java
@@ -0,0 +1,63 @@
+/*
+ * 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.testservlet;
+
+import java.io.IOException;
+
+import javax.servlet.Servlet;
+
+import org.apache.sling.api.SlingHttpServletRequest;
+import org.apache.sling.api.SlingHttpServletResponse;
+import org.apache.sling.api.servlets.SlingSafeMethodsServlet;
+import org.apache.sling.contentmapper.ContentMapper;
+import org.apache.sling.contentmapper.MappingTarget;
+import org.osgi.service.component.annotations.Component;
+import org.osgi.service.component.annotations.Reference;
+
+/** Render the current Resource to JSON */
+@Component(service = Servlet.class,
+    property = {
+            "sling.servlet.resourceTypes=sling/servlet/default",
+            "sling.servlet.prefix:Integer=-1",
+
+            "sling.servlet.methods=GET",
+            "sling.servlet.methods=HEAD",
+            "sling.servlet.selectors=s:ts",
+            "sling.servlet.extension=json",
+    })
+public class TestServlet extends SlingSafeMethodsServlet {
+    private static final long serialVersionUID = 1L;
+
+    @Reference(target="(" + MappingTarget.TARGET_TYPE + "=json)")
+    private transient MappingTarget mappingTarget;
+
+    @Reference(target="(" + ContentMapper.ROLE + "=api)")
+    private transient ContentMapper contentMapper;
+
+    @Override
+    public void doGet(SlingHttpServletRequest request, SlingHttpServletResponse response) throws IOException {
+
+        MappingTarget.TargetNode target = mappingTarget.newTargetNode();
+        contentMapper.map(request.getResource(), target, new UrlBuilder(request));
+        response.setCharacterEncoding("UTF-8");
+        response.setContentType("application/json");
+        response.getWriter().write(target.adaptTo(String.class));
+    }
+}
\ No newline at end of file
diff --git a/remote-content-api/src/main/java/org/apache/sling/testservlet/UrlBuilder.java b/remote-content-api/src/main/java/org/apache/sling/testservlet/UrlBuilder.java
new file mode 100644
index 0000000..43cd0ae
--- /dev/null
+++ b/remote-content-api/src/main/java/org/apache/sling/testservlet/UrlBuilder.java
@@ -0,0 +1,51 @@
+/*
+ * 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.testservlet;
+
+import org.apache.sling.api.SlingHttpServletRequest;
+import org.apache.sling.contentmapper.ContentMapper;
+
+class UrlBuilder implements ContentMapper.UrlBuilder {
+    private SlingHttpServletRequest request;
+
+    UrlBuilder(SlingHttpServletRequest request) {
+        this.request = request;
+    }
+
+    public String pathToUrlNoExtension(String path) {
+        return String.format(
+            "%s://%s:%d%s",
+            request.getScheme(),
+            request.getServerName(),
+            request.getServerPort(),
+            path
+        );
+    }
+
+    @Override
+    public String pathToUrl(String path) {
+        return String.format(
+            "%s.%s.%s",
+            pathToUrlNoExtension(path),
+            request.getRequestPathInfo().getSelectorString(),
+            request.getRequestPathInfo().getExtension()
+        );
+    }
+}
\ No newline at end of file