You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@sling.apache.org by pa...@apache.org on 2020/01/17 20:31:35 UTC

[sling-org-apache-sling-feature-extension-apiregions] branch master updated: SLING-9007: Add launcher spi that generates the property files. (#4)

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

pauls pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/sling-org-apache-sling-feature-extension-apiregions.git


The following commit(s) were added to refs/heads/master by this push:
     new 3031d96  SLING-9007: Add launcher spi that generates the property files. (#4)
3031d96 is described below

commit 3031d96dcb2004b81c1474b0b92df8155114cac0
Author: Karl Pauls <pa...@apache.org>
AuthorDate: Fri Jan 17 21:31:29 2020 +0100

    SLING-9007: Add launcher spi that generates the property files. (#4)
---
 pom.xml                                            |   6 +
 .../apiregions/APIRegionMergeHandler.java          |  16 ++-
 .../apiregions/launcher/LauncherProperties.java    | 160 +++++++++++++++++++++
 .../apiregions/launcher/RegionLauncher.java        |  71 +++++++++
 .../launcher/RegionLauncherExtension.java          |  54 +++++++
 ...apache.sling.feature.builder.PostProcessHandler |   2 -
 .../org.apache.sling.feature.launcher.spi.Launcher |   1 +
 ...eature.launcher.spi.extensions.ExtensionHandler |   1 +
 8 files changed, 304 insertions(+), 7 deletions(-)

diff --git a/pom.xml b/pom.xml
index 9debc0b..5103f99 100644
--- a/pom.xml
+++ b/pom.xml
@@ -77,6 +77,12 @@
             <version>6.0.0</version>
             <scope>provided</scope>
         </dependency>
+        <dependency>
+            <groupId>org.apache.sling</groupId>
+            <artifactId>org.apache.sling.feature.launcher</artifactId>
+            <version>1.1.1-SNAPSHOT</version>
+            <scope>provided</scope>
+        </dependency>
 
         <!-- Testing -->
         <dependency>
diff --git a/src/main/java/org/apache/sling/feature/extension/apiregions/APIRegionMergeHandler.java b/src/main/java/org/apache/sling/feature/extension/apiregions/APIRegionMergeHandler.java
index 2ad9647..a544954 100644
--- a/src/main/java/org/apache/sling/feature/extension/apiregions/APIRegionMergeHandler.java
+++ b/src/main/java/org/apache/sling/feature/extension/apiregions/APIRegionMergeHandler.java
@@ -69,17 +69,23 @@ public class APIRegionMergeHandler implements MergeHandler {
                             targetRegion.add(srcExp);
                         }
                     }
-                    LinkedHashSet<ArtifactId> origins = new LinkedHashSet<>(Arrays.asList(targetRegion.getFeatureOrigins()));
-                    origins.add(source.getId());
-                    targetRegion.setFeatureOrigins(origins.toArray(new ArtifactId[0]));
+                    LinkedHashSet<ArtifactId> targetOrigins = new LinkedHashSet<>(Arrays.asList(targetRegion.getFeatureOrigins()));
+                    LinkedHashSet<ArtifactId> sourceOrigins = new LinkedHashSet<>(Arrays.asList(sourceRegion.getFeatureOrigins()));
+                    if (sourceOrigins.isEmpty()) {
+                        sourceOrigins.add(source.getId());
+                    }
+                    targetOrigins.addAll(sourceOrigins);
+                    targetRegion.setFeatureOrigins(targetOrigins.toArray(new ArtifactId[0]));
                 }
             }
 
             // If there are any remaining regions in the src extension, process them now
             for (final ApiRegion r : srcRegions.listRegions()) {
                 LinkedHashSet<ArtifactId> origins = new LinkedHashSet<>(Arrays.asList(r.getFeatureOrigins()));
-                origins.add(source.getId());
-                r.setFeatureOrigins(origins.toArray(new ArtifactId[0]));
+                if (origins.isEmpty()) {
+                    origins.add(source.getId());
+                    r.setFeatureOrigins(origins.toArray(new ArtifactId[0]));
+                }
                 if (!targetRegions.add(r)) {
                     throw new IllegalStateException("Duplicate region " + r.getName());
                 }
diff --git a/src/main/java/org/apache/sling/feature/extension/apiregions/launcher/LauncherProperties.java b/src/main/java/org/apache/sling/feature/extension/apiregions/launcher/LauncherProperties.java
new file mode 100644
index 0000000..516ed09
--- /dev/null
+++ b/src/main/java/org/apache/sling/feature/extension/apiregions/launcher/LauncherProperties.java
@@ -0,0 +1,160 @@
+/*
+ * 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.sling.feature.extension.apiregions.launcher;
+
+import java.io.File;
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.io.UncheckedIOException;
+import java.util.Arrays;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.Map;
+import java.util.Properties;
+import java.util.Set;
+import java.util.jar.Attributes;
+import java.util.jar.JarFile;
+import java.util.stream.Collectors;
+
+import org.apache.sling.feature.Artifact;
+import org.apache.sling.feature.ArtifactId;
+import org.apache.sling.feature.Feature;
+import org.apache.sling.feature.builder.ArtifactProvider;
+import org.apache.sling.feature.extension.apiregions.api.ApiExport;
+import org.apache.sling.feature.extension.apiregions.api.ApiRegion;
+import org.apache.sling.feature.extension.apiregions.api.ApiRegions;
+import org.apache.sling.feature.io.IOUtils;
+import org.osgi.framework.Constants;
+import org.osgi.framework.Version;
+
+public class LauncherProperties
+{
+    public static Properties getBundleIDtoBSNandVersionMap(Feature app, ArtifactProvider artifactProvider) {
+        Map<ArtifactId, String> map = new HashMap<>();
+
+        for (Artifact bundle : app.getBundles())
+        {
+            map.computeIfAbsent(bundle.getId(), id ->
+            {
+                try(JarFile jarFile = IOUtils.getJarFileFromURL(artifactProvider.provide(id), true, null)) {
+                    Attributes manifest = jarFile.getManifest().getMainAttributes();
+                    String bsn = manifest.getValue(Constants.BUNDLE_SYMBOLICNAME);
+                    if (bsn != null && !bsn.trim().isEmpty())
+                    {
+                        return bsn.trim() + "~" + Version.parseVersion(manifest.getValue(Constants.BUNDLE_VERSION));
+                    }
+                    else {
+                        return null;
+                    }
+                } catch (IOException ex) {
+                    throw new UncheckedIOException(ex);
+                }
+            });
+        }
+
+        Properties result = new Properties();
+
+        for (Map.Entry<ArtifactId, String> entry : map.entrySet()) {
+            result.setProperty(entry.getKey().toMvnId(), entry.getValue());
+        }
+
+        return result;
+    }
+
+    public static Properties getBundleIDtoFeaturesMap(Feature app) {
+        Map<ArtifactId, Set<ArtifactId>> map = new HashMap<>();
+
+        for (Artifact bundle : app.getBundles())
+        {
+            map.compute(bundle.getId(), (id, features) ->
+            {
+                if (features == null)
+                {
+                    features = new HashSet<>();
+                }
+                features.addAll(Arrays.asList(bundle.getFeatureOrigins()));
+                return features;
+            });
+        }
+
+        Properties result = new Properties();
+
+        for (Map.Entry<ArtifactId, Set<ArtifactId>> entry : map.entrySet()) {
+            result.setProperty(entry.getKey().toMvnId(), entry.getValue().stream().map(ArtifactId::toMvnId).collect(Collectors.joining(",")));
+        }
+
+        return result;
+    }
+
+    public static Properties getFeatureIDtoRegionsMap(ApiRegions regions) {
+        Map<ArtifactId, Set<String>> map = new HashMap<>();
+
+        for (ApiRegion region : regions.listRegions())
+        {
+            for (ArtifactId featureId : region.getFeatureOrigins()) {
+                map.compute(featureId, (id, regionNames) -> {
+                    if (regionNames == null) {
+                        regionNames = new HashSet<>();
+                    }
+                    regionNames.add(region.getName());
+                    return regionNames;
+                });
+            }
+        }
+
+        Properties result = new Properties();
+
+        for (Map.Entry<ArtifactId, Set<String>> entry : map.entrySet()) {
+            result.setProperty(entry.getKey().toMvnId(), String.join(",", entry.getValue()));
+        }
+
+        return result;
+    }
+
+    public static Properties getRegionNametoPackagesMap(ApiRegions regions) {
+        Map<String, Set<String>> map = new HashMap<>();
+
+        for (ApiRegion region : regions.listRegions())
+        {
+            for (ApiExport export : region.listExports()) {
+                map.compute(region.getName(), (name, exports) -> {
+                    if (exports == null) {
+                        exports = new HashSet<>();
+                    }
+                    exports.add(export.getName());
+                    return exports;
+                });
+            }
+        }
+
+        Properties result = new Properties();
+
+        for (Map.Entry<String, Set<String>> entry : map.entrySet()) {
+            result.setProperty(entry.getKey(), String.join(",", entry.getValue()));
+        }
+
+        return result;
+    }
+
+
+    public static void save(Properties properties, File file) throws IOException {
+        try (FileOutputStream output = new FileOutputStream(file))
+        {
+            properties.store(output, "");
+        }
+    }
+}
diff --git a/src/main/java/org/apache/sling/feature/extension/apiregions/launcher/RegionLauncher.java b/src/main/java/org/apache/sling/feature/extension/apiregions/launcher/RegionLauncher.java
new file mode 100644
index 0000000..850581d
--- /dev/null
+++ b/src/main/java/org/apache/sling/feature/extension/apiregions/launcher/RegionLauncher.java
@@ -0,0 +1,71 @@
+/*
+ * 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.sling.feature.extension.apiregions.launcher;
+
+import java.io.File;
+import java.io.IOException;
+import java.io.UncheckedIOException;
+
+import org.apache.sling.feature.ArtifactId;
+import org.apache.sling.feature.Feature;
+import org.apache.sling.feature.builder.ArtifactProvider;
+import org.apache.sling.feature.launcher.impl.launchers.FrameworkLauncher;
+import org.apache.sling.feature.launcher.spi.LauncherPrepareContext;
+import org.apache.sling.feature.launcher.spi.LauncherRunContext;
+
+public class RegionLauncher extends FrameworkLauncher
+{
+    public static final String IDBSNVER_FILENAME = "idbsnver.properties";
+    public static final String BUNDLE_FEATURE_FILENAME = "bundles.properties";
+
+    @Override
+    public void prepare(LauncherPrepareContext context, ArtifactId frameworkId, Feature app) throws Exception
+    {
+        super.prepare(context, frameworkId, app);
+
+        ArtifactProvider artifactProvider = id ->
+        {
+            try
+            {
+                return context.getArtifactFile(id);
+            }
+            catch (IOException e)
+            {
+                throw new UncheckedIOException(e);
+            }
+        };
+
+
+        final File base = File.createTempFile("apiregions", ".properties");
+        base.delete();
+        base.mkdirs();
+        File idbsnverFile = new File(base, IDBSNVER_FILENAME);
+        File bundlesFile = new File(base, BUNDLE_FEATURE_FILENAME);
+
+        LauncherProperties.save(LauncherProperties.getBundleIDtoBSNandVersionMap(app, artifactProvider), idbsnverFile);
+        LauncherProperties.save(LauncherProperties.getBundleIDtoFeaturesMap(app), bundlesFile);
+
+        app.getFrameworkProperties().put("sling.feature.apiregions.resource." + IDBSNVER_FILENAME, idbsnverFile.toURI().toURL().toString());
+        app.getFrameworkProperties().put("sling.feature.apiregions.resource." + BUNDLE_FEATURE_FILENAME, bundlesFile.toURI().toURL().toString());
+    }
+
+    @Override
+    public int run(LauncherRunContext context, ClassLoader cl) throws Exception
+    {
+        return super.run(context, cl);
+    }
+}
diff --git a/src/main/java/org/apache/sling/feature/extension/apiregions/launcher/RegionLauncherExtension.java b/src/main/java/org/apache/sling/feature/extension/apiregions/launcher/RegionLauncherExtension.java
new file mode 100644
index 0000000..7a180a7
--- /dev/null
+++ b/src/main/java/org/apache/sling/feature/extension/apiregions/launcher/RegionLauncherExtension.java
@@ -0,0 +1,54 @@
+/*
+ * 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.sling.feature.extension.apiregions.launcher;
+
+import java.io.File;
+import javax.json.JsonArray;
+
+import org.apache.sling.feature.Extension;
+import org.apache.sling.feature.extension.apiregions.api.ApiRegions;
+import org.apache.sling.feature.launcher.spi.extensions.ExtensionContext;
+import org.apache.sling.feature.launcher.spi.extensions.ExtensionHandler;
+
+public class RegionLauncherExtension implements ExtensionHandler
+{
+    public static final String FEATURE_REGION_FILENAME = "features.properties";
+    public static final String REGION_PACKAGE_FILENAME = "regions.properties";
+
+    @Override
+    public boolean handle(ExtensionContext extensionContext, Extension extension) throws Exception
+    {
+        if (!extension.getName().equals(ApiRegions.EXTENSION_NAME))
+            return false;
+
+        final File base = File.createTempFile("apiregions", ".properties");
+        base.delete();
+        base.mkdirs();
+        File featuresFile = new File(base, FEATURE_REGION_FILENAME);
+        File regionsFile = new File(base, REGION_PACKAGE_FILENAME);
+
+        final ApiRegions apiRegions = ApiRegions.parse((JsonArray) extension.getJSONStructure());
+
+        LauncherProperties.save(LauncherProperties.getFeatureIDtoRegionsMap(apiRegions), featuresFile);
+        LauncherProperties.save(LauncherProperties.getRegionNametoPackagesMap(apiRegions), regionsFile);
+
+        extensionContext.addFrameworkProperty("sling.feature.apiregions.resource." + FEATURE_REGION_FILENAME, featuresFile.toURI().toURL().toString());
+        extensionContext.addFrameworkProperty("sling.feature.apiregions.resource." + REGION_PACKAGE_FILENAME, regionsFile.toURI().toURL().toString());
+
+        return true;
+    }
+}
diff --git a/src/main/resources/META-INF/services/org.apache.sling.feature.builder.PostProcessHandler b/src/main/resources/META-INF/services/org.apache.sling.feature.builder.PostProcessHandler
deleted file mode 100644
index 1bf6138..0000000
--- a/src/main/resources/META-INF/services/org.apache.sling.feature.builder.PostProcessHandler
+++ /dev/null
@@ -1,2 +0,0 @@
-org.apache.sling.feature.extension.apiregions.BundleMappingHandler
-org.apache.sling.feature.extension.apiregions.BundleArtifactFeatureHandler
diff --git a/src/main/resources/META-INF/services/org.apache.sling.feature.launcher.spi.Launcher b/src/main/resources/META-INF/services/org.apache.sling.feature.launcher.spi.Launcher
new file mode 100644
index 0000000..887412d
--- /dev/null
+++ b/src/main/resources/META-INF/services/org.apache.sling.feature.launcher.spi.Launcher
@@ -0,0 +1 @@
+org.apache.sling.feature.extension.apiregions.launcher.RegionLauncher
\ No newline at end of file
diff --git a/src/main/resources/META-INF/services/org.apache.sling.feature.launcher.spi.extensions.ExtensionHandler b/src/main/resources/META-INF/services/org.apache.sling.feature.launcher.spi.extensions.ExtensionHandler
new file mode 100644
index 0000000..89e2efc
--- /dev/null
+++ b/src/main/resources/META-INF/services/org.apache.sling.feature.launcher.spi.extensions.ExtensionHandler
@@ -0,0 +1 @@
+org.apache.sling.feature.extension.apiregions.launcher.RegionLauncherExtension
\ No newline at end of file