You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@sling.apache.org by ro...@apache.org on 2017/11/07 09:57:52 UTC
[sling-org-apache-sling-provisioning-model] 14/19: SLING-4126 :
Provide a mechanism to merge configurations
This is an automated email from the ASF dual-hosted git repository.
rombert pushed a commit to annotated tag org.apache.sling.provisioning.model-1.2.0
in repository https://gitbox.apache.org/repos/asf/sling-org-apache-sling-provisioning-model.git
commit 2192bda035063aad7e638b5b6e5cd3a955e087bb
Author: Carsten Ziegeler <cz...@apache.org>
AuthorDate: Mon Jun 8 13:45:31 2015 +0000
SLING-4126 : Provide a mechanism to merge configurations
git-svn-id: https://svn.apache.org/repos/asf/sling/trunk/tooling/support/provisioning-model@1684183 13f79535-47bb-0310-9956-ffa450edef68
---
.../sling/provisioning/model/ModelConstants.java | 18 ++
.../sling/provisioning/model/ModelUtility.java | 233 ++++++++++++++-------
.../sling/provisioning/model/io/ModelReader.java | 12 +-
.../sling/provisioning/model/io/ModelWriter.java | 22 +-
.../sling/provisioning/model/io/package-info.java | 2 +-
.../sling/provisioning/model/ModelUtilityTest.java | 125 +++++++++++
.../org/apache/sling/provisioning/model/U.java | 8 +-
.../apache/sling/provisioning/model/io/IOTest.java | 17 +-
src/test/resources/merge/config-base.txt | 44 ++++
src/test/resources/merge/config-merge.txt | 35 ++++
10 files changed, 430 insertions(+), 86 deletions(-)
diff --git a/src/main/java/org/apache/sling/provisioning/model/ModelConstants.java b/src/main/java/org/apache/sling/provisioning/model/ModelConstants.java
index e5e74dd..b65ae84 100644
--- a/src/main/java/org/apache/sling/provisioning/model/ModelConstants.java
+++ b/src/main/java/org/apache/sling/provisioning/model/ModelConstants.java
@@ -45,12 +45,30 @@ public abstract class ModelConstants {
/** Format of the unprocessed configuration values. */
public static final String CFG_UNPROCESSED_FORMAT = ":rawconfig.format";
+ /**
+ * Format of the unprocessed configuration values.
+ * @since 1.1
+ */
+ public static final String CFG_UNPROCESSED_MODE = ":rawconfig.mode";
+
/** Format of the Apache Felix Config Admin. */
public static final String CFG_FORMAT_FELIX_CA = "felixca";
/** Property file format. */
public static final String CFG_FORMAT_PROPERTIES = "properties";
+ /**
+ * Mode for overwriting a configuration.
+ * @since 1.1
+ */
+ public static final String CFG_MODE_OVERWRITE = "overwrite";
+
+ /**
+ * Mode for merging a configuration
+ * @since 1.1
+ */
+ public static final String CFG_MODE_MERGE = "merge";
+
/** Name of the webapp run mode. */
public static final String RUN_MODE_WEBAPP = ":webapp";
diff --git a/src/main/java/org/apache/sling/provisioning/model/ModelUtility.java b/src/main/java/org/apache/sling/provisioning/model/ModelUtility.java
index 8c9087f..aa64ed9 100644
--- a/src/main/java/org/apache/sling/provisioning/model/ModelUtility.java
+++ b/src/main/java/org/apache/sling/provisioning/model/ModelUtility.java
@@ -24,8 +24,10 @@ import java.util.Arrays;
import java.util.Dictionary;
import java.util.Enumeration;
import java.util.HashMap;
+import java.util.HashSet;
import java.util.Map;
import java.util.Properties;
+import java.util.Set;
import org.apache.felix.cm.file.ConfigurationHandler;
@@ -125,11 +127,8 @@ public abstract class ModelUtility {
// configurations
for(final Configuration config : runMode.getConfigurations()) {
final Configuration found = baseRunMode.getOrCreateConfiguration(config.getPid(), config.getFactoryPid());
- final Enumeration<String> e = config.getProperties().keys();
- while ( e.hasMoreElements() ) {
- final String key = e.nextElement();
- found.getProperties().put(key, config.getProperties().get(key));
- }
+
+ mergeConfiguration(found, config);
}
// settings
@@ -142,6 +141,79 @@ public abstract class ModelUtility {
}
/**
+ * Merge two configurations
+ * @param baseConfig The base configuration.
+ * @param mergeConfig The merge configuration.
+ */
+ private static void mergeConfiguration(final Configuration baseConfig, final Configuration mergeConfig) {
+ // check for merge mode
+ final boolean baseIsRaw = baseConfig.getProperties().get(ModelConstants.CFG_UNPROCESSED) != null;
+ final boolean mergeIsRaw = mergeConfig.getProperties().get(ModelConstants.CFG_UNPROCESSED) != null;
+ // simplest case, both are raw
+ if ( baseIsRaw && mergeIsRaw ) {
+ final String cfgMode = (String)mergeConfig.getProperties().get(ModelConstants.CFG_UNPROCESSED_MODE);
+ if ( cfgMode == null || ModelConstants.CFG_MODE_OVERWRITE.equals(cfgMode) ) {
+ copyConfigurationProperties(baseConfig, mergeConfig);
+ } else {
+ final Configuration newConfig = new Configuration(baseConfig.getPid(), baseConfig.getFactoryPid());
+ getProcessedConfiguration(newConfig, baseConfig);
+ clearConfiguration(baseConfig);
+ copyConfigurationProperties(baseConfig, newConfig);
+
+ clearConfiguration(newConfig);
+ getProcessedConfiguration(newConfig, mergeConfig);
+ copyConfigurationProperties(baseConfig, newConfig);
+ }
+
+ // another simple case, both are not raw
+ } else if ( !baseIsRaw && !mergeIsRaw ) {
+ // merge mode is always overwrite
+ clearConfiguration(baseConfig);
+ copyConfigurationProperties(baseConfig, mergeConfig);
+
+ // base is not raw but merge is
+ } else if ( !baseIsRaw && mergeIsRaw ) {
+ final String cfgMode = (String)mergeConfig.getProperties().get(ModelConstants.CFG_UNPROCESSED_MODE);
+ if ( cfgMode == null || ModelConstants.CFG_MODE_OVERWRITE.equals(cfgMode) ) {
+ clearConfiguration(baseConfig);
+ copyConfigurationProperties(baseConfig, mergeConfig);
+ } else {
+ final Configuration newMergeConfig = new Configuration(mergeConfig.getPid(), mergeConfig.getFactoryPid());
+ getProcessedConfiguration(newMergeConfig, mergeConfig);
+ copyConfigurationProperties(baseConfig, newMergeConfig);
+ }
+
+ // base is raw, but merge is not raw
+ } else {
+ // merge mode is always overwrite
+ clearConfiguration(baseConfig);
+ copyConfigurationProperties(baseConfig, mergeConfig);
+ }
+ }
+
+ private static void clearConfiguration(final Configuration cfg) {
+ final Set<String> keys = new HashSet<String>();
+ final Enumeration<String> e = cfg.getProperties().keys();
+ while ( e.hasMoreElements() ) {
+ keys.add(e.nextElement());
+ }
+
+ for(final String key : keys) {
+ cfg.getProperties().remove(key);
+ }
+ }
+
+ private static void copyConfigurationProperties(final Configuration baseConfig, final Configuration mergeConfig) {
+ final Enumeration<String> e = mergeConfig.getProperties().keys();
+ while ( e.hasMoreElements() ) {
+ final String key = e.nextElement();
+ if ( !key.equals(ModelConstants.CFG_UNPROCESSED_MODE) ) {
+ baseConfig.getProperties().put(key, mergeConfig.getProperties().get(key));
+ }
+ }
+ }
+
+ /**
* Optional variable resolver
*/
public interface VariableResolver {
@@ -204,80 +276,8 @@ public abstract class ModelUtility {
newRunMode.getConfigurations().setLocation(runMode.getConfigurations().getLocation());
for(final Configuration config : runMode.getConfigurations()) {
final Configuration newConfig = newRunMode.getOrCreateConfiguration(config.getPid(), config.getFactoryPid());
- newConfig.setComment(config.getComment());
- newConfig.setLocation(config.getLocation());
-
- // check for raw configuration
- final String rawConfig = (String)config.getProperties().get(ModelConstants.CFG_UNPROCESSED);
- if ( rawConfig != null ) {
- if ( config.isSpecial() ) {
- newConfig.getProperties().put(config.getPid(), rawConfig);
- } else {
- final String format = (String)config.getProperties().get(ModelConstants.CFG_UNPROCESSED_FORMAT);
-
- if ( ModelConstants.CFG_FORMAT_PROPERTIES.equals(format) ) {
- // properties
- final Properties props = new Properties();
- try {
- props.load(new StringReader(rawConfig));
- } catch ( final IOException ioe) {
- throw new IllegalArgumentException("Unable to read configuration properties.", ioe);
- }
- final Enumeration<Object> i = props.keys();
- while ( i.hasMoreElements() ) {
- final String key = (String)i.nextElement();
- newConfig.getProperties().put(key, props.get(key));
- }
- } else {
- // Apache Felix CA format
- // the raw format might have comments, we have to remove them first
- final StringBuilder sb = new StringBuilder();
- try {
- final LineNumberReader lnr = new LineNumberReader(new StringReader(rawConfig));
- String line = null;
- while ((line = lnr.readLine()) != null ) {
- line = line.trim();
- if ( line.isEmpty() || line.startsWith("#")) {
- continue;
- }
- sb.append(line);
- sb.append('\n');
- }
- } catch ( final IOException ioe) {
- throw new IllegalArgumentException("Unable to read configuration properties: " + config, ioe);
- }
- ByteArrayInputStream bais = null;
- try {
- bais = new ByteArrayInputStream(sb.toString().getBytes("UTF-8"));
- @SuppressWarnings("unchecked")
- final Dictionary<String, Object> props = ConfigurationHandler.read(bais);
- final Enumeration<String> i = props.keys();
- while ( i.hasMoreElements() ) {
- final String key = i.nextElement();
- newConfig.getProperties().put(key, props.get(key));
- }
- } catch ( final IOException ioe) {
- throw new IllegalArgumentException("Unable to read configuration properties: " + config, ioe);
- } finally {
- if ( bais != null ) {
- try {
- bais.close();
- } catch ( final IOException ignore ) {
- // ignore
- }
- }
- }
- }
- }
- } else {
- // simply copy
- final Enumeration<String> i = config.getProperties().keys();
- while ( i.hasMoreElements() ) {
- final String key = i.nextElement();
- newConfig.getProperties().put(key, config.getProperties().get(key));
- }
- }
+ getProcessedConfiguration(newConfig, config);
}
newRunMode.getSettings().setComment(runMode.getSettings().getComment());
@@ -421,4 +421,81 @@ public abstract class ModelUtility {
}
return errors;
}
+
+ private static void getProcessedConfiguration(final Configuration newConfig, final Configuration config) {
+ newConfig.setComment(config.getComment());
+ newConfig.setLocation(config.getLocation());
+
+ // check for raw configuration
+ final String rawConfig = (String)config.getProperties().get(ModelConstants.CFG_UNPROCESSED);
+ if ( rawConfig != null ) {
+ if ( config.isSpecial() ) {
+ newConfig.getProperties().put(config.getPid(), rawConfig);
+ } else {
+ final String format = (String)config.getProperties().get(ModelConstants.CFG_UNPROCESSED_FORMAT);
+
+ if ( ModelConstants.CFG_FORMAT_PROPERTIES.equals(format) ) {
+ // properties
+ final Properties props = new Properties();
+ try {
+ props.load(new StringReader(rawConfig));
+ } catch ( final IOException ioe) {
+ throw new IllegalArgumentException("Unable to read configuration properties.", ioe);
+ }
+ final Enumeration<Object> i = props.keys();
+ while ( i.hasMoreElements() ) {
+ final String key = (String)i.nextElement();
+ newConfig.getProperties().put(key, props.get(key));
+ }
+ } else {
+ // Apache Felix CA format
+ // the raw format might have comments, we have to remove them first
+ final StringBuilder sb = new StringBuilder();
+ try {
+ final LineNumberReader lnr = new LineNumberReader(new StringReader(rawConfig));
+ String line = null;
+ while ((line = lnr.readLine()) != null ) {
+ line = line.trim();
+ if ( line.isEmpty() || line.startsWith("#")) {
+ continue;
+ }
+ sb.append(line);
+ sb.append('\n');
+ }
+ } catch ( final IOException ioe) {
+ throw new IllegalArgumentException("Unable to read configuration properties: " + config, ioe);
+ }
+
+ ByteArrayInputStream bais = null;
+ try {
+ bais = new ByteArrayInputStream(sb.toString().getBytes("UTF-8"));
+ @SuppressWarnings("unchecked")
+ final Dictionary<String, Object> props = ConfigurationHandler.read(bais);
+ final Enumeration<String> i = props.keys();
+ while ( i.hasMoreElements() ) {
+ final String key = i.nextElement();
+ newConfig.getProperties().put(key, props.get(key));
+ }
+ } catch ( final IOException ioe) {
+ throw new IllegalArgumentException("Unable to read configuration properties: " + config, ioe);
+ } finally {
+ if ( bais != null ) {
+ try {
+ bais.close();
+ } catch ( final IOException ignore ) {
+ // ignore
+ }
+ }
+ }
+ }
+ }
+ } else {
+ // simply copy
+ final Enumeration<String> i = config.getProperties().keys();
+ while ( i.hasMoreElements() ) {
+ final String key = i.nextElement();
+ newConfig.getProperties().put(key, config.getProperties().get(key));
+ }
+ }
+ }
}
diff --git a/src/main/java/org/apache/sling/provisioning/model/io/ModelReader.java b/src/main/java/org/apache/sling/provisioning/model/io/ModelReader.java
index 9419880..4d1f9b2 100644
--- a/src/main/java/org/apache/sling/provisioning/model/io/ModelReader.java
+++ b/src/main/java/org/apache/sling/provisioning/model/io/ModelReader.java
@@ -243,7 +243,7 @@ public class ModelReader {
final int startPos = line.indexOf("[");
if ( startPos != -1 ) {
configId = line.substring(0, startPos).trim();
- cfgPars = parseParameters(line.substring(startPos + 1, line.length() - 1).trim(), new String[] {"format"});
+ cfgPars = parseParameters(line.substring(startPos + 1, line.length() - 1).trim(), new String[] {"format", "mode"});
}
}
String format = cfgPars.get("format");
@@ -255,6 +255,15 @@ public class ModelReader {
} else {
format = ModelConstants.CFG_FORMAT_FELIX_CA;
}
+ String cfgMode= cfgPars.get("mode");
+ if ( cfgMode != null ) {
+ if ( !ModelConstants.CFG_MODE_OVERWRITE.equals(cfgMode)
+ && !ModelConstants.CFG_MODE_MERGE.equals(cfgMode) ) {
+ throw new IOException(exceptionPrefix + "Unknown mode configuration parameter in line " + this.lineNumberReader.getLineNumber() + ": " + line);
+ }
+ } else {
+ cfgMode = ModelConstants.CFG_MODE_OVERWRITE;
+ }
final String pid;
final String factoryPid;
final int factoryPos = configId.indexOf('-');
@@ -271,6 +280,7 @@ public class ModelReader {
config = runMode.getOrCreateConfiguration(pid, factoryPid);
this.init(config);
config.getProperties().put(ModelConstants.CFG_UNPROCESSED_FORMAT, format);
+ config.getProperties().put(ModelConstants.CFG_UNPROCESSED_MODE, cfgMode);
configBuilder = new StringBuilder();
mode = CATEGORY.CONFIG;
break;
diff --git a/src/main/java/org/apache/sling/provisioning/model/io/ModelWriter.java b/src/main/java/org/apache/sling/provisioning/model/io/ModelWriter.java
index 470e5fa..8baf9a6 100644
--- a/src/main/java/org/apache/sling/provisioning/model/io/ModelWriter.java
+++ b/src/main/java/org/apache/sling/provisioning/model/io/ModelWriter.java
@@ -175,15 +175,31 @@ public class ModelWriter {
if ( format == null ) {
format = ModelConstants.CFG_FORMAT_FELIX_CA;
}
+ String cfgMode = (String)config.getProperties().get(ModelConstants.CFG_UNPROCESSED_MODE);
+ if ( cfgMode == null ) {
+ cfgMode = ModelConstants.CFG_MODE_OVERWRITE;
+ }
pw.print(" ");
if ( config.getFactoryPid() != null ) {
pw.print(config.getFactoryPid());
pw.print("-");
}
pw.print(config.getPid());
- if ( !ModelConstants.CFG_FORMAT_FELIX_CA.equals(format) ) {
- pw.print(" [format=");
- pw.print(format);
+ final boolean isDefaultFormat = ModelConstants.CFG_FORMAT_FELIX_CA.equals(format);
+ final boolean isDefaultMode = ModelConstants.CFG_MODE_OVERWRITE.equals(cfgMode);
+ if ( !isDefaultFormat || !isDefaultMode ) {
+ pw.print(" [");
+ if ( !isDefaultFormat ) {
+ pw.print("format=");
+ pw.print(format);
+ if ( !isDefaultMode ) {
+ pw.print(",");
+ }
+ }
+ if ( !isDefaultMode) {
+ pw.print("mode=");
+ pw.print(cfgMode);
+ }
pw.print("]");
}
pw.println();
diff --git a/src/main/java/org/apache/sling/provisioning/model/io/package-info.java b/src/main/java/org/apache/sling/provisioning/model/io/package-info.java
index 31f116d..7db48c0 100644
--- a/src/main/java/org/apache/sling/provisioning/model/io/package-info.java
+++ b/src/main/java/org/apache/sling/provisioning/model/io/package-info.java
@@ -17,7 +17,7 @@
* under the License.
*/
-@Version("1.0")
+@Version("1.1")
package org.apache.sling.provisioning.model.io;
import aQute.bnd.annotation.Version;
diff --git a/src/test/java/org/apache/sling/provisioning/model/ModelUtilityTest.java b/src/test/java/org/apache/sling/provisioning/model/ModelUtilityTest.java
index e066712..bfa682f 100644
--- a/src/test/java/org/apache/sling/provisioning/model/ModelUtilityTest.java
+++ b/src/test/java/org/apache/sling/provisioning/model/ModelUtilityTest.java
@@ -16,8 +16,10 @@
*/
package org.apache.sling.provisioning.model;
+import static org.junit.Assert.assertArrayEquals;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertNull;
import java.util.List;
@@ -68,4 +70,127 @@ public class ModelUtilityTest {
assertEquals("org.sling.service.runmode.A", cfgs2.get(0).getPid());
assertEquals("org.sling.service.runmode.C", cfgs2.get(1).getPid());
}
+
+ @Test public void mergeRawTest() throws Exception {
+ final Model baseRaw = U.readCompleteTestModel(new String[] {"merge/config-base.txt"});
+ final Model mergeRaw = U.readCompleteTestModel(new String[] {"merge/config-merge.txt"});
+
+ ModelUtility.merge(baseRaw, mergeRaw);
+
+ final List<Configuration> cfgs = U.assertConfigurationsInRunMode(baseRaw.getFeature("configadmin").getRunMode(), 3);
+
+ final Configuration cfgA = cfgs.get(0);
+ assertEquals("org.apache.test.A", cfgA.getPid());
+ assertNull(cfgA.getFactoryPid());
+ assertEquals(1, cfgA.getProperties().size());
+ assertEquals("AA", cfgA.getProperties().get("name"));
+
+ final Configuration cfgB = cfgs.get(1);
+ assertEquals("org.apache.test.B", cfgB.getPid());
+ assertNull(cfgB.getFactoryPid());
+ assertEquals(3, cfgB.getProperties().size());
+ assertEquals("BB", cfgB.getProperties().get("name"));
+ assertEquals("bar", cfgB.getProperties().get("foo"));
+ assertArrayEquals(new String[] {"one", "two", "three"}, (String[])cfgB.getProperties().get("array"));
+
+ final Configuration cfgC = cfgs.get(2);
+ assertEquals("org.apache.test.C", cfgC.getPid());
+ assertNull(cfgC.getFactoryPid());
+ assertEquals(3, cfgC.getProperties().size());
+ assertEquals("C", cfgC.getProperties().get("name"));
+ assertEquals("bar", cfgB.getProperties().get("foo"));
+ assertArrayEquals(new Integer[] {1,2,3}, (Integer[])cfgC.getProperties().get("array"));
+ }
+
+ @Test public void mergeEffectiveTest() throws Exception {
+ final Model baseRaw = U.readCompleteTestModel(new String[] {"merge/config-base.txt"});
+ final Model mergeRaw = U.readCompleteTestModel(new String[] {"merge/config-merge.txt"});
+
+ final Model baseEffective = ModelUtility.getEffectiveModel(baseRaw, null);
+ final Model mergeEffective = ModelUtility.getEffectiveModel(mergeRaw, null);
+
+ ModelUtility.merge(baseEffective, mergeEffective);
+
+ final List<Configuration> cfgs = U.assertConfigurationsInRunMode(baseEffective.getFeature("configadmin").getRunMode(), 3);
+
+ final Configuration cfgA = cfgs.get(0);
+ assertEquals("org.apache.test.A", cfgA.getPid());
+ assertNull(cfgA.getFactoryPid());
+ assertEquals(1, cfgA.getProperties().size());
+ assertEquals("AA", cfgA.getProperties().get("name"));
+
+ final Configuration cfgB = cfgs.get(1);
+ assertEquals("org.apache.test.B", cfgB.getPid());
+ assertNull(cfgB.getFactoryPid());
+ assertEquals(2, cfgB.getProperties().size());
+ assertEquals("BB", cfgB.getProperties().get("name"));
+ assertEquals("bar", cfgB.getProperties().get("foo"));
+
+ final Configuration cfgC = cfgs.get(2);
+ assertEquals("org.apache.test.C", cfgC.getPid());
+ assertNull(cfgC.getFactoryPid());
+ assertEquals(1, cfgC.getProperties().size());
+ assertEquals("bar", cfgB.getProperties().get("foo"));
+ }
+
+ @Test public void mergeBaseRawTest() throws Exception {
+ final Model baseRaw = U.readCompleteTestModel(new String[] {"merge/config-base.txt"});
+ final Model mergeRaw = U.readCompleteTestModel(new String[] {"merge/config-merge.txt"});
+ final Model mergeEffective = ModelUtility.getEffectiveModel(mergeRaw, null);
+
+ ModelUtility.merge(baseRaw, mergeEffective);
+
+ final List<Configuration> cfgs = U.assertConfigurationsInRunMode(baseRaw.getFeature("configadmin").getRunMode(), 3);
+
+ final Configuration cfgA = cfgs.get(0);
+ assertEquals("org.apache.test.A", cfgA.getPid());
+ assertNull(cfgA.getFactoryPid());
+ assertEquals(1, cfgA.getProperties().size());
+ assertEquals("AA", cfgA.getProperties().get("name"));
+
+ final Configuration cfgB = cfgs.get(1);
+ assertEquals("org.apache.test.B", cfgB.getPid());
+ assertNull(cfgB.getFactoryPid());
+ assertEquals(2, cfgB.getProperties().size());
+ assertEquals("BB", cfgB.getProperties().get("name"));
+ assertEquals("bar", cfgB.getProperties().get("foo"));
+
+ final Configuration cfgC = cfgs.get(2);
+ assertEquals("org.apache.test.C", cfgC.getPid());
+ assertNull(cfgC.getFactoryPid());
+ assertEquals(1, cfgC.getProperties().size());
+ assertEquals("bar", cfgB.getProperties().get("foo"));
+ }
+
+ @Test public void mergeBaseEffectiveTest() throws Exception {
+ final Model baseRaw = U.readCompleteTestModel(new String[] {"merge/config-base.txt"});
+ final Model mergeRaw = U.readCompleteTestModel(new String[] {"merge/config-merge.txt"});
+ final Model baseEffective = ModelUtility.getEffectiveModel(baseRaw, null);
+
+ ModelUtility.merge(baseEffective, mergeRaw);
+
+ final List<Configuration> cfgs = U.assertConfigurationsInRunMode(baseEffective.getFeature("configadmin").getRunMode(), 3);
+
+ final Configuration cfgA = cfgs.get(0);
+ assertEquals("org.apache.test.A", cfgA.getPid());
+ assertNull(cfgA.getFactoryPid());
+ assertEquals(1, cfgA.getProperties().size());
+ assertEquals("AA", cfgA.getProperties().get("name"));
+
+ final Configuration cfgB = cfgs.get(1);
+ assertEquals("org.apache.test.B", cfgB.getPid());
+ assertNull(cfgB.getFactoryPid());
+ assertEquals(3, cfgB.getProperties().size());
+ assertEquals("BB", cfgB.getProperties().get("name"));
+ assertEquals("bar", cfgB.getProperties().get("foo"));
+ assertArrayEquals(new String[] {"one", "two", "three"}, (String[])cfgB.getProperties().get("array"));
+
+ final Configuration cfgC = cfgs.get(2);
+ assertEquals("org.apache.test.C", cfgC.getPid());
+ assertNull(cfgC.getFactoryPid());
+ assertEquals(3, cfgC.getProperties().size());
+ assertEquals("C", cfgC.getProperties().get("name"));
+ assertEquals("bar", cfgB.getProperties().get("foo"));
+ assertArrayEquals(new Integer[] {1,2,3}, (Integer[])cfgC.getProperties().get("array"));
+ }
}
diff --git a/src/test/java/org/apache/sling/provisioning/model/U.java b/src/test/java/org/apache/sling/provisioning/model/U.java
index 65576de..a7924ad 100644
--- a/src/test/java/org/apache/sling/provisioning/model/U.java
+++ b/src/test/java/org/apache/sling/provisioning/model/U.java
@@ -52,7 +52,7 @@ public class U {
/** Read the complete model from that names */
public static Model readCompleteTestModel(final String[] names) throws Exception {
- final Model result = new Model();
+ Model result = null;
for(final String name : names) {
final Reader reader = new InputStreamReader(U.class.getResourceAsStream("/" + name), "UTF-8");
@@ -62,7 +62,11 @@ public class U {
if (errors != null ) {
throw new Exception("Invalid model at " + name + " : " + errors);
}
- ModelUtility.merge(result, current);
+ if ( result == null ) {
+ result = current;
+ } else {
+ ModelUtility.merge(result, current);
+ }
} finally {
reader.close();
}
diff --git a/src/test/java/org/apache/sling/provisioning/model/io/IOTest.java b/src/test/java/org/apache/sling/provisioning/model/io/IOTest.java
index 9abf82d..e271a00 100644
--- a/src/test/java/org/apache/sling/provisioning/model/io/IOTest.java
+++ b/src/test/java/org/apache/sling/provisioning/model/io/IOTest.java
@@ -43,7 +43,7 @@ public class IOTest {
U.verifyTestModel(result, false);
- // Write the merged model
+ // Write the merged raw model
StringWriter writer = new StringWriter();
try {
ModelWriter.write(writer, result);
@@ -66,6 +66,21 @@ public class IOTest {
// Resolve variables and verify the result
final Model effective = ModelUtility.getEffectiveModel(readModel, null);
U.verifyTestModel(effective, true);
+
+ // write effective model
+ writer = new StringWriter();
+ ModelWriter.write(writer, effective);
+ writer.close();
+
+ reader = new StringReader(writer.toString());
+ final Model readModel2 = ModelReader.read(reader, "memory");
+ reader.close();
+ final Map<Traceable, String> readErrors2 = ModelUtility.validate(readModel2);
+ if (readErrors2 != null ) {
+ throw new Exception("Invalid read model : " + readErrors2);
+ }
+ // and verify the result
+ U.verifyTestModel(readModel2, true);
}
@Test public void testMultilineConfiguration() throws Exception {
diff --git a/src/test/resources/merge/config-base.txt b/src/test/resources/merge/config-base.txt
new file mode 100644
index 0000000..e5c0451
--- /dev/null
+++ b/src/test/resources/merge/config-base.txt
@@ -0,0 +1,44 @@
+#
+# 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 a feature description
+#
+# A feature consists of variables and run mode dependent artifacts.
+#
+[feature name=configadmin]
+
+[configurations]
+org.apache.test.A
+ name="A"
+
+org.apache.test.B
+ array=[
+ "one",
+ "two",
+ "three"
+ ]
+ name="B"
+
+org.apache.test.C
+ array=I[
+ "1",
+ "2",
+ "3"
+ ]
+ name="C"
+
\ No newline at end of file
diff --git a/src/test/resources/merge/config-merge.txt b/src/test/resources/merge/config-merge.txt
new file mode 100644
index 0000000..b640577
--- /dev/null
+++ b/src/test/resources/merge/config-merge.txt
@@ -0,0 +1,35 @@
+#
+# 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 a feature description
+#
+# A feature consists of variables and run mode dependent artifacts.
+#
+[feature name=configadmin]
+
+[configurations]
+org.apache.test.A [mode=merge]
+ name="AA"
+
+org.apache.test.B [mode=merge]
+ name="BB"
+ foo="bar"
+
+org.apache.test.C [mode=merge]
+ foo="bar"
+
\ No newline at end of file
--
To stop receiving notification emails like this one, please contact
"commits@sling.apache.org" <co...@sling.apache.org>.