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/03/01 17:47:49 UTC

[03/14] incubator-tamaya git commit: Added support for having backend data visible in MutableConfig.

Added support for having backend data visible in MutableConfig.


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

Branch: refs/heads/master
Commit: 51260b637c3ef5f4289f118ae4e08e6db45d3712
Parents: 98fe89a
Author: anatole <an...@apache.org>
Authored: Tue Mar 1 09:45:21 2016 +0100
Committer: anatole <an...@apache.org>
Committed: Tue Mar 1 09:45:21 2016 +0100

----------------------------------------------------------------------
 .../mutableconfig/MutableConfiguration.java     |   4 +-
 .../MutableConfigurationQuery.java              | 239 +++++++++++--------
 .../internal/BasePropertySource.java            |   2 +-
 .../PropertiesFileConfigBackendSpi.java         |   6 +-
 .../internal/SimplePropertySource.java          |  75 ++++--
 .../XmlPropertiesFileConfigBackendSpi.java      |   6 +-
 .../AbstractMutableConfigurationBackendSpi.java |  33 ++-
 .../spi/MutableConfigurationBackendSpi.java     |  11 +
 .../MutableConfigurationQueryTest.java          |   4 +-
 .../PropertiesFileConfigBackendTest.java        |  37 ---
 10 files changed, 249 insertions(+), 168 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/incubator-tamaya/blob/51260b63/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
