You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@tamaya.apache.org by an...@apache.org on 2016/10/30 22:06:37 UTC

[15/15] incubator-tamaya-extensions git commit: TAMAYA-182: Streamlined/unified builder API and fixed some bugs popping up during testing.

TAMAYA-182: Streamlined/unified builder API and fixed some bugs popping up during testing.


Project: http://git-wip-us.apache.org/repos/asf/incubator-tamaya-extensions/repo
Commit: http://git-wip-us.apache.org/repos/asf/incubator-tamaya-extensions/commit/3aca9112
Tree: http://git-wip-us.apache.org/repos/asf/incubator-tamaya-extensions/tree/3aca9112
Diff: http://git-wip-us.apache.org/repos/asf/incubator-tamaya-extensions/diff/3aca9112

Branch: refs/heads/master
Commit: 3aca9112035e8b1ed70ecd739b03de15c32a3617
Parents: fe7cd8f
Author: anatole <an...@apache.org>
Authored: Sun Oct 30 22:59:21 2016 +0100
Committer: anatole <an...@apache.org>
Committed: Sun Oct 30 22:59:21 2016 +0100

----------------------------------------------------------------------
 ...faultConfigurationContextChangeListener.java |   5 +-
 .../functions/ConfigurationFunctions.java       |   5 +
 .../tamaya/functions/SimplePropertySource.java  |  89 ++++
 modules/mutable-config/pom.xml                  |  82 ++++
 .../mutableconfig/ChangePropagationPolicy.java  |  53 +++
 .../mutableconfig/MutableConfiguration.java     | 126 ++++++
 .../MutableConfigurationProvider.java           | 239 +++++++++++
 .../internal/DefaultMutableConfiguration.java   | 170 ++++++++
 .../DefaultMutableConfigurationSpi.java         |  38 ++
 .../MutablePropertiesPropertySource.java        | 196 +++++++++
 .../MutableXmlPropertiesPropertySource.java     | 198 +++++++++
 .../mutableconfig/spi/ConfigChangeRequest.java  | 176 ++++++++
 .../spi/MutableConfigurationProviderSpi.java    |  42 ++
 .../spi/MutablePropertySource.java              |  47 +++
 ...leconfig.spi.MutableConfigurationProviderSpi |  19 +
 .../MutableConfigurationProviderTest.java       |  84 ++++
 .../mutableconfig/MutableConfigurationTest.java | 187 +++++++++
 .../PropertiesFileConfigBackendTest.java        |  29 ++
 .../internal/WritablePropertiesSource.java      |  49 +++
 .../internal/WritableXmlPropertiesSource.java   |  49 +++
 .../org.apache.tamaya.spi.PropertySource        |  20 +
 modules/spi-support/pom.xml                     |   6 +-
 .../tamaya/spisupport/CLIPropertySource.java    | 101 +++++
 .../tamaya/spisupport/DefaultConfiguration.java |   4 +-
 .../spisupport/DefaultConfigurationContext.java | 253 ++++++------
 .../DefaultConfigurationContextBuilder.java     | 410 +++++++++++++++++++
 .../spisupport/EnvironmentPropertySource.java   | 102 +++++
 .../spisupport/PropertyConverterManager.java    | 248 ++++++-----
 .../spisupport/PropertyFilterComparator.java    |  60 +++
 .../spisupport/PropertyFilterManager.java       | 131 ++++++
 .../tamaya/spisupport/SimplePropertySource.java | 151 +++++++
 .../tamaya/spisupport/SystemPropertySource.java | 125 ++++++
 .../java/org/apache/tamaya/spisupport/A.java    |  29 ++
 .../java/org/apache/tamaya/spisupport/B.java    |  29 ++
 .../spisupport/BasePropertySourceTest.java      | 106 +++++
 .../java/org/apache/tamaya/spisupport/C.java    |  56 +++
 .../spisupport/CLIPropertySourceTest.java       |  59 +++
 .../tamaya/spisupport/CTestConverter.java       |  32 ++
 .../DefaultConfigurationContextTest.java        | 183 +++++++++
 .../tamaya/spisupport/EnumConverterTest.java    |  60 +++
 .../EnvironmentPropertySourceTest.java          |  67 +++
 .../PriorityServiceComparatorTest.java          |  45 ++
 .../PropertiesFilePropertySourceTest.java       |  60 +++
 .../PropertyConverterManagerTest.java           | 180 ++++++++
 .../spisupport/SimplePropertySourceTest.java    |  85 ++++
 .../spisupport/SystemPropertySourceTest.java    | 102 +++++
 .../spisupport/TestPropertyDefaultSource.java   |  56 +++
 .../org.apache.tamaya.spi.PropertyConverter     |  38 ++
 .../src/test/resources/invalid-properties.xml   |  25 ++
 .../src/test/resources/non-xml-properties.xml   |  18 +
 .../test/resources/overrideOrdinal.properties   |  25 ++
 .../src/test/resources/testfile.properties      |  22 +
 .../src/test/resources/valid-properties.xml     |  25 ++
 53 files changed, 4565 insertions(+), 231 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/incubator-tamaya-extensions/blob/3aca9112/modules/events/src/main/java/org/apache/tamaya/events/internal/DefaultConfigurationContextChangeListener.java
----------------------------------------------------------------------
diff --git a/modules/events/src/main/java/org/apache/tamaya/events/internal/DefaultConfigurationContextChangeListener.java b/modules/events/src/main/java/org/apache/tamaya/events/internal/DefaultConfigurationContextChangeListener.java
index e49856d..8a9ff64 100644
--- a/modules/events/src/main/java/org/apache/tamaya/events/internal/DefaultConfigurationContextChangeListener.java
+++ b/modules/events/src/main/java/org/apache/tamaya/events/internal/DefaultConfigurationContextChangeListener.java
@@ -56,10 +56,7 @@ public class DefaultConfigurationContextChangeListener implements ConfigEventLis
                     .setContext(context);
             if (!affectedPropertySources.isEmpty()) {
                 Set<String> propertySourceNames = new HashSet<>();
-                for (PropertySource removed : contextChange.getRemovedPropertySources()) {
-                    propertySourceNames.add(removed.getName());
-                }
-                newContextBuilder.removePropertySources(propertySourceNames);
+                newContextBuilder.removePropertySources(contextChange.getRemovedPropertySources());
             }
             newContextBuilder.addPropertySources(contextChange.getAddedPropertySources());
             newContextBuilder.addPropertySources(contextChange.getUpdatedPropertySources());

http://git-wip-us.apache.org/repos/asf/incubator-tamaya-extensions/blob/3aca9112/modules/functions/src/main/java/org/apache/tamaya/functions/ConfigurationFunctions.java
----------------------------------------------------------------------
diff --git a/modules/functions/src/main/java/org/apache/tamaya/functions/ConfigurationFunctions.java b/modules/functions/src/main/java/org/apache/tamaya/functions/ConfigurationFunctions.java
index 6dd0427..97934f6 100644
--- a/modules/functions/src/main/java/org/apache/tamaya/functions/ConfigurationFunctions.java
+++ b/modules/functions/src/main/java/org/apache/tamaya/functions/ConfigurationFunctions.java
@@ -124,6 +124,11 @@ public final class ConfigurationFunctions {
         }
 
         @Override
+        public PropertySource getPropertySource(String name) {
+            return null;
+        }
+
+        @Override
         public <T> void addPropertyConverter(TypeLiteral<T> typeToConvert, PropertyConverter<T> propertyConverter) {
             // ignore
         }

http://git-wip-us.apache.org/repos/asf/incubator-tamaya-extensions/blob/3aca9112/modules/functions/src/main/java/org/apache/tamaya/functions/SimplePropertySource.java
----------------------------------------------------------------------
diff --git a/modules/functions/src/main/java/org/apache/tamaya/functions/SimplePropertySource.java b/modules/functions/src/main/java/org/apache/tamaya/functions/SimplePropertySource.java
new file mode 100644
index 0000000..5dad7bb
--- /dev/null
+++ b/modules/functions/src/main/java/org/apache/tamaya/functions/SimplePropertySource.java
@@ -0,0 +1,89 @@
+/*
+ * 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.
+ */
+package org.apache.tamaya.functions;
+
+import org.apache.tamaya.spi.PropertySource;
+import org.apache.tamaya.spi.PropertyValue;
+
+import java.util.HashMap;
+import java.util.Map;
+import java.util.Objects;
+import java.util.logging.Level;
+import java.util.logging.Logger;
+
+/**
+* Simple property source implementation using a map.
+*/
+public class SimplePropertySource implements PropertySource {
+    /** The properties. */
+    private final Map<String, String> properties;
+    /** The source's name. */
+    private final String name;
+    /** The default ordinal. */
+    private int defaultOrdinal;
+
+    public SimplePropertySource(String name, Map<String, String> properties){
+        this.properties = new HashMap<>(properties);
+        this.name = Objects.requireNonNull(name);
+    }
+
+    @Override
+    public int getOrdinal(){
+        PropertyValue configuredOrdinal = get(TAMAYA_ORDINAL);
+        if(configuredOrdinal!=null){
+            try{
+                return Integer.parseInt(configuredOrdinal.getValue());
+            } catch(Exception e){
+                Logger.getLogger(getClass().getName()).log(Level.WARNING,
+                        "Configured Ordinal is not an int number: " + configuredOrdinal, e);
+            }
+        }
+        return getDefaultOrdinal();
+    }
+
+    public int getDefaultOrdinal(){
+        return defaultOrdinal;
+    }
+
+    @Override
+    public String getName() {
+        return name;
+    }
+
+    @Override
+    public PropertyValue get(String key) {
+        return PropertyValue.of(key, this.properties.get(key),
+                getName());
+    }
+
+    @Override
+    public Map<String, String> getProperties() {
+        return this.properties;
+    }
+
+    @Override
+    public boolean isScannable() {
+        return false;
+    }
+
+    @Override
+    public String toString(){
+        return "SimplePropertySource(name="+name+", numProps="+properties.size()+")";
+    }
+}

