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/03/20 10:47:09 UTC

[sling-whiteboard] branch master updated: Support variables in converting from features to provisioning model

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 66f6185  Support variables in converting from features to provisioning model
66f6185 is described below

commit 66f618560ba46eea302d88fa41eab76be672ad03
Author: David Bosschaert <da...@gmail.com>
AuthorDate: Tue Mar 20 10:46:52 2018 +0000

    Support variables in converting from features to provisioning model
---
 .../sling/feature/analyser/AnalyserTest.java       |   6 +-
 .../impl/ApplicationBuilderTest.java               |   4 +-
 featuremodel/feature-modelconverter/pom.xml        |  18 +++-
 .../modelconverter/impl/FeatureToProvisioning.java |  24 +++--
 .../modelconverter/impl/ModelConverterTest.java    |  74 +++++++++++++--
 .../src/test/resources/boot.json                   |  92 +++++++++++++++----
 .../src/test/resources/boot.txt                    |  70 +++++++++-----
 .../src/test/resources/oak.json                    | 101 +++++++++++++++++++++
 .../src/test/resources/oak.txt                     |  91 +++++++++++++++++++
 .../feature/resolver/FrameworkResolverTest.java    |   4 +-
 .../apache/sling/feature/support/FeatureUtil.java  |  13 ++-
 .../feature/support/json/FeatureJSONReader.java    |  14 +--
 .../support/json/FeatureJSONReaderTest.java        |   6 +-
 .../support/json/FeatureJSONWriterTest.java        |   4 +-
 .../org/apache/sling/feature/support/json/U.java   |   6 +-
 .../java/org/apache/sling/feature/Application.java |  11 +++
 .../java/org/apache/sling/feature/ArtifactId.java  |   6 +-
 .../apache/sling/feature/maven/Preprocessor.java   |  10 +-
 .../apache/sling/feature/maven/ProjectHelper.java  |   6 +-
 19 files changed, 464 insertions(+), 96 deletions(-)

diff --git a/featuremodel/feature-analyser/src/test/java/org/apache/sling/feature/analyser/AnalyserTest.java b/featuremodel/feature-analyser/src/test/java/org/apache/sling/feature/analyser/AnalyserTest.java
index f2b4b95..8fd9bd5 100644
--- a/featuremodel/feature-analyser/src/test/java/org/apache/sling/feature/analyser/AnalyserTest.java
+++ b/featuremodel/feature-analyser/src/test/java/org/apache/sling/feature/analyser/AnalyserTest.java
@@ -28,7 +28,7 @@ import org.apache.sling.feature.support.ArtifactManager;
 import org.apache.sling.feature.support.ArtifactManagerConfig;
 import org.apache.sling.feature.support.FeatureUtil;
 import org.apache.sling.feature.support.json.FeatureJSONReader;
-import org.apache.sling.feature.support.json.FeatureJSONReader.Phase;
+import org.apache.sling.feature.support.json.FeatureJSONReader.SubstituteVariables;
 import org.junit.Test;
 
 import java.io.File;
