You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@jackrabbit.apache.org by kw...@apache.org on 2022/02/20 10:57:52 UTC

[jackrabbit-filevault] branch feature/JCRVLT-558 created (now 09180e2)

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

kwin pushed a change to branch feature/JCRVLT-558
in repository https://gitbox.apache.org/repos/asf/jackrabbit-filevault.git.


      at 09180e2  JCRVLT-558 expose StandaloneManagerProvider from vault-core

This branch includes the following new commits:

     new 09180e2  JCRVLT-558 expose StandaloneManagerProvider from vault-core

The 1 revisions listed above as "new" are entirely new to this
repository and will be described in separate emails.  The revisions
listed as "add" were already present in the repository and have only
been added to this reference.


[jackrabbit-filevault] 01/01: JCRVLT-558 expose StandaloneManagerProvider from vault-core

Posted by kw...@apache.org.
This is an automated email from the ASF dual-hosted git repository.

kwin pushed a commit to branch feature/JCRVLT-558
in repository https://gitbox.apache.org/repos/asf/jackrabbit-filevault.git

commit 09180e2c2e5cca0f4579f3b902ae18d2877e43c3
Author: Konrad Windszus <kw...@apache.org>
AuthorDate: Sun Feb 20 11:57:43 2022 +0100

    JCRVLT-558 expose StandaloneManagerProvider from vault-core
    
    Introduce CndUtil for reusing parsing from Sling bundle headers
---
 vault-core/bnd.bnd                                 |  3 +
 vault-core/pom.xml                                 |  5 ++
 .../jackrabbit/vault/fs/io/DocViewParser.java      |  6 ++
 .../vault/util/StandaloneManagerProvider.java      | 51 ++++++++-------
 .../src/main/resources/default-nodetypes.cnd       |  0
 .../spi/impl/nodetype/NodeTypeValidator.java       |  5 +-
 .../impl/nodetype/NodeTypeValidatorFactory.java    | 72 +++++----------------
 .../spi/util/classloaderurl/CndUtil.java           | 73 ++++++++++++++++++++++
 .../spi/util/classloaderurl/URLFactory.java        | 20 ++++++
 .../spi/util/classloaderurl/package-info.java      |  2 +-
 .../impl/nodetype/JcrNodeTypeMetaDataImplTest.java |  5 +-
 .../spi/impl/nodetype/NodeTypeValidatorTest.java   |  3 +-
 12 files changed, 161 insertions(+), 84 deletions(-)

diff --git a/vault-core/bnd.bnd b/vault-core/bnd.bnd
index 87e44d7..5f1c845 100644
--- a/vault-core/bnd.bnd
+++ b/vault-core/bnd.bnd
@@ -18,12 +18,15 @@ Import-Package: org.apache.jackrabbit.spi2dav;resolution:=optional,\
                             org.apache.sling.jcr.api;resolution:=optional,\
                             org.apache.jackrabbit.*;version=!,\
                             *
+# include complete packages (all transitive dependencies lead to Import-Package instructions)
+-conditionalpackage: org.apache.jackrabbit.jcr2spi.*
 DynamicImport-Package: *
 -includeresource: @txw2-[0-9.]*.jar!/com/sun/xml/txw2/output/(IndentingXMLStreamWriter|DelegatingXMLStreamWriter).*,\
                   @woodstox-core-[0-9.]*.jar!/!module-info.class,\
                   @stax2-api-[0-9.]*.jar!/!module-info.class,\
                   @maven-artifact-[0-9.]*.jar!/org/apache/maven/artifact/versioning/ComparableVersion*.class,\
                   @h2-[0-9.]*.jar!/org/h2/util/CloseWatcher*.class
+                  
 # whitelist the private reference usage in Packaging.getJcrPackageRegistry(Session)
 -fixupmessages:"Export org.apache.jackrabbit.vault.packaging,  has 1,  private references [org.apache.jackrabbit.vault.packaging.registry.impl]"; \
     restrict:=warning; \
diff --git a/vault-core/pom.xml b/vault-core/pom.xml
index bfa22f7..0e56fcc 100644
--- a/vault-core/pom.xml
+++ b/vault-core/pom.xml
@@ -153,6 +153,11 @@
             <artifactId>jackrabbit-spi2dav</artifactId>
             <scope>provided</scope>
         </dependency>