http://git-wip-us.apache.org/repos/asf/incubator-tamaya-extensions/blob/3aca9112/modules/mutable-config/pom.xml
----------------------------------------------------------------------
diff --git a/modules/mutable-config/pom.xml b/modules/mutable-config/pom.xml
new file mode 100644
index 0000000..e9be993
--- /dev/null
+++ b/modules/mutable-config/pom.xml
@@ -0,0 +1,82 @@
+<!-- 
+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 current 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.
+-->
+<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
+    <modelVersion>4.0.0</modelVersion>
+
+    <parent>
+        <groupId>org.apache.tamaya.ext</groupId>
+        <artifactId>tamaya-extensions</artifactId>
+        <version>0.3-incubating-SNAPSHOT</version>
+        <relativePath>..</relativePath>
+    </parent>
+    <artifactId>tamaya-mutable-config</artifactId>
+    <name>Apache Tamaya Modules - Mutable Configuration</name>
+    <description>This module provides abstraction, if your scenario needs to actively change configuration entries
+        and write changes back to some property sources, files etc.</description>
+    <packaging>bundle</packaging>
+
+    <properties>
+        <jdkVersion>1.7</jdkVersion>
+    </properties>
+
+    <dependencies>
+        <dependency>
+            <groupId>org.apache.tamaya</groupId>
+            <artifactId>tamaya-api</artifactId>
+            <version>${project.version}</version>
+        </dependency>
+        <dependency>
+            <groupId>org.apache.tamaya.ext</groupId>
+            <artifactId>tamaya-spisupport</artifactId>
+            <version>${project.version}</version>
+        </dependency>
+        <dependency>
+            <groupId>org.apache.tamaya</groupId>
+            <artifactId>tamaya-core</artifactId>
+            <version>${project.version}</version>
+            <scope>runtime</scope>
+        </dependency>
+        <dependency>
+            <groupId>org.hamcrest</groupId>
+            <artifactId>java-hamcrest</artifactId>
+        </dependency>
+
+        <dependency>
+            <groupId>junit</groupId>
+            <artifactId>junit</artifactId>
+        </dependency>
+    </dependencies>
+
+    <build>
+        <plugins>
+            <plugin>
+                <groupId>org.apache.felix</groupId>
+                <artifactId>maven-bundle-plugin</artifactId>
+                <extensions>true</extensions>
+                <configuration>
+                    <instructions>
+                        <Export-Package>
+                            org.apache.tamaya.mutableconfig
+                        </Export-Package>
+                    </instructions>
+                </configuration>
+            </plugin>
+        </plugins>
+    </build>
+</project>

http://git-wip-us.apache.org/repos/asf/incubator-tamaya-extensions/blob/3aca9112/modules/mutable-config/src/main/java/org/apache/tamaya/mutableconfig/ChangePropagationPolicy.java
----------------------------------------------------------------------
diff --git a/modules/mutable-config/src/main/java/org/apache/tamaya/mutableconfig/ChangePropagationPolicy.java b/modules/mutable-config/src/main/java/org/apache/tamaya/mutableconfig/ChangePropagationPolicy.java
new file mode 100644
index 0000000..5378166
--- /dev/null
+++ b/modules/mutable-config/src/main/java/org/apache/tamaya/mutableconfig/ChangePropagationPolicy.java
@@ -0,0 +1,53 @@
+/*
+ * 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.
+ */
+package org.apache.tamaya.mutableconfig;
+
+import org.apache.tamaya.mutableconfig.spi.ConfigChangeRequest;
+import org.apache.tamaya.spi.PropertySource;
+
+import java.util.Collection;
+
+/**
+ * Policy that defines how changes are applied to the available
+ * {@link org.apache.tamaya.mutableconfig.spi.MutablePropertySource} instances, e.g.
+ * <ul>
+ *     <li><b>ALL: </b>Changes are propagated to all {@link org.apache.tamaya.mutableconfig.spi.MutablePropertySource}
+ *     instances in order of significance. This means that a key added, updated or removed in each instance, if the key
+ *     is writable/removable.</li>
+ *     <li><b>SIGNIFICANT_ONLY: </b>A change (creation, update) is only applied, if
+ * <ol>
+ *     <li>the value is not provided by a more significant read-only property source.</li>
+ *     <li>there is no more significant writable property source, which supports writing a g iven key.</li>
+ * </ol>
+ * In other words a added or updated value is written exactly once to the most significant
+ * writable property source, which accepts a given key. Otherwise the change is discarded.</li>
+ * <li><b>NONE: </b>Do not apply any changes.</li>
+ * </ul>
+ */
+public interface ChangePropagationPolicy {
+
+    /**
+     * Method being called when a multiple key/value pairs are added or updated.
+     * @param propertySources the property sources, including readable property sources of the current configuration,
+     *                        never null.
+     * @param configChange the configuration change, not null.
+     */
+    void applyChange(ConfigChangeRequest configChange, Collection<PropertySource> propertySources);
+
+}

http://git-wip-us.apache.org/repos/asf/incubator-tamaya-extensions/blob/3aca9112/modules/mutable-config/src/main/java/org/apache/tamaya/mutableconfig/MutableConfiguration.java
----------------------------------------------------------------------
diff --git a/modules/mutable-config/src/main/java/org/apache/tamaya/mutableconfig/MutableConfiguration.java b/modules/mutable-config/src/main/java/org/apache/tamaya/mutableconfig/MutableConfiguration.java
new file mode 100644
index 0000000..451769e
--- /dev/null
+++ b/modules/mutable-config/src/main/java/org/apache/tamaya/mutableconfig/MutableConfiguration.java
@@ -0,0 +1,126 @@
+/*
+ * 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.
+ */
+package org.apache.tamaya.mutableconfig;
+
+import org.apache.tamaya.Configuration;
+import org.apache.tamaya.mutableconfig.spi.ConfigChangeRequest;
+
+import java.util.Collection;
+import java.util.Map;
+
+
+/**
+ * This interface extends the Configuration interface hereby adding methods to change configuration entries.
+ * Hereby not all configuration entries are necessarily mutable, since some entries may be read from non
+ * mutable areas of configuration. Of course, it is always possible to add a mutable shadow layer on top of all
+ * property sources to persist/control any changes applied. The exact management and storage persistence algorithm
+ * should be transparent.
+ *
+ * As a consequence clients should first check, using the corresponding methods, if entries can be added/updated or
+ * removed.
+ *
+ * This class should only used in a single threaded context, though all methods inherited from {@link Configuration}
+ * must be thread-safe. Methods handling configuration changes are expected to be used in a single threaded environment
+ * only. For multi-threaded us create a new instance of {@link MutableConfiguration} for each thread.
+ */
+public interface MutableConfiguration extends Configuration {
+
+    /**
+     * Storesd the changes. After a commit the change is not editable anymore. All changes applied will be written to
+     * the corresponding configuration backend.
+     *
+     * NOTE that changes applied must not necessarily be visible in the current {@link Configuration} instance,
+     * since visibility of changes also depends on the ordinals set on the {@link org.apache.tamaya.spi.PropertySource}s
+     * configured.
+     * @throws org.apache.tamaya.ConfigException if the request already has been committed or cancelled, or the commit fails.
+     */
+    void store();
+
+    /**
+     * Access the current configuration change context, built up on all the change context of the participating
+     * {@link org.apache.tamaya.mutableconfig.spi.MutablePropertySource} instances.
+     * @return the colleted changes as one single config change for the current transaction, or null, if no transaction
+     * is active.
+     */
+    ConfigChangeRequest getConfigChangeRequest();
+
+    /**
+     * Access the active {@link ChangePropagationPolicy}.This policy controls how configuration changes are written/published
+     * to the known {@link org.apache.tamaya.mutableconfig.spi.MutablePropertySource} instances of a {@link Configuration}.
+     * @return he active {@link ChangePropagationPolicy}, never null.
+     */
+    ChangePropagationPolicy getChangePropagationPolicy();
+
+    /**
+     * Sets a property.
+     *
+     * @param key   the property's key, not null.
+     * @param value the property's value, not null.
+     * @return the former property value, or null.
+     * @throws org.apache.tamaya.ConfigException if the key/value cannot be added, or the request is read-only.
+     */
+    MutableConfiguration put(String key, String value);
+
+    /**
+     * Puts all given configuration entries. This method should check that all given properties are
+     * basically removable, as defined by #isWritable. If any of the passed keys is not writable during this initial
+     * check, the operation should not perform any configuration changes and throw a
+     * {@link org.apache.tamaya.ConfigException}. If errors occur afterwards, when the properties are effectively
+     * written back to the backends, the errors should be collected and returned as part of the ConfigException
+     * payload. Nevertheless the operation should in that case remove all entries as far as possible and abort the
+     * writing operation.
+     *
+     * @param properties the properties tobe written, not null.
+     * @return the config change request
+     * @throws org.apache.tamaya.ConfigException if any of the given properties could not be written, or the request
+     * is read-only.
+     */
+    MutableConfiguration putAll(Map<String, String> properties);
+
+    /**
+     * Removes all given configuration entries. This method should check that all given properties are
+     * basically removable, as defined by #isRemovable. If any of the passed keys is not removable during this initial
+     * check, the operation should not perform any configuration changes and throw a
+     * {@link org.apache.tamaya.ConfigException}. If errors
+     * occur afterwards, when the properties are effectively written back to the backends, the errors should be
+     * collected and returned as part of the ConfigException payload. Nevertheless the operation should in that case
+     * remove all entries as far as possible and abort the writing operation.
+     *
+     * @param keys the property's keys to be removedProperties, not null.
+     * @return the config change request
+     * @throws org.apache.tamaya.ConfigException if any of the given keys could not be removedProperties, or the
+     * request is read-only.
+     */
+    MutableConfiguration remove(Collection<String> keys);
+
+    /**
+     * Removes all given configuration entries. This method should check that all given properties are
+     * basically removable, as defined by #isRemovable. If any of the passed keys is not removable during this initial
+     * check, the operation should not perform any configuration changes and throw a {@link org.apache.tamaya.ConfigException}. If errors
+     * occur afterwards, when the properties are effectively written back to the backends, the errors should be
+     * collected and returned as part of the ConfigException payload. Nevertheless the operation should in that case
+     * remove all entries as far as possible and abort the writing operation.
+     *
+     * @param keys the property's keys to be removedProperties, not null.
+     * @return the config change request
+     * @throws org.apache.tamaya.ConfigException if any of the given keys could not be removedProperties, or the request is read-only.
+     */
+    MutableConfiguration remove(String... keys);
+
+}

