You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@sling.apache.org by da...@apache.org on 2020/08/12 15:28:51 UTC

[sling-org-apache-sling-installer-factory-feature] branch SLING-9658 updated (f0e7f51 -> e3c652a)

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

davidb pushed a change to branch SLING-9658
in repository https://gitbox.apache.org/repos/asf/sling-org-apache-sling-installer-factory-feature.git.


 discard f0e7f51  SLING-9658 Support binary archives in .far files
     new e3c652a  SLING-9658 Support binary archives in .far files

This update added new revisions after undoing existing revisions.
That is to say, some revisions that were in the old version of the
branch are not in the new version.  This situation occurs
when a user --force pushes a change and generates a repository
containing something like this:

 * -- * -- B -- O -- O -- O   (f0e7f51)
            \
             N -- N -- N   refs/heads/SLING-9658 (e3c652a)

You should already have received notification emails for all of the O
revisions, and so the following emails describe only the N revisions
from the common base, B.

Any revisions marked "omit" are not gone; other references still
refer to them.  Any revisions marked "discard" are gone forever.

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.


Summary of changes:
 .../apache/sling/feature/spi/context/ExtensionHandlerContext.java    | 3 ---
 .../sling/installer/factory/model/impl/InstallFeatureModelTask.java  | 5 -----
 2 files changed, 8 deletions(-)


[sling-org-apache-sling-installer-factory-feature] 01/01: SLING-9658 Support binary archives in .far files

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

davidb pushed a commit to branch SLING-9658
in repository https://gitbox.apache.org/repos/asf/sling-org-apache-sling-installer-factory-feature.git

commit e3c652a63a8c4c04511108fef221f290c93c22f6
Author: David Bosschaert <bo...@adobe.com>
AuthorDate: Wed Aug 12 16:23:45 2020 +0100

    SLING-9658 Support binary archives in .far files
    
    Initial extension handler service API and refactored
    InstallFeatureModelTask that uses these services to handle extensions.
---
 pom.xml                                            |   9 +-
 .../feature/spi/context/ExtensionHandler.java      |   8 ++
 .../spi/context/ExtensionHandlerContext.java       |  31 +++++++
 .../model/impl/APIRegionsExtensionHandler.java     |  56 ++++++++++++
 .../model/impl/BinaryArtifactExtensionHandler.java |  58 ++++++++++++
 .../model/impl/FeatureModelInstallerPlugin.java    |   3 +
 .../model/impl/InstallFeatureModelTask.java        | 100 ++++++++++++++++-----
 .../model/impl/RepoinitExtensionHandler.java       |  33 +++++++
 8 files changed, 274 insertions(+), 24 deletions(-)

diff --git a/pom.xml b/pom.xml
index 507b9fa..3e246df 100644
--- a/pom.xml
+++ b/pom.xml
@@ -93,7 +93,7 @@
         <dependency>
             <groupId>org.apache.sling</groupId>
             <artifactId>org.apache.sling.feature</artifactId>
-            <version>1.2.0</version>
+            <version>1.2.4</version>
             <scope>provided</scope>
         </dependency>
         <dependency>
@@ -102,6 +102,13 @@
             <version>1.1.4</version>
             <scope>provided</scope>
         </dependency>
+        <dependency>
+            <groupId>org.apache.felix</groupId>
+            <artifactId>org.apache.felix.utils</artifactId>
+            <version>1.11.4</version>
+            <scope>provided</scope>
+        </dependency>
+        
    <!-- Testing -->
         <dependency>
             <groupId>junit</groupId>
