You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@sling.apache.org by ra...@apache.org on 2020/03/06 17:29:02 UTC

[sling-org-apache-sling-scripting-bundle-tracker] branch master updated: SLING-9181 - The Scripting Bundle Tracker should be extended to allow more flexibility for resource type definitions

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

radu pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/sling-org-apache-sling-scripting-bundle-tracker.git


The following commit(s) were added to refs/heads/master by this push:
     new ee23513  SLING-9181 - The Scripting Bundle Tracker should be extended to allow more flexibility for resource type definitions
ee23513 is described below

commit ee235138cafd6d775387ada813d964f9eb9f18c0
Author: Radu Cotescu <ra...@apache.org>
AuthorDate: Fri Mar 6 18:27:04 2020 +0100

    SLING-9181 - The Scripting Bundle Tracker should be extended to allow more flexibility for resource type definitions
    
    * added a unified way to parse resource type strings
---
 .../tracker/internal/BundledScriptFinder.java      |  25 ++--
 .../tracker/internal/BundledScriptTracker.java     |  18 +--
 .../tracker/internal/ResourceTypeParser.java       | 134 +++++++++++++++++++++
 .../tracker/internal/ResourceTypeParserTest.java   |  87 +++++++++++++
 4 files changed, 239 insertions(+), 25 deletions(-)