http://git-wip-us.apache.org/repos/asf/incubator-tamaya-extensions/blob/3aca9112/modules/mutable-config/src/main/java/org/apache/tamaya/mutableconfig/MutableConfigurationProvider.java
----------------------------------------------------------------------
diff --git a/modules/mutable-config/src/main/java/org/apache/tamaya/mutableconfig/MutableConfigurationProvider.java b/modules/mutable-config/src/main/java/org/apache/tamaya/mutableconfig/MutableConfigurationProvider.java
new file mode 100644
index 0000000..c2cd20e
--- /dev/null
+++ b/modules/mutable-config/src/main/java/org/apache/tamaya/mutableconfig/MutableConfigurationProvider.java
@@ -0,0 +1,239 @@
+/*
+ * 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.
+ */
+package org.apache.tamaya.mutableconfig;
+
+import org.apache.tamaya.ConfigException;
+import org.apache.tamaya.Configuration;
+import org.apache.tamaya.ConfigurationProvider;
+import org.apache.tamaya.mutableconfig.spi.ConfigChangeRequest;
+import org.apache.tamaya.mutableconfig.spi.MutableConfigurationProviderSpi;
+import org.apache.tamaya.mutableconfig.spi.MutablePropertySource;
+import org.apache.tamaya.spi.PropertySource;
+import org.apache.tamaya.spi.ServiceContextManager;
+
+import java.util.Arrays;
+import java.util.Collection;
+import java.util.HashSet;
+import java.util.Set;
+import java.util.logging.Logger;
+
+
+/**
+ * Accessor for creating {@link MutableConfiguration} instances to change configuration and commit changes.
+ */
+public final class MutableConfigurationProvider {
+
+    private static final Logger LOG = Logger.getLogger(MutableConfigurationProvider.class.getName());
+    /**
+     * URIs used by this query instance to identify the backends to use for write operations.
+     */
+    private static MutableConfigurationProviderSpi mutableConfigurationProviderSpi = loadSpi();
+
+    /**
+     * SPI loader method.
+     * @throws ConfigException if loading fails.
+     * @return the SPI, never null.
+     */
+    private static MutableConfigurationProviderSpi loadSpi() {
+        try{
+            return ServiceContextManager.getServiceContext().getService(
+                    MutableConfigurationProviderSpi.class)  ;
+        } catch(Exception e){
+            throw new ConfigException("Failed to initialize MutableConfigurationProviderSpi - " +
+                    "mutable configuration support.");
+        }
+    }
+
+
+    /** Singleton constructor. */
+    private MutableConfigurationProvider(){}
+
+    /**
+     * Creates a new {@link MutableConfiguration} for the given default configuration, using all
+     * {@link MutablePropertySource} instances found in its context and {@code autoCommit = false}.
+     *
+     * @return a new MutableConfiguration instance
+     */
+    public static MutableConfiguration createMutableConfiguration(){
+        return mutableConfigurationProviderSpi.createMutableConfiguration(
+                ConfigurationProvider.getConfiguration(), getApplyMostSignificantOnlyChangePolicy());
+    }
+
+    /**
+     * Creates a new {@link MutableConfiguration} for the given default configuration, using all
+     * {@link MutablePropertySource} instances found in its context and {@code autoCommit = false}.
+     * @param changePropgationPolicy policy that defines how a change is written back and which property
+     *                               sources are finally eligible for a write operation.
+     * @return a new MutableConfiguration instance, with the given change policy active.
+     */
+    public static MutableConfiguration createMutableConfiguration(ChangePropagationPolicy changePropgationPolicy){
+        return mutableConfigurationProviderSpi.createMutableConfiguration(
+                ConfigurationProvider.getConfiguration(), changePropgationPolicy);
+    }
+
+
+    /**
+     * Creates a new {@link MutableConfiguration} for the given configuration, using all
+     * {@link MutablePropertySource} instances found in its context and {@code MOST_SIGNIFICANT_ONLY_POLICY}
+     * configuration writing policy.
+     *
+     * @param configuration the configuration to use to write the changes/config.
+     * @return a new MutableConfiguration instance
+     */
+    public static MutableConfiguration createMutableConfiguration(Configuration configuration){
+        return createMutableConfiguration(configuration, MOST_SIGNIFICANT_ONLY_POLICY);
+    }
+
+    /**
+     * Creates a new {@link MutableConfiguration} for the given configuration, using all
+     * {@link MutablePropertySource} instances found in its context and {@code ALL_POLICY}
+     * configuration writing policy.
+     *
+     * @param configuration the configuration to use to write the changes/config.
+     * @param changePropagationPolicy the configuration writing policy.
+     * @return a new MutableConfiguration instance
+     */
+    public static MutableConfiguration createMutableConfiguration(Configuration configuration, ChangePropagationPolicy changePropagationPolicy){
+        return mutableConfigurationProviderSpi.createMutableConfiguration(configuration, changePropagationPolicy);
+    }
+
+    /**
+     * This propagation policy writes through all changes to all mutable property sources, where applicable.
+     * This is also the default policy.
+     * @return default all policy.
+     */
+    public static ChangePropagationPolicy getApplyAllChangePolicy(){
+        return ALL_POLICY;
+    }
+
+    /**
+     * This propagation policy writes changes only once to the most significant property source, where a change is
+     * applicable.
+     * @return a corresponding {@link ChangePropagationPolicy} implementation, never null.
+     */
+    public static ChangePropagationPolicy getApplyMostSignificantOnlyChangePolicy(){
+        return MOST_SIGNIFICANT_ONLY_POLICY;
+    }
+
+    /**
+     * This propagation policy writes changes only once to the most significant property source, where a change is
+     * applicable.
+     * @param propertySourceNames the names of the mutable property sources to be considered for writing any changes to.
+     * @return a corresponding {@link ChangePropagationPolicy} implementation, never null.
+     */
+    public static ChangePropagationPolicy getApplySelectiveChangePolicy(String... propertySourceNames){
+        return new SelectiveChangeApplyPolicy(propertySourceNames);
+    }
+
+    /**
+     * This propagation policy writes changes only once to the most significant property source, where a change is
+     * applicable.
+     * @return a corresponding {@link ChangePropagationPolicy} implementation, never null.
+     */
+    public static ChangePropagationPolicy getApplyNonePolicy(){
+        return NONE_POLICY;
+    }
+
+    /**
+     * This propagation policy writes through all changes to all mutable property sources, where applicable.
+     */
+    private static final ChangePropagationPolicy ALL_POLICY = new ChangePropagationPolicy() {
+        @Override
+        public void applyChange(ConfigChangeRequest change, Collection<PropertySource> propertySources) {
+            for(PropertySource propertySource: propertySources){
+                if(propertySource instanceof MutablePropertySource){
+                    MutablePropertySource target = (MutablePropertySource)propertySource;
+                    try{
+                        target.applyChange(change);
+                    }catch(ConfigException e){
+                        LOG.warning("Failed to store changes '"+change+"' not applicable to "+target.getName()
+                        +"("+target.getClass().getName()+").");
+                    }
+                }
+            }
+        }
+
+    };
+
+    /**
+     * This propagation policy writes changes only once to the most significant property source, where a change is
+     * applicable.
+     */
+    private static final ChangePropagationPolicy MOST_SIGNIFICANT_ONLY_POLICY = new ChangePropagationPolicy() {
+        @Override
+        public void applyChange(ConfigChangeRequest change, Collection<PropertySource> propertySources) {
+            for(PropertySource propertySource: propertySources){
+                if(propertySource instanceof MutablePropertySource){
+                    MutablePropertySource target = (MutablePropertySource)propertySource;
+                    try{
+                        target.applyChange(change);
+                    }catch(ConfigException e){
+                        LOG.warning("Failed to store changes '"+change+"' not applicable to "+target.getName()
+                                +"("+target.getClass().getName()+").");
+                    }
+                    break;
+                }
+            }
+        }
+
+    };
+
+    /**
+     * This propagation policy writes changes only once to the most significant property source, where a change is
+     * applicable.
+     */
+    private static final ChangePropagationPolicy NONE_POLICY = new ChangePropagationPolicy() {
+        @Override
+        public void applyChange(ConfigChangeRequest change, Collection<PropertySource> propertySources) {
+            LOG.warning("Cannot store changes '"+change+"': prohibited by change policy (read-only).");
+        }
+    };
+
+    /**
+     * This propagation policy writes through all changes to all mutable property sources, where applicable.
+     */
+    private static final class SelectiveChangeApplyPolicy implements ChangePropagationPolicy {
+
+        private Set<String> propertySourceNames = new HashSet<>();
+
+        SelectiveChangeApplyPolicy(String... propertySourceNames){
+            this.propertySourceNames.addAll(Arrays.asList(propertySourceNames));
+        }
+
+        @Override
+        public void applyChange(ConfigChangeRequest change, Collection<PropertySource> propertySources) {
+            for(PropertySource propertySource: propertySources){
+                if(propertySource instanceof MutablePropertySource){
+                    if(this.propertySourceNames.contains(propertySource.getName())) {
+                        MutablePropertySource target = (MutablePropertySource) propertySource;
+                        try{
+                            target.applyChange(change);
+                        }catch(ConfigException e){
+                            LOG.warning("Failed to store changes '"+change+"' not applicable to "+target.getName()
+                                    +"("+target.getClass().getName()+").");
+                        }
+                        break;
+                    }
+                }
+            }
+        }
+    };
+
+
+}