diff --git a/src/main/java/org/apache/sling/feature/spi/context/ExtensionHandler.java b/src/main/java/org/apache/sling/feature/spi/context/ExtensionHandler.java
new file mode 100644
index 0000000..79dde1b
--- /dev/null
+++ b/src/main/java/org/apache/sling/feature/spi/context/ExtensionHandler.java
@@ -0,0 +1,8 @@
+package org.apache.sling.feature.spi.context;
+
+import org.apache.sling.feature.Extension;
+import org.apache.sling.feature.Feature;
+
+public interface ExtensionHandler {
+    public boolean handle(ExtensionHandlerContext context, Extension extension, Feature feature) throws Exception;
+}
diff --git a/src/main/java/org/apache/sling/feature/spi/context/ExtensionHandlerContext.java b/src/main/java/org/apache/sling/feature/spi/context/ExtensionHandlerContext.java
new file mode 100644
index 0000000..cf9d17f
--- /dev/null
+++ b/src/main/java/org/apache/sling/feature/spi/context/ExtensionHandlerContext.java
@@ -0,0 +1,31 @@
+package org.apache.sling.feature.spi.context;
+
+import org.apache.sling.feature.io.artifacts.ArtifactManager;
+
+import java.net.URL;
+import java.util.Dictionary;
+
+public interface ExtensionHandlerContext {
+    /**
+     * Add a bundle to be installed by the launcher.
+     * @param startLevel The start level for the bundle.
+     * @param file The file with the bundle.
+     */
+    public void addBundle(final Integer startLevel, final URL file);
+
+    /**
+     * Add an artifact to be installed by the launcher
+     * @param file The file
+     */
+    public void addInstallableArtifact(final URL file);
+
+    /**
+     * Add a configuration to be installed by the launcher
+     * @param pid The pid
+     * @param factoryPid The factory pid
+     * @param properties The propertis
+     */
+    public void addConfiguration(final String pid, final String factoryPid, final Dictionary<String, Object> properties);
+
+    public ArtifactManager getArtifactManager();
+}
diff --git a/src/main/java/org/apache/sling/installer/factory/model/impl/APIRegionsExtensionHandler.java b/src/main/java/org/apache/sling/installer/factory/model/impl/APIRegionsExtensionHandler.java
new file mode 100644
index 0000000..f4db956
--- /dev/null
+++ b/src/main/java/org/apache/sling/installer/factory/model/impl/APIRegionsExtensionHandler.java
@@ -0,0 +1,56 @@
+package org.apache.sling.installer.factory.model.impl;
+
+import org.apache.sling.feature.Extension;
+import org.apache.sling.feature.ExtensionType;
+import org.apache.sling.feature.Feature;
+import org.apache.sling.feature.extension.apiregions.api.ApiRegions;
+import org.apache.sling.feature.extension.apiregions.launcher.LauncherProperties;
+import org.apache.sling.feature.spi.context.ExtensionHandler;
+import org.apache.sling.feature.spi.context.ExtensionHandlerContext;
+import org.osgi.service.component.annotations.Component;
+
+import java.util.ArrayList;
+import java.util.Dictionary;
+import java.util.Hashtable;
+import java.util.List;
+import java.util.Map;
+import java.util.Properties;
+
+@Component
+public class APIRegionsExtensionHandler implements ExtensionHandler {
+    private static final String REGION_FACTORY_PID = "org.apache.sling.feature.apiregions.factory~";
+
+    private static final String PROP_idbsnver = "mapping.bundleid.bsnver";
+    private static final String PROP_bundleFeatures = "mapping.bundleid.features";
+    private static final String PROP_featureRegions = "mapping.featureid.regions";
+    private static final String PROP_regionPackage = "mapping.region.packages";
+
+    @Override
+    public boolean handle(ExtensionHandlerContext context, Extension extension, Feature feature) throws Exception {
+        if (!extension.getName().equals(ApiRegions.EXTENSION_NAME) ||
+                extension.getType() != ExtensionType.JSON) {
+            return false;
+        }
+
+        final ApiRegions regions = ApiRegions.parse(extension.getJSONStructure().asJsonArray());
+
+        final String configPid = REGION_FACTORY_PID.concat(feature.getId().toMvnName().replace('-', '_'));
+        final Dictionary<String, Object> props = new Hashtable<>();
+        props.put(PROP_idbsnver, convert(LauncherProperties.getBundleIDtoBSNandVersionMap(feature, context.getArtifactManager())));
+        props.put(PROP_bundleFeatures, convert(LauncherProperties.getBundleIDtoFeaturesMap(feature)));
+        props.put(PROP_featureRegions, convert(LauncherProperties.getFeatureIDtoRegionsMap(regions)));
+        props.put(PROP_regionPackage, convert(LauncherProperties.getRegionNametoPackagesMap(regions)));
+
+        context.addConfiguration(null, configPid, props);
+        return true;
+    }
+
+    private String[] convert(final Properties props) {
+        final List<String> result = new ArrayList<>();
+
+        for(final Map.Entry<Object, Object> entry : props.entrySet()) {
+            result.add(entry.getKey().toString().concat("=").concat(entry.getValue().toString()));
+        }
+        return result.toArray(new String[result.size()]);
+    }
+}
diff --git a/src/main/java/org/apache/sling/installer/factory/model/impl/BinaryArtifactExtensionHandler.java b/src/main/java/org/apache/sling/installer/factory/model/impl/BinaryArtifactExtensionHandler.java
new file mode 100644
index 0000000..10045df
--- /dev/null
+++ b/src/main/java/org/apache/sling/installer/factory/model/impl/BinaryArtifactExtensionHandler.java
@@ -0,0 +1,58 @@
+package org.apache.sling.installer.factory.model.impl;
+
+import org.apache.felix.utils.manifest.Clause;
+import org.apache.felix.utils.manifest.Directive;
+import org.apache.felix.utils.manifest.Parser;
+import org.apache.sling.feature.Extension;
+import org.apache.sling.feature.ExtensionType;
+import org.apache.sling.feature.Feature;
+import org.apache.sling.feature.spi.context.ExtensionHandler;
+import org.apache.sling.feature.spi.context.ExtensionHandlerContext;
+import org.osgi.framework.BundleContext;
+import org.osgi.service.component.annotations.Activate;
+import org.osgi.service.component.annotations.Component;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.Map;
+
+@Component
+public class BinaryArtifactExtensionHandler implements ExtensionHandler {
+    private static final String BINARY_EXTENSIONS_PROP = "org.apache.sling.feature.binary.extensions";
+
+    private final Map<String, Map<String, String>> binaryExtensions;
+    private final Logger logger = LoggerFactory.getLogger(this.getClass());
+
+    @Activate
+    public BinaryArtifactExtensionHandler(BundleContext bc) {
+        Map<String, Map<String, String>> be = new HashMap<>();
+
+        // Syntax: system-fonts;dir:=abc;overwrite:=true,customer-fonts;dir:=eft
+        Clause[] extClauses = Parser.parseHeader(bc.getProperty(BINARY_EXTENSIONS_PROP));
+        for (Clause c : extClauses) {
+            Map<String,String> cfg = new HashMap<>();
+
+            for (Directive d : c.getDirectives()) {
+                cfg.put(d.getName(), d.getValue());
+            }
+            be.put(c.getName(), Collections.unmodifiableMap(cfg));
+        }
+
+        binaryExtensions = Collections.unmodifiableMap(be);
+    }
+
+    @Override
+    public boolean handle(ExtensionHandlerContext context, Extension extension, Feature feature) throws Exception {
+        if (extension.getType() != ExtensionType.ARTIFACTS ||
+                binaryExtensions.get(extension.getName()) == null) {
+            return false;
+        } else {
+            // Binary extension
+            // TODO unzip
+
+            return true;
+        }
+    }
+}
diff --git a/src/main/java/org/apache/sling/installer/factory/model/impl/FeatureModelInstallerPlugin.java b/src/main/java/org/apache/sling/installer/factory/model/impl/FeatureModelInstallerPlugin.java
index eaec3c5..048b309 100644
--- a/src/main/java/org/apache/sling/installer/factory/model/impl/FeatureModelInstallerPlugin.java
+++ b/src/main/java/org/apache/sling/installer/factory/model/impl/FeatureModelInstallerPlugin.java
@@ -180,6 +180,9 @@ public class FeatureModelInstallerPlugin implements InstallTaskFactory, Resource
                 if (!feature.isAssembled()) {
                     final BuilderContext ctx = new BuilderContext(this.artifactManager.toFeatureProvider());
                     ctx.setArtifactProvider(this.artifactManager);
+
+                    // Set all merge extensions here from the service registry?
+
                     feature = FeatureBuilder.assemble(feature, ctx);
                 }
 
