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/21 16:25:18 UTC
[sling-whiteboard] branch master updated: Write configurations
associated with artifacts alongside these
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 19f026e Write configurations associated with artifacts alongside these
19f026e is described below
commit 19f026e21396f95136785c620c8b8c341dc97150
Author: David Bosschaert <da...@gmail.com>
AuthorDate: Wed Mar 21 16:24:39 2018 +0000
Write configurations associated with artifacts alongside these
---
.../modelconverter/impl/ProvisioningToFeature.java | 73 +++++++++++++++-----
.../modelconverter/impl/ModelConverterTest.java | 78 ++++++++++++++++++++--
.../feature/support/json/FeatureJSONWriter.java | 7 +-
.../sling/feature/support/json/JSONWriterBase.java | 29 ++++++--
.../sling/feature/support/json/WriteOption.java | 23 +++++++
5 files changed, 180 insertions(+), 30 deletions(-)
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 a521780..5d0ac7c 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
@@ -30,6 +30,7 @@ import org.apache.sling.feature.support.ArtifactManagerConfig;
import org.apache.sling.feature.support.FeatureUtil;
import org.apache.sling.feature.support.json.ApplicationJSONWriter;
import org.apache.sling.feature.support.json.FeatureJSONWriter;
+import org.apache.sling.feature.support.json.WriteOption;
import org.apache.sling.provisioning.model.Artifact;
import org.apache.sling.provisioning.model.ArtifactGroup;
import org.apache.sling.provisioning.model.Configuration;
@@ -52,6 +53,7 @@ import java.io.FileReader;
import java.io.FileWriter;
import java.io.IOException;
import java.util.ArrayList;
+import java.util.Arrays;
import java.util.Collections;
import java.util.Enumeration;
import java.util.HashSet;
@@ -67,7 +69,7 @@ public class ProvisioningToFeature {
private static Logger LOGGER = LoggerFactory.getLogger(ProvisioningToFeature.class);
public static void convert(File file, String output) {
- Model model = createModel(Collections.singletonList(file), null, false);
+ Model model = createModel(Collections.singletonList(file), null, true, false);
final List<org.apache.sling.feature.Feature> features = buildFeatures(model);
if (features.size() != 1)
throw new IllegalStateException("TODO");
@@ -77,7 +79,7 @@ public class ProvisioningToFeature {
public static void convert(List<File> files, String outputFile, String runModes, boolean createApp,
boolean includeModelInfo, String propsFile) {
- final Model model = createModel(files, runModes, includeModelInfo);
+ final Model model = createModel(files, runModes, false, includeModelInfo);
if ( createApp ) {
final Application app = buildApplication(model, propsFile);
@@ -99,27 +101,28 @@ public class ProvisioningToFeature {
* @param includeModelInfo
*/
private static Model createModel(final List<File> files,
- final String runModes, boolean includeModelInfo) {
+ final String runModes, boolean allRunModes, boolean includeModelInfo) {
LOGGER.info("Assembling model...");
+ ResolverOptions variableResolver = new ResolverOptions().variableResolver(new VariableResolver() {
+ @Override
+ public String resolve(final Feature feature, final String name) {
+ // Keep variables as-is in the model
+ return "${" + name + "}";
+ }
+ });
+
Model model = null;
for(final File initFile : files) {
try {
- model = processModel(model, initFile, includeModelInfo,
- new ResolverOptions().variableResolver(new VariableResolver() {
- @Override
- public String resolve(final Feature feature, final String name) {
- // Keep variables as-is in the model
- return "${" + name + "}";
- }
- })
- );
+ model = processModel(model, initFile, includeModelInfo, variableResolver);
} catch ( final IOException iae) {
LOGGER.error("Unable to read provisioning model {} : {}", initFile, iae.getMessage(), iae);
System.exit(1);
}
}
- final Map<Traceable, String> errors = ModelUtility.validate(model);
+ final Model effectiveModel = ModelUtility.getEffectiveModel(model, variableResolver);
+ final Map<Traceable, String> errors = ModelUtility.validate(effectiveModel);
if ( errors != null ) {
LOGGER.error("Invalid assembled provisioning model.");
for(final Map.Entry<Traceable, String> entry : errors.entrySet()) {
@@ -127,11 +130,24 @@ public class ProvisioningToFeature {
}
System.exit(1);
}
- final Set<String> modes = calculateRunModes(model, runModes);
+ final Set<String> modes;
+ if (allRunModes) {
+ modes = new HashSet<>();
+ for (Feature f : effectiveModel.getFeatures()) {
+ for (RunMode rm : f.getRunModes()) {
+ String[] names = rm.getNames();
+ if (names != null) {
+ modes.addAll(Arrays.asList(names));
+ }
+ }
+ }
+ } else {
+ modes = calculateRunModes(effectiveModel, runModes);
+ }
- removeInactiveFeaturesAndRunModes(model, modes);
+ removeInactiveFeaturesAndRunModes(effectiveModel, modes);
- return model;
+ return effectiveModel;
}
/**
@@ -420,6 +436,29 @@ public class ProvisioningToFeature {
final String key = keys.nextElement();
newCfg.getProperties().put(key, cfg.getProperties().get(key));
}
+
+ String[] runModeNames = runMode.getNames();
+ if (runModeNames != null) {
+ // If this configuration is associated with a runmode other than null, attach it to a bundle
+ // that has the same runmodes
+ Artifact art = null;
+ for (ArtifactGroup group : runMode.getArtifactGroups()) {
+ if (art != null)
+ break;
+
+ for (Artifact artifact : group) {
+ art = artifact;
+ break;
+ }
+ }
+ if (art == null) {
+ throw new IllegalStateException("Should have at least one artifact in runmodes " +
+ Arrays.toString(runModeNames) + " to attach configuration to");
+ }
+
+ newCfg.getProperties().put(org.apache.sling.feature.Configuration.PROP_ARTIFACT, art.toMvnUrl());
+ }
+
configurations.add(newCfg);
}
@@ -491,7 +530,7 @@ public class ProvisioningToFeature {
final File file = new File(out);
try ( final FileWriter writer = new FileWriter(file)) {
- FeatureJSONWriter.write(writer, f);
+ FeatureJSONWriter.write(writer, f, WriteOption.OLD_STYLE_FACTORY_CONFIGS);
} catch ( final IOException ioe) {
LOGGER.error("Unable to write feature to {} : {}", out, ioe.getMessage(), ioe);
System.exit(1);
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 bf35578..6facd22 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
@@ -93,6 +93,11 @@ public class ModelConverterTest {
testConvertToProvisioningModel("/oak.json", "/oak.txt");
}
+ @Test
+ public void testOakToFeature() throws Exception {
+ testConvertToFeature("/oak.txt", "/oak.json");
+ }
+
public void testConvertToFeature(String originalProvModel, String expectedJSON) throws Exception {
File inFile = new File(getClass().getResource(originalProvModel).toURI());
File outFile = new File(tempDir.toFile(), expectedJSON + ".generated");
@@ -133,7 +138,7 @@ public class ModelConverterTest {
assertFeatureKVMapEquals(expected.getVariables(), actual.getVariables());
assertBundlesEqual(expected.getBundles(), actual.getBundles());
- assertConfigurationsEqual(expected.getConfigurations(), actual.getConfigurations());
+ assertConfigurationsEqual(expected.getConfigurations(), actual.getConfigurations(), expected.getBundles(), actual.getBundles());
assertFeatureKVMapEquals(expected.getFrameworkProperties(), actual.getFrameworkProperties());
// Ignore caps and reqs, includes and extensions here since they cannot come from the prov model.
@@ -149,26 +154,86 @@ public class ModelConverterTest {
if (ac.getId().equals(ex.getId())) {
found = true;
assertFeatureKVMapEquals(ex.getMetadata(), ac.getMetadata());
+ break;
}
}
- assertTrue(found);
+ assertTrue("Not found: " + ex, found);
}
}
- private void assertConfigurationsEqual(Configurations expected, Configurations actual) {
+ private void assertConfigurationsEqual(Configurations expected, Configurations actual, Bundles exBundles, Bundles acBundles) {
for (Iterator<org.apache.sling.feature.Configuration> it = expected.iterator(); it.hasNext(); ) {
org.apache.sling.feature.Configuration ex = it.next();
boolean found = false;
for (Iterator<org.apache.sling.feature.Configuration> it2 = actual.iterator(); it2.hasNext(); ) {
org.apache.sling.feature.Configuration ac = it2.next();
- if (ac.getPid().equals(ex.getPid())) {
+ if (ex.getPid() != null) {
+ if (ex.getPid().equals(ac.getPid())) {
+ found = true;
+ assertConfigProps(ex, ac, exBundles, acBundles);
+ }
+ } else {
+ if (ex.getFactoryPid().equals(ac.getFactoryPid())) {
+ found = true;
+ assertConfigProps(ex, ac, exBundles, acBundles);
+ }
+ }
+ }
+ assertTrue(found);
+ }
+ }
+
+ private void assertConfigProps(org.apache.sling.feature.Configuration expected, org.apache.sling.feature.Configuration actual, Bundles exBundles, Bundles acBundles) {
+ // If the configuration is associated with an artifact, it's considered equal
+ // if both artifacts have the same runmode (as the configuration is really
+ // associated with the runmode.
+ Object art = expected.getProperties().remove(org.apache.sling.feature.Configuration.PROP_ARTIFACT);
+ if (art instanceof String) {
+ String expectedArtifact = (String) art;
+ String actualArtifact = (String) actual.getProperties().remove(org.apache.sling.feature.Configuration.PROP_ARTIFACT);
+
+ String expectedRunmodes = null;
+ for(Iterator<org.apache.sling.feature.Artifact> it = exBundles.iterator(); it.hasNext(); ) {
+ org.apache.sling.feature.Artifact a = it.next();
+ if (a.getId().toMvnId().equals(expectedArtifact)) {
+ expectedRunmodes = a.getMetadata().get("run-modes");
+ }
+ }
+
+ boolean found = false;
+ for(Iterator<org.apache.sling.feature.Artifact> it = acBundles.iterator(); it.hasNext(); ) {
+ org.apache.sling.feature.Artifact a = it.next();
+ if (a.getId().toMvnId().equals(actualArtifact)) {
found = true;
- assertEquals(ex.getProperties(), ac.getProperties());
+ assertEquals(expectedRunmodes, a.getMetadata().get("run-modes"));
+ break;
}
}
assertTrue(found);
}
+
+ assertTrue("Configurations not equal: " + expected.getProperties() + " vs " + actual.getProperties(),
+ configPropsEqual(expected.getProperties(), actual.getProperties()));
+ }
+
+ private boolean configPropsEqual(Dictionary<String, Object> d1, Dictionary<String, Object> d2) {
+ if (d1.size() != d2.size()) {
+ return false;
+ }
+
+ for (Enumeration<String> e = d1.keys(); e.hasMoreElements(); ) {
+ String k = e.nextElement();
+ Object v = d1.get(k);
+ if (v instanceof Object[]) {
+ if (!Arrays.equals((Object[]) v, (Object[]) d2.get(k)))
+ return false;
+ } else {
+ if (!v.equals(d2.get(k)))
+ return false;
+ }
+ }
+ return true;
}
private void assertModelsEqual(Model expected, Model actual) {
@@ -279,6 +344,7 @@ public class ModelConverterTest {
return m1.equals(m2);
}
+ // TODO can this one go?
private Map<String, Object> cfgMap(Dictionary<String, Object> properties) {
Map<String, Object> m = new HashMap<>();
for (Enumeration<String> e = properties.keys(); e.hasMoreElements(); ) {
@@ -292,7 +358,7 @@ public class ModelConverterTest {
String[] kv = line.trim().split("=");
if (kv.length >= 2) {
- String v = kv[1].trim().replaceAll("[" +Pattern.quote("[") + "]\\s+[\"]", "[\"");
+ String v = kv[1].trim().replaceAll("[" + Pattern.quote("[") + "]\\s+[\"]", "[\"");
v = v.replaceAll("[\"][,]\\s*[]]","\"]");
m.put(kv[0].trim(), v.trim());
}
diff --git a/featuremodel/feature-support/src/main/java/org/apache/sling/feature/support/json/FeatureJSONWriter.java b/featuremodel/feature-support/src/main/java/org/apache/sling/feature/support/json/FeatureJSONWriter.java
index 28f6f71..8cf5f5b 100644
--- a/featuremodel/feature-support/src/main/java/org/apache/sling/feature/support/json/FeatureJSONWriter.java
+++ b/featuremodel/feature-support/src/main/java/org/apache/sling/feature/support/json/FeatureJSONWriter.java
@@ -44,6 +44,9 @@ import static org.apache.sling.feature.support.util.ManifestUtil.marshalDirectiv
* Simple JSON writer for a feature
*/
public class FeatureJSONWriter extends JSONWriterBase {
+ private FeatureJSONWriter(WriteOption ... options) {
+ super(options);
+ }
/**
* Writes the feature to the writer.
@@ -52,9 +55,9 @@ public class FeatureJSONWriter extends JSONWriterBase {
* @param feature Feature
* @throws IOException If writing fails
*/
- public static void write(final Writer writer, final Feature feature)
+ public static void write(final Writer writer, final Feature feature, final WriteOption ... options)
throws IOException {
- final FeatureJSONWriter w = new FeatureJSONWriter();
+ final FeatureJSONWriter w = new FeatureJSONWriter(options);
w.writeFeature(writer, feature);
}
diff --git a/featuremodel/feature-support/src/main/java/org/apache/sling/feature/support/json/JSONWriterBase.java b/featuremodel/feature-support/src/main/java/org/apache/sling/feature/support/json/JSONWriterBase.java
index ba02dc0..2dc1438 100644
--- a/featuremodel/feature-support/src/main/java/org/apache/sling/feature/support/json/JSONWriterBase.java
+++ b/featuremodel/feature-support/src/main/java/org/apache/sling/feature/support/json/JSONWriterBase.java
@@ -26,6 +26,7 @@ import org.apache.sling.feature.KeyValueMap;
import java.io.StringReader;
import java.lang.reflect.Array;
+import java.util.Arrays;
import java.util.Enumeration;
import java.util.List;
import java.util.Map;
@@ -36,11 +37,20 @@ import javax.json.JsonObject;
import javax.json.JsonObjectBuilder;
import javax.json.JsonStructure;
-
/**
* Common functionality for writing JSON
*/
abstract class JSONWriterBase {
+ private final char factoryConfigSeparator;
+
+ protected JSONWriterBase(WriteOption ... opts) {
+ if (Arrays.asList(opts).contains(WriteOption.OLD_STYLE_FACTORY_CONFIGS)) {
+ factoryConfigSeparator = '-';
+ } else {
+ factoryConfigSeparator = '~';
+ }
+ }
+
protected void writeBundles(final JsonObjectBuilder ob,
final Bundles bundles,
final Configurations allConfigs) {
@@ -51,9 +61,16 @@ abstract class JSONWriterBase {
for(final Artifact artifact : bundles) {
final Configurations cfgs = new Configurations();
for(final Configuration cfg : allConfigs) {
- final String artifactProp = (String)cfg.getProperties().get(Configuration.PROP_ARTIFACT);
- if ( artifact.getId().toMvnId().equals(artifactProp) ) {
- cfgs.add(cfg);
+ String artifactProp = (String)cfg.getProperties().get(Configuration.PROP_ARTIFACT);
+ if (artifactProp != null) {
+ if (artifactProp.startsWith("mvn:")) {
+ // Change Maven URL to maven GAV syntax
+ artifactProp = artifactProp.substring("mvn:".length());
+ artifactProp = artifactProp.replace('/', ':');
+ }
+ if (artifact.getId().toMvnId().equals(artifactProp)) {
+ cfgs.add(cfg);
+ }
}
}
KeyValueMap md = artifact.getMetadata();
@@ -79,6 +96,8 @@ abstract class JSONWriterBase {
bundleObj.add(me.getKey(), me.getValue());
}
+ writeConfigurations(bundleObj, cfgs);
+
bundleArray.add(bundleObj.build());
}
}
@@ -109,7 +128,7 @@ abstract class JSONWriterBase {
for(final Configuration cfg : cfgs) {
final String key;
if ( cfg.isFactoryConfiguration() ) {
- key = cfg.getFactoryPid() + "~" + cfg.getName();
+ key = cfg.getFactoryPid() + factoryConfigSeparator + cfg.getName();
} else {
key = cfg.getPid();
}
diff --git a/featuremodel/feature-support/src/main/java/org/apache/sling/feature/support/json/WriteOption.java b/featuremodel/feature-support/src/main/java/org/apache/sling/feature/support/json/WriteOption.java
new file mode 100644
index 0000000..01f0158
--- /dev/null
+++ b/featuremodel/feature-support/src/main/java/org/apache/sling/feature/support/json/WriteOption.java
@@ -0,0 +1,23 @@
+package org.apache.sling.feature.support.json;
+/*
+ * 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.
+ */
+public enum WriteOption {
+ /* Write factory configurations out in the old style with a '-' separator.
+ * If this option is not used the new style with the '~' separator is used.
+ */
+ OLD_STYLE_FACTORY_CONFIGS
+}
--
To stop receiving notification emails like this one, please contact
davidb@apache.org.