http://git-wip-us.apache.org/repos/asf/incubator-tamaya-extensions/blob/3aca9112/modules/mutable-config/src/main/java/org/apache/tamaya/mutableconfig/internal/DefaultMutableConfiguration.java
----------------------------------------------------------------------
diff --git a/modules/mutable-config/src/main/java/org/apache/tamaya/mutableconfig/internal/DefaultMutableConfiguration.java b/modules/mutable-config/src/main/java/org/apache/tamaya/mutableconfig/internal/DefaultMutableConfiguration.java
new file mode 100644
index 0000000..ad272ef
--- /dev/null
+++ b/modules/mutable-config/src/main/java/org/apache/tamaya/mutableconfig/internal/DefaultMutableConfiguration.java
@@ -0,0 +1,170 @@
+/*
+ * 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.
+ */
+package org.apache.tamaya.mutableconfig.internal;
+
+import org.apache.tamaya.ConfigOperator;
+import org.apache.tamaya.ConfigQuery;
+import org.apache.tamaya.Configuration;
+import org.apache.tamaya.TypeLiteral;
+import org.apache.tamaya.mutableconfig.ChangePropagationPolicy;
+import org.apache.tamaya.mutableconfig.MutableConfiguration;
+import org.apache.tamaya.mutableconfig.spi.ConfigChangeRequest;
+import org.apache.tamaya.mutableconfig.spi.MutablePropertySource;
+import org.apache.tamaya.spi.ConfigurationContext;
+import org.apache.tamaya.spi.PropertySource;
+
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Collection;
+import java.util.List;
+import java.util.Map;
+import java.util.Objects;
+import java.util.UUID;
+import java.util.logging.Logger;
+
+
+/**
+ * Default implementation of a {@link MutableConfiguration}.
+ */
+public class DefaultMutableConfiguration implements MutableConfiguration {
+    private static final Logger LOG = Logger.getLogger(DefaultMutableConfiguration.class.getName());
+    private ConfigChangeRequest changeRequest = new ConfigChangeRequest(UUID.randomUUID().toString());
+    private final Configuration config;
+    private ChangePropagationPolicy changePropagationPolicy;
+
+    public DefaultMutableConfiguration(Configuration config, ChangePropagationPolicy changePropagationPolicy){
+        this.config = Objects.requireNonNull(config);
+        this.changePropagationPolicy = Objects.requireNonNull(changePropagationPolicy);
+    }
+
+    @Override
+    public ChangePropagationPolicy getChangePropagationPolicy(){
+        return changePropagationPolicy;
+    }
+
+    @Override
+    public ConfigChangeRequest getConfigChangeRequest(){
+        return changeRequest;
+    }
+
+    protected List<MutablePropertySource> getMutablePropertySources() {
+        List<MutablePropertySource> result = new ArrayList<>();
+        for(PropertySource propertySource:this.config.getContext().getPropertySources()) {
+            if(propertySource instanceof  MutablePropertySource){
+                result.add((MutablePropertySource)propertySource);
+            }
+        }
+        return result;
+    }
+
+
+    @Override
+    public MutableConfiguration put(String key, String value) {
+        changeRequest.put(key, value);
+        return this;
+    }
+
+    @Override
+    public MutableConfiguration putAll(Map<String, String> properties) {
+        changeRequest.putAll(properties);
+        return this;
+    }
+
+    @Override
+    public MutableConfiguration remove(String... keys) {
+        changeRequest.removeAll(Arrays.asList(keys));
+        return this;
+    }
+
+
+    @Override
+    public void store() {
+        this.changePropagationPolicy.applyChange(changeRequest, config.getContext().getPropertySources());
+    }
+
+    @Override
+    public MutableConfiguration remove(Collection<String> keys) {
+        for(MutablePropertySource target:getMutablePropertySources()) {
+            changeRequest.removeAll(keys);
+        }
+        return this;
+    }
+
+    @Override
+    public String get(String key) {
+        return this.config.get(key);
+    }
+
+    @Override
+    public String getOrDefault(String key, String defaultValue) {
+        return this.config.getOrDefault(key, defaultValue);
+    }
+
+    @Override
+    public <T> T getOrDefault(String key, Class<T> type, T defaultValue) {
+        return this.config.getOrDefault(key, type, defaultValue);
+    }
+
+    @Override
+    public <T> T get(String key, Class<T> type) {
+        return this.config.get(key, type);
+    }
+
+    @Override
+    public <T> T get(String key, TypeLiteral<T> type) {
+        return this.config.get(key, type);
+    }
+
+    @Override
+    public <T> T getOrDefault(String key, TypeLiteral<T> type, T defaultValue) {
+        return this.config.getOrDefault(key, type, defaultValue);
+    }
+
+        @Override
+    public Map<String, String> getProperties() {
+        return this.config.getProperties();
+    }
+
+    @Override
+    public Configuration with(ConfigOperator operator) {
+        return operator.operate(this);
+    }
+
+    @Override
+    public <T> T query(ConfigQuery<T> query) {
+        return query.query(this);
+    }
+
+    @Override
+    public ConfigurationContext getContext() {
+        return config.getContext();
+    }
+
+    private Collection<PropertySource> getPropertySources() {
+        return this.config.getContext().getPropertySources();
+    }
+
+    @Override
+    public String toString() {
+        return "DefaultMutableConfiguration{" +
+                "config=" + config +
+                '}';
+    }
+
+}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/incubator-tamaya-extensions/blob/3aca9112/modules/mutable-config/src/main/java/org/apache/tamaya/mutableconfig/internal/DefaultMutableConfigurationSpi.java
----------------------------------------------------------------------
diff --git a/modules/mutable-config/src/main/java/org/apache/tamaya/mutableconfig/internal/DefaultMutableConfigurationSpi.java b/modules/mutable-config/src/main/java/org/apache/tamaya/mutableconfig/internal/DefaultMutableConfigurationSpi.java
new file mode 100644
index 0000000..a47cd0e
--- /dev/null
+++ b/modules/mutable-config/src/main/java/org/apache/tamaya/mutableconfig/internal/DefaultMutableConfigurationSpi.java
@@ -0,0 +1,38 @@
+/*
+ * 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.
+ */
+package org.apache.tamaya.mutableconfig.internal;
+
+import org.apache.tamaya.Configuration;
+import org.apache.tamaya.mutableconfig.ChangePropagationPolicy;
+import org.apache.tamaya.mutableconfig.MutableConfiguration;
+import org.apache.tamaya.mutableconfig.spi.MutableConfigurationProviderSpi;
+
+
+/**
+ * SPI implementation that creates instances of {@link DefaultMutableConfiguration}, hereby for
+ * each instance of {@link Configuration} a new instance has to be returned.
+ */
+public class DefaultMutableConfigurationSpi implements MutableConfigurationProviderSpi {
+
+    @Override
+    public MutableConfiguration createMutableConfiguration(Configuration configuration,
+                                                    ChangePropagationPolicy propagationPolicy){
+        return new DefaultMutableConfiguration(configuration, propagationPolicy);
+    }
+}