index 9b8da41..4ad3d70 100644
--- 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
@@ -39,12 +39,12 @@ import java.util.Map;
 public interface MutableConfiguration extends Configuration {
 
     /**
-     * Identifies the configuration backends that are targeted by this instance and which are
+     * Identifies the configuration backend that are targeted by this instance and which are
      * also responsible for writing back the changes applied.
      *
      * @return the backend URI, never null.
      */
-    Collection<URI> getBackendURIs();
+    URI getBackendURI();
 
     /**
      * Checks if a configuration key is writable (or it can be added).

http://git-wip-us.apache.org/repos/asf/incubator-tamaya/blob/51260b63/modules/mutable-config/src/main/java/org/apache/tamaya/mutableconfig/MutableConfigurationQuery.java
----------------------------------------------------------------------
diff --git a/modules/mutable-config/src/main/java/org/apache/tamaya/mutableconfig/MutableConfigurationQuery.java b/modules/mutable-config/src/main/java/org/apache/tamaya/mutableconfig/MutableConfigurationQuery.java
index 34177c3..fc7f6cc 100644
--- a/modules/mutable-config/src/main/java/org/apache/tamaya/mutableconfig/MutableConfigurationQuery.java
+++ b/modules/mutable-config/src/main/java/org/apache/tamaya/mutableconfig/MutableConfigurationQuery.java
@@ -29,61 +29,58 @@ import org.apache.tamaya.mutableconfig.spi.MutableConfigurationBackendSpi;
 import org.apache.tamaya.mutableconfig.spi.MutableConfigurationBackendProviderSpi;
 import org.apache.tamaya.spi.ConversionContext;
 import org.apache.tamaya.spi.PropertyConverter;
+import org.apache.tamaya.spi.PropertyValue;
 import org.apache.tamaya.spi.ServiceContextManager;
 
 import java.net.URI;
 import java.net.URISyntaxException;
-import java.util.ArrayList;
-import java.util.Arrays;
 import java.util.Collection;
-import java.util.Collections;
 import java.util.HashMap;
-import java.util.List;
 import java.util.Map;
 import java.util.Objects;
 
 
 /**
- * Accessor for creating {@link MutableConfiguration} instances to change and commit configuration.
+ * Accessor for creating {@link MutableConfiguration} instances to change configuration and commit changes.
  */
 public final class MutableConfigurationQuery implements ConfigQuery<MutableConfiguration> {
 
     /**
      * URIs used by this query instance to identify the backends to use for write operations.
      */
-    private final List<MutableConfigurationBackendSpi> targets = new ArrayList<>();
+    private final MutableConfigurationBackendSpi target;
 
     private ValueVisibilityPolicy valueVisibilityPolicy;
 
     /** Singleton constructor. */
-    private MutableConfigurationQuery(ValueVisibilityPolicy valueVisibilityPolicy, List<MutableConfigurationBackendSpi> targets){
-        this.targets.addAll(targets);
+    private MutableConfigurationQuery(MutableConfigurationBackendSpi target, ValueVisibilityPolicy valueVisibilityPolicy){
+        this.target = Objects.requireNonNull(target);
         this.valueVisibilityPolicy = valueVisibilityPolicy;
     }
 
     @Override
     public MutableConfiguration query(Configuration config) {
-        return new DefaultMutableConfiguration(valueVisibilityPolicy, config, targets);
+        return new DefaultMutableConfiguration(target, valueVisibilityPolicy, config);
     }
 
     /**
-     * Creates a new change request for the given configurationSource
+     * Creates a new {@link MutableConfigurationQuery} for the given configuration target.
      *
-     * @param configurationTargets the configuration targets (String to create URIs) to use to write the changes/config. By passing multiple
+     * @param configurationTarget the configuration targets (String to create URIs) to use to write the changes/config. By passing multiple
      *                             URIs you can write back changes into multiple configuration backends, e.g.
      *                             one for redistributing changes using multicast mechanism, a local property file
      *                             for failover as well as the shared etcd server.
      * @return a new ChangeRequest
      * @throws org.apache.tamaya.ConfigException if the given configurationSource cannot be edited.
      */
-    public static MutableConfigurationQuery of(String... configurationTargets){
-        return of(ValueVisibilityPolicy.CONFIG, configurationTargets);
+    public static MutableConfigurationQuery of(String configurationTarget){
+        return of(configurationTarget, ValueVisibilityPolicy.CONFIG);
     }
 
     /**
-     * Creates a new change request for the given configurationSource
+     * Creates a new {@link MutableConfigurationQuery} for the given configuration target and visibility policy.
      *
-     * @param configurationTargets the configuration targets (String to create URIs) to use to write the changes/config. By passing multiple
+     * @param configurationTarget the configuration targets (String to create URIs) to use to write the changes/config. By passing multiple
      *                             URIs you can write back changes into multiple configuration backends, e.g.
      *                             one for redistributing changes using multicast mechanism, a local property file
      *                             for failover as well as the shared etcd server.
@@ -92,35 +89,32 @@ public final class MutableConfigurationQuery implements ConfigQuery<MutableConfi
      * @return a new ChangeRequest
      * @throws org.apache.tamaya.ConfigException if the given configurationSource cannot be edited.
      */
-    public static MutableConfigurationQuery of(ValueVisibilityPolicy valueVisibilityPolicy, String... configurationTargets){
+    public static MutableConfigurationQuery of(String configurationTarget, ValueVisibilityPolicy valueVisibilityPolicy){
         try {
-            URI[] uris = new URI[configurationTargets.length];
-            for (int i = 0; i < configurationTargets.length; i++) {
-                uris[i] = new URI(configurationTargets[i]);
-            }
-            return of(valueVisibilityPolicy, uris);
+            URI uri = new URI(configurationTarget);
+            return of(uri, valueVisibilityPolicy);
         } catch(URISyntaxException e){
-            throw new ConfigException("Invalid URIs encountered in " + Arrays.toString(configurationTargets));
+            throw new ConfigException("Invalid URI " + configurationTarget);
         }
     }
 
     /**
-     * Creates a new change request for the given configurationSource
+     * Creates a new {@link MutableConfigurationQuery} for the given configuration target.
      *
-     * @param configurationTargets the configuration targets to use to write the changes/config. By passing multiple
+     * @param configurationTarget the configuration targets to use to write the changes/config. By passing multiple
      *                             URIs you can write back changes into multiple configuration backends, e.g.
      *                             one for redistributing changes using multicast mechanism, a local property file
      *                             for failover as well as the shared etcd server.
      * @return a new ChangeRequest
      * @throws org.apache.tamaya.ConfigException if the given configurationSource cannot be edited.
      */
-    public static MutableConfigurationQuery of(URI... configurationTargets){
-        return of(ValueVisibilityPolicy.CONFIG, configurationTargets);
+    public static MutableConfigurationQuery of(URI configurationTarget){
+        return of(configurationTarget, ValueVisibilityPolicy.CONFIG);
     }
     /**
-     * Creates a new change request for the given configurationSource
+     * Creates a new {@link MutableConfigurationQuery} for the given configuration target and visibility policy.
      *
-     * @param configurationTargets the configuration targets to use to write the changes/config. By passing multiple
+     * @param configurationTarget the configuration targets to use to write the changes/config. By passing multiple
      *                             URIs you can write back changes into multiple configuration backends, e.g.
      *                             one for redistributing changes using multicast mechanism, a local property file
      *                             for failover as well as the shared etcd server.
@@ -129,25 +123,89 @@ public final class MutableConfigurationQuery implements ConfigQuery<MutableConfi
      * @return a new ChangeRequest
      * @throws org.apache.tamaya.ConfigException if the given configurationSource cannot be edited.
      */
-    public static MutableConfigurationQuery of(ValueVisibilityPolicy valueVisibilityPolicy, URI... configurationTargets){
-        if(Objects.requireNonNull(configurationTargets).length==0){
-            throw new IllegalArgumentException("At least one target URI is required.");
-        }
-        List<MutableConfigurationBackendSpi> targets = new ArrayList<>();
+    public static MutableConfigurationQuery of(URI configurationTarget, ValueVisibilityPolicy valueVisibilityPolicy){
+        MutableConfigurationBackendSpi target = null;
         for(MutableConfigurationBackendProviderSpi spi:ServiceContextManager.getServiceContext()
                 .getServices(MutableConfigurationBackendProviderSpi.class)){
-            for(URI target:configurationTargets) {
-                MutableConfigurationBackendSpi req = spi.getBackend(target);
-                if (req != null) {
-                    targets.add(req);
-                }
+            MutableConfigurationBackendSpi req = spi.getBackend(Objects.requireNonNull(configurationTarget));
+            if (req != null) {
+                target = req;
+                break;
             }
         }
-        if(targets.isEmpty()) {
-            throw new ConfigException("Not an editable configuration target for: " +
-                    Arrays.toString(configurationTargets));
+        if(target==null) {
+            throw new ConfigException("Not an editable configuration target: " +
+                    configurationTarget);
+        }
+        return new MutableConfigurationQuery(target, Objects.requireNonNull(valueVisibilityPolicy));
+    }
+
+
+
+    /**
+     * Creates a new {@link MutableConfiguration} for the given configuration target.
+     *
+     * @param configurationTarget the configuration targets (String to create URIs) to use to write the changes/config. By passing multiple
+     *                             URIs you can write back changes into multiple configuration backends, e.g.
+     *                             one for redistributing changes using multicast mechanism, a local property file
+     *                             for failover as well as the shared etcd server.
+     * @return a new ChangeRequest
+     * @throws org.apache.tamaya.ConfigException if the given configurationSource cannot be edited.
+     */
+    public static MutableConfiguration createMutableConfiguration(String configurationTarget){
+        return createMutableConfiguration(configurationTarget, ValueVisibilityPolicy.CONFIG);
+    }
+
+    /**
+     * Creates a new {@link MutableConfiguration} for the given configuration target and visibility policy.
+     *
+     * @param configurationTarget the configuration targets (String to create URIs) to use to write the changes/config. By passing multiple
+     *                             URIs you can write back changes into multiple configuration backends, e.g.
+     *                             one for redistributing changes using multicast mechanism, a local property file
+     *                             for failover as well as the shared etcd server.
+     * @param valueVisibilityPolicy the policy that defines how values edited, added or removed are reflected in the read
+     *                         accesses of the {@link MutableConfiguration} created.
+     * @return a new ChangeRequest
+     * @throws org.apache.tamaya.ConfigException if the given configurationSource cannot be edited.
+     */
+    public static MutableConfiguration createMutableConfiguration(String configurationTarget,
+                                                                  ValueVisibilityPolicy valueVisibilityPolicy){
+        try {
+            URI uri = new URI(configurationTarget);
+            return createMutableConfiguration(uri, valueVisibilityPolicy);
+        } catch(URISyntaxException e){
+            throw new ConfigException("Invalid URI " + configurationTarget);
         }
-        return new MutableConfigurationQuery(Objects.requireNonNull(valueVisibilityPolicy), targets);
+    }
+
+    /**
+     * Creates a new {@link MutableConfiguration} for the given configuration target.
+     *
+     * @param configurationTarget the configuration targets to use to write the changes/config. By passing multiple
+     *                             URIs you can write back changes into multiple configuration backends, e.g.
+     *                             one for redistributing changes using multicast mechanism, a local property file
+     *                             for failover as well as the shared etcd server.
+     * @return a new ChangeRequest
+     * @throws org.apache.tamaya.ConfigException if the given configurationSource cannot be edited.
+     */
+    public static MutableConfiguration createMutableConfiguration(URI configurationTarget){
+        return createMutableConfiguration(configurationTarget, ValueVisibilityPolicy.CONFIG);
+    }
+    /**
+     * Creates a new {@link MutableConfiguration} for the given configuration target and visibility policy.
+     *
+     * @param configurationTarget the configuration targets to use to write the changes/config. By passing multiple
+     *                             URIs you can write back changes into multiple configuration backends, e.g.
+     *                             one for redistributing changes using multicast mechanism, a local property file
+     *                             for failover as well as the shared etcd server.
+     * @param valueVisibilityPolicy the policy that defines how values edited, added or removed are reflected in the read
+     *                         accesses of the {@link MutableConfiguration} created.
+     * @return a new ChangeRequest
+     * @throws org.apache.tamaya.ConfigException if the given configurationSource cannot be edited.
+     */
+    public static MutableConfiguration createMutableConfiguration(URI configurationTarget,
+                                                                  ValueVisibilityPolicy valueVisibilityPolicy){
+        return Configuration.EMPTY.query(of(configurationTarget, valueVisibilityPolicy));
     }
 
 
@@ -157,72 +215,49 @@ public final class MutableConfigurationQuery implements ConfigQuery<MutableConfi
     private static final class DefaultMutableConfiguration extends AbstractMutableConfiguration
             implements MutableConfiguration {
 
-        private final List<MutableConfigurationBackendSpi> targets;
+        private final MutableConfigurationBackendSpi target;
         private final Configuration config;
         private ValueVisibilityPolicy valueVisibilityPolicy;
 
-        DefaultMutableConfiguration(ValueVisibilityPolicy valueVisibilityPolicy, Configuration config, List<MutableConfigurationBackendSpi> targets){
-            this.targets = Objects.requireNonNull(targets);
+        DefaultMutableConfiguration(MutableConfigurationBackendSpi target, ValueVisibilityPolicy valueVisibilityPolicy, Configuration config){
+            this.target = Objects.requireNonNull(target);
             this.config = Objects.requireNonNull(config);
             this.valueVisibilityPolicy = valueVisibilityPolicy;
         }
 
         @Override
-        public List<URI> getBackendURIs() {
-            List<URI> result = new ArrayList<>(targets.size());
-            for(MutableConfigurationBackendSpi backend: targets){
-                result.add(backend.getBackendURI());
-            }
-            return Collections.unmodifiableList(result);
+        public URI getBackendURI() {
+            return target.getBackendURI();
         }
 
         @Override
         public boolean isWritable(String keyExpression) {
-            for(MutableConfigurationBackendSpi req:targets){
-                if(req.isWritable(keyExpression)){
-                    return true;
-                }
-            }
-            return false;
+            return target.isWritable(keyExpression);
         }
 
         @Override
         public boolean isRemovable(String keyExpression) {
-            for(MutableConfigurationBackendSpi req:targets){
-                if(req.isRemovable(keyExpression)){
-                    return true;
-                }
-            }
-            return false;
+            return target.isRemovable(keyExpression);
         }
 
         @Override
         public boolean isExisting(String keyExpression) {
-            for(MutableConfigurationBackendSpi req:targets){
-                if(req.isExisting(keyExpression)){
-                    return true;
-                }
-            }
-            return false;
+            return target.isExisting(keyExpression);
         }
 
         @Override
         public MutableConfiguration put(String key, String value) {
-            for(MutableConfigurationBackendSpi req:targets){
-                if(req.isWritable(key)){
-                    req.put(key, value);
-                }
+            if(target.isWritable(key)){
+                target.put(key, value);
             }
-            return super.put(key, value);
+            return this;
         }
 
         @Override
         public MutableConfiguration putAll(Map<String, String> properties) {
-            for(MutableConfigurationBackendSpi req:targets){
-                for(Map.Entry<String,String> en:properties.entrySet()) {
-                    if (req.isWritable(en.getKey())) {
-                        req.put(en.getKey(), en.getValue());
-                    }
+            for(Map.Entry<String,String> en:properties.entrySet()) {
+                if (target.isWritable(en.getKey())) {
+                    target.put(en.getKey(), en.getValue());
                 }
             }
             return super.putAll(properties);
@@ -230,11 +265,9 @@ public final class MutableConfigurationQuery implements ConfigQuery<MutableConfi
 
         @Override
         public MutableConfiguration remove(String... keys) {
-            for(MutableConfigurationBackendSpi req:targets){
-                for(String key:keys){
-                    if (req.isRemovable(key)) {
-                        req.remove(key);
-                    }
+            for(String key:keys){
+                if (target.isRemovable(key)) {
+                    target.remove(key);
                 }
             }
             return super.remove(keys);
@@ -242,11 +275,9 @@ public final class MutableConfigurationQuery implements ConfigQuery<MutableConfi
 
         @Override
         public MutableConfiguration remove(Collection<String> keys) {
-            for(MutableConfigurationBackendSpi req:targets){
-                for(String key:keys){
-                    if (req.isRemovable(key)) {
-                        req.remove(key);
-                    }
+            for(String key:keys){
+                if (target.isRemovable(key)) {
+                    target.remove(key);
                 }
             }
             return super.remove(keys);
@@ -254,9 +285,7 @@ public final class MutableConfigurationQuery implements ConfigQuery<MutableConfi
 
         @Override
         protected void commitInternal() {
-            for(MutableConfigurationBackendSpi req:targets){
-                req.commit();
-            }
+            target.commit();
         }
 
         @Override
@@ -268,14 +297,25 @@ public final class MutableConfigurationQuery implements ConfigQuery<MutableConfi
                     if(removed){
                         return null;
                     }
-                    return addedOrUpdated!=null?addedOrUpdated:this.config.get(key);
+                    return addedOrUpdated!=null?addedOrUpdated:getInternal(key);
                 case CONFIG:
                 default:
-                    String val = this.config.get(key);
+                    String val = getInternal(key);
                     return val == null?addedOrUpdated:val;
             }
         }
 
+        private String getInternal(String key) {
+           Map<String,String> props = this.config.getProperties();
+            if(props.isEmpty()){
+                PropertyValue val = this.target.getBackendPropertySource().get(key);
+                if(val!=null){
+                    return val.getValue();
+                }
+            }
+            return this.config.get(key);
+        }
+
         @Override
         public String getOrDefault(String key, String defaultValue) {
             String val = get(key);
@@ -301,7 +341,7 @@ public final class MutableConfigurationQuery implements ConfigQuery<MutableConfi
         public <T> T getOrDefault(String key, TypeLiteral<T> type, T defaultValue) {
             String val = get(key);
             if(val==null) {
-                return config.getOrDefault(key, type, defaultValue);
+                return defaultValue;
             }
             for(PropertyConverter conv: ConfigurationProvider.getConfigurationContext().getPropertyConverters(type)){
                 Object o = conv.convert(val, new ConversionContext.Builder(key, type).setConfiguration(config).build());
@@ -314,7 +354,12 @@ public final class MutableConfigurationQuery implements ConfigQuery<MutableConfi
 
         @Override
         public Map<String, String> getProperties() {
-            Map<String, String> configProps = new HashMap<>(config.getProperties());
+            Map<String, String> configProps = new HashMap<>();
+            if(config.getProperties().isEmpty()) {
+                configProps.putAll(target.getBackendPropertySource().getProperties());
+            }else{
+                configProps.putAll(config.getProperties());
+            }
             switch(valueVisibilityPolicy){
                 case CHANGES:
                     for(String key:removedProperties){
@@ -350,7 +395,7 @@ public final class MutableConfigurationQuery implements ConfigQuery<MutableConfi
         public String toString() {
             return "DefaultMutableConfiguration{" +
                     "config=" + config +
-                    ", targets=" + targets +
+                    ", target=" + target +
                     '}';
         }
     }

http://git-wip-us.apache.org/repos/asf/incubator-tamaya/blob/51260b63/modules/mutable-config/src/main/java/org/apache/tamaya/mutableconfig/internal/BasePropertySource.java
----------------------------------------------------------------------
diff --git a/modules/mutable-config/src/main/java/org/apache/tamaya/mutableconfig/internal/BasePropertySource.java b/modules/mutable-config/src/main/java/org/apache/tamaya/mutableconfig/internal/BasePropertySource.java
index e3d65f9..2fe87df 100644
--- a/modules/mutable-config/src/main/java/org/apache/tamaya/mutableconfig/internal/BasePropertySource.java
+++ b/modules/mutable-config/src/main/java/org/apache/tamaya/mutableconfig/internal/BasePropertySource.java
@@ -30,7 +30,7 @@ import java.util.logging.Logger;
  * Abstract {@link PropertySource} that allows to set a default ordinal that will be used, if no
  * ordinal is provided with the config.
  */
-public abstract class BasePropertySource implements PropertySource{
+abstract class BasePropertySource implements PropertySource{
     /** default ordinal that will be used, if no ordinal is provided with the config. */
     private final int defaultOrdinal;
 

http://git-wip-us.apache.org/repos/asf/incubator-tamaya/blob/51260b63/modules/mutable-config/src/main/java/org/apache/tamaya/mutableconfig/internal/PropertiesFileConfigBackendSpi.java
----------------------------------------------------------------------
diff --git a/modules/mutable-config/src/main/java/org/apache/tamaya/mutableconfig/internal/PropertiesFileConfigBackendSpi.java b/modules/mutable-config/src/main/java/org/apache/tamaya/mutableconfig/internal/PropertiesFileConfigBackendSpi.java
index 15a68cb..39bd0cf 100644
--- a/modules/mutable-config/src/main/java/org/apache/tamaya/mutableconfig/internal/PropertiesFileConfigBackendSpi.java
+++ b/modules/mutable-config/src/main/java/org/apache/tamaya/mutableconfig/internal/PropertiesFileConfigBackendSpi.java
@@ -19,7 +19,7 @@
 package org.apache.tamaya.mutableconfig.internal;
 
 import org.apache.tamaya.ConfigException;
-import org.apache.tamaya.mutableconfig.spi.AbstractMutableConfigurationBackendSpiSpi;
+import org.apache.tamaya.mutableconfig.spi.AbstractMutableConfigurationBackendSpi;
 
 import java.io.BufferedOutputStream;
 import java.io.File;
@@ -35,7 +35,7 @@ import java.util.logging.Logger;
 /**
  * Change Request implementation based on .properties file.
  */
-class PropertiesFileConfigBackendSpi extends AbstractMutableConfigurationBackendSpiSpi {
+class PropertiesFileConfigBackendSpi extends AbstractMutableConfigurationBackendSpi {
 
     private static final Logger LOG = Logger.getLogger(PropertiesFileConfigBackendSpi.class.getName());
 
@@ -49,7 +49,7 @@ class PropertiesFileConfigBackendSpi extends AbstractMutableConfigurationBackend
      * @param file the file
      */
     PropertiesFileConfigBackendSpi(File file){
-        super(file.toURI());
+        super(file.toURI(), new SimplePropertySource(file));
         this.file = file;
         if(file.exists()) {
             try (InputStream is = getBackendURI().toURL().openStream()) {

http://git-wip-us.apache.org/repos/asf/incubator-tamaya/blob/51260b63/modules/mutable-config/src/main/java/org/apache/tamaya/mutableconfig/internal/SimplePropertySource.java
----------------------------------------------------------------------
diff --git a/modules/mutable-config/src/main/java/org/apache/tamaya/mutableconfig/internal/SimplePropertySource.java b/modules/mutable-config/src/main/java/org/apache/tamaya/mutableconfig/internal/SimplePropertySource.java
index 1e2ab52..68b6745 100644
--- a/modules/mutable-config/src/main/java/org/apache/tamaya/mutableconfig/internal/SimplePropertySource.java
+++ b/modules/mutable-config/src/main/java/org/apache/tamaya/mutableconfig/internal/SimplePropertySource.java
@@ -18,25 +18,48 @@
  */
 package org.apache.tamaya.mutableconfig.internal;
 
-import org.apache.tamaya.ConfigException;
-
 import java.io.File;
 import java.io.IOException;
 import java.io.InputStream;
+import java.net.MalformedURLException;
 import java.net.URL;
-import java.util.HashMap;
-import java.util.Map;
-import java.util.Objects;
-import java.util.Properties;
+import java.util.*;
+import java.util.logging.Level;
+import java.util.logging.Logger;
 
 /**
  * Simple implementation of a {@link org.apache.tamaya.spi.PropertySource} for properties-files.
  */
-public class SimplePropertySource extends BasePropertySource {
+class SimplePropertySource extends BasePropertySource {
+
+    /**
+     * The logger.
+     */
+    private static final Logger LOG = Logger.getLogger(SimplePropertySource.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 URL resource;
+
+    /**
+     * 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.
      */
@@ -49,11 +72,12 @@ public class SimplePropertySource extends BasePropertySource {
      */
     public SimplePropertySource(File propertiesLocation) {
         super(0);
+        this.name = propertiesLocation.toString();
         try {
-            this.properties = load(propertiesLocation.toURI().toURL());
-            this.name = propertiesLocation.toString();
-        } catch (IOException e) {
-            throw new ConfigException("Failed to load properties from " + propertiesLocation, e);
+            this.resource = propertiesLocation.toURI().toURL();
+            load();
+        } catch (MalformedURLException e) {
+            LOG.log(Level.SEVERE, "Cannot convert file to URL: " + propertiesLocation, e);
         }
     }
 
@@ -64,8 +88,9 @@ public class SimplePropertySource extends BasePropertySource {
      */
     public SimplePropertySource(URL propertiesLocation) {
         super(0);
-        this.properties = load(propertiesLocation);
-        this.name = propertiesLocation.toExternalForm();
+        this.name = propertiesLocation.toString();
+        this.resource = propertiesLocation;
+        load();
     }
 
     /**
@@ -76,8 +101,8 @@ public class SimplePropertySource extends BasePropertySource {
      */
     public SimplePropertySource(String name, Map<String, String> properties) {
         super(0);
-        this.properties = new HashMap<>(properties);
         this.name = Objects.requireNonNull(name);
+        this.properties = new HashMap<>(properties);
     }
 
     /**
@@ -88,8 +113,9 @@ public class SimplePropertySource extends BasePropertySource {
      */
     public SimplePropertySource(String name, URL propertiesLocation) {
         super(0);
-        this.properties = load(propertiesLocation);
         this.name = Objects.requireNonNull(name);
+        this.resource = propertiesLocation;
+        load();
     }
 
     @Override
@@ -99,19 +125,25 @@ public class SimplePropertySource extends BasePropertySource {
 
     @Override
     public Map<String, String> getProperties() {
+        checkLoad();
         return this.properties;
     }
 
+    private void checkLoad() {
+        if(resource!=null && (lastRead+updateInterval)<System.currentTimeMillis()){
+            load();
+        }
+    }
+
     /**
      * loads the Properties from the given URL
      *
-     * @param propertiesFile {@link URL} to load Properties from
      * @return loaded {@link Properties}
      * @throws IllegalStateException in case of an error while reading properties-file
      */
-    private Map<String, String> load(URL propertiesFile) {
+    private void load() {
         Map<String, String> properties = new HashMap<>();
-        try (InputStream stream = propertiesFile.openStream()) {
+        try (InputStream stream = resource.openStream()) {
             Properties props = new Properties();
             if (stream != null) {
                 props.load(stream);
@@ -119,10 +151,13 @@ public class SimplePropertySource extends BasePropertySource {
             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 " + resource);
         } catch (IOException e) {
-            throw new ConfigException("Error loading properties " + propertiesFile, e);
+            LOG.log(Level.FINEST, "Cannot load properties from " + resource, e);
+            this.properties = Collections.emptyMap();
         }
-        return properties;
     }
 
 }

http://git-wip-us.apache.org/repos/asf/incubator-tamaya/blob/51260b63/modules/mutable-config/src/main/java/org/apache/tamaya/mutableconfig/internal/XmlPropertiesFileConfigBackendSpi.java
----------------------------------------------------------------------
diff --git a/modules/mutable-config/src/main/java/org/apache/tamaya/mutableconfig/internal/XmlPropertiesFileConfigBackendSpi.java b/modules/mutable-config/src/main/java/org/apache/tamaya/mutableconfig/internal/XmlPropertiesFileConfigBackendSpi.java
index cdca80d..68f7e8f 100644
--- a/modules/mutable-config/src/main/java/org/apache/tamaya/mutableconfig/internal/XmlPropertiesFileConfigBackendSpi.java
+++ b/modules/mutable-config/src/main/java/org/apache/tamaya/mutableconfig/internal/XmlPropertiesFileConfigBackendSpi.java
@@ -19,7 +19,7 @@
 package org.apache.tamaya.mutableconfig.internal;
 
 import org.apache.tamaya.ConfigException;
-import org.apache.tamaya.mutableconfig.spi.AbstractMutableConfigurationBackendSpiSpi;
+import org.apache.tamaya.mutableconfig.spi.AbstractMutableConfigurationBackendSpi;
 
 import java.io.BufferedOutputStream;
 import java.io.File;
@@ -35,7 +35,7 @@ import java.util.logging.Logger;
 /**
  * Change Request implementation based on .xml properties file.
  */
-class XmlPropertiesFileConfigBackendSpi extends AbstractMutableConfigurationBackendSpiSpi {
+class XmlPropertiesFileConfigBackendSpi extends AbstractMutableConfigurationBackendSpi {
 
     private static final Logger LOG = Logger.getLogger(XmlPropertiesFileConfigBackendSpi.class.getName());
 
@@ -49,7 +49,7 @@ class XmlPropertiesFileConfigBackendSpi extends AbstractMutableConfigurationBack
      * @param file the file
      */
     XmlPropertiesFileConfigBackendSpi(File file){
-        super(file.toURI());
+        super(file.toURI(), new SimplePropertySource(file));
         this.file = file;
         if(file.exists()) {
             try (InputStream is = getBackendURI().toURL().openStream()) {

http://git-wip-us.apache.org/repos/asf/incubator-tamaya/blob/51260b63/modules/mutable-config/src/main/java/org/apache/tamaya/mutableconfig/spi/AbstractMutableConfigurationBackendSpi.java
----------------------------------------------------------------------
diff --git a/modules/mutable-config/src/main/java/org/apache/tamaya/mutableconfig/spi/AbstractMutableConfigurationBackendSpi.java b/modules/mutable-config/src/main/java/org/apache/tamaya/mutableconfig/spi/AbstractMutableConfigurationBackendSpi.java
index 867f346..d529847 100644
--- a/modules/mutable-config/src/main/java/org/apache/tamaya/mutableconfig/spi/AbstractMutableConfigurationBackendSpi.java
+++ b/modules/mutable-config/src/main/java/org/apache/tamaya/mutableconfig/spi/AbstractMutableConfigurationBackendSpi.java
@@ -18,6 +18,8 @@
  */
 package org.apache.tamaya.mutableconfig.spi;
 
+import org.apache.tamaya.spi.PropertySource;
+
 import java.net.URI;
 import java.util.*;
 
@@ -26,27 +28,47 @@ import java.util.*;
  */
 public abstract class AbstractMutableConfigurationBackendSpi implements MutableConfigurationBackendSpi {
 
+    /** The URI identifying the current backend. */
     private final URI backendURI;
 
     /**
-     * The Properties.
+     * The property source containing the current backend property data.
+     */
+    private PropertySource backendPropertySource;
+
+    /**
+     * The added or changed properties (uncommitted)..
      */
     protected final Map<String,String> addedProperties = new HashMap<>();
     /**
-     * The Removed.
+     * The removed properties (uncommitted).
      */
     protected final Set<String> removedProperties = new HashSet<>();
 
+    /**
+     * Get the uncommitted removed properties.
+     * @return the uncommitted removed properties, never null.
+     */
     protected Set<String> getRemovedProperties() {
         return removedProperties;
     }
 
+    /**
+     * Get the uncommitted properties added or updated so far.
+     * @return the uncommitted properties added or updated, never null.
+     */
     protected Map<String,String> getAddedProperties() {
         return addedProperties;
     }
 
-    protected AbstractMutableConfigurationBackendSpi(URI backendURI){
+    /**
+     * Creates a new instance.
+     * @param backendURI the backend URI, not null.
+     * @param backendPropertySource the backend property source, not null.
+     */
+    protected AbstractMutableConfigurationBackendSpi(URI backendURI, PropertySource backendPropertySource){
         this.backendURI = Objects.requireNonNull(backendURI);
+        this.backendPropertySource = Objects.requireNonNull(backendPropertySource);
     }
 
     @Override
@@ -55,6 +77,11 @@ public abstract class AbstractMutableConfigurationBackendSpi implements MutableC
     }
 
     @Override
+    public PropertySource getBackendPropertySource(){
+        return backendPropertySource;
+    }
+
+    @Override
     public boolean isWritable(String keyExpression) {
         return true;
     }

http://git-wip-us.apache.org/repos/asf/incubator-tamaya/blob/51260b63/modules/mutable-config/src/main/java/org/apache/tamaya/mutableconfig/spi/MutableConfigurationBackendSpi.java
----------------------------------------------------------------------
diff --git a/modules/mutable-config/src/main/java/org/apache/tamaya/mutableconfig/spi/MutableConfigurationBackendSpi.java b/modules/mutable-config/src/main/java/org/apache/tamaya/mutableconfig/spi/MutableConfigurationBackendSpi.java
index 1541f26..7f93c7d 100644
--- a/modules/mutable-config/src/main/java/org/apache/tamaya/mutableconfig/spi/MutableConfigurationBackendSpi.java
+++ b/modules/mutable-config/src/main/java/org/apache/tamaya/mutableconfig/spi/MutableConfigurationBackendSpi.java
@@ -18,6 +18,9 @@
  */
 package org.apache.tamaya.mutableconfig.spi;
 
+import org.apache.tamaya.spi.PropertySource;
+import org.apache.tamaya.spi.PropertyValue;
+
 import java.net.URI;
 import java.util.Collection;
 import java.util.Map;
@@ -79,6 +82,14 @@ public interface MutableConfigurationBackendSpi {
      */
     void put(String key, String value);
 
+
+    /**
+     * Access a {@link org.apache.tamaya.spi.PropertySource} for reading any properties from the write target.
+     * @return the {@link org.apache.tamaya.spi.PropertySource} never {@code null}. In case of a write only
+     * data sink, simply return PropertySource.EMPTY.
+     */
+    PropertySource getBackendPropertySource();
+
     /**
      * 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

http://git-wip-us.apache.org/repos/asf/incubator-tamaya/blob/51260b63/modules/mutable-config/src/test/java/org/apache/tamaya/mutableconfig/MutableConfigurationQueryTest.java
----------------------------------------------------------------------
diff --git a/modules/mutable-config/src/test/java/org/apache/tamaya/mutableconfig/MutableConfigurationQueryTest.java b/modules/mutable-config/src/test/java/org/apache/tamaya/mutableconfig/MutableConfigurationQueryTest.java
index 6ab394d..f50a85e 100644
--- a/modules/mutable-config/src/test/java/org/apache/tamaya/mutableconfig/MutableConfigurationQueryTest.java
+++ b/modules/mutable-config/src/test/java/org/apache/tamaya/mutableconfig/MutableConfigurationQueryTest.java
@@ -68,7 +68,7 @@ public class MutableConfigurationQueryTest {
     @Test(expected=NullPointerException.class)
     public void testNullCreateChangeRequest1() throws Exception {
         MutableConfiguration req = ConfigurationProvider.getConfiguration().query(
-                MutableConfigurationQuery.of((URI[])null));
+                MutableConfigurationQuery.of((URI)null));
     }
 
     /**
@@ -79,6 +79,6 @@ public class MutableConfigurationQueryTest {
     @Test(expected=NullPointerException.class)
     public void testNullCreateChangeRequest2() throws Exception {
         MutableConfiguration req = ConfigurationProvider.getConfiguration().query(
-                MutableConfigurationQuery.of((String[])null));
+                MutableConfigurationQuery.of((String)null));
     }
 }
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/incubator-tamaya/blob/51260b63/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
index 78a6379..9a3e130 100644
--- 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
@@ -122,41 +122,4 @@ public class PropertiesFileConfigBackendTest {
         assertEquals("value4", props.getProperty("key4"));
     }
 
-    @Test
-    public void testReadWrite_Compound() throws IOException {
-        File f1 = File.createTempFile("testReadWrite_Compound",".xml");
-        f1.delete();
-        File f2 = File.createTempFile("testReadWrite_Compound",".properties");
-        f2.delete();
-        MutableConfiguration req = ConfigurationProvider.getConfiguration().query(
-                MutableConfigurationQuery.of(f1.toURI(), f2.toURI()));
-        req.put("key1", "value1");
-        Map<String,String> cm = new HashMap<>();
-        cm.put("key2", "value2");
-        cm.put("key3", "value3");
-        req.putAll(cm);
-        req.commit();
-        assertTrue(f1.exists());
-        assertTrue(f2.exists());
-        MutableConfiguration req2 = ConfigurationProvider.getConfiguration().query(
-                MutableConfigurationQuery.of(f1.toURI(), f2.toURI()));
-        assertTrue(req != req2);
-        req2.remove("foo");
-        req2.remove("key3");
-        req2.put("key1", "value1.2");
-        req2.put("key4", "value4");
-        req2.commit();
-        Properties props = new Properties();
-        props.load(f2.toURL().openStream());
-        assertEquals(3, props.size());
-        assertEquals("value1.2", props.getProperty("key1"));
-        assertEquals("value2", props.getProperty("key2"));
-        assertEquals("value4", props.getProperty("key4"));
-        props = new Properties();
-        props.loadFromXML(f1.toURL().openStream());
-        assertEquals(3, props.size());
-        assertEquals("value1.2", props.getProperty("key1"));
-        assertEquals("value2", props.getProperty("key2"));
-        assertEquals("value4", props.getProperty("key4"));
-    }
 }
\ No newline at end of file