tamaya-commits mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From anat...@apache.org
Subject [06/18] incubator-tamaya-extensions git commit: Adapted to comply with JSR API, fixed bugs. Imrpved API regarding sections, section filtering.
Date Wed, 03 Jan 2018 00:09:02 GMT
Adapted to comply with JSR API, fixed bugs. Imrpved API regarding sections, section filtering.

Signed-off-by: Anatole Tresch <anatole@apache.org>


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

Branch: refs/heads/configjsr
Commit: 36b446614d7c95b2ed1db9e15ff6ddaeeca1f7ab
Parents: 581c92e
Author: Anatole Tresch <anatole@apache.org>
Authored: Wed Dec 27 12:37:03 2017 +0100
Committer: Anatole Tresch <anatole@apache.org>
Committed: Wed Dec 27 12:37:03 2017 +0100

----------------------------------------------------------------------
 modules/functions/pom.xml                       |   5 +-
 .../tamaya/functions/ConfigSourceFunctions.java | 451 +++++++++++++++++++
 .../functions/ConfigurationFunctions.java       |   2 +-
 .../tamaya/functions/EnrichedConfigSource.java  |  93 ++++
 .../functions/EnrichedPropertySource.java       | 103 -----
 .../tamaya/functions/FilteredConfigSource.java  |  89 ++++
 .../functions/FilteredPropertySource.java       |  93 ----
 .../tamaya/functions/MappedConfigSource.java    | 109 +++++
 .../tamaya/functions/MappedPropertySource.java  | 119 -----
 .../functions/PropertySourceFunctions.java      | 410 -----------------
 .../functions/ValueMappedConfigSource.java      |  75 +++
 .../functions/ValueMappedPropertySource.java    |  86 ----
 .../functions/CombinedConfigurationTest.java    |   1 -
 .../functions/ConfigSourceFunctionsTest.java    | 434 ++++++++++++++++++
 .../functions/EnrichedConfigSourceTest.java     | 216 +++++++++
 .../functions/EnrichedConfigurationTest.java    |   4 -
 .../functions/EnrichedPropertySourceTest.java   | 250 ----------
 .../functions/FilteredConfigSourceTest.java     | 188 ++++++++
 .../functions/FilteredPropertySourceTest.java   | 214 ---------
 .../tamaya/functions/InMemoryConfigSource.java  |  68 +++
 .../tamaya/functions/InMemoryConfiguration.java |  35 --
 .../functions/InMemoryPropertySource.java       |  86 ----
 .../functions/MappedConfigSourceTest.java       | 159 +++++++
 .../functions/MappedPropertySourceTest.java     | 176 --------
 .../functions/PropertySourceFunctionsTest.java  | 367 ---------------
 .../functions/ValueMappedConfigSourceTest.java  | 148 ++++++
 .../ValueMappedPropertySourceTest.java          | 183 --------
 27 files changed, 2033 insertions(+), 2131 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/incubator-tamaya-extensions/blob/36b44661/modules/functions/pom.xml
----------------------------------------------------------------------
diff --git a/modules/functions/pom.xml b/modules/functions/pom.xml
index 17de980..4baa580 100644
--- a/modules/functions/pom.xml
+++ b/modules/functions/pom.xml
@@ -41,10 +41,9 @@ under the License.
         </dependency>
         <dependency>
             <groupId>org.apache.tamaya</groupId>
-            <artifactId>tamaya-spisupport</artifactId>
-            <version>${project.version}</version>
+            <artifactId>tamaya-base</artifactId>
+            <version>${tamaya-apicore.version}</version>
         </dependency>
-
         <dependency>
             <groupId>org.assertj</groupId>
             <artifactId>assertj-core</artifactId>

