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

reschke pushed a commit to branch OAK-10952
in repository https://gitbox.apache.org/repos/asf/jackrabbit-oak.git

commit 1713fd5352342afb0e6bc1d45d2059dc67d54735
Author: Julian Reschke <[email protected]>
AuthorDate: Thu Apr 17 12:59:41 2025 +0100

    OAK-10952: improve autogenerated namespace prefixes - test with prototype
---
 .../oak/commons/NamespaceHelperPrototypeTest.java  | 157 +++++++++++++++++++++
 1 file changed, 157 insertions(+)

diff --git 
a/oak-commons/src/test/java/org/apache/jackrabbit/oak/commons/NamespaceHelperPrototypeTest.java
 
b/oak-commons/src/test/java/org/apache/jackrabbit/oak/commons/NamespaceHelperPrototypeTest.java
new file mode 100644
index 0000000000..0ac437c055
--- /dev/null
+++ 
b/oak-commons/src/test/java/org/apache/jackrabbit/oak/commons/NamespaceHelperPrototypeTest.java
@@ -0,0 +1,157 @@
+/*
+ * 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.jackrabbit.oak.commons;
+
+// experimental location for prototyping namespace related support functions
+
+import org.jetbrains.annotations.NotNull;
+import org.junit.Test;
+
+import java.nio.charset.StandardCharsets;
+import java.util.Base64;
+import java.util.Locale;
+import java.util.Map;
+import java.util.UUID;
+import java.util.function.Function;
+
+import static org.junit.Assert.assertEquals;
+
+public class NamespaceHelperPrototypeTest {
+
+    private static final Map<String, String> KNOWN_PREFIXES =
+            Map.of("http://purl.org/dc/terms/";, "dc",
+                    "http://ns.adobe.com/exif/1.0/";, "exif");
+
+    private static @NotNull String suggestPrefix(@NotNull String namespace,
+                                                 @NotNull Function<String, 
String> lookupPrefix) {
+        // try hard-wired map
+        String known = KNOWN_PREFIXES.get(namespace);
+
+        // lookup using supplied mapper as well
+        String lookedUpNamespace = known != null ? lookupPrefix.apply(known) : 
null;
+
+        // return hardwired prefix if unused or mapper has the prefix mapped 
to the same namespace
+        if (known != null && (lookedUpNamespace == null || 
namespace.equals(lookedUpNamespace))) {
+            return known;
+        } else {
+            return makeUpPrefix(namespace, lookupPrefix);
+        }
+    }
+
+    private static @NotNull String suggestPrefix(String namespace) {
+        return suggestPrefix(namespace, n -> null);
+    }
+
+    private static @NotNull String makeUpPrefix(@NotNull String namespace,
+                                       @NotNull Function<String, String> 
lookupNamespace) {
+        String prefix = namespace.toLowerCase(Locale.ENGLISH);
+
+        // https://www.w3.org/guide/editor/namespaces.html
+        if (prefix.startsWith("http://www.w3c.org/ns/";)) {
+            prefix = prefix.substring(22);
+        }
+
+        // strip scheme when http(s)
+        if (prefix.startsWith("http://";)) {
+            prefix = prefix.substring(7);
+        } else if (prefix.startsWith("https://";)) {
+            prefix = prefix.substring(8);
+        }
+
+        // strip common host name prefixes
+        if (prefix.startsWith("www.")) {
+            prefix = prefix.substring(4);
+        } else if (prefix.startsWith("ns")) {
+            prefix = prefix.substring(3);
+        }
+
+        // strip trailing slash
+        if (prefix.endsWith("/")) {
+            prefix = prefix.substring(0, prefix.length() - 1);
+        }
+
+        // TODO: make sure it's really a valid JCR name prefix
+        prefix = prefix.replace("/", "-");
+
+        String lookedUpNamespace = lookupNamespace.apply(prefix);
+        if (lookedUpNamespace == null || lookedUpNamespace.equals(namespace)) {
+            return prefix;
+        } else {
+            return makeUpPrefixTryEvenHarder(namespace, lookupNamespace);
+        }
+    }
+
+    private static @NotNull String makeUpPrefixTryEvenHarder(@NotNull String 
namespace,
+                                                             @NotNull 
Function<String, String> lookupNamespace) {
+
+        String prefix = "b64-" + 
Base64.getUrlEncoder().withoutPadding().encodeToString(namespace.getBytes(StandardCharsets.UTF_8));
+        String lookedUpNamespace = lookupNamespace.apply(prefix);
+        if (lookedUpNamespace == null || lookedUpNamespace.equals(namespace)) {
+            return prefix;
+        } else {
+            // ok, we're giving up
+            while (namespace.equals(lookupNamespace.apply(prefix))) {
+                prefix = "uuid-" + UUID.randomUUID();
+            }
+            return prefix;
+        }
+    }
+
+    @Test
+    public void testSuggestPrefix() {
+
+        // hardwired
+        assertEquals("dc", suggestPrefix("http://purl.org/dc/terms/";));
+        assertEquals("exif", suggestPrefix("http://ns.adobe.com/exif/1.0/";));
+
+        // unknown namespace, just scheme and host name
+        assertEquals("example.org", suggestPrefix("https://example.org";));
+        assertEquals("example.org", suggestPrefix("http://example.org";));
+        assertEquals("example.org", suggestPrefix("http://ns.example.org/";));
+        assertEquals("example.org", suggestPrefix("https://www.example.org";));
+
+        // W3C rules
+        assertEquals("foobar", suggestPrefix("http://www.w3c.org/ns/foobar";));
+
+        // unknown namespace, ... with path
+        assertEquals("example.org-foo", 
suggestPrefix("https://www.example.org/foo";));
+    }
+
+    @Test
+    public void testSuggestPrefixWithExistingPrefixes() {
+
+        // prefix that would be suggested is already mapped to the provided 
namespace
+        assertEquals("dc", suggestPrefix("http://purl.org/dc/terms/";,
+                Map.of("http://purl.org/dc/terms/";, "dc")::get));
+
+        // use of hardwired prefix will not work as that prefix is already 
mapped to a different namespace
+        assertEquals("purl.org-dc-terms", 
suggestPrefix("http://purl.org/dc/terms/";,
+                Map.of("dc", "http://purl.org/dc/terms/somethingelse";)::get));
+
+        // lookup generated by simple extraction from namespace name will not 
work as prefix is already assigned
+        // -> generate based on base64 encoding
+        assertEquals("b64-aHR0cDovL3B1cmwub3JnL2RjL3Rlcm1zLw", 
suggestPrefix("http://purl.org/dc/terms/";,
+                Map.of("dc", "http://purl.org/dc/terms/somethingelse";,
+                        "purl.org-dc-terms", 
"http://purl.org/dc/terms/somethingelse";)::get));
+
+        // if even *that* fails
+        assertEquals("b64-aHR0cDovL3B1cmwub3JnL2RjL3Rlcm1zLw", 
suggestPrefix("http://purl.org/dc/terms/";,
+                Map.of("dc", "http://purl.org/dc/terms/somethingelse";,
+                        "purl.org-dc-terms", 
"http://purl.org/dc/terms/somethingelse";,
+                        "b64-aHR0cDovL3B1cmwub3JnL2RjL3Rlcm1zLw", 
"http://purl.org/dc/terms/somethingelse";)::get));
+    }
+}

Reply via email to