You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@sling.apache.org by cz...@apache.org on 2020/11/10 08:18:16 UTC
[sling-org-apache-sling-feature] branch master updated: SLING-9887
: Record feature origins for configurations
This is an automated email from the ASF dual-hosted git repository.
cziegeler pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/sling-org-apache-sling-feature.git
The following commit(s) were added to refs/heads/master by this push:
new c91f514 SLING-9887 : Record feature origins for configurations
c91f514 is described below
commit c91f51489b02346a0c04cdd3f7f843b66159454b
Author: Carsten Ziegeler <cz...@apache.org>
AuthorDate: Tue Nov 10 09:17:55 2020 +0100
SLING-9887 : Record feature origins for configurations
---
.../org/apache/sling/feature/Configuration.java | 46 ++++++
.../apache/sling/feature/builder/BuilderUtil.java | 117 +++++++-------
.../sling/feature/builder/FeatureBuilder.java | 9 +-
.../org/apache/sling/feature/package-info.java | 2 +-
.../apache/sling/feature/ConfigurationTest.java | 36 +++++
.../sling/feature/builder/BuilderUtilTest.java | 104 ++++++++-----
.../sling/feature/builder/FeatureBuilderTest.java | 169 ++++++++++++++++++++-
7 files changed, 388 insertions(+), 95 deletions(-)
diff --git a/src/main/java/org/apache/sling/feature/Configuration.java b/src/main/java/org/apache/sling/feature/Configuration.java
index b44e9a6..97133c5 100644
--- a/src/main/java/org/apache/sling/feature/Configuration.java
+++ b/src/main/java/org/apache/sling/feature/Configuration.java
@@ -16,11 +16,16 @@
*/
package org.apache.sling.feature;
+import java.util.ArrayList;
+import java.util.Collections;
import java.util.Dictionary;
import java.util.Enumeration;
import java.util.Hashtable;
+import java.util.List;
+import java.util.stream.Collectors;
import org.apache.felix.cm.json.Configurations;
+import org.osgi.util.converter.Converters;
/**
@@ -52,6 +57,13 @@ public class Configuration
*/
public static final String PROP_ARTIFACT_ID = PROP_PREFIX + "service.bundleLocation";
+ /**
+ * This optional configuration property stores the artifact ids (array) of the
+ * features this configuration has been specified.
+ * @since 1.6
+ */
+ public static final String PROP_FEATURE_ORIGINS = PROP_PREFIX + "origins";
+
/** The pid or name for factory pids. */
private final String pid;
@@ -168,6 +180,40 @@ public class Configuration
}
/**
+ * Get the feature origins - if recorded
+ *
+ * @return A immutable list of feature artifact ids - list might be empty
+ * @since 1.6
+ * @throws IllegalArgumentException If the stored values are not valid artifact ids
+ */
+ public List<ArtifactId> getFeatureOrigins() {
+ final List<ArtifactId> list = new ArrayList<>();
+ final Object origins = this.properties.get(PROP_FEATURE_ORIGINS);
+ if ( origins != null ) {
+ final String[] values = Converters.standardConverter().convert(origins).to(String[].class);
+ for(final String v : values) {
+ list.add(ArtifactId.parse(v));
+ }
+ }
+ return Collections.unmodifiableList(list);
+ }
+
+ /**
+ * Set the feature origins
+ * @param featureOrigins the list of artifact ids or null to remove the info from this object
+ * @since 1.6
+ */
+ public void setFeatureOrigins(final List<ArtifactId> featureOrigins) {
+ if ( featureOrigins == null || featureOrigins.isEmpty() ) {
+ this.properties.remove(PROP_FEATURE_ORIGINS);
+ } else {
+ final List<String> list = featureOrigins.stream().map(ArtifactId::toMvnId).collect(Collectors.toList());
+ final String[] values = Converters.standardConverter().convert(list).to(String[].class);
+ this.properties.put(PROP_FEATURE_ORIGINS, values);
+ }
+ }
+
+ /**
* Get the configuration properties of the configuration. This configuration
* properties are all properties minus properties used to manage the
* configuration. Managing properties have to start with
diff --git a/src/main/java/org/apache/sling/feature/builder/BuilderUtil.java b/src/main/java/org/apache/sling/feature/builder/BuilderUtil.java
index 9298f36..1be3bbd 100644
--- a/src/main/java/org/apache/sling/feature/builder/BuilderUtil.java
+++ b/src/main/java/org/apache/sling/feature/builder/BuilderUtil.java
@@ -472,68 +472,83 @@ class BuilderUtil {
}
// configurations - merge / override
- static void mergeConfigurations(final Configurations target, final Configurations source, final Map<String, String> overrides) {
- for(final Configuration cfg : source) {
- boolean found = false;
- for(int c = 0; c < target.size();c++) {
- final Configuration current = target.get(c);
+ static void mergeConfigurations(final Configurations target,
+ final Configurations source,
+ final Map<String, String> overrides,
+ final ArtifactId sourceFeatureId) {
- if ( current.compareTo(cfg) == 0 ) {
- found = true;
+ for(final Configuration cfg : source) {
+ final List<ArtifactId> sourceOrigins = cfg.getFeatureOrigins().isEmpty() ? Collections.singletonList(sourceFeatureId) : cfg.getFeatureOrigins();
+ Configuration found = target.getConfiguration(cfg.getPid());
- boolean handled = false;
- outer:
- for (Map.Entry<String, String> override : overrides.entrySet()) {
- if (match(cfg, override.getKey())) {
- if (BuilderContext.CONFIG_USE_LATEST.equals(override.getValue())) {
- int idx = target.indexOf(current);
- target.remove(current);
- target.add(idx, cfg.copy(cfg.getPid()));
- handled = true;
- }
- else if (BuilderContext.CONFIG_FAIL_ON_PROPERTY_CLASH.equals(override.getValue())){
- for (Enumeration<String> i = cfg.getProperties().keys(); i.hasMoreElements(); ) {
- final String key = i.nextElement();
- if (current.getProperties().get(key) != null) {
- break outer;
- }
- else {
- current.getProperties().put(key, cfg.getProperties().get(key));
- }
- }
- handled = true;
- }
- else if (BuilderContext.CONFIG_MERGE_LATEST.equals(override.getValue())) {
- for (Enumeration<String> i = cfg.getProperties().keys(); i.hasMoreElements(); ) {
- final String key = i.nextElement();
- current.getProperties().put(key, cfg.getProperties().get(key));
+ if ( found != null ) {
+ boolean handled = false;
+ outer:
+ for (Map.Entry<String, String> override : overrides.entrySet()) {
+ if (match(cfg, override.getKey())) {
+ if (BuilderContext.CONFIG_USE_LATEST.equals(override.getValue())) {
+ int idx = target.indexOf(found);
+ target.remove(found);
+ found = cfg.copy(cfg.getPid());
+ target.add(idx, found);
+ handled = true;
+ } else if (BuilderContext.CONFIG_FAIL_ON_PROPERTY_CLASH.equals(override.getValue())){
+ final List<ArtifactId> origins = found.getFeatureOrigins();
+ for (Enumeration<String> i = cfg.getProperties().keys(); i.hasMoreElements(); ) {
+ final String key = i.nextElement();
+ if (found.getProperties().get(key) != null) {
+ break outer;
+ } else {
+ found.getProperties().put(key, cfg.getProperties().get(key));
}
- handled = true;
}
- else if (BuilderContext.CONFIG_USE_FIRST.equals(override.getValue())) {
- handled = true;
+ // restore origin
+ found.setFeatureOrigins(origins);
+ handled = true;
+ } else if (BuilderContext.CONFIG_MERGE_LATEST.equals(override.getValue())) {
+ final List<ArtifactId> origins = found.getFeatureOrigins();
+ for (Enumeration<String> i = cfg.getProperties().keys(); i.hasMoreElements(); ) {
+ final String key = i.nextElement();
+ found.getProperties().put(key, cfg.getProperties().get(key));
}
- else if (BuilderContext.CONFIG_MERGE_FIRST.equals(override.getValue())) {
- for (Enumeration<String> i = cfg.getProperties().keys(); i.hasMoreElements(); ) {
- final String key = i.nextElement();
- if (current.getProperties().get(key) == null) {
- current.getProperties().put(key, cfg.getProperties().get(key));
- }
+ // restore origin
+ found.setFeatureOrigins(origins);
+ handled = true;
+ } else if (BuilderContext.CONFIG_USE_FIRST.equals(override.getValue())) {
+ handled = true;
+ found = null;
+ } else if (BuilderContext.CONFIG_MERGE_FIRST.equals(override.getValue())) {
+ final List<ArtifactId> origins = found.getFeatureOrigins();
+ for (Enumeration<String> i = cfg.getProperties().keys(); i.hasMoreElements(); ) {
+ final String key = i.nextElement();
+ if (found.getProperties().get(key) == null) {
+ found.getProperties().put(key, cfg.getProperties().get(key));
}
- handled = true;
}
- break outer;
+ // restore origin
+ found.setFeatureOrigins(origins);
+ handled = true;
}
- }
- if (!handled) {
- throw new IllegalStateException("Configuration override rule required to select between configurations for " +
- cfg.getPid());
+ break outer;
}
}
+ if (!handled) {
+ throw new IllegalStateException("Configuration override rule required to select between configurations for " +
+ cfg.getPid());
+ }
+ } else {
+ // create new configuration
+ found = cfg.copy(cfg.getPid());
+ target.add(found);
+ if ( !found.getFeatureOrigins().isEmpty() ) {
+ found = null;
+ }
}
- if ( !found ) {
- final Configuration newCfg = cfg.copy(cfg.getPid());
- target.add(newCfg);
+ if ( found != null ) {
+ // update origin
+ final List<ArtifactId> origins = new ArrayList<>(found.getFeatureOrigins());
+ origins.addAll(sourceOrigins);
+ found.setFeatureOrigins(origins);
}
}
}
diff --git a/src/main/java/org/apache/sling/feature/builder/FeatureBuilder.java b/src/main/java/org/apache/sling/feature/builder/FeatureBuilder.java
index 21e08b1..f582a64 100644
--- a/src/main/java/org/apache/sling/feature/builder/FeatureBuilder.java
+++ b/src/main/java/org/apache/sling/feature/builder/FeatureBuilder.java
@@ -356,6 +356,13 @@ public abstract class FeatureBuilder {
}
}
}
+ // correct feature origins
+ for(final Configuration cfg : result.getConfigurations()) {
+ final List<ArtifactId> origins = cfg.getFeatureOrigins();
+ if ( origins.size() == 1 && origins.contains(feature.getId())) {
+ cfg.setFeatureOrigins(null);
+ }
+ }
}
result.setAssembled(true);
@@ -373,7 +380,7 @@ public abstract class FeatureBuilder {
final String originKey) {
BuilderUtil.mergeVariables(target.getVariables(), source.getVariables(), context);
BuilderUtil.mergeArtifacts(target.getBundles(), source.getBundles(), source, artifactOverrides, originKey);
- BuilderUtil.mergeConfigurations(target.getConfigurations(), source.getConfigurations(), configOverrides);
+ BuilderUtil.mergeConfigurations(target.getConfigurations(), source.getConfigurations(), configOverrides, source.getId());
BuilderUtil.mergeFrameworkProperties(target.getFrameworkProperties(), source.getFrameworkProperties(), context);
BuilderUtil.mergeRequirements(target.getRequirements(), source.getRequirements());
BuilderUtil.mergeCapabilities(target.getCapabilities(), source.getCapabilities());
diff --git a/src/main/java/org/apache/sling/feature/package-info.java b/src/main/java/org/apache/sling/feature/package-info.java
index 6ed34c0..9d1cc7f 100644
--- a/src/main/java/org/apache/sling/feature/package-info.java
+++ b/src/main/java/org/apache/sling/feature/package-info.java
@@ -17,7 +17,7 @@
* under the License.
*/
-@org.osgi.annotation.versioning.Version("1.5.0")
+@org.osgi.annotation.versioning.Version("1.6.0")
package org.apache.sling.feature;
diff --git a/src/test/java/org/apache/sling/feature/ConfigurationTest.java b/src/test/java/org/apache/sling/feature/ConfigurationTest.java
index dacdb10..2e28cb3 100644
--- a/src/test/java/org/apache/sling/feature/ConfigurationTest.java
+++ b/src/test/java/org/apache/sling/feature/ConfigurationTest.java
@@ -16,12 +16,17 @@
*/
package org.apache.sling.feature;
+import static org.junit.Assert.assertArrayEquals;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertNull;
import static org.junit.Assert.assertTrue;
import static org.junit.Assert.fail;
+import java.util.Arrays;
+import java.util.Collections;
+
import org.junit.Test;
public class ConfigurationTest {
@@ -67,4 +72,35 @@ public class ConfigurationTest {
assertNull(Configuration.getFactoryPid(pid));
assertNull(Configuration.getName(pid));
}
+
+ @Test
+ public void testFeatureOrigins() {
+ final Configuration cfg = new Configuration("foo");
+ assertTrue(cfg.getFeatureOrigins().isEmpty());
+ assertNull(cfg.getConfigurationProperties().get(Configuration.PROP_FEATURE_ORIGINS));
+ assertNull(cfg.getProperties().get(Configuration.PROP_FEATURE_ORIGINS));
+
+ // single id
+ final ArtifactId id = ArtifactId.parse("g:a:1");
+ cfg.setFeatureOrigins(Collections.singletonList(id));
+ assertEquals(1, cfg.getFeatureOrigins().size());
+ assertEquals(id, cfg.getFeatureOrigins().get(0));
+
+ assertNull(cfg.getConfigurationProperties().get(Configuration.PROP_FEATURE_ORIGINS));
+ assertNotNull(cfg.getProperties().get(Configuration.PROP_FEATURE_ORIGINS));
+ final String[] array = (String[]) cfg.getProperties().get(Configuration.PROP_FEATURE_ORIGINS);
+ assertArrayEquals(new String[] {id.toMvnId()}, array);
+
+ // add another id
+ final ArtifactId id2 = ArtifactId.parse("g:b:2");
+ cfg.setFeatureOrigins(Arrays.asList(id, id2));
+ assertEquals(2, cfg.getFeatureOrigins().size());
+ assertEquals(id, cfg.getFeatureOrigins().get(0));
+ assertEquals(id2, cfg.getFeatureOrigins().get(1));
+
+ assertNull(cfg.getConfigurationProperties().get(Configuration.PROP_FEATURE_ORIGINS));
+ assertNotNull(cfg.getProperties().get(Configuration.PROP_FEATURE_ORIGINS));
+ final String[] array2 = (String[]) cfg.getProperties().get(Configuration.PROP_FEATURE_ORIGINS);
+ assertArrayEquals(new String[] {id.toMvnId(), id2.toMvnId()}, array2);
+ }
}
diff --git a/src/test/java/org/apache/sling/feature/builder/BuilderUtilTest.java b/src/test/java/org/apache/sling/feature/builder/BuilderUtilTest.java
index dd86386..06a06bf 100644
--- a/src/test/java/org/apache/sling/feature/builder/BuilderUtilTest.java
+++ b/src/test/java/org/apache/sling/feature/builder/BuilderUtilTest.java
@@ -27,7 +27,6 @@ import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.HashMap;
-import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
@@ -598,6 +597,8 @@ public class BuilderUtilTest {
assertEquals(0, cfg.size());
}
+ private static final ArtifactId SOURCE_ID = ArtifactId.parse("source:source:1");
+
@Test public void testMergeConfigurations() {
Configurations target = new Configurations();
Configurations source = new Configurations();
@@ -607,10 +608,13 @@ public class BuilderUtilTest {
Configuration bar = new Configuration("bar");
bar.getProperties().put("barKey", "valueBAR");
source.add(bar);
- BuilderUtil.mergeConfigurations(target, source, Collections.emptyMap());
+ BuilderUtil.mergeConfigurations(target, source, Collections.emptyMap(), SOURCE_ID);
assertEquals(2, target.size());
- assertEquals(target.getConfiguration("foo").getProperties(), foo.getProperties());
- assertEquals(target.getConfiguration("bar").getProperties(), bar.getProperties());
+ assertEquals(target.getConfiguration("foo").getConfigurationProperties(), foo.getConfigurationProperties());
+ assertTrue(target.getConfiguration("foo").getFeatureOrigins().isEmpty());
+ assertEquals(target.getConfiguration("bar").getConfigurationProperties(), bar.getConfigurationProperties());
+ assertEquals(1, target.getConfiguration("bar").getFeatureOrigins().size());
+ assertEquals(SOURCE_ID, target.getConfiguration("bar").getFeatureOrigins().get(0));
}
@Test public void testMergeConfigurationsCLASH() {
@@ -619,7 +623,7 @@ public class BuilderUtilTest {
target.add(new Configuration("foo"));
source.add(new Configuration("foo"));
try {
- BuilderUtil.mergeConfigurations(target, source, Collections.emptyMap());
+ BuilderUtil.mergeConfigurations(target, source, Collections.emptyMap(), SOURCE_ID);
fail();
} catch (IllegalStateException ex) {
@@ -635,13 +639,15 @@ public class BuilderUtilTest {
Configuration foo2 = new Configuration("foo");
foo2.getProperties().put("barKey", "valueBAR");
source.add(foo2);
- BuilderUtil.mergeConfigurations(target, source, Collections.singletonMap("fo*", BuilderContext.CONFIG_FAIL_ON_PROPERTY_CLASH));
+ BuilderUtil.mergeConfigurations(target, source, Collections.singletonMap("fo*", BuilderContext.CONFIG_FAIL_ON_PROPERTY_CLASH), SOURCE_ID);
- assertEquals("valueFOO", target.getConfiguration("foo").getProperties().get("fooKey"));
- assertEquals("valueBAR", target.getConfiguration("foo").getProperties().get("barKey"));
+ assertEquals("valueFOO", target.getConfiguration("foo").getConfigurationProperties().get("fooKey"));
+ assertEquals("valueBAR", target.getConfiguration("foo").getConfigurationProperties().get("barKey"));
+ assertEquals(1, target.getConfiguration("foo").getFeatureOrigins().size());
+ assertEquals(SOURCE_ID, target.getConfiguration("foo").getFeatureOrigins().get(0));
try {
- BuilderUtil.mergeConfigurations(target, source, Collections.singletonMap("fo*", BuilderContext.CONFIG_FAIL_ON_PROPERTY_CLASH));
+ BuilderUtil.mergeConfigurations(target, source, Collections.singletonMap("fo*", BuilderContext.CONFIG_FAIL_ON_PROPERTY_CLASH), SOURCE_ID);
fail();
} catch (IllegalStateException ex) {
@@ -657,10 +663,11 @@ public class BuilderUtilTest {
Configuration foo2 = new Configuration("foo");
foo2.getProperties().put("barKey", "valueBAR");
source.add(foo2);
- BuilderUtil.mergeConfigurations(target, source, Collections.singletonMap("fo*", BuilderContext.CONFIG_USE_FIRST));
+ BuilderUtil.mergeConfigurations(target, source, Collections.singletonMap("fo*", BuilderContext.CONFIG_USE_FIRST), SOURCE_ID);
- assertEquals("valueFOO", target.getConfiguration("foo").getProperties().get("fooKey"));
- assertNull(target.getConfiguration("foo").getProperties().get("barKey"));
+ assertEquals("valueFOO", target.getConfiguration("foo").getConfigurationProperties().get("fooKey"));
+ assertNull(target.getConfiguration("foo").getConfigurationProperties().get("barKey"));
+ assertTrue(target.getConfiguration("foo").getFeatureOrigins().isEmpty());
}
@Test public void testMergeConfigurationsUSELATEST() {
@@ -672,10 +679,12 @@ public class BuilderUtilTest {
Configuration foo2 = new Configuration("foo");
foo2.getProperties().put("barKey", "valueBAR");
source.add(foo2);
- BuilderUtil.mergeConfigurations(target, source, Collections.singletonMap("fo*", BuilderContext.CONFIG_USE_LATEST));
+ BuilderUtil.mergeConfigurations(target, source, Collections.singletonMap("fo*", BuilderContext.CONFIG_USE_LATEST), SOURCE_ID);
- assertEquals("valueBAR", target.getConfiguration("foo").getProperties().get("barKey"));
- assertNull(target.getConfiguration("foo").getProperties().get("fooKey"));
+ assertEquals("valueBAR", target.getConfiguration("foo").getConfigurationProperties().get("barKey"));
+ assertNull(target.getConfiguration("foo").getConfigurationProperties().get("fooKey"));
+ assertEquals(1, target.getConfiguration("foo").getFeatureOrigins().size());
+ assertEquals(SOURCE_ID, target.getConfiguration("foo").getFeatureOrigins().get(0));
}
@Test public void testMergeConfigurationsMERGELATEST() {
@@ -687,9 +696,11 @@ public class BuilderUtilTest {
Configuration foo2 = new Configuration("foo");
foo2.getProperties().put("fooKey", "valueBAR");
source.add(foo2);
- BuilderUtil.mergeConfigurations(target, source, Collections.singletonMap("fo*", BuilderContext.CONFIG_MERGE_LATEST));
+ BuilderUtil.mergeConfigurations(target, source, Collections.singletonMap("fo*", BuilderContext.CONFIG_MERGE_LATEST), SOURCE_ID);
- assertEquals("valueBAR", target.getConfiguration("foo").getProperties().get("fooKey"));
+ assertEquals("valueBAR", target.getConfiguration("foo").getConfigurationProperties().get("fooKey"));
+ assertEquals(1, target.getConfiguration("foo").getFeatureOrigins().size());
+ assertEquals(SOURCE_ID, target.getConfiguration("foo").getFeatureOrigins().get(0));
}
@Test public void testMergeConfigurationsMERGEFIRST() {
@@ -702,10 +713,12 @@ public class BuilderUtilTest {
foo2.getProperties().put("fooKey", "valueBAR");
foo2.getProperties().put("barKey", "valueBAR");
source.add(foo2);
- BuilderUtil.mergeConfigurations(target, source, Collections.singletonMap("fo*", BuilderContext.CONFIG_MERGE_FIRST));
+ BuilderUtil.mergeConfigurations(target, source, Collections.singletonMap("fo*", BuilderContext.CONFIG_MERGE_FIRST), SOURCE_ID);
- assertEquals("valueFOO", target.getConfiguration("foo").getProperties().get("fooKey"));
- assertEquals("valueBAR", target.getConfiguration("foo").getProperties().get("barKey"));
+ assertEquals("valueFOO", target.getConfiguration("foo").getConfigurationProperties().get("fooKey"));
+ assertEquals("valueBAR", target.getConfiguration("foo").getConfigurationProperties().get("barKey"));
+ assertEquals(1, target.getConfiguration("foo").getFeatureOrigins().size());
+ assertEquals(SOURCE_ID, target.getConfiguration("foo").getFeatureOrigins().get(0));
}
@Test public void testMergeConfigurationsFactory() {
@@ -717,10 +730,13 @@ public class BuilderUtilTest {
Configuration bar = new Configuration("bar~bar");
bar.getProperties().put("barKey", "valueBAR");
source.add(bar);
- BuilderUtil.mergeConfigurations(target, source, Collections.emptyMap());
+ BuilderUtil.mergeConfigurations(target, source, Collections.emptyMap(), SOURCE_ID);
assertEquals(2, target.size());
- assertEquals(target.getConfiguration("foo~foo").getProperties(), foo.getProperties());
- assertEquals(target.getConfiguration("bar~bar").getProperties(), bar.getProperties());
+ assertEquals(target.getConfiguration("foo~foo").getConfigurationProperties(), foo.getConfigurationProperties());
+ assertTrue(target.getConfiguration("foo~foo").getFeatureOrigins().isEmpty());
+ assertEquals(target.getConfiguration("bar~bar").getConfigurationProperties(), bar.getConfigurationProperties());
+ assertEquals(1, target.getConfiguration("bar~bar").getFeatureOrigins().size());
+ assertEquals(SOURCE_ID, target.getConfiguration("bar~bar").getFeatureOrigins().get(0));
}
@Test public void testMergeConfigurationsCLASHFactory() {
@@ -729,7 +745,7 @@ public class BuilderUtilTest {
target.add(new Configuration("foo~foo"));
source.add(new Configuration("foo~foo"));
try {
- BuilderUtil.mergeConfigurations(target, source, Collections.emptyMap());
+ BuilderUtil.mergeConfigurations(target, source, Collections.emptyMap(), SOURCE_ID);
fail();
} catch (IllegalStateException ex) {
@@ -745,13 +761,15 @@ public class BuilderUtilTest {
Configuration foo2 = new Configuration("foo~foo");
foo2.getProperties().put("barKey", "valueBAR");
source.add(foo2);
- BuilderUtil.mergeConfigurations(target, source, Collections.singletonMap("fo*~f*", BuilderContext.CONFIG_FAIL_ON_PROPERTY_CLASH));
-
- assertEquals("valueFOO", target.getConfiguration("foo~foo").getProperties().get("fooKey"));
- assertEquals("valueBAR", target.getConfiguration("foo~foo").getProperties().get("barKey"));
+ BuilderUtil.mergeConfigurations(target, source, Collections.singletonMap("fo*~f*", BuilderContext.CONFIG_FAIL_ON_PROPERTY_CLASH), SOURCE_ID);
+ assertEquals("valueFOO", target.getConfiguration("foo~foo").getConfigurationProperties().get("fooKey"));
+ assertEquals("valueBAR", target.getConfiguration("foo~foo").getConfigurationProperties().get("barKey"));
+ assertEquals(1, target.getConfiguration("foo~foo").getFeatureOrigins().size());
+ assertEquals(SOURCE_ID, target.getConfiguration("foo~foo").getFeatureOrigins().get(0));
+
try {
- BuilderUtil.mergeConfigurations(target, source, Collections.singletonMap("fo*~fo*", BuilderContext.CONFIG_FAIL_ON_PROPERTY_CLASH));
+ BuilderUtil.mergeConfigurations(target, source, Collections.singletonMap("fo*~fo*", BuilderContext.CONFIG_FAIL_ON_PROPERTY_CLASH), SOURCE_ID);
fail();
} catch (IllegalStateException ex) {
@@ -767,10 +785,12 @@ public class BuilderUtilTest {
Configuration foo2 = new Configuration("foo~foo");
foo2.getProperties().put("barKey", "valueBAR");
source.add(foo2);
- BuilderUtil.mergeConfigurations(target, source, Collections.singletonMap("fo*~f*", BuilderContext.CONFIG_USE_LATEST));
+ BuilderUtil.mergeConfigurations(target, source, Collections.singletonMap("fo*~f*", BuilderContext.CONFIG_USE_LATEST), SOURCE_ID);
- assertEquals("valueBAR", target.getConfiguration("foo~foo").getProperties().get("barKey"));
- assertNull(target.getConfiguration("foo~foo").getProperties().get("fooKey"));
+ assertEquals("valueBAR", target.getConfiguration("foo~foo").getConfigurationProperties().get("barKey"));
+ assertNull(target.getConfiguration("foo~foo").getConfigurationProperties().get("fooKey"));
+ assertEquals(1, target.getConfiguration("foo~foo").getFeatureOrigins().size());
+ assertEquals(SOURCE_ID, target.getConfiguration("foo~foo").getFeatureOrigins().get(0));
}
@Test public void testMergeConfigurationsMERGELATESTFactory() {
@@ -782,9 +802,11 @@ public class BuilderUtilTest {
Configuration foo2 = new Configuration("foo~foo");
foo2.getProperties().put("fooKey", "valueBAR");
source.add(foo2);
- BuilderUtil.mergeConfigurations(target, source, Collections.singletonMap("foo~foo", BuilderContext.CONFIG_MERGE_LATEST));
+ BuilderUtil.mergeConfigurations(target, source, Collections.singletonMap("foo~foo", BuilderContext.CONFIG_MERGE_LATEST), SOURCE_ID);
- assertEquals("valueBAR", target.getConfiguration("foo~foo").getProperties().get("fooKey"));
+ assertEquals("valueBAR", target.getConfiguration("foo~foo").getConfigurationProperties().get("fooKey"));
+ assertEquals(1, target.getConfiguration("foo~foo").getFeatureOrigins().size());
+ assertEquals(SOURCE_ID, target.getConfiguration("foo~foo").getFeatureOrigins().get(0));
}
@Test public void testMergeConfigurationsMixed() {
@@ -798,17 +820,21 @@ public class BuilderUtilTest {
source.add(foo4);
Configuration foo2 = new Configuration("foo");
foo2.getProperties().put("fooKey", "valueBAR");
- source.add(foo2);
+ target.add(foo2);
Configuration foo3 = new Configuration("foo");
foo2.getProperties().put("fooKey", "valueBAR2");
source.add(foo3);
Map<String, String> overrides = new HashMap<>();
overrides.put("foo", BuilderContext.CONFIG_MERGE_LATEST);
overrides.put("foo~foo", BuilderContext.CONFIG_USE_LATEST);
- BuilderUtil.mergeConfigurations(target, source, overrides);
-
- assertEquals("valueFOO4", target.getConfiguration("foo~foo").getProperties().get("fooKey"));
- assertEquals("valueBAR2", target.getConfiguration("foo").getProperties().get("fooKey"));
+ BuilderUtil.mergeConfigurations(target, source, overrides, SOURCE_ID);
+
+ assertEquals("valueFOO4", target.getConfiguration("foo~foo").getConfigurationProperties().get("fooKey"));
+ assertEquals("valueBAR2", target.getConfiguration("foo").getConfigurationProperties().get("fooKey"));
+ assertEquals(1, target.getConfiguration("foo").getFeatureOrigins().size());
+ assertEquals(SOURCE_ID, target.getConfiguration("foo").getFeatureOrigins().get(0));
+ assertEquals(1, target.getConfiguration("foo~foo").getFeatureOrigins().size());
+ assertEquals(SOURCE_ID, target.getConfiguration("foo~foo").getFeatureOrigins().get(0));
}
@SafeVarargs
diff --git a/src/test/java/org/apache/sling/feature/builder/FeatureBuilderTest.java b/src/test/java/org/apache/sling/feature/builder/FeatureBuilderTest.java
index d58d472..e32ae42 100644
--- a/src/test/java/org/apache/sling/feature/builder/FeatureBuilderTest.java
+++ b/src/test/java/org/apache/sling/feature/builder/FeatureBuilderTest.java
@@ -131,7 +131,7 @@ public class FeatureBuilderTest {
for(final Configuration cfg : expected.getConfigurations()) {
final Configuration found = actuals.getConfigurations().getConfiguration(cfg.getPid());
assertNotNull("Configuration " + cfg, found);
- assertEquals("Configuration " + cfg, cfg.getProperties(), found.getProperties());
+ assertEquals("Configuration " + cfg, cfg.getConfigurationProperties(), found.getConfigurationProperties());
}
// frameworkProperties
@@ -203,7 +203,6 @@ public class FeatureBuilderTest {
Feature a = new Feature(ArtifactId.fromMvnId("g:a:1"));
Feature b = new Feature(ArtifactId.fromMvnId("g:b:1"));
-
a.getBundles().add(BuilderUtilTest.createBundle("o/a/1.0.0", 10));
a.getBundles().add(BuilderUtilTest.createBundle("o/a/2.0.0", 9));
a.getBundles().add(BuilderUtilTest.createBundle("o/a/3.0.0", 11));
@@ -264,7 +263,6 @@ public class FeatureBuilderTest {
Feature a = new Feature(ArtifactId.fromMvnId("g:a:1"));
Feature b = new Feature(ArtifactId.fromMvnId("g:b:1"));
-
a.getBundles().add(BuilderUtilTest.createBundle("o/a/1.0.0", 10));
a.getBundles().add(BuilderUtilTest.createBundle("o/a/2.0.0", 9));
a.getBundles().add(BuilderUtilTest.createBundle("o/a/3.0.0", 11));
@@ -1127,6 +1125,171 @@ public class FeatureBuilderTest {
assertEquals("world", result[1]);
}
+ @Test public void testMergeConfigurationFeatureOrigins() {
+ final Feature f1 = new Feature(ArtifactId.parse("g:a:1"));
+ final Configuration c1 = new Configuration("c1");
+ f1.getConfigurations().add(c1);
+ final Configuration c2 = new Configuration("c2");
+ f1.getConfigurations().add(c2);
+
+ final Feature f2 = new Feature(ArtifactId.parse("g:b:1"));
+ final Configuration c3 = new Configuration("c2");
+ f2.getConfigurations().add(c3);
+ final Configuration c4 = new Configuration("c3");
+ f2.getConfigurations().add(c4);
+
+ final BuilderContext bc = new BuilderContext(provider);
+ bc.addConfigsOverrides(Collections.singletonMap("*", BuilderContext.CONFIG_MERGE_LATEST));
+ final Feature f = FeatureBuilder.assemble(ArtifactId.parse("g:f:1"), bc, f1, f2);
+
+ assertEquals(3, f.getConfigurations().size());
+ final Configuration fc1 = f.getConfigurations().getConfiguration("c1");
+ assertNotNull(fc1);
+ final Configuration fc2 = f.getConfigurations().getConfiguration("c2");
+ assertNotNull(fc2);
+ final Configuration fc3 = f.getConfigurations().getConfiguration("c3");
+ assertNotNull(fc3);
+ assertEquals(1, fc1.getFeatureOrigins().size());
+ assertEquals(f1.getId(), fc1.getFeatureOrigins().get(0));
+ assertEquals(2, fc2.getFeatureOrigins().size());
+ assertEquals(f1.getId(), fc2.getFeatureOrigins().get(0));
+ assertEquals(f2.getId(), fc2.getFeatureOrigins().get(1));
+ assertEquals(1, fc3.getFeatureOrigins().size());
+ assertEquals(f2.getId(), fc3.getFeatureOrigins().get(0));
+
+ // merge with empty feature - this should not change the origins
+ final Feature empty = new Feature(ArtifactId.parse("g:c:1"));
+ final Feature ft1 = FeatureBuilder.assemble(ArtifactId.parse("g:e:1"), bc, empty, f);
+
+ assertEquals(3, ft1.getConfigurations().size());
+ final Configuration cft1_1 = ft1.getConfigurations().getConfiguration("c1");
+ assertNotNull(cft1_1);
+ assertEquals(1, cft1_1.getFeatureOrigins().size());
+ assertEquals(f1.getId(), cft1_1.getFeatureOrigins().get(0));
+
+ final Configuration cft1_2 = ft1.getConfigurations().getConfiguration("c2");
+ assertNotNull(cft1_2);
+ assertEquals(2, cft1_2.getFeatureOrigins().size());
+ assertEquals(f1.getId(), cft1_2.getFeatureOrigins().get(0));
+ assertEquals(f2.getId(), cft1_2.getFeatureOrigins().get(1));
+
+ final Configuration cft1_3 = ft1.getConfigurations().getConfiguration("c3");
+ assertNotNull(cft1_3);
+ assertEquals(1, cft1_3.getFeatureOrigins().size());
+ assertEquals(f2.getId(), cft1_3.getFeatureOrigins().get(0));
+
+ // merge with empty feature, reverse order
+ final Feature ft2 = FeatureBuilder.assemble(ArtifactId.parse("g:e:1"), bc, f, empty);
+ assertEquals(3, ft2.getConfigurations().size());
+ final Configuration cft2_1 = ft2.getConfigurations().getConfiguration("c1");
+ assertNotNull(cft2_1);
+ assertEquals(1, cft2_1.getFeatureOrigins().size());
+ assertEquals(f1.getId(), cft2_1.getFeatureOrigins().get(0));
+
+ final Configuration cft2_2 = ft2.getConfigurations().getConfiguration("c2");
+ assertNotNull(cft2_2);
+ assertEquals(2, cft2_2.getFeatureOrigins().size());
+ assertEquals(f1.getId(), cft2_2.getFeatureOrigins().get(0));
+ assertEquals(f2.getId(), cft2_2.getFeatureOrigins().get(1));
+
+ final Configuration cft2_3 = ft2.getConfigurations().getConfiguration("c3");
+ assertNotNull(cft2_3);
+ assertEquals(1, cft2_3.getFeatureOrigins().size());
+ assertEquals(f2.getId(), cft2_3.getFeatureOrigins().get(0));
+
+ // merge with another feature containing c3
+ final Feature f3 = new Feature(ArtifactId.parse("g:x:1"));
+ final Configuration f3c3 = new Configuration("c3");
+ f3.getConfigurations().add(f3c3);
+ final Feature ft3 = FeatureBuilder.assemble(ArtifactId.parse("g:e:1"), bc, f3, f);
+ assertEquals(3, ft3.getConfigurations().size());
+ final Configuration cft3_1 = ft3.getConfigurations().getConfiguration("c1");
+ assertNotNull(cft3_1);
+ assertEquals(1, cft3_1.getFeatureOrigins().size());
+ assertEquals(f1.getId(), cft3_1.getFeatureOrigins().get(0));
+
+ final Configuration cft3_2 = ft3.getConfigurations().getConfiguration("c2");
+ assertNotNull(cft3_2);
+ assertEquals(2, cft3_2.getFeatureOrigins().size());
+ assertEquals(f1.getId(), cft3_2.getFeatureOrigins().get(0));
+ assertEquals(f2.getId(), cft3_2.getFeatureOrigins().get(1));
+
+ final Configuration cft3_3 = ft3.getConfigurations().getConfiguration("c3");
+ assertNotNull(cft3_3);
+ assertEquals(2, cft3_3.getFeatureOrigins().size());
+ assertEquals(f3.getId(), cft3_3.getFeatureOrigins().get(0));
+ assertEquals(f2.getId(), cft3_3.getFeatureOrigins().get(1));
+
+ // merge with another feature containing c3 - reverse order
+ final Feature ft4 = FeatureBuilder.assemble(ArtifactId.parse("g:e:1"), bc, f, f3);
+ assertEquals(3, ft4.getConfigurations().size());
+ final Configuration cft4_1 = ft4.getConfigurations().getConfiguration("c1");
+ assertNotNull(cft4_1);
+ assertEquals(1, cft4_1.getFeatureOrigins().size());
+ assertEquals(f1.getId(), cft4_1.getFeatureOrigins().get(0));
+
+ final Configuration cft4_2 = ft4.getConfigurations().getConfiguration("c2");
+ assertNotNull(cft4_2);
+ assertEquals(2, cft4_2.getFeatureOrigins().size());
+ assertEquals(f1.getId(), cft4_2.getFeatureOrigins().get(0));
+ assertEquals(f2.getId(), cft4_2.getFeatureOrigins().get(1));
+
+ final Configuration cft4_3 = ft4.getConfigurations().getConfiguration("c3");
+ assertNotNull(cft4_3);
+ assertEquals(2, cft4_3.getFeatureOrigins().size());
+ assertEquals(f2.getId(), cft4_3.getFeatureOrigins().get(0));
+ assertEquals(f3.getId(), cft4_3.getFeatureOrigins().get(1));
+ }
+
+ @Test public void testPrototypeConfigurationFeatureOrigins() {
+ final Feature prototype = new Feature(ArtifactId.parse("g:a:1"));
+ final Configuration c1 = new Configuration("c1");
+ prototype.getConfigurations().add(c1);
+ final Configuration c2 = new Configuration("c2");
+ prototype.getConfigurations().add(c2);
+
+ final Feature feature = new Feature(ArtifactId.parse("g:b:1"));
+ final Configuration c3 = new Configuration("c2");
+ feature.getConfigurations().add(c3);
+ final Configuration c4 = new Configuration("c3");
+ feature.getConfigurations().add(c4);
+
+ feature.setPrototype(new Prototype(prototype.getId()));
+ final BuilderContext bc = new BuilderContext(new FeatureProvider(){
+
+ @Override
+ public Feature provide(final ArtifactId id) {
+ if ( id.equals(prototype.getId()) ) {
+ return prototype;
+ }
+ return provider.provide(id);
+ }
+
+ });
+ bc.addConfigsOverrides(Collections.singletonMap("*", BuilderContext.CONFIG_MERGE_LATEST));
+ final Feature assembled = FeatureBuilder.assemble(feature, bc);
+
+ assertEquals(3, assembled.getConfigurations().size());
+
+ // c1 is only in the prototype - origin set to prototype
+ final Configuration fc1 = assembled.getConfigurations().getConfiguration("c1");
+ assertNotNull(fc1);
+ assertEquals(1, fc1.getFeatureOrigins().size());
+ assertEquals(prototype.getId(), fc1.getFeatureOrigins().get(0));
+
+ // c2 is in both - origin set to both
+ final Configuration fc2 = assembled.getConfigurations().getConfiguration("c2");
+ assertNotNull(fc2);
+ assertEquals(2, fc2.getFeatureOrigins().size());
+ assertEquals(prototype.getId(), fc2.getFeatureOrigins().get(0));
+ assertEquals(feature.getId(), fc2.getFeatureOrigins().get(1));
+
+ // c3 is only in the feature - no origins set
+ final Configuration fc3 = assembled.getConfigurations().getConfiguration("c3");
+ assertNotNull(fc3);
+ assertTrue(fc3.getFeatureOrigins().isEmpty());
+ }
+
private static class MatchingRequirementImpl extends RequirementImpl implements MatchingRequirement {
public MatchingRequirementImpl(Resource res, String ns, Map<String, String> dirs, Map<String, Object> attrs) {