http://git-wip-us.apache.org/repos/asf/incubator-tamaya-extensions/blob/3aca9112/modules/mutable-config/src/main/java/org/apache/tamaya/mutableconfig/propertysources/MutablePropertiesPropertySource.java
----------------------------------------------------------------------
diff --git a/modules/mutable-config/src/main/java/org/apache/tamaya/mutableconfig/propertysources/MutablePropertiesPropertySource.java b/modules/mutable-config/src/main/java/org/apache/tamaya/mutableconfig/propertysources/MutablePropertiesPropertySource.java
new file mode 100644
index 0000000..af9bed4
--- /dev/null
+++ b/modules/mutable-config/src/main/java/org/apache/tamaya/mutableconfig/propertysources/MutablePropertiesPropertySource.java
@@ -0,0 +1,196 @@
+/*
+ * 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.
+ */
+package org.apache.tamaya.mutableconfig.propertysources;
+
+import org.apache.tamaya.ConfigException;
+import org.apache.tamaya.mutableconfig.spi.ConfigChangeRequest;
+import org.apache.tamaya.mutableconfig.spi.MutablePropertySource;
+import org.apache.tamaya.spi.PropertyValue;
+import org.apache.tamaya.spi.PropertyValueBuilder;
+import org.apache.tamaya.spisupport.BasePropertySource;
+
+import java.io.BufferedOutputStream;
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.util.Collections;
+import java.util.Date;
+import java.util.HashMap;
+import java.util.Map;
+import java.util.Properties;
+import java.util.logging.Level;
+import java.util.logging.Logger;
+
+/**
+ * Simple implementation of a mutable {@link org.apache.tamaya.spi.PropertySource} for .properties files.
+ */
+public class MutablePropertiesPropertySource extends BasePropertySource
+implements MutablePropertySource{
+
+    /**
+     * The logger.
+     */
+    private static final Logger LOG = Logger.getLogger(MutablePropertiesPropertySource.class.getName());
+
+    /**
+     * Default update interval is 1 minute.
+     */
+    private static final long DEFAULT_UPDATE_INTERVAL = 60000L;
+
+    /**
+     * The property source name.
+     */
+    private String name;
+
+    /**
+     * The configuration resource's URL.
+     */
+    private File file;
+
+    /**
+     * Timestamp of last read.
+     */
+    private long lastRead;
+
+    /**
+     * Interval, when the resource should try to update its contents.
+     */
+    private long updateInterval = DEFAULT_UPDATE_INTERVAL;
+    /**
+     * The current properties.
+     */
+    private Map<String, String> properties = new HashMap<>();
+
+    /**
+     * Creates a new Properties based PropertySource based on the given URL.
+     *
+     * @param propertiesLocation the URL encoded location, not null.
+     * @param defaultOrdinal the default ordinal to be used, when no ordinal is provided with the property
+     *                       source's properties.
+     */
+    public MutablePropertiesPropertySource(File propertiesLocation, int defaultOrdinal) {
+        super(defaultOrdinal);
+        this.name = propertiesLocation.toString();
+        try {
+            this.file = propertiesLocation;
+            load();
+        } catch (Exception e) {
+            LOG.log(Level.SEVERE, "Cannot convert file to URL: " + propertiesLocation, e);
+        }
+    }
+
+    @Override
+    public PropertyValue get(String key) {
+        Map<String,String> properties = getProperties();
+        String val = properties.get(key);
+        if(val==null){
+            return null;
+        }
+        PropertyValueBuilder b = new PropertyValueBuilder(key, val, getName());
+        String metaKeyStart = "_" + key + ".";
+        for(Map.Entry<String,String> en:properties.entrySet()) {
+            if(en.getKey().startsWith(metaKeyStart)){
+                b.addContextData(en.getKey().substring(metaKeyStart.length()), en.getValue());
+            }
+        }
+        return b.build();
+    }
+
+    @Override
+    public String getName() {
+        return name;
+    }
+
+    @Override
+    public Map<String, String> getProperties() {
+        checkLoad();
+        return Collections.unmodifiableMap(this.properties);
+    }
+
+
+    private void checkLoad() {
+        if(file!=null && (lastRead+updateInterval)<System.currentTimeMillis()){
+            load();
+        }
+    }
+
+    /**
+     * loads the Properties from the given URL
+     *
+     * @throws IllegalStateException in case of an error while reading properties-file
+     */
+    private void load() {
+        try (InputStream stream = new FileInputStream(file)) {
+            Map<String, String> properties = new HashMap<>();
+            Properties props = new Properties();
+            props.load(stream);
+            for (String key : props.stringPropertyNames()) {
+                properties.put(key, props.getProperty(key));
+            }
+            this.lastRead = System.currentTimeMillis();
+            LOG.log(Level.FINEST, "Loaded properties from " + file);
+            this.properties = properties;
+        } catch (IOException e) {
+            LOG.log(Level.FINEST, "Cannot load properties from " + file, e);
+        }
+    }
+
+    @Override
+    public void applyChange(ConfigChangeRequest change) {
+        if(change.isEmpty()){
+            LOG.info("Nothing to commit for transaction: " + change.getTransactionID());
+            return;
+        }
+        if(!file.exists()){
+            try {
+                if(!file.createNewFile()){
+                    throw new ConfigException("Failed to create config file " + file);
+                }
+            } catch (IOException e) {
+                throw new ConfigException("Failed to create config file " + file, e);
+            }
+        }
+        for(Map.Entry<String,String> en:change.getAddedProperties().entrySet()){
+            int index = en.getKey().indexOf('?');
+            if(index>0){
+                this.properties.put(en.getKey().substring(0, index), en.getValue());
+            }else{
+                this.properties.put(en.getKey(), en.getValue());
+            }
+        }
+        for(String rmKey:change.getRemovedProperties()){
+            this.properties.remove(rmKey);
+        }
+        try(BufferedOutputStream bos = new BufferedOutputStream(new FileOutputStream(file))){
+            Properties props = new Properties();
+            for (Map.Entry<String,String> en : this.properties.entrySet()) {
+                props.setProperty(en.getKey(), en.getValue());
+            }
+            props.store(bos, "Properties written from Tamaya on " + new Date());
+            bos.flush();
+        }
+        catch(Exception e){
+            throw new ConfigException("Failed to write config to " + file, e);
+        }
+    }
+
+
+}