+        <dependency>
+            <groupId>org.apache.jackrabbit</groupId>
+            <artifactId>jackrabbit-jcr2spi</artifactId>
+            <scope>provided</scope>
+        </dependency>
         <!-- JCR Stuff -->
         <dependency>
             <groupId>javax.jcr</groupId>
diff --git a/vault-core/src/main/java/org/apache/jackrabbit/vault/fs/io/DocViewParser.java b/vault-core/src/main/java/org/apache/jackrabbit/vault/fs/io/DocViewParser.java
index d8f1074..a9438c0 100644
--- a/vault-core/src/main/java/org/apache/jackrabbit/vault/fs/io/DocViewParser.java
+++ b/vault-core/src/main/java/org/apache/jackrabbit/vault/fs/io/DocViewParser.java
@@ -138,6 +138,12 @@ public class DocViewParser {
         }
     }
 
+    /**
+     * Don't forget to reset the reader or use a new reader before parsing the xml.
+     * @param reader the reader from which to read the XML
+     * @return {@code true} in case the given source is Document View XML format
+     * @throws IOException
+     */
     public static boolean isDocView(Reader reader) throws IOException {
         // read a couple of chars...1024 should be enough
         char[] buffer = new char[1024];
diff --git a/vault-validation/src/main/java/org/apache/jackrabbit/vault/validation/spi/impl/nodetype/NodeTypeManagerProvider.java b/vault-core/src/main/java/org/apache/jackrabbit/vault/util/StandaloneManagerProvider.java
similarity index 83%
rename from vault-validation/src/main/java/org/apache/jackrabbit/vault/validation/spi/impl/nodetype/NodeTypeManagerProvider.java
rename to vault-core/src/main/java/org/apache/jackrabbit/vault/util/StandaloneManagerProvider.java
index 05146d8..db91ed0 100644
--- a/vault-validation/src/main/java/org/apache/jackrabbit/vault/validation/spi/impl/nodetype/NodeTypeManagerProvider.java
+++ b/vault-core/src/main/java/org/apache/jackrabbit/vault/util/StandaloneManagerProvider.java
@@ -14,7 +14,7 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
-package org.apache.jackrabbit.vault.validation.spi.impl.nodetype;
+package org.apache.jackrabbit.vault.util;
 
 import java.io.IOException;
 import java.io.InputStreamReader;
@@ -22,8 +22,6 @@ import java.io.Reader;
 import java.nio.charset.StandardCharsets;
 import java.util.Map;
 
-import javax.jcr.AccessDeniedException;
-import javax.jcr.NamespaceException;
 import javax.jcr.NamespaceRegistry;
 import javax.jcr.RepositoryException;
 import javax.jcr.UnsupportedRepositoryOperationException;
@@ -61,25 +59,35 @@ import org.apache.jackrabbit.spi.commons.nodetype.NodeTypeStorageImpl;
 import org.apache.jackrabbit.spi.commons.value.QValueFactoryImpl;
 import org.apache.jackrabbit.value.ValueFactoryImpl;
 import org.jetbrains.annotations.NotNull;
+import org.osgi.annotation.versioning.ProviderType;
 
-public class NodeTypeManagerProvider implements ManagerProvider, NamespaceStorage {
+/**
+ * A {@link ManagerProvider} which works without an underlying JCR repository.
+ * Useful for dealing with namespaces and node types outside the repository context.
+ */
+@ProviderType
+public final class StandaloneManagerProvider implements ManagerProvider, NamespaceStorage {
 
     // namespace related helpers
     private final @NotNull NamespaceMapping namespaceMapping;
     private final @NotNull NamespaceRegistry namespaceRegistry;
     private final @NotNull NamespaceResolver namespaceResolver;
     private final @NotNull NamePathResolver npResolver;
-    
-    // nodetype related helpers
+
+    // node type related helpers
     private final @NotNull NodeTypeStorage nodeTypeStorage;
     private final @NotNull NodeTypeRegistryImpl nodeTypeRegistry;
     private final @NotNull NodeTypeManagerImpl nodeTypeManager;
-    
+
     private final @NotNull ItemDefinitionProvider itemDefinitionProvider;
 
-    public NodeTypeManagerProvider() throws IOException, RepositoryException, ParseException {
+    public StandaloneManagerProvider() throws IOException, RepositoryException, ParseException {
+        this(true);
+    }
+
+    public StandaloneManagerProvider(boolean registerDefaultNodeTypes) throws IOException, RepositoryException, ParseException {
         namespaceMapping = new NamespaceMapping();
-        // add default mapping, the rest comes from the CDN provided via the reader
+        // add default mapping, the rest comes from the CND provided via the reader
         namespaceMapping.setMapping(NamespaceRegistry.PREFIX_EMPTY, NamespaceRegistry.NAMESPACE_EMPTY);
         namespaceRegistry = new NamespaceRegistryImpl(this);
         namespaceResolver = new RegistryNamespaceResolver(namespaceRegistry);
@@ -88,11 +96,12 @@ public class NodeTypeManagerProvider implements ManagerProvider, NamespaceStorag
         nodeTypeRegistry = NodeTypeRegistryImpl.create(nodeTypeStorage, namespaceRegistry);
         nodeTypeManager = new NodeTypeManagerImpl(nodeTypeRegistry, this);
         itemDefinitionProvider = new ItemDefinitionProviderImpl(nodeTypeRegistry, null, null);
-        // always provide default nodetypes
-        try (Reader reader = new InputStreamReader(
-                this.getClass().getResourceAsStream("/default-nodetypes.cnd"),
-                StandardCharsets.US_ASCII)) {
-            registerNodeTypes(reader);
+        if (registerDefaultNodeTypes) {
+            try (Reader reader = new InputStreamReader(
+                    this.getClass().getResourceAsStream("/default-nodetypes.cnd"),
+                    StandardCharsets.US_ASCII)) {
+                registerNodeTypes(reader);
+            }
         }
     }
 
@@ -107,12 +116,12 @@ public class NodeTypeManagerProvider implements ManagerProvider, NamespaceStorag
 
     @Override
     public @NotNull NameResolver getNameResolver() {
-        return npResolver;
+        return getNamePathResolver();
     }
 
     @Override
     public @NotNull PathResolver getPathResolver() {
-        return npResolver;
+        return getNamePathResolver();
     }
 
     @Override
@@ -180,24 +189,22 @@ public class NodeTypeManagerProvider implements ManagerProvider, NamespaceStorag
     }
 
     @Override
-    public String getPrefix(String uri) throws NamespaceException, RepositoryException {
+    public String getPrefix(String uri) throws RepositoryException {
         return namespaceMapping.getPrefix(uri);
     }
 
     @Override
-    public String getURI(String prefix) throws NamespaceException, RepositoryException {
+    public String getURI(String prefix) throws RepositoryException {
         return namespaceMapping.getURI(prefix);
     }
 
     @Override
-    public void registerNamespace(String prefix, String uri)
-            throws NamespaceException, UnsupportedRepositoryOperationException, AccessDeniedException, RepositoryException {
+    public void registerNamespace(String prefix, String uri) throws RepositoryException {
         namespaceMapping.setMapping(prefix, uri);
     }
 
     @Override
-    public void unregisterNamespace(String uri)
-            throws NamespaceException, UnsupportedRepositoryOperationException, AccessDeniedException, RepositoryException {
+    public void unregisterNamespace(String uri) throws RepositoryException {
         namespaceMapping.removeMapping(uri);
     }
 }
diff --git a/vault-validation/src/main/resources/default-nodetypes.cnd b/vault-core/src/main/resources/default-nodetypes.cnd
similarity index 100%
rename from vault-validation/src/main/resources/default-nodetypes.cnd
rename to vault-core/src/main/resources/default-nodetypes.cnd
diff --git a/vault-validation/src/main/java/org/apache/jackrabbit/vault/validation/spi/impl/nodetype/NodeTypeValidator.java b/vault-validation/src/main/java/org/apache/jackrabbit/vault/validation/spi/impl/nodetype/NodeTypeValidator.java
index cca7bc2..e4c8140 100644
--- a/vault-validation/src/main/java/org/apache/jackrabbit/vault/validation/spi/impl/nodetype/NodeTypeValidator.java
+++ b/vault-validation/src/main/java/org/apache/jackrabbit/vault/validation/spi/impl/nodetype/NodeTypeValidator.java
@@ -50,6 +50,7 @@ import org.apache.jackrabbit.value.StringValue;
 import org.apache.jackrabbit.vault.fs.api.WorkspaceFilter;
 import org.apache.jackrabbit.vault.util.DocViewNode2;
 import org.apache.jackrabbit.vault.util.DocViewProperty2;
+import org.apache.jackrabbit.vault.util.StandaloneManagerProvider;
 import org.apache.jackrabbit.vault.validation.ValidationExecutor;
 import org.apache.jackrabbit.vault.validation.spi.DocumentViewXmlValidator;
 import org.apache.jackrabbit.vault.validation.spi.JcrPathValidator;
@@ -74,13 +75,13 @@ public class NodeTypeValidator implements DocumentViewXmlValidator, JcrPathValid
     private final ValidationMessageSeverity severityForUnknownNodeTypes;
     private final ValidationMessageSeverity severityForDefaultNodeTypeViolations;
     private final DocViewPropertyValueFactory docViewPropertyValueFactory;
-    private final NodeTypeManagerProvider ntManagerProvider;
+    private final StandaloneManagerProvider ntManagerProvider;
     private final Set<String> loggedUnknownNodeTypeMessages;
 
     private final @NotNull Name defaultType;
     private JcrNodeTypeMetaData currentNodeTypeMetaData;
 
-    public NodeTypeValidator(boolean isIncremental, @NotNull WorkspaceFilter filter, @NotNull NodeTypeManagerProvider ntManagerProvider,
+    public NodeTypeValidator(boolean isIncremental, @NotNull WorkspaceFilter filter, @NotNull StandaloneManagerProvider ntManagerProvider,
             @NotNull Name defaultPrimaryNodeType, @NotNull ValidationMessageSeverity defaultSeverity,
             @NotNull ValidationMessageSeverity severityForUnknownNodeTypes, @NotNull ValidationMessageSeverity severityForDefaultNodeTypeViolations)
             throws ConstraintViolationException, NoSuchNodeTypeException {
diff --git a/vault-validation/src/main/java/org/apache/jackrabbit/vault/validation/spi/impl/nodetype/NodeTypeValidatorFactory.java b/vault-validation/src/main/java/org/apache/jackrabbit/vault/validation/spi/impl/nodetype/NodeTypeValidatorFactory.java
index aab39ef..99c75b0 100644
--- a/vault-validation/src/main/java/org/apache/jackrabbit/vault/validation/spi/impl/nodetype/NodeTypeValidatorFactory.java
+++ b/vault-validation/src/main/java/org/apache/jackrabbit/vault/validation/spi/impl/nodetype/NodeTypeValidatorFactory.java
@@ -17,28 +17,24 @@
 package org.apache.jackrabbit.vault.validation.spi.impl.nodetype;
 
 import java.io.IOException;
-import java.io.InputStreamReader;
-import java.io.Reader;
-import java.net.JarURLConnection;
-import java.net.URL;
-import java.nio.charset.StandardCharsets;
+import java.io.UncheckedIOException;
+import java.util.Arrays;
 import java.util.Collections;
 import java.util.HashMap;
-import java.util.LinkedList;
-import java.util.List;
 import java.util.Map;
-import java.util.jar.Manifest;
 
 import javax.jcr.RepositoryException;
 
 import org.apache.commons.lang3.StringUtils;
 import org.apache.jackrabbit.JcrConstants;
 import org.apache.jackrabbit.commons.cnd.ParseException;
+import org.apache.jackrabbit.vault.util.StandaloneManagerProvider;
 import org.apache.jackrabbit.vault.validation.spi.ValidationContext;
 import org.apache.jackrabbit.vault.validation.spi.ValidationMessageSeverity;
 import org.apache.jackrabbit.vault.validation.spi.Validator;
 import org.apache.jackrabbit.vault.validation.spi.ValidatorFactory;
 import org.apache.jackrabbit.vault.validation.spi.ValidatorSettings;
+import org.apache.jackrabbit.vault.validation.spi.util.classloaderurl.CndUtil;
 import org.apache.jackrabbit.vault.validation.spi.util.classloaderurl.URLFactory;
 import org.jetbrains.annotations.NotNull;
 import org.jetbrains.annotations.Nullable;
@@ -63,8 +59,6 @@ public class NodeTypeValidatorFactory implements ValidatorFactory {
     /** Comma-separated list of name spaces that are known as valid (even if not defined in the CND files). Use syntax "prefix1=ns-uri1,prefix2=nsuri2,...". */
     public static final String OPTION_VALID_NAMESPACES = "validNameSpaces";
 
-
-
     private static final Logger LOGGER = LoggerFactory.getLogger(NodeTypeValidatorFactory.class);
 
     @Override
@@ -109,61 +103,27 @@ public class NodeTypeValidatorFactory implements ValidatorFactory {
         }
 
         try {
-            NodeTypeManagerProvider ntManagerProvider = null;
-            ntManagerProvider = new NodeTypeManagerProvider();
-            for (String cndUrl : resolveJarUrls(cndUrls.split(","))) {
-                try (Reader reader = new InputStreamReader(URLFactory.createURL(cndUrl).openStream(), StandardCharsets.US_ASCII)) {
-                    LOGGER.info("Register node types from {}", cndUrl);
-                    ntManagerProvider.registerNodeTypes(reader);
-                } catch (RepositoryException | IOException | ParseException e) {
-                    throw new IllegalArgumentException("Error loading node types from CND at " + cndUrl, e);
+            StandaloneManagerProvider managerProvider = new StandaloneManagerProvider();
+            URLFactory.processUrlStreams(CndUtil.resolveJarUrls(Arrays.asList(cndUrls.split(","))), t -> {
+                try {
+                    managerProvider.registerNodeTypes(t);
+                } catch (IOException e) {
+                    throw new UncheckedIOException(e);
                 }
-            }
+                catch (ParseException | RepositoryException e) {
+                    throw new IllegalArgumentException(e);
+                }
+            });
             for (Map.Entry<String, String> entry : validNameSpaces.entrySet()) {
-                ntManagerProvider.registerNamespace(entry.getKey(), entry.getValue());
+                managerProvider.registerNamespace(entry.getKey(), entry.getValue());
             }
-            return new NodeTypeValidator(context.isIncremental(), context.getFilter(), ntManagerProvider, ntManagerProvider.getNameResolver().getQName(defaultNodeType), settings.getDefaultSeverity(),
+            return new NodeTypeValidator(context.isIncremental(), context.getFilter(), managerProvider, managerProvider.getNameResolver().getQName(defaultNodeType), settings.getDefaultSeverity(),
                     severityForUnknownNodetypes, severityForDefaultNodeTypeViolations);
         } catch (IOException | RepositoryException | ParseException e) {
             throw new IllegalArgumentException("Error loading default node type " + defaultNodeType, e);
         }
     }
 
-    /**
-     * Resolve URLs pointing to JARs with META-INF/MANIFEST carrying a {@code Sling-Nodetypes} header
-     * @param urls
-     * @return
-     */
-    static List<String> resolveJarUrls(String... urls) {
-        List<String> resolvedUrls = new LinkedList<>();
-        for (String url : urls) {
-            url = url.trim();
-            if (url.endsWith(".jar")) {
-                // https://docs.oracle.com/javase/7/docs/api/java/net/JarURLConnection.html
-                URL jarUrl;
-                try {
-                    jarUrl = URLFactory.createURL("jar:" + url + "!/");
-                    JarURLConnection jarConnection = (JarURLConnection)jarUrl.openConnection();
-                    Manifest manifest = jarConnection.getManifest();
-                    String slingNodetypes = manifest.getMainAttributes().getValue("Sling-Nodetypes");
-                    // split by "," and generate new JAR Urls
-                    if (slingNodetypes == null) {
-                        LOGGER.warn("No 'Sling-Nodetypes' header found in manifest of '{}'", jarUrl);
-                    } else {
-                        for (String nodetype : slingNodetypes.split(",")) {
-                            resolvedUrls.add(jarUrl.toString() + nodetype.trim());
-                        }
-                    }
-                } catch (IOException e) {
-                    throw new IllegalArgumentException("Could not read from JAR " + url, e);
-                }
-            } else {
-                resolvedUrls.add(url);
-            }
-        }
-        return resolvedUrls;
-    }
-
     static Map<String,String> parseNamespaces(String optionValue) {
         Map<String,String> result = new HashMap<>();
         String[] namespaces = optionValue.split(",");
diff --git a/vault-validation/src/main/java/org/apache/jackrabbit/vault/validation/spi/util/classloaderurl/CndUtil.java b/vault-validation/src/main/java/org/apache/jackrabbit/vault/validation/spi/util/classloaderurl/CndUtil.java
new file mode 100644
index 0000000..9b7c2a4
--- /dev/null
+++ b/vault-validation/src/main/java/org/apache/jackrabbit/vault/validation/spi/util/classloaderurl/CndUtil.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.jackrabbit.vault.validation.spi.util.classloaderurl;
+
+import java.io.IOException;
+import java.net.JarURLConnection;
+import java.net.URL;
+import java.util.LinkedList;
+import java.util.List;
+import java.util.jar.Manifest;
+
+import org.osgi.annotation.versioning.ProviderType;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+@ProviderType
+public final class CndUtil {
+
+    private static final Logger LOGGER = LoggerFactory.getLogger(CndUtil.class);
+
+    private CndUtil() {
+        // static util methods only
+    }
+    /**
+     * Resolve URLs pointing to JARs with META-INF/MANIFEST carrying a {@code Sling-Nodetypes} header
+     * @param urls
+     * @return
+     */
+    public static List<String> resolveJarUrls(List<String> urls) {
+        List<String> resolvedUrls = new LinkedList<>();
+        for (String url : urls) {
+            url = url.trim();
+            if (url.endsWith(".jar")) {
+                // https://docs.oracle.com/javase/7/docs/api/java/net/JarURLConnection.html
+                URL jarUrl;
+                try {
+                    jarUrl = URLFactory.createURL("jar:" + url + "!/");
+                    JarURLConnection jarConnection = (JarURLConnection)jarUrl.openConnection();
+                    Manifest manifest = jarConnection.getManifest();
+                    String slingNodetypes = manifest.getMainAttributes().getValue("Sling-Nodetypes");
+                    // split by "," and generate new JAR Urls
+                    if (slingNodetypes == null) {
+                        LOGGER.warn("No 'Sling-Nodetypes' header found in manifest of '{}'", jarUrl);
+                    } else {
+                        for (String nodetype : slingNodetypes.split(",")) {
+                            resolvedUrls.add(jarUrl.toString() + nodetype.trim());
+                        }
+                    }
+                } catch (IOException e) {
+                    throw new IllegalArgumentException("Could not read from JAR " + url, e);
+                }
+            } else {
+                resolvedUrls.add(url);
+            }
+        }
+        return resolvedUrls;
+    }
+
+}
diff --git a/vault-validation/src/main/java/org/apache/jackrabbit/vault/validation/spi/util/classloaderurl/URLFactory.java b/vault-validation/src/main/java/org/apache/jackrabbit/vault/validation/spi/util/classloaderurl/URLFactory.java
index 517168a..96956e4 100644
--- a/vault-validation/src/main/java/org/apache/jackrabbit/vault/validation/spi/util/classloaderurl/URLFactory.java
+++ b/vault-validation/src/main/java/org/apache/jackrabbit/vault/validation/spi/util/classloaderurl/URLFactory.java
@@ -16,9 +16,19 @@
  */
 package org.apache.jackrabbit.vault.validation.spi.util.classloaderurl;
 
+import java.io.IOException;
+
+import java.io.InputStreamReader;
+import java.io.Reader;
 import java.net.MalformedURLException;
 import java.net.URL;
+import java.nio.charset.StandardCharsets;
+import java.util.List;
+import java.util.function.Consumer;
+
+import org.osgi.annotation.versioning.ProviderType;
 
+@ProviderType
 public class URLFactory {
     public static final String TCCL_PROTOCOL_PREFIX = "tccl:";
     
@@ -38,4 +48,14 @@ public class URLFactory {
         }
         return url;
     }
+
+    public static void processUrlStreams(List<String> urls, Consumer<Reader> readerProcessor) {
+        for (String url : urls) {
+            try (Reader reader = new InputStreamReader(URLFactory.createURL(url).openStream(), StandardCharsets.US_ASCII)) {
+                readerProcessor.accept(reader);
+            } catch (IOException e) {
+                throw new IllegalArgumentException("Error loading content from " + url, e);
+            }
+        }
+    }
 }
diff --git a/vault-validation/src/main/java/org/apache/jackrabbit/vault/validation/spi/util/classloaderurl/package-info.java b/vault-validation/src/main/java/org/apache/jackrabbit/vault/validation/spi/util/classloaderurl/package-info.java
index c23cd0a..a5380a1 100644
--- a/vault-validation/src/main/java/org/apache/jackrabbit/vault/validation/spi/util/classloaderurl/package-info.java
+++ b/vault-validation/src/main/java/org/apache/jackrabbit/vault/validation/spi/util/classloaderurl/package-info.java
@@ -14,7 +14,7 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
-@Version("1.0.0")
+@Version("1.1.0")
 package org.apache.jackrabbit.vault.validation.spi.util.classloaderurl;
 
 import org.osgi.annotation.versioning.Version;
diff --git a/vault-validation/src/test/java/org/apache/jackrabbit/vault/validation/spi/impl/nodetype/JcrNodeTypeMetaDataImplTest.java b/vault-validation/src/test/java/org/apache/jackrabbit/vault/validation/spi/impl/nodetype/JcrNodeTypeMetaDataImplTest.java
index e827ff7..09bac29 100644
--- a/vault-validation/src/test/java/org/apache/jackrabbit/vault/validation/spi/impl/nodetype/JcrNodeTypeMetaDataImplTest.java
+++ b/vault-validation/src/test/java/org/apache/jackrabbit/vault/validation/spi/impl/nodetype/JcrNodeTypeMetaDataImplTest.java
@@ -40,6 +40,7 @@ import org.apache.jackrabbit.spi.commons.conversion.MalformedPathException;
 import org.apache.jackrabbit.value.ValueFactoryImpl;
 import org.apache.jackrabbit.vault.fs.api.PathFilterSet;
 import org.apache.jackrabbit.vault.fs.config.DefaultWorkspaceFilter;
+import org.apache.jackrabbit.vault.util.StandaloneManagerProvider;
 import org.apache.jackrabbit.vault.validation.AnyValidationViolationMessageMatcher;
 import org.apache.jackrabbit.vault.validation.ValidationExecutorTest;
 import org.apache.jackrabbit.vault.validation.spi.NodeContext;
@@ -53,7 +54,7 @@ import org.junit.Test;
 
 public class JcrNodeTypeMetaDataImplTest {
 
-    private NodeTypeManagerProvider ntManagerProvider;
+    private StandaloneManagerProvider ntManagerProvider;
 
     private JcrNodeTypeMetaDataImpl root;
 
@@ -62,7 +63,7 @@ public class JcrNodeTypeMetaDataImplTest {
 
     @Before
     public void setUp() throws IOException, RepositoryException, ParseException {
-        ntManagerProvider = new NodeTypeManagerProvider();
+        ntManagerProvider = new StandaloneManagerProvider();
         root = JcrNodeTypeMetaDataImpl.createRoot(false, ntManagerProvider.getEffectiveNodeTypeProvider());
     }
 
diff --git a/vault-validation/src/test/java/org/apache/jackrabbit/vault/validation/spi/impl/nodetype/NodeTypeValidatorTest.java b/vault-validation/src/test/java/org/apache/jackrabbit/vault/validation/spi/impl/nodetype/NodeTypeValidatorTest.java
index 8004744..b89d4e6 100644
--- a/vault-validation/src/test/java/org/apache/jackrabbit/vault/validation/spi/impl/nodetype/NodeTypeValidatorTest.java
+++ b/vault-validation/src/test/java/org/apache/jackrabbit/vault/validation/spi/impl/nodetype/NodeTypeValidatorTest.java
@@ -40,6 +40,7 @@ import org.apache.jackrabbit.vault.fs.config.ConfigurationException;
 import org.apache.jackrabbit.vault.fs.config.DefaultWorkspaceFilter;
 import org.apache.jackrabbit.vault.util.DocViewNode2;
 import org.apache.jackrabbit.vault.util.DocViewProperty2;
+import org.apache.jackrabbit.vault.util.StandaloneManagerProvider;
 import org.apache.jackrabbit.vault.validation.AnyValidationViolationMessageMatcher;
 import org.apache.jackrabbit.vault.validation.ValidationExecutorTest;
 import org.apache.jackrabbit.vault.validation.spi.NodeContext;
@@ -70,7 +71,7 @@ public class NodeTypeValidatorTest {
 
     static NodeTypeValidator createValidator(WorkspaceFilter filter, Name defaultNodeType, String... cndUrls)
             throws IOException, RepositoryException, ParseException {
-        NodeTypeManagerProvider ntManagerProvider = new NodeTypeManagerProvider();
+        StandaloneManagerProvider ntManagerProvider = new StandaloneManagerProvider();
         for (String cndUrl : cndUrls) {
             try (Reader reader = new InputStreamReader(URLFactory.createURL(cndUrl).openStream(), StandardCharsets.US_ASCII)) {
                 ntManagerProvider.registerNodeTypes(reader);