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 2021/02/07 13:14:55 UTC

[jackrabbit-filevault] 01/01: JCRVLT-503 introduce composite package registry

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

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

commit 99db81b686f3c6988f6298817b3df20e5de9cced
Author: Konrad Windszus <kw...@apache.org>
AuthorDate: Sun Feb 7 14:14:35 2021 +0100

    JCRVLT-503 introduce composite package registry
---
 .../jackrabbit/vault/packaging/Packaging.java      |  18 +++
 .../vault/packaging/impl/PackagingImpl.java        |  42 ++++++-
 .../registry/impl/CompositePackageRegistry.java    | 140 +++++++++++++++++++++
 3 files changed, 194 insertions(+), 6 deletions(-)

diff --git a/vault-core/src/main/java/org/apache/jackrabbit/vault/packaging/Packaging.java b/vault-core/src/main/java/org/apache/jackrabbit/vault/packaging/Packaging.java
index 76cc618..f89c28f 100644
--- a/vault-core/src/main/java/org/apache/jackrabbit/vault/packaging/Packaging.java
+++ b/vault-core/src/main/java/org/apache/jackrabbit/vault/packaging/Packaging.java
@@ -21,6 +21,8 @@ import javax.jcr.Node;
 import javax.jcr.RepositoryException;
 import javax.jcr.Session;
 
+import org.apache.jackrabbit.vault.packaging.registry.PackageRegistry;
+import org.apache.jackrabbit.vault.packaging.registry.impl.JcrPackageRegistry;
 import org.osgi.annotation.versioning.ProviderType;
 
 /**
@@ -68,4 +70,20 @@ public interface Packaging {
      * @since 2.3.0
      */
     JcrPackage open(Node node, boolean allowInvalid) throws RepositoryException;
+    
+    /**
+     * Returns a new composite package registry which acts on all currently registered package registries and 
+     * a JCR-based registry for the current configuration and the given session.
+     * All operations creating new packages will act on the primary registry which is determined by argument
+     * {@code useJcrRegistryAsPrimaryRegistry}.
+     * Due to the dynamic nature of package registries the return value should not be persisted.
+     * 
+     * @param session the JCR session to use for the JCR-based registry
+     * @param useJcrRegistryAsPrimaryRegistry if {@code true} the JCR-based registry will be used as primary
+     * registry, otherwise the first registered package registry is used and the JCR-based registry will be inserted as last registry. 
+     * @return the composite package registry
+     */
+    PackageRegistry getCompositePackageRegistry(Session session, boolean useJcrRegistryAsPrimaryRegistry);
+
+    JcrPackageRegistry getJcrPackageRegistry(Session session);
 }
\ No newline at end of file
diff --git a/vault-core/src/main/java/org/apache/jackrabbit/vault/packaging/impl/PackagingImpl.java b/vault-core/src/main/java/org/apache/jackrabbit/vault/packaging/impl/PackagingImpl.java
index 9cb04ac..96ea176 100644
--- a/vault-core/src/main/java/org/apache/jackrabbit/vault/packaging/impl/PackagingImpl.java
+++ b/vault-core/src/main/java/org/apache/jackrabbit/vault/packaging/impl/PackagingImpl.java
@@ -16,6 +16,9 @@
  */
 package org.apache.jackrabbit.vault.packaging.impl;
 
+import java.util.ArrayList;
+import java.util.List;
+
 import javax.jcr.Node;
 import javax.jcr.RepositoryException;
 import javax.jcr.Session;
@@ -27,11 +30,15 @@ import org.apache.jackrabbit.vault.packaging.PackageManager;
 import org.apache.jackrabbit.vault.packaging.Packaging;
 import org.apache.jackrabbit.vault.packaging.events.impl.PackageEventDispatcher;
 import org.apache.jackrabbit.vault.packaging.registry.PackageRegistry;