http://git-wip-us.apache.org/repos/asf/incubator-tamaya-extensions/blob/3aca9112/modules/mutable-config/src/main/java/org/apache/tamaya/mutableconfig/propertysources/MutableXmlPropertiesPropertySource.java
----------------------------------------------------------------------
diff --git a/modules/mutable-config/src/main/java/org/apache/tamaya/mutableconfig/propertysources/MutableXmlPropertiesPropertySource.java b/modules/mutable-config/src/main/java/org/apache/tamaya/mutableconfig/propertysources/MutableXmlPropertiesPropertySource.java
new file mode 100644
index 0000000..514ed1d
--- /dev/null
+++ b/modules/mutable-config/src/main/java/org/apache/tamaya/mutableconfig/propertysources/MutableXmlPropertiesPropertySource.java
@@ -0,0 +1,198 @@
+/*
+ * 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.
+ */
+package org.apache.tamaya.mutableconfig.propertysources;
+
+import org.apache.tamaya.ConfigException;
+import org.apache.tamaya.mutableconfig.spi.ConfigChangeRequest;
+import org.apache.tamaya.mutableconfig.spi.MutablePropertySource;
+import org.apache.tamaya.spi.PropertyValue;
+import org.apache.tamaya.spi.PropertyValueBuilder;
+import org.apache.tamaya.spisupport.BasePropertySource;
+
+import java.io.BufferedOutputStream;
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.util.Collections;
+import java.util.Date;
+import java.util.HashMap;
+import java.util.Map;
+import java.util.Properties;
+import java.util.logging.Level;
+import java.util.logging.Logger;
+
+/**
+ * Simple implementation of a mutable {@link org.apache.tamaya.spi.PropertySource} for .xml properties files.
+ */
+public class MutableXmlPropertiesPropertySource extends BasePropertySource
+implements MutablePropertySource{
+
+    /**
+     * The logger.
+     */
+    private static final Logger LOG = Logger.getLogger(MutableXmlPropertiesPropertySource.class.getName());
+    /**
+     * Default update interval is 1 minute.
+     */
+    private static final long DEFAULT_UPDATE_INTERVAL = 60000L;
+
+    /**
+     * The property source name.
+     */
+    private String name;
+
+    /**
+     * The configuration resource's URL.
+     */
+    private File file;
+
+    /**
+     * Timestamp of last read.
+     */
+    private long lastRead;
+
+    /**
+     * Interval, when the resource should try to update its contents.
+     */
+    private long updateInterval = DEFAULT_UPDATE_INTERVAL;
+    /**
+     * The current properties.
+     */
+    private Map<String, String> properties = new HashMap<>();
+
+    /**
+     * Creates a new Properties based PropertySource based on the given URL.
+     *
+     * @param propertiesLocation the URL encoded location, not null.
+     * @param defaultOrdinal the default ordinal to be used, when no ordinal is provided with the property
+     *                       source's properties.
+     */
+    public MutableXmlPropertiesPropertySource(File propertiesLocation, int defaultOrdinal) {
+        super(defaultOrdinal);
+        this.name = propertiesLocation.toString();
+        try {
+            this.file = propertiesLocation;
+            load();
+        } catch (Exception e) {
+            LOG.log(Level.SEVERE, "Cannot convert file to URL: " + propertiesLocation, e);
+        }
+    }
+
+
+
+    @Override
+    public PropertyValue get(String key) {
+        Map<String,String> properties = getProperties();
+        String val = properties.get(key);
+        if(val==null){
+            return null;
+        }
+        PropertyValueBuilder b = new PropertyValueBuilder(key, val, getName());
+        String metaKeyStart = "_" + key + ".";
+        for(Map.Entry<String,String> en:properties.entrySet()) {
+            if(en.getKey().startsWith(metaKeyStart)){
+                b.addContextData(en.getKey().substring(metaKeyStart.length()), en.getValue());
+            }
+        }
+        return b.build();
+    }
+
+    @Override
+    public String getName() {
+        return name;
+    }
+
+    @Override
+    public Map<String, String> getProperties() {
+        checkLoad();
+        return Collections.unmodifiableMap(this.properties);
+    }
+
+
+    private void checkLoad() {
+        if(file!=null && (lastRead+updateInterval)<System.currentTimeMillis()){
+            load();
+        }
+    }
+
+    /**
+     * loads the Properties from the given URL
+     *
+     * @throws IllegalStateException in case of an error while reading properties-file
+     */
+    private void load() {
+        try (InputStream stream = new FileInputStream(file)) {
+            Map<String, String> properties = new HashMap<>();
+            Properties props = new Properties();
+            props.loadFromXML(stream);
+            for (String key : props.stringPropertyNames()) {
+                properties.put(key, props.getProperty(key));
+            }
+            this.lastRead = System.currentTimeMillis();
+            this.properties = properties;
+            LOG.log(Level.FINEST, "Loaded properties from " + file);
+            this.properties = properties;
+        } catch (IOException e) {
+            LOG.log(Level.FINEST, "Cannot load properties from " + file, e);
+        }
+    }
+
+    @Override
+    public void applyChange(ConfigChangeRequest configChange) {
+        if(configChange.isEmpty()){
+            LOG.info("Nothing to commit for transaction: " + configChange.getTransactionID());
+            return;
+        }
+        if(!file.exists()){
+            try {
+                if(!file.createNewFile()){
+                    throw new ConfigException("Failed to create config file " + file);
+                }
+            } catch (IOException e) {
+                throw new ConfigException("Failed to create config file " + file, e);
+            }
+        }
+        for(Map.Entry<String,String> en:configChange.getAddedProperties().entrySet()){
+            int index = en.getKey().indexOf('?');
+            if(index>0){
+                this.properties.put(en.getKey().substring(0, index), en.getValue());
+            }else{
+                this.properties.put(en.getKey(), en.getValue());
+            }
+        }
+        for(String rmKey:configChange.getRemovedProperties()){
+            this.properties.remove(rmKey);
+        }
+        try(BufferedOutputStream bos = new BufferedOutputStream(new FileOutputStream(file))){
+            Properties props = new Properties();
+            for (Map.Entry<String,String> en : this.properties.entrySet()) {
+                props.setProperty(en.getKey(), en.getValue());
+            }
+            props.storeToXML(bos, "Properties written from Tamaya on " + new Date());
+            bos.flush();
+        }
+        catch(Exception e){
+            throw new ConfigException("Failed to write config to " + file, e);
+        }
+    }
+
+
+}

http://git-wip-us.apache.org/repos/asf/incubator-tamaya-extensions/blob/3aca9112/modules/mutable-config/src/main/java/org/apache/tamaya/mutableconfig/spi/ConfigChangeRequest.java
----------------------------------------------------------------------
diff --git a/modules/mutable-config/src/main/java/org/apache/tamaya/mutableconfig/spi/ConfigChangeRequest.java b/modules/mutable-config/src/main/java/org/apache/tamaya/mutableconfig/spi/ConfigChangeRequest.java
new file mode 100644
index 0000000..2349ad1
--- /dev/null
+++ b/modules/mutable-config/src/main/java/org/apache/tamaya/mutableconfig/spi/ConfigChangeRequest.java
@@ -0,0 +1,176 @@
+/*
+ * 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.
+ */
+package org.apache.tamaya.mutableconfig.spi;
+
+import java.util.Collection;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.Map;
+import java.util.Objects;
+import java.util.Set;
+
+/**
+ * Change context used for managing configuration changes within an
+ * {@link org.apache.tamaya.mutableconfig.spi.MutablePropertySource}.
+ */
+public final class ConfigChangeRequest {
+    /**
+     * The transaction id.
+     */
+    private String transactionId;
+    /**
+     * The starting point.
+     */
+    private long startedAt = System.currentTimeMillis();
+    /**
+     * The Properties.
+     */
+    private final Map<String,String> addedProperties = new HashMap<>();
+    /**
+     * The Removed.
+     */
+    private final Set<String> removedProperties = new HashSet<>();
+
+    /**
+     * Creates a new instance bound to the given transaction.
+     * @param transactionID the transaction ID, not null.
+     */
+    public ConfigChangeRequest(String transactionID){
+        this.transactionId = Objects.requireNonNull(transactionID);
+    }
+
+    /**
+     * Sets the started at value. By default {@link #startedAt} is already set on instance creation to
+     * {@code System.currentTimeMillis()}.
+     * @param startedAt the new UTC POSIX timestamp in millis.
+     */
+    public void setStartedAt(long startedAt) {
+        this.startedAt = startedAt;
+    }
+
+    /**
+     * Get the corresppnding transaction ID of this instance.
+     * @return the transaction ID, never null.
+     */
+    public String getTransactionID(){
+        return transactionId;
+    }
+
+    /**
+     * Timestamp in UTC millis, when this transaction (context) was created.
+     * @return the timestamp in millis.
+     */
+    public long getStartedAt(){
+        return startedAt;
+    }
+
+    /**
+     * Get an unmodifiable key/value map of properties added or updated.
+     * @return an unmodifiable key/value map of properties added or updated, never null.
+     */
+    public Map<String,String> getAddedProperties(){
+        return Collections.unmodifiableMap(addedProperties);
+    }
+
+    /**
+     * Get an unmodifiable key set of properties removed.
+     * @return an unmodifiable key set of properties removed, never null.
+     */
+    public Set<String> getRemovedProperties(){
+        return Collections.unmodifiableSet(removedProperties);
+    }
+
+    /**
+     * Adds/updates a new key/value pair.
+     * @param key the key, not null.
+     * @param value the value, not null.
+     */
+    public void put(String key, String value) {
+        this.addedProperties.put(key, value);
+        this.removedProperties.remove(key);
+    }
+
+    /**
+     * Add/updated multiple key/values.
+     * @param properties the keys and values to be added/updated, not null.
+     */
+    public void putAll(Map<String, String> properties) {
+        this.addedProperties.putAll(properties);
+        this.removedProperties.removeAll(properties.keySet());
+    }
+
+    /**
+     * Remove all the given keys, ir present.
+     * @param key the key to be removed, not null.
+     */
+    public void remove(String key) {
+        this.removedProperties.add(key);
+        this.addedProperties.remove(key);
+    }
+
+    /**
+     * Remove all the given keys, ir present.
+     * @param keys the keys to be removed, not null.
+     */
+    public void removeAll(Collection<String> keys) {
+        this.removedProperties.addAll(keys);
+        for(String k:keys) {
+            this.addedProperties.remove(k);
+        }
+    }
+
+    /**
+     * Allows easily to check if no additions/changes an no removals are present in the current transaction.
+     * @return true, if not actions have to be committed.
+     */
+    public boolean isEmpty() {
+        return this.addedProperties.isEmpty() && this.removedProperties.isEmpty();
+    }
+
+    @Override
+    public boolean equals(Object o) {
+        if (this == o) {
+            return true;
+        }
+        if (!(o instanceof ConfigChangeRequest)) {
+            return false;
+        }
+        ConfigChangeRequest that = (ConfigChangeRequest) o;
+        return transactionId.equals(that.transactionId);
+
+    }
+
+    @Override
+    public int hashCode() {
+        return transactionId.hashCode();
+    }
+
+    @Override
+    public String toString() {
+        return "ConfigChangeRequest{" +
+                "transactionId=" + transactionId +
+                ", startedAt=" + startedAt +
+                ", addedProperties=" + addedProperties +
+                ", removedProperties=" + removedProperties +
+                '}';
+    }
+
+
+}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/incubator-tamaya-extensions/blob/3aca9112/modules/mutable-config/src/main/java/org/apache/tamaya/mutableconfig/spi/MutableConfigurationProviderSpi.java
----------------------------------------------------------------------
diff --git a/modules/mutable-config/src/main/java/org/apache/tamaya/mutableconfig/spi/MutableConfigurationProviderSpi.java b/modules/mutable-config/src/main/java/org/apache/tamaya/mutableconfig/spi/MutableConfigurationProviderSpi.java
new file mode 100644
index 0000000..4412085
--- /dev/null
+++ b/modules/mutable-config/src/main/java/org/apache/tamaya/mutableconfig/spi/MutableConfigurationProviderSpi.java
@@ -0,0 +1,42 @@
+/*
+ * 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.
+ */
+package org.apache.tamaya.mutableconfig.spi;
+
+import org.apache.tamaya.Configuration;
+import org.apache.tamaya.mutableconfig.ChangePropagationPolicy;
+import org.apache.tamaya.mutableconfig.MutableConfiguration;
+
+
+/**
+ * Provider SPI used by {@link org.apache.tamaya.mutableconfig.MutableConfigurationProvider}. Providers may override
+ * other providers registering with a higher {@link javax.annotation.Priority} value annotated.
+ */
+public interface MutableConfigurationProviderSpi {
+
+   /**
+    * Creates a new {@link MutableConfiguration} with {@code autoCommit = false} as default.
+    *
+    * @param configuration the configuration, not null.
+    * @param propagationPolicy policy that defines how changes are published to the property
+    *                          sources.
+    * @return a new mutable configuration instance.
+    */
+   MutableConfiguration createMutableConfiguration(Configuration configuration,
+                                                   ChangePropagationPolicy propagationPolicy);
+}