diff --git a/src/main/java/org/apache/sling/installer/factory/model/impl/InstallFeatureModelTask.java b/src/main/java/org/apache/sling/installer/factory/model/impl/InstallFeatureModelTask.java
index a63ff6b..9b37be6 100644
--- a/src/main/java/org/apache/sling/installer/factory/model/impl/InstallFeatureModelTask.java
+++ b/src/main/java/org/apache/sling/installer/factory/model/impl/InstallFeatureModelTask.java
@@ -26,13 +26,12 @@ import java.io.OutputStream;
 import java.io.Reader;
 import java.io.StringReader;
 import java.net.MalformedURLException;
+import java.net.URL;
 import java.net.URLConnection;
 import java.util.ArrayList;
 import java.util.Dictionary;
 import java.util.Hashtable;
 import java.util.List;
-import java.util.Map;
-import java.util.Properties;
 
 import org.apache.sling.feature.Artifact;
 import org.apache.sling.feature.ArtifactId;
@@ -40,11 +39,12 @@ import org.apache.sling.feature.Configuration;
 import org.apache.sling.feature.Extension;
 import org.apache.sling.feature.ExtensionType;
 import org.apache.sling.feature.Feature;
-import org.apache.sling.feature.extension.apiregions.api.ApiRegions;
-import org.apache.sling.feature.extension.apiregions.launcher.LauncherProperties;
 import org.apache.sling.feature.io.archive.ArchiveReader;
 import org.apache.sling.feature.io.artifacts.ArtifactHandler;