+import org.apache.jackrabbit.vault.packaging.registry.impl.AbstractPackageRegistry;
+import org.apache.jackrabbit.vault.packaging.registry.impl.CompositePackageRegistry;
+import org.apache.jackrabbit.vault.packaging.registry.impl.JcrPackageRegistry;
 import org.osgi.service.component.annotations.Activate;
 import org.osgi.service.component.annotations.Component;
 import org.osgi.service.component.annotations.Reference;
 import org.osgi.service.component.annotations.ReferenceCardinality;
 import org.osgi.service.component.annotations.ReferencePolicy;
+import org.osgi.service.component.annotations.ReferencePolicyOption;
 import org.osgi.service.metatype.annotations.AttributeDefinition;
 import org.osgi.service.metatype.annotations.Designate;
 import org.osgi.service.metatype.annotations.ObjectClassDefinition;
@@ -57,12 +64,12 @@ public class PackagingImpl implements Packaging {
     @Reference
     private PackageEventDispatcher eventDispatcher;
     
-    // In case a PackageRegistry is exposed as OSGi Service this will be considered
+    // In case a PackageRegistry is exposed as OSGi Service the first one will be considered
     // as base registry to fall back for dependency checks - currently only FSPackageRegistry is exposed as such
-    // currently no support for multiple registered PackageRegistries (OSGi Framework will will pick first found)
-    @Reference (cardinality = ReferenceCardinality.OPTIONAL,
-            policy = ReferencePolicy.DYNAMIC)
-    private volatile PackageRegistry baseRegistry;
+    @Reference (cardinality = ReferenceCardinality.MULTIPLE,
+            policy = ReferencePolicy.DYNAMIC,
+            policyOption = ReferencePolicyOption.GREEDY)
+    private List<PackageRegistry> registries;
 
     /**
      * package manager is a singleton
@@ -112,7 +119,10 @@ public class PackagingImpl implements Packaging {
     public JcrPackageManager getPackageManager(Session session) {
         JcrPackageManagerImpl mgr = new JcrPackageManagerImpl(session, config.packageRoots(), config.authIdsForHookExecution(), config.authIdsForRootInstallation());
         mgr.setDispatcher(eventDispatcher);
-        mgr.getInternalRegistry().setBaseRegistry(baseRegistry);
+        List<PackageRegistry> allRegistries = registries;
+        if (!allRegistries.isEmpty()) {
+            mgr.getInternalRegistry().setBaseRegistry(allRegistries.get(0));
+        }
         return mgr;
     }
 
@@ -130,4 +140,24 @@ public class PackagingImpl implements Packaging {
         JcrPackageManager pMgr = getPackageManager(node.getSession());
         return pMgr.open(node, allowInvalid);
     }
+
+    @Override
+    public PackageRegistry getCompositePackageRegistry(Session session, boolean useJcrRegistryAsPrimaryRegistry) {
+        List<PackageRegistry> allRegistries = new ArrayList<>(registries);
+        JcrPackageRegistry jcrPackageRegistry = getJcrPackageRegistry(session);
+        if (useJcrRegistryAsPrimaryRegistry) {
+            allRegistries.add(0, jcrPackageRegistry);
+        } else {
+            allRegistries.add(jcrPackageRegistry);
+        }
+        return new CompositePackageRegistry(allRegistries);
+    }
+
+    @Override
+    public JcrPackageRegistry getJcrPackageRegistry(Session session) {
+        JcrPackageRegistry registry = new JcrPackageRegistry(session, new AbstractPackageRegistry.SecurityConfig(config.authIdsForHookExecution(), config.authIdsForRootInstallation()), config.packageRoots());
+        registry.setDispatcher(eventDispatcher);
+        // TODO: baseRegistry?
+        return registry;
+    }
 }
\ No newline at end of file
diff --git a/vault-core/src/main/java/org/apache/jackrabbit/vault/packaging/registry/impl/CompositePackageRegistry.java b/vault-core/src/main/java/org/apache/jackrabbit/vault/packaging/registry/impl/CompositePackageRegistry.java
new file mode 100644
index 0000000..7e70a3a
--- /dev/null
+++ b/vault-core/src/main/java/org/apache/jackrabbit/vault/packaging/registry/impl/CompositePackageRegistry.java
@@ -0,0 +1,140 @@
+/*
+ * 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.packaging.registry.impl;
+
+import java.io.File;
+import java.io.IOException;
+import java.io.InputStream;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Set;
+
+import org.apache.jackrabbit.vault.packaging.Dependency;
+import org.apache.jackrabbit.vault.packaging.NoSuchPackageException;
+import org.apache.jackrabbit.vault.packaging.PackageExistsException;
+import org.apache.jackrabbit.vault.packaging.PackageId;
+import org.apache.jackrabbit.vault.packaging.registry.DependencyReport;
+import org.apache.jackrabbit.vault.packaging.registry.ExecutionPlanBuilder;
+import org.apache.jackrabbit.vault.packaging.registry.PackageRegistry;
+import org.apache.jackrabbit.vault.packaging.registry.RegisteredPackage;
+import org.jetbrains.annotations.NotNull;
+import org.jetbrains.annotations.Nullable;
+
+public class CompositePackageRegistry implements PackageRegistry {
+
+    private final List<PackageRegistry> registries;
+    private final PackageRegistry primaryRegistry;
+    
+    public CompositePackageRegistry(List<PackageRegistry> registries) {
+        this.registries = registries;
+        this.primaryRegistry = registries.get(0);
+    }
+
+    @Override
+    public boolean contains(@NotNull PackageId id) throws IOException {
+        for (PackageRegistry registry : registries) {
+            if (registry.contains(id)) {
+                return true;
+            }
+        }
+        return false;
+    }
+
+    @Override
+    public @NotNull Set<PackageId> packages() throws IOException {
+        Set<PackageId> allPackages = new HashSet<>();
+        for (PackageRegistry registry : registries) {
+            allPackages.addAll(registry.packages());
+        }
+        return allPackages;
+    }
+
+    @Override
+    public @Nullable RegisteredPackage open(@NotNull PackageId id) throws IOException {
+        for (PackageRegistry registry : registries) {
+            if (registry.contains(id)) {
+                return registry.open(id);
+            }
+        }
+        return null;
+    }
+
+    @Override
+    public @NotNull PackageId register(@NotNull InputStream in, boolean replace) throws IOException, PackageExistsException {
+        return primaryRegistry.register(in, replace);
+    }
+
+    @Override
+    public @NotNull PackageId register(@NotNull File file, boolean replace) throws IOException, PackageExistsException {
+        return primaryRegistry.register(file, replace);
+    }
+
+    @Override
+    public @NotNull PackageId registerExternal(@NotNull File file, boolean replace) throws IOException, PackageExistsException {
+        return primaryRegistry.registerExternal(file, replace);
+    }
+
+    @Override
+    public void remove(@NotNull PackageId id) throws IOException, NoSuchPackageException {
+        for (PackageRegistry registry : registries) {
+            if (registry.contains(id)) {
+                registry.remove(id);
+                return;
+            }
+        }
+        throw new NoSuchPackageException("No registry contains the given package id " + id);
+    }
+
+    @Override
+    public @NotNull DependencyReport analyzeDependencies(@NotNull PackageId id, boolean onlyInstalled)
+            throws IOException, NoSuchPackageException {
+        for (PackageRegistry registry : registries) {
+            if (registry.contains(id)) {
+                return registry.analyzeDependencies(id, onlyInstalled);
+            }
+        }
+        throw new NoSuchPackageException("No registry contains the given package id " + id);
+    }
+
+    @Override
+    public @Nullable PackageId resolve(@NotNull Dependency dependency, boolean onlyInstalled) throws IOException {
+        PackageId packageId = null;
+        for (PackageRegistry registry : registries) {
+            packageId = registry.resolve(dependency, onlyInstalled);
+            if (packageId != null) {
+                return packageId;
+            }
+        }
+        return packageId;
+    }
+
+    @Override
+    public @NotNull PackageId[] usage(@NotNull PackageId id) throws IOException {
+        for (PackageRegistry registry : registries) {
+            if (registry.contains(id)) {
+                return registry.usage(id);
+            }
+        }
+        return new PackageId[] {};
+    }
+
+    @Override
+    public @NotNull ExecutionPlanBuilder createExecutionPlan() {
+        return new ExecutionPlanBuilderImpl(this);
+    }
+
+}