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:36 UTC

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

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

http://git-wip-us.apache.org/repos/asf/incubator-tamaya-extensions/blob/3aca9112/modules/mutable-config/src/test/resources/META-INF/services/org.apache.tamaya.spi.PropertySource
----------------------------------------------------------------------
diff --git a/modules/mutable-config/src/test/resources/META-INF/services/org.apache.tamaya.spi.PropertySource b/modules/mutable-config/src/test/resources/META-INF/services/org.apache.tamaya.spi.PropertySource
new file mode 100644
index 0000000..609b9fe
--- /dev/null
+++ b/modules/mutable-config/src/test/resources/META-INF/services/org.apache.tamaya.spi.PropertySource
@@ -0,0 +1,20 @@
+#
+# 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.WritablePropertiesSource
+org.apache.tamaya.mutableconfig.internal.WritableXmlPropertiesSource

http://git-wip-us.apache.org/repos/asf/incubator-tamaya-extensions/blob/3aca9112/modules/spi-support/pom.xml
----------------------------------------------------------------------
diff --git a/modules/spi-support/pom.xml b/modules/spi-support/pom.xml
index c324481..edc8df3 100644
--- a/modules/spi-support/pom.xml
+++ b/modules/spi-support/pom.xml
@@ -23,7 +23,7 @@ under the License.
 
     <parent>
         <groupId>org.apache.tamaya.ext</groupId>
-        <artifactId>tamaya-extensions</artifactId>
+        <artifactId>tamaya-extensions-all</artifactId>
         <version>0.3-incubating-SNAPSHOT</version>
         <relativePath>..</relativePath>
     </parent>
@@ -56,6 +56,10 @@ under the License.
             <groupId>junit</groupId>
             <artifactId>junit</artifactId>
         </dependency>
+        <dependency>
+            <groupId>org.hamcrest</groupId>
+            <artifactId>java-hamcrest</artifactId>
+        </dependency>
     </dependencies>
 
     <build>

http://git-wip-us.apache.org/repos/asf/incubator-tamaya-extensions/blob/3aca9112/modules/spi-support/src/main/java/org/apache/tamaya/spisupport/CLIPropertySource.java
----------------------------------------------------------------------
diff --git a/modules/spi-support/src/main/java/org/apache/tamaya/spisupport/CLIPropertySource.java b/modules/spi-support/src/main/java/org/apache/tamaya/spisupport/CLIPropertySource.java
new file mode 100644
index 0000000..ec0a532
--- /dev/null
+++ b/modules/spi-support/src/main/java/org/apache/tamaya/spisupport/CLIPropertySource.java
@@ -0,0 +1,101 @@
+/*
+ * 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.spisupport;
+
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.Map;
+import java.util.Objects;
+
+/**
+ * PropertySource that allows to add the programs main arguments as configuration entries. Unix syntax using '--' and
+ * '-' params is supported.
+ */
+public class CLIPropertySource extends BasePropertySource{
+
+    /** The original main arguments. */
+    private static String[] args = new String[0];
+
+    /** The map of parsed main arguments. */
+    private static Map<String,String> mainArgs;
+
+    /** Initializes the initial state. */
+    static{
+        initMainArgs(args);
+    }
+
+
+    /**
+     * Creates a new instance.
+     */
+    public CLIPropertySource(){}
+
+    /**
+     * Configure the main arguments, hereby parsing and mapping the main arguments into
+     * configuration propertiesi as key-value pairs.
+     * @param args the main arguments, not null.
+     */
+    public static void initMainArgs(String... args){
+        CLIPropertySource.args = Objects.requireNonNull(args);
+        // TODO is there a way to figure out the args?
+        String argsProp = System.getProperty("main.args");
+        if(argsProp!=null){
+            CLIPropertySource.args = argsProp.split("\\s");
+        }
+        Map<String,String> result = null;
+        if(CLIPropertySource.args==null){
+            result = Collections.emptyMap();
+        }else{
+            result = new HashMap<>();
+            String prefix = System.getProperty("main.args.prefix");
+            if(prefix==null){
+                prefix="";
+            }
+            String key = null;
+            for(String arg:CLIPropertySource.args){
+                if(arg.startsWith("--")){
+                    arg = arg.substring(2);
+                    int index = arg.indexOf("=");
+                    if(index>0){
+                        key = arg.substring(0,index).trim();
+                        result.put(prefix+key, arg.substring(index+1).trim());
+                        key = null;
+                    }else{
+                        result.put(prefix+arg, arg);
+                    }
+                }else if(arg.startsWith("-")){
+                    key = arg.substring(1);
+                }else{
+                    if(key!=null){
+                        result.put(prefix+key, arg);
+                        key = null;
+                    }else{
+                        result.put(prefix+arg, arg);
+                    }
+                }
+            }
+        }
+        CLIPropertySource.mainArgs = Collections.unmodifiableMap(result);
+    }
+
+    @Override
+    public Map<String, String> getProperties() {
+        return Collections.unmodifiableMap(mainArgs);
+    }
+}

http://git-wip-us.apache.org/repos/asf/incubator-tamaya-extensions/blob/3aca9112/modules/spi-support/src/main/java/org/apache/tamaya/spisupport/DefaultConfiguration.java
----------------------------------------------------------------------
diff --git a/modules/spi-support/src/main/java/org/apache/tamaya/spisupport/DefaultConfiguration.java b/modules/spi-support/src/main/java/org/apache/tamaya/spisupport/DefaultConfiguration.java
index 52a0d11..56c6e3d 100644
--- a/modules/spi-support/src/main/java/org/apache/tamaya/spisupport/DefaultConfiguration.java
+++ b/modules/spi-support/src/main/java/org/apache/tamaya/spisupport/DefaultConfiguration.java
@@ -75,7 +75,7 @@ public class DefaultConfiguration implements Configuration {
         if(configData==null){
             return null;
         }
-        return PropertyFiltering.applyFilter(key, configData.getConfigEntries(), configurationContext);
+        return PropertyFilterManager.applyFilter(key, configData.getConfigEntries(), configurationContext);
     }
 
     /**
@@ -124,7 +124,7 @@ public class DefaultConfiguration implements Configuration {
      */
     @Override
     public Map<String, String> getProperties() {
-        return PropertyFiltering.applyFilters(evaluateUnfilteredMap(), configurationContext);
+        return PropertyFilterManager.applyFilters(evaluateUnfilteredMap(), configurationContext);
     }
 
     /**

http://git-wip-us.apache.org/repos/asf/incubator-tamaya-extensions/blob/3aca9112/modules/spi-support/src/main/java/org/apache/tamaya/spisupport/DefaultConfigurationContext.java
----------------------------------------------------------------------
diff --git a/modules/spi-support/src/main/java/org/apache/tamaya/spisupport/DefaultConfigurationContext.java b/modules/spi-support/src/main/java/org/apache/tamaya/spisupport/DefaultConfigurationContext.java
index 76f254b..fca6527 100644
--- a/modules/spi-support/src/main/java/org/apache/tamaya/spisupport/DefaultConfigurationContext.java
+++ b/modules/spi-support/src/main/java/org/apache/tamaya/spisupport/DefaultConfigurationContext.java
@@ -1,41 +1,36 @@
 /*
  * 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
+ *  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
+ *     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.
+ *  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.spisupport;
 
-import org.apache.tamaya.ConfigurationProvider;
 import org.apache.tamaya.TypeLiteral;
 import org.apache.tamaya.spi.ConfigurationContext;
 import org.apache.tamaya.spi.ConfigurationContextBuilder;
 import org.apache.tamaya.spi.PropertyConverter;
 import org.apache.tamaya.spi.PropertyFilter;
 import org.apache.tamaya.spi.PropertySource;
-import org.apache.tamaya.spi.PropertySourceProvider;
 import org.apache.tamaya.spi.PropertyValueCombinationPolicy;
 import org.apache.tamaya.spi.ServiceContextManager;
 
-import javax.annotation.Priority;
-import java.io.Serializable;
 import java.util.ArrayList;
 import java.util.Arrays;
 import java.util.Collection;
 import java.util.Collections;
-import java.util.Comparator;
 import java.util.List;
 import java.util.Map;
 import java.util.concurrent.locks.Lock;
@@ -73,70 +68,54 @@ public class DefaultConfigurationContext implements ConfigurationContext {
      * Lock for internal synchronization.
      */
     private final ReentrantReadWriteLock propertySourceLock = new ReentrantReadWriteLock();