+import org.apache.sling.feature.io.artifacts.ArtifactManager;
 import org.apache.sling.feature.io.json.FeatureJSONReader;
+import org.apache.sling.feature.spi.context.ExtensionHandler;
+import org.apache.sling.feature.spi.context.ExtensionHandlerContext;
 import org.apache.sling.installer.api.InstallableResource;
 import org.apache.sling.installer.api.OsgiInstaller;
 import org.apache.sling.installer.api.tasks.InstallationContext;
@@ -52,27 +52,25 @@ import org.apache.sling.installer.api.tasks.ResourceState;
 import org.apache.sling.installer.api.tasks.TaskResource;
 import org.apache.sling.installer.api.tasks.TaskResourceGroup;
 import org.osgi.framework.BundleContext;
-import org.osgi.framework.Constants;
+import org.osgi.util.tracker.ServiceTracker;
 
 /**
  * This task installs a feature model resources.
  */
 public class InstallFeatureModelTask extends AbstractFeatureModelTask {
+    private final InstallContext installContext;
 
-    private static final String PROP_idbsnver = "mapping.bundleid.bsnver";
-    private static final String PROP_bundleFeatures = "mapping.bundleid.features";
-    private static final String PROP_featureRegions = "mapping.featureid.regions";
-    private static final String PROP_regionPackage = "mapping.region.packages";
-
-    private static final String REGION_FACTORY_PID = "org.apache.sling.feature.apiregions.factory~";
-    private static final String REPOINIT_FACTORY_PID = "org.apache.sling.jcr.repoinit.RepositoryInitializer~";
 
-    private final InstallContext installContext;
+// It's not a DS component so we can't do @Reference
+//    @Reference
+//    private List<ExtensionHandler> extensionHandlers;
+    final ServiceTracker<ExtensionHandler, ExtensionHandler> extensionHandlerTracker;
 
     public InstallFeatureModelTask(final TaskResourceGroup group,
             final InstallContext installContext, final BundleContext bundleContext) {
         super(group, bundleContext);
         this.installContext = installContext;
+        this.extensionHandlerTracker = new ServiceTracker<>(bundleContext, ExtensionHandler.class, null);
     }
 
     @Override
@@ -139,6 +137,32 @@ public class InstallFeatureModelTask extends AbstractFeatureModelTask {
                     cfg.getConfigurationProperties(), null, InstallableResource.TYPE_CONFIG, null));
         }
 
+        ExtensionHandlerContext context = new ContextImpl(result);
+
+        for (Extension ext : feature.getExtensions()) {
+            boolean handlerFound = false;
+            for (ExtensionHandler eh : extensionHandlerTracker.getServices(new ExtensionHandler[] {})) {
+                try {
+                    handlerFound |= eh.handle(context, ext, feature);
+                } catch (Exception e) {
+                    logger.error("Exception while processing extension {} with handler {}", ext, eh, e);
+                }
+
+                if (!handlerFound) {
+                    if (ExtensionType.ARTIFACTS == ext.getType()) {
+                        // Unhandled ARTIFACTS extensions get stored
+                        for (final Artifact artifact : ext.getArtifacts()) {
+                            addArtifact(artifact, result);
+                        }
+                    } else {
+                        // should this be an error?
+                        logger.warn("No extension handler found for mandartory extension " + ext);
+                    }
+                }
+            }
+        }
+
+        /* done by RepoinitExtensionHandler
         // repoinit
         final Extension repoInit = feature.getExtensions().getByName(Extension.EXTENSION_NAME_REPOINIT);
         if (repoInit != null && repoInit.getType() == ExtensionType.TEXT) {
@@ -150,6 +174,7 @@ public class InstallFeatureModelTask extends AbstractFeatureModelTask {
             result.add(new InstallableResource("/".concat(configPid).concat(".config"), null,
                     props, null, InstallableResource.TYPE_CONFIG, null));
         }
+        */
 
         // extract artifacts
         if (this.installContext.storageDirectory != null) {
@@ -178,6 +203,7 @@ public class InstallFeatureModelTask extends AbstractFeatureModelTask {
             }
         }
 