http://git-wip-us.apache.org/repos/asf/incubator-tamaya-extensions/blob/36b44661/modules/functions/src/main/java/org/apache/tamaya/functions/ConfigSourceFunctions.java
----------------------------------------------------------------------
diff --git a/modules/functions/src/main/java/org/apache/tamaya/functions/ConfigSourceFunctions.java b/modules/functions/src/main/java/org/apache/tamaya/functions/ConfigSourceFunctions.java
new file mode 100644
index 0000000..90081ed
--- /dev/null
+++ b/modules/functions/src/main/java/org/apache/tamaya/functions/ConfigSourceFunctions.java
@@ -0,0 +1,451 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.tamaya.functions;
+
+import javax.config.ConfigProvider;
+import javax.config.spi.ConfigSource;
+import java.util.*;
+import java.util.function.Function;
+
+/**
+ * Accessor that provides useful functions along with configuration.
+ */
+public final class ConfigSourceFunctions {
+    /**
+     * Implementation of an empty propertySource.
+     */
+    private static final ConfigSource EMPTY_PROPERTYSOURCE = new ConfigSource() {
+
+        @Override
+        public int getOrdinal() {
+            return 0;
+        }
+
+        @Override
+        public String getName() {
+            return "<empty>";
+        }
+
+        @Override
+        public String getValue(String key) {
+            return null;
+        }
+
+        @Override
+        public Map<String, String> getProperties() {
+            return Collections.emptyMap();
+        }
+
+        @Override
+        public String toString() {
+            return "ConfigSource<empty>";
+        }
+    };
+
+
+    private static final Function<String,Integer> DEFAULT_AREA_CALCULATOR =
+                                            s -> s.lastIndexOf('.');
+
+    /**
+     * Private singleton constructor.
+     */
+    private ConfigSourceFunctions() {
+    }
+
+    /**
+     * Calculates the current section key and compares it to the given key.
+     *
+     * @param key        the fully qualified entry key, not null
+     * @param sectionKey the section key, not null
+     * @param sectionCalculator function to calculate the split point of a key's section, e.g. {@code key.lastIndexOf('.')},
+     *                          not null.
+     * @param directChildrenOnly if true, only keys with the same area match. Otherwise also containing super-areas can
+     *                           match.
+     * @return true, if the entry is exact in this section
+     */
+    private static boolean isKeyInSection(String key, String sectionKey,
+                                          Function<String,Integer> sectionCalculator, boolean directChildrenOnly) {
+        Objects.requireNonNull(key, "Key must be given.");
+        Objects.requireNonNull(sectionCalculator, "Section calculator must be given.");
+        Objects.requireNonNull(sectionKey, "Section key must be given.");
+
+        sectionKey = normalizeSectionKey(sectionKey);
+
+        int lastIndex = sectionCalculator.apply(key);
+        String curAreaKey = lastIndex > 0 ? key.substring(0, lastIndex) : "";
+        if(directChildrenOnly) {
+            return curAreaKey.equals(sectionKey);
+        }else{
+            return curAreaKey.startsWith(sectionKey);
+        }
+    }
+
+    private static String normalizeKey(String key) {
+        return normalizeKey(key, DEFAULT_AREA_CALCULATOR);
+    }
+
+    private static String normalizeKey(String key, Function<String,Integer> sectionCalculator) {
+        if(key.isEmpty()){
+            return key;
+        }
+        int index = sectionCalculator.apply(key.substring(0,1));
+        if(index==0){
+            return key.substring(1);
+        }
+        return key;
+    }
+
+    private static String normalizeSectionKey(String sectionKey) {
+        return normalizeSectionKey(sectionKey, DEFAULT_AREA_CALCULATOR);
+    }
+
+    private static String normalizeSectionKey(String sectionKey, Function<String,Integer> areaCalculator) {
+        // Ignore unneeded and trailing dot at the end of the section key
+        if(sectionKey.isEmpty()){
+            return sectionKey;
+        }
+        int lastIndex = areaCalculator.apply(sectionKey);
+        int firstIndex = areaCalculator.apply(sectionKey.substring(0,1));
+
+        String normalizedKey = lastIndex==(sectionKey.length()-1)
+                   ? sectionKey.substring(0, sectionKey.length() - 1)
+                   : sectionKey;
+
+        normalizedKey = firstIndex==0 ? sectionKey.length() == 1 ? ""
+                                                                              : normalizedKey.substring(1)
+                                                   : normalizedKey;
+
+        return normalizedKey;
+    }
+
+    /**
+     * Checks if the given key is <i>directly</i> included in one of the given sections.
+     *
+     * @param key             the fully qualified entry key, not {@code null}
+     * @param sectionKeys      the section keys, not {@code null}
+     * @return true, if the entry is in one of the given sections
+     */
+    public static boolean isKeyInSection(String key, String... sectionKeys) {
+        return isKeyInSection(key, true, DEFAULT_AREA_CALCULATOR, sectionKeys);
+    }
+
+    /**
+     * Checks if the given key is included in one of the given sections.
+     *
+     * @param key             the fully qualified entry key, not {@code null}
+     * @param sectionKeys      the section keys, not {@code null}
+     * @param directChildrenOnly if true, then only keys match, which are a direct child of the given section.
+     * @return true, if the entry is in one of the given sections
+     */
+    public static boolean isKeyInSection(String key, boolean directChildrenOnly, String... sectionKeys) {
+        return isKeyInSection(key, directChildrenOnly, DEFAULT_AREA_CALCULATOR, sectionKeys);
+    }
+
+    /**
+     * Checks if the given key is included in one of the given sections, using the given separator to identify sections.
+     *
+     * @param key             the fully qualified entry key, not {@code null}
+     * @param sectionKeys     the section keys, not {@code null}
+     * @param areaCalculator  the function to calculate the split point to identify the section of a key.
+     * @param directChildrenOnly if true, then only keys match, which are a direct child of the given section.
+     * @return true, if the entry is in one of the given sections
+     */
+    public static boolean isKeyInSection(String key, boolean directChildrenOnly,
+                                         Function<String,Integer> areaCalculator, String... sectionKeys) {
+        Objects.requireNonNull(key, "Key must be given.");
+        Objects.requireNonNull(sectionKeys, "Section keys must be given.");
+
+        for (String areaKey : sectionKeys) {
+            if (areaKey == null) {
+                continue;
+            }
+            if (isKeyInSection(key, areaKey, areaCalculator, directChildrenOnly)) {
+                return true;
+            }
+        }
+        return false;
+    }
+
+    /**
+     * Return a query to evaluate the set with all fully qualified section names. This method should return the sections as accurate as possible,
+     * but may not provide a complete set of sections that are finally accessible, especially when the underlying storage
+     * does not support key iteration.
+     *
+     * @param properties properties to find sections in.
+     * @return set with all sections, never {@code null}.
+     */
+    public static Set<String> sections(Map<String, String> properties) {
+        return sections(properties, DEFAULT_AREA_CALCULATOR);
+    }
+
+    /**
+     * Return a query to evaluate the set with all fully qualified section names. This method should return the sections as accurate as possible,
+     * but may not provide a complete set of sections that are finally accessible, especially when the underlying storage
+     * does not support key iteration.
+     *
+     * @param properties properties to find sections in.
+     * @return set with all sections, never {@code null}.
+     */
+    public static Set<String> sections(Map<String, String> properties, Function<String,Integer> areaCalculator) {
+        final Set<String> areas = new HashSet<>();
+        for (String key : properties.keySet()) {
+            String normalizedKey = normalizeKey(key, areaCalculator);
+
+            int index = areaCalculator.apply(normalizedKey);
+            if (index > 0) {
+                areas.add(normalizedKey.substring(0, index));
+            } else {
+                areas.add("<root>");
+            }
+        }
+        return areas;
+    }
+
+    /**
+     * Return a query to evaluate the set with all fully qualified section names, containing the transitive closure also including all
+     * subarea names, regardless if properties are accessible or not. This method should return the sections as accurate
+     * as possible, but may not provide a complete set of sections that are finally accessible, especially when the
+     * underlying storage does not support key iteration.
+     *
+     * @param properties properties to find transitive sections in.
+     * @return s set with all transitive sections, never {@code null}.
+     */
+    public static Set<String> transitiveSections(Map<String, String> properties) {
+        return transitiveSections(properties, DEFAULT_AREA_CALCULATOR);
+    }
+
+    /**
+     * Return a query to evaluate the set with all fully qualified section names, containing the transitive closure also including all
+     * subarea names, regardless if properties are accessible or not. This method should return the sections as accurate
+     * as possible, but may not provide a complete set of sections that are finally accessible, especially when the
+     * underlying storage does not support key iteration.
+     * 
+     * @param properties properties to find transitive sections in.
+     * @return s set with all transitive sections, never {@code null}.
+     */
+    public static Set<String> transitiveSections(Map<String, String> properties, Function<String,Integer> areaCalculator) {
+        final Set<String> transitiveAreas = new HashSet<>();
+        for (String section : sections(properties, areaCalculator)) {
+            section = normalizeSectionKey(section, areaCalculator);
+
+            int index = areaCalculator.apply(section);
+            if (index < 0 && section.isEmpty()) {
+                transitiveAreas.add("<root>");
+            } if (index < 0) {
+                transitiveAreas.add(section);
+            } else {
+                while (index > 0) {
+                    section = section.substring(0, index);
+                    transitiveAreas.add(section);
+                    index = section.lastIndexOf('.');
+                }
+            }
+        }
+        return transitiveAreas;
+    }
+
+    /**
+     * Return a query to evaluate the set with all fully qualified section names, containing only the
+     * sections that match the predicate and have properties attached. This method should return the sections as accurate as possible,
+     * but may not provide a complete set of sections that are finally accessible, especially when the underlying storage
+     * does not support key iteration.
+     * 
+     * @param properties properties to find sections in.
+     * @param predicate A predicate to determine, which sections should be returned, not {@code null}.
+     * @return s set with all sections, never {@code null}.
+     */
+    public static Set<String> sections(Map<String, String> properties, final Predicate<String> predicate) {
+        Set<String> treeSet = new TreeSet<>();
+        for (String area : sections(properties)) {
+            if (predicate.test(area)) {
+                treeSet.add(area);
+            }
+        }
+        return treeSet;
+    }
+
+    /**
+     * Return a query to evaluate the set with all fully qualified section names, containing the transitive closure also including all
+     * subarea names, regardless if properties are accessible or not. This method should return the sections as accurate as possible,
+     * but may not provide a complete set of sections that are finally accessible, especially when the underlying storage
+     * does not support key iteration.
+     *
+     * @param properties properties to find transitive sections in.
+     * @param predicate A predicate to determine, which sections should be returned, not {@code null}.
+     * @return s set with all transitive sections, never {@code null}.
+     */
+    public static Set<String> transitiveSections(Map<String, String> properties, Predicate<String> predicate) {
+        Set<String> treeSet = new TreeSet<>();
+        for (String area : transitiveSections(properties)) {
+            if (predicate.test(area)) {
+                treeSet.add(area);
+            }
+        }
+        return treeSet;
+    }
+
+
+    /**
+     *Extracts the submap containing only entries with keys
+     * that are contained in the given sections. Hereby
+     * the section key is stripped away from the Map of the resulting keys.
+     *
+     * @param properties properties to find recursive sections in.
+     * @param sectionKeys the section keys, not null
+     * @return the section configuration, with the areaKey stripped away.
+     */
+    public static Map<String, String> sectionsRecursive(Map<String, String> properties, String... sectionKeys) {
+        return sectionsRecursive(properties, true, sectionKeys);
+    }
+
+    /**
+     * Extracts the submap containing only entries with keys
+     * that are contained in the given section and it's subsections.
+     *
+     * @param properties properties to find sections in.
+     * @param sectionKeys the section keys, not null
+     * @param stripKeys   if set to true, the section key is stripped away fromMap the resulting key.
+     * @return the section configuration, with the areaKey stripped away.
+     */
+    public static Map<String, String> sectionsRecursive(Map<String, String> properties, boolean stripKeys, String... sectionKeys) {
+        Map<String, String> result = new HashMap<>(properties.size());
+        for (Map.Entry<String, String> en : properties.entrySet()) {
+            if (isKeyInSection(en.getKey(), false,DEFAULT_AREA_CALCULATOR, sectionKeys)) {
+                if (stripKeys) {
+                    result.put(stripSectionKeys(en.getKey(), sectionKeys), en.getValue());
+                }else {
+                    result.put(en.getKey(), en.getValue());
+                }
+            }
+        }
+        return result;
+    }
+
+    /**
+     * Strips the section key of the given absolute key, if it is one of the areaKeys passed.
+     *
+     * @param key      the current key, not null.
+     * @param areaKeys the areaKeys, not null.
+     * @return the stripped key, or the original key (if no section was matching).
+     */
+    static String stripSectionKeys(String key, String... areaKeys) {
+        for (String areaKey : areaKeys) {
+            if (key.startsWith(areaKey + '.')) {
+                return key.substring(areaKey.length() + 1);
+            }
+        }
+        return key;
+    }
+
+    /**
+     * Creates a ConfigOperator that adds the given items.
+     *
+     * @param propertySource source property source that is changed.
+     * @param items    the items to be added/replaced.
+     * @param override if true, all items existing are overridden by the new ones passed.
+     * @return the ConfigOperator, never null.
+     */
+    public static ConfigSource addItems(ConfigSource propertySource, final Map<String, String> items, final boolean override) {
+        return new EnrichedConfigSource(propertySource, items, override);
+    }
+
+    /**
+     * Creates an operator that adds items to the instance (existing items will not be overridden).
+     *
+     * @param propertySource source property source that is changed.
+     * @param items the items, not null.
+     * @return the operator, never null.
+     */
+    public static ConfigSource addItems(ConfigSource propertySource, Map<String, String> items) {
+        return addItems(propertySource, items, false);
+    }
+
+    /**
+     * Creates an operator that replaces the given items.
+     *
+     * @param propertySource source property source that is changed.
+     * @param items the items.
+     * @return the operator for replacing the items.
+     */
+    public static ConfigSource replaceItems(ConfigSource propertySource, Map<String, String> items) {
+        return addItems(propertySource, items, true);
+    }
+
+    /**
+     * Accesses an empty PropertySource.
+     *
+     * @return an empty PropertySource, never null.
+     */
+    public static ConfigSource emptyConfigSource() {
+        return EMPTY_PROPERTYSOURCE;
+    }
+
+    /**
+     * Find all {@link ConfigSource} instances managed by the current
+     * {@link javax.config.Config} that are assignable to the given type.
+     *
+     * @param expression the regular expression to match the source's name.
+     * @return the list of all {@link ConfigSource} instances matching, never null.
+     */
+    public static Collection<? extends ConfigSource> findPropertySourcesByName(String expression) {
+        List result = new ArrayList<>();
+        for (ConfigSource src : ConfigProvider.getConfig().getConfigSources()) {
+            if (src.getName().matches(expression)) {
+                result.add(src);
+            }
+        }
+        return result;
+    }
+
+    /**
+     * Get a list of all {@link ConfigSource} instances managed by the current
+     * {@link javax.config.Config} that are assignable to the given type.
+     *
+     * @param <T> the type of the property source instances requested 
+     * @param type target type to filter for property sources. 
+     * @return the list of all {@link ConfigSource} instances matching, never null.
+     */
+    public static <T> Collection<T> getPropertySources(Class<T> type) {
+        List<T> result = new ArrayList<>();
+        for (ConfigSource src : ConfigProvider.getConfig().getConfigSources()) {
+            if (type.isAssignableFrom(src.getClass())) {
+                result.add((T) src);
+            }
+        }
+        return result;
+    }
+
+    /**
+     * Get a list of all {@link ConfigSource} instances managed by the current
+     * {@link javax.config.Config} that are assignable to the given type.
+     *
+     * @param <T> the type of the property source instances requested
+     * @param type target type to filter for property sources. 
+     * @return the list of all {@link ConfigSource} instances matching, never null.
+     */
+    public static <T> T getPropertySource(Class<T> type) {
+        for (ConfigSource src : ConfigProvider.getConfig().getConfigSources()) {
+            if (type.isAssignableFrom(src.getClass())) {
+                return (T) src;
+            }
+        }
+        return null;
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/incubator-tamaya-extensions/blob/36b44661/modules/functions/src/main/java/org/apache/tamaya/functions/ConfigurationFunctions.java
----------------------------------------------------------------------
diff --git a/modules/functions/src/main/java/org/apache/tamaya/functions/ConfigurationFunctions.java b/modules/functions/src/main/java/org/apache/tamaya/functions/ConfigurationFunctions.java
index 76581b7..15e6242 100644
--- a/modules/functions/src/main/java/org/apache/tamaya/functions/ConfigurationFunctions.java
+++ b/modules/functions/src/main/java/org/apache/tamaya/functions/ConfigurationFunctions.java
@@ -303,7 +303,7 @@ public final class ConfigurationFunctions {
             if (stripKeys) {
                 return new MappedConfiguration(
                         filtered,
-                        k -> PropertySourceFunctions.stripSectionKeys(k, sectionKeys),
+                        k -> ConfigSourceFunctions.stripSectionKeys(k, sectionKeys),
                         "stripped");
             }
             return filtered;

http://git-wip-us.apache.org/repos/asf/incubator-tamaya-extensions/blob/36b44661/modules/functions/src/main/java/org/apache/tamaya/functions/EnrichedConfigSource.java
----------------------------------------------------------------------
diff --git a/modules/functions/src/main/java/org/apache/tamaya/functions/EnrichedConfigSource.java b/modules/functions/src/main/java/org/apache/tamaya/functions/EnrichedConfigSource.java
new file mode 100644
index 0000000..c628a95
--- /dev/null
+++ b/modules/functions/src/main/java/org/apache/tamaya/functions/EnrichedConfigSource.java
@@ -0,0 +1,93 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.tamaya.functions;
+
+import org.apache.tamaya.base.configsource.ConfigSourceComparator;
+
+import javax.config.spi.ConfigSource;
+import java.util.*;
+
+/**
+ * PropertySource, that has values added or overridden.
+ */
+class EnrichedConfigSource implements ConfigSource {
+
+    private final ConfigSource basePropertySource;
+
+    private final Map<String, String> addedProperties = new HashMap<>();
+
+    private final boolean overriding;
+
+    /**
+     * Constructor.
+     *
+     * @param propertySource the base property source, not null.
+     * @param properties the properties to be added.
+     * @param overriding flag if existing properties are overridden.
+     */
+    EnrichedConfigSource(ConfigSource propertySource, Map<String, String> properties, boolean overriding) {
+        this.basePropertySource = Objects.requireNonNull(propertySource);
+        for(Map.Entry<String,String> en:properties.entrySet()){
+            this.addedProperties.putAll(properties);
+        }
+        this.overriding = overriding;
+    }
+
+
+    @Override
+    public int getOrdinal() {
+        return ConfigSourceComparator.getOrdinal(basePropertySource);
+    }
+
+    @Override
+    public String getName() {
+        return basePropertySource.getName();
+    }
+
+    @Override
+    public String getValue(String key) {
+        if (overriding) {
+            String val = addedProperties.get(key);
+            if (val != null) {
+                return val;
+            }
+            return basePropertySource.getValue(key);
+        }
+        String val = basePropertySource.getValue(key);
+        if (val != null) {
+            return val;
+        }
+        return addedProperties.get(key);
+
+    }
+
+    @Override
+    public Map<String, String> getProperties() {
+        Map<String, String> allProps = new HashMap<>();
+        if (overriding) {
+            allProps.putAll(basePropertySource.getProperties());
+            allProps.putAll(addedProperties);
+        } else {
+            allProps.putAll(addedProperties);
+            allProps.putAll(basePropertySource.getProperties());
+        }
+        return allProps;
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/incubator-tamaya-extensions/blob/36b44661/modules/functions/src/main/java/org/apache/tamaya/functions/EnrichedPropertySource.java
----------------------------------------------------------------------
diff --git a/modules/functions/src/main/java/org/apache/tamaya/functions/EnrichedPropertySource.java b/modules/functions/src/main/java/org/apache/tamaya/functions/EnrichedPropertySource.java
deleted file mode 100644
index c1367b8..0000000
--- a/modules/functions/src/main/java/org/apache/tamaya/functions/EnrichedPropertySource.java
+++ /dev/null
@@ -1,103 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements.  See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership.  The ASF licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License.  You may obtain a copy of the License at
- *
- *   http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing,
- * software distributed under the License is distributed on an
- * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- * KIND, either express or implied.  See the License for the
- * specific language governing permissions and limitations
- * under the License.
- */
-package org.apache.tamaya.functions;
-
-import org.apache.tamaya.spi.PropertySource;
-import org.apache.tamaya.spi.PropertyValue;
-import org.apache.tamaya.spisupport.PropertySourceComparator;
-
-import java.util.*;
-
-/**
- * PropertySource, that has values added or overridden.
- */
-class EnrichedPropertySource implements PropertySource {
-
-    private final PropertySource basePropertySource;
-
-    private final Map<String, PropertyValue> addedProperties = new HashMap<>();
-
-    private final boolean overriding;
-
-    /**
-     * Constructor.
-     *
-     * @param propertySource the base property source, not null.
-     * @param properties the properties to be added.
-     * @param overriding flag if existing properties are overridden.
-     */
-    EnrichedPropertySource(PropertySource propertySource, Map<String, String> properties, boolean overriding) {
-        this.basePropertySource = Objects.requireNonNull(propertySource);
-        for(Map.Entry<String,String> en:properties.entrySet()){
-            this.addedProperties.put(en.getKey(), PropertyValue.of(en.getKey(), en.getValue(), propertySource.getName()));
-        }
-        this.overriding = overriding;
-    }
-
-
-    @Override
-    public int getOrdinal() {
-        return PropertySourceComparator.getOrdinal(basePropertySource);
-    }
-
-    @Override
-    public String getName() {
-        return basePropertySource.getName();
-    }
-
-    @Override
-    public PropertyValue get(String key) {
-        if (overriding) {
-            PropertyValue val = addedProperties.get(key);
-            if (val != null) {
-                return val;
-            }
-            return basePropertySource.get(key);
-        }
-        PropertyValue val = basePropertySource.get(key);
-        if (val != null) {
-            return val;
-        }
-        return addedProperties.get(key);
-
-    }
-
-    @Override
-    public Map<String, PropertyValue> getProperties() {
-        Map<String, PropertyValue> allProps;
-        if (overriding) {
-            allProps = new HashMap<>();
-            for(PropertyValue val:basePropertySource.getProperties().values()){
-                allProps.put(val.getKey(), val);
-            }
-            allProps.putAll(addedProperties);
-        } else {
-            allProps = new HashMap<>(addedProperties);
-            for(PropertyValue val:basePropertySource.getProperties().values()){
-                allProps.put(val.getKey(), val);
-            }
-        }
-        return allProps;
-    }
-
-    @Override
-    public boolean isScannable() {
-        return basePropertySource.isScannable();
-    }
-}

http://git-wip-us.apache.org/repos/asf/incubator-tamaya-extensions/blob/36b44661/modules/functions/src/main/java/org/apache/tamaya/functions/FilteredConfigSource.java
----------------------------------------------------------------------
diff --git a/modules/functions/src/main/java/org/apache/tamaya/functions/FilteredConfigSource.java b/modules/functions/src/main/java/org/apache/tamaya/functions/FilteredConfigSource.java
new file mode 100644
index 0000000..51ccb3b
--- /dev/null
+++ b/modules/functions/src/main/java/org/apache/tamaya/functions/FilteredConfigSource.java
@@ -0,0 +1,89 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.tamaya.functions;
+
+
+import org.apache.tamaya.base.configsource.ConfigSourceComparator;
+
+import javax.config.spi.ConfigSource;
+import java.util.HashMap;
+import java.util.Map;
+import java.util.Objects;
+
+/**
+ * PropertySource that on the fly filters out part of the key/values of the underlying PropertySource.
+ */
+class FilteredConfigSource implements ConfigSource {
+
+    private final ConfigSource baseSource;
+    private final Predicate<String> filter;
+
+    /**
+     * Creates a new instance
+     * @param baseSource the underlying PropertySource
+     * @param filter the filter to be applied.
+     */
+    public FilteredConfigSource(ConfigSource baseSource, Predicate<String> filter){
+        this.baseSource = Objects.requireNonNull(baseSource);
+        this.filter = Objects.requireNonNull(filter);
+    }
+
+    @Override
+    public int getOrdinal(){
+        return ConfigSourceComparator.getOrdinal(getBaseSource());
+    }
+
+    @Override
+    public String getName() {
+        return baseSource.getName();
+    }
+
+    @Override
+    public String getValue(String key) {
+        String val = this.getBaseSource().getValue(key);
+        if(val!=null && filter.test(key)) {
+            return val;
+        }
+        return null;
+    }
+
+    @Override
+    public Map<String, String> getProperties(){
+        final Map<String,String> result = new HashMap<>();
+        for(Map.Entry<String,String> en: this.getBaseSource().getProperties().entrySet()) {
+            if (filter.test(en.getKey())) {
+                result.put(en.getKey(), en.getValue());
+            }
+        }
+        return result;
+    }
+
+    protected ConfigSource getBaseSource() {
+        return baseSource;
+    }
+
+    @Override
+    public String toString() {
+        return "FilteredPropertySource{" +
+                "baseSource=" + getBaseSource() +
+                ", filter=" + filter +
+                '}';
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/incubator-tamaya-extensions/blob/36b44661/modules/functions/src/main/java/org/apache/tamaya/functions/FilteredPropertySource.java
----------------------------------------------------------------------
diff --git a/modules/functions/src/main/java/org/apache/tamaya/functions/FilteredPropertySource.java b/modules/functions/src/main/java/org/apache/tamaya/functions/FilteredPropertySource.java
deleted file mode 100644
index 133862d..0000000
--- a/modules/functions/src/main/java/org/apache/tamaya/functions/FilteredPropertySource.java
+++ /dev/null
@@ -1,93 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements.  See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership.  The ASF licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License.  You may obtain a copy of the License at
- *
- *   http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing,
- * software distributed under the License is distributed on an
- * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- * KIND, either express or implied.  See the License for the
- * specific language governing permissions and limitations
- * under the License.
- */
-package org.apache.tamaya.functions;
-
-import org.apache.tamaya.spi.PropertySource;
-import org.apache.tamaya.spi.PropertyValue;
-import org.apache.tamaya.spisupport.PropertySourceComparator;
-
-import java.util.HashMap;
-import java.util.Map;
-import java.util.Objects;
-
-/**
- * PropertySource that on the fly filters out part of the key/values of the underlying PropertySource.
- */
-class FilteredPropertySource implements PropertySource {
-
-    private final PropertySource baseSource;
-    private final Predicate<String> filter;
-
-    /**
-     * Creates a new instance
-     * @param baseSource the underlying PropertySource
-     * @param filter the filter to be applied.
-     */
-    public FilteredPropertySource(PropertySource baseSource, Predicate<String> filter){
-        this.baseSource = Objects.requireNonNull(baseSource);
-        this.filter = Objects.requireNonNull(filter);
-    }
-
-    @Override
-    public int getOrdinal(){
-        return PropertySourceComparator.getOrdinal(getBaseSource());
-    }
-
-    @Override
-    public String getName() {
-        return baseSource.getName();
-    }
-
-    @Override
-    public PropertyValue get(String key) {
-        PropertyValue val = this.getBaseSource().get(key);
-        if(val!=null && filter.test(val.getKey())) {
-            return val;
-        }
-        return null;
-    }
-
-    @Override
-    public Map<String, PropertyValue> getProperties(){
-        final Map<String,PropertyValue> result = new HashMap<>();
-        for(PropertyValue val: this.getBaseSource().getProperties().values()) {
-            if (filter.test(val.getKey())) {
-                result.put(val.getKey(), val);
-            }
-        }
-        return result;
-    }
-
-    @Override
-    public boolean isScannable() {
-        return getBaseSource().isScannable();
-    }
-
-    @Override
-    public String toString() {
-        return "FilteredPropertySource{" +
-                "baseSource=" + getBaseSource() +
-                ", filter=" + filter +
-                '}';
-    }
-
-    protected PropertySource getBaseSource() {
-        return baseSource;
-    }
-}

http://git-wip-us.apache.org/repos/asf/incubator-tamaya-extensions/blob/36b44661/modules/functions/src/main/java/org/apache/tamaya/functions/MappedConfigSource.java
----------------------------------------------------------------------
diff --git a/modules/functions/src/main/java/org/apache/tamaya/functions/MappedConfigSource.java b/modules/functions/src/main/java/org/apache/tamaya/functions/MappedConfigSource.java
new file mode 100644
index 0000000..1b3881b
--- /dev/null
+++ b/modules/functions/src/main/java/org/apache/tamaya/functions/MappedConfigSource.java
@@ -0,0 +1,109 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.tamaya.functions;
+
+
+import org.apache.tamaya.base.configsource.ConfigSourceComparator;
+
+import javax.config.spi.ConfigSource;
+import java.util.*;
+
+/**
+ * PropertySource implementation that maps certain parts (defined by an {@code UnaryOperator<String>}) to alternate sections.
+ */
+class MappedConfigSource implements ConfigSource {
+
+    private static final long serialVersionUID = 8690637705511432083L;
+
+    /**
+     * The mapping operator.
+     */
+    private final KeyMapper keyMapper;
+
+    /**
+     * The base configuration.
+     */
+    private final ConfigSource propertySource;
+
+    /**
+     * Creates a new instance.
+     *
+     * @param config    the base configuration, not null
+     * @param keyMapper The mapping operator, not null
+     */
+    public MappedConfigSource(ConfigSource config, KeyMapper keyMapper) {
+        this.propertySource = Objects.requireNonNull(config);
+        this.keyMapper = Objects.requireNonNull(keyMapper);
+    }
+
+    @Override
+    public int getOrdinal() {
+        return ConfigSourceComparator.getOrdinal(this.propertySource);
+    }
+
+    @Override
+    public String getName() {
+        return this.propertySource.getName() + "[mapped]";
+    }
+
+    @Override
+    public Map<String, String> getProperties() {
+        Map<String,String> result = new HashMap<>();
+        for (Map.Entry<String,String> en : this.propertySource.getProperties().entrySet()) {
+            String targetKey = keyMapper.mapKey(en.getKey());
+            if (targetKey != null) {
+                result.put(targetKey, en.getValue());
+            }
+        }
+        return result;
+    }
+
+    /**
+     * <p>Access a property by its key.</p>
+     *
+     * <p>
+     *  The key of the property to be returned must be equal to the key
+     *  returned by the mapping operator (key mapper) and not equal
+     *  to the key of the base configuration.
+     * </p>
+     *
+     * @param key the property's key, not {@code null}.
+     * @return the property value map, where {@code map.get(key) == value},
+     *         including also any metadata. In case a value is {@code null},
+     *         simply return {@code null}.
+     */
+    @Override
+    public String getValue(String key) {
+        Objects.requireNonNull(key, "Key must be given.");
+
+        String mappedKey = keyMapper.mapKey(key);
+        String result = null;
+
+        if (mappedKey != null) {
+            for (Map.Entry<String,String> en : propertySource.getProperties().entrySet()) {
+                String newKey = keyMapper.mapKey(en.getKey());
+                if (mappedKey.equals(newKey)) {
+                    return en.getValue();
+                }
+            }
+        }
+        return result;
+    }
+
+}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/incubator-tamaya-extensions/blob/36b44661/modules/functions/src/main/java/org/apache/tamaya/functions/MappedPropertySource.java
----------------------------------------------------------------------
diff --git a/modules/functions/src/main/java/org/apache/tamaya/functions/MappedPropertySource.java b/modules/functions/src/main/java/org/apache/tamaya/functions/MappedPropertySource.java
deleted file mode 100644
index 7e48f22..0000000
--- a/modules/functions/src/main/java/org/apache/tamaya/functions/MappedPropertySource.java
+++ /dev/null
@@ -1,119 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements.  See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership.  The ASF licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License.  You may obtain a copy of the License at
- *
- *   http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing,
- * software distributed under the License is distributed on an
- * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- * KIND, either express or implied.  See the License for the
- * specific language governing permissions and limitations
- * under the License.
- */
-package org.apache.tamaya.functions;
-
-import org.apache.tamaya.spi.PropertySource;
-import org.apache.tamaya.spi.PropertyValue;
-import org.apache.tamaya.spisupport.PropertySourceComparator;
-
-import java.util.*;
-
-/**
- * PropertySource implementation that maps certain parts (defined by an {@code UnaryOperator<String>}) to alternate sections.
- */
-class MappedPropertySource implements PropertySource {
-
-    private static final long serialVersionUID = 8690637705511432083L;
-
-    /**
-     * The mapping operator.
-     */
-    private final KeyMapper keyMapper;
-
-    /**
-     * The base configuration.
-     */
-    private final PropertySource propertySource;
-
-    /**
-     * Creates a new instance.
-     *
-     * @param config    the base configuration, not null
-     * @param keyMapper The mapping operator, not null
-     */
-    public MappedPropertySource(PropertySource config, KeyMapper keyMapper) {
-        this.propertySource = Objects.requireNonNull(config);
-        this.keyMapper = Objects.requireNonNull(keyMapper);
-    }
-
-    @Override
-    public int getOrdinal() {
-        return PropertySourceComparator.getOrdinal(this.propertySource);
-    }
-
-    @Override
-    public String getName() {
-        return this.propertySource.getName() + "[mapped]";
-    }
-
-    @Override
-    public Map<String, PropertyValue> getProperties() {
-        Map<String,PropertyValue> result = new HashMap<>();
-        for (PropertyValue en : this.propertySource.getProperties().values()) {
-            String targetKey = keyMapper.mapKey(en.getKey());
-            if (targetKey != null) {
-                result.put(targetKey, PropertyValue.of(targetKey, en.getValue(), getName()));
-            }
-        }
-        return result;
-    }
-
-    @Override
-    public boolean isScannable() {
-        return propertySource.isScannable();
-    }
-
-
-    /**
-     * <p>Access a property by its key.</p>
-     *
-     * <p>
-     *  The key of the property to be returned must be equal to the key
-     *  returned by the mapping operator (key mapper) and not equal
-     *  to the key of the base configuration.
-     * </p>
-     *
-     * @param key the property's key, not {@code null}.
-     * @return the property value map, where {@code map.get(key) == value},
-     *         including also any metadata. In case a value is {@code null},
-     *         simply return {@code null}.
-     */
-    @Override
-    public PropertyValue get(String key) {
-        Objects.requireNonNull(key, "Key must be given.");
-
-        String mappedKey = keyMapper.mapKey(key);
-        PropertyValue result = null;
-
-        if (mappedKey != null) {
-            for (PropertyValue property : propertySource.getProperties().values()) {
-                String newKey = keyMapper.mapKey(property.getKey());
-
-                if (mappedKey.equals(newKey)) {
-                    String mappedName = getName();
-                    return property.toBuilder().mapKey(newKey)
-                                   .setSource(mappedName).build();
-                }
-            }
-        }
-
-        return result;
-    }
-
-}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/incubator-tamaya-extensions/blob/36b44661/modules/functions/src/main/java/org/apache/tamaya/functions/PropertySourceFunctions.java
----------------------------------------------------------------------
diff --git a/modules/functions/src/main/java/org/apache/tamaya/functions/PropertySourceFunctions.java b/modules/functions/src/main/java/org/apache/tamaya/functions/PropertySourceFunctions.java
deleted file mode 100644
index 6f20d6f..0000000
--- a/modules/functions/src/main/java/org/apache/tamaya/functions/PropertySourceFunctions.java
+++ /dev/null
@@ -1,410 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements.  See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership.  The ASF licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License.  You may obtain a copy of the License at
- *
- *   http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing,
- * software distributed under the License is distributed on an
- * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- * KIND, either express or implied.  See the License for the
- * specific language governing permissions and limitations
- * under the License.
- */
-package org.apache.tamaya.functions;
-
-import org.apache.tamaya.ConfigurationProvider;
-import org.apache.tamaya.spi.PropertySource;
-import org.apache.tamaya.spi.PropertyValue;
-
-import java.util.*;
-
-import static java.lang.System.arraycopy;
-
-/**
- * Accessor that provides useful functions along with configuration.
- */
-public final class PropertySourceFunctions {
-    /**
-     * Implementation of an empty propertySource.
-     */
-    private static final PropertySource EMPTY_PROPERTYSOURCE = new PropertySource() {
-
-        @Override
-        public int getOrdinal() {
-            return 0;
-        }
-
-        @Override
-        public String getName() {
-            return "<empty>";
-        }
-
-        @Override
-        public PropertyValue get(String key) {
-            return null;
-        }
-
-        @Override
-        public Map<String, PropertyValue> getProperties() {
-            return Collections.emptyMap();
-        }
-
-        @Override
-        public boolean isScannable() {
-            return true;
-        }
-
-        @Override
-        public String toString() {
-            return "PropertySource<empty>";
-        }
-    };
-
-    /**
-     * Private singleton constructor.
-     */
-    private PropertySourceFunctions() {
-    }
-
-    /**
-     * Calculates the current section key and compares it to the given key.
-     *
-     * @param key        the fully qualified entry key, not null
-     * @param sectionKey the section key, not null
-     *
-     * @return true, if the entry is exact in this section
-     */
-    public static boolean isKeyInSection(String key, String sectionKey) {
-        Objects.requireNonNull(key, "Key must be given.");
-        Objects.requireNonNull(sectionKey, "Section key must be given.");
-
-        sectionKey = normalizeSectionKey(sectionKey);
-
-        int lastIndex = key.lastIndexOf('.');
-        String curAreaKey = lastIndex > 0 ? key.substring(0, lastIndex) : "";
-        return curAreaKey.equals(sectionKey);
-    }
-
-    private static String normalizeKey(String key) {
-        return key.startsWith(".") ? key.substring(1)
-                                   : key;
-    }
-
-    static String normalizeSectionKey(String sectionKey) {
-        // Ignore unneeded and trailing dot at the end of the section key
-
-        String normalizedKey = sectionKey.endsWith(".")
-                   ? sectionKey.substring(0, sectionKey.length() - 1)
-                   : sectionKey;
-
-        normalizedKey = sectionKey.startsWith(".") ? sectionKey.length() == 1 ? ""
-                                                                              : normalizedKey.substring(1)
-                                                   : normalizedKey;
-
-        return normalizedKey;
-    }
-
-    /**
-     * Calculates the current section key and compares it to the given section keys.
-     *
-     * @param key             the fully qualified entry key, not {@code null}
-     * @param sectionKey      the section keys, not {@code null}
-     * @param moreSectionKeys the more section keys, not {@code null}
-     *
-     * @return true, if the entry is in one of the given sections
-     */
-    public static boolean isKeyInSections(String key, String sectionKey, String... moreSectionKeys) {
-        Objects.requireNonNull(key, "Key must be given.");
-        Objects.requireNonNull(sectionKey, "At least one section key must be given.");
-        Objects.requireNonNull(moreSectionKeys, "Additional section keys must not be null.");
-
-        String[] sectionKeys = new String[moreSectionKeys.length + 1];
-        sectionKeys[0] = sectionKey;
-
-        if (moreSectionKeys.length > 0) {
-            arraycopy(moreSectionKeys, 0, sectionKeys, 1, moreSectionKeys.length);
-        }
-
-        return isKeyInSections(key, sectionKeys);
-    }
-
-    /**
-     * Calculates the current section key and compares it to the given section keys.
-     *
-     * @param key             the fully qualified entry key, not {@code null}
-     * @param sectionKeys     the section keys, not {@code null}
-     *
-     *  @return true, if the entry is in one of the given sections
-     */
-    public static boolean isKeyInSections(String key, String[] sectionKeys) {
-        Objects.requireNonNull(key, "Key must be given.");
-        Objects.requireNonNull(sectionKeys, "Section keys must be given.");
-
-        boolean result = false;
-
-        for (String areaKey : sectionKeys) {
-            if (areaKey == null) {
-                continue;
-            }
-
-            if (isKeyInSection(key, areaKey)) {
-                result = true;
-                break;
-            }
-        }
-
-        return result;
-    }
-
-    /**
-     * Return a query to evaluate the set with all fully qualified section names. This method should return the sections as accurate as possible,
-     * but may not provide a complete set of sections that are finally accessible, especially when the underlying storage
-     * does not support key iteration.
-     *
-     * @param properties properties to find sections in.
-     * @return set with all sections, never {@code null}.
-     */
-    public static Set<String> sections(Map<String, String> properties) {
-        final Set<String> areas = new HashSet<>();
-        for (String key : properties.keySet()) {
-            String normalizedKey = normalizeKey(key);
-
-            int index = normalizedKey.lastIndexOf('.');
-            if (index > 0) {
-                areas.add(normalizedKey.substring(0, index));
-            } else {
-                areas.add("<root>");
-            }
-        }
-        return areas;
-    }
-
-    /**
-     * Return a query to evaluate the set with all fully qualified section names, containing the transitive closure also including all
-     * subarea names, regardless if properties are accessible or not. This method should return the sections as accurate
-     * as possible, but may not provide a complete set of sections that are finally accessible, especially when the
-     * underlying storage does not support key iteration.
-     * 
-     * @param properties properties to find transitive sections in.
-     * @return s set with all transitive sections, never {@code null}.
-     */
-    public static Set<String> transitiveSections(Map<String, String> properties) {
-        final Set<String> transitiveAreas = new HashSet<>();
-        for (String section : sections(properties)) {
-            section = normalizeSectionKey(section);
-
-            int index = section.lastIndexOf('.');
-            if (index < 0 && section.isEmpty()) {
-                transitiveAreas.add("<root>");
-            } if (index < 0) {
-                transitiveAreas.add(section);
-            } else {
-                while (index > 0) {
-                    section = section.substring(0, index);
-                    transitiveAreas.add(section);
-                    index = section.lastIndexOf('.');
-                }
-            }
-        }
-        return transitiveAreas;
-    }
-
-    /**
-     * Return a query to evaluate the set with all fully qualified section names, containing only the
-     * sections that match the predicate and have properties attached. This method should return the sections as accurate as possible,
-     * but may not provide a complete set of sections that are finally accessible, especially when the underlying storage
-     * does not support key iteration.
-     * 
-     * @param properties properties to find sections in.
-     * @param predicate A predicate to determine, which sections should be returned, not {@code null}.
-     * @return s set with all sections, never {@code null}.
-     */
-    public static Set<String> sections(Map<String, String> properties, final Predicate<String> predicate) {
-        Set<String> treeSet = new TreeSet<>();
-        for (String area : sections(properties)) {
-            if (predicate.test(area)) {
-                treeSet.add(area);
-            }
-        }
-        return treeSet;
-    }
-
-    /**
-     * Return a query to evaluate the set with all fully qualified section names, containing the transitive closure also including all
-     * subarea names, regardless if properties are accessible or not. This method should return the sections as accurate as possible,
-     * but may not provide a complete set of sections that are finally accessible, especially when the underlying storage
-     * does not support key iteration.
-     *
-     * @param properties properties to find transitive sections in.
-     * @param predicate A predicate to determine, which sections should be returned, not {@code null}.
-     * @return s set with all transitive sections, never {@code null}.
-     */
-    public static Set<String> transitiveSections(Map<String, String> properties, Predicate<String> predicate) {
-        Set<String> treeSet = new TreeSet<>();
-        for (String area : transitiveSections(properties)) {
-            if (predicate.test(area)) {
-                treeSet.add(area);
-            }
-        }
-        return treeSet;
-    }
-
-
-    /**
-     * Creates a ConfigOperator that creates a Configuration containing only keys
-     * that are contained in the given section (recursive). Hereby
-     * the section key is stripped away from the Map of the resulting keys.
-     *
-     * @param properties properties to find recursive sections in.
-     * @param sectionKeys the section keys, not null
-     * @return the section configuration, with the areaKey stripped away.
-     */
-    public static Map<String, String> sectionsRecursive(Map<String, String> properties, String... sectionKeys) {
-        return sectionRecursive(properties, true, sectionKeys);
-    }
-
-    /**
-     * Creates a ConfigOperator that creates a Configuration containing only keys
-     * that are contained in the given section (recursive).
-     *
-     * @param properties properties to find sections in.
-     * @param sectionKeys the section keys, not null
-     * @param stripKeys   if set to true, the section key is stripped away fromMap the resulting key.
-     * @return the section configuration, with the areaKey stripped away.
-     */
-    public static Map<String, String> sectionRecursive(Map<String, String> properties, boolean stripKeys, String... sectionKeys) {
-        Map<String, String> result = new HashMap<>(properties.size());
-        if (stripKeys) {
-            for (Map.Entry<String, String> en : properties.entrySet()) {
-                if (isKeyInSections(en.getKey(), sectionKeys)) {
-                    result.put(en.getKey(), en.getValue());
-                }
-            }
-        } else {
-            for (Map.Entry<String, String> en : properties.entrySet()) {
-                if (isKeyInSections(en.getKey(), sectionKeys)) {
-                    result.put(stripSectionKeys(en.getKey(), sectionKeys), en.getValue());
-                }
-            }
-        }
-        return result;
-    }
-
-    /**
-     * Strips the section key of the given absolute key, if it is one of the areaKeys passed.
-     *
-     * @param key      the current key, not null.
-     * @param areaKeys the areaKeys, not null.
-     * @return the stripped key, or the original key (if no section was matching).
-     */
-    static String stripSectionKeys(String key, String... areaKeys) {
-        for (String areaKey : areaKeys) {
-            if (key.startsWith(areaKey + '.')) {
-                return key.substring(areaKey.length() + 1);
-            }
-        }
-        return key;
-    }
-
-    /**
-     * Creates a ConfigOperator that adds the given items.
-     *
-     * @param propertySource source property source that is changed.
-     * @param items    the items to be added/replaced.
-     * @param override if true, all items existing are overridden by the new ones passed.
-     * @return the ConfigOperator, never null.
-     */
-    public static PropertySource addItems(PropertySource propertySource, final Map<String, String> items, final boolean override) {
-        return new EnrichedPropertySource(propertySource, items, override);
-    }
-
-    /**
-     * Creates an operator that adds items to the instance.
-     *
-     * @param propertySource source property source that is changed.
-     * @param items the items, not null.
-     * @return the operator, never null.
-     */
-    public static PropertySource addItems(PropertySource propertySource, Map<String, String> items) {
-        return addItems(propertySource, items, false);
-    }
-
-    /**
-     * Creates an operator that replaces the given items.
-     *
-     * @param propertySource source property source that is changed.
-     * @param items the items.
-     * @return the operator for replacing the items.
-     */
-    public static PropertySource replaceItems(PropertySource propertySource, Map<String, String> items) {
-        return addItems(propertySource, items, true);
-    }
-
-    /**
-     * Accesses an empty PropertySource.
-     *
-     * @return an empty PropertySource, never null.
-     */
-    public static PropertySource emptyPropertySource() {
-        return EMPTY_PROPERTYSOURCE;
-    }
-
-    /**
-     * Find all {@link PropertySource} instances managed by the current
-     * {@link org.apache.tamaya.spi.ConfigurationContext} that are assignable to the given type.
-     *
-     * @param expression the regular expression to match the source's name.
-     * @return the list of all {@link PropertySource} instances matching, never null.
-     */
-    public static Collection<? extends PropertySource> findPropertySourcesByName(String expression) {
-        List result = new ArrayList<>();
-        for (PropertySource src : ConfigurationProvider.getConfigurationContext().getPropertySources()) {
-            if (src.getName().matches(expression)) {
-                result.add(src);
-            }
-        }
-        return result;
-    }
-
-    /**
-     * Get a list of all {@link PropertySource} instances managed by the current
-     * {@link org.apache.tamaya.spi.ConfigurationContext} that are assignable to the given type.
-     *
-     * @param <T> the type of the property source instances requested 
-     * @param type target type to filter for property sources. 
-     * @return the list of all {@link PropertySource} instances matching, never null.
-     */
-    public static <T> Collection<T> getPropertySources(Class<T> type) {
-        List<T> result = new ArrayList<>();
-        for (PropertySource src : ConfigurationProvider.getConfigurationContext().getPropertySources()) {
-            if (type.isAssignableFrom(src.getClass())) {
-                result.add((T) src);
-            }
-        }
-        return result;
-    }
-
-    /**
-     * Get a list of all {@link PropertySource} instances managed by the current
-     * {@link org.apache.tamaya.spi.ConfigurationContext} that are assignable to the given type.
-     *
-     * @param <T> the type of the property source instances requested
-     * @param type target type to filter for property sources. 
-     * @return the list of all {@link PropertySource} instances matching, never null.
-     */
-    public static <T> T getPropertySource(Class<T> type) {
-        for (PropertySource src : ConfigurationProvider.getConfigurationContext().getPropertySources()) {
-            if (type.isAssignableFrom(src.getClass())) {
-                return (T) src;
-            }
-        }
-        return null;
-    }
-
-}

http://git-wip-us.apache.org/repos/asf/incubator-tamaya-extensions/blob/36b44661/modules/functions/src/main/java/org/apache/tamaya/functions/ValueMappedConfigSource.java
----------------------------------------------------------------------
diff --git a/modules/functions/src/main/java/org/apache/tamaya/functions/ValueMappedConfigSource.java b/modules/functions/src/main/java/org/apache/tamaya/functions/ValueMappedConfigSource.java
new file mode 100644
index 0000000..dd23c66
--- /dev/null
+++ b/modules/functions/src/main/java/org/apache/tamaya/functions/ValueMappedConfigSource.java
@@ -0,0 +1,75 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.tamaya.functions;
+
+import org.apache.tamaya.base.configsource.ConfigSourceComparator;
+
+import javax.config.spi.ConfigSource;
+import java.util.*;
+
+
+/**
+ * Property source which filters any key/values dynamically.
+ */
+class ValueMappedConfigSource implements ConfigSource{
+
+    private final String name;
+    private final PropertyMapper valueFilter;
+    private final ConfigSource source;
+
+    public ValueMappedConfigSource(String name, PropertyMapper valueFilter, ConfigSource current) {
+        this.name =  name!=null?name:"<valueFiltered> -> name="+current.getName()+", valueFilter="+valueFilter.toString();
+        this.valueFilter = valueFilter;
+        this.source = Objects.requireNonNull(current);
+    }
+
+    @Override
+    public int getOrdinal() {
+        return ConfigSourceComparator.getOrdinal(source);
+    }
+
+    @Override
+    public String getName() {
+        return name;
+    }
+
+    @Override
+    public String getValue(String key) {
+        return this.source.getValue(key);
+    }
+
+    @Override
+    public Map<String, String> getProperties() {
+        Map<String,String> result = new HashMap<>();
+        for(Map.Entry<String,String> en: source.getProperties().entrySet()) {
+            String mappedValue = valueFilter.mapProperty(en.getKey(), en.getValue());
+            result.put(en.getKey(), mappedValue);
+        }
+        return result;
+    }
+
+    @Override
+    public String toString() {
+        return "ValueMappedConfigSource{" +
+                "source=" + source.getName() +
+                ", name='" + name + '\'' +
+                ", valueFilter=" + valueFilter +
+                '}';
+    }
+}

http://git-wip-us.apache.org/repos/asf/incubator-tamaya-extensions/blob/36b44661/modules/functions/src/main/java/org/apache/tamaya/functions/ValueMappedPropertySource.java
----------------------------------------------------------------------
diff --git a/modules/functions/src/main/java/org/apache/tamaya/functions/ValueMappedPropertySource.java b/modules/functions/src/main/java/org/apache/tamaya/functions/ValueMappedPropertySource.java
deleted file mode 100644
index dfb128f..0000000
--- a/modules/functions/src/main/java/org/apache/tamaya/functions/ValueMappedPropertySource.java
+++ /dev/null
@@ -1,86 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements.  See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership.  The ASF licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License.  You may obtain a copy of the License at
- *
- *   http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing,
- * software distributed under the License is distributed on an
- * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- * KIND, either express or implied.  See the License for the
- * specific language governing permissions and limitations
- * under the License.
- */
-package org.apache.tamaya.functions;
-
-import org.apache.tamaya.spi.PropertySource;
-import org.apache.tamaya.spi.PropertyValue;
-import org.apache.tamaya.spisupport.PropertySourceComparator;
-
-import java.util.*;
-
-
-/**
- * Property source which filters any key/values dynamically.
- */
-class ValueMappedPropertySource implements PropertySource{
-
-    private final String name;
-    private final PropertyMapper valueFilter;
-    private final PropertySource source;
-
-    public ValueMappedPropertySource(String name, PropertyMapper valueFilter, PropertySource current) {
-        this.name =  name!=null?name:"<valueFiltered> -> name="+current.getName()+", valueFilter="+valueFilter.toString();
-        this.valueFilter = valueFilter;
-        this.source = Objects.requireNonNull(current);
-    }
-
-    @Override
-    public int getOrdinal() {
-        return PropertySourceComparator.getOrdinal(source);
-    }
-
-    @Override
-    public String getName() {
-        return name;
-    }
-
-    @Override
-    public PropertyValue get(String key) {
-        PropertyValue value = this.source.get(key);
-        if(value!=null) {
-            return PropertyValue.of(key, valueFilter.mapProperty(key, value.getValue()), getName());
-        }
-        return null;
-    }
-
-    @Override
-    public Map<String, PropertyValue> getProperties() {
-        Map<String,PropertyValue> result = new HashMap<>();
-        for(PropertyValue val : source.getProperties().values()) {
-            String mappedValue = valueFilter.mapProperty(val.getKey(), val.getValue());
-            PropertyValue value = val.toBuilder().setValue(mappedValue).build();
-            result.put(val.getKey(), value);
-        }
-        return result;
-    }
-
-    @Override
-    public boolean isScannable() {
-        return source.isScannable();
-    }
-
-    @Override
-    public String toString() {
-        return "ValueMappedPropertySource{" +
-                "source=" + source.getName() +
-                ", name='" + name + '\'' +
-                ", valueFilter=" + valueFilter +
-                '}';
-    }
-}

http://git-wip-us.apache.org/repos/asf/incubator-tamaya-extensions/blob/36b44661/modules/functions/src/test/java/org/apache/tamaya/functions/CombinedConfigurationTest.java
----------------------------------------------------------------------
diff --git a/modules/functions/src/test/java/org/apache/tamaya/functions/CombinedConfigurationTest.java b/modules/functions/src/test/java/org/apache/tamaya/functions/CombinedConfigurationTest.java
index bb27ccd..432c5c0 100644
--- a/modules/functions/src/test/java/org/apache/tamaya/functions/CombinedConfigurationTest.java
+++ b/modules/functions/src/test/java/org/apache/tamaya/functions/CombinedConfigurationTest.java
@@ -20,7 +20,6 @@ package org.apache.tamaya.functions;
 
 import org.apache.tamaya.base.DefaultConfigBuilder;
 import org.apache.tamaya.base.configsource.SimpleConfigSource;
-import org.apache.tamaya.spisupport.DefaultConfiguration;
 import org.assertj.core.api.ThrowableAssert;
 import org.junit.Test;
 import org.mockito.Mockito;

http://git-wip-us.apache.org/repos/asf/incubator-tamaya-extensions/blob/36b44661/modules/functions/src/test/java/org/apache/tamaya/functions/ConfigSourceFunctionsTest.java
----------------------------------------------------------------------
diff --git a/modules/functions/src/test/java/org/apache/tamaya/functions/ConfigSourceFunctionsTest.java b/modules/functions/src/test/java/org/apache/tamaya/functions/ConfigSourceFunctionsTest.java
new file mode 100644
index 0000000..06734db
--- /dev/null
+++ b/modules/functions/src/test/java/org/apache/tamaya/functions/ConfigSourceFunctionsTest.java
@@ -0,0 +1,434 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.tamaya.functions;
+
+import org.apache.tamaya.base.configsource.SimpleConfigSource;
+import org.assertj.core.api.ThrowableAssert;
+import org.junit.Test;
+
+import javax.config.spi.ConfigSource;
+import java.util.HashMap;
+import java.util.Map;
+import java.util.Set;
+
+import static org.apache.tamaya.functions.ConfigSourceFunctions.*;
+import static org.assertj.core.api.Assertions.assertThat;
+import static org.assertj.core.api.Assertions.assertThatThrownBy;
+import static org.assertj.core.api.Assertions.entry;
+import static org.junit.Assert.*;
+
+
+public class ConfigSourceFunctionsTest {
+
+    /*
+     * Tests for isKeyInSection(String, String)
+     */
+
+    @Test
+    public void isKeyInSectionThrowsNPEIfKeyIsNull() {
+        assertThatThrownBy(new ThrowableAssert.ThrowingCallable() {
+            @Override
+            public void call() throws Throwable {
+                isKeyInSection("a.b.c", null);
+            }
+        }).isInstanceOf(NullPointerException.class)
+          .hasMessage("Section keys must be given.");
+    }
+
+    @Test
+    public void isKeyInSectionThrowsNPEIfSectionKeyIsNull() {
+        assertThatThrownBy(new ThrowableAssert.ThrowingCallable() {
+            @Override
+            public void call() throws Throwable {
+                isKeyInSection(null, "a.b.c");
+            }
+        }).isInstanceOf(NullPointerException.class)
+          .hasMessage("Key must be given.");
+    }
+
+    @Test
+    public void isKeyInSectionForKeyInRootSection() {
+        String key = "key";
+        String sectionKey = "";
+
+        boolean result = isKeyInSection(key, sectionKey);
+
+        assertThat(result).describedAs("Key '%s' is in root section '%s'")
+                          .isTrue();
+    }
+
+    @Test
+    public void isKeyInSectionForKeyInExplicitRootSection() {
+        String key = "key";
+        String sectionKey = ".";
+
+        boolean result = isKeyInSection(key, sectionKey);
+
+        assertThat(result).describedAs("Key '%s' is in root section '%s'")
+                          .isTrue();
+    }
+
+    @Test
+    public void isKeyInSectionForKeyInSection() throws Exception {
+        String key = "abc.def.g.h.key";
+        String section = "abc.def.g.h";
+
+        boolean result = isKeyInSection(key, section);
+
+        assertThat(result).describedAs("Key %s is in section %s", key, section)
+                          .isTrue();
+    }
+
+    @Test
+    public void isKeyInSectionForKeyNotInSection() throws Exception {
+        String key = "abc.def.g.h.i.key";
+        String section = "abc.def.g.h";
+
+        boolean result = isKeyInSection(key, section);
+
+        assertThat(result).describedAs("Key %s is not in section %s", key, section)
+                          .isFalse();
+    }
+
+    @Test
+    public void isKeyInSectionIgnoresTrailingDotAtTheEndOfTheSection() throws Exception {
+        String key = "abc.def.g.h.key";
+        String section = "abc.def.g.h.";
+
+        boolean result = isKeyInSection(key, section);
+
+        assertThat(result).describedAs("Key %s is in section %s", key, section)
+                          .isTrue();
+    }
+
+
+    /*
+     * Tests for isKeyInSection(String, String, String...)
+     */
+
+    @Test
+    public void isKeyInSectionsStringStringStringVarargThrowsNPEIfKeyIsNull() {
+        assertThatThrownBy(new ThrowableAssert.ThrowingCallable() {
+            @Override
+            public void call() throws Throwable {
+                ConfigSourceFunctions.isKeyInSection(null, "a.b.", "a.b", "b.c");
+            }
+        }).isInstanceOf(NullPointerException.class)
+          .hasMessage("Key must be given.");
+    }
+
+    @Test
+    public void isKeyInSectionStringStringStringVarargshrowsNPEIfMoreSectionKeysIsNull() {
+        // null should not cause any problems
+        boolean result = isKeyInSection("key", "l.b", (String) null);
+
+        assertThat(result).isFalse();
+    }
+
+    @Test
+    public void isKeyInSectionStringStringStringVaragrsSectioOfKeyIsAtEndOfVarargs() {
+        String section = "abc.def.";
+        String key = section + "key";
+
+        // null should not cause any problems
+        boolean result = ConfigSourceFunctions.isKeyInSection(key, "l.b", null, "abc", section);
+
+        assertThat(result).describedAs("Key '%s' is in section '%s'.", key, section).isTrue();
+    }
+
+
+    /*
+     * Tests for sections(Map<String, String>)
+     */
+
+    // null as parameter
+
+    // empty as parameter
+
+    // all keys in root section
+
+    // some keys in packages
+
+    @Test
+    public void sectionsMapReturnsAllSectionsForGivenKeysInMap() {
+        HashMap<String, String> kv = new HashMap<>();
+
+        kv.put("abc.key", "v");
+        kv.put("abc.def.key", "v");
+        kv.put("a.key", "v");
+        kv.put("b.key", "v");
+        kv.put("key", "v");
+
+        Set<String> result = sections(kv);
+
+        assertThat(result).isNotNull()
+                          .isNotEmpty()
+                          .contains("abc", "abc.def", "a", "b", "<root>");
+    }
+
+    @Test
+    public void sectionsMapTreatsLeadingDotAsOptional() {
+        HashMap<String, String> kv = new HashMap<>();
+
+        kv.put(".abc.key", "v");
+        kv.put(".abc.def.key", "v");
+        kv.put(".a.key", "v");
+        kv.put(".b.key", "v");
+        kv.put(".key", "v");
+
+        Set<String> result = sections(kv);
+
+        assertThat(result).isNotNull()
+                          .isNotEmpty()
+                          .contains("abc", "abc.def", "a", "b", "<root>");
+    }
+
+    /*
+     * Tests for sections(Map<String, String> , Predicate<String>)
+     */
+
+    @Test
+    public void sectionsMapPredicateFiltersAccordingToFilter() {
+        HashMap<String, String> kv = new HashMap<>();
+
+        kv.put(".abc.key", "v");
+        kv.put(".abc.def.key", "v");
+        kv.put(".a.key", "v");
+        kv.put(".b.key", "v");
+        kv.put(".key", "v");
+
+        Set<String> result = sections(kv, new Predicate<String>() {
+            @Override
+            public boolean test(String s) {
+                return !s.startsWith("a");
+            }
+        });
+
+        assertThat(result).isNotNull()
+                          .isNotEmpty()
+                          .contains("b", "<root>");
+    }
+
+    /*
+     * Tests for transitiveSections(Map<String, String>)
+     */
+
+    @Test
+    public void bla() {
+        HashMap<String, String> kv = new HashMap<>();
+
+        kv.put(".abc.key", "v");
+        kv.put(".abc.def.key", "v");
+        kv.put(".abc.def.ghi.key", "v");
+        kv.put(".a.key", "v");
+        kv.put(".b.key", "v");
+        kv.put(".key", "v");
+
+        Set<String> result = transitiveSections(kv);
+
+        for (String s : result) {
+            System.out.println(s);
+        }
+
+
+        assertThat(result).isNotNull()
+                          .isNotEmpty()
+                          .contains("abc", "abc.def", "a", "b", "<root>");
+
+
+    }
+
+
+    @Test
+    public void testIsKeyInSections() throws Exception {
+        SimpleConfigSource configSource = SimpleConfigSource.builder("test")
+                .withProperty("a", "1")
+                .withProperty("a.a.1", "1.1.1")
+                .withProperty("a.a.2", "1.1.2")
+                .withProperty("a.b", "1.2")
+                .withProperty("b", "2")
+                .build();
+
+        assertTrue(ConfigSourceFunctions.isKeyInSection("a.1", "a", "b"));
+        assertTrue(ConfigSourceFunctions.isKeyInSection("a.1", "b", "a"));
+        assertFalse(ConfigSourceFunctions.isKeyInSection("a.1", ""));
+        assertFalse(ConfigSourceFunctions.isKeyInSection("a.b.1", "a"));
+        assertTrue(ConfigSourceFunctions.isKeyInSection("a.b.1", "a.b"));
+        assertFalse(ConfigSourceFunctions.isKeyInSection("a.b.1", "", "a"));
+        assertTrue(ConfigSourceFunctions.isKeyInSection("a.b.1", "", "a.b"));
+        assertFalse(ConfigSourceFunctions.isKeyInSection("c.a",  "","c.a"));
+        assertFalse(ConfigSourceFunctions.isKeyInSection("a.3", "b"));
+    }
+
+
+    @Test
+    public void testTransitiveSections() throws Exception {
+        Map<String,String> sections = new HashMap<>();
+        sections.put("a.b.c.d.e", "1");
+        sections.put("a.x.y", "2");
+        sections.put("bb", "2");
+        Set<String> transitiveSections = ConfigSourceFunctions.transitiveSections(sections);
+        assertThat(transitiveSections)
+                .isNotNull()
+                .contains("a", "a.b", "a.b.c", "<root>");
+    }
+
+
+    @Test
+    public void testSectionsRecursive() throws Exception {
+        Map<String,String> sections = new HashMap<>();
+        sections.put("a.b.c.d.e", "1");
+        sections.put("a.x.y", "2");
+        sections.put("b.b", "2");
+        sections.put("bb", "2");
+        Map<String,String> recursiveSections = ConfigSourceFunctions.sectionsRecursive(sections, true,"a.b");
+        assertThat(recursiveSections)
+                .isNotNull()
+                .hasSize(1)
+                .contains(entry("c.d.e", "1"));
+        recursiveSections = ConfigSourceFunctions.sectionsRecursive(sections, true,"a");
+        assertThat(recursiveSections)
+                .isNotNull()
+                .hasSize(2)
+                .contains(entry("b.c.d.e", "1"), entry("x.y", "2"));
+        recursiveSections = ConfigSourceFunctions.sectionsRecursive(sections, true,"b");
+        assertThat(recursiveSections)
+                .isNotNull()
+                .hasSize(1)
+                .contains(entry("b", "2"));
+        recursiveSections = ConfigSourceFunctions.sectionsRecursive(sections, false,"a.b");
+        assertThat(recursiveSections)
+                .isNotNull()
+                .hasSize(1)
+                .contains(entry("a.b.c.d.e", "1"));
+        recursiveSections = ConfigSourceFunctions.sectionsRecursive(sections, false,"a");
+        assertThat(recursiveSections)
+                .isNotNull()
+                .hasSize(2)
+                .contains(entry("a.b.c.d.e", "1"), entry("a.x.y", "2"));
+        recursiveSections = ConfigSourceFunctions.sectionsRecursive(sections, false,"b");
+        assertThat(recursiveSections)
+                .isNotNull()
+                .hasSize(1)
+                .contains(entry("b.b", "2"));
+        recursiveSections = ConfigSourceFunctions.sectionsRecursive(sections, true,"b");
+        assertThat(recursiveSections)
+                .isNotNull()
+                .hasSize(1)
+                .contains(entry("b", "2"));
+    }
+
+    @Test
+    public void testStripSectionKeys() throws Exception {
+        String result = ConfigSourceFunctions.stripSectionKeys("a.b.c", new String[]{ "a.b", "a"});
+        assertThat(result)
+                .isNotNull().isEqualTo("c");
+        result = ConfigSourceFunctions.stripSectionKeys("a", new String[]{ "a"});
+        assertThat(result)
+                .isNotNull().isEqualTo("a");
+        result = ConfigSourceFunctions.stripSectionKeys("foo.bar", new String[]{ ""});
+        assertThat(result)
+                .isNotNull().isEqualTo("foo.bar");
+    }
+
+    @Test
+    public void testAddItems_Override_Default() throws Exception {
+        ConfigSource cs = SimpleConfigSource.builder("test")
+                .withProperty("a", "1")
+                .withProperty("b", "2")
+                .build();
+        Map<String, String> additions = new HashMap<>();
+        additions.put("b", "2-added");
+        additions.put("c", "3");
+        ConfigSource configSource = ConfigSourceFunctions.addItems(cs, additions);
+        assertNotNull(configSource);
+        assertThat(configSource.getPropertyNames())
+                .isNotNull()
+                .contains("a", "b", "c");
+        assertThat(configSource.getProperties())
+                .isNotNull()
+                .contains(entry("a", "1"), entry("b", "2"), entry("c", "3"));
+    }
+
+    @Test
+    public void testAddItemsOverride_Explicit() throws Exception {
+        ConfigSource cs = SimpleConfigSource.builder("test")
+                .withProperty("a", "1")
+                .withProperty("b", "2")
+                .build();
+        Map<String, String> additions = new HashMap<>();
+        additions.put("b", "2-added");
+        additions.put("c", "3");
+        ConfigSource configSource = ConfigSourceFunctions.addItems(cs, additions, true);
+        assertNotNull(configSource);
+        assertThat(configSource.getPropertyNames())
+                .isNotNull()
+                .contains("a", "b", "c");
+        assertThat(configSource.getProperties())
+                .isNotNull()
+                .contains(entry("a", "1"), entry("b", "2-added"), entry("c", "3"));
+    }
+
+    @Test
+    public void testAddItemsOverride_False() throws Exception {
+        ConfigSource cs = SimpleConfigSource.builder("test")
+                .withProperty("a", "1")
+                .withProperty("b", "2")
+                .build();
+        Map<String, String> additions = new HashMap<>();
+        additions.put("b", "2-added");
+        additions.put("c", "3");
+        ConfigSource configSource = ConfigSourceFunctions.addItems(cs, additions, false);
+        assertNotNull(configSource);
+        assertThat(configSource.getPropertyNames())
+                .isNotNull()
+                .contains("a", "b", "c");
+        assertThat(configSource.getProperties())
+                .isNotNull()
+                .contains(entry("a", "1"), entry("b", "2"), entry("c", "3"));
+    }
+
+    @Test
+    public void testReplaceItems() throws Exception {
+        ConfigSource cs = SimpleConfigSource.builder("test")
+                .withProperty("a", "1")
+                .withProperty("b", "2")
+                .build();
+        Map<String, String> replacements = new HashMap<>();
+        replacements.put("b", "2-added");
+        replacements.put("c", "3");
+        ConfigSource configSource = ConfigSourceFunctions.replaceItems(cs, replacements);
+        assertNotNull(configSource);
+        assertThat(configSource.getPropertyNames())
+                .isNotNull()
+                .contains("a", "b", "c");
+        assertThat(configSource.getProperties())
+                .isNotNull()
+                .contains(entry("a", "1"), entry("b", "2-added"), entry("c", "3"));
+    }
+
+    @Test
+    public void testEmptyPropertySource() throws Exception {
+        ConfigSource ps = ConfigSourceFunctions.emptyConfigSource();
+        assertThat(ps).isNotNull();
+        assertNotNull(ps.getProperties());
+        assertTrue(ps.getProperties().isEmpty());
+        assertEquals(ps.getName(), "<empty>" );
+    }
+}
\ No newline at end of file



Mime
View raw message