-
-    /** Comparator used for ordering property sources. */
-    private final PropertySourceComparator propertySourceComparator = new PropertySourceComparator();
-
-    /** Comparator used for ordering property filters. */
-    private final PropertyFilterComparator propertyFilterComparator = new PropertyFilterComparator();
-
+    /**
+     * Lock for internal synchronization.
+     */
+    private final ReentrantReadWriteLock propertyFilterLock = new ReentrantReadWriteLock();
 
     /**
-     * The first time the Configuration system gets invoked we do initialize
-     * all our {@link PropertySource}s and
-     * {@link PropertyFilter}s which are known at startup.
+     * Creates an empty Configuration context.
      */
-    public DefaultConfigurationContext() {
-        List<PropertySource> propertySources = new ArrayList<>();
+    protected DefaultConfigurationContext() {
+        this(new DefaultConfigurationContextBuilder());
+    }
 
+    DefaultConfigurationContext(DefaultConfigurationContextBuilder builder) {
+        List<PropertySource> propertySources = new ArrayList<>();
         // first we load all PropertySources which got registered via java.util.ServiceLoader
-        propertySources.addAll(ServiceContextManager.getServiceContext().getServices(PropertySource.class));
-
-        // after that we add all PropertySources which get dynamically registered via their PropertySourceProviders
-        propertySources.addAll(evaluatePropertySourcesFromProviders());
-
+        propertySources.addAll(builder.propertySources);
         // now sort them according to their ordinal values
-        Collections.sort(propertySources, new PropertySourceComparator());
-
         immutablePropertySources = Collections.unmodifiableList(propertySources);
         LOG.info("Registered " + immutablePropertySources.size() + " property sources: " +
                 immutablePropertySources);
 
         // as next step we pick up the PropertyFilters pretty much the same way
-        List<PropertyFilter> propertyFilters = new ArrayList<>();
-        propertyFilters.addAll(ServiceContextManager.getServiceContext().getServices(PropertyFilter.class));
-        Collections.sort(propertyFilters, new PropertyFilterComparator());
+        List<PropertyFilter> propertyFilters = new ArrayList<>(builder.getPropertyFilters());
         immutablePropertyFilters = Collections.unmodifiableList(propertyFilters);
         LOG.info("Registered " + immutablePropertyFilters.size() + " property filters: " +
                 immutablePropertyFilters);
 
-        immutablePropertyFilters = Collections.unmodifiableList(propertyFilters);
-        LOG.info("Registered " + immutablePropertyFilters.size() + " property filters: " +
-                immutablePropertyFilters);
-        propertyValueCombinationPolicy = ServiceContextManager.getServiceContext().getService(PropertyValueCombinationPolicy.class);
-        if(propertyValueCombinationPolicy==null) {
+        // Finally add the converters
+        for(Map.Entry<TypeLiteral<?>, Collection<PropertyConverter<?>>> en:builder.getPropertyConverter().entrySet()) {
+            for (PropertyConverter converter : en.getValue()) {
+                this.propertyConverterManager.register(en.getKey(), converter);
+            }
+        }
+        LOG.info("Registered " + propertyConverterManager.getPropertyConverters().size() + " property converters: " +
+                propertyConverterManager.getPropertyConverters());
+
+        propertyValueCombinationPolicy = builder.combinationPolicy;
+        if(propertyValueCombinationPolicy==null){
+            propertyValueCombinationPolicy = ServiceContextManager.getServiceContext().getService(PropertyValueCombinationPolicy.class);
+        }
+        if(propertyValueCombinationPolicy==null){
             propertyValueCombinationPolicy = PropertyValueCombinationPolicy.DEFAULT_OVERRIDING_COLLECTOR;
         }
         LOG.info("Using PropertyValueCombinationPolicy: " + propertyValueCombinationPolicy);
     }
 
-    /**
-     * Pick up all {@link PropertySourceProvider}s and return all the
-     * {@link PropertySource}s they like to register.
-     */
-    private Collection<? extends PropertySource> evaluatePropertySourcesFromProviders() {
-        List<PropertySource> propertySources = new ArrayList<>();
-        Collection<PropertySourceProvider> propertySourceProviders = ServiceContextManager.getServiceContext().getServices(PropertySourceProvider.class);
-        for (PropertySourceProvider propertySourceProvider : propertySourceProviders) {
-            Collection<PropertySource> sources = propertySourceProvider.getPropertySources();
-            LOG.finer("PropertySourceProvider " + propertySourceProvider.getClass().getName() +
-                    " provided the following property sources: " + sources);
-                propertySources.addAll(sources);
-        }
-
-        return propertySources;
-    }
 
+    @Deprecated
     @Override
     public void addPropertySources(PropertySource... propertySourcesToAdd) {
         Lock writeLock = propertySourceLock.writeLock();
@@ -152,77 +131,119 @@ public class DefaultConfigurationContext implements ConfigurationContext {
         }
     }
 
-    /**
-     * Comparator used for comparing PropertySources.
-     */
-    private static class PropertySourceComparator implements Comparator<PropertySource>, Serializable {
-
-        private static final long serialVersionUID = 1L;
-
-        /**
-         * Order property source reversely, the most important come first.
-         *
-         * @param source1 the first PropertySource
-         * @param source2 the second PropertySource
-         * @return the comparison result.
-         */
-        private int comparePropertySources(PropertySource source1, PropertySource source2) {
-            if (source1.getOrdinal() < source2.getOrdinal()) {
-                return -1;
-            } else if (source1.getOrdinal() > source2.getOrdinal()) {
-                return 1;
-            } else {
-                return source1.getClass().getName().compareTo(source2.getClass().getName());
-            }
+    @Override
+    public boolean equals(Object o) {
+        if (this == o) {
+            return true;
+        }
+        if (!(o instanceof DefaultConfigurationContext)){
+            return false;
         }
 
-        @Override
-        public int compare(PropertySource source1, PropertySource source2) {
-            return comparePropertySources(source1, source2);
+        DefaultConfigurationContext that = (DefaultConfigurationContext) o;
+
+        if (!propertyConverterManager.equals(that.propertyConverterManager)) {
+            return false;
+        }
+        if (!immutablePropertySources.equals(that.immutablePropertySources)) {
+            return false;
+        }
+        if (!immutablePropertyFilters.equals(that.immutablePropertyFilters)) {
+            return false;
         }
+        return getPropertyValueCombinationPolicy().equals(that.getPropertyValueCombinationPolicy());
+
     }
 
-    /**
-     * Comparator used for comparing PropertyFilters.
-     */
-    private static class PropertyFilterComparator implements Comparator<PropertyFilter>, Serializable{
-
-        private static final long serialVersionUID = 1L;
-
-        /**
-         * Compare 2 filters for ordering the filter chain.
-         *
-         * @param filter1 the first filter
-         * @param filter2 the second filter
-         * @return the comparison result
-         */
-        private int comparePropertyFilters(PropertyFilter filter1, PropertyFilter filter2) {
-            Priority prio1 = filter1.getClass().getAnnotation(Priority.class);
-            Priority prio2 = filter2.getClass().getAnnotation(Priority.class);
-            int ord1 = prio1 != null ? prio1.value() : 0;
-            int ord2 = prio2 != null ? prio2.value() : 0;
-
-            if (ord1 < ord2) {
-                return -1;
-            } else if (ord1 > ord2) {
-                return 1;
-            } else {
-                return filter1.getClass().getName().compareTo(filter2.getClass().getName());
+    @Override
+    public int hashCode() {
+        int result = propertyConverterManager.hashCode();
+        result = 31 * result + immutablePropertySources.hashCode();
+        result = 31 * result + immutablePropertyFilters.hashCode();
+        result = 31 * result + getPropertyValueCombinationPolicy().hashCode();
+        return result;
+    }
+
+    @Override
+    public String toString() {
+        StringBuilder b = new StringBuilder("ConfigurationContext{\n");
+        b.append("  Property Sources\n");
+        b.append("  ----------------\n");
+        b.append("  CLASS                         NAME                                                                  ORDINAL SCANNABLE SIZE\n");
+        for(PropertySource ps:getPropertySources()){
+            b.append("  ");
+            appendFormatted(b, ps.getClass().getSimpleName(), 30);
+            appendFormatted(b, ps.getName(), 70);
+            appendFormatted(b, String.valueOf(ps.getOrdinal()), 8);
+            appendFormatted(b, String.valueOf(ps.isScannable()), 10);
+            if(ps.isScannable()) {
+                appendFormatted(b, String.valueOf(ps.getProperties().size()), 8);
+            }else{
+                appendFormatted(b, "-", 8);
+            }
+            b.append('\n');
+        }
+        b.append("\n");
+        b.append("  Property Filters\n");
+        b.append("  ----------------\n");
+        b.append("  CLASS                         INFO\n");
+        for(PropertyFilter filter:getPropertyFilters()){
+            b.append("  ");
+            appendFormatted(b, filter.getClass().getSimpleName(), 30);
+            b.append(removeNewLines(filter.toString()));
+            b.append('\n');
+        }
+        b.append("\n\n");
+        b.append("  Property Converters\n");
+        b.append("  -------------------\n");
+        b.append("  CLASS                         TYPE                          INFO\n");
+        for(Map.Entry<TypeLiteral<?>, List<PropertyConverter<?>>> converterEntry:getPropertyConverters().entrySet()){
+            for(PropertyConverter converter: converterEntry.getValue()){
+                b.append("  ");
+                appendFormatted(b, converter.getClass().getSimpleName(), 30);
+                appendFormatted(b, converterEntry.getKey().getRawType().getSimpleName(), 30);
+                b.append(removeNewLines(converter.toString()));
+                b.append('\n');
             }
         }
+        b.append('}');
+        return b.toString();
+    }
 
-        @Override
-        public int compare(PropertyFilter filter1, PropertyFilter filter2) {
-            return comparePropertyFilters(filter1, filter2);
+    private void appendFormatted(StringBuilder b, String text, int length) {
+        int padding;
+        if(text.length() <= (length)){
+            b.append(text);
+            padding = length - text.length();
+        }else{
+            b.append(text.substring(0, length-1));
+            padding = 1;
+        }
+        for(int i=0;i<padding;i++){
+            b.append(' ');
         }
     }
 
+    private String removeNewLines(String s) {
+        return s.replace('\n', ' ').replace('\r', ' ');
+    }
+
     @Override
     public List<PropertySource> getPropertySources() {
         return immutablePropertySources;
     }
 
     @Override
+    public PropertySource getPropertySource(String name) {
+        for(PropertySource ps:getPropertySources()){
+            if(name.equals(ps.getName())){
+                return ps;
+            }
+        }
+        return null;
+    }
+
+    @Override
     public <T> void addPropertyConverter(TypeLiteral<T> typeToConvert, PropertyConverter<T> propertyConverter) {
         propertyConverterManager.register(typeToConvert, propertyConverter);
         LOG.info("Added PropertyConverter: " + propertyConverter.getClass().getName());
@@ -250,7 +271,7 @@ public class DefaultConfigurationContext implements ConfigurationContext {
 
     @Override
     public ConfigurationContextBuilder toBuilder() {
-        return ConfigurationProvider.getConfigurationContextBuilder().setContext(this);
+        return new DefaultConfigurationContextBuilder(this);
     }
 
 }

http://git-wip-us.apache.org/repos/asf/incubator-tamaya-extensions/blob/3aca9112/modules/spi-support/src/main/java/org/apache/tamaya/spisupport/DefaultConfigurationContextBuilder.java
----------------------------------------------------------------------
diff --git a/modules/spi-support/src/main/java/org/apache/tamaya/spisupport/DefaultConfigurationContextBuilder.java b/modules/spi-support/src/main/java/org/apache/tamaya/spisupport/DefaultConfigurationContextBuilder.java
new file mode 100644
index 0000000..edf8173
--- /dev/null
+++ b/modules/spi-support/src/main/java/org/apache/tamaya/spisupport/DefaultConfigurationContextBuilder.java
@@ -0,0 +1,410 @@
+/*
+ * 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.spisupport;
+
+import org.apache.tamaya.TypeLiteral;
+import org.apache.tamaya.spi.ConfigurationContext;
+import org.apache.tamaya.spi.ConfigurationContextBuilder;
+import org.apache.tamaya.spi.PropertyConverter;
+import org.apache.tamaya.spi.PropertyFilter;
+import org.apache.tamaya.spi.PropertySource;
+import org.apache.tamaya.spi.PropertySourceProvider;
+import org.apache.tamaya.spi.PropertyValueCombinationPolicy;
+import org.apache.tamaya.spi.ServiceContextManager;
+
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.Comparator;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.Objects;
+import java.util.logging.Logger;
+
+/**
+ * Default implementation of {@link ConfigurationContextBuilder}.
+ */
+public class DefaultConfigurationContextBuilder implements ConfigurationContextBuilder {
+
+    private static final Logger LOG = Logger.getLogger(DefaultConfigurationContextBuilder.class.getName());
+
+    public static final Comparator<PropertySource> DEFAULT_PROPERTYSOURCE_COMPARATOR = new PropertySourceComparator();
+    public static final Comparator<?> DEFAULT_PROPERTYFILTER_COMPARATOR = new PriorityServiceComparator();
+
+    List<PropertyFilter> propertyFilters = new ArrayList<>();
+    List<PropertySource> propertySources = new ArrayList<>();
+    PropertyValueCombinationPolicy combinationPolicy =
+            PropertyValueCombinationPolicy.DEFAULT_OVERRIDING_COLLECTOR;
+    Map<TypeLiteral<?>, Collection<PropertyConverter<?>>> propertyConverters = new HashMap<>();
+
+    /**
+     * Flag if the config has already been built.
+     * Configuration can be built only once
+     */
+    private boolean built;
+
+
+
+    /**
+     * Creates a new builder instance.
+     */
+    public DefaultConfigurationContextBuilder() {
+    }
+
+    /**
+     * Creates a new builder instance.
+     */
+    public DefaultConfigurationContextBuilder(ConfigurationContext context) {
+        this.propertyConverters.putAll(context.getPropertyConverters());
+        this.propertyFilters.addAll(context.getPropertyFilters());
+        for(PropertySource ps:context.getPropertySources()) {
+            addPropertySources(ps);
+        }
+        this.combinationPolicy = context.getPropertyValueCombinationPolicy();
+    }
+
+    /**
+     * Allows to set configuration context during unit tests.
+     */
+    ConfigurationContextBuilder setConfigurationContext(ConfigurationContext configurationContext) {
+        checkBuilderState();
+        //noinspection deprecation
+        this.propertyFilters.clear();
+        this.propertyFilters.addAll(configurationContext.getPropertyFilters());
+        this.propertySources.clear();
+        for(PropertySource ps:configurationContext.getPropertySources()) {
+            addPropertySources(ps);
+        }
+        this.propertyConverters.clear();
+        this.propertyConverters.putAll(configurationContext.getPropertyConverters());
+        this.combinationPolicy = configurationContext.getPropertyValueCombinationPolicy();
+        return this;
+    }
+
+
+    @Override
+    public ConfigurationContextBuilder setContext(ConfigurationContext context) {
+        checkBuilderState();
+        this.propertyConverters.putAll(context.getPropertyConverters());
+        for(PropertySource ps:context.getPropertySources()){
+            this.propertySources.add(ps);
+        }
+        this.propertyFilters.addAll(context.getPropertyFilters());
+        this.combinationPolicy = context.getPropertyValueCombinationPolicy();
+        return this;
+    }
+
+    @Override
+    public ConfigurationContextBuilder addPropertySources(PropertySource... sources){
+        return addPropertySources(Arrays.asList(sources));
+    }
+
+    @Override
+    public ConfigurationContextBuilder addPropertySources(Collection<PropertySource> sources){
+        checkBuilderState();
+        for(PropertySource source:sources) {
+            if (!this.propertySources.contains(source)) {
+                this.propertySources.add(source);
+            }
+        }
+        return this;
+    }
+
+    protected DefaultConfigurationContextBuilder loadDefaultPropertyFilters() {
+        checkBuilderState();
+        for(PropertyFilter pf:ServiceContextManager.getServiceContext().getServices(PropertyFilter.class)){
+            addPropertyFilters(pf);
+        }
+        return this;
+    }
+
+    protected DefaultConfigurationContextBuilder loadDefaultPropertySources() {
+        checkBuilderState();
+        for(PropertySource ps:ServiceContextManager.getServiceContext().getServices(PropertySource.class)){
+            addPropertySources(ps);
+        }
+        for(PropertySourceProvider pv:ServiceContextManager.getServiceContext().getServices(PropertySourceProvider.class)){
+            for(PropertySource ps:pv.getPropertySources()){
+                addPropertySources(ps);
+            }
+        }
+        return this;
+    }
+
+    protected DefaultConfigurationContextBuilder loadDefaultPropertyConverters() {
+        checkBuilderState();
+        for(Map.Entry<TypeLiteral, Collection<PropertyConverter>> en:getDefaultPropertyConverters().entrySet()){
+            for(PropertyConverter pc: en.getValue()) {
+                addPropertyConverters(en.getKey(), pc);
+            }
+        }
+        return this;
+    }
+
+    @Override
+    public ConfigurationContextBuilder removePropertySources(PropertySource... propertySources) {
+        return removePropertySources(Arrays.asList(propertySources));
+    }
+
+    @Override
+    public ConfigurationContextBuilder removePropertySources(Collection<PropertySource> propertySources) {
+        checkBuilderState();
+        this.propertySources.removeAll(propertySources);
+        return this;
+    }
+
+    private PropertySource getPropertySource(String name) {
+        for(PropertySource ps:propertySources){
+            if(ps.getName().equals(name)){
+                return ps;
+            }
+        }
+        throw new IllegalArgumentException("No such PropertySource: "+name);
+    }
+
+    @Override
+    public List<PropertySource> getPropertySources() {
+        return this.propertySources;
+    }
+
+    @Override
+    public ConfigurationContextBuilder increasePriority(PropertySource propertySource) {
+        checkBuilderState();
+        int index = propertySources.indexOf(propertySource);
+        if(index<0){
+            throw new IllegalArgumentException("No such PropertySource: " + propertySource);
+        }
+        if(index<(propertySources.size()-1)){
+            propertySources.remove(propertySource);
+            propertySources.add(index+1, propertySource);
+        }
+        return this;
+    }
+
+    @Override
+    public ConfigurationContextBuilder decreasePriority(PropertySource propertySource) {
+        checkBuilderState();
+        int index = propertySources.indexOf(propertySource);
+        if(index<0){
+            throw new IllegalArgumentException("No such PropertySource: " + propertySource);
+        }
+        if(index>0){
+            propertySources.remove(propertySource);
+            propertySources.add(index-1, propertySource);
+        }
+        return this;
+    }
+
+    @Override
+    public ConfigurationContextBuilder highestPriority(PropertySource propertySource) {
+        checkBuilderState();
+        int index = propertySources.indexOf(propertySource);
+        if(index<0){
+            throw new IllegalArgumentException("No such PropertySource: " + propertySource);
+        }
+        if(index<(propertySources.size()-1)){
+            propertySources.remove(propertySource);
+            propertySources.add(propertySource);
+        }
+        return this;
+    }
+
+    @Override
+    public ConfigurationContextBuilder lowestPriority(PropertySource propertySource) {
+        checkBuilderState();
+        int index = propertySources.indexOf(propertySource);
+        if(index<0){
+            throw new IllegalArgumentException("No such PropertySource: " + propertySource);
+        }
+        if(index>0){
+            propertySources.remove(propertySource);
+            propertySources.add(0, propertySource);
+        }
+        return this;
+    }
+
+    @Override
+    public ConfigurationContextBuilder addPropertyFilters(PropertyFilter... filters){
+        return addPropertyFilters(Arrays.asList(filters));
+    }
+
+    @Override
+    public ConfigurationContextBuilder addPropertyFilters(Collection<PropertyFilter> filters){
+        checkBuilderState();
+        for(PropertyFilter f:filters) {
+            if (!this.propertyFilters.contains(f)) {
+                this.propertyFilters.add(f);
+            }
+        }
+        return this;
+    }
+
+    @Override
+    public ConfigurationContextBuilder removePropertyFilters(PropertyFilter... filters) {
+        return removePropertyFilters(Arrays.asList(filters));
+    }
+
+    @Override
+    public ConfigurationContextBuilder removePropertyFilters(Collection<PropertyFilter> filters) {
+        checkBuilderState();
+        this.propertyFilters.removeAll(filters);
+        return this;
+    }
+
+
+    @Override
+    public <T> ConfigurationContextBuilder removePropertyConverters(TypeLiteral<T> typeToConvert,
+                                                                    PropertyConverter<T>... converters) {
+        return removePropertyConverters(typeToConvert, Arrays.asList(converters));
+    }
+
+    @Override
+    public <T> ConfigurationContextBuilder removePropertyConverters(TypeLiteral<T> typeToConvert,
+                                                                    Collection<PropertyConverter<T>> converters) {
+        Collection<PropertyConverter<?>> subConverters = this.propertyConverters.get(typeToConvert);
+        if(subConverters!=null) {
+            subConverters.removeAll(converters);
+        }
+        return this;
+    }
+
+    @Override
+    public ConfigurationContextBuilder removePropertyConverters(TypeLiteral<?> typeToConvert) {
+        this.propertyConverters.remove(typeToConvert);
+        return this;
+    }
+
+
+    @Override
+    public ConfigurationContextBuilder setPropertyValueCombinationPolicy(PropertyValueCombinationPolicy combinationPolicy){
+        checkBuilderState();
+        this.combinationPolicy = Objects.requireNonNull(combinationPolicy);
+        return this;
+    }
+
+
+    @Override
+    public <T> ConfigurationContextBuilder addPropertyConverters(TypeLiteral<T> type, PropertyConverter<T>... propertyConverters){
+        checkBuilderState();
+        Objects.requireNonNull(type);
+        Objects.requireNonNull(propertyConverters);
+        Collection<PropertyConverter<?>> converters = this.propertyConverters.get(type);
+        if(converters==null){
+            converters = new ArrayList<>();
+            this.propertyConverters.put(type, converters);
+        }
+        for(PropertyConverter<T> propertyConverter:propertyConverters) {
+            if (!converters.contains(propertyConverter)) {
+                converters.add(propertyConverter);
+            } else {
+                LOG.warning("Converter ignored, already registered: " + propertyConverter);
+            }
+        }
+        return this;
+    }
+
+    @Override
+    public <T> ConfigurationContextBuilder addPropertyConverters(TypeLiteral<T> type, Collection<PropertyConverter<T>> propertyConverters){
+        checkBuilderState();
+        Objects.requireNonNull(type);
+        Objects.requireNonNull(propertyConverters);
+        Collection<PropertyConverter<?>> converters = this.propertyConverters.get(type);
+        if(converters==null){
+            converters = new ArrayList<>();
+            this.propertyConverters.put(type, converters);
+        }
+        for(PropertyConverter<T> propertyConverter:propertyConverters) {
+            if (!converters.contains(propertyConverter)) {
+                converters.add(propertyConverter);
+            } else {
+                LOG.warning("Converter ignored, already registered: " + propertyConverter);
+            }
+        }
+        return this;
+    }
+
+    protected ConfigurationContextBuilder loadDefaults() {
+        checkBuilderState();
+        this.combinationPolicy = PropertyValueCombinationPolicy.DEFAULT_OVERRIDING_COLLECTOR;
+        loadDefaultPropertySources();
+        loadDefaultPropertyFilters();
+        loadDefaultPropertyConverters();
+        return this;
+    }
+
+
+    private Map<TypeLiteral, Collection<PropertyConverter>> getDefaultPropertyConverters() {
+        Map<TypeLiteral, Collection<PropertyConverter>> result = new HashMap<>();
+        for (PropertyConverter conv : ServiceContextManager.getServiceContext().getServices(
+                PropertyConverter.class)) {
+            TypeLiteral target = TypeLiteral.of(TypeLiteral.of(conv.getClass()).getType());
+            Collection<PropertyConverter> convList = result.get(target);
+            if (convList == null) {
+                convList = new ArrayList<>();
+                result.put(target, convList);
+            }
+            convList.add(conv);
+        }
+        return result;
+    }
+
+
+    /**
+     * Builds a new configuration based on the configuration of this builder instance.
+     *
+     * @return a new {@link Configuration configuration instance},
+     *         never {@code null}.
+     */
+    @Override
+    public ConfigurationContext build() {
+        checkBuilderState();
+        built = true;
+        return new DefaultConfigurationContext(this);
+    }
+
+    @Override
+    public ConfigurationContextBuilder sortPropertyFilter(Comparator<PropertyFilter> comparator) {
+        Collections.sort(propertyFilters, comparator);
+        return this;
+    }
+
+    @Override
+    public ConfigurationContextBuilder sortPropertySources(Comparator<PropertySource> comparator) {
+        Collections.sort(propertySources, comparator);
+        return this;
+    }
+
+    private void checkBuilderState() {
+        if (built) {
+            throw new IllegalStateException("Configuration has already been build.");
+        }
+    }
+
+    @Override
+    public List<PropertyFilter> getPropertyFilters() {
+        return propertyFilters;
+    }
+
+    @Override
+    public Map<TypeLiteral<?>, Collection<PropertyConverter<?>>> getPropertyConverter() {
+        return Collections.unmodifiableMap(this.propertyConverters);
+    }
+}

http://git-wip-us.apache.org/repos/asf/incubator-tamaya-extensions/blob/3aca9112/modules/spi-support/src/main/java/org/apache/tamaya/spisupport/EnvironmentPropertySource.java
----------------------------------------------------------------------
diff --git a/modules/spi-support/src/main/java/org/apache/tamaya/spisupport/EnvironmentPropertySource.java b/modules/spi-support/src/main/java/org/apache/tamaya/spisupport/EnvironmentPropertySource.java
new file mode 100644
index 0000000..dca8060
--- /dev/null
+++ b/modules/spi-support/src/main/java/org/apache/tamaya/spisupport/EnvironmentPropertySource.java
@@ -0,0 +1,102 @@
+/*
+ * 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.spisupport;
+
+import org.apache.tamaya.spi.PropertySource;
+import org.apache.tamaya.spi.PropertyValue;
+
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.Map;
+import java.util.logging.Logger;
+
+/**
+ * This {@link PropertySource} provides all Properties which are set
+ * via
+ * {@code export myprop=myval} on UNIX Systems or
+ * {@code set myprop=myval} on Windows. You can disable this feature by setting {@code tamaya.envprops.disable}
+ * or {@code tamaya.defaults.disable}.
+ */
+public class EnvironmentPropertySource implements PropertySource {
+
+    private static final Logger LOG = Logger.getLogger(EnvironmentPropertySource.class.getName());
+
+    /**
+     * default ordinal for {@link org.apache.tamaya.core.propertysource.EnvironmentPropertySource}
+     */
+    public static final int DEFAULT_ORDINAL = 300;
+
+    private final boolean disabled = evaluateDisabled();
+
+    private boolean evaluateDisabled() {
+        String value = System.getProperty("tamaya.envprops.disable");
+        if(value==null){
+            value = System.getenv("tamaya.envprops.disable");
+        }
+        if(value==null){
+            value = System.getProperty("tamaya.defaults.disable");
+        }
+        if(value==null){
+            value = System.getenv("tamaya.defaults.disable");
+        }
+        if(value==null){
+            return false;
+        }
+        return value.isEmpty() || Boolean.parseBoolean(value);
+    }
+
+    @Override
+    public int getOrdinal() {
+        return DEFAULT_ORDINAL;
+    }
+
+    @Override
+    public String getName() {
+        if(disabled){
+            return "environment-properties(disabled)";
+        }
+        return "environment-properties";
+    }
+
+    @Override
+    public PropertyValue get(String key) {
+        if(disabled){
+            return null;
+        }
+        return PropertyValue.of(key, System.getenv(key), getName());
+    }
+
+    @Override
+    public Map<String, String> getProperties() {
+        if(disabled){
+            return Collections.emptyMap();
+        }
+        Map<String, String> entries = new HashMap<>(System.getenv());
+        for (Map.Entry<String, String> entry : System.getenv().entrySet()) {
+            entries.put("_" + entry.getKey() + ".source", getName());
+        }
+        return entries;
+    }
+
+    @Override
+    public boolean isScannable() {
+        return true;
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/incubator-tamaya-extensions/blob/3aca9112/modules/spi-support/src/main/java/org/apache/tamaya/spisupport/PropertyConverterManager.java
----------------------------------------------------------------------
diff --git a/modules/spi-support/src/main/java/org/apache/tamaya/spisupport/PropertyConverterManager.java b/modules/spi-support/src/main/java/org/apache/tamaya/spisupport/PropertyConverterManager.java
index 2be6313..1f1a2a9 100644
--- a/modules/spi-support/src/main/java/org/apache/tamaya/spisupport/PropertyConverterManager.java
+++ b/modules/spi-support/src/main/java/org/apache/tamaya/spisupport/PropertyConverterManager.java
@@ -1,20 +1,20 @@
 /*
  * 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
+ *  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
+ *     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.
+ *  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.spisupport;
 
@@ -24,24 +24,18 @@ import org.apache.tamaya.spi.ConversionContext;
 import org.apache.tamaya.spi.PropertyConverter;
 import org.apache.tamaya.spi.ServiceContextManager;
 
-import javax.annotation.Priority;
 import java.lang.reflect.Constructor;
 import java.lang.reflect.Method;
 import java.lang.reflect.Modifier;
 import java.lang.reflect.Type;
 import java.security.AccessController;
 import java.security.PrivilegedAction;
-import java.util.ArrayList;
-import java.util.Collections;
-import java.util.Comparator;
-import java.util.HashMap;
-import java.util.List;
-import java.util.Map;
-import java.util.Objects;
+import java.util.*;
 import java.util.concurrent.ConcurrentHashMap;
 import java.util.concurrent.locks.Lock;
 import java.util.concurrent.locks.ReadWriteLock;
 import java.util.concurrent.locks.ReentrantReadWriteLock;
+import java.util.logging.Level;
 import java.util.logging.Logger;
 
 /**
@@ -70,7 +64,7 @@ public class PropertyConverterManager {
 
         @Override
         public int compare(Object o1, Object o2) {
-            int prio = getPriority(o1) - getPriority(o2);
+            int prio = PriorityServiceComparator.getPriority(o1) - PriorityServiceComparator.getPriority(o2);
             if (prio < 0) {
                 return 1;
             } else if (prio > 0) {
@@ -82,21 +76,6 @@ public class PropertyConverterManager {
     };
 
     /**
-     * Checks the given instance for a @Priority annotation. If present the annotation's value s evaluated. If no such
-     * annotation is present, a default priority is returned (1);
-     * @param o the instance, not null.
-     * @return a priority, by default 1.
-     */
-    public static int getPriority(Object o){
-        int prio = 1;
-        Priority priority = o.getClass().getAnnotation(Priority.class);
-        if (priority != null) {
-            prio = priority.value();
-        }
-        return prio;
-    }
-
-    /**
      * Constructor.
      */
     public PropertyConverterManager() {
@@ -132,11 +111,16 @@ public class PropertyConverterManager {
         try {
             writeLock.lock();
             List converters = List.class.cast(this.converters.get(targetType));
+            if(converters!=null && converters.contains(converter)){
+                return;
+            }
             List<PropertyConverter<?>> newConverters = new ArrayList<>();
             if (converters != null) {
                 newConverters.addAll(converters);
             }
-            newConverters.add(converter);
+            if(!newConverters.contains(converter)) {
+                newConverters.add(converter);
+            }
             Collections.sort(newConverters, PRIORITY_COMPARATOR);
             this.converters.put(targetType, Collections.unmodifiableList(newConverters));
             // evaluate transitive closure for all inherited supertypes and implemented interfaces
@@ -185,8 +169,7 @@ public class PropertyConverterManager {
      * @return true, if a converter for the given type is registered, or a default one can be created.
      */
     public boolean isTargetTypeSupported(TypeLiteral<?> targetType) {
-        return converters.containsKey(targetType) || transitiveConverters.containsKey(targetType)
-                || createDefaultPropertyConverter(targetType) != null;
+        return converters.containsKey(targetType) || transitiveConverters.containsKey(targetType) || createDefaultPropertyConverter(targetType) != null;
     }
 
     /**
@@ -211,29 +194,25 @@ public class PropertyConverterManager {
      * Get the list of all current registered converters for the given target type.
      * If not converters are registered, they component tries to create and register a dynamic
      * converter based on String costructor or static factory methods available.
-     *
-     * <p>The converters provided are of the following type and returned in the following order:</p>
-     *
+     * The converters provided are of the following type and returned in the following order:
      * <ul>
-     *     <li>Converters mapped explicitly to the required target type are returned first, ordered
-     *     by decreasing priority. This means, if explicit converters are registered these are used
-     *     primarly for converting a value.</li>
-     *     <li>The target type of each explicitly registered converter also can be transitively mapped to
-     *     1) all directly implemented interfaces, 2) all its superclasses (except Object), 3) all the interfaces
-     *     implemented by its superclasses. These groups of transitive converters is returned similarly in the
-     *     order as mentioned, whereas also here a priority based decreasing ordering is applied.</li>
-     *     <li>java.lang wrapper classes and native types are automatically mapped.</li>
-     *     <li>If no explicit converters are registered, for Enum types a default implementation is provided that
-     *     compares the configuration values with the different enum members defined (cases sensitive mapping).</li>
+     * <li>Converters mapped explicitly to the required target type are returned first, ordered
+     * by decreasing priority. This means, if explicit converters are registered these are used
+     * primarly for converting a value.</li>
+     * <li>The target type of each explicitly registered converter also can be transitively mapped to
+     * 1) all directly implemented interfaces, 2) all its superclasses (except Object), 3) all the interfaces
+     * implemented by its superclasses. These groups of transitive converters is returned similarly in the
+     * order as mentioned, whereas also here a priority based decreasing ordering is applied.</li>
+     * <li>java.lang wrapper classes and native types are automatically mapped.</li>
+     * <li>If no explicit converters are registered, for Enum types a default implementation is provided that
+     * compares the configuration values with the different enum members defined (cases sensitive mapping).</li>
      * </ul>
-     *
-     *
+     * <p>
      * So given that list above directly registered mappings always are tried first, before any transitive mapping
      * should be used. Also in all cases @Priority annotations are honored for ordering of the converters in place.
      * Transitive conversion is supported for all directly implemented interfaces (including inherited ones) and
      * the inheritance hierarchy (exception Object). Superinterfaces of implemented interfaces are ignored.
      *
-     *
      * @param targetType the target type, not null.
      * @param <T>        the type class
      * @return the ordered list of converters (may be empty for not convertible types).
@@ -246,55 +225,58 @@ public class PropertyConverterManager {
         // direct mapped converters
         try {
             readLock.lock();
-            converters = List.class.cast(this.converters.get(targetType));
-        } finally {
-            readLock.unlock();
-        }
-        if (converters != null) {
-            converterList.addAll(converters);
-        }
-        // transitive converter
-        try {
-            readLock.lock();
-            converters = List.class.cast(this.transitiveConverters.get(targetType));
+            addConvertersToList(List.class.cast(this.converters.get(targetType)), converterList);
+            addConvertersToList(List.class.cast(this.transitiveConverters.get(targetType)), converterList);
         } finally {
             readLock.unlock();
         }
-        if (converters != null) {
-            converterList.addAll(converters);
-        }
-        // handling of java.ui.lang wrapper classes
+        // handling of java.lang wrapper classes
         TypeLiteral<T> boxedType = mapBoxedType(targetType);
         if (boxedType != null) {
             try {
                 readLock.lock();
-                converters = List.class.cast(this.converters.get(boxedType));
+                addConvertersToList(List.class.cast(this.converters.get(boxedType)), converterList);
             } finally {
                 readLock.unlock();
             }
-            if (converters != null) {
-                converterList.addAll(converters);
-            }
         }
-        if (converterList.isEmpty()) {
+        if (converterList.isEmpty() && !TypeLiteral.of(String.class).equals(targetType)) {
             // adding any converters created on the fly, e.g. for enum types.
             PropertyConverter<T> defaultConverter = createDefaultPropertyConverter(targetType);
             if (defaultConverter != null) {
                 register(targetType, defaultConverter);
                 try {
                     readLock.lock();
-                    converters = List.class.cast(this.converters.get(targetType));
+                    addConvertersToList(List.class.cast(this.converters.get(targetType)), converterList);
                 } finally {
                     readLock.unlock();
                 }
             }
-            if (converters != null) {
-                converterList.addAll(converters);
+        }
+        // check for parametrized types, ignoring param type
+        // direct mapped converters
+        if(targetType.getType()!=null) {
+            try {
+                readLock.lock();
+                addConvertersToList(List.class.cast(this.converters.get(
+                        TypeLiteral.of(targetType.getRawType()))), converterList);
+            } finally {
+                readLock.unlock();
             }
         }
         return converterList;
     }
 
+    private <T> void addConvertersToList(Collection<PropertyConverter<T>> converters, List<PropertyConverter<T>> converterList) {
+        if (converters != null) {
+            for(PropertyConverter<T> conv:converters) {
+                if(!converterList.contains(conv)) {
+                    converterList.add(conv);
+                }
+            }
+        }
+    }
+
     /**
      * Maps native types to the corresponding boxed types.
      *
@@ -302,7 +284,6 @@ public class PropertyConverterManager {
      * @param <T>        the type
      * @return the boxed type, or null.
      */
-    @SuppressWarnings("all")
     private <T> TypeLiteral<T> mapBoxedType(TypeLiteral<T> targetType) {
         Type parameterType = targetType.getType();
         if (parameterType == int.class) {
@@ -370,46 +351,40 @@ public class PropertyConverterManager {
         PropertyConverter<T> converter = null;
         final Method factoryMethod = getFactoryMethod(targetType.getRawType(), "of", "valueOf", "instanceOf", "getInstance", "from", "fromString", "parse");
         if (factoryMethod != null) {
+            converter = new DefaultPropertyConverter<>(factoryMethod, targetType.getRawType());
+        }
+        if (converter == null) {
+            final Constructor<T> constr;
+            try {
+                constr = targetType.getRawType().getDeclaredConstructor(String.class);
+            } catch (NoSuchMethodException e) {
+                LOG.log(Level.FINEST, "No matching constrctor for " + targetType, e);
+                return null;
+            }
             converter = new PropertyConverter<T>() {
-                @Override
-                public T convert(String value, ConversionContext context) {
-                    try {
-                        if (!Modifier.isStatic(factoryMethod.getModifiers())) {
-                            throw new ConfigException(factoryMethod.toGenericString() +
-                                    " is not a static method. Only static " +
-                                    "methods can be used as factory methods.");
-                        }
+                    @Override
+                    public T convert(String value, ConversionContext context) {
                         AccessController.doPrivileged(new PrivilegedAction<Object>() {
+                            @Override
                             public Object run() {
-                                factoryMethod.setAccessible(true);
+                                AccessController.doPrivileged(new PrivilegedAction<Object>() {
+                                    @Override
+                                    public Object run() {
+                                        constr.setAccessible(true);
+                                        return null;
+                                    }
+                                });
                                 return null;
                             }
                         });
-                        Object invoke = factoryMethod.invoke(null, value);
-                        return targetType.getRawType().cast(invoke);
-                    } catch (Exception e) {
-                        throw new ConfigException("Failed to decode '" + value + "'", e);
-                    }
-                }
-            };
-        }
-        if (converter == null) {
-            try {
-                final Constructor<T> constr = targetType.getRawType().getDeclaredConstructor(String.class);
-                converter = new PropertyConverter<T>() {
-                    @Override
-                    public T convert(String value, ConversionContext context) {
                         try {
-                            constr.setAccessible(true);
                             return constr.newInstance(value);
                         } catch (Exception e) {
-                            throw new ConfigException("Failed to decode '" + value + "'", e);
+                            LOG.log(Level.SEVERE, "Error creating new PropertyConverter instance " + targetType, e);
                         }
+                        return null;
                     }
                 };
-            } catch (Exception e) {
-                LOG.finest("Failed to construct instance of type: " + targetType.getRawType().getName() + ": " + e);
-            }
         }
         return converter;
     }
@@ -434,4 +409,61 @@ public class PropertyConverterManager {
         return null;
     }
 
+    @Override
+    public boolean equals(Object o) {
+        if (this == o) {
+            return true;
+        }
+        if (!(o instanceof PropertyConverterManager)) {
+            return false;
+        }
+        PropertyConverterManager that = (PropertyConverterManager) o;
+        return converters.equals(that.converters);
+
+    }
+
+    @Override
+    public int hashCode() {
+        return converters.hashCode();
+    }
+
+    /**
+     * Default converter im��ementation perfoming several lookups for String converion
+     * option.
+     * @param <T>
+     */
+    private static class DefaultPropertyConverter<T> implements PropertyConverter<T> {
+
+        private final Method factoryMethod;
+        private final Class<T> targetType;
+
+        DefaultPropertyConverter(Method factoryMethod, Class<T> targetType){
+            this.factoryMethod = Objects.requireNonNull(factoryMethod);
+            this.targetType =  Objects.requireNonNull(targetType);
+        }
+
+        @Override
+        public T convert(String value, ConversionContext context) {
+            context.addSupportedFormats(getClass(), "<String -> "+factoryMethod.toGenericString());
+
+            if (!Modifier.isStatic(factoryMethod.getModifiers())) {
+                throw new ConfigException(factoryMethod.toGenericString() +
+                        " is not a static method. Only static " +
+                        "methods can be used as factory methods.");
+            }
+            try {
+                AccessController.doPrivileged(new PrivilegedAction<Object>() {
+                    @Override
+                    public Object run() {
+                        factoryMethod.setAccessible(true);
+                        return null;
+                    }
+                });
+                Object invoke = factoryMethod.invoke(null, value);
+                return targetType.cast(invoke);
+            } catch (Exception e) {
+                throw new ConfigException("Failed to decode '" + value + "'", e);
+            }
+        }
+    }
 }

http://git-wip-us.apache.org/repos/asf/incubator-tamaya-extensions/blob/3aca9112/modules/spi-support/src/main/java/org/apache/tamaya/spisupport/PropertyFilterComparator.java
----------------------------------------------------------------------
diff --git a/modules/spi-support/src/main/java/org/apache/tamaya/spisupport/PropertyFilterComparator.java b/modules/spi-support/src/main/java/org/apache/tamaya/spisupport/PropertyFilterComparator.java
new file mode 100644
index 0000000..a7a5c66
--- /dev/null
+++ b/modules/spi-support/src/main/java/org/apache/tamaya/spisupport/PropertyFilterComparator.java
@@ -0,0 +1,60 @@
+/*
+ * 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.spisupport;
+
+import org.apache.tamaya.spi.PropertyFilter;
+
+import javax.annotation.Priority;
+import java.io.Serializable;
+import java.util.Comparator;
+
+/**
+ * Comparator for PropertyFilters based on their priority annotations.
+ */
+public class PropertyFilterComparator implements Comparator<PropertyFilter>, Serializable {
+
+    private static final long serialVersionUID = 1L;
+
+    /**
+     * Compare 2 filters for ordering the filter chain.
+     *
+     * @param filter1 the first filter
+     * @param filter2 the second filter
+     * @return the comparison result
+     */
+    private int comparePropertyFilters(PropertyFilter filter1, PropertyFilter filter2) {
+        Priority prio1 = filter1.getClass().getAnnotation(Priority.class);
+        Priority prio2 = filter2.getClass().getAnnotation(Priority.class);
+        int ord1 = prio1 != null ? prio1.value() : 0;
+        int ord2 = prio2 != null ? prio2.value() : 0;
+
+        if (ord1 < ord2) {
+            return -1;
+        } else if (ord1 > ord2) {
+            return 1;
+        } else {
+            return filter1.getClass().getName().compareTo(filter2.getClass().getName());
+        }
+    }
+
+    @Override
+    public int compare(PropertyFilter filter1, PropertyFilter filter2) {
+        return comparePropertyFilters(filter1, filter2);
+    }
+}

http://git-wip-us.apache.org/repos/asf/incubator-tamaya-extensions/blob/3aca9112/modules/spi-support/src/main/java/org/apache/tamaya/spisupport/PropertyFilterManager.java
----------------------------------------------------------------------
diff --git a/modules/spi-support/src/main/java/org/apache/tamaya/spisupport/PropertyFilterManager.java b/modules/spi-support/src/main/java/org/apache/tamaya/spisupport/PropertyFilterManager.java
new file mode 100644
index 0000000..611722a
--- /dev/null
+++ b/modules/spi-support/src/main/java/org/apache/tamaya/spisupport/PropertyFilterManager.java
@@ -0,0 +1,131 @@
+/*
+ * 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.spisupport;
+
+import org.apache.tamaya.spi.ConfigurationContext;
+import org.apache.tamaya.spi.FilterContext;
+import org.apache.tamaya.spi.PropertyFilter;
+
+import java.util.HashMap;
+import java.util.Map;
+import java.util.concurrent.atomic.AtomicInteger;
+import java.util.logging.Level;
+import java.util.logging.Logger;
+
+/**
+ * Implementation of the Configuration API. This class uses the current {@link ConfigurationContext} to evaluate the
+ * chain of {@link org.apache.tamaya.spi.PropertySource} and {@link PropertyFilter}
+ * instance to evaluate the current Configuration.
+ */
+public final class PropertyFilterManager {
+    /**
+     * The logger.
+     */
+    private static final Logger LOG = Logger.getLogger(PropertyFilterManager.class.getName());
+    /**
+     * The maximal number of filter cycles performed before aborting.
+     */
+    private static final int MAX_FILTER_LOOPS = 10;
+
+    /**
+     * Private singleton constructor.
+     */
+    private PropertyFilterManager(){}
+
+    public static String applyFilter(String key, Map<String,String> configData, ConfigurationContext configurationContext) {
+        // Apply filters to values, prevent values filtered to null!
+        String unfilteredValue = configData.get(key);
+        for (int i = 0; i < MAX_FILTER_LOOPS; i++) {
+            boolean changed = false;
+            // Apply filters to values, prevent values filtered to null!
+            for (PropertyFilter filter : configurationContext.getPropertyFilters()) {
+                String newValue = filter.filterProperty(unfilteredValue, new FilterContext(key, configData, true));
+                if (newValue != null && !newValue.equals(unfilteredValue)) {
+                    changed = true;
+                    if (LOG.isLoggable(Level.FINEST)) {
+                        LOG.finest("Filter - " + key + ": " + unfilteredValue + " -> " + newValue + " by " + filter);
+                    }
+                } else if (unfilteredValue != null && !unfilteredValue.equals(newValue)) {
+                    changed = true;
+                    if (LOG.isLoggable(Level.FINEST)) {
+                        LOG.finest("Filter - " + key + ": " + unfilteredValue + " -> " + newValue + " by " + filter);
+                    }
+                }
+                unfilteredValue = newValue;
+            }
+            if (!changed) {
+                LOG.finest("Finishing filter loop, no changes detected.");
+                break;
+            } else {
+                if (i == (MAX_FILTER_LOOPS - 1)) {
+                    if (LOG.isLoggable(Level.WARNING)) {
+                        LOG.warning("Maximal filter loop count reached, aborting filter evaluation after cycles: " + i);
+                    }
+                } else {
+                    LOG.finest("Repeating filter loop, changes detected.");
+                }
+            }
+        }
+        return unfilteredValue;
+    }
+
+    public static Map<String, String> applyFilters(Map<String, String> inputMap, ConfigurationContext configurationContext) {
+        Map<String, String> resultMap = new HashMap<>(inputMap);
+        // Apply filters to values, prevent values filtered to null!
+        for (int i = 0; i < MAX_FILTER_LOOPS; i++) {
+            AtomicInteger changes = new AtomicInteger();
+            for (PropertyFilter filter : configurationContext.getPropertyFilters()) {
+                for (Map.Entry<String, String> entry : inputMap.entrySet()) {
+                    final String k = entry.getKey();
+                    final String v = entry.getValue();
+
+                    String newValue = filter.filterProperty(v, new FilterContext(k, inputMap, false));
+                    if (newValue != null && !newValue.equals(v)) {
+                        changes.incrementAndGet();
+                        LOG.finest("Filter - " + k + ": " + v + " -> " + newValue + " by " + filter);
+                    } else if (v != null && !v.equals(newValue)) {
+                        changes.incrementAndGet();
+                        LOG.finest("Filter - " + k + ": " + v + " -> " + newValue + " by " + filter);
+                    }
+                    // Remove null values
+                    if (null != newValue) {
+                        resultMap.put(k, newValue);
+                    }else{
+                        resultMap.remove(k);
+                    }
+                }
+            }
+            if (changes.get() == 0) {
+                LOG.finest("Finishing filter loop, no changes detected.");
+                break;
+            } else {
+                if (i == (MAX_FILTER_LOOPS - 1)) {
+                    if (LOG.isLoggable(Level.WARNING)) {
+                        LOG.warning("Maximal filter loop count reached, aborting filter evaluation after cycles: " + i);
+                    }
+                } else {
+                    LOG.finest("Repeating filter loop, changes detected: " + changes.get());
+                }
+                changes.set(0);
+            }
+        }
+        return resultMap;
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/incubator-tamaya-extensions/blob/3aca9112/modules/spi-support/src/main/java/org/apache/tamaya/spisupport/SimplePropertySource.java
----------------------------------------------------------------------
diff --git a/modules/spi-support/src/main/java/org/apache/tamaya/spisupport/SimplePropertySource.java b/modules/spi-support/src/main/java/org/apache/tamaya/spisupport/SimplePropertySource.java
new file mode 100644
index 0000000..6c15e35
--- /dev/null
+++ b/modules/spi-support/src/main/java/org/apache/tamaya/spisupport/SimplePropertySource.java
@@ -0,0 +1,151 @@
+/*
+ * 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.spisupport;
+
+import org.apache.tamaya.ConfigException;
+
+import java.io.File;
+import java.io.IOException;
+import java.io.InputStream;
+import java.net.URL;
+import java.util.HashMap;
+import java.util.Map;
+import java.util.Objects;
+import java.util.Properties;
+import java.util.logging.Logger;
+
+/**
+ * Simple implementation of a {@link org.apache.tamaya.spi.PropertySource} for
+ * simple property files and XML property files.
+ */
+public class SimplePropertySource extends BasePropertySource {
+
+    private static final Logger LOG = Logger.getLogger(SimplePropertySource.class.getName());
+
+    /**
+     * The property source name.
+     */
+    private String name;
+
+    /**
+     * The current properties.
+     */
+    private Map<String, String> properties;
+
+    /**
+     * Creates a new Properties based PropertySource based on the given URL.
+     *
+     * @param propertiesLocation the URL encoded location, not null.
+     */
+    public SimplePropertySource(File propertiesLocation) {
+        super(0);
+        try {
+            this.name = propertiesLocation.toString();
+            this.properties = load(propertiesLocation.toURI().toURL());
+        } catch (IOException e) {
+            throw new ConfigException("Failed to load properties from " + propertiesLocation, e);
+        }
+    }
+
+    /**
+     * Creates a new Properties based PropertySource based on the given URL.
+     *
+     * @param propertiesLocation the URL encoded location, not null.
+     */
+    public SimplePropertySource(URL propertiesLocation) {
+        super(0);
+        this.properties = load(Objects.requireNonNull(propertiesLocation));
+        this.name = propertiesLocation.toString();
+    }
+
+    /**
+     * Creates a new Properties based PropertySource based on the given properties map.
+     *
+     * @param name       the name, not null.
+     * @param properties the properties, not null.
+     */
+    public SimplePropertySource(String name, Map<String, String> properties) {
+        super(0);
+        this.properties = new HashMap<>(properties);
+        this.name = Objects.requireNonNull(name);
+    }
+
+    /**
+     * Creates a new Properties based PropertySource based on the given URL.
+     *
+     * @param name               The property source name
+     * @param propertiesLocation the URL encoded location, not null.
+     */
+    public SimplePropertySource(String name, URL propertiesLocation) {
+        super(0);
+        this.properties = load(propertiesLocation);
+        this.name = Objects.requireNonNull(name);
+    }
+
+    @Override
+    public String getName() {
+        return name;
+    }
+
+    @Override
+    public Map<String, String> getProperties() {
+        return this.properties;
+    }
+
+    /**
+     * 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) {
+        boolean isXML = isXMLPropertieFiles(propertiesFile);
+
+        Map<String, String> properties = new HashMap<>();
+        try (InputStream stream = propertiesFile.openStream()) {
+            Properties props = new Properties();
+            if (stream != null) {
+                if (isXML) {
+                    props.loadFromXML(stream);
+                } else {
+                    props.load(stream);
+                }
+            }
+
+            for (String key : props.stringPropertyNames()) {
+                properties.put(key, props.getProperty(key));
+                if (getName() == null){
+                    LOG.warning("No property source name found for " + this +", ommitting source meta-entries.");
+                } else {
+                    properties.put("_" + key + ".source", getName());
+                }
+            }
+        } catch (IOException e) {
+            throw new ConfigException("Error loading properties from " + propertiesFile, e);
+        }
+
+        return properties;
+    }
+
+    private boolean isXMLPropertieFiles(URL url) {
+        return url.getFile().endsWith(".xml");
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/incubator-tamaya-extensions/blob/3aca9112/modules/spi-support/src/main/java/org/apache/tamaya/spisupport/SystemPropertySource.java
----------------------------------------------------------------------
diff --git a/modules/spi-support/src/main/java/org/apache/tamaya/spisupport/SystemPropertySource.java b/modules/spi-support/src/main/java/org/apache/tamaya/spisupport/SystemPropertySource.java
new file mode 100644
index 0000000..5f48738
--- /dev/null
+++ b/modules/spi-support/src/main/java/org/apache/tamaya/spisupport/SystemPropertySource.java
@@ -0,0 +1,125 @@
+/*
+ * 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.spisupport;
+
+import org.apache.tamaya.spi.PropertySource;
+import org.apache.tamaya.spi.PropertyValue;
+
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.Map;
+import java.util.Properties;
+
+/**
+ * This {@link PropertySource} manages the system properties. You can disable this feature by
+ * setting {@code tamaya.envprops.disable} or {@code tamaya.defaults.disable}.
+ */
+public class SystemPropertySource implements PropertySource {
+
+    /**
+     * default ordinal for {@link org.apache.tamaya.core.propertysource.SystemPropertySource}
+     */
+    public static final int DEFAULT_ORDINAL = 1000;
+
+    private volatile Map<String,String> cachedProperties;
+
+    /**
+     * previous System.getProperties().hashCode()
+     * so we can check if we need to reload
+     */
+    private int previousHash;
+
+    private final boolean disabled = evaluateDisabled();
+
+    private boolean evaluateDisabled() {
+        String value = System.getProperty("tamaya.sysprops.disable");
+        if(value==null){
+            value = System.getenv("tamaya.sysprops.disable");
+        }
+        if(value==null){
+            value = System.getProperty("tamaya.defaults.disable");
+        }
+        if(value==null){
+            value = System.getenv("tamaya.defaults.disable");
+        }
+        if(value==null){
+            return false;
+        }
+        return value.isEmpty() || Boolean.parseBoolean(value);
+    }
+
+
+
+    public SystemPropertySource() {
+        cachedProperties = loadProperties();
+        previousHash = System.getProperties().hashCode();
+    }
+
+    private Map<String, String> loadProperties() {
+        Map<String,String> props = new HashMap<>();
+        Properties sysProps = System.getProperties();
+        for(String name: sysProps.stringPropertyNames()) {
+            props.put(name,sysProps.getProperty(name));
+            props.put("_"+name+".source",getName());
+        }
+        return props;
+    }
+
+    @Override
+    public int getOrdinal() {
+        return DEFAULT_ORDINAL;
+    }
+
+    @Override
+    public String getName() {
+        if(disabled){
+            return "system-properties(disabled)";
+        }
+        return "system-properties";
+    }
+
+    @Override
+    public PropertyValue get(String key) {
+        if(disabled){
+            return null;
+        }
+        return PropertyValue.of(key, System.getProperty(key), getName());
+    }
+
+    @Override
+    public Map<String, String> getProperties() {
+        if(disabled){
+            return Collections.emptyMap();
+        }
+        // only need to reload and fill our map if something has changed
+        // synchronization was removed, Instance was marked as volatile. In the worst case it
+        // is reloaded twice, but the values will be the same.
+        if (previousHash != System.getProperties().hashCode()) {
+            Map<String, String> properties = loadProperties();
+            this.cachedProperties = Collections.unmodifiableMap(properties);
+            previousHash = System.getProperties().hashCode();
+        }
+        return this.cachedProperties;
+    }
+
+    @Override
+    public boolean isScannable() {
+        return true;
+    }
+}

http://git-wip-us.apache.org/repos/asf/incubator-tamaya-extensions/blob/3aca9112/modules/spi-support/src/test/java/org/apache/tamaya/spisupport/A.java
----------------------------------------------------------------------
diff --git a/modules/spi-support/src/test/java/org/apache/tamaya/spisupport/A.java b/modules/spi-support/src/test/java/org/apache/tamaya/spisupport/A.java
new file mode 100644
index 0000000..4101f1e
--- /dev/null
+++ b/modules/spi-support/src/test/java/org/apache/tamaya/spisupport/A.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.spisupport;
+
+/**
+ * Test class for testing transitively evaluated property converters.
+ */
+class A implements AutoCloseable{
+    @Override
+    public void close() throws Exception {
+
+    }
+}

http://git-wip-us.apache.org/repos/asf/incubator-tamaya-extensions/blob/3aca9112/modules/spi-support/src/test/java/org/apache/tamaya/spisupport/B.java
----------------------------------------------------------------------
diff --git a/modules/spi-support/src/test/java/org/apache/tamaya/spisupport/B.java b/modules/spi-support/src/test/java/org/apache/tamaya/spisupport/B.java
new file mode 100644
index 0000000..584b923
--- /dev/null
+++ b/modules/spi-support/src/test/java/org/apache/tamaya/spisupport/B.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.spisupport;
+
+/**
+ * Test class for testing transitively evaluated property converters.
+ */
+public class B extends A implements Runnable{
+    @Override
+    public void run() {
+
+    }
+}