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 2018/04/03 13:45:55 UTC

[sling-whiteboard] branch master updated: Improve handling of runmodes in provisioning model-feature conversions

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

davidb pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/sling-whiteboard.git


The following commit(s) were added to refs/heads/master by this push:
     new 364eb10  Improve handling of runmodes in provisioning model-feature conversions
364eb10 is described below

commit 364eb107feade07af92161569845b1c1d0bd5a86
Author: David Bosschaert <da...@gmail.com>
AuthorDate: Tue Apr 3 14:43:49 2018 +0100

    Improve handling of runmodes in provisioning model-feature conversions
    
    Also handle cases where ':' is used in configuration keys, something
    that the OSGi configurator doesn't allow.
---
 .../modelconverter/impl/FeatureToProvisioning.java | 46 +++++++---
 .../modelconverter/impl/ProvisioningToFeature.java | 97 ++++++++++++++--------
 .../modelconverter/impl/ModelConverterTest.java    | 62 ++++++++++----
 .../src/test/resources/boot.json                   |  5 ++
 .../src/test/resources/boot.txt                    |  6 ++
 .../src/test/resources/launchpad.json              | 28 +++++++
 .../src/test/resources/launchpad.txt               | 20 +++++
 .../src/test/resources/oak.json                    |  6 +-
 .../src/test/resources/simple.json                 |  9 ++
 .../src/test/resources/simple.txt                  | 24 ++++++
 10 files changed, 239 insertions(+), 64 deletions(-)