http://git-wip-us.apache.org/repos/asf/incubator-tamaya-extensions/blob/3aca9112/modules/mutable-config/src/main/java/org/apache/tamaya/mutableconfig/spi/MutablePropertySource.java
----------------------------------------------------------------------
diff --git a/modules/mutable-config/src/main/java/org/apache/tamaya/mutableconfig/spi/MutablePropertySource.java b/modules/mutable-config/src/main/java/org/apache/tamaya/mutableconfig/spi/MutablePropertySource.java
new file mode 100644
index 0000000..b648341
--- /dev/null
+++ b/modules/mutable-config/src/main/java/org/apache/tamaya/mutableconfig/spi/MutablePropertySource.java
@@ -0,0 +1,47 @@
+/*
+ * 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.
+ */
+package org.apache.tamaya.mutableconfig.spi;
+
+import org.apache.tamaya.spi.PropertySource;
+
+
+/**
+ * This interface models a writable backend for configuration data.
+ *
+ * As a consequence clients should first check, using the corresponding methods, if entries are to edited or removedProperties
+ * actually are eligible for change/creation or removal.
+ */
+public interface MutablePropertySource extends PropertySource {
+
+    /**
+     * Puts all given configuration entries. This method should check that all given properties are
+     * basically removable, as defined by #isWritable. If any of the passed keys is not writable during this initial
+     * check, the operation should not perform any configuration changes and throw a {@link org.apache.tamaya.ConfigException}. If errors
+     * occur afterwards, when the properties are effectively written back to the backends, the errors should be
+     * collected and returned as part of the ConfigException payload. Nevertheless the operation should in that case
+     * remove all entries as far as possible and abort the writing operation.
+     *
+     * @param configChange the {@link ConfigChangeRequest}, containing the transactionId used to isolate
+     *                     the change, the properties to be added/overridden and the property keys
+     *                     being removed.
+     * @throws org.apache.tamaya.ConfigException if any of the given properties could not be written, or the request is read-only.
+     */
+    void applyChange(ConfigChangeRequest configChange);
+
+}