+        /* done by APIRegionsExtensionHandler
         // api regions
         final Extension regionExt = feature.getExtensions().getByName(ApiRegions.EXTENSION_NAME);
         if ( regionExt != null ) {
@@ -198,6 +224,7 @@ public class InstallFeatureModelTask extends AbstractFeatureModelTask {
                 return null;
             }
         }
+        */
 
         // bundles
         for (final Artifact bundle : feature.getBundles()) {
@@ -206,6 +233,7 @@ public class InstallFeatureModelTask extends AbstractFeatureModelTask {
             }
         }
 
+        /*
         // artifact extensions
         for(final Extension ext : feature.getExtensions()) {
             if ( ext.getType() == ExtensionType.ARTIFACTS ) {
@@ -214,19 +242,11 @@ public class InstallFeatureModelTask extends AbstractFeatureModelTask {
                 }
             }
         }
+        */
 
         return result;
     }
 
-    private String[] convert(final Properties props) {
-        final List<String> result = new ArrayList<>();
-
-        for(final Map.Entry<Object, Object> entry : props.entrySet()) {
-            result.add(entry.getKey().toString().concat("=").concat(entry.getValue().toString()));
-        }
-        return result.toArray(new String[result.size()]);
-    }
-
     private boolean addArtifact(final Artifact artifact,
             final List<InstallableResource> result) {
         File artifactFile = (this.installContext.storageDirectory == null ? null
@@ -269,9 +289,43 @@ public class InstallFeatureModelTask extends AbstractFeatureModelTask {
         }
         return true;
     }
-
     @Override
     public String getSortKey() {
         return "30-" + getResource().getAttribute(FeatureModelInstallerPlugin.ATTR_ID);
     }
+
+    private class ContextImpl implements ExtensionHandlerContext {
+        private final List<InstallableResource> results;
+
+        public ContextImpl(List<InstallableResource> results) {
+            this.results = results;
+        }
+
+        @Override
+        public void addBundle(Integer startLevel, URL file) {
+            // TODO Auto-generated method stub
+        }
+
+        @Override
+        public void addInstallableArtifact(URL file) {
+            // TODO Auto-generated method stub
+        }
+
+        @Override
+        public void addConfiguration(String pid, String factoryPid, Dictionary<String, Object> properties) {
+            // TODO handler factoryPid, is this ok?
+            String cfgPid = pid;
+            if (factoryPid != null) {
+                cfgPid = factoryPid;
+            }
+
+            results.add(new InstallableResource("/".concat(cfgPid).concat(".config"), null,
+                    properties, null, InstallableResource.TYPE_CONFIG, null));
+        }
+
+        @Override
+        public ArtifactManager getArtifactManager() {
+            return installContext.artifactManager;
+        }
+    }
 }
diff --git a/src/main/java/org/apache/sling/installer/factory/model/impl/RepoinitExtensionHandler.java b/src/main/java/org/apache/sling/installer/factory/model/impl/RepoinitExtensionHandler.java
new file mode 100644
index 0000000..3ae762a
--- /dev/null
+++ b/src/main/java/org/apache/sling/installer/factory/model/impl/RepoinitExtensionHandler.java
@@ -0,0 +1,33 @@
+package org.apache.sling.installer.factory.model.impl;
+
+import org.apache.sling.feature.Extension;
+import org.apache.sling.feature.ExtensionType;
+import org.apache.sling.feature.Feature;
+import org.apache.sling.feature.spi.context.ExtensionHandler;
+import org.apache.sling.feature.spi.context.ExtensionHandlerContext;
+import org.osgi.framework.Constants;
+import org.osgi.service.component.annotations.Component;
+
+import java.util.Dictionary;
+import java.util.Hashtable;
+
+@Component
+public class RepoinitExtensionHandler implements ExtensionHandler {
+    private static final String REPOINIT_FACTORY_PID = "org.apache.sling.jcr.repoinit.RepositoryInitializer~";
+
+    @Override
+    public boolean handle(ExtensionHandlerContext context, Extension extension, Feature feature) throws Exception {
+        if (!extension.getName().equals(Extension.EXTENSION_NAME_REPOINIT) ||
+                extension.getType() != ExtensionType.TEXT) {
+            return false;
+        }
+
+        final String configPid = REPOINIT_FACTORY_PID.concat(feature.getId().toMvnName().replace('-', '_'));
+        final Dictionary<String, Object> props = new Hashtable<>();
+        props.put("scripts", extension.getText());
+        props.put(Constants.SERVICE_RANKING, 200);
+
+        context.addConfiguration(null, configPid, props);
+        return true;
+    }
+}