diff --git a/featuremodel/feature-modelconverter/src/main/java/org/apache/sling/feature/modelconverter/impl/FeatureToProvisioning.java b/featuremodel/feature-modelconverter/src/main/java/org/apache/sling/feature/modelconverter/impl/FeatureToProvisioning.java
index 3c904fe..dd6d830 100644
--- a/featuremodel/feature-modelconverter/src/main/java/org/apache/sling/feature/modelconverter/impl/FeatureToProvisioning.java
+++ b/featuremodel/feature-modelconverter/src/main/java/org/apache/sling/feature/modelconverter/impl/FeatureToProvisioning.java
@@ -151,40 +151,64 @@ public class FeatureToProvisioning {
         // configurations
         for(final org.apache.sling.feature.Configuration cfg : configurations) {
             final Configuration c;
+
+            String[] runModes = null;
             if ( cfg.isFactoryConfiguration() ) {
                 c = new Configuration(cfg.getName(), cfg.getFactoryPid());
             } else {
-                c = new Configuration(cfg.getPid(), null);
+                String pid = cfg.getPid();
+                pid = pid.replaceAll("[.][.](\\S+)", ":$1");
+                int rmIdx = pid.indexOf(".runmodes.");
+                if (rmIdx > 0) {
+                    String rm = pid.substring(rmIdx + ".runmodes.".length());
+                    pid = pid.substring(0, rmIdx);
+                    runModes = rm.split("[.]");
+                }
+                c = new Configuration(pid, null);
             }
             final Enumeration<String> keys = cfg.getProperties().keys();
             while ( keys.hasMoreElements() ) {
-                final String key = keys.nextElement();
-                c.getProperties().put(key, cfg.getProperties().get(key));
-            }
+                String key = keys.nextElement();
+                Object val = cfg.getProperties().get(key);
 
-            String[] runModes = null;
-            Object rm = c.getProperties().remove(".runmodes");
-            if (rm instanceof String) {
-                runModes = ((String) rm).split(",");
+                if (key.startsWith("..")) {
+                    key = ":" + key.substring(2);
+                }
+                c.getProperties().put(key, val);
             }
+
             f.getOrCreateRunMode(runModes).getConfigurations().add(c);
         }
 
         // framework properties
         for(final Map.Entry<String, String> prop : frameworkProps) {
-            f.getOrCreateRunMode(null).getSettings().put(prop.getKey(), prop.getValue());
+            String key = prop.getKey();
+            if (key.startsWith(".runmodes:")) {
+                int lastIdx = key.lastIndexOf(':');
+                String rm = key.substring(".runmodes:".length(), lastIdx);
+                String[] runmodes = rm.split(",");
+                key = key.substring(lastIdx + 1);
+                f.getOrCreateRunMode(runmodes).getSettings().put(key, prop.getValue());
+            } else {
+                f.getOrCreateRunMode(null).getSettings().put(key, prop.getValue());
+            }
         }
 
         // extensions: content packages and repoinit
         for(final Extension ext : extensions) {
             if ( Extension.NAME_CONTENT_PACKAGES.equals(ext.getName()) ) {
                 for(final org.apache.sling.feature.Artifact cp : ext.getArtifacts() ) {
+                    String[] runmodes = null;
                     final ArtifactId id = cp.getId();
                     final Artifact newCP = new Artifact(id.getGroupId(), id.getArtifactId(), id.getVersion(), id.getClassifier(), id.getType());
                     for(final Map.Entry<String, String> prop : cp.getMetadata()) {
-                        newCP.getMetadata().put(prop.getKey(), prop.getValue());
+                        if (prop.getKey().equals("runmodes")) {
+                            runmodes = prop.getValue().split(",");
+                        } else {
+                            newCP.getMetadata().put(prop.getKey(), prop.getValue());
+                        }
                     }
-                    f.getOrCreateRunMode(null).getOrCreateArtifactGroup(0).add(newCP);
+                    f.getOrCreateRunMode(runmodes).getOrCreateArtifactGroup(20).add(newCP);
                 }
 
             } else if ( Extension.NAME_REPOINIT.equals(ext.getName()) ) {
diff --git a/featuremodel/feature-modelconverter/src/main/java/org/apache/sling/feature/modelconverter/impl/ProvisioningToFeature.java b/featuremodel/feature-modelconverter/src/main/java/org/apache/sling/feature/modelconverter/impl/ProvisioningToFeature.java
index 62a4f00..6af4aa3 100644
--- a/featuremodel/feature-modelconverter/src/main/java/org/apache/sling/feature/modelconverter/impl/ProvisioningToFeature.java
+++ b/featuremodel/feature-modelconverter/src/main/java/org/apache/sling/feature/modelconverter/impl/ProvisioningToFeature.java
@@ -148,7 +148,7 @@ public class ProvisioningToFeature {
             modes = calculateRunModes(effectiveModel, runModes);
         }
 
-        removeInactiveFeaturesAndRunModes(effectiveModel, modes);
+        // removeInactiveFeaturesAndRunModes(effectiveModel, modes);
 
         return effectiveModel;
     }
@@ -237,6 +237,7 @@ public class ProvisioningToFeature {
         }
     }
 
+    // TODO is this needed for something?
     private static void removeInactiveFeaturesAndRunModes(final Model m,
             final Set<String> activeRunModes) {
         final String[] requiredFeatures = new String[] {ModelConstants.FEATURE_LAUNCHPAD, ModelConstants.FEATURE_BOOT};
@@ -394,35 +395,33 @@ public class ProvisioningToFeature {
 
         Extension cpExtension = extensions.getByName(Extension.NAME_CONTENT_PACKAGES);
         for(final RunMode runMode : feature.getRunModes() ) {
-            if ( !ModelConstants.FEATURE_LAUNCHPAD.equals(feature.getName()) ) {
-                for(final ArtifactGroup group : runMode.getArtifactGroups()) {
-                    for(final Artifact artifact : group) {
-                        final ArtifactId id = ArtifactId.fromMvnUrl(artifact.toMvnUrl());
-                        final org.apache.sling.feature.Artifact newArtifact = new org.apache.sling.feature.Artifact(id);
+            for(final ArtifactGroup group : runMode.getArtifactGroups()) {
+                for(final Artifact artifact : group) {
+                    final ArtifactId id = ArtifactId.fromMvnUrl(artifact.toMvnUrl());
+                    final org.apache.sling.feature.Artifact newArtifact = new org.apache.sling.feature.Artifact(id);
 
-                        for(final Map.Entry<String, String> entry : artifact.getMetadata().entrySet()) {
-                            newArtifact.getMetadata().put(entry.getKey(), entry.getValue());
-                        }
+                    for(final Map.Entry<String, String> entry : artifact.getMetadata().entrySet()) {
+                        newArtifact.getMetadata().put(entry.getKey(), entry.getValue());
+                    }
 
-                        if ( newArtifact.getId().getType().equals("zip") ) {
-                            if ( cpExtension == null ) {
-                                cpExtension = new Extension(ExtensionType.ARTIFACTS, Extension.NAME_CONTENT_PACKAGES, true);
-                                extensions.add(cpExtension);
-                            }
-                            cpExtension.getArtifacts().add(newArtifact);
-                        } else {
-                            int startLevel = group.getStartLevel();
-                            if ( startLevel == 0) {
-                                if ( ModelConstants.FEATURE_BOOT.equals(feature.getName()) ) {
-                                    startLevel = 1;
-                                } else if ( startLevel == 0 ) {
-                                    startLevel = 20;
-                                }
+                    if ( newArtifact.getId().getType().equals("zip") ) {
+                        if ( cpExtension == null ) {
+                            cpExtension = new Extension(ExtensionType.ARTIFACTS, Extension.NAME_CONTENT_PACKAGES, true);
+                            extensions.add(cpExtension);
+                        }
+                        cpExtension.getArtifacts().add(newArtifact);
+                    } else {
+                        int startLevel = group.getStartLevel();
+                        if ( startLevel == 0) {
+                            if ( ModelConstants.FEATURE_BOOT.equals(feature.getName()) ) {
+                                startLevel = 1;
+                            } else if ( startLevel == 0 ) {
+                                startLevel = 20;
                             }
-                            newArtifact.getMetadata().put("start-level", String.valueOf(startLevel));
-
-                            bundles.add(newArtifact);
                         }
+                        newArtifact.getMetadata().put("start-level", String.valueOf(startLevel));
+
+                        bundles.add(newArtifact);
                     }
                 }
             }
@@ -430,26 +429,54 @@ public class ProvisioningToFeature {
             for(final Configuration cfg : runMode.getConfigurations()) {
                 final org.apache.sling.feature.Configuration newCfg;
                 if ( cfg.getFactoryPid() != null ) {
-                    newCfg = new org.apache.sling.feature.Configuration(cfg.getFactoryPid(), cfg.getPid());
+                    String pid = cfg.getPid();
+                    if (pid.startsWith(":")) {
+                        // The configurator doesn't accept colons ':' in it's keys, so replace these
+                        pid = ".." + pid.substring(1);
+                    }
+
+                    String[] runModeNames = runMode.getNames();
+                    if (runModeNames != null) {
+                        pid = pid + ".runmodes." + String.join(".", runModeNames);
+                    }
+
+                    newCfg = new org.apache.sling.feature.Configuration(cfg.getFactoryPid(), pid);
                 } else {
-                    newCfg = new org.apache.sling.feature.Configuration(cfg.getPid());
+                    String pid = cfg.getPid();
+                    if (pid.startsWith(":")) {
+                        // The configurator doesn't accept colons ':' in it's keys, so replace these
+                        pid = ".." + pid.substring(1);
+                    }
+
+                    String[] runModeNames = runMode.getNames();
+                    if (runModeNames != null) {
+                        pid = pid + ".runmodes." + String.join(".", runModeNames);
+                    }
+
+                    newCfg = new org.apache.sling.feature.Configuration(pid);
                 }
                 final Enumeration<String> keys = cfg.getProperties().keys();
                 while ( keys.hasMoreElements() ) {
-                    final String key = keys.nextElement();
-                    newCfg.getProperties().put(key, cfg.getProperties().get(key));
-                }
+                    String key = keys.nextElement();
+                    Object value = cfg.getProperties().get(key);
 
-                String[] runModeNames = runMode.getNames();
-                if (runModeNames != null) {
-                    newCfg.getProperties().put(".runmodes", String.join(",", runModeNames));
+                    if (key.startsWith(":")) {
+                        key = ".." + key.substring(1);
+                    }
+                    newCfg.getProperties().put(key, value);
                 }
 
                 configurations.add(newCfg);
             }
 
             for(final Map.Entry<String, String> prop : runMode.getSettings()) {
-                properties.put(prop.getKey(), prop.getValue());
+                String[] runModeNames = runMode.getNames();
+                if (runModeNames == null) {
+                    properties.put(prop.getKey(), prop.getValue());
+                } else {
+                    properties.put(".runmodes:" + String.join(",", runModeNames) + ":" +
+                            prop.getKey(), prop.getValue());
+                }
             }
         }
         Extension repoExtension = extensions.getByName(Extension.NAME_REPOINIT);
diff --git a/featuremodel/feature-modelconverter/src/test/java/org/apache/sling/feature/modelconverter/impl/ModelConverterTest.java b/featuremodel/feature-modelconverter/src/test/java/org/apache/sling/feature/modelconverter/impl/ModelConverterTest.java
index 98f2dbc..249d9dc 100644
--- a/featuremodel/feature-modelconverter/src/test/java/org/apache/sling/feature/modelconverter/impl/ModelConverterTest.java
+++ b/featuremodel/feature-modelconverter/src/test/java/org/apache/sling/feature/modelconverter/impl/ModelConverterTest.java
@@ -115,6 +115,26 @@ public class ModelConverterTest {
     }
 
     @Test
+    public void testLaunchpadToProvModel() throws Exception {
+        testConvertToProvisioningModel("/launchpad.json", "/launchpad.txt");
+    }
+
+    @Test
+    public void testLaunchpadToFeature() throws Exception {
+        testConvertToFeature("/launchpad.txt", "/launchpad.json");
+    }
+
+    @Test
+    public void testSimpleToProvModel() throws Exception {
+        testConvertToProvisioningModel("/simple.json", "/simple.txt");
+    }
+
+    @Test
+    public void testSimpleToFeature() throws Exception {
+        testConvertToFeature("/simple.txt", "/simple.json");
+    }
+
+    @Test
     public void testProvModelRoundtripFolder() throws Exception {
         String dir = System.getProperty("test.prov.files.dir");
         File filesDir;
@@ -365,27 +385,31 @@ public class ModelConverterTest {
 
             boolean found = false;
             for (Configuration cfg2 : configs2) {
-                if (!cfg2.getPid().equals(cfg1.getPid())) {
+                if (cfg1.getFactoryPid() == null) {
+                    if (cfg2.getFactoryPid() != null) {
+                        continue;
+                    }
+                } else if (!cfg1.getFactoryPid().equals(cfg2.getFactoryPid())) {
                     continue;
                 }
-                found = true;
 
-                if (cfg1.getFactoryPid() == null) {
-                    if (cfg2.getFactoryPid() != null)
-                        return false;
-                } else {
-                    if (!cfg1.getFactoryPid().equals(cfg2.getFactoryPid())) {
-                        return false;
-                    }
+                if (!cfg1.getPid().equals(cfg2.getPid())) {
+                    continue;
                 }
 
+                // Factory and ordinary PIDs are equal, so check the content
+                found = true;
+
                 if (!configPropsEqual(cfg1.getProperties(), cfg2.getProperties())) {
                     return false;
                 }
 
                 break;
             }
-            assertTrue("Configuration with PID " + cfg1.getPid() + " not found", found);
+            if (!found) {
+                // Configuration with this PID not found
+                return false;
+            }
         }
 
         Map<String, String> m1 = kvToMap(rm1.getSettings());
@@ -426,13 +450,23 @@ public class ModelConverterTest {
         List<Artifact> al2 = new ArrayList<>();
         g2.iterator().forEachRemaining(al2::add);
 
-        for (int i=0; i < al1.size(); i++) {
+        for (int i=0; i<al1.size(); i++) {
             Artifact a1 = al1.get(i);
-            Artifact a2 = al2.get(i);
-            if (a1.compareTo(a2) != 0)
+            boolean found = false;
+            for (Iterator<Artifact> it = al2.iterator(); it.hasNext(); ) {
+                Artifact a2 = it.next();
+                if (a1.compareTo(a2) == 0) {
+                    found = true;
+                    it.remove();
+                }
+            }
+            if (!found) {
                 return false;
+            }
         }
-        return true;
+
+        // Should have found all artifacts
+        return (al2.size() == 0);
     }
 
     private int effectiveStartLevel(String featureName, int startLevel) {
diff --git a/featuremodel/feature-modelconverter/src/test/resources/boot.json b/featuremodel/feature-modelconverter/src/test/resources/boot.json
index c267b67..4cc7d40 100644
--- a/featuremodel/feature-modelconverter/src/test/resources/boot.json
+++ b/featuremodel/feature-modelconverter/src/test/resources/boot.json
@@ -90,6 +90,11 @@
         "sling.run.mode.install.options": "oak_tar,oak_mongo",
         "repository.home": "${sling.home}/repository",
         "localIndexDir": "${sling.home}/repository/index",
+        
+        "# we need runmodes here too...": "",
+        ".runmodes:a:something": "else",
+        ".runmodes::b:special": "true", 
+        
         "#": "${sling.home} needs to be provided at launch time"
     }
 }
diff --git a/featuremodel/feature-modelconverter/src/test/resources/boot.txt b/featuremodel/feature-modelconverter/src/test/resources/boot.txt
index df5a947..d8a6fec 100644
--- a/featuremodel/feature-modelconverter/src/test/resources/boot.txt
+++ b/featuremodel/feature-modelconverter/src/test/resources/boot.txt
@@ -28,6 +28,12 @@
     sling.run.mode.install.options=oak_tar,oak_mongo
     repository.home=${sling.home}/repository
     localIndexDir=${sling.home}/repository/index
+    
+[settings runModes=:b]
+    special=true    
+    
+[settings runModes=a]
+    something=else    
 
 [variables]
     slf4j.version=1.7.25
diff --git a/featuremodel/feature-modelconverter/src/test/resources/launchpad.json b/featuremodel/feature-modelconverter/src/test/resources/launchpad.json
new file mode 100644
index 0000000..0dd9318
--- /dev/null
+++ b/featuremodel/feature-modelconverter/src/test/resources/launchpad.json
@@ -0,0 +1,28 @@
+{
+  "id":"generated:feature:1.0.0",
+  "variables":{
+    "provisioning.model.name":":launchpad"
+  },
+  "bundles":[
+    {
+      "id":"org.apache.sling:org.apache.sling.launchpad.base:5.6.10-2.6.26",
+      "start-level":"20"
+    },
+    {
+      "id":"org.apache.sling:org.apache.sling.commons.osgi:2.4.0",
+      "run-modes":":something",
+      "start-level":"20"
+    }
+  ],
+  "configurations":{
+    "..bootstrap":{
+      "..bootstrap":"uninstall com.google.guava 15.0.0\n"
+    },
+    "..bootstrap.runmodes.:standalone":{
+      "..bootstrap":"uninstall org.apache.felix.http.bridge\nuninstall org.apache.felix.http.api\n"
+    },
+    "org.apache.testing.ConfigPid.factory-configuration.runmodes.:standalone":{
+      "key1":"val1"
+    }
+  }
+}
\ No newline at end of file
diff --git a/featuremodel/feature-modelconverter/src/test/resources/launchpad.txt b/featuremodel/feature-modelconverter/src/test/resources/launchpad.txt
new file mode 100644
index 0000000..188bf76
--- /dev/null
+++ b/featuremodel/feature-modelconverter/src/test/resources/launchpad.txt
@@ -0,0 +1,20 @@
+[feature name=:launchpad]
+
+[artifacts]
+  org.apache.sling/org.apache.sling.launchpad.base/5.6.10-2.6.26
+
+[configurations]
+  :bootstrap
+    uninstall com.google.guava 15.0.0
+
+[artifacts runModes=:something]
+
+  org.apache.sling/org.apache.sling.commons.osgi/2.4.0
+
+[configurations runModes=:standalone]
+  :bootstrap
+    uninstall org.apache.felix.http.bridge
+    uninstall org.apache.felix.http.api
+
+  org.apache.testing.ConfigPid.factory-configuration
+    key1="val1"
diff --git a/featuremodel/feature-modelconverter/src/test/resources/oak.json b/featuremodel/feature-modelconverter/src/test/resources/oak.json
index d94aa8d..03f64c3 100644
--- a/featuremodel/feature-modelconverter/src/test/resources/oak.json
+++ b/featuremodel/feature-modelconverter/src/test/resources/oak.json
@@ -86,12 +86,10 @@
             "userPrivilegeNames": ["jcr:all"],
             "groupPrivilegeNames": ["jcr:read"]
         },
-        "org.apache.jackrabbit.oak.segment.SegmentNodeStoreService": {
-            ".runmodes": "oak_tar", 
+        "org.apache.jackrabbit.oak.segment.SegmentNodeStoreService.runmodes.oak_tar": {
             "name": "Default NodeStore"
         },
-        "org.apache.jackrabbit.oak.plugins.document.DocumentNodeStoreService": {
-            ".runmodes": "oak_mongo", 
+        "org.apache.jackrabbit.oak.plugins.document.DocumentNodeStoreService.runmodes.oak_mongo": {
             "mongouri": "mongodb://localhost:27017",
             "db": "sling"
         }
diff --git a/featuremodel/feature-modelconverter/src/test/resources/simple.json b/featuremodel/feature-modelconverter/src/test/resources/simple.json
new file mode 100644
index 0000000..4cc130a
--- /dev/null
+++ b/featuremodel/feature-modelconverter/src/test/resources/simple.json
@@ -0,0 +1,9 @@
+{
+  "id":"generated:simple:1.0.0",
+  "bundles":[
+    {
+      "id":"org.apache.aries:org.apache.aries.util:1.1.3",
+      "start-level":"20"
+    }
+  ]
+}
diff --git a/featuremodel/feature-modelconverter/src/test/resources/simple.txt b/featuremodel/feature-modelconverter/src/test/resources/simple.txt
new file mode 100644
index 0000000..53e40a2
--- /dev/null
+++ b/featuremodel/feature-modelconverter/src/test/resources/simple.txt
@@ -0,0 +1,24 @@
+#
+#  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.
+#
+# The :boot feature contains all things to bootstrap the installation.
+#
+[feature name=simple]
+
+[artifacts]
+    org.apache.aries/org.apache.aries.util/1.1.3

-- 
To stop receiving notification emails like this one, please contact
davidb@apache.org.