@@ -47,7 +47,7 @@ public class AnalyserTest {
         final Analyser analyser = new Analyser(scanner);
         try ( final Reader reader = new InputStreamReader(AnalyserTest.class.getResourceAsStream("/feature_complete.json"),
                 "UTF-8") ) {
-            Feature feature = FeatureJSONReader.read(reader, "feature", Phase.RESOLVE);
+            Feature feature = FeatureJSONReader.read(reader, "feature", SubstituteVariables.RESOLVE);
 
             Application app = FeatureUtil.assembleApplication(null, ArtifactManager.getArtifactManager(new ArtifactManagerConfig()),
                     getTestResolver(), feature);
@@ -62,7 +62,7 @@ public class AnalyserTest {
         final Analyser analyser = new Analyser(scanner);
         try ( final Reader reader = new InputStreamReader(AnalyserTest.class.getResourceAsStream("/feature_incomplete.json"),
                 "UTF-8") ) {
-            Feature feature = FeatureJSONReader.read(reader, "feature", Phase.RESOLVE);
+            Feature feature = FeatureJSONReader.read(reader, "feature", SubstituteVariables.RESOLVE);
 
             Application app = FeatureUtil.assembleApplication(null, ArtifactManager.getArtifactManager(new ArtifactManagerConfig()),
                     getTestResolver(), feature);
diff --git a/featuremodel/feature-applicationbuilder/src/test/java/org/apache/sling/feature/applicationbuilder/impl/ApplicationBuilderTest.java b/featuremodel/feature-applicationbuilder/src/test/java/org/apache/sling/feature/applicationbuilder/impl/ApplicationBuilderTest.java
index 9d84329..6efa834 100644
--- a/featuremodel/feature-applicationbuilder/src/test/java/org/apache/sling/feature/applicationbuilder/impl/ApplicationBuilderTest.java
+++ b/featuremodel/feature-applicationbuilder/src/test/java/org/apache/sling/feature/applicationbuilder/impl/ApplicationBuilderTest.java
@@ -29,7 +29,7 @@ import org.apache.sling.feature.support.ArtifactManager;
 import org.apache.sling.feature.support.ArtifactManagerConfig;
 import org.apache.sling.feature.support.json.ApplicationJSONWriter;
 import org.apache.sling.feature.support.json.FeatureJSONReader;
-import org.apache.sling.feature.support.json.FeatureJSONReader.Phase;
+import org.apache.sling.feature.support.json.FeatureJSONReader.SubstituteVariables;
 import org.junit.After;
 import org.junit.Before;
 import org.junit.Test;
@@ -156,7 +156,7 @@ public class ApplicationBuilderTest {
         final ArtifactHandler featureArtifact = artifactManager.getArtifactHandler(file);
 
         try (final FileReader r = new FileReader(featureArtifact.getFile())) {
-            final Feature f = FeatureJSONReader.read(r, featureArtifact.getUrl(), Phase.RESOLVE);
+            final Feature f = FeatureJSONReader.read(r, featureArtifact.getUrl(), SubstituteVariables.RESOLVE);
             return f;
         }
     }
diff --git a/featuremodel/feature-modelconverter/pom.xml b/featuremodel/feature-modelconverter/pom.xml
index 8d19064..c77652f 100644
--- a/featuremodel/feature-modelconverter/pom.xml
+++ b/featuremodel/feature-modelconverter/pom.xml
@@ -112,6 +112,12 @@
              <version>1.3.1</version>
         </dependency>
         <dependency>
+            <groupId>org.apache.felix</groupId>
+            <artifactId>org.apache.felix.framework</artifactId>
+            <version>5.6.10</version>
+            <scope>provided</scope>
+        </dependency>
+        <dependency>
             <groupId>org.apache.sling</groupId>
             <artifactId>org.apache.sling.feature</artifactId>
             <version>0.0.1-SNAPSHOT</version>
@@ -156,9 +162,15 @@
         </dependency>
         <dependency>
             <groupId>org.apache.felix</groupId>
-            <artifactId>org.apache.felix.framework</artifactId>
-            <version>5.6.10</version>
-            <!--  <scope>test</scope>  -->
+            <artifactId>org.apache.felix.converter</artifactId>
+            <version>0.1.0-SNAPSHOT</version>
+            <scope>test</scope>
+        </dependency>
+        <dependency>
+            <groupId>org.apache.felix</groupId>
+            <artifactId>org.apache.felix.configurator</artifactId>
+            <version>0.0.1-SNAPSHOT</version>
+            <scope>test</scope>
         </dependency>
     </dependencies>
 </project>
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 2325549..ed0bd38 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
@@ -27,6 +27,7 @@ import org.apache.sling.feature.process.FeatureResolver;
 import org.apache.sling.feature.support.ArtifactManager;
 import org.apache.sling.feature.support.FeatureUtil;
 import org.apache.sling.feature.support.json.ApplicationJSONReader;
+import org.apache.sling.feature.support.json.FeatureJSONReader.SubstituteVariables;
 import org.apache.sling.provisioning.model.Artifact;
 import org.apache.sling.provisioning.model.Configuration;
 import org.apache.sling.provisioning.model.Feature;
@@ -52,15 +53,18 @@ public class FeatureToProvisioning {
     private static final String PROVISIONING_MODEL_NAME_VARIABLE = "provisioning.model.name";
 
     public static void convert(File file, String output, ArtifactManager am) throws IOException {
-        org.apache.sling.feature.Feature feature = FeatureUtil.getFeature(file.getAbsolutePath(), am);
+        org.apache.sling.feature.Feature feature = FeatureUtil.getFeature(file.getAbsolutePath(), am, SubstituteVariables.NONE);
 
-        String featureName = feature.getVariables().get(PROVISIONING_MODEL_NAME_VARIABLE);
-        if (featureName == null) {
+        Object featureNameVar = feature.getVariables().remove(PROVISIONING_MODEL_NAME_VARIABLE);
+        String featureName;
+        if (featureNameVar instanceof String) {
+            featureName = (String) featureNameVar;
+        } else {
             featureName = feature.getId().getArtifactId();
         }
 
         Feature newFeature = new Feature(featureName);
-        convert(newFeature, feature.getBundles(), feature.getConfigurations(), feature.getFrameworkProperties(), feature.getExtensions(), output);
+        convert(newFeature, feature.getVariables(), feature.getBundles(), feature.getConfigurations(), feature.getFrameworkProperties(), feature.getExtensions(), output);
     }
 
     public static void convert(List<File> files, String output, boolean createApp, ArtifactManager am) throws Exception {
@@ -95,11 +99,16 @@ public class FeatureToProvisioning {
         }
         final Feature feature = new Feature(featureName);
 
-        convert(feature, app.getBundles(), app.getConfigurations(), app.getFrameworkProperties(), app.getExtensions(), outputFile);
+        convert(feature, app.getVariables(), app.getBundles(), app.getConfigurations(), app.getFrameworkProperties(), app.getExtensions(), outputFile);
     }
 
-    private static void convert(Feature f, Bundles bundles, Configurations configurations, KeyValueMap frameworkProps,
+    private static void convert(Feature f, KeyValueMap variables, Bundles bundles, Configurations configurations, KeyValueMap frameworkProps,
             Extensions extensions, String outputFile) {
+        org.apache.sling.provisioning.model.KeyValueMap<String> vars = f.getVariables();
+        for (Map.Entry<String, String> entry : variables) {
+            vars.put(entry.getKey(), entry.getValue());
+        }
+
         Map<org.apache.sling.feature.Configuration, org.apache.sling.feature.Artifact> configBundleMap = new HashMap<>();
 
         // bundles
@@ -153,6 +162,9 @@ public class FeatureToProvisioning {
                 c.getProperties().put(key, cfg.getProperties().get(key));
             }
 
+            // Remove these if they got in
+            c.getProperties().remove(org.apache.sling.feature.Configuration.PROP_ARTIFACT);
+
             // Check if the configuration has an associated runmode via the bundle that it belongs to
             org.apache.sling.feature.Artifact bundle = configBundleMap.get(cfg);
             String[] runModes;
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 bba43c5..46dc48b 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
@@ -24,6 +24,7 @@ import org.apache.sling.provisioning.model.Configuration;
 import org.apache.sling.provisioning.model.Feature;
 import org.apache.sling.provisioning.model.KeyValueMap;
 import org.apache.sling.provisioning.model.Model;
+import org.apache.sling.provisioning.model.ModelConstants;
 import org.apache.sling.provisioning.model.RunMode;
 import org.apache.sling.provisioning.model.Section;
 import org.junit.After;
@@ -31,17 +32,23 @@ import org.junit.Before;
 import org.junit.Test;
 
 import java.io.File;
+import java.io.IOException;
+import java.net.URISyntaxException;
 import java.nio.file.Files;
 import java.nio.file.Path;
 import java.util.ArrayList;
 import java.util.Arrays;
 import java.util.Comparator;
+import java.util.Dictionary;
+import java.util.Enumeration;
 import java.util.HashMap;
 import java.util.HashSet;
 import java.util.List;
 import java.util.Map;
+import java.util.regex.Pattern;
 
 import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertTrue;
 import static org.junit.Assert.fail;
 
 public class ModelConverterTest {
@@ -66,13 +73,22 @@ public class ModelConverterTest {
 
     @Test
     public void testBoot() throws Exception {
-        File inFile = new File(getClass().getResource("/boot.json").toURI());
-        File outFile = new File(tempDir.toFile(), "/boot.generated.txt");
+        testConvertToProvisioningModel("/boot.json", "/boot.txt");
+    }
+
+    @Test
+    public void testOak() throws Exception {
+        testConvertToProvisioningModel("/oak.json", "/oak.txt");
+    }
+
+    private void testConvertToProvisioningModel(String originalJSON, String expectedProvModel) throws URISyntaxException, IOException {
+        File inFile = new File(getClass().getResource(originalJSON).toURI());
+        File outFile = new File(tempDir.toFile(), expectedProvModel + ".generated");
 
         FeatureToProvisioning.convert(inFile, outFile.getAbsolutePath(),
                 artifactManager);
 
-        File expectedFile = new File(getClass().getResource("/boot.txt").toURI());
+        File expectedFile = new File(getClass().getResource(expectedProvModel).toURI());
         Model expected = ProvisioningToFeature.readProvisioningModel(expectedFile);
         Model actual = ProvisioningToFeature.readProvisioningModel(outFile);
         assertModelsEqual(expected, actual);
@@ -117,6 +133,9 @@ public class ModelConverterTest {
             if (rm2.getNames() != null)
                 return false;
         } else {
+            if (rm2.getNames() == null)
+                return false;
+
             HashSet<String> names1 = new HashSet<>(Arrays.asList(rm1.getNames()));
             HashSet<String> names2 = new HashSet<>(Arrays.asList(rm2.getNames()));
 
@@ -150,9 +169,22 @@ public class ModelConverterTest {
 
         for (int i=0; i < configs1.size(); i++) {
             Configuration cfg1 = configs1.get(i);
-            Configuration cfg2 = configs2.get(i);
-            if (!cfg1.getProperties().equals(cfg2.getProperties()))
-                return false;
+
+            boolean found = false;
+            for (Configuration cfg2 : configs2) {
+                if (!cfg2.getPid().equals(cfg1.getPid())) {
+                    continue;
+                }
+                found = true;
+
+                Map<String, Object> m1 = cfgMap(cfg1.getProperties());
+                Map<String, Object> m2 = cfgMap(cfg2.getProperties());
+                if (!m1.equals(m2)) {
+                    return false;
+                }
+                break;
+            }
+            assertTrue("Configuration with PID " + cfg1.getPid() + " not found", found);
         }
 
         Map<String, String> m1 = kvToMap(rm1.getSettings());
@@ -161,6 +193,31 @@ public class ModelConverterTest {
         return m1.equals(m2);
     }
 
+    private Map<String, Object> cfgMap(Dictionary<String, Object> properties) {
+        Map<String, Object> m = new HashMap<>();
+        for (Enumeration<String> e = properties.keys(); e.hasMoreElements(); ) {
+            String key = e.nextElement();
+            Object value = properties.get(key);
+            if (ModelConstants.CFG_UNPROCESSED.equals(key) && value instanceof String) {
+                String val = (String) value;
+                // Collapse line continuation characters
+                val = val.replaceAll("[\\\\]\\r?\\n", "");
+                for (String line : val.split("\\r?\\n")) {
+
+                    String[] kv = line.trim().split("=");
+                    if (kv.length >= 2) {
+                        String v = kv[1].trim().replaceAll("[" +Pattern.quote("[") + "]\\s+[\"]", "[\"");
+                        v = v.replaceAll("[\"][,]\\s*[]]","\"]");
+                        m.put(kv[0].trim(), v.trim());
+                    }
+                }
+            } else {
+                m.put(key, value);
+            }
+        }
+        return m;
+    }
+
     private Map<String, String> kvToMap(KeyValueMap<String> kvm) {
         Map<String, String> m = new HashMap<>();
 
@@ -191,10 +248,7 @@ public class ModelConverterTest {
     }
 
     private void assertKVMapEquals(KeyValueMap<String> expected, KeyValueMap<String> actual) {
-        assertEquals(expected.size(), actual.size());
-        for (Map.Entry<String, String> entry : expected) {
-            assertEquals(entry.getValue(), actual.get(entry.getKey()));
-        }
+        assertEquals(kvToMap(expected), kvToMap(actual));
     }
 
     private void assertSectionsEqual(List<Section> expected, List<Section> actual) {
diff --git a/featuremodel/feature-modelconverter/src/test/resources/boot.json b/featuremodel/feature-modelconverter/src/test/resources/boot.json
index 2a17a40..8d0634a 100644
--- a/featuremodel/feature-modelconverter/src/test/resources/boot.json
+++ b/featuremodel/feature-modelconverter/src/test/resources/boot.json
@@ -9,25 +9,79 @@
         "#": "The model name when transformed to the provisioning model",
         "provisioning.model.name": ":boot"
     },
-    "bundles": 
-        ["org.slf4j/slf4j-api/${slf4j.version}",
-        "org.apache.sling/org.apache.sling.commons.log/5.1.0",
-        "org.apache.sling/org.apache.sling.commons.logservice/1.0.6",
-        "org.slf4j/jcl-over-slf4j/${slf4j.version}",
-        "org.slf4j/log4j-over-slf4j/${slf4j.version}",
-        "org.apache.sling/org.apache.sling.settings/1.3.8",
-        "org.apache.sling/org.apache.sling.fragment.xml/1.0.2",
-        "org.apache.sling/org.apache.sling.fragment.transaction/1.0.0",
-        "org.apache.sling/org.apache.sling.javax.activation/0.1.0",
-        "org.apache.sling/org.apache.sling.fragment.ws/1.0.2",
-        "org.apache.sling/org.apache.sling.launchpad.installer/1.2.2",
-        "org.apache.sling/org.apache.sling.installer.core/3.8.12",
-        "org.apache.sling/org.apache.sling.installer.provider.file/1.1.0",
-        "org.apache.sling/org.apache.sling.installer.factory.configuration/1.1.2",
-        "org.apache.felix/org.apache.felix.configadmin/1.8.16",
-        "org.apache.felix/org.apache.felix.eventadmin/1.4.10",
-        "org.apache.aries/org.apache.aries.util/1.1.3",
-        "org.apache.geronimo.specs/geronimo-atinject_1.0_spec/1.0"],
+    "bundles": [
+        {
+            "id": "org.slf4j/slf4j-api/${slf4j.version}",
+            "start-level": 20
+        },
+        {
+            "id": "org.apache.sling/org.apache.sling.commons.log/5.1.0",
+            "start-level": 20
+        },
+        {
+            "id": "org.apache.sling/org.apache.sling.commons.logservice/1.0.6",
+            "start-level": 20
+        },
+        {
+            "id": "org.slf4j/jcl-over-slf4j/${slf4j.version}",
+            "start-level": 20
+        },
+        {
+            "id": "org.slf4j/log4j-over-slf4j/${slf4j.version}",
+            "start-level": 20
+        },
+        {
+            "id": "org.apache.sling/org.apache.sling.settings/1.3.8",
+            "start-level": 20
+        },
+        {
+            "id": "org.apache.sling/org.apache.sling.fragment.xml/1.0.2",
+            "start-level": 20
+        },
+        {
+            "id": "org.apache.sling/org.apache.sling.fragment.transaction/1.0.0",
+            "start-level": 20
+        },
+        {
+            "id": "org.apache.sling/org.apache.sling.javax.activation/0.1.0",
+            "start-level": 20
+        },
+        {
+            "id": "org.apache.sling/org.apache.sling.fragment.ws/1.0.2",
+            "start-level": 20
+        },
+        {
+            "id": "org.apache.sling/org.apache.sling.launchpad.installer/1.2.2",
+            "start-level": 20
+        },
+        {
+            "id": "org.apache.sling/org.apache.sling.installer.core/3.8.12",
+            "start-level": 20
+        },
+        {
+            "id": "org.apache.sling/org.apache.sling.installer.provider.file/1.1.0",
+            "start-level": 20
+        },
+        {
+            "id": "org.apache.sling/org.apache.sling.installer.factory.configuration/1.1.2",
+            "start-level": 20
+        },
+        {
+            "id": "org.apache.felix/org.apache.felix.configadmin/1.8.16",
+            "start-level": 20
+        },
+        {
+            "id": "org.apache.felix/org.apache.felix.eventadmin/1.4.10",
+            "start-level": 20
+        },
+        {
+            "id": "org.apache.aries/org.apache.aries.util/1.1.3",
+            "start-level": 20
+        },
+        {
+            "id": "org.apache.geronimo.specs/geronimo-atinject_1.0_spec/1.0",
+            "start-level": 20
+        }],
         
     "framework-properties": {
         "# oak_tar and oak_mongo run modes are mutually exclusive":
diff --git a/featuremodel/feature-modelconverter/src/test/resources/boot.txt b/featuremodel/feature-modelconverter/src/test/resources/boot.txt
index b8d2e7f..7e22e39 100644
--- a/featuremodel/feature-modelconverter/src/test/resources/boot.txt
+++ b/featuremodel/feature-modelconverter/src/test/resources/boot.txt
@@ -1,26 +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.
+#
+# The :boot feature contains all things to bootstrap the installation.
+#
 [feature name=:boot]
 
+# additional entries for sling.properties
+# ---------------------------------------
+# oak_tar and oak_mongo run modes are mutually exclusive,
+# and cannot be changed after the first startup
 [settings]
-  localIndexDir=${sling.home}/repository/index
-  repository.home=${sling.home}/repository
-  sling.run.mode.install.options=oak_tar,oak_mongo
+    sling.run.mode.install.options=oak_tar,oak_mongo
+    repository.home=${sling.home}/repository
+    localIndexDir=${sling.home}/repository/index
+
+[variables]
+    slf4j.version=1.7.25
 
 [artifacts startLevel=20]
-  org.apache.aries/org.apache.aries.util/1.1.3
-  org.apache.felix/org.apache.felix.configadmin/1.8.16
-  org.apache.felix/org.apache.felix.eventadmin/1.4.10
-  org.apache.geronimo.specs/geronimo-atinject_1.0_spec/1.0
-  org.apache.sling/org.apache.sling.commons.log/5.1.0
-  org.apache.sling/org.apache.sling.commons.logservice/1.0.6
-  org.apache.sling/org.apache.sling.fragment.transaction/1.0.0
-  org.apache.sling/org.apache.sling.fragment.ws/1.0.2
-  org.apache.sling/org.apache.sling.fragment.xml/1.0.2
-  org.apache.sling/org.apache.sling.installer.core/3.8.12
-  org.apache.sling/org.apache.sling.installer.factory.configuration/1.1.2
-  org.apache.sling/org.apache.sling.installer.provider.file/1.1.0
-  org.apache.sling/org.apache.sling.javax.activation/0.1.0
-  org.apache.sling/org.apache.sling.launchpad.installer/1.2.2
-  org.apache.sling/org.apache.sling.settings/1.3.8
-  org.slf4j/jcl-over-slf4j/1.7.25
-  org.slf4j/log4j-over-slf4j/1.7.25
-  org.slf4j/slf4j-api/1.7.25
+    org.slf4j/slf4j-api/${slf4j.version}
+    org.apache.sling/org.apache.sling.commons.log/5.1.0
+    org.apache.sling/org.apache.sling.commons.logservice/1.0.6
+    org.slf4j/jcl-over-slf4j/${slf4j.version}
+    org.slf4j/log4j-over-slf4j/${slf4j.version}
+    org.apache.sling/org.apache.sling.settings/1.3.8
+    org.apache.sling/org.apache.sling.fragment.xml/1.0.2
+    org.apache.sling/org.apache.sling.fragment.transaction/1.0.0
+    org.apache.sling/org.apache.sling.javax.activation/0.1.0
+    org.apache.sling/org.apache.sling.fragment.ws/1.0.2
+    org.apache.sling/org.apache.sling.launchpad.installer/1.2.2
+    org.apache.sling/org.apache.sling.installer.core/3.8.12
+    org.apache.sling/org.apache.sling.installer.provider.file/1.1.0
+    org.apache.sling/org.apache.sling.installer.factory.configuration/1.1.2
+    org.apache.felix/org.apache.felix.configadmin/1.8.16
+    org.apache.felix/org.apache.felix.eventadmin/1.4.10
+    org.apache.aries/org.apache.aries.util/1.1.3
+    # dependency with javax.inject - required for Sling Models (SLING-4710)
+    org.apache.geronimo.specs/geronimo-atinject_1.0_spec/1.0
diff --git a/featuremodel/feature-modelconverter/src/test/resources/oak.json b/featuremodel/feature-modelconverter/src/test/resources/oak.json
new file mode 100644
index 0000000..ab50c29
--- /dev/null
+++ b/featuremodel/feature-modelconverter/src/test/resources/oak.json
@@ -0,0 +1,101 @@
+{
+    "id": "org.apache.sling.simple/oak/1.0.0",
+    
+    "variables": {
+        "oak.version": "1.6.8"
+    },
+    
+    "bundles": [
+        {
+            "id": "org.apache.felix/org.apache.felix.jaas/1.0.2",
+            "start-level": 10
+        },
+        {
+            "id": "org.apache.jackrabbit/oak-core/${oak.version}",
+            "start-level": 15
+        },
+        {
+            "id": "org.apache.jackrabbit/oak-commons/${oak.version}",
+            "start-level": 15
+        },
+        {
+            "id": "org.apache.jackrabbit/oak-lucene/${oak.version}",
+            "start-level": 15
+        },
+        {
+            "id": "org.apache.jackrabbit/oak-blob/${oak.version}",
+            "start-level": 15
+        },
+        {
+            "id": "org.apache.jackrabbit/oak-jcr/${oak.version}",
+            "start-level": 15
+        },
+        {
+            "id": "org.apache.jackrabbit/oak-segment-tar/${oak.version}",
+            "start-level": 15,
+            "run-modes": "oak_tar",
+            "configurations": {
+                "org.apache.jackrabbit.oak.segment.SegmentNodeStoreService": {
+                    "name": "Default NodeStore"
+                }
+            }
+        },
+        {
+            "id": "org.mongodb/mongo-java-driver/3.4.1",
+            "start-level": 15,
+            "run-modes": "oak_mongo",
+            "configurations": {
+                "org.apache.jackrabbit.oak.plugins.document.DocumentNodeStoreService": {
+                    "mongouri": "mongodb://localhost:27017",
+                    "db": "sling"
+                }
+            }
+        },
+        {
+            "id": "com.h2database/h2-mvstore/1.4.196",
+            "start-level": 15,
+            "run-modes": "oak_mongo"
+        },
+        {
+            "id": "org.apache.sling/org.apache.sling.jcr.oak.server/1.1.4",
+            "start-level": 16
+        }
+    ],
+    "configurations": {
+        "org.apache.felix.jaas.Configuration.factory-GuestLoginModule": {
+            "jaas.controlFlag": "optional",
+            "jaas.classname": "org.apache.jackrabbit.oak.spi.security.authentication.GuestLoginModule",
+            "jaas.ranking:Integer": 300
+        }, 
+        "org.apache.felix.jaas.Configuration.factory-LoginModuleImpl" : {
+            "jaas.controlFlag": "required",
+            "jaas.classname": "org.apache.jackrabbit.oak.security.authentication.user.LoginModuleImpl"
+        },
+        "org.apache.felix.jaas.Configuration.factory-TokenLoginModule" : {
+            "jaas.controlFlag": "sufficient",
+            "jaas.classname": "org.apache.jackrabbit.oak.security.authentication.token.TokenLoginModule",
+            "jaas.ranking:Integer": 200
+        },
+        "org.apache.felix.jaas.ConfigurationSpi": {
+            "jaas.defaultRealmName": "jackrabbit.oak",
+            "jaas.configProviderName": "FelixJaasProvider"
+        },
+        "org.apache.jackrabbit.oak.security.authentication.AuthenticationConfigurationImpl" : {
+            "org.apache.jackrabbit.oak.authentication.configSpiName": "FelixJaasProvider"
+        },
+        "org.apache.jackrabbit.oak.security.user.UserConfigurationImpl": {
+            "groupsPath": "/home/groups",
+            "usersPath": "/home/users",
+            "defaultDepth": "1",
+            "importBehavior": "besteffort"
+        },
+        "org.apache.jackrabbit.oak.security.user.RandomAuthorizableNodeName": {
+            "length:Integer": 21
+        },
+        "org.apache.jackrabbit.oak.spi.security.user.action.DefaultAuthorizableActionProvider": {
+            "enabledActions": ["org.apache.jackrabbit.oak.spi.security.user.action.AccessControlAction"],
+            "userPrivilegeNames": ["jcr:all"],
+            "groupPrivilegeNames": ["jcr:read"]
+        }
+    }
+}
diff --git a/featuremodel/feature-modelconverter/src/test/resources/oak.txt b/featuremodel/feature-modelconverter/src/test/resources/oak.txt
new file mode 100644
index 0000000..5d2675c
--- /dev/null
+++ b/featuremodel/feature-modelconverter/src/test/resources/oak.txt
@@ -0,0 +1,91 @@
+#
+#  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.
+#
+# This is the OAK feature.
+[feature name=oak]
+
+[variables]
+    oak.version=1.6.8
+
+# The segment node store is used via a configuration
+[artifacts startLevel=10]
+    org.apache.felix/org.apache.felix.jaas/1.0.2
+
+[artifacts startLevel=15]
+    org.apache.jackrabbit/oak-core/${oak.version}
+    org.apache.jackrabbit/oak-commons/${oak.version}
+    org.apache.jackrabbit/oak-lucene/${oak.version}
+    org.apache.jackrabbit/oak-blob/${oak.version}
+    org.apache.jackrabbit/oak-jcr/${oak.version}
+
+[artifacts startLevel=15 runModes=oak_tar]
+    org.apache.jackrabbit/oak-segment-tar/${oak.version}
+
+[artifacts startLevel=15 runModes=oak_mongo]
+    org.mongodb/mongo-java-driver/3.4.1
+    com.h2database/h2-mvstore/1.4.196
+
+# start the Oak server instance after all components have been configured
+# and started to avoid restarting that component ( see SLING-4556 )
+[artifacts startLevel=16]
+    org.apache.sling/org.apache.sling.jcr.oak.server/1.1.4
+
+[configurations]
+  org.apache.felix.jaas.Configuration.factory-GuestLoginModule
+    jaas.controlFlag="optional"
+    jaas.classname="org.apache.jackrabbit.oak.spi.security.authentication.GuestLoginModule"
+    jaas.ranking=I"300"
+
+  org.apache.felix.jaas.Configuration.factory-LoginModuleImpl
+    jaas.controlFlag="required"
+    jaas.classname="org.apache.jackrabbit.oak.security.authentication.user.LoginModuleImpl"
+
+  org.apache.felix.jaas.Configuration.factory-TokenLoginModule
+    jaas.controlFlag="sufficient"
+    jaas.classname="org.apache.jackrabbit.oak.security.authentication.token.TokenLoginModule"
+    jaas.ranking=I"200"
+
+  org.apache.felix.jaas.ConfigurationSpi
+    jaas.defaultRealmName="jackrabbit.oak"
+    jaas.configProviderName="FelixJaasProvider"
+
+  org.apache.jackrabbit.oak.security.authentication.AuthenticationConfigurationImpl
+    org.apache.jackrabbit.oak.authentication.configSpiName="FelixJaasProvider"
+
+  org.apache.jackrabbit.oak.security.user.UserConfigurationImpl
+    groupsPath="/home/groups"
+    usersPath="/home/users"
+    defaultDepth="1"
+    importBehavior="besteffort"
+
+  org.apache.jackrabbit.oak.security.user.RandomAuthorizableNodeName
+    length=I"21"
+
+  org.apache.jackrabbit.oak.spi.security.user.action.DefaultAuthorizableActionProvider
+    enabledActions=["org.apache.jackrabbit.oak.spi.security.user.action.AccessControlAction"]
+    userPrivilegeNames=["jcr:all"]
+    groupPrivilegeNames=["jcr:read"]
+
+[configurations runModes=oak_tar]
+  org.apache.jackrabbit.oak.segment.SegmentNodeStoreService
+    name="Default\ NodeStore"
+
+[configurations runModes=oak_mongo]
+  org.apache.jackrabbit.oak.plugins.document.DocumentNodeStoreService
+    mongouri="mongodb://localhost:27017"
+    db="sling"
diff --git a/featuremodel/feature-resolver/src/test/java/org/apache/sling/feature/resolver/FrameworkResolverTest.java b/featuremodel/feature-resolver/src/test/java/org/apache/sling/feature/resolver/FrameworkResolverTest.java
index 4d3cb59..fa947ca 100644
--- a/featuremodel/feature-resolver/src/test/java/org/apache/sling/feature/resolver/FrameworkResolverTest.java
+++ b/featuremodel/feature-resolver/src/test/java/org/apache/sling/feature/resolver/FrameworkResolverTest.java
@@ -23,7 +23,7 @@ import org.apache.sling.feature.support.ArtifactHandler;
 import org.apache.sling.feature.support.ArtifactManager;
 import org.apache.sling.feature.support.ArtifactManagerConfig;
 import org.apache.sling.feature.support.json.FeatureJSONReader;
-import org.apache.sling.feature.support.json.FeatureJSONReader.Phase;
+import org.apache.sling.feature.support.json.FeatureJSONReader.SubstituteVariables;
 import org.junit.After;
 import org.junit.Before;
 import org.junit.Test;
@@ -141,7 +141,7 @@ public class FrameworkResolverTest {
         final ArtifactHandler featureArtifact = artifactManager.getArtifactHandler(file);
 
         try (final FileReader r = new FileReader(featureArtifact.getFile())) {
-            final Feature f = FeatureJSONReader.read(r, featureArtifact.getUrl(), Phase.RESOLVE);
+            final Feature f = FeatureJSONReader.read(r, featureArtifact.getUrl(), SubstituteVariables.RESOLVE);
             return f;
         }
     }
diff --git a/featuremodel/feature-support/src/main/java/org/apache/sling/feature/support/FeatureUtil.java b/featuremodel/feature-support/src/main/java/org/apache/sling/feature/support/FeatureUtil.java
index 3a39086..7c53d79 100644
--- a/featuremodel/feature-support/src/main/java/org/apache/sling/feature/support/FeatureUtil.java
+++ b/featuremodel/feature-support/src/main/java/org/apache/sling/feature/support/FeatureUtil.java
@@ -24,7 +24,7 @@ import org.apache.sling.feature.process.BuilderContext;
 import org.apache.sling.feature.process.FeatureProvider;
 import org.apache.sling.feature.process.FeatureResolver;
 import org.apache.sling.feature.support.json.FeatureJSONReader;
-import org.apache.sling.feature.support.json.FeatureJSONReader.Phase;
+import org.apache.sling.feature.support.json.FeatureJSONReader.SubstituteVariables;
 
 import java.io.File;
 import java.io.FileReader;
@@ -245,7 +245,7 @@ public class FeatureUtil {
                 try {
                     final ArtifactHandler handler = artifactManager.getArtifactHandler("mvn:" + id.toMvnPath());
                     try (final FileReader r = new FileReader(handler.getFile())) {
-                        final Feature f = FeatureJSONReader.read(r, handler.getUrl(), Phase.RESOLVE);
+                        final Feature f = FeatureJSONReader.read(r, handler.getUrl(), SubstituteVariables.RESOLVE);
                         return f;
                     }
 
@@ -274,12 +274,17 @@ public class FeatureUtil {
      * @throws IOException If reading fails
      */
     public static Feature getFeature(final String file,
-            final ArtifactManager artifactManager)
+            final ArtifactManager artifactManager) throws IOException {
+        return getFeature(file, artifactManager, SubstituteVariables.RESOLVE);
+    }
+
+    public static Feature getFeature(final String file,
+            final ArtifactManager artifactManager, final SubstituteVariables substituteVariables)
     throws IOException {
         final ArtifactHandler featureArtifact = artifactManager.getArtifactHandler(file);
 
         try (final FileReader r = new FileReader(featureArtifact.getFile())) {
-            final Feature f = FeatureJSONReader.read(r, featureArtifact.getUrl(), Phase.RESOLVE);
+            final Feature f = FeatureJSONReader.read(r, featureArtifact.getUrl(), substituteVariables);
             return f;
         }
     }
diff --git a/featuremodel/feature-support/src/main/java/org/apache/sling/feature/support/json/FeatureJSONReader.java b/featuremodel/feature-support/src/main/java/org/apache/sling/feature/support/json/FeatureJSONReader.java
index 2e30e38..45f8532 100644
--- a/featuremodel/feature-support/src/main/java/org/apache/sling/feature/support/json/FeatureJSONReader.java
+++ b/featuremodel/feature-support/src/main/java/org/apache/sling/feature/support/json/FeatureJSONReader.java
@@ -46,7 +46,7 @@ import static org.apache.sling.feature.support.util.ManifestUtil.unmarshalDirect
  * This class offers a method to read a {@code Feature} using a {@code Reader} instance.
  */
 public class FeatureJSONReader extends JSONReaderBase {
-    public enum Phase { RESOLVE, LAUNCH }
+    public enum SubstituteVariables { NONE, RESOLVE, LAUNCH }
 
     // The pattern that variables in Feature JSON follow
     private static final Pattern VARIABLE_PATTERN = Pattern.compile("\\$\\{[a-zA-Z0-9.-_]+\\}");
@@ -60,7 +60,7 @@ public class FeatureJSONReader extends JSONReaderBase {
      * @return The read feature
      * @throws IOException If an IO errors occurs or the JSON is invalid.
      */
-    public static Feature read(final Reader reader, final String location, final Phase phase)
+    public static Feature read(final Reader reader, final String location, final SubstituteVariables phase)
     throws IOException {
         return read(reader, null, location, phase);
     }
@@ -78,7 +78,7 @@ public class FeatureJSONReader extends JSONReaderBase {
     public static Feature read(final Reader reader,
             final ArtifactId providedId,
             final String location,
-            final Phase phase)
+            final SubstituteVariables phase)
     throws IOException {
         try {
             final FeatureJSONReader mr = new FeatureJSONReader(providedId, location, phase);
@@ -98,14 +98,14 @@ public class FeatureJSONReader extends JSONReaderBase {
     private Map<String, String> variables;
 
     /** The current reading phase. */
-    private final Phase phase;
+    private final SubstituteVariables phase;
 
     /**
      * Private constructor
      * @param pId Optional id
      * @param location Optional location
      */
-    FeatureJSONReader(final ArtifactId pId, final String location, final Phase phase) {
+    FeatureJSONReader(final ArtifactId pId, final String location, final SubstituteVariables phase) {
         super(location);
         this.providedId = pId;
         this.phase = phase;
@@ -172,7 +172,7 @@ public class FeatureJSONReader extends JSONReaderBase {
 
     @Override
     protected Object handleResolveVars(Object val) {
-        if (phase == Phase.RESOLVE) {
+        if (phase == SubstituteVariables.RESOLVE) {
             return handleVars(val);
         } else {
             return val;
@@ -181,7 +181,7 @@ public class FeatureJSONReader extends JSONReaderBase {
 
     @Override
     protected Object handleLaunchVars(Object val) {
-        if (phase == Phase.LAUNCH) {
+        if (phase == SubstituteVariables.LAUNCH) {
             return handleVars(val);
         }
         return val;
diff --git a/featuremodel/feature-support/src/test/java/org/apache/sling/feature/support/json/FeatureJSONReaderTest.java b/featuremodel/feature-support/src/test/java/org/apache/sling/feature/support/json/FeatureJSONReaderTest.java
index 8410877..2bcaa1c 100644
--- a/featuremodel/feature-support/src/test/java/org/apache/sling/feature/support/json/FeatureJSONReaderTest.java
+++ b/featuremodel/feature-support/src/test/java/org/apache/sling/feature/support/json/FeatureJSONReaderTest.java
@@ -25,7 +25,7 @@ import org.apache.sling.feature.Extensions;
 import org.apache.sling.feature.Feature;
 import org.apache.sling.feature.Include;
 import org.apache.sling.feature.KeyValueMap;
-import org.apache.sling.feature.support.json.FeatureJSONReader.Phase;
+import org.apache.sling.feature.support.json.FeatureJSONReader.SubstituteVariables;
 import org.junit.Test;
 import org.osgi.resource.Capability;
 import org.osgi.resource.Requirement;
@@ -122,7 +122,7 @@ public class FeatureJSONReaderTest {
     }
 
     @Test public void testReadWithVariablesLaunch() throws Exception {
-        final Feature feature = U.readFeature("test3", Phase.LAUNCH);
+        final Feature feature = U.readFeature("test3", SubstituteVariables.LAUNCH);
 
         List<Include> includes = feature.getIncludes();
         assertEquals(1, includes.size());
@@ -195,7 +195,7 @@ public class FeatureJSONReaderTest {
     }
 
     @Test public void testHandleVars() throws Exception {
-        FeatureJSONReader reader = new FeatureJSONReader(null, null, Phase.LAUNCH);
+        FeatureJSONReader reader = new FeatureJSONReader(null, null, SubstituteVariables.LAUNCH);
         Map<String, Object> vars = new HashMap<>();
         vars.put("var1", "bar");
         vars.put("varvariable", "${myvar}");
diff --git a/featuremodel/feature-support/src/test/java/org/apache/sling/feature/support/json/FeatureJSONWriterTest.java b/featuremodel/feature-support/src/test/java/org/apache/sling/feature/support/json/FeatureJSONWriterTest.java
index a373558..37db933 100644
--- a/featuremodel/feature-support/src/test/java/org/apache/sling/feature/support/json/FeatureJSONWriterTest.java
+++ b/featuremodel/feature-support/src/test/java/org/apache/sling/feature/support/json/FeatureJSONWriterTest.java
@@ -17,7 +17,7 @@
 package org.apache.sling.feature.support.json;
 
 import org.apache.sling.feature.Feature;
-import org.apache.sling.feature.support.json.FeatureJSONReader.Phase;
+import org.apache.sling.feature.support.json.FeatureJSONReader.SubstituteVariables;
 import org.junit.Test;
 
 import java.io.StringReader;
@@ -34,7 +34,7 @@ public class FeatureJSONWriterTest {
         try ( final StringWriter writer = new StringWriter() ) {
             FeatureJSONWriter.write(writer, f);
             try ( final StringReader reader = new StringReader(writer.toString()) ) {
-                rf = FeatureJSONReader.read(reader, null, Phase.RESOLVE);
+                rf = FeatureJSONReader.read(reader, null, SubstituteVariables.RESOLVE);
             }
         }
         assertEquals(f.getId(), rf.getId());
diff --git a/featuremodel/feature-support/src/test/java/org/apache/sling/feature/support/json/U.java b/featuremodel/feature-support/src/test/java/org/apache/sling/feature/support/json/U.java
index eee0e8e..1eaf415 100644
--- a/featuremodel/feature-support/src/test/java/org/apache/sling/feature/support/json/U.java
+++ b/featuremodel/feature-support/src/test/java/org/apache/sling/feature/support/json/U.java
@@ -18,7 +18,7 @@ package org.apache.sling.feature.support.json;
 
 import org.apache.sling.feature.Configuration;
 import org.apache.sling.feature.Feature;
-import org.apache.sling.feature.support.json.FeatureJSONReader.Phase;
+import org.apache.sling.feature.support.json.FeatureJSONReader.SubstituteVariables;
 import org.osgi.resource.Capability;
 import org.osgi.resource.Requirement;
 
@@ -34,10 +34,10 @@ public class U {
     /** Read the feature from the provided resource
      */
     public static Feature readFeature(final String name) throws Exception {
-        return readFeature(name, Phase.RESOLVE);
+        return readFeature(name, SubstituteVariables.RESOLVE);
     }
 
-    public static Feature readFeature(final String name, final Phase phase) throws Exception {
+    public static Feature readFeature(final String name, final SubstituteVariables phase) throws Exception {
         try ( final Reader reader = new InputStreamReader(U.class.getResourceAsStream("/features/" + name + ".json"),
                 "UTF-8") ) {
             return FeatureJSONReader.read(reader, name, phase);
diff --git a/featuremodel/feature/src/main/java/org/apache/sling/feature/Application.java b/featuremodel/feature/src/main/java/org/apache/sling/feature/Application.java
index 7ca58e4..53c3c75 100644
--- a/featuremodel/feature/src/main/java/org/apache/sling/feature/Application.java
+++ b/featuremodel/feature/src/main/java/org/apache/sling/feature/Application.java
@@ -31,6 +31,8 @@ import java.util.List;
  * </ul>
  */
 public class Application {
+    /** The variables of this application. */
+    private final KeyValueMap variables = new KeyValueMap();
 
     /** Container for bundles. */
     private final Bundles bundles = new Bundles();
@@ -109,6 +111,15 @@ public class Application {
         this.framework = framework;
     }
 
+    /**
+     * Get the variables
+     * The map is modifiable
+     * @return The map of variables
+     */
+    public KeyValueMap getVariables() {
+        return this.variables;
+    }
+
     @Override
     public String toString() {
         return "Application [features=" + this.features
diff --git a/featuremodel/feature/src/main/java/org/apache/sling/feature/ArtifactId.java b/featuremodel/feature/src/main/java/org/apache/sling/feature/ArtifactId.java
index 9eca7a9..60860de 100644
--- a/featuremodel/feature/src/main/java/org/apache/sling/feature/ArtifactId.java
+++ b/featuremodel/feature/src/main/java/org/apache/sling/feature/ArtifactId.java
@@ -16,12 +16,12 @@
  */
 package org.apache.sling.feature;
 
+import org.osgi.framework.Version;
+
 import java.util.ArrayList;
 import java.util.Arrays;
 import java.util.List;
 
-import org.osgi.framework.Version;
-
 /**
  * An artifact identifier.
  *
@@ -67,7 +67,7 @@ public class ArtifactId implements Comparable<ArtifactId> {
         this.groupId = groupId;
         this.artifactId = artifactId;
         this.version = version;
-        this.getOSGiVersion();
+
         if ( "bundle".equals(type) || type == null || type.isEmpty() ) {
             this.type = "jar";
         } else {
diff --git a/featuremodel/osgifeature-maven-plugin/src/main/java/org/apache/sling/feature/maven/Preprocessor.java b/featuremodel/osgifeature-maven-plugin/src/main/java/org/apache/sling/feature/maven/Preprocessor.java
index 3799712..4e2f08b 100644
--- a/featuremodel/osgifeature-maven-plugin/src/main/java/org/apache/sling/feature/maven/Preprocessor.java
+++ b/featuremodel/osgifeature-maven-plugin/src/main/java/org/apache/sling/feature/maven/Preprocessor.java
@@ -28,7 +28,7 @@ import org.apache.sling.feature.process.FeatureBuilder;
 import org.apache.sling.feature.process.FeatureProvider;
 import org.apache.sling.feature.support.FeatureUtil;
 import org.apache.sling.feature.support.json.FeatureJSONReader;
-import org.apache.sling.feature.support.json.FeatureJSONReader.Phase;
+import org.apache.sling.feature.support.json.FeatureJSONReader.SubstituteVariables;
 import org.codehaus.plexus.logging.Logger;
 
 import java.io.File;
@@ -194,7 +194,7 @@ public class Preprocessor {
 
                 // We should pass in an "id" to FeatureJSONReader.read and later on check the id (again, need to handle ref files)
                 try (final FileReader reader = new FileReader(file)) {
-                    final Feature feature = FeatureJSONReader.read(reader, id, file.getAbsolutePath(), Phase.RESOLVE);
+                    final Feature feature = FeatureJSONReader.read(reader, id, file.getAbsolutePath(), SubstituteVariables.RESOLVE);
 
                     this.checkFeatureId(id, feature);
 
@@ -369,7 +369,7 @@ public class Preprocessor {
         if ( config.getInlinedFeature() != null ) {
             logger.debug("Reading inlined model from project " + project.getId());
             try (final Reader reader = new StringReader(config.getInlinedFeature())) {
-                feature = FeatureJSONReader.read(reader, id, null, Phase.RESOLVE);
+                feature = FeatureJSONReader.read(reader, id, null, SubstituteVariables.RESOLVE);
             } catch ( final IOException io) {
                 throw new RuntimeException("Unable to read inlined feature", io);
             }
@@ -380,7 +380,7 @@ public class Preprocessor {
             }
             logger.debug("Reading feature " + featureFile + " in project " + project.getId());
             try (final FileReader reader = new FileReader(featureFile)) {
-                feature = FeatureJSONReader.read(reader, id, featureFile.getAbsolutePath(), Phase.RESOLVE);
+                feature = FeatureJSONReader.read(reader, id, featureFile.getAbsolutePath(), SubstituteVariables.RESOLVE);
             } catch ( final IOException io) {
                 throw new RuntimeException("Unable to read feature " + featureFile, io);
             }
@@ -503,7 +503,7 @@ public class Preprocessor {
                     // "external" dependency, we can already resolve it
                     final File featureFile = ProjectHelper.getOrResolveArtifact(info.project, env.session, env.artifactHandlerManager, env.resolver, id).getFile();
                     try (final FileReader r = new FileReader(featureFile)) {
-                        return FeatureJSONReader.read(r, featureFile.getAbsolutePath(), Phase.RESOLVE);
+                        return FeatureJSONReader.read(r, featureFile.getAbsolutePath(), SubstituteVariables.RESOLVE);
                     } catch ( final IOException ioe) {
                         env.logger.error("Unable to read feature file from " + featureFile, ioe);
                     }
diff --git a/featuremodel/osgifeature-maven-plugin/src/main/java/org/apache/sling/feature/maven/ProjectHelper.java b/featuremodel/osgifeature-maven-plugin/src/main/java/org/apache/sling/feature/maven/ProjectHelper.java
index 2efb69c..ce3314c 100644
--- a/featuremodel/osgifeature-maven-plugin/src/main/java/org/apache/sling/feature/maven/ProjectHelper.java
+++ b/featuremodel/osgifeature-maven-plugin/src/main/java/org/apache/sling/feature/maven/ProjectHelper.java
@@ -31,7 +31,7 @@ import org.apache.maven.project.MavenProject;
 import org.apache.sling.feature.ArtifactId;
 import org.apache.sling.feature.Feature;
 import org.apache.sling.feature.support.json.FeatureJSONReader;
-import org.apache.sling.feature.support.json.FeatureJSONReader.Phase;
+import org.apache.sling.feature.support.json.FeatureJSONReader.SubstituteVariables;
 import org.apache.sling.feature.support.json.FeatureJSONWriter;
 import org.codehaus.plexus.util.xml.Xpp3Dom;
 
@@ -96,7 +96,7 @@ public abstract class ProjectHelper {
                 result = null;
             } else {
                 try ( final StringReader r = new StringReader(text) ) {
-                    result = FeatureJSONReader.read(r, project.getId(), Phase.RESOLVE);
+                    result = FeatureJSONReader.read(r, project.getId(), SubstituteVariables.RESOLVE);
                     project.setContextValue(cacheKey, result);
                 } catch ( final IOException ioe) {
                     throw new RuntimeException(ioe.getMessage(), ioe);
@@ -125,7 +125,7 @@ public abstract class ProjectHelper {
                         throw new RuntimeException("Unable to get feature from internal store.");
                     }
                     try ( final StringReader r = new StringReader(text) ) {
-                        final Feature feature = FeatureJSONReader.read(r, project.getId(), Phase.RESOLVE);
+                        final Feature feature = FeatureJSONReader.read(r, project.getId(), SubstituteVariables.RESOLVE);
                         result.add(feature);
                     } catch ( final IOException ioe) {
                         throw new RuntimeException(ioe.getMessage(), ioe);

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