diff --git a/src/main/java/org/apache/sling/scripting/bundle/tracker/internal/BundledScriptFinder.java b/src/main/java/org/apache/sling/scripting/bundle/tracker/internal/BundledScriptFinder.java
index f967a4a..0bc350d 100644
--- a/src/main/java/org/apache/sling/scripting/bundle/tracker/internal/BundledScriptFinder.java
+++ b/src/main/java/org/apache/sling/scripting/bundle/tracker/internal/BundledScriptFinder.java
@@ -81,22 +81,20 @@ public class BundledScriptFinder {
 
     private List<String> buildScriptMatches(SlingHttpServletRequest request, String providerType) {
         List<String> matches = new ArrayList<>();
-        String resourceType = providerType;
-        String version = null;
         String method = request.getMethod();
         boolean defaultMethod = DEFAULT_METHODS.contains(method);
-        if (resourceType.contains(SLASH) && StringUtils.countMatches(resourceType, SLASH) == 1) {
-            version = resourceType.substring(resourceType.indexOf(SLASH) + 1);
-            resourceType = resourceType.substring(0, resourceType.length() - version.length() - 1);
-        }
+        ResourceTypeParser.ResourceType resourceType = ResourceTypeParser.parseResourceType(providerType);
         String extension = request.getRequestPathInfo().getExtension();
         String[] selectors = request.getRequestPathInfo().getSelectors();
         if (selectors.length > 0) {
             for (int i = selectors.length - 1; i >= 0; i--) {
-                String scriptForMethod = resourceType + (StringUtils.isNotEmpty(version) ? SLASH + version + SLASH : SLASH) +
+                String scriptForMethod = resourceType.getType() +
+                        (StringUtils.isNotEmpty(resourceType.getVersion()) ? SLASH + resourceType.getVersion() + SLASH : SLASH) +
                         method + DOT + String.join(SLASH, Arrays.copyOf(selectors, i + 1));
-                String scriptNoMethod = resourceType + (StringUtils.isNotEmpty(version) ? SLASH + version + SLASH : SLASH) + String.join
-                        (SLASH, Arrays.copyOf(selectors, i + 1));
+                String scriptNoMethod = resourceType.getType() +
+                        (StringUtils.isNotEmpty(resourceType.getVersion()) ? SLASH + resourceType.getVersion() + SLASH : SLASH) +
+                        String.join
+                                (SLASH, Arrays.copyOf(selectors, i + 1));
                 if (StringUtils.isNotEmpty(extension)) {
                     if (defaultMethod) {
                         matches.add(scriptNoMethod + DOT + extension);
@@ -109,15 +107,16 @@ public class BundledScriptFinder {
                 matches.add(scriptForMethod);
             }
         }
-        String scriptForMethod = resourceType + (StringUtils.isNotEmpty(version) ? SLASH + version + SLASH : SLASH) + method;
-        String scriptNoMethod = resourceType + (StringUtils.isNotEmpty(version) ? SLASH + version + SLASH : SLASH) + resourceType
-                .substring(resourceType.lastIndexOf(DOT) + 1);
+        String scriptForMethod = resourceType.getType() +
+                (StringUtils.isNotEmpty(resourceType.getVersion()) ? SLASH + resourceType.getVersion() + SLASH : SLASH) + method;
+        String scriptNoMethod = resourceType.getType() +
+                (StringUtils.isNotEmpty(resourceType.getVersion()) ? SLASH + resourceType.getVersion() + SLASH : SLASH) +
+                resourceType.getResourceLabel();
         if (StringUtils.isNotEmpty(extension)) {
             if (defaultMethod) {
                 matches.add(scriptNoMethod + DOT + extension);
             }
             matches.add(scriptForMethod + DOT + extension);
-
         }
         if (defaultMethod) {
             matches.add(scriptNoMethod);
diff --git a/src/main/java/org/apache/sling/scripting/bundle/tracker/internal/BundledScriptTracker.java b/src/main/java/org/apache/sling/scripting/bundle/tracker/internal/BundledScriptTracker.java
index ef16eb4..b4841e5 100644
--- a/src/main/java/org/apache/sling/scripting/bundle/tracker/internal/BundledScriptTracker.java
+++ b/src/main/java/org/apache/sling/scripting/bundle/tracker/internal/BundledScriptTracker.java
@@ -288,22 +288,16 @@ public class BundledScriptTracker implements BundleTrackerCustomizer<List<Servic
 
     private String getResourceType(Hashtable<String, Object> props) {
         String[] values = PropertiesUtil.toStringArray(props.get(ServletResolverConstants.SLING_SERVLET_RESOURCE_TYPES));
-        int idx = values[0].indexOf("/");
-        if (idx != -1) {
-            return values[0].substring(0, idx);
-        } else {
-            return values[0];
-        }
+        String resourceTypeValue = values[0];
+        ResourceTypeParser.ResourceType resourceType = ResourceTypeParser.parseResourceType(resourceTypeValue);
+        return resourceType.getType();
     }
 
     private String getResourceTypeVersion(ServiceReference<?> ref) {
         String[] values = PropertiesUtil.toStringArray(ref.getProperty(ServletResolverConstants.SLING_SERVLET_RESOURCE_TYPES));
-        int idx = values[0].indexOf("/");
-        if (idx != -1) {
-            return values[0].substring(idx + 1);
-        } else {
-            return null;
-        }
+        String resourceTypeValue = values[0];
+        ResourceTypeParser.ResourceType resourceType = ResourceTypeParser.parseResourceType(resourceTypeValue);
+        return resourceType.getVersion();
     }
 
     private void set(String key, ServiceReference<?> ref, Hashtable<String, Object> props) {
diff --git a/src/main/java/org/apache/sling/scripting/bundle/tracker/internal/ResourceTypeParser.java b/src/main/java/org/apache/sling/scripting/bundle/tracker/internal/ResourceTypeParser.java
new file mode 100644
index 0000000..122a85c
--- /dev/null
+++ b/src/main/java/org/apache/sling/scripting/bundle/tracker/internal/ResourceTypeParser.java
@@ -0,0 +1,134 @@
+/*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ ~ 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.scripting.bundle.tracker.internal;
+
+import org.apache.commons.lang3.StringUtils;
+import org.jetbrains.annotations.NotNull;
+import org.jetbrains.annotations.Nullable;
+import org.osgi.framework.Version;
+
+/**
+ * The {@code ResourceTypeParser} provides methods for parsing resource type strings.
+ *
+ * <p>The following patterns are supported:</p>
+ * <ol>
+ * <li><tt>a/b/c</tt> - path-based</li>
+ * <li><tt>a/b/c/1.0.0</tt> - path-based, versioned</li>
+ * <li><tt>a.b.c</tt> - Java package name</li>
+ * <li><tt>a.b.c/1.0.0</tt> - Java package name, versioned</li>
+ * <li><tt>a</tt> - flat (sub-set of path-based)</li>
+ * </ol>
+ */
+final class ResourceTypeParser {
+
+    private ResourceTypeParser() {
+    }
+
+    /**
+     * The {@code ResourceType} class encapsulates the details about a resource type.
+     */
+    static class ResourceType {
+        private final String type;
+        private final String version;
+        private final String resourceLabel;
+
+        private ResourceType(@NotNull String type, @Nullable String version) {
+            this.type = type;
+            this.version = version;
+            if (type.lastIndexOf('/') != -1) {
+                resourceLabel = type.substring(type.lastIndexOf('/') + 1);
+            } else if (type.lastIndexOf('.') != -1) {
+                resourceLabel = type.substring(type.lastIndexOf('.') + 1);
+            } else {
+                resourceLabel = type;
+            }
+        }
+
+        /**
+         * Returns a resource type's label. The label is important for script selection, since it will provide the name of the main script
+         * for this resource type. For more details check the Apache Sling
+         * <a href="https://sling.apache.org/documentation/the-sling-engine/url-to-script-resolution.html#scripts-for-get-requests">URL to
+         * Script Resolution</a> page
+         *
+         * @return the resource type label
+         */
+        @NotNull
+        public String getResourceLabel() {
+            return resourceLabel;
+        }
+
+        /**
+         * Returns the resource type string, without any version information.
+         *
+         * @return the resource type string
+         */
+        @NotNull
+        String getType() {
+            return type;
+        }
+
+        /**
+         * Returns the version, if available.
+         *
+         * @return the version, if available; {@code null} otherwise
+         */
+        @Nullable
+        String getVersion() {
+            return version;
+        }
+    }
+
+    /**
+     * Given a {@code resourceTypeString}, this method will extract a {@link ResourceType} object.
+     * <p>The accepted patterns are:</p>
+     * <ol>
+     * <li><tt>a/b/c</tt> - path-based</li>
+     * <li><tt>a/b/c/1.0.0</tt> - path-based, versioned</li>
+     * <li><tt>a.b.c</tt> - Java package name</li>
+     * <li><tt>a.b.c/1.0.0</tt> - Java package name, versioned</li>
+     * <li><tt>a</tt> - flat (sub-set of path-based)</li>
+     * </ol>
+     *
+     * @param resourceTypeString the resource type string to parse
+     * @return a {@link ResourceType} object
+     * @throws IllegalArgumentException if the {@code resourceTypeString} cannot be parsed
+     */
+    @NotNull
+    static ResourceType parseResourceType(@NotNull String resourceTypeString) {
+        String type = StringUtils.EMPTY;
+        String version = null;
+        if (StringUtils.isNotEmpty(resourceTypeString)) {
+            int lastSlash = resourceTypeString.lastIndexOf('/');
+            if (lastSlash != -1 && !resourceTypeString.endsWith("/")) {
+                try {
+                    version = Version.parseVersion(resourceTypeString.substring(lastSlash + 1)).toString();
+                    type = resourceTypeString.substring(0, lastSlash);
+                } catch (IllegalArgumentException e) {
+                    type = resourceTypeString;
+                }
+            } else {
+                type = resourceTypeString;
+            }
+        }
+        if (StringUtils.isEmpty(type)) {
+            throw new IllegalArgumentException(String.format("Cannot extract a type for the resourceTypeString %s.", resourceTypeString));
+        }
+        return new ResourceType(type, version);
+    }
+}
diff --git a/src/test/java/org/apache/sling/scripting/bundle/tracker/internal/ResourceTypeParserTest.java b/src/test/java/org/apache/sling/scripting/bundle/tracker/internal/ResourceTypeParserTest.java
new file mode 100644
index 0000000..47f92ef
--- /dev/null
+++ b/src/test/java/org/apache/sling/scripting/bundle/tracker/internal/ResourceTypeParserTest.java
@@ -0,0 +1,87 @@
+/*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ ~ 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.scripting.bundle.tracker.internal;
+
+import org.apache.commons.lang3.StringUtils;
+import org.junit.Test;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNull;
+
+public class ResourceTypeParserTest {
+
+    @Test
+    public void testSlashNoVersion() {
+        ResourceTypeParser.ResourceType t1 = ResourceTypeParser.parseResourceType("a/b/c");
+        assertEquals("a/b/c", t1.getType());
+        assertEquals("c", t1.getResourceLabel());
+        assertNull(t1.getVersion());
+    }
+
+    @Test
+    public void testSlashVersion() {
+        ResourceTypeParser.ResourceType t1 = ResourceTypeParser.parseResourceType("a/b/c/1.0.0");
+        assertEquals("a/b/c", t1.getType());
+        assertEquals("c", t1.getResourceLabel());
+        assertEquals("1.0.0", t1.getVersion());
+    }
+
+    @Test
+    public void testOneSegmentNoVersion() {
+        ResourceTypeParser.ResourceType t1 = ResourceTypeParser.parseResourceType("a");
+        assertEquals("a", t1.getType());
+        assertEquals("a", t1.getResourceLabel());
+        assertNull(t1.getVersion());
+    }
+
+    @Test
+    public void testOneSegmentVersion() {
+        ResourceTypeParser.ResourceType t1 = ResourceTypeParser.parseResourceType("a/1.2.3");
+        assertEquals("a", t1.getType());
+        assertEquals("a", t1.getResourceLabel());
+        assertEquals("1.2.3", t1.getVersion());
+    }
+
+    @Test
+    public void testDotNoVersion() {
+        ResourceTypeParser.ResourceType t1 = ResourceTypeParser.parseResourceType("a.b.c");
+        assertEquals("a.b.c", t1.getType());
+        assertEquals("c", t1.getResourceLabel());
+        assertNull(t1.getVersion());
+    }
+
+    @Test
+    public void testDotVersion() {
+        ResourceTypeParser.ResourceType t1 = ResourceTypeParser.parseResourceType("a.b.c/42.0.0");
+        assertEquals("a.b.c", t1.getType());
+        assertEquals("c", t1.getResourceLabel());
+        assertEquals("42.0.0", t1.getVersion());
+    }
+
+    @Test(expected = IllegalArgumentException.class)
+    public void testEmptyString() {
+        ResourceTypeParser.ResourceType t1 = ResourceTypeParser.parseResourceType(StringUtils.EMPTY);
+    }
+
+    @Test(expected = IllegalArgumentException.class)
+    public void testNull() {
+        ResourceTypeParser.ResourceType t1 = ResourceTypeParser.parseResourceType(null);
+    }
+
+}