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 <cziege...@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" <commits@sling.apache.org>.