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

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


The following commit(s) were added to refs/heads/trunk by this push:
     new 43619290a5 OAK-10760: oak-core should check namespace registry 
consistency on st… (#1447)
43619290a5 is described below

commit 43619290a5ebdc9c60aa9d1929f796e5033f59da
Author: mbaedke <manfred.bae...@gmail.com>
AuthorDate: Fri May 17 18:54:43 2024 +0200

    OAK-10760: oak-core should check namespace registry consistency on st… 
(#1447)
    
    * OAK-10760: oak-core should check namespace registry consistency on startup
    
    Implemented.
    
    * OAK-10760: oak-core should check namespace registry consistency on startup
    
    Removed Guava usage, improved log messages.
    
    * OAK-10760: oak-core should check namespace registry consistency on startup
    
    Added flag to avoid multiple consistency checks.
    
    * OAK-10760: oak-core should check namespace registry consistency on startup
    
    Fixed property miscount and URI encoding issues.
---
 .../plugins/name/ReadOnlyNamespaceRegistry.java    | 76 +++++++++++++++++++++-
 1 file changed, 73 insertions(+), 3 deletions(-)

diff --git 
a/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/name/ReadOnlyNamespaceRegistry.java
 
b/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/name/ReadOnlyNamespaceRegistry.java
index 87d12054d4..ddf6509ce0 100644
--- 
a/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/name/ReadOnlyNamespaceRegistry.java
+++ 
b/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/name/ReadOnlyNamespaceRegistry.java
@@ -16,7 +16,6 @@
  */
 package org.apache.jackrabbit.oak.plugins.name;
 
-import static org.apache.jackrabbit.guava.common.collect.Iterables.toArray;
 import static java.util.Collections.emptyList;
 import static org.apache.jackrabbit.oak.api.Type.STRING;
 import static org.apache.jackrabbit.oak.api.Type.STRINGS;
@@ -26,11 +25,19 @@ import javax.jcr.NamespaceRegistry;
 import javax.jcr.RepositoryException;
 import javax.jcr.UnsupportedRepositoryOperationException;
 
+import org.apache.jackrabbit.util.Text;
 import org.apache.jackrabbit.oak.api.PropertyState;
 import org.apache.jackrabbit.oak.api.Root;
 import org.apache.jackrabbit.oak.api.Tree;
 import org.apache.jackrabbit.oak.spi.namespace.NamespaceConstants;
 import org.jetbrains.annotations.NotNull;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.List;
+import java.util.stream.Collectors;
 
 /**
  * Read-only namespace registry. Used mostly internally when access to the
@@ -42,12 +49,19 @@ import org.jetbrains.annotations.NotNull;
 public class ReadOnlyNamespaceRegistry
         implements NamespaceRegistry, NamespaceConstants {
 
+    private static final Logger LOG = 
LoggerFactory.getLogger(ReadOnlyNamespaceRegistry.class);
+
+    private static volatile boolean CONSISTENCY_CHECKED;
+
     protected final Tree namespaces;
     protected final Tree nsdata;
 
     public ReadOnlyNamespaceRegistry(Root root) {
         this.namespaces = root.getTree(NAMESPACES_PATH);
         this.nsdata = namespaces.getChild(REP_NSDATA);
+        if (!CONSISTENCY_CHECKED) {
+            checkConsistency();
+        }
     }
 
     private Iterable<String> getNSData(String name) {
@@ -74,12 +88,16 @@ public class ReadOnlyNamespaceRegistry
 
     @Override @NotNull
     public String[] getPrefixes() {
-        return toArray(getNSData(REP_PREFIXES), String.class);
+        List<String> prefixes = new ArrayList();
+        getNSData(REP_PREFIXES).forEach(prefixes::add);
+        return prefixes.toArray(new String[prefixes.size()]);
     }
 
     @Override @NotNull
     public String[] getURIs() {
-        return toArray(getNSData(REP_URIS), String.class);
+        List<String> uris = new ArrayList<>();
+        getNSData(REP_URIS).forEach(uris::add);
+        return uris.toArray(new String[uris.size()]);
     }
 
     @Override @NotNull
@@ -112,4 +130,56 @@ public class ReadOnlyNamespaceRegistry
                 "No namespace prefix registered for URI " + uri);
     }
 
+    protected void checkConsistency() {
+        final String jcrPrimaryType = "jcr:primaryType";
+        List<String> prefixes = Arrays.asList(getPrefixes());
+        List<String> encodedUris = 
Arrays.stream(getURIs()).map(Namespaces::encodeUri).collect(Collectors.toList());
+        if (prefixes.size() != encodedUris.size()) {
+            LOG.error("The namespace registry is inconsistent: found {} 
registered namespace prefixes and {} registered namespace URIs. The numbers 
have to be equal.", prefixes.size(), encodedUris.size());
+        }
+        int mappedPrefixCount = 0;
+        for (PropertyState propertyState : namespaces.getProperties()) {
+            String prefix = propertyState.getName();
+            if (!prefix.equals(jcrPrimaryType)) {
+                mappedPrefixCount++;
+                if (!prefixes.contains(prefix)) {
+                    LOG.error("The namespace registry is inconsistent: 
namespace prefix {} is mapped to a namespace URI, but not contained in the list 
of registered namespace prefixes.", prefix);
+                }
+                try {
+                    getURI(prefix);
+                } catch (NamespaceException e) {
+                    LOG.error("The namespace registry is inconsistent: 
namespace prefix {} is not mapped to a namespace URI.", prefix);
+                }
+            }
+        }
+        //prefixes contains the unmapped empty prefix
+        if (mappedPrefixCount + 1 != prefixes.size()) {
+            LOG.error("The namespace registry is inconsistent: found {} mapped 
namespace prefixes and {} registered namespace prefixes. The numbers have to be 
equal.", mappedPrefixCount, prefixes.size());
+        }
+        int mappedUriCount = 0;
+        for (PropertyState propertyState : nsdata.getProperties()) {
+            String encodedUri = propertyState.getName();
+            switch (encodedUri) {
+                case REP_PREFIXES:
+                case REP_URIS:
+                case jcrPrimaryType:
+                    break;
+                default:
+                    mappedUriCount++;
+                    if (!encodedUris.contains(encodedUri)) {
+                        LOG.error("The namespace registry is inconsistent: 
encoded namespace URI {} is mapped to a namespace prefix, but not contained in 
the list of registered namespace URIs.", encodedUri);
+                    }
+                    try {
+                        getPrefix(Text.unescapeIllegalJcrChars(encodedUri));
+                    } catch (NamespaceException e) {
+                        LOG.error("The namespace registry is inconsistent: 
namespace URI {} is not mapped to a namespace prefix.", encodedUri);
+                    }
+            }
+        }
+        //encodedUris contains the unmapped empty namespace URI
+        if (mappedUriCount + 1 != encodedUris.size()) {
+            LOG.error("The namespace registry is inconsistent: found {} mapped 
namespace URIs and {} registered namespace URIs. The numbers have to be 
equal.", mappedUriCount, encodedUris.size());
+        }
+        CONSISTENCY_CHECKED = true;
+    }
 }

Reply via email to