http://git-wip-us.apache.org/repos/asf/incubator-tamaya-extensions/blob/3aca9112/modules/mutable-config/src/main/resources/META-INF/services/org.apache.tamaya.mutableconfig.spi.MutableConfigurationProviderSpi
----------------------------------------------------------------------
diff --git a/modules/mutable-config/src/main/resources/META-INF/services/org.apache.tamaya.mutableconfig.spi.MutableConfigurationProviderSpi b/modules/mutable-config/src/main/resources/META-INF/services/org.apache.tamaya.mutableconfig.spi.MutableConfigurationProviderSpi
new file mode 100644
index 0000000..eb366fc
--- /dev/null
+++ b/modules/mutable-config/src/main/resources/META-INF/services/org.apache.tamaya.mutableconfig.spi.MutableConfigurationProviderSpi
@@ -0,0 +1,19 @@
+#
+# 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 current 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.
+#
+org.apache.tamaya.mutableconfig.internal.DefaultMutableConfigurationSpi
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/incubator-tamaya-extensions/blob/3aca9112/modules/mutable-config/src/test/java/org/apache/tamaya/mutableconfig/MutableConfigurationProviderTest.java
----------------------------------------------------------------------
diff --git a/modules/mutable-config/src/test/java/org/apache/tamaya/mutableconfig/MutableConfigurationProviderTest.java b/modules/mutable-config/src/test/java/org/apache/tamaya/mutableconfig/MutableConfigurationProviderTest.java
new file mode 100644
index 0000000..b316b7d
--- /dev/null
+++ b/modules/mutable-config/src/test/java/org/apache/tamaya/mutableconfig/MutableConfigurationProviderTest.java
@@ -0,0 +1,84 @@
+/*
+ * 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.
+ */
+
+package org.apache.tamaya.mutableconfig;
+
+import org.apache.tamaya.ConfigurationProvider;
+import org.junit.Test;
+
+import static org.junit.Assert.*;
+
+/**
+ * Created by atsticks on 26.08.16.
+ */
+public class MutableConfigurationProviderTest {
+    @Test
+    public void createMutableConfiguration() throws Exception {
+        assertNotNull(MutableConfigurationProvider.createMutableConfiguration());
+    }
+
+    @Test
+    public void createMutableConfiguration1() throws Exception {
+        MutableConfiguration cfg = MutableConfigurationProvider
+                .createMutableConfiguration(ConfigurationProvider.getConfiguration());
+        assertNotNull(cfg);
+        assertEquals(cfg.getChangePropagationPolicy(),
+                MutableConfigurationProvider.getApplyMostSignificantOnlyChangePolicy());
+    }
+
+    @Test
+    public void createMutableConfiguration2() throws Exception {
+        ChangePropagationPolicy policy = MutableConfigurationProvider.getApplySelectiveChangePolicy("blabla");
+        MutableConfiguration cfg = MutableConfigurationProvider
+                .createMutableConfiguration(ConfigurationProvider.getConfiguration(),
+                        policy);
+        assertNotNull(cfg);
+        assertEquals(cfg.getChangePropagationPolicy(), policy);
+    }
+
+    @Test
+    public void createMutableConfiguration3() throws Exception {
+        ChangePropagationPolicy policy = MutableConfigurationProvider.getApplySelectiveChangePolicy("gugus");
+        MutableConfiguration cfg = MutableConfigurationProvider
+                .createMutableConfiguration(policy);
+        assertNotNull(cfg);
+        assertEquals(cfg.getChangePropagationPolicy(), policy);
+    }
+
+    @Test
+    public void getApplyAllChangePolicy() throws Exception {
+        assertNotNull(MutableConfigurationProvider.getApplyAllChangePolicy());
+    }
+
+    @Test
+    public void getApplyMostSignificantOnlyChangePolicy() throws Exception {
+        assertNotNull(MutableConfigurationProvider.getApplyMostSignificantOnlyChangePolicy());
+    }
+
+    @Test
+    public void getApplySelectiveChangePolicy() throws Exception {
+        assertNotNull(MutableConfigurationProvider.getApplySelectiveChangePolicy());
+    }
+
+    @Test
+    public void getApplyNonePolicy() throws Exception {
+        assertNotNull(MutableConfigurationProvider.getApplyNonePolicy());
+    }
+
+}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/incubator-tamaya-extensions/blob/3aca9112/modules/mutable-config/src/test/java/org/apache/tamaya/mutableconfig/MutableConfigurationTest.java
----------------------------------------------------------------------
diff --git a/modules/mutable-config/src/test/java/org/apache/tamaya/mutableconfig/MutableConfigurationTest.java b/modules/mutable-config/src/test/java/org/apache/tamaya/mutableconfig/MutableConfigurationTest.java
new file mode 100644
index 0000000..814f3ce
--- /dev/null
+++ b/modules/mutable-config/src/test/java/org/apache/tamaya/mutableconfig/MutableConfigurationTest.java
@@ -0,0 +1,187 @@
+/*
+ * 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.
+ */
+package org.apache.tamaya.mutableconfig;
+
+import org.apache.tamaya.Configuration;
+import org.apache.tamaya.ConfigurationProvider;
+import org.apache.tamaya.mutableconfig.internal.WritablePropertiesSource;
+import org.apache.tamaya.mutableconfig.internal.WritableXmlPropertiesSource;
+import org.junit.Test;
+
+import java.io.File;
+import java.io.IOException;
+import java.util.HashMap;
+import java.util.Map;
+import java.util.Properties;
+
+import static org.junit.Assert.*;
+
+/**
+ * Tests for {@link MutableConfiguration}.
+ */
+public class MutableConfigurationTest {
+
+    /**
+     * Test create change request.
+     *
+     * @throws Exception the exception
+     */
+    @Test
+    public void testCreateMutableConfiguration() throws Exception {
+        File f = File.createTempFile("ConfigChangeRequest",".properties");
+        MutableConfiguration cfg1 = MutableConfigurationProvider.createMutableConfiguration(
+                ConfigurationProvider.getConfiguration(),
+                MutableConfigurationProvider.getApplyAllChangePolicy());
+        assertNotNull(cfg1);
+        assertNotNull(cfg1.getConfigChangeRequest());
+        MutableConfiguration cfg2 = MutableConfigurationProvider.createMutableConfiguration(
+                ConfigurationProvider.getConfiguration());
+        assertNotNull(cfg2);
+        assertNotNull(cfg2.getConfigChangeRequest());
+        assertTrue(cfg1!=cfg2);
+        assertTrue(cfg1.getConfigChangeRequest()!=cfg2.getConfigChangeRequest());
+    }
+
+    /**
+     * Test null create change request.
+     *
+     * @throws Exception the exception
+     */
+    @Test(expected=NullPointerException.class)
+    public void testNullCreateMutableConfiguration1() throws Exception {
+        MutableConfigurationProvider.createMutableConfiguration(
+                (Configuration) null);
+    }
+
+    /**
+     * Test null create change request.
+     *
+     * @throws Exception the exception
+     */
+    @Test(expected=NullPointerException.class)
+    public void testNullCreateMutableConfiguration2() throws Exception {
+        MutableConfigurationProvider.createMutableConfiguration(
+                (ChangePropagationPolicy) null);
+    }
+
+    /**
+     * Test read write properties with rollback.
+     *
+     * @throws IOException the io exception
+     */
+    @Test
+    public void testReadWriteProperties_WithCancel() throws IOException {
+        WritablePropertiesSource.target.delete();
+        MutableConfiguration mutConfig = MutableConfigurationProvider.createMutableConfiguration(
+                ConfigurationProvider.getConfiguration()
+        );
+        mutConfig.put("key1", "value1");
+        Map<String,String> cm = new HashMap<>();
+        cm.put("key2", "value2");
+        cm.put("key3", "value3");
+    }
+
+    /**
+     * Test read write properties with commit.
+     *
+     * @throws IOException the io exception
+     */
+    @Test
+    public void testReadWriteProperties_WithCommit() throws IOException {
+        WritablePropertiesSource.target.delete();
+        MutableConfiguration mutConfig = MutableConfigurationProvider.createMutableConfiguration(
+                ConfigurationProvider.getConfiguration()
+        );
+        mutConfig.put("key1", "value1");
+        Map<String,String> cm = new HashMap<>();
+        cm.put("key2", "value2");
+        cm.put("key3", "value3");
+        mutConfig.putAll(cm);
+        mutConfig.store();
+        assertTrue(WritablePropertiesSource.target.exists());
+        MutableConfiguration mmutConfig2 = MutableConfigurationProvider.createMutableConfiguration(
+                ConfigurationProvider.getConfiguration()
+        );
+        mmutConfig2.remove("foo");
+        mmutConfig2.remove("key3");
+        mmutConfig2.put("key1", "value1.2");
+        mmutConfig2.put("key4", "value4");
+        mmutConfig2.store();
+        Properties props = new Properties();
+        props.load(WritablePropertiesSource.target.toURL().openStream());
+        assertEquals(3, props.size());
+        assertEquals("value1.2", props.getProperty("key1"));
+        assertEquals("value2", props.getProperty("key2"));
+        assertEquals("value4", props.getProperty("key4"));
+    }
+
+    /**
+     * Test read write xml properties with commit.
+     *
+     * @throws IOException the io exception
+     */
+    @Test
+    public void testReadWriteXmlProperties_WithCommit() throws IOException {
+        WritableXmlPropertiesSource.target.delete();
+        MutableConfiguration cfg = MutableConfigurationProvider.createMutableConfiguration(
+                ConfigurationProvider.getConfiguration(), MutableConfigurationProvider.getApplyAllChangePolicy());
+        cfg.put("key1", "value1");
+        Map<String,String> cm = new HashMap<>();
+        cm.put("key2", "value2");
+        cm.put("key3", "value3");
+        cfg.putAll(cm);
+        cfg.store();
+        assertTrue(WritableXmlPropertiesSource.target.exists());
+        MutableConfiguration cfg2 = MutableConfigurationProvider.createMutableConfiguration(
+                ConfigurationProvider.getConfiguration());
+        assertTrue(cfg != cfg2);
+        cfg2.remove("foo");
+        cfg2.remove("key3");
+        cfg2.put("key1", "value1.2");
+        cfg2.put("key4", "value4");
+        cfg2.store();
+        Properties props = new Properties();
+        props.loadFromXML( WritableXmlPropertiesSource.target.toURL().openStream());
+        assertEquals(3, props.size());
+        assertEquals("value1", props.getProperty("key1"));
+        assertEquals("value2", props.getProperty("key2"));
+    }
+
+    /**
+     * Test read write xml properties with commit.
+     *
+     * @throws IOException the io exception
+     */
+    @Test
+    public void testWriteWithNoChangePolicy() throws IOException {
+        WritableXmlPropertiesSource.target.delete();
+        MutableConfiguration cfg = MutableConfigurationProvider.createMutableConfiguration(
+                ConfigurationProvider.getConfiguration(),
+                MutableConfigurationProvider.getApplyNonePolicy());
+        cfg.put("key1", "value1");
+        Map<String,String> cm = new HashMap<>();
+        cm.put("key2", "value2");
+        cm.put("key3", "value3");
+        cfg.putAll(cm);
+        cfg.store();
+        assertFalse(WritableXmlPropertiesSource.target.exists());
+    }
+
+
+}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/incubator-tamaya-extensions/blob/3aca9112/modules/mutable-config/src/test/java/org/apache/tamaya/mutableconfig/internal/PropertiesFileConfigBackendTest.java
----------------------------------------------------------------------
diff --git a/modules/mutable-config/src/test/java/org/apache/tamaya/mutableconfig/internal/PropertiesFileConfigBackendTest.java b/modules/mutable-config/src/test/java/org/apache/tamaya/mutableconfig/internal/PropertiesFileConfigBackendTest.java
new file mode 100644
index 0000000..e6c79f5
--- /dev/null
+++ b/modules/mutable-config/src/test/java/org/apache/tamaya/mutableconfig/internal/PropertiesFileConfigBackendTest.java
@@ -0,0 +1,29 @@
+/*
+ * 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.
+ */
+package org.apache.tamaya.mutableconfig.internal;
+
+import org.apache.tamaya.mutableconfig.propertysources.MutablePropertiesPropertySource;
+
+
+/**
+ * Tests for {@link MutablePropertiesPropertySource}.
+ */
+public class PropertiesFileConfigBackendTest {
+
+}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/incubator-tamaya-extensions/blob/3aca9112/modules/mutable-config/src/test/java/org/apache/tamaya/mutableconfig/internal/WritablePropertiesSource.java
----------------------------------------------------------------------
diff --git a/modules/mutable-config/src/test/java/org/apache/tamaya/mutableconfig/internal/WritablePropertiesSource.java b/modules/mutable-config/src/test/java/org/apache/tamaya/mutableconfig/internal/WritablePropertiesSource.java
new file mode 100644
index 0000000..5257c8b
--- /dev/null
+++ b/modules/mutable-config/src/test/java/org/apache/tamaya/mutableconfig/internal/WritablePropertiesSource.java
@@ -0,0 +1,49 @@
+/*
+ * 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.
+ */
+package org.apache.tamaya.mutableconfig.internal;
+
+import org.apache.tamaya.mutableconfig.propertysources.MutablePropertiesPropertySource;
+
+import java.io.File;
+import java.io.IOException;
+
+/**
+ * Writable test property source based on the {@link MutablePropertiesPropertySource}.
+ */
+public class WritablePropertiesSource extends MutablePropertiesPropertySource {
+
+    public static File target = createFile();
+
+    private static File createFile() {
+        try {
+            return File.createTempFile("writableProps",".properties");
+        } catch (IOException e) {
+            e.printStackTrace();
+            throw new IllegalStateException("Cannot init test.", e);
+        }
+    }
+
+    /**
+     * Creates a new Properties based PropertySource based on the given URL.
+     */
+    public WritablePropertiesSource() throws IOException {
+        super(target, 100);
+    }
+    
+}