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/02/02 17:16:10 UTC

[1/8] incubator-tamaya git commit: TAMAYA-136: Adding PropertyValue for PropertySource SPI TAMAYA-137: Extending PropertyFilter SPI, added Experimental annotation.

Repository: incubator-tamaya
Updated Branches:
  refs/heads/master b6f5edf9e -> d778cb814


TAMAYA-136: Adding PropertyValue for PropertySource SPI
TAMAYA-137: Extending PropertyFilter SPI, added Experimental annotation.


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

Branch: refs/heads/master
Commit: 13f69dae9ee4c83ec1114a8d1cc8b9eadd7d36b7
Parents: b6f5edf
Author: anatole <an...@apache.org>
Authored: Tue Feb 2 10:18:42 2016 +0100
Committer: anatole <an...@apache.org>
Committed: Tue Feb 2 10:18:42 2016 +0100

----------------------------------------------------------------------
 .../org/apache/tamaya/spi/Experimental.java     |  33 ++++
 .../org/apache/tamaya/spi/FilterContext.java    | 173 +++++++++++++++++++
 .../org/apache/tamaya/spi/PropertyFilter.java   |   7 +-
 .../org/apache/tamaya/spi/PropertySource.java   |   7 +-
 .../org/apache/tamaya/spi/PropertyValue.java    |  73 ++++++++
 .../apache/tamaya/spi/PropertyValueBuilder.java | 106 ++++++++++++
 .../spi/PropertyValueCombinationPolicy.java     |   4 +-
 code/api/src/main/resources/banner.txt          |  11 --
 code/api/src/main/resources/tamaya-banner.txt   |  11 ++
 .../tamaya/spi/PropertyValueBuilderTest.java    |  65 +++++++
 .../apache/tamaya/spi/PropertyValueTest.java    |  51 ++++++
 11 files changed, 520 insertions(+), 21 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/incubator-tamaya/blob/13f69dae/code/api/src/main/java/org/apache/tamaya/spi/Experimental.java
----------------------------------------------------------------------
diff --git a/code/api/src/main/java/org/apache/tamaya/spi/Experimental.java b/code/api/src/main/java/org/apache/tamaya/spi/Experimental.java
new file mode 100644
index 0000000..dc3dfec
--- /dev/null
+++ b/code/api/src/main/java/org/apache/tamaya/spi/Experimental.java
@@ -0,0 +1,33 @@
+/*
+ * 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.spi;
+
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+
+/**
+ * This is a simple annotation for flaging out functionality or features the Tamaya team is not sure if it is already
+ * stabilized, so use it with some caution.
+ */
+@Retention(RetentionPolicy.SOURCE)
+@Target({ElementType.METHOD, ElementType.ANNOTATION_TYPE, ElementType.FIELD, ElementType.TYPE})
+public @interface Experimental {
+}

http://git-wip-us.apache.org/repos/asf/incubator-tamaya/blob/13f69dae/code/api/src/main/java/org/apache/tamaya/spi/FilterContext.java
----------------------------------------------------------------------
diff --git a/code/api/src/main/java/org/apache/tamaya/spi/FilterContext.java b/code/api/src/main/java/org/apache/tamaya/spi/FilterContext.java
new file mode 100644
index 0000000..8371df7
--- /dev/null
+++ b/code/api/src/main/java/org/apache/tamaya/spi/FilterContext.java
@@ -0,0 +1,173 @@
+/*
+ * 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.spi;
+
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.Map;
+import java.util.Objects;
+
+/**
+ * A conversion context containing all the required values for implementing conversion. Use the included #Builder
+ * for creating new instances of. This class is thread-safe to use. Adding supported formats is synchronized.
+ *
+ * @see PropertyConverter
+ */
+public class FilterContext {
+
+    private final String key;
+    @org.apache.tamaya.Experimental
+    private Map<String, String> metaEntries = new HashMap();
+
+    /**
+     * Private constructor used from builder.
+     *
+     * @param builder the builder, not null.
+     */
+    protected FilterContext(Builder builder) {
+        this.key = builder.key;
+        this.metaEntries.putAll(builder.metaEntries);
+    }
+
+    /**
+     * Get the key accessed. This information is very useful to evaluate additional metadata needed to determine/
+     * control further aspects of the conversion.
+     *
+     * @return the key. This may be null in case where a default value has to be converted and no unique underlying
+     * key/value configuration is present..
+     */
+    public String getKey() {
+        return key;
+    }
+
+    /**
+     * This map contains the following keys:
+     * <ul>
+     * <li>the original value <b>before</b> any filters were applied on it.</li>
+     * <li>all values starting with an {@code _<key>.}. for example {@code a.value}</li>
+     * may have a map set with {@code a.value} (oringinal value), {@code _a.value.origin,
+     * _a.value.type, etc}. The exact contents is determine by the {@link PropertySource}s
+     * active.
+     * </ul>
+     * Also important to know is that this map given contains all the evaluated raw entries, regardless
+     * of the filters that are later applied. This ensures that met-information required by one filter is
+     * not hidden by another filter, because of an invalid filter ordering. In other words filters may remove
+     * key/value pairs, e.g. fir security reasons, by returning {@code null}, but the values in the raw map
+     * passed as input to the filter process will not be affected by any such removal (but the final properties
+     * returned are affected, of course).
+     * <p/>
+     * Finally, when a single property is accessed, e.g. by calling {@code Configuration.get(String)}.
+     *
+     * @return the configuration instance, or null.
+     */
+    @org.apache.tamaya.Experimental
+    public Map<String, String> getMetaEntries() {
+        return metaEntries;
+    }
+
+    /**
+     * Property to check, if the entry filtered is actually accessed as single value, or as part of a full Map
+     * access. For both scenarios filtering may be different.
+     * @return true, if it is a directly accessed key.
+     */
+    @org.apache.tamaya.Experimental
+    public boolean isSingleAccessedProperty(){
+        return this.metaEntries.size()==1;
+    }
+
+    @Override
+    public String toString() {
+        return "FilterContext{" +
+                "key='" + key + '\'' +
+                ", metaEntries=" + metaEntries +
+                '}';
+    }
+
+    /**
+     * Builder to create new instances of {@link FilterContext}.
+     */
+    public static final class Builder {
+        /**
+         * The accessed key, or null.
+         */
+        private String key;
+        private Map<String, String> metaEntries = new HashMap();
+
+        /**
+         * Creates a new Builder instance.
+         *
+         * @param key the requested key, may be null.
+         */
+        public Builder(String key, String value) {
+            this(key, Collections.<String, String>emptyMap());
+            metaEntries.put(key, value);
+        }
+
+        /**
+         * Creates a new Builder instance.
+         *
+         * @param metaData the configuration, not null.
+         * @param key      the requested key, may be null.
+         */
+        public Builder(String key, Map<String, String> metaData) {
+            this.key = key;
+            this.metaEntries.putAll(metaData);
+        }
+
+        /**
+         * Sets the key.
+         *
+         * @param key the key, not null.
+         * @return the builder instance, for chaining
+         */
+        public Builder setKey(String key) {
+            this.key = Objects.requireNonNull(key);
+            return this;
+        }
+
+        /**
+         * Sets the configuration.
+         *
+         * @param metaProperties the meta configuration, not null
+         * @return the builder instance, for chaining
+         */
+        public Builder setMetaProperties(Map<String, String> metaProperties) {
+            this.metaEntries.putAll(Objects.requireNonNull(metaProperties));
+            return this;
+        }
+
+        /**
+         * Builds a new context instance.
+         *
+         * @return a new context, never null.
+         */
+        public FilterContext build() {
+            return new FilterContext(this);
+        }
+
+
+        @Override
+        public String toString() {
+            return "Builder{" +
+                    "key='" + key + '\'' +
+                    ", metaEntries=" + metaEntries +
+                    '}';
+        }
+    }
+}

http://git-wip-us.apache.org/repos/asf/incubator-tamaya/blob/13f69dae/code/api/src/main/java/org/apache/tamaya/spi/PropertyFilter.java
----------------------------------------------------------------------
diff --git a/code/api/src/main/java/org/apache/tamaya/spi/PropertyFilter.java b/code/api/src/main/java/org/apache/tamaya/spi/PropertyFilter.java
index 55f4295..1ecc88a 100644
--- a/code/api/src/main/java/org/apache/tamaya/spi/PropertyFilter.java
+++ b/code/api/src/main/java/org/apache/tamaya/spi/PropertyFilter.java
@@ -39,11 +39,10 @@ public interface PropertyFilter {
      *     <li>reentrant</li>
      *     <li>thread-safe</li>
      * </ul>
-     *
-     * @param key the key accessed, not null.
-     * @param valueToBeFiltered the value to be filtered, not null.
+     * @param value the value to be filtered, which also can be {@code null} if removed by another filter.
+     * @param context the filter context, not null.
      * @return the filtered value, or {@code null} if the value should be removed alltogether.
      */
-    String filterProperty(String key, String valueToBeFiltered);
+    String filterProperty(String value, FilterContext context);
 
 }

http://git-wip-us.apache.org/repos/asf/incubator-tamaya/blob/13f69dae/code/api/src/main/java/org/apache/tamaya/spi/PropertySource.java
----------------------------------------------------------------------
diff --git a/code/api/src/main/java/org/apache/tamaya/spi/PropertySource.java b/code/api/src/main/java/org/apache/tamaya/spi/PropertySource.java
index 2ec280b..14765eb 100644
--- a/code/api/src/main/java/org/apache/tamaya/spi/PropertySource.java
+++ b/code/api/src/main/java/org/apache/tamaya/spi/PropertySource.java
@@ -91,18 +91,17 @@ public interface PropertySource {
     /**
      * Access a property.
      *
-     * //X TODO discuss if the key can be null
      * @param key the property's key, not null.
-     * @return the property's keys.
+     * @return the property value, including also its metadata. In case a value is null it is valid to return
+     * {#code null} here.
      */
-    String get(String key);
+    PropertyValue get(String key);
 
     /**
      * Access the current properties as Map. The resulting Map may not return all items accessible, e.g.
      * when the underlying storage does not support iteration of its entries.
      *
      * @return the a corresponding map, never null.
-     * //X TODO or should we just do getPropertyKeys()? Think about security (key) vs easier merging (full map)?
      */
     Map<String,String> getProperties();
 

http://git-wip-us.apache.org/repos/asf/incubator-tamaya/blob/13f69dae/code/api/src/main/java/org/apache/tamaya/spi/PropertyValue.java
----------------------------------------------------------------------
diff --git a/code/api/src/main/java/org/apache/tamaya/spi/PropertyValue.java b/code/api/src/main/java/org/apache/tamaya/spi/PropertyValue.java
new file mode 100644
index 0000000..5529005
--- /dev/null
+++ b/code/api/src/main/java/org/apache/tamaya/spi/PropertyValue.java
@@ -0,0 +1,73 @@
+/*
+ * 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.spi;
+
+import java.util.HashMap;
+import java.util.Map;
+
+/**
+ * Class modelling the result of a request for a property value.
+ */
+public final class PropertyValue {
+    /** The requested key. */
+    private String key;
+    /** The value found. */
+    private String value;
+    /** Additional metadata provided by thhe provider. */
+    private Map<String,String> contextData;
+
+    PropertyValue(PropertyValueBuilder builder){
+        this.key = builder.key;
+        this.value = builder.value;
+        if(builder.contextData!=null) {
+            this.contextData = new HashMap<>(builder.contextData);
+        }
+    }
+
+    /**
+     * The requested key.
+     * @return the, key never null.
+     */
+    public String getKey() {
+        return key;
+    }
+
+    /**
+     * THe value.
+     * @return the value, in case a value is null it is valid to return {#code null} as result for
+     * {@link PropertySource#get(String)}.
+     */
+    public String getValue() {
+        return value;
+    }
+
+    public Map<String, String> getContextData() {
+        return contextData;
+    }
+
+    /**
+     * Creates a new builder instance.
+     * @param key the key, not null.
+     * @param value the value.
+     * @return a new builder instance.
+     */
+    public static PropertyValueBuilder builder(String key, String value){
+        return new PropertyValueBuilder(key, value);
+    }
+}

http://git-wip-us.apache.org/repos/asf/incubator-tamaya/blob/13f69dae/code/api/src/main/java/org/apache/tamaya/spi/PropertyValueBuilder.java
----------------------------------------------------------------------
diff --git a/code/api/src/main/java/org/apache/tamaya/spi/PropertyValueBuilder.java b/code/api/src/main/java/org/apache/tamaya/spi/PropertyValueBuilder.java
new file mode 100644
index 0000000..d75130b
--- /dev/null
+++ b/code/api/src/main/java/org/apache/tamaya/spi/PropertyValueBuilder.java
@@ -0,0 +1,106 @@
+/*
+ * 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.spi;
+
+import java.util.HashMap;
+import java.util.Map;
+import java.util.Objects;
+
+/**
+ * Builder to create a {@link PropertyValue} instance.
+ */
+public class PropertyValueBuilder {
+    /** The key accessed. */
+    String key;
+    /** The property value. */
+    String value;
+    /** additional metadata entries (optional). */
+    Map<String,String> contextData;
+
+    /**
+     * Create a new builder instance, for a given
+     * @param value the value, not null. If a value is null {@link PropertySource#get(String)} should return
+     * {@code null}.
+     */
+    public PropertyValueBuilder(String key, String value) {
+        this.key = Objects.requireNonNull(key);
+        this.value = Objects.requireNonNull(value);
+    }
+
+    /**
+     * Replaces/sets the context data.
+     * @param contextData the context data to be applied, not null. Note that all keys should only identify the context
+     *                    data item. the builder does create a corresponding metadata entry, e.g.
+     *                    <pre>
+     *                    provider=myProviderName
+     *                    ttl=250
+     *                    creationIndex=1
+     *                    modificationIndex=23
+     *                    </pre>
+     *                    will be mapped, given a key {@code test.env.name} to
+     *                    <pre>
+     *                    _test.env.name.provider=myProviderName
+     *                    _test.env.name.ttl=250
+     *                    _test.env.name.creationIndex=1
+     *                    _test.env.name.modificationIndex=23
+     *                    </pre>
+     * @return the builder for chaining.
+     */
+    public PropertyValueBuilder setContextData(Map<String, String> contextData) {
+        if(this.contextData==null){
+            this.contextData = new HashMap<>();
+        } else{
+            this.contextData.clear();
+        }
+        for(Map.Entry<String,String> en:contextData.entrySet()) {
+            this.contextData.put("_"+this.key+'.'+en.getKey(), en.getValue());
+        }
+        return this;
+    }
+
+    /**
+     * Add an additional context data information.
+     * @param key the context data key, not null.
+     * @param value the context value, not null (will be converted to String).
+     * @return the builder for chaining.
+     */
+    public PropertyValueBuilder addContextData(String key, Object value) {
+        if(this.contextData==null){
+            this.contextData = new HashMap<>();
+        }
+        this.contextData.put("_"+this.key+'.'+key, String.valueOf(Objects.requireNonNull(value)));
+        return this;
+    }
+
+    /**
+     * Creates a new immutable {@link PropertyValue}.
+     * @return a new immutable {@link PropertyValue}, never null.
+     */
+    public PropertyValue build(){
+        return new PropertyValue(this);
+    }
+
+    @Override
+    public String toString() {
+        return "PropertyValueBuilder{" +
+                "value='" + value + '\'' +
+                ", contextData=" + contextData +
+                '}';
+    }
+}

http://git-wip-us.apache.org/repos/asf/incubator-tamaya/blob/13f69dae/code/api/src/main/java/org/apache/tamaya/spi/PropertyValueCombinationPolicy.java
----------------------------------------------------------------------
diff --git a/code/api/src/main/java/org/apache/tamaya/spi/PropertyValueCombinationPolicy.java b/code/api/src/main/java/org/apache/tamaya/spi/PropertyValueCombinationPolicy.java
index 45292fc..11726f5 100644
--- a/code/api/src/main/java/org/apache/tamaya/spi/PropertyValueCombinationPolicy.java
+++ b/code/api/src/main/java/org/apache/tamaya/spi/PropertyValueCombinationPolicy.java
@@ -35,8 +35,8 @@ public interface PropertyValueCombinationPolicy {
 
         @Override
         public String collect(String currentValue, String key, PropertySource propertySource) {
-            String value = propertySource.get(key);
-            return value!=null?value:currentValue;
+            PropertyValue value = propertySource.get(key);
+            return value!=null?value.getValue():currentValue;
         }
 
     };

http://git-wip-us.apache.org/repos/asf/incubator-tamaya/blob/13f69dae/code/api/src/main/resources/banner.txt
----------------------------------------------------------------------
diff --git a/code/api/src/main/resources/banner.txt b/code/api/src/main/resources/banner.txt
deleted file mode 100644
index b4ceca4..0000000
--- a/code/api/src/main/resources/banner.txt
+++ /dev/null
@@ -1,11 +0,0 @@
-
- █████╗ ██████╗  █████╗  ██████╗██╗  ██╗███████╗    ████████╗ █████╗ ███╗   ███╗ █████╗ ██╗   ██╗ █████╗
-██╔══██╗██╔══██╗██╔══██╗██╔════╝██║  ██║██╔════╝    ╚══██╔══╝██╔══██╗████╗ ████║██╔══██╗╚██╗ ██╔╝██╔══██╗
-███████║██████╔╝███████║██║     ███████║█████╗         ██║   ███████║██╔████╔██║███████║ ╚████╔╝ ███████║
-██╔══██║██╔═══╝ ██╔══██║██║     ██╔══██║██╔══╝         ██║   ██╔══██║██║╚██╔╝██║██╔══██║  ╚██╔╝  ██╔══██║
-██║  ██║██║     ██║  ██║╚██████╗██║  ██║███████╗       ██║   ██║  ██║██║ ╚═╝ ██║██║  ██║   ██║   ██║  ██║
-╚═╝  ╚═╝╚═╝     ╚═╝  ╚═╝ ╚═════╝╚═╝  ╚═╝╚══════╝       ╚═╝   ╚═╝  ╚═╝╚═╝     ╚═╝╚═╝  ╚═╝   ╚═╝   ╚═╝  ╚═╝
-
-Apache Tamaya Configuration API:  http://tamaya.incubator.apache.org
-
-

http://git-wip-us.apache.org/repos/asf/incubator-tamaya/blob/13f69dae/code/api/src/main/resources/tamaya-banner.txt
----------------------------------------------------------------------
diff --git a/code/api/src/main/resources/tamaya-banner.txt b/code/api/src/main/resources/tamaya-banner.txt
new file mode 100644
index 0000000..b4ceca4
--- /dev/null
+++ b/code/api/src/main/resources/tamaya-banner.txt
@@ -0,0 +1,11 @@
+
+ █████╗ ██████╗  █████╗  ██████╗██╗  ██╗███████╗    ████████╗ █████╗ ███╗   ███╗ █████╗ ██╗   ██╗ █████╗
+██╔══██╗██╔══██╗██╔══██╗██╔════╝██║  ██║██╔════╝    ╚══██╔══╝██╔══██╗████╗ ████║██╔══██╗╚██╗ ██╔╝██╔══██╗
+███████║██████╔╝███████║██║     ███████║█████╗         ██║   ███████║██╔████╔██║███████║ ╚████╔╝ ███████║
+██╔══██║██╔═══╝ ██╔══██║██║     ██╔══██║██╔══╝         ██║   ██╔══██║██║╚██╔╝██║██╔══██║  ╚██╔╝  ██╔══██║
+██║  ██║██║     ██║  ██║╚██████╗██║  ██║███████╗       ██║   ██║  ██║██║ ╚═╝ ██║██║  ██║   ██║   ██║  ██║
+╚═╝  ╚═╝╚═╝     ╚═╝  ╚═╝ ╚═════╝╚═╝  ╚═╝╚══════╝       ╚═╝   ╚═╝  ╚═╝╚═╝     ╚═╝╚═╝  ╚═╝   ╚═╝   ╚═╝  ╚═╝
+
+Apache Tamaya Configuration API:  http://tamaya.incubator.apache.org
+
+

http://git-wip-us.apache.org/repos/asf/incubator-tamaya/blob/13f69dae/code/api/src/test/java/org/apache/tamaya/spi/PropertyValueBuilderTest.java
----------------------------------------------------------------------
diff --git a/code/api/src/test/java/org/apache/tamaya/spi/PropertyValueBuilderTest.java b/code/api/src/test/java/org/apache/tamaya/spi/PropertyValueBuilderTest.java
new file mode 100644
index 0000000..7c8f349
--- /dev/null
+++ b/code/api/src/test/java/org/apache/tamaya/spi/PropertyValueBuilderTest.java
@@ -0,0 +1,65 @@
+/*
+ * 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.spi;
+
+import org.junit.Test;
+
+import java.util.HashMap;
+import java.util.Map;
+
+import static org.junit.Assert.*;
+
+/**
+ * Created by atsticks on 02.02.16.
+ */
+public class PropertyValueBuilderTest {
+
+    @Test
+    public void testSetContextData() throws Exception {
+        PropertyValueBuilder b = new PropertyValueBuilder("k", "v");
+        Map<String,String> context = new HashMap<>();
+        context.put("source", "testSetContextData");
+        context.put("ts", String.valueOf(System.currentTimeMillis()));
+        context.put("y", "yValue");
+        b.setContextData(new HashMap<String, String>());
+        b.setContextData(context);
+        context.remove("y");
+        b.setContextData(context);
+        Map<String,String> contextData = b.build().getContextData();
+        assertEquals(contextData.size(), context.size());
+        assertEquals(contextData.get("_k.source"), "testSetContextData");
+        assertNotNull(contextData.get("_k.ts"));
+        assertNull(contextData.get("_k.y"));
+    }
+
+    @Test
+    public void testAddContextData() throws Exception {
+        PropertyValueBuilder b = new PropertyValueBuilder("k", "v");
+        b.addContextData("source", "testAddContextData");
+        b.addContextData("ts", System.currentTimeMillis());
+        b.addContextData("y", "yValue");
+        b.addContextData("y", "y2");
+        Map<String,String> contextData = b.build().getContextData();
+        assertEquals(contextData.size(), 3);
+        assertEquals(contextData.get("_k.source"), "testAddContextData");
+        assertNotNull(contextData.get("_k.ts"));
+        assertEquals(contextData.get("_k.y"), "y2");
+    }
+
+}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/incubator-tamaya/blob/13f69dae/code/api/src/test/java/org/apache/tamaya/spi/PropertyValueTest.java
----------------------------------------------------------------------
diff --git a/code/api/src/test/java/org/apache/tamaya/spi/PropertyValueTest.java b/code/api/src/test/java/org/apache/tamaya/spi/PropertyValueTest.java
new file mode 100644
index 0000000..48fd23f
--- /dev/null
+++ b/code/api/src/test/java/org/apache/tamaya/spi/PropertyValueTest.java
@@ -0,0 +1,51 @@
+/*
+ * 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.spi;
+
+import org.junit.Test;
+
+import static org.junit.Assert.*;
+
+/**
+ * Created by atsticks on 02.02.16.
+ */
+public class PropertyValueTest {
+
+    @Test
+    public void testGetKey() throws Exception {
+        PropertyValue pv = PropertyValue.builder("k", "v").build();
+        assertEquals("k", pv.getKey());
+    }
+
+    @Test
+    public void testGetValue() throws Exception {
+        PropertyValue pv = PropertyValue.builder("k", "v").build();
+        assertEquals("v", pv.getValue());
+    }
+
+    @Test
+    public void testGetContextData() throws Exception {
+        PropertyValue pv = PropertyValue.builder("k", "v")
+                .addContextData("k", "v2").build();
+        assertEquals("v", pv.getValue());
+        assertEquals("k", pv.getKey());
+        assertEquals("v2", pv.getContextData().get("_k.k"));
+    }
+
+}
\ No newline at end of file


[7/8] incubator-tamaya git commit: TAMAYA-136: Adding PropertyValue for PropertySource SPI. All changes and test fixes in all modules/examples relevant for release.

Posted by an...@apache.org.
http://git-wip-us.apache.org/repos/asf/incubator-tamaya/blob/d778cb81/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
index 79b0844..3f85f53 100644
--- a/modules/functions/src/main/java/org/apache/tamaya/functions/MappedPropertySource.java
+++ b/modules/functions/src/main/java/org/apache/tamaya/functions/MappedPropertySource.java
@@ -19,6 +19,7 @@
 package org.apache.tamaya.functions;
 
 import org.apache.tamaya.spi.PropertySource;
+import org.apache.tamaya.spi.PropertyValue;
 
 import java.util.HashMap;
 import java.util.Map;
@@ -80,8 +81,8 @@ class MappedPropertySource implements PropertySource {
     }
 
     @Override
-    public String get(String key) {
-        return getProperties().get(key);
+    public PropertyValue get(String key) {
+        return PropertyValue.of(key, getProperties().get(key), getName());
     }
 
 }
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/incubator-tamaya/blob/d778cb81/modules/functions/src/main/java/org/apache/tamaya/functions/MetaEnrichedPropertySource.java
----------------------------------------------------------------------
diff --git a/modules/functions/src/main/java/org/apache/tamaya/functions/MetaEnrichedPropertySource.java b/modules/functions/src/main/java/org/apache/tamaya/functions/MetaEnrichedPropertySource.java
deleted file mode 100644
index 42b5957..0000000
--- a/modules/functions/src/main/java/org/apache/tamaya/functions/MetaEnrichedPropertySource.java
+++ /dev/null
@@ -1,91 +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 java.util.HashMap;
-import java.util.Map;
-import java.util.Objects;
-
-/**
- * Configuration that filters part of the entries defined by a filter predicate.
- */
-class MetaEnrichedPropertySource implements PropertySource {
-
-    private final PropertySource basePropertySource;
-    private final Map<String, String> metaInfo;
-
-    MetaEnrichedPropertySource(PropertySource basePropertySource, Map<String, String> metaInfo) {
-        this.basePropertySource = Objects.requireNonNull(basePropertySource);
-        this.metaInfo = Objects.requireNonNull(metaInfo);
-    }
-
-    // [meta:origin]a.b.c
-    @Override
-    public String get(String key) {
-        if(key.startsWith("[meta:")){
-            key = key.substring(6);
-            int index = key.indexOf(']');
-            String metaKey = key.substring(0,index);
-            String entryKey = key.substring(index+1);
-            String value =  basePropertySource.get(entryKey);
-            if(value!=null) {
-                return metaInfo.get(metaKey);
-            }
-        }
-        return basePropertySource.get(key);
-    }
-
-    @Override
-    public int getOrdinal() {
-        return basePropertySource.getOrdinal();
-    }
-
-    @Override
-    public String getName() {
-        return basePropertySource.getName();
-    }
-
-    @Override
-    public Map<String, String> getProperties() {
-        Map<String, String> baseProperties = basePropertySource.getProperties();
-        Map<String, String> allProperties = new HashMap<>(baseProperties);
-        for(Map.Entry<String,String> en: baseProperties.entrySet()) {
-            for (Map.Entry<String, String> miEn : metaInfo.entrySet()) {
-                allProperties.put("[meta:" + miEn.getKey() + ']' + en.getKey(), miEn.getValue());
-            }
-        }
-        return allProperties;
-    }
-
-    @Override
-    public boolean isScannable() {
-        return basePropertySource.isScannable();
-    }
-
-    @Override
-    public String toString() {
-        return "MetaEnrichedPropertySource{" +
-                "basePropertySource=" + basePropertySource +
-                ", metaInfo=" + metaInfo +
-                '}';
-    }
-
-}

http://git-wip-us.apache.org/repos/asf/incubator-tamaya/blob/d778cb81/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
index 11aa58c..23de455 100644
--- a/modules/functions/src/main/java/org/apache/tamaya/functions/PropertySourceFunctions.java
+++ b/modules/functions/src/main/java/org/apache/tamaya/functions/PropertySourceFunctions.java
@@ -20,6 +20,7 @@ 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.ArrayList;
 import java.util.Collection;
@@ -50,7 +51,7 @@ public final class PropertySourceFunctions {
         }
 
         @Override
-        public String get(String key) {
+        public PropertyValue get(String key) {
             return null;
         }
 
@@ -77,40 +78,6 @@ public final class PropertySourceFunctions {
     }
 
     /**
-     * Creates a ConfigOperator that creates a Configuration containing only keys
-     * that are contained in the given section (non recursive). Hereby
-     * the section key is stripped away fromMap the resulting key.
-     * <p>
-     * Metadata is added only for keys that are present on the original configuration.
-     * They are added in the following format:
-     * <pre>
-     *     Given are
-     *       1) a configuration with two entries: entry1, entry 2
-     *       2) metadata as metaKey1=metaValue1, metaKey2=metaValue2
-     *
-     * The final configuration will look like:
-     *
-     *     entry1=entry1Value;
-     *     entry2=entry2Value;
-     *     [meta:metaKey1]entry1=metaValue1
-     *     [meta:metaKey2]entry1=metaValue2
-     *     [meta:metaKey1]entry2=metaValue1
-     *     [meta:metaKey2]entry2=metaValue2
-     * </pre>
-     * <p>
-     * This mechanism allows to add meta information such as origin, sensitivity, to all keys of a current
-     * PropertySource or Configuration. If done on multiple PropertySources that are combined the corresponding
-     * values are visible in synch with the values visible.
-     *
-     * @param propertySource the base propertySource, not null.
-     * @param metaData       the metaData to be added, not null
-     * @return the metadata enriched configuration, not null.
-     */
-    public static PropertySource addMetaData(PropertySource propertySource, Map<String, String> metaData) {
-        return new MetaEnrichedPropertySource(propertySource, metaData);
-    }
-
-    /**
      * Calculates the current section key and compares it with the given key.
      *
      * @param key        the fully qualified entry key, not null

http://git-wip-us.apache.org/repos/asf/incubator-tamaya/blob/d778cb81/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
index b0e9db8..a06b8b6 100644
--- a/modules/functions/src/main/java/org/apache/tamaya/functions/ValueMappedPropertySource.java
+++ b/modules/functions/src/main/java/org/apache/tamaya/functions/ValueMappedPropertySource.java
@@ -19,6 +19,7 @@
 package org.apache.tamaya.functions;
 
 import org.apache.tamaya.spi.PropertySource;
+import org.apache.tamaya.spi.PropertyValue;
 
 import java.util.HashMap;
 import java.util.Map;
@@ -51,10 +52,10 @@ class ValueMappedPropertySource implements PropertySource{
     }
 
     @Override
-    public String get(String key) {
-        String value = this.source.get(key);
+    public PropertyValue get(String key) {
+        PropertyValue value = this.source.get(key);
         if(value!=null) {
-            return valueFilter.mapProperty(key, value);
+            return PropertyValue.of(key, valueFilter.mapProperty(key, value.getValue()), getName());
         }
         return null;
     }

http://git-wip-us.apache.org/repos/asf/incubator-tamaya/blob/d778cb81/modules/injection/src/test/java/org/apache/tamaya/inject/TestPropertySource.java
----------------------------------------------------------------------
diff --git a/modules/injection/src/test/java/org/apache/tamaya/inject/TestPropertySource.java b/modules/injection/src/test/java/org/apache/tamaya/inject/TestPropertySource.java
index b58d8a4..ff5d0fd 100644
--- a/modules/injection/src/test/java/org/apache/tamaya/inject/TestPropertySource.java
+++ b/modules/injection/src/test/java/org/apache/tamaya/inject/TestPropertySource.java
@@ -19,6 +19,7 @@
 package org.apache.tamaya.inject;
 
 import org.apache.tamaya.spi.PropertySource;
+import org.apache.tamaya.spi.PropertyValue;
 
 import java.util.HashMap;
 import java.util.Map;
@@ -48,8 +49,8 @@ public class TestPropertySource implements PropertySource {
     }
 
     @Override
-    public String get(String key) {
-        return properties.get(key);
+    public PropertyValue get(String key) {
+        return PropertyValue.of(key,properties.get(key),getName());
     }
 
     @Override

http://git-wip-us.apache.org/repos/asf/incubator-tamaya/blob/d778cb81/modules/injection/src/test/java/org/apache/tamaya/inject/internal/DefaultDynamicValueTest.java
----------------------------------------------------------------------
diff --git a/modules/injection/src/test/java/org/apache/tamaya/inject/internal/DefaultDynamicValueTest.java b/modules/injection/src/test/java/org/apache/tamaya/inject/internal/DefaultDynamicValueTest.java
index 84f1f27..dd16f36 100644
--- a/modules/injection/src/test/java/org/apache/tamaya/inject/internal/DefaultDynamicValueTest.java
+++ b/modules/injection/src/test/java/org/apache/tamaya/inject/internal/DefaultDynamicValueTest.java
@@ -28,6 +28,7 @@ import org.apache.tamaya.inject.api.UpdatePolicy;
 import org.apache.tamaya.spi.ConversionContext;
 import org.apache.tamaya.spi.PropertyConverter;
 import org.apache.tamaya.spi.PropertySource;
+import org.apache.tamaya.spi.PropertyValue;
 import org.junit.Test;
 
 import org.apache.tamaya.Configuration;
@@ -78,8 +79,8 @@ public class DefaultDynamicValueTest {
                 }
 
                 @Override
-                public String get(String key) {
-                    return properties.get(key);
+                public PropertyValue get(String key) {
+                    return PropertyValue.of(key,properties.get(key),getName());
                 }
 
                 @Override

http://git-wip-us.apache.org/repos/asf/incubator-tamaya/blob/d778cb81/modules/integration/cdi-se/src/test/java/org/apache/tamaya/integration/cdi/cfg/ProvidedPropertySource.java
----------------------------------------------------------------------
diff --git a/modules/integration/cdi-se/src/test/java/org/apache/tamaya/integration/cdi/cfg/ProvidedPropertySource.java b/modules/integration/cdi-se/src/test/java/org/apache/tamaya/integration/cdi/cfg/ProvidedPropertySource.java
index 1c383b4..f7e3c6d 100644
--- a/modules/integration/cdi-se/src/test/java/org/apache/tamaya/integration/cdi/cfg/ProvidedPropertySource.java
+++ b/modules/integration/cdi-se/src/test/java/org/apache/tamaya/integration/cdi/cfg/ProvidedPropertySource.java
@@ -20,6 +20,7 @@
 package org.apache.tamaya.integration.cdi.cfg;
 
 import org.apache.tamaya.spi.PropertySource;
+import org.apache.tamaya.spi.PropertyValue;
 
 import javax.enterprise.inject.Vetoed;
 import java.util.HashMap;
@@ -50,8 +51,8 @@ class ProvidedPropertySource implements PropertySource{
     }
 
     @Override
-    public String get(String key) {
-        return config.get(key);
+    public PropertyValue get(String key) {
+        return PropertyValue.of(key, config.get(key), getName());
     }
 
     @Override

http://git-wip-us.apache.org/repos/asf/incubator-tamaya/blob/d778cb81/modules/integration/cdi-se/src/test/java/org/apache/tamaya/integration/cdi/cfg/TestPropertySource.java
----------------------------------------------------------------------
diff --git a/modules/integration/cdi-se/src/test/java/org/apache/tamaya/integration/cdi/cfg/TestPropertySource.java b/modules/integration/cdi-se/src/test/java/org/apache/tamaya/integration/cdi/cfg/TestPropertySource.java
index 1db3d2c..75c55ca 100644
--- a/modules/integration/cdi-se/src/test/java/org/apache/tamaya/integration/cdi/cfg/TestPropertySource.java
+++ b/modules/integration/cdi-se/src/test/java/org/apache/tamaya/integration/cdi/cfg/TestPropertySource.java
@@ -20,6 +20,7 @@
 package org.apache.tamaya.integration.cdi.cfg;
 
 import org.apache.tamaya.spi.PropertySource;
+import org.apache.tamaya.spi.PropertyValue;
 
 import javax.inject.Singleton;
 import java.util.HashMap;
@@ -62,8 +63,8 @@ public class TestPropertySource implements PropertySource{
     }
 
     @Override
-    public String get(String key) {
-        return config.get(key);
+    public PropertyValue get(String key) {
+        return PropertyValue.of(key, config.get(key), getName());
     }
 
     @Override

http://git-wip-us.apache.org/repos/asf/incubator-tamaya/blob/d778cb81/modules/integration/etcd/src/main/java/org/apache/tamaya/etcd/EtcdAccessor.java
----------------------------------------------------------------------
diff --git a/modules/integration/etcd/src/main/java/org/apache/tamaya/etcd/EtcdAccessor.java b/modules/integration/etcd/src/main/java/org/apache/tamaya/etcd/EtcdAccessor.java
index 6923d9e..677d369 100644
--- a/modules/integration/etcd/src/main/java/org/apache/tamaya/etcd/EtcdAccessor.java
+++ b/modules/integration/etcd/src/main/java/org/apache/tamaya/etcd/EtcdAccessor.java
@@ -55,6 +55,11 @@ public class EtcdAccessor {
 
     /** Timeout in seconds. */
     private int timeout = 2;
+    /** Timeout in seconds. */
+    private int socketTimeout = 1000;
+    /** Timeout in seconds. */
+    private int connectTimeout = 1000;
+
     /** Property that make Johnzon accept commentc. */
     public static final String JOHNZON_SUPPORTS_COMMENTS_PROP = "org.apache.johnzon.supports-comments";
     /** The JSON reader factory used. */
@@ -100,8 +105,8 @@ public class EtcdAccessor {
         try {
             CloseableHttpClient httpclient = HttpClients.createDefault();
             HttpGet httpGet = new HttpGet(serverURL + "/version");
-            httpGet.setConfig(RequestConfig.copy(RequestConfig.DEFAULT).setSocketTimeout(timeout)
-                    .setConnectionRequestTimeout(timeout).setConnectTimeout(timeout).build());
+            httpGet.setConfig(RequestConfig.copy(RequestConfig.DEFAULT)
+            .setSocketTimeout(socketTimeout).setConnectTimeout(timeout).build());
             response = httpclient.execute(httpGet);
             HttpEntity entity;
             if (response.getStatusLine().getStatusCode() == HttpStatus.SC_OK) {
@@ -155,16 +160,19 @@ public class EtcdAccessor {
         Map<String,String> result = new HashMap<>();
         try {
             HttpGet httpGet = new HttpGet(serverURL + "/v2/keys/"+key);
-            httpGet.setConfig(RequestConfig.copy(RequestConfig.DEFAULT).setSocketTimeout(timeout)
-                    .setConnectionRequestTimeout(timeout).setConnectTimeout(timeout).build());
+            httpGet.setConfig(RequestConfig.copy(RequestConfig.DEFAULT)
+            .setSocketTimeout(socketTimeout)
+                    .setConnectionRequestTimeout(timeout).setConnectTimeout(connectTimeout).build());
             response = httpclient.execute(httpGet);
             if (response.getStatusLine().getStatusCode() == HttpStatus.SC_OK) {
                 HttpEntity entity = response.getEntity();
                 JsonReader reader = readerFactory.createReader(new StringReader(EntityUtils.toString(entity)));
                 JsonObject o = reader.readObject();
                 JsonObject node = o.getJsonObject("node");
-                result.put(key, node.getString("value"));
-                result.put("_" + key +".source", "[etcd]"+serverURL);
+                if(node.containsKey("value")) {
+                    result.put(key, node.getString("value"));
+                    result.put("_" + key +".source", "[etcd]"+serverURL);
+                }
                 if(node.containsKey("createdIndex")) {
                     result.put("_" + key +".createdIndex", String.valueOf(node.getInt("createdIndex")));
                 }
@@ -250,8 +258,8 @@ public class EtcdAccessor {
         Map<String,String> result = new HashMap<>();
         try{
             HttpPut put = new HttpPut(serverURL + "/v2/keys/"+key);
-            put.setConfig(RequestConfig.copy(RequestConfig.DEFAULT).setSocketTimeout(timeout)
-                    .setConnectionRequestTimeout(timeout).setConnectTimeout(timeout).build());
+            put.setConfig(RequestConfig.copy(RequestConfig.DEFAULT).setSocketTimeout(socketTimeout)
+                    .setConnectionRequestTimeout(timeout).setConnectTimeout(connectTimeout).build());
             List<NameValuePair> nvps = new ArrayList<>();
             nvps.add(new BasicNameValuePair("value", value));
             if(ttlSeconds!=null){
@@ -336,8 +344,8 @@ public class EtcdAccessor {
         Map<String,String> result = new HashMap<>();
         try{
             HttpDelete delete = new HttpDelete(serverURL + "/v2/keys/"+key);
-            delete.setConfig(RequestConfig.copy(RequestConfig.DEFAULT).setSocketTimeout(timeout)
-                    .setConnectionRequestTimeout(timeout).setConnectTimeout(timeout).build());
+            delete.setConfig(RequestConfig.copy(RequestConfig.DEFAULT).setSocketTimeout(socketTimeout)
+                    .setConnectionRequestTimeout(timeout).setConnectTimeout(connectTimeout).build());
             response = httpclient.execute(delete);
             if (response.getStatusLine().getStatusCode() == HttpStatus.SC_OK) {
                 HttpEntity entity = response.getEntity();
@@ -449,8 +457,9 @@ public class EtcdAccessor {
         Map<String,String> result = new HashMap<>();
         try{
             HttpGet get = new HttpGet(serverURL + "/v2/keys/"+directory+"?recursive="+recursive);
-            get.setConfig(RequestConfig.copy(RequestConfig.DEFAULT).setSocketTimeout(timeout)
-                    .setConnectionRequestTimeout(timeout).setConnectTimeout(timeout).build());
+            get.setConfig(RequestConfig.copy(RequestConfig.DEFAULT)
+                    .setSocketTimeout(socketTimeout)
+                    .setConnectionRequestTimeout(timeout).setConnectTimeout(connectTimeout).build());
             response = httpclient.execute(get);
             if (response.getStatusLine().getStatusCode() == HttpStatus.SC_OK) {
                 HttpEntity entity = response.getEntity();

http://git-wip-us.apache.org/repos/asf/incubator-tamaya/blob/d778cb81/modules/integration/etcd/src/main/java/org/apache/tamaya/etcd/EtcdPropertySource.java
----------------------------------------------------------------------
diff --git a/modules/integration/etcd/src/main/java/org/apache/tamaya/etcd/EtcdPropertySource.java b/modules/integration/etcd/src/main/java/org/apache/tamaya/etcd/EtcdPropertySource.java
index b441141..db3902b 100644
--- a/modules/integration/etcd/src/main/java/org/apache/tamaya/etcd/EtcdPropertySource.java
+++ b/modules/integration/etcd/src/main/java/org/apache/tamaya/etcd/EtcdPropertySource.java
@@ -19,8 +19,12 @@
 package org.apache.tamaya.etcd;
 
 import org.apache.tamaya.spi.PropertySource;
+import org.apache.tamaya.spi.PropertyValue;
+import org.apache.tamaya.spi.PropertyValueBuilder;
 
-import java.util.*;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.Map;
 import java.util.logging.Level;
 import java.util.logging.Logger;
 
@@ -34,17 +38,13 @@ public class EtcdPropertySource implements PropertySource{
 
     private String prefix = System.getProperty("tamaya.etcd.prefix", "");
 
-    public EtcdPropertySource(){
-
-
-    }
 
     @Override
     public int getOrdinal() {
-        String configuredOrdinal = get(TAMAYA_ORDINAL);
+        PropertyValue configuredOrdinal = get(TAMAYA_ORDINAL);
         if(configuredOrdinal!=null){
             try{
-                return Integer.parseInt(configuredOrdinal);
+                return Integer.parseInt(configuredOrdinal.getValue());
             } catch(Exception e){
                 Logger.getLogger(getClass().getName()).log(Level.WARNING,
                         "Configured Ordinal is not an int number: " + configuredOrdinal, e);
@@ -67,7 +67,7 @@ public class EtcdPropertySource implements PropertySource{
     }
 
     @Override
-    public String get(String key) {
+    public PropertyValue get(String key) {
         // check prefix, if key does not start with it, it is not part of our name space
         // if so, the prefix part must be removed, so etcd can resolve without it
         if(!key.startsWith(prefix)){
@@ -96,7 +96,7 @@ public class EtcdPropertySource implements PropertySource{
                 props = accessor.get(reqKey);
                 if(!props.containsKey("_ERROR")) {
                     // No repfix mapping necessary here, since we only access/return the value...
-                    return props.get(reqKey);
+                    return new PropertyValueBuilder(key, props.get(reqKey), getName()).setContextData(props).build();
                 } else{
                     LOG.log(Level.FINE, "etcd error on " + accessor.getUrl() + ": " + props.get("_ERROR"));
                 }
@@ -109,7 +109,7 @@ public class EtcdPropertySource implements PropertySource{
 
     @Override
     public Map<String, String> getProperties() {
-        if(EtcdBackends.getEtcdBackends().isEmpty()){
+        if(!EtcdBackends.getEtcdBackends().isEmpty()){
             for(EtcdAccessor accessor: EtcdBackends.getEtcdBackends()){
                 try{
                     Map<String, String> props = accessor.getProperties("");

http://git-wip-us.apache.org/repos/asf/incubator-tamaya/blob/d778cb81/modules/integration/etcd/src/main/java/org/apache/tamaya/etcd/internal/EtcdConfigChangeRequest.java
----------------------------------------------------------------------
diff --git a/modules/integration/etcd/src/main/java/org/apache/tamaya/etcd/internal/EtcdConfigChangeRequest.java b/modules/integration/etcd/src/main/java/org/apache/tamaya/etcd/internal/EtcdConfigChangeRequest.java
index f3c7813..06ef1df 100644
--- a/modules/integration/etcd/src/main/java/org/apache/tamaya/etcd/internal/EtcdConfigChangeRequest.java
+++ b/modules/integration/etcd/src/main/java/org/apache/tamaya/etcd/internal/EtcdConfigChangeRequest.java
@@ -28,7 +28,10 @@ import java.util.logging.Level;
 import java.util.logging.Logger;
 
 /**
- * Change Request implementation based on etcd services.
+ * Change Request implementation based on etcd services. Etcd also supports a ttl to set values only for a defined
+ * number of seconds {@code ttl}. This is also supported by this component by adding ttl as a key parameter, e.g.
+ * {@code changeRequest.set("myTimedKey?ttl=30", "myValue");} will set a key {@code myTimedKey} valid only for
+ * 30 seconds.
  */
 class EtcdConfigChangeRequest extends AbstractConfigChangeRequest{
 
@@ -60,18 +63,32 @@ class EtcdConfigChangeRequest extends AbstractConfigChangeRequest{
         checkClosed();
         for(EtcdAccessor accessor: EtcdBackends.getEtcdBackends()){
             try{
-//                for(String k:getRemoved()){
-//                    Map<String,String> res = accessor.delete(k);
-//                    if(res.get("_ERROR")!=null){
-//                        LOG.info("Failed to remove key from etcd: " + k);
-//                    }
-//                }
-//                for(Map.Entry<String,String> en:getProperties().entrySet()){
-//                    Map<String,String> res = accessor.set(en.getKey(), en.getValue());
-//                    if(res.get("_ERROR")!=null){
-//                        LOG.info("Failed key from etcd: " + en.getKey()  + "=" + en.getValue());
-//                    }
-//                }
+                for(String k:getRemoved()){
+                    Map<String,String> res = accessor.delete(k);
+                    if(res.get("_ERROR")!=null){
+                        LOG.info("Failed to remove key from etcd: " + k);
+                    }
+                }
+                for(Map.Entry<String,String> en:getProperties().entrySet()){
+                    String key = en.getKey();
+                    Integer ttl = null;
+                    int index = en.getKey().indexOf('?');
+                    if(index>0){
+                        key = en.getKey().substring(0, index);
+                        String rawQuery = en.getKey().substring(index+1);
+                        String[] queries = rawQuery.split("&");
+                        for(String query:queries){
+                            if(query.contains("ttl")){
+                                int qIdx = query.indexOf('=');
+                                ttl = qIdx>0?Integer.parseInt(query.substring(qIdx+1).trim()):null;
+                            }
+                        }
+                    }
+                    Map<String,String> res = accessor.set(key, en.getValue(), ttl);
+                    if(res.get("_ERROR")!=null){
+                        LOG.info("Failed key from etcd: " + en.getKey()  + "=" + en.getValue());
+                    }
+                }
             } catch(Exception e){
                 LOG.log(Level.FINE, "etcd access failed on " + accessor.getUrl() + ", trying next...", e);
             }

http://git-wip-us.apache.org/repos/asf/incubator-tamaya/blob/d778cb81/modules/json/src/main/java/org/apache/tamaya/json/JSONPropertySource.java
----------------------------------------------------------------------
diff --git a/modules/json/src/main/java/org/apache/tamaya/json/JSONPropertySource.java b/modules/json/src/main/java/org/apache/tamaya/json/JSONPropertySource.java
index 48c6521..43cfa73 100644
--- a/modules/json/src/main/java/org/apache/tamaya/json/JSONPropertySource.java
+++ b/modules/json/src/main/java/org/apache/tamaya/json/JSONPropertySource.java
@@ -20,6 +20,7 @@ package org.apache.tamaya.json;
 
 import org.apache.tamaya.ConfigException;
 import org.apache.tamaya.spi.PropertySource;
+import org.apache.tamaya.spi.PropertyValue;
 
 import java.io.InputStream;
 import java.net.URL;
@@ -89,10 +90,10 @@ public class JSONPropertySource implements PropertySource {
 
     @Override
     public int getOrdinal() {
-        String configuredOrdinal = get(TAMAYA_ORDINAL);
+        PropertyValue configuredOrdinal = get(TAMAYA_ORDINAL);
         if(configuredOrdinal!=null){
             try{
-                return Integer.parseInt(configuredOrdinal);
+                return Integer.parseInt(configuredOrdinal.getValue());
             } catch(Exception e){
                 Logger.getLogger(getClass().getName()).log(Level.WARNING,
                         "Configured Ordinal is not an int number: " + configuredOrdinal, e);
@@ -107,8 +108,8 @@ public class JSONPropertySource implements PropertySource {
     }
 
     @Override
-    public String get(String key) {
-        return getProperties().get(key);
+    public PropertyValue get(String key) {
+        return PropertyValue.of(key, getProperties().get(key), getName());
     }
 
     @Override

http://git-wip-us.apache.org/repos/asf/incubator-tamaya/blob/d778cb81/modules/json/src/test/java/org/apache/tamaya/json/CommonJSONTestCaseCollection.java
----------------------------------------------------------------------
diff --git a/modules/json/src/test/java/org/apache/tamaya/json/CommonJSONTestCaseCollection.java b/modules/json/src/test/java/org/apache/tamaya/json/CommonJSONTestCaseCollection.java
index 8283e7c..946878c 100644
--- a/modules/json/src/test/java/org/apache/tamaya/json/CommonJSONTestCaseCollection.java
+++ b/modules/json/src/test/java/org/apache/tamaya/json/CommonJSONTestCaseCollection.java
@@ -20,6 +20,7 @@ package org.apache.tamaya.json;
 
 import org.apache.tamaya.ConfigException;
 import org.apache.tamaya.spi.PropertySource;
+import org.apache.tamaya.spi.PropertyValue;
 import org.hamcrest.CoreMatchers;
 import org.hamcrest.Matchers;
 import org.junit.Test;
@@ -50,9 +51,9 @@ public abstract class CommonJSONTestCaseCollection {
         PropertySource propertySource = getPropertiesFrom(configURL);
 
         assertThat(propertySource.get("name"), Matchers.notNullValue());
-        assertThat(propertySource.get("name"), equalTo("\u041e\u043b\u0438\u0432\u0435\u0440"));
+        assertThat(propertySource.get("name").getValue(), equalTo("\u041e\u043b\u0438\u0432\u0435\u0440"));
         assertThat(propertySource.get("\u0444\u0430\u043c\u0438\u043b\u0438\u044f"), Matchers.notNullValue());
-        assertThat(propertySource.get("\u0444\u0430\u043c\u0438\u043b\u0438\u044f"), Matchers.equalTo("Fischer"));
+        assertThat(propertySource.get("\u0444\u0430\u043c\u0438\u043b\u0438\u044f").getValue(), Matchers.equalTo("Fischer"));
     }
 
     @Test
@@ -66,16 +67,16 @@ public abstract class CommonJSONTestCaseCollection {
 
         assertThat(properties.getProperties().keySet(), hasSize(5));
 
-        String keyB = properties.get("b");
-        String keyDO = properties.get("d.o");
-        String keyDP = properties.get("d.p");
+        PropertyValue keyB = properties.get("b");
+        PropertyValue keyDO = properties.get("d.o");
+        PropertyValue keyDP = properties.get("d.p");
 
         assertThat(keyB, notNullValue());
-        assertThat(keyB, equalTo("B"));
+        assertThat(keyB.getValue(), equalTo("B"));
         assertThat(keyDO, notNullValue());
-        assertThat(keyDO, equalTo("O"));
+        assertThat(keyDO.getValue(), equalTo("O"));
         assertThat(keyDP, Matchers.notNullValue());
-        assertThat(keyDP, is("P"));
+        assertThat(keyDP.getValue(), is("P"));
     }
 
     @Test
@@ -90,19 +91,19 @@ public abstract class CommonJSONTestCaseCollection {
 
         assertThat(properties.getProperties().keySet(), hasSize(4));
 
-        String keyA = properties.get("a");
-        String keyDO = properties.get("b.o");
-        String keyDP = properties.get("b.p");
-        String keyC = properties.get("c");
+        PropertyValue keyA = properties.get("a");
+        PropertyValue keyDO = properties.get("b.o");
+        PropertyValue keyDP = properties.get("b.p");
+        PropertyValue keyC = properties.get("c");
 
         assertThat(keyA, notNullValue());
-        assertThat(keyA, is("A"));
+        assertThat(keyA.getValue(), is("A"));
         assertThat(keyC, notNullValue());
-        assertThat(keyC, equalTo("C"));
+        assertThat(keyC.getValue(), equalTo("C"));
         assertThat(keyDO, notNullValue());
-        assertThat(keyDO, equalTo("O"));
+        assertThat(keyDO.getValue(), equalTo("O"));
         assertThat(keyDP, notNullValue());
-        assertThat(keyDP, is("P"));
+        assertThat(keyDP.getValue(), is("P"));
     }
 
     @Test(expected = ConfigException.class)
@@ -153,16 +154,16 @@ public abstract class CommonJSONTestCaseCollection {
 
         assertThat(properties.getProperties().keySet(), hasSize(3));
 
-        String keyA = properties.get("a");
-        String keyB = properties.get("b");
-        String keyC = properties.get("c");
+        PropertyValue keyA = properties.get("a");
+        PropertyValue keyB = properties.get("b");
+        PropertyValue keyC = properties.get("c");
 
         assertThat(keyA, notNullValue());
-        assertThat(keyA, equalTo("A"));
+        assertThat(keyA.getValue(), equalTo("A"));
         assertThat(keyB, notNullValue());
-        assertThat(keyB, is("B"));
+        assertThat(keyB.getValue(), is("B"));
         assertThat(keyC, notNullValue());
-        assertThat(keyC, is("C"));
+        assertThat(keyC.getValue(), is("C"));
     }
 
     @Test(expected = ConfigException.class)

http://git-wip-us.apache.org/repos/asf/incubator-tamaya/blob/d778cb81/modules/json/src/test/java/org/apache/tamaya/json/JSONPropertySourceTest.java
----------------------------------------------------------------------
diff --git a/modules/json/src/test/java/org/apache/tamaya/json/JSONPropertySourceTest.java b/modules/json/src/test/java/org/apache/tamaya/json/JSONPropertySourceTest.java
index b3a96b3..9892446 100644
--- a/modules/json/src/test/java/org/apache/tamaya/json/JSONPropertySourceTest.java
+++ b/modules/json/src/test/java/org/apache/tamaya/json/JSONPropertySourceTest.java
@@ -37,7 +37,7 @@ public class JSONPropertySourceTest extends CommonJSONTestCaseCollection {
         assertThat(configURL, CoreMatchers.notNullValue());
 
         JSONPropertySource source = new JSONPropertySource(configURL, 4);
-        assertEquals(source.get(PropertySource.TAMAYA_ORDINAL), "16784");
+        assertEquals(source.get(PropertySource.TAMAYA_ORDINAL).getValue(), "16784");
     }
     
     @Test(expected=ConfigException.class)

http://git-wip-us.apache.org/repos/asf/incubator-tamaya/blob/d778cb81/modules/mutable-config/src/main/java/org/apache/tamaya/mutableconfig/ConfigChangeManager.java
----------------------------------------------------------------------
diff --git a/modules/mutable-config/src/main/java/org/apache/tamaya/mutableconfig/ConfigChangeManager.java b/modules/mutable-config/src/main/java/org/apache/tamaya/mutableconfig/ConfigChangeManager.java
index 5188e10..8142fcc 100644
--- a/modules/mutable-config/src/main/java/org/apache/tamaya/mutableconfig/ConfigChangeManager.java
+++ b/modules/mutable-config/src/main/java/org/apache/tamaya/mutableconfig/ConfigChangeManager.java
@@ -23,6 +23,7 @@ import org.apache.tamaya.mutableconfig.spi.ConfigChangeManagerSpi;
 import org.apache.tamaya.spi.ServiceContextManager;
 
 import java.net.URI;
+import java.net.URISyntaxException;
 import java.util.ArrayList;
 import java.util.Arrays;
 import java.util.Collection;
@@ -44,6 +45,28 @@ public final class ConfigChangeManager {
     /**
      * Creates a new change request for the given configurationSource
      *
+     * @param configurationTargets the configuration targets (String to create URIs) to use to write the changes/config. By passing multiple
+     *                             URIs you can write back changes into multiple configuration backends, e.g.
+     *                             one for redistributing changes using multicast mechanism, a local property file
+     *                             for failover as well as the shared etcd server.
+     * @return a new ChangeRequest
+     * @throws org.apache.tamaya.ConfigException if the given configurationSource cannot be edited.
+     */
+    public static ConfigChangeRequest createChangeRequest(String... configurationTargets){
+        try {
+            URI[] uris = new URI[configurationTargets.length];
+            for (int i = 0; i < configurationTargets.length; i++) {
+                uris[i] = new URI(configurationTargets[i]);
+            }
+            return createChangeRequest(uris);
+        } catch(URISyntaxException e){
+            throw new ConfigException("Invalid URIs enocuntered in " + Arrays.toString(configurationTargets));
+        }
+    }
+
+    /**
+     * Creates a new change request for the given configurationSource
+     *
      * @param configurationTargets the configuration targets to use to write the changes/config. By passing multiple
      *                             URIs you can write back changes into multiple configuration backends, e.g.
      *                             one for redistributing changes using multicast mechanism, a local property file

http://git-wip-us.apache.org/repos/asf/incubator-tamaya/blob/d778cb81/modules/mutable-config/src/main/java/org/apache/tamaya/mutableconfig/internal/PropertiesFileConfigChangeRequest.java
----------------------------------------------------------------------
diff --git a/modules/mutable-config/src/main/java/org/apache/tamaya/mutableconfig/internal/PropertiesFileConfigChangeRequest.java b/modules/mutable-config/src/main/java/org/apache/tamaya/mutableconfig/internal/PropertiesFileConfigChangeRequest.java
index d06a438..94d3f2e 100644
--- a/modules/mutable-config/src/main/java/org/apache/tamaya/mutableconfig/internal/PropertiesFileConfigChangeRequest.java
+++ b/modules/mutable-config/src/main/java/org/apache/tamaya/mutableconfig/internal/PropertiesFileConfigChangeRequest.java
@@ -21,7 +21,11 @@ package org.apache.tamaya.mutableconfig.internal;
 import org.apache.tamaya.ConfigException;
 import org.apache.tamaya.mutableconfig.spi.AbstractConfigChangeRequest;
 
-import java.io.*;
+import java.io.BufferedOutputStream;
+import java.io.File;
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.io.InputStream;
 import java.net.URI;
 import java.util.Map;
 import java.util.Properties;
@@ -84,7 +88,12 @@ class PropertiesFileConfigChangeRequest extends AbstractConfigChangeRequest{
             }
         }
         for(Map.Entry<String,String> en:super.properties.entrySet()){
-            this.properties.put(en.getKey(), en.getValue());
+            int index = en.getKey().indexOf('?');
+            if(index>0){
+                this.properties.put(en.getKey().substring(0, index), en.getValue());
+            }else{
+                this.properties.put(en.getKey(), en.getValue());
+            }
         }
         for(String rmKey:super.removed){
             this.properties.remove(rmKey);

http://git-wip-us.apache.org/repos/asf/incubator-tamaya/blob/d778cb81/modules/mutable-config/src/main/java/org/apache/tamaya/mutableconfig/internal/XmlPropertiesFileConfigChangeRequest.java
----------------------------------------------------------------------
diff --git a/modules/mutable-config/src/main/java/org/apache/tamaya/mutableconfig/internal/XmlPropertiesFileConfigChangeRequest.java b/modules/mutable-config/src/main/java/org/apache/tamaya/mutableconfig/internal/XmlPropertiesFileConfigChangeRequest.java
index f98aceb..9211641 100644
--- a/modules/mutable-config/src/main/java/org/apache/tamaya/mutableconfig/internal/XmlPropertiesFileConfigChangeRequest.java
+++ b/modules/mutable-config/src/main/java/org/apache/tamaya/mutableconfig/internal/XmlPropertiesFileConfigChangeRequest.java
@@ -88,7 +88,12 @@ class XmlPropertiesFileConfigChangeRequest extends AbstractConfigChangeRequest{
             }
         }
         for(Map.Entry<String,String> en:super.properties.entrySet()){
-            this.properties.put(en.getKey(), en.getValue());
+            int index = en.getKey().indexOf('?');
+            if(index>0){
+                this.properties.put(en.getKey().substring(0, index), en.getValue());
+            }else{
+                this.properties.put(en.getKey(), en.getValue());
+            }
         }
         for(String rmKey:super.removed){
             this.properties.remove(rmKey);

http://git-wip-us.apache.org/repos/asf/incubator-tamaya/blob/d778cb81/modules/mutable-config/src/main/java/org/apache/tamaya/mutableconfig/spi/AbstractConfigChangeRequest.java
----------------------------------------------------------------------
diff --git a/modules/mutable-config/src/main/java/org/apache/tamaya/mutableconfig/spi/AbstractConfigChangeRequest.java b/modules/mutable-config/src/main/java/org/apache/tamaya/mutableconfig/spi/AbstractConfigChangeRequest.java
index 28966e7..5e319db 100644
--- a/modules/mutable-config/src/main/java/org/apache/tamaya/mutableconfig/spi/AbstractConfigChangeRequest.java
+++ b/modules/mutable-config/src/main/java/org/apache/tamaya/mutableconfig/spi/AbstractConfigChangeRequest.java
@@ -50,6 +50,14 @@ public abstract class AbstractConfigChangeRequest implements ConfigChangeRequest
     protected final Set<String> removed = new HashSet<>();
     private boolean closed = false;
 
+    protected Set<String> getRemoved() {
+        return removed;
+    }
+
+    protected Map<String,String> getProperties() {
+        return properties;
+    }
+
     /**
      * Instantiates a new Abstract config change request.
      *

http://git-wip-us.apache.org/repos/asf/incubator-tamaya/blob/d778cb81/modules/mutable-config/src/test/java/org/apache/tamaya/mutableconfig/ConfigChangeManagerTest.java
----------------------------------------------------------------------
diff --git a/modules/mutable-config/src/test/java/org/apache/tamaya/mutableconfig/ConfigChangeManagerTest.java b/modules/mutable-config/src/test/java/org/apache/tamaya/mutableconfig/ConfigChangeManagerTest.java
index 2e47383..8f4305c 100644
--- a/modules/mutable-config/src/test/java/org/apache/tamaya/mutableconfig/ConfigChangeManagerTest.java
+++ b/modules/mutable-config/src/test/java/org/apache/tamaya/mutableconfig/ConfigChangeManagerTest.java
@@ -62,7 +62,17 @@ public class ConfigChangeManagerTest {
      * @throws Exception the exception
      */
     @Test(expected=NullPointerException.class)
-    public void testNullCreateChangeRequest() throws Exception {
-        ConfigChangeRequest req = ConfigChangeManager.createChangeRequest(null);
+    public void testNullCreateChangeRequest1() throws Exception {
+        ConfigChangeRequest req = ConfigChangeManager.createChangeRequest((URI[])null);
+    }
+
+    /**
+     * Test null create change request.
+     *
+     * @throws Exception the exception
+     */
+    @Test(expected=NullPointerException.class)
+    public void testNullCreateChangeRequest2() throws Exception {
+        ConfigChangeRequest req = ConfigChangeManager.createChangeRequest((String[])null);
     }
 }
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/incubator-tamaya/blob/d778cb81/modules/pom.xml
----------------------------------------------------------------------
diff --git a/modules/pom.xml b/modules/pom.xml
index 62fdd17..8b265de 100644
--- a/modules/pom.xml
+++ b/modules/pom.xml
@@ -51,6 +51,7 @@ under the License.
         <module>optional</module>
         <module>classloader-support</module>
         <module>integration</module>
+        <module>filter</module>
     </modules>
 
     <build>

http://git-wip-us.apache.org/repos/asf/incubator-tamaya/blob/d778cb81/modules/remote/src/main/java/org/apache/tamaya/remote/BaseRemotePropertySource.java
----------------------------------------------------------------------
diff --git a/modules/remote/src/main/java/org/apache/tamaya/remote/BaseRemotePropertySource.java b/modules/remote/src/main/java/org/apache/tamaya/remote/BaseRemotePropertySource.java
index bf7579d..0fd1c67 100644
--- a/modules/remote/src/main/java/org/apache/tamaya/remote/BaseRemotePropertySource.java
+++ b/modules/remote/src/main/java/org/apache/tamaya/remote/BaseRemotePropertySource.java
@@ -22,6 +22,7 @@ import org.apache.tamaya.format.ConfigurationData;
 import org.apache.tamaya.format.ConfigurationFormat;
 import org.apache.tamaya.json.JSONFormat;
 import org.apache.tamaya.spi.PropertySource;
+import org.apache.tamaya.spi.PropertyValue;
 
 import java.io.InputStream;
 import java.net.URL;
@@ -119,16 +120,16 @@ public abstract class BaseRemotePropertySource implements PropertySource{
     }
 
     @Override
-    public String get(String key) {
-        return getProperties().get(key);
+    public PropertyValue get(String key) {
+        return PropertyValue.of(key,getProperties().get(key),getName());
     }
 
     @Override
     public int getOrdinal(){
-        String configuredOrdinal = get(TAMAYA_ORDINAL);
+        PropertyValue configuredOrdinal = get(TAMAYA_ORDINAL);
         if(configuredOrdinal!=null){
             try{
-                return Integer.parseInt(configuredOrdinal);
+                return Integer.parseInt(configuredOrdinal.getValue());
             } catch(Exception e){
                 Logger.getLogger(getClass().getName()).log(Level.WARNING,
                         "Configured Ordinal is not an int number: " + configuredOrdinal, e);

http://git-wip-us.apache.org/repos/asf/incubator-tamaya/blob/d778cb81/modules/resolver/src/main/java/org/apache/tamaya/resolver/internal/ExpressionResolutionFilter.java
----------------------------------------------------------------------
diff --git a/modules/resolver/src/main/java/org/apache/tamaya/resolver/internal/ExpressionResolutionFilter.java b/modules/resolver/src/main/java/org/apache/tamaya/resolver/internal/ExpressionResolutionFilter.java
index 13816c8..e8bad93 100644
--- a/modules/resolver/src/main/java/org/apache/tamaya/resolver/internal/ExpressionResolutionFilter.java
+++ b/modules/resolver/src/main/java/org/apache/tamaya/resolver/internal/ExpressionResolutionFilter.java
@@ -19,6 +19,7 @@
 package org.apache.tamaya.resolver.internal;
 
 import org.apache.tamaya.resolver.spi.ExpressionEvaluator;
+import org.apache.tamaya.spi.FilterContext;
 import org.apache.tamaya.spi.PropertyFilter;
 import org.apache.tamaya.spi.ServiceContextManager;
 
@@ -71,14 +72,14 @@ public class ExpressionResolutionFilter implements PropertyFilter {
      * <li><code>\${resolverId:expression}foo${resolverId2:expression2}bar</code> (first expression is escaped).</li>
      * </ul>
      *
-     * @param key the key to be filtered
+     * @param context the filter context
      * @param valueToBeFiltered value to be analyzed for expressions
      * @return the resolved value, or the input in case where no expression was detected.
      */
     @Override
-    public String filterProperty(String key, String valueToBeFiltered){
-        LOG.finest("Resolving " + valueToBeFiltered + "(key=" + key + ")");
-        return evaluator.evaluateExpression(key, valueToBeFiltered);
+    public String filterProperty(String valueToBeFiltered, FilterContext context){
+        LOG.finest("Resolving " + valueToBeFiltered + "(key=" + context.getKey() + ")");
+        return evaluator.evaluateExpression(context.getKey(), valueToBeFiltered);
     }
 
 

http://git-wip-us.apache.org/repos/asf/incubator-tamaya/blob/d778cb81/modules/resolver/src/test/java/org/apache/tamaya/resolver/MyTestPropertySource.java
----------------------------------------------------------------------
diff --git a/modules/resolver/src/test/java/org/apache/tamaya/resolver/MyTestPropertySource.java b/modules/resolver/src/test/java/org/apache/tamaya/resolver/MyTestPropertySource.java
index 1a06f22..7d99cbc 100644
--- a/modules/resolver/src/test/java/org/apache/tamaya/resolver/MyTestPropertySource.java
+++ b/modules/resolver/src/test/java/org/apache/tamaya/resolver/MyTestPropertySource.java
@@ -19,6 +19,7 @@
 package org.apache.tamaya.resolver;
 
 import org.apache.tamaya.spi.PropertySource;
+import org.apache.tamaya.spi.PropertyValue;
 
 import java.io.File;
 import java.net.URISyntaxException;
@@ -85,8 +86,8 @@ public class MyTestPropertySource implements PropertySource{
     }
 
     @Override
-    public String get(String key) {
-        return properties.get(key);
+    public PropertyValue get(String key) {
+        return PropertyValue.of(key, properties.get(key), getName());
     }
 
     @Override

http://git-wip-us.apache.org/repos/asf/incubator-tamaya/blob/d778cb81/modules/resources/src/main/java/org/apache/tamaya/resource/AbstractPathPropertySourceProvider.java
----------------------------------------------------------------------
diff --git a/modules/resources/src/main/java/org/apache/tamaya/resource/AbstractPathPropertySourceProvider.java b/modules/resources/src/main/java/org/apache/tamaya/resource/AbstractPathPropertySourceProvider.java
index 0df3151..1b62c65 100644
--- a/modules/resources/src/main/java/org/apache/tamaya/resource/AbstractPathPropertySourceProvider.java
+++ b/modules/resources/src/main/java/org/apache/tamaya/resource/AbstractPathPropertySourceProvider.java
@@ -33,6 +33,7 @@ import java.util.logging.Logger;
 
 import org.apache.tamaya.spi.PropertySource;
 import org.apache.tamaya.spi.PropertySourceProvider;
+import org.apache.tamaya.spi.PropertyValue;
 
 /**
  * Abstract base class that uses a descriptive resource path to define the locations of configuration files to be
@@ -142,10 +143,10 @@ public abstract class AbstractPathPropertySourceProvider implements PropertySour
 
         @Override
         public int getOrdinal() {
-            String configuredOrdinal = get(TAMAYA_ORDINAL);
+            PropertyValue configuredOrdinal = get(TAMAYA_ORDINAL);
             if (configuredOrdinal != null) {
                 try {
-                    return Integer.parseInt(configuredOrdinal);
+                    return Integer.parseInt(configuredOrdinal.getValue());
                 } catch (Exception e) {
                     Logger.getLogger(getClass().getName()).log(Level.WARNING,
                             "Configured Ordinal is not an int number: " + configuredOrdinal, e);
@@ -169,8 +170,8 @@ public abstract class AbstractPathPropertySourceProvider implements PropertySour
         }
 
         @Override
-        public String get(String key) {
-            return properties.get(key);
+        public PropertyValue get(String key) {
+            return PropertyValue.of(key, getProperties().get(key), getName());
         }
 
         @Override

http://git-wip-us.apache.org/repos/asf/incubator-tamaya/blob/d778cb81/modules/resources/src/test/java/org/apache/tamaya/resource/AbstractPathPropertySourceProviderTest.java
----------------------------------------------------------------------
diff --git a/modules/resources/src/test/java/org/apache/tamaya/resource/AbstractPathPropertySourceProviderTest.java b/modules/resources/src/test/java/org/apache/tamaya/resource/AbstractPathPropertySourceProviderTest.java
index fa5560a..8fe1b2b 100644
--- a/modules/resources/src/test/java/org/apache/tamaya/resource/AbstractPathPropertySourceProviderTest.java
+++ b/modules/resources/src/test/java/org/apache/tamaya/resource/AbstractPathPropertySourceProviderTest.java
@@ -19,6 +19,8 @@
 package org.apache.tamaya.resource;
 
 import org.apache.tamaya.spi.PropertySource;
+import org.apache.tamaya.spi.PropertyValue;
+import org.apache.tamaya.spi.PropertyValueBuilder;
 import org.junit.Test;
 
 import java.net.URL;
@@ -87,10 +89,10 @@ public class AbstractPathPropertySourceProviderTest {
          * @return the 'importance' aka ordinal of the configured values. The higher, the more important.
          */
         public int getOrdinal() {
-            String configuredOrdinal = get(TAMAYA_ORDINAL);
+            PropertyValue configuredOrdinal = get(TAMAYA_ORDINAL);
             if (configuredOrdinal != null) {
                 try {
-                    return Integer.parseInt(configuredOrdinal);
+                    return Integer.parseInt(configuredOrdinal.getValue());
                 } catch (Exception e) {
                     Logger.getLogger(getClass().getName()).log(Level.WARNING,
                             "Configured Ordinal is not an int number: " + configuredOrdinal, e);
@@ -114,7 +116,7 @@ public class AbstractPathPropertySourceProviderTest {
         }
 
         @Override
-        public String get(String key) {
+        public PropertyValue get(String key) {
             return null;
         }
 

http://git-wip-us.apache.org/repos/asf/incubator-tamaya/blob/d778cb81/modules/resources/src/test/java/org/apache/tamaya/resource/internal/PathBasedPropertySourceProvider.java
----------------------------------------------------------------------
diff --git a/modules/resources/src/test/java/org/apache/tamaya/resource/internal/PathBasedPropertySourceProvider.java b/modules/resources/src/test/java/org/apache/tamaya/resource/internal/PathBasedPropertySourceProvider.java
index 39885b8..7ea9b4c 100644
--- a/modules/resources/src/test/java/org/apache/tamaya/resource/internal/PathBasedPropertySourceProvider.java
+++ b/modules/resources/src/test/java/org/apache/tamaya/resource/internal/PathBasedPropertySourceProvider.java
@@ -20,6 +20,8 @@ package org.apache.tamaya.resource.internal;
 
 import org.apache.tamaya.resource.AbstractPathPropertySourceProvider;
 import org.apache.tamaya.spi.PropertySource;
+import org.apache.tamaya.spi.PropertyValue;
+import org.apache.tamaya.spi.PropertyValueBuilder;
 
 import java.io.InputStream;
 import java.net.URL;
@@ -78,8 +80,8 @@ public class PathBasedPropertySourceProvider extends AbstractPathPropertySourceP
         }
 
         @Override
-        public String get(String key) {
-            return properties.get(key);
+        public PropertyValue get(String key) {
+            return PropertyValue.of(key,properties.get(key), getName());
         }
 
         @Override

http://git-wip-us.apache.org/repos/asf/incubator-tamaya/blob/d778cb81/modules/server/pom.xml
----------------------------------------------------------------------
diff --git a/modules/server/pom.xml b/modules/server/pom.xml
index ff74e01..62fb139 100644
--- a/modules/server/pom.xml
+++ b/modules/server/pom.xml
@@ -33,20 +33,27 @@ under the License.
 
     <properties>
         <jdkVersion>1.7</jdkVersion>
+        <dropwizard.version>0.9.2</dropwizard.version>
     </properties>
 
+    <!-- Add typical dependencies for a web application -->
     <dependencies>
         <dependency>
+            <groupId>io.dropwizard</groupId>
+            <artifactId>dropwizard-core</artifactId>
+            <version>${dropwizard.version}</version>
+        </dependency>
+        <dependency>
             <groupId>org.apache.tamaya</groupId>
             <artifactId>tamaya-api</artifactId>
             <version>${project.version}</version>
-            <scope>provided</scope>
+            <scope>compile</scope>
         </dependency>
         <dependency>
             <groupId>org.apache.tamaya</groupId>
             <artifactId>tamaya-core</artifactId>
             <version>${project.version}</version>
-            <scope>provided</scope>
+            <scope>compile</scope>
         </dependency>
         <dependency>
             <groupId>${project.groupId}</groupId>
@@ -62,17 +69,85 @@ under the License.
             <groupId>junit</groupId>
             <artifactId>junit</artifactId>
         </dependency>
-        <dependency>
-            <groupId>org.apache.cxf</groupId>
-            <artifactId>apache-cxf</artifactId>
-            <type>pom</type>
-            <version>3.1.2</version>
-        </dependency>
     </dependencies>
 
     <build>
         <plugins>
             <plugin>
+                <groupId>com.spotify</groupId>
+                <artifactId>docker-maven-plugin</artifactId>
+                <version>0.3.258</version>
+                <configuration>
+                    <imageName>apache/tamaya/config-server</imageName>
+                    <imageTags>
+                        <imageTag>${project.version}</imageTag>
+                    </imageTags>
+                    <baseImage>java:8-jre</baseImage>
+                    <entryPoint>["java", "-jar", "/${project.build.finalName}.jar", "server", "/config-server.yml"]</entryPoint>
+                    <exposes>
+                        <expose>8080</expose>
+                    </exposes>
+                    <resources>
+                        <resource>
+                            <targetPath>/</targetPath>
+                            <directory>${project.build.directory}</directory>
+                            <include>${project.build.finalName}.jar</include>
+                        </resource>
+                        <resource>
+                            <targetPath>/</targetPath>
+                            <directory>${project.build.directory}/classes</directory>
+                            <include>config-server.yml</include>
+                        </resource>
+                    </resources>
+                </configuration>
+            </plugin>
+            <plugin>
+                <groupId>org.apache.maven.plugins</groupId>
+                <artifactId>maven-jar-plugin</artifactId>
+                <version>2.4</version>
+                <configuration>
+                    <archive>
+                        <manifest>
+                            <addDefaultImplementationEntries>true</addDefaultImplementationEntries>
+                        </manifest>
+                    </archive>
+                </configuration>
+            </plugin>
+            <plugin>
+                <groupId>org.apache.maven.plugins</groupId>
+                <artifactId>maven-shade-plugin</artifactId>
+                <version>2.3</version>
+                <configuration>
+                    <createDependencyReducedPom>true</createDependencyReducedPom>
+                    <filters>
+                        <filter>
+                            <artifact>*:*</artifact>
+                            <excludes>
+                                <exclude>META-INF/*.SF</exclude>
+                                <exclude>META-INF/*.DSA</exclude>
+                                <exclude>META-INF/*.RSA</exclude>
+                            </excludes>
+                        </filter>
+                    </filters>
+                </configuration>
+                <executions>
+                    <execution>
+                        <phase>package</phase>
+                        <goals>
+                            <goal>shade</goal>
+                        </goals>
+                        <configuration>
+                            <transformers>
+                                <transformer implementation="org.apache.maven.plugins.shade.resource.ServicesResourceTransformer"/>
+                                <transformer implementation="org.apache.maven.plugins.shade.resource.ManifestResourceTransformer">
+                                    <mainClass>org.apache.tamaya.server.ConfigServiceApp</mainClass>
+                                </transformer>
+                            </transformers>
+                        </configuration>
+                    </execution>
+                </executions>
+            </plugin>
+            <plugin>
                 <groupId>org.apache.felix</groupId>
                 <artifactId>maven-bundle-plugin</artifactId>
                 <extensions>true</extensions>

http://git-wip-us.apache.org/repos/asf/incubator-tamaya/blob/d778cb81/modules/server/src/main/java/org/apache/tamaya/server/ConfigServer.java
----------------------------------------------------------------------
diff --git a/modules/server/src/main/java/org/apache/tamaya/server/ConfigServer.java b/modules/server/src/main/java/org/apache/tamaya/server/ConfigServer.java
deleted file mode 100644
index 3d0c070..0000000
--- a/modules/server/src/main/java/org/apache/tamaya/server/ConfigServer.java
+++ /dev/null
@@ -1,50 +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.server;
-
-import org.apache.tamaya.spi.ServiceContextManager;
-
-/**
- * Simple Server singleton for starting the built-in simple configuration server.
- */
-public final class ConfigServer {
-    /**
-     * Utility class constructor.
-     */
-    private ConfigServer(){}
-
-    /**
-     * Creates a new server instance.
-     * @return a new server instance.
-     */
-    public static Server createServer(){
-        return ServiceContextManager.getServiceContext().getService(Server.class);
-    }
-
-    /**
-     * Main method to start the simple config server as a main method.
-     * @param args the args provided.
-     */
-    public static void main(String... args){
-        String portVal = System.getProperty("port");
-        int port = portVal==null?8888:Integer.parseInt(portVal);
-        createServer().start(port);
-    }
-
-}

http://git-wip-us.apache.org/repos/asf/incubator-tamaya/blob/d778cb81/modules/server/src/main/java/org/apache/tamaya/server/ConfigServiceApp.java
----------------------------------------------------------------------
diff --git a/modules/server/src/main/java/org/apache/tamaya/server/ConfigServiceApp.java b/modules/server/src/main/java/org/apache/tamaya/server/ConfigServiceApp.java
new file mode 100644
index 0000000..2e98998
--- /dev/null
+++ b/modules/server/src/main/java/org/apache/tamaya/server/ConfigServiceApp.java
@@ -0,0 +1,57 @@
+/*
+ * 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.server;
+
+import io.dropwizard.Application;
+import io.dropwizard.setup.Bootstrap;
+import io.dropwizard.setup.Environment;
+
+/**
+ * Main Application for the Tamaya Configuration Server.
+ */
+public class ConfigServiceApp extends Application<ConfigServiceConfiguration> {
+
+    public static void main(String... args) throws Exception {
+        new ConfigServiceApp().run(args);
+    }
+
+    @Override
+    public String getName() {
+        return "Tamaya Config-Server";
+    }
+
+    @Override
+    public void initialize(Bootstrap<ConfigServiceConfiguration> bootstrap) {
+        // nothing to do yet
+    }
+
+    @Override
+    public void run(ConfigServiceConfiguration configuration,
+                    Environment environment) {
+        final ConfigurationResource resource = new ConfigurationResource(
+                configuration.getScope()
+        );
+    //    final TemplateHealthCheck healthCheck =
+    //            new TemplateHealthCheck(configuration.getTemplate());
+    //    environment.healthChecks().register("template", healthCheck);
+        environment.jersey().register(resource);
+    }
+
+
+}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/incubator-tamaya/blob/d778cb81/modules/server/src/main/java/org/apache/tamaya/server/ConfigServiceConfiguration.java
----------------------------------------------------------------------
diff --git a/modules/server/src/main/java/org/apache/tamaya/server/ConfigServiceConfiguration.java b/modules/server/src/main/java/org/apache/tamaya/server/ConfigServiceConfiguration.java
new file mode 100644
index 0000000..6248e82
--- /dev/null
+++ b/modules/server/src/main/java/org/apache/tamaya/server/ConfigServiceConfiguration.java
@@ -0,0 +1,41 @@
+/*
+ * 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.server;
+
+import com.fasterxml.jackson.annotation.JsonProperty;
+import io.dropwizard.Configuration;
+
+/**
+ *Configuration Server DropWizard Configuration.
+ */
+public class ConfigServiceConfiguration extends Configuration {
+
+    private String scope;
+
+    @JsonProperty
+    public String getScope() {
+        return scope;
+    }
+
+    @JsonProperty
+    public void setScope(String scope) {
+        this.scope = scope;
+    }
+
+}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/incubator-tamaya/blob/d778cb81/modules/server/src/main/java/org/apache/tamaya/server/ConfigurationResource.java
----------------------------------------------------------------------
diff --git a/modules/server/src/main/java/org/apache/tamaya/server/ConfigurationResource.java b/modules/server/src/main/java/org/apache/tamaya/server/ConfigurationResource.java
new file mode 100644
index 0000000..ec01097
--- /dev/null
+++ b/modules/server/src/main/java/org/apache/tamaya/server/ConfigurationResource.java
@@ -0,0 +1,321 @@
+/*
+ * 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.server;
+
+import org.apache.tamaya.Configuration;
+import org.apache.tamaya.ConfigurationProvider;
+import org.apache.tamaya.functions.ConfigurationFunctions;
+
+import javax.json.Json;
+import javax.json.JsonArray;
+import javax.json.JsonArrayBuilder;
+import javax.json.JsonObject;
+import javax.json.JsonObjectBuilder;
+import javax.json.JsonWriter;
+import javax.json.stream.JsonGenerator;
+import javax.ws.rs.DELETE;
+import javax.ws.rs.FormParam;
+import javax.ws.rs.GET;
+import javax.ws.rs.PUT;
+import javax.ws.rs.Path;
+import javax.ws.rs.PathParam;
+import javax.ws.rs.Produces;
+import javax.ws.rs.QueryParam;
+import javax.ws.rs.core.MediaType;
+import java.io.StringWriter;
+import java.util.Map;
+import java.util.Objects;
+import java.util.concurrent.atomic.AtomicLong;
+
+/**
+ * Spring boot based configuration service that behavious compatible with etcd REST API (excluded the blocking API
+ * calls).
+ */
+@Path("/")
+@Produces({MediaType.APPLICATION_JSON, MediaType.TEXT_PLAIN})
+public class ConfigurationResource {
+    private final String scope;
+    private final AtomicLong readCounter  = new AtomicLong();
+    private final AtomicLong writeCounter  = new AtomicLong();
+    private final AtomicLong deleteCounter  = new AtomicLong();
+
+    public ConfigurationResource(String scope) {
+        this.scope = scope;
+    }
+
+    @GET
+    @Path("/version")
+    @Produces({MediaType.APPLICATION_JSON, MediaType.TEXT_PLAIN})
+    public String version() {
+        return "{ \"version\" : \"Apache Tamaya: 0.2-incubating\" }";
+    }
+
+    @GET
+    @Path("/v2/keys")
+    public String readEtcdConfig(@QueryParam("recursive") Boolean recursive) {
+        return readConfig(recursive);
+    }
+
+    /**
+     *
+     * This models a etcd2 compliant access point for getting a property value.
+     * @return
+     */
+    @GET
+    @Path("/keys")
+    public String readConfig(@QueryParam("recursive") Boolean recursive) {
+        readCounter.incrementAndGet();
+        Configuration config = ConfigurationProvider.getConfiguration();
+        Map<String,String> children = config.getProperties();
+        JsonArrayBuilder ab = Json.createArrayBuilder();
+        for(Map.Entry<String,String> en: children.entrySet()){
+            Node node = new Node(config, en.getKey(), "node");
+            ab.add(node.createJsonObject());
+        }
+        Node node = new Node(config, null, "node", ab.build());
+        JsonObjectBuilder root = Json.createObjectBuilder().add("action", "get")
+                .add("node", node.createJsonObject());
+        StringWriter writer = new StringWriter();
+        JsonWriter jwriter = Json.createWriter(writer);
+        jwriter.writeObject(root.build());
+        return writer.toString();
+    }
+
+    /**
+     * This models a etcd2 compliant access point for getting a property value.
+     * @param key
+     * @return
+     */
+    @GET
+    @Path("/v2/keys/{key}")
+    public String readEtcdConfig(@PathParam("key") String key, @QueryParam("recursive") Boolean recursive) {
+        return readConfig(key, recursive);
+    }
+
+    /**
+     * This models a etcd2 compliant access point for getting a property value.
+     * @param key
+     * @return
+     */
+    @GET
+    @Path("/keys/{key}")
+    public String readConfig(@PathParam("key") String key, @QueryParam("recursive") Boolean recursive) {
+        readCounter.incrementAndGet();
+        Configuration config = ConfigurationProvider.getConfiguration();
+        if(key!=null) {
+            if (key.startsWith("/")) {
+                key = key.substring(1);
+            }
+            if (config.get(key) != null && !recursive) {
+                Node node = new Node(config, key, "node");
+                JsonObjectBuilder root = Json.createObjectBuilder().add("action", "get")
+                        .add("node", node.createJsonObject());
+                StringWriter writer = new StringWriter();
+                JsonGenerator gen = Json.createGenerator(writer);
+                gen.write(root.build());
+                return writer.toString();
+            }
+        }
+        Map<String,String> children = null;
+        if(key==null){
+            children = config.getProperties();
+        } else{
+            children = config.with(ConfigurationFunctions.section(key)).getProperties();
+        }
+        JsonArrayBuilder ab = Json.createArrayBuilder();
+        for(Map.Entry<String,String> en: children.entrySet()){
+            Node node = new Node(config, en.getKey(), "node");
+            ab.add(node.createJsonObject());
+        }
+        Node node = new Node(config, key, "node", ab.build());
+        JsonObjectBuilder root = Json.createObjectBuilder().add("action", "get")
+                .add("node", node.createJsonObject());
+        StringWriter writer = new StringWriter();
+        JsonWriter jwriter = Json.createWriter(writer);
+        jwriter.writeObject(root.build());
+        return writer.toString();
+    }
+
+    @PUT
+    @Path("/v2/keys/{key}")
+    public String writeEtcdConfig(@PathParam("key") String key, @javax.ws.rs.FormParam("value") String value,
+                              @FormParam("ttl") Integer ttl) {
+        return writeConfig(key, value, ttl);
+    }
+    /**
+     * This models a etcd2 compliant access point for getting a property value:
+     * <pre>
+     *     {
+     "action": "set",
+     "node": {
+     "createdIndex": 3,
+     "key": "/message",
+     "modifiedIndex": 3,
+     "value": "Hello etcd"
+     },
+     "prevNode": {
+     "createdIndex": 2,
+     "key": "/message",
+     "value": "Hello world",
+     "modifiedIndex": 2
+     }
+     }
+     * </pre>
+     * @param key
+     * @return
+     */
+    @PUT
+    @Path("/keys/{key}")
+    public String writeConfig(@PathParam("key") String key, @javax.ws.rs.FormParam("value") String value,
+                              @FormParam("ttl") Integer ttl) {
+        writeCounter.incrementAndGet();
+        Configuration config = ConfigurationProvider.getConfiguration();
+        if(key.startsWith("/")){
+            key = key.substring(1);
+        }
+        Node prevNode = new Node(config, key, "prevNode");
+        // TODO implement write! value and ttl as input
+        Node node = new Node(config, key, "node");
+        JsonObjectBuilder root = Json.createObjectBuilder().add("action", "set")
+                .add("node", node.createJsonObject())
+                .add("prevNode", prevNode.createJsonObject());
+        StringWriter writer = new StringWriter();
+        JsonWriter jwriter = Json.createWriter(writer);
+        jwriter.writeObject(root.build());
+        return writer.toString();
+    }
+
+    @DELETE
+    @Path("/v2/keys/{key}")
+    public String deleteEtcdConfig(@PathParam("key") String key) {
+        return deleteConfig(key);
+    }
+    /**
+     * This models a etcd2 compliant access point for getting a property value:
+     * <pre>
+     *     {
+     "action": "set",
+     "node": {
+     "createdIndex": 3,
+     "key": "/message",
+     "modifiedIndex": 3,
+     "value": "Hello etcd"
+     },
+     "prevNode": {
+     "createdIndex": 2,
+     "key": "/message",
+     "value": "Hello world",
+     "modifiedIndex": 2
+     }
+     }
+     * </pre>
+     * @param key
+     * @return
+     */
+    @DELETE
+    @Path("/keys/{key}")
+    public String deleteConfig(@PathParam("key") String key) {
+        deleteCounter.incrementAndGet();
+        Configuration config = ConfigurationProvider.getConfiguration();
+        if(key.startsWith("/")){
+            key = key.substring(1);
+        }
+        Node prevNode = new Node(config, key, "prevNode");
+        // TODO implement write! value and ttl as input
+        Node node = new Node(config, key, "node");
+        JsonObjectBuilder root = Json.createObjectBuilder().add("action", "delete")
+                .add("node", node.createJsonObject())
+                .add("prevNode", prevNode.createJsonObject());
+        StringWriter writer = new StringWriter();
+        JsonWriter jwriter = Json.createWriter(writer);
+        jwriter.writeObject(root.build());
+        return writer.toString();
+    }
+
+    public long getDeleteCounter(){
+        return deleteCounter.get();
+    }
+
+    public long getReadCounter(){
+        return readCounter.get();
+    }
+
+    public long getWriteCounter(){
+        return writeCounter.get();
+    }
+
+    /**
+     * Internal representation of a configuration node as modelled by etc.
+     */
+    private static final class Node{
+        private Integer createdIndex;
+        private Integer modifiedIndex;
+        private String key;
+        private String value;
+        private String nodeId;
+        private Integer ttl;
+        private String expiration;
+        private JsonArray nodes;
+
+        Node(Configuration config, String key, String nodeId){
+            this(config, key, nodeId, null);
+        }
+        Node(Configuration config, String key, String nodeId, JsonArray nodes){
+            this.key = key;
+            this.nodeId = Objects.requireNonNull(nodeId);
+            if(key!=null) {
+                value = config.get(key);
+                createdIndex = config.getOrDefault("_" + key + ".createdIndex", Integer.class, null);
+                modifiedIndex = config.getOrDefault("_" + key + ".modifiedIndex", Integer.class, null);
+                ttl = config.getOrDefault("_" + key + ".ttl", Integer.class, null);
+                expiration = config.getOrDefault("_" + key + ".expiration", null);
+            }
+            this.nodes = nodes;
+        }
+
+        JsonObject createJsonObject(){
+            JsonObjectBuilder nodeBuilder = Json.createObjectBuilder();
+            if(key!=null) {
+                nodeBuilder.add("key", '/' + key);
+            }else{
+                nodeBuilder.add("dir", true);
+            }
+            if(value!=null){
+                nodeBuilder.add("value", value);
+            }
+            if(createdIndex!=null){
+                nodeBuilder.add("createdIndex", createdIndex.intValue());
+            }
+            if(modifiedIndex!=null){
+                nodeBuilder.add("modifiedIndex", modifiedIndex.intValue());
+            }
+            if(ttl!=null){
+                nodeBuilder.add("ttl", ttl.intValue());
+            }
+            if(expiration!=null){
+                nodeBuilder.add("expiration", value);
+            }
+            if(nodes!=null){
+                nodeBuilder.add("nodes", nodes);
+            }
+            return nodeBuilder.build();
+        }
+    }
+
+}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/incubator-tamaya/blob/d778cb81/modules/server/src/main/java/org/apache/tamaya/server/FilteredConfigServlet.java
----------------------------------------------------------------------
diff --git a/modules/server/src/main/java/org/apache/tamaya/server/FilteredConfigServlet.java b/modules/server/src/main/java/org/apache/tamaya/server/FilteredConfigServlet.java
deleted file mode 100644
index 8fe0f49..0000000
--- a/modules/server/src/main/java/org/apache/tamaya/server/FilteredConfigServlet.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.server;
-
-import org.apache.http.HttpStatus;
-import org.apache.tamaya.server.internal.MediaTypeUtil;
-import org.apache.tamaya.server.spi.ConfigService;
-import org.apache.tamaya.spi.ServiceContextManager;
-
-import javax.servlet.ServletException;
-import javax.servlet.http.HttpServlet;
-import javax.servlet.http.HttpServletRequest;
-import javax.servlet.http.HttpServletResponse;
-import javax.ws.rs.core.HttpHeaders;
-import javax.ws.rs.core.MediaType;
-import javax.ws.rs.core.Response;
-import java.io.IOException;
-import java.util.logging.Level;
-import java.util.logging.Logger;
-
-/**
- * Servlet to be registered for answering requests for filterted configuration. You can register this servlet e.g.
- * under {@code /config/filtered}. Then it allows to perform requests in the form of {@code /config/filtered/$PATH},
- * e.g. {@code /config/filtered/java,sun?scope=CLIENT&scopeId=1.2.3.4&format=text/json}.
- */
-public class FilteredConfigServlet extends HttpServlet{
-
-    private static final Logger LOG = Logger.getLogger(FilteredConfigServlet.class.getName());
-
-    private static final long serialVersionUID = 1L;
-
-    /**
-     * Gets the Service delegate to provide the configuration representation in different formats and scopes.
-     */
-    private ConfigService getConfService(){
-        return ServiceContextManager.getServiceContext()
-                    .getService(ConfigService.class);
-    }
-
-    @Override
-    protected void doGet(HttpServletRequest request, HttpServletResponse res) throws ServletException, IOException {
-        MediaType mediaType = MediaTypeUtil.getMediaType(request.getParameter("format"),request.getHeader(HttpHeaders.ACCEPT));
-        String scope = request.getParameter("scope");
-        String scopeId = request.getParameter("scopeId");
-        String path = request.getPathInfo();
-        if(path==null || path.isEmpty()){
-            res.setStatus(HttpStatus.SC_BAD_REQUEST);
-            return;
-        }
-        if(path.startsWith("/")){
-            path = path.substring(1);
-        }
-        try {
-            String response = getConfService().getConfigurationWithPath(path, mediaType, scope, scopeId, request);
-            if(response!=null){
-                res.setStatus(HttpStatus.SC_OK);
-                res.setHeader(HttpHeaders.CONTENT_ENCODING, "utf-8");
-                res.setContentType(mediaType.toString());
-                res.setHeader(HttpHeaders.CONTENT_TYPE, MediaType.APPLICATION_JSON_TYPE.toString());
-                res.getOutputStream().print(response);
-                return;
-            }
-            res.setStatus(HttpStatus.SC_BAD_REQUEST);
-        } catch(Exception e){
-            LOG.log(Level.SEVERE, "Error printing config.", e);
-            Response.status(Response.Status.INTERNAL_SERVER_ERROR);
-        }
-    }
-
-}

http://git-wip-us.apache.org/repos/asf/incubator-tamaya/blob/d778cb81/modules/server/src/main/java/org/apache/tamaya/server/FullConfigServlet.java
----------------------------------------------------------------------
diff --git a/modules/server/src/main/java/org/apache/tamaya/server/FullConfigServlet.java b/modules/server/src/main/java/org/apache/tamaya/server/FullConfigServlet.java
deleted file mode 100644
index daddead..0000000
--- a/modules/server/src/main/java/org/apache/tamaya/server/FullConfigServlet.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.server;
-
-import org.apache.http.HttpStatus;
-import org.apache.tamaya.server.internal.MediaTypeUtil;
-import org.apache.tamaya.server.spi.ConfigService;
-import org.apache.tamaya.spi.ServiceContextManager;
-
-import javax.servlet.ServletException;
-import javax.servlet.http.HttpServlet;
-import javax.servlet.http.HttpServletRequest;
-import javax.servlet.http.HttpServletResponse;
-import javax.ws.rs.core.HttpHeaders;
-import javax.ws.rs.core.MediaType;
-import javax.ws.rs.core.Response;
-import java.io.IOException;
-import java.util.logging.Level;
-import java.util.logging.Logger;
-
-
-/**
- * Servlet to be registered for answering requests for accessing unscoped configuration. You can register this
- * servlet e.g. under {@code /config}. Then it allows to perform requests in the form of
- * {@code /config/java,sun?scope=CLIENT&scopeId=1.2.3.4&format=text/json}.
- */
-public class FullConfigServlet extends HttpServlet{
-
-    private static final Logger LOG = Logger.getLogger(FilteredConfigServlet.class.getName());
-
-    private static final long serialVersionUID = 1L;
-
-    /**
-     * Gets the Service delegate to provide the configuration representation in different formats and scopes.
-     */
-    private ConfigService getConfService(){
-        return ServiceContextManager.getServiceContext()
-                .getService(ConfigService.class);
-    }
-
-    /**
-     * Servlet to be registered for answering requests for accessing unscoped configuration. You can register this
-     * servlet e.g. under {@code /config}. Then it allows to perform requests in the form of
-     * {@code /config/java,sun?scope=CLIENT&scopeId=1.2.3.4&format=text/json}.
-     */
-    @Override
-    protected void doGet(HttpServletRequest request, HttpServletResponse res) throws ServletException, IOException {
-        MediaType mediaType = MediaTypeUtil.getMediaType(request.getParameter("format"),
-                request.getHeader(HttpHeaders.ACCEPT));
-        String scope = request.getParameter("scope");
-        String scopeId = request.getParameter("scopeId");
-        try {
-            String response = getConfService().getConfiguration(mediaType, scope, scopeId, request);
-            if(response!=null) {
-                res.setStatus(HttpStatus.SC_OK);
-                res.setHeader(HttpHeaders.CONTENT_ENCODING, "utf-8");
-                if (mediaType.equals(MediaType.APPLICATION_JSON_TYPE)) {
-                    res.setHeader(HttpHeaders.CONTENT_TYPE, MediaType.APPLICATION_JSON_TYPE.toString());
-                    res.getOutputStream().print(response);
-                    return;
-                }
-            }
-            res.setStatus(HttpStatus.SC_BAD_REQUEST);
-        } catch(Exception e){
-            LOG.log(Level.SEVERE, "Error printing config.", e);
-            Response.status(Response.Status.INTERNAL_SERVER_ERROR);
-        }
-    }
-
-}

http://git-wip-us.apache.org/repos/asf/incubator-tamaya/blob/d778cb81/modules/server/src/main/java/org/apache/tamaya/server/Server.java
----------------------------------------------------------------------
diff --git a/modules/server/src/main/java/org/apache/tamaya/server/Server.java b/modules/server/src/main/java/org/apache/tamaya/server/Server.java
deleted file mode 100644
index 5e2cb52..0000000
--- a/modules/server/src/main/java/org/apache/tamaya/server/Server.java
+++ /dev/null
@@ -1,46 +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.server;
-
-/**
- * Simple abstraction of the Server interface.
- */
-public interface Server {
-    /**
-     * Starts the server on the given port-
-     * @param port the target port.
-     */
-    void start(int port);
-
-    /**
-     * Checks if the server us started.
-     * @return true if the server us started.
-     */
-    boolean isStarted();
-
-    /**
-     * Stops the server, but does not destroy it, so it might be restarted.
-     */
-    void stop();
-
-    /**
-     * Destroy the server instance.
-     */
-    void destroy();
-}



[5/8] incubator-tamaya git commit: TAMAYA-136: Adding PropertyValue for PropertySource SPI.

Posted by an...@apache.org.
TAMAYA-136: Adding PropertyValue for PropertySource SPI.


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

Branch: refs/heads/master
Commit: 0be037b844450e30ab58a78cab9ddd9bd07585c1
Parents: 80432ae
Author: anatole <an...@apache.org>
Authored: Tue Feb 2 15:24:18 2016 +0100
Committer: anatole <an...@apache.org>
Committed: Tue Feb 2 15:24:18 2016 +0100

----------------------------------------------------------------------
 .../core/internal/DefaultConfiguration.java     |  17 +-
 .../tamaya/core/internal/PropertyFiltering.java |  40 ++--
 .../core/propertysource/BasePropertySource.java |  30 ++-
 .../EnvironmentPropertySource.java              |   5 +-
 .../propertysource/SystemPropertySource.java    |   6 +-
 .../ConverterTestsPropertySource.java           | 189 ++++++++++---------
 .../propertysource/BasePropertySourceTest.java  |   7 +-
 .../EnvironmentPropertySourceTest.java          |   2 +-
 .../PropertiesFilePropertySourceTest.java       |   9 +-
 .../SystemPropertySourceTest.java               |   6 +-
 .../provider/JavaConfigurationProviderTest.java |   2 +-
 .../core/testdata/TestPropertyFilter.java       |   5 +-
 .../testdata/TestRemovingPropertyFilter.java    |   7 +-
 13 files changed, 187 insertions(+), 138 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/incubator-tamaya/blob/0be037b8/code/core/src/main/java/org/apache/tamaya/core/internal/DefaultConfiguration.java
----------------------------------------------------------------------
diff --git a/code/core/src/main/java/org/apache/tamaya/core/internal/DefaultConfiguration.java b/code/core/src/main/java/org/apache/tamaya/core/internal/DefaultConfiguration.java
index f7c363c..0f74628 100644
--- a/code/core/src/main/java/org/apache/tamaya/core/internal/DefaultConfiguration.java
+++ b/code/core/src/main/java/org/apache/tamaya/core/internal/DefaultConfiguration.java
@@ -23,7 +23,12 @@ import org.apache.tamaya.ConfigOperator;
 import org.apache.tamaya.ConfigQuery;
 import org.apache.tamaya.Configuration;
 import org.apache.tamaya.TypeLiteral;
-import org.apache.tamaya.spi.*;
+import org.apache.tamaya.spi.ConfigurationContext;
+import org.apache.tamaya.spi.ConversionContext;
+import org.apache.tamaya.spi.PropertyConverter;
+import org.apache.tamaya.spi.PropertyFilter;
+import org.apache.tamaya.spi.PropertySource;
+import org.apache.tamaya.spi.PropertyValueCombinationPolicy;
 
 import java.util.ArrayList;
 import java.util.Collections;
@@ -61,12 +66,16 @@ public class DefaultConfiguration implements Configuration {
 
 
     public String get(String key) {
-        return PropertyFiltering.applyFilter(key, evaluteRawValue(key), configurationContext);
+        Map<String,String> value = evaluteRawValue(key);
+        if(value==null || value.get(key)==null){
+            return null;
+        }
+        return PropertyFiltering.applyFilter(key, value, configurationContext);
     }
 
-    protected String evaluteRawValue(String key) {
+    protected Map<String,String> evaluteRawValue(String key) {
         List<PropertySource> propertySources = configurationContext.getPropertySources();
-        String unfilteredValue = null;
+        Map<String,String> unfilteredValue = null;
         PropertyValueCombinationPolicy combinationPolicy = this.configurationContext
                 .getPropertyValueCombinationPolicy();
         for (PropertySource propertySource : propertySources) {

http://git-wip-us.apache.org/repos/asf/incubator-tamaya/blob/0be037b8/code/core/src/main/java/org/apache/tamaya/core/internal/PropertyFiltering.java
----------------------------------------------------------------------
diff --git a/code/core/src/main/java/org/apache/tamaya/core/internal/PropertyFiltering.java b/code/core/src/main/java/org/apache/tamaya/core/internal/PropertyFiltering.java
index 9f84e7c..f0d15bc 100644
--- a/code/core/src/main/java/org/apache/tamaya/core/internal/PropertyFiltering.java
+++ b/code/core/src/main/java/org/apache/tamaya/core/internal/PropertyFiltering.java
@@ -19,9 +19,11 @@
 package org.apache.tamaya.core.internal;
 
 import org.apache.tamaya.spi.ConfigurationContext;
+import org.apache.tamaya.spi.FilterContext;
 import org.apache.tamaya.spi.PropertyFilter;
 import org.apache.tamaya.spi.PropertySource;
 
+import java.util.Collections;
 import java.util.HashMap;
 import java.util.Map;
 import java.util.concurrent.atomic.AtomicInteger;
@@ -38,6 +40,7 @@ public final class PropertyFiltering{
      * The logger.
      */
     private static final Logger LOG = Logger.getLogger(PropertyFiltering.class.getName());
+
     /**
      * The maximal number of filter cycles performed before aborting.
      */
@@ -48,25 +51,27 @@ public final class PropertyFiltering{
      */
     private PropertyFiltering(){}
 
-    public static String applyFilter(String key, String unfilteredValue, ConfigurationContext configurationContext) {
+    public static String applyFilter(String key, Map<String,String> configData, ConfigurationContext configurationContext) {
         // Apply filters to values, prevent values filtered to null!
+        String result = configData.get(key);
         for (int i = 0; i < MAX_FILTER_LOOPS; i++) {
             boolean changed = false;
             // Apply filters to values, prevent values filtered to null!
+            FilterContext filterContext = new FilterContext(key, configData);
             for (PropertyFilter filter : configurationContext.getPropertyFilters()) {
-                String newValue = filter.filterProperty(key, unfilteredValue);
-                if (newValue != null && !newValue.equals(unfilteredValue)) {
+                String newValue = filter.filterProperty(result, filterContext);
+                if (newValue != null && !newValue.equals(result)) {
                     changed = true;
                     if (LOG.isLoggable(Level.FINEST)) {
-                        LOG.finest("Filter - " + key + ": " + unfilteredValue + " -> " + newValue + " by " + filter);
+                        LOG.finest("Filter - " + key + ": " + result + " -> " + newValue + " by " + filter);
                     }
-                } else if (unfilteredValue != null && !unfilteredValue.equals(newValue)) {
+                } else if (result != null && !result.equals(newValue)) {
                     changed = true;
                     if (LOG.isLoggable(Level.FINEST)) {
-                        LOG.finest("Filter - " + key + ": " + unfilteredValue + " -> " + newValue + " by " + filter);
+                        LOG.finest("Filter - " + key + ": " + result + " -> " + newValue + " by " + filter);
                     }
                 }
-                unfilteredValue = newValue;
+                result = newValue;
             }
             if (!changed) {
                 LOG.finest("Finishing filter loop, no changes detected.");
@@ -81,20 +86,21 @@ public final class PropertyFiltering{
                 }
             }
         }
-        return unfilteredValue;
+        return result;
     }
 
     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!
+        Map<String, String> metaData = filterMetadata(inputMap);
         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()) {
+            for (Map.Entry<String, String> entry : inputMap.entrySet()) {
+                FilterContext filterContext = new FilterContext(entry.getKey(), inputMap);
+                for (PropertyFilter filter : configurationContext.getPropertyFilters()) {
                     final String k = entry.getKey();
                     final String v = entry.getValue();
-
-                    String newValue = filter.filterProperty(k, v);
+                    String newValue = filter.filterProperty(v, filterContext);
                     if (newValue != null && !newValue.equals(v)) {
                         changes.incrementAndGet();
                         LOG.finest("Filter - " + k + ": " + v + " -> " + newValue + " by " + filter);
@@ -128,4 +134,14 @@ public final class PropertyFiltering{
         return resultMap;
     }
 
+    private static Map<String, String> filterMetadata(Map<String, String> inputMap) {
+        Map<String,String> result = new HashMap<>();
+        for(Map.Entry<String,String> en:inputMap.entrySet()){
+            if(en.getKey().startsWith("_")){
+                result.put(en.getKey(), en.getValue());
+            }
+        }
+        return Collections.unmodifiableMap(result);
+    }
+
 }

http://git-wip-us.apache.org/repos/asf/incubator-tamaya/blob/0be037b8/code/core/src/main/java/org/apache/tamaya/core/propertysource/BasePropertySource.java
----------------------------------------------------------------------
diff --git a/code/core/src/main/java/org/apache/tamaya/core/propertysource/BasePropertySource.java b/code/core/src/main/java/org/apache/tamaya/core/propertysource/BasePropertySource.java
index e9f53f9..b5c7378 100644
--- a/code/core/src/main/java/org/apache/tamaya/core/propertysource/BasePropertySource.java
+++ b/code/core/src/main/java/org/apache/tamaya/core/propertysource/BasePropertySource.java
@@ -19,7 +19,10 @@
 package org.apache.tamaya.core.propertysource;
 
 import org.apache.tamaya.spi.PropertySource;
+import org.apache.tamaya.spi.PropertyValue;
+import org.apache.tamaya.spi.PropertyValueBuilder;
 
+import java.util.Map;
 import java.util.logging.Level;
 import java.util.logging.Logger;
 
@@ -53,13 +56,14 @@ public abstract class BasePropertySource implements PropertySource{
 
     @Override
     public int getOrdinal() {
-        String configuredOrdinal = get(TAMAYA_ORDINAL);
+        PropertyValue configuredOrdinal = get(TAMAYA_ORDINAL);
+
         if(configuredOrdinal!=null){
-            try{
-                return Integer.parseInt(configuredOrdinal);
-            } catch(Exception e){
+            try {
+                return Integer.parseInt(configuredOrdinal.getValue());
+            } catch (Exception e) {
                 Logger.getLogger(getClass().getName()).log(Level.WARNING,
-                        "Configured Ordinal is not an int number: " + configuredOrdinal, e);
+                        "Configured Ordinal is not an int number: " + configuredOrdinal.getValue(), e);
             }
         }
         return getDefaultOrdinal();
@@ -74,8 +78,20 @@ public abstract class BasePropertySource implements PropertySource{
     }
 
     @Override
-    public String get(String key) {
-        return getProperties().get(key);
+    public PropertyValue get(String key) {
+        Map<String,String> properties = getProperties();
+        String val = properties.get(key);
+        if(val==null){
+            return null;
+        }
+        PropertyValueBuilder b = new PropertyValueBuilder(key, val, getName());
+        String metaKeyStart = "_" + key + ".";
+        for(Map.Entry<String,String> en:properties.entrySet()) {
+            if(en.getKey().startsWith(metaKeyStart)){
+                b.addContextData(en.getKey().substring(metaKeyStart.length()), en.getValue());
+            }
+        }
+        return b.build();
     }
 
     @Override

http://git-wip-us.apache.org/repos/asf/incubator-tamaya/blob/0be037b8/code/core/src/main/java/org/apache/tamaya/core/propertysource/EnvironmentPropertySource.java
----------------------------------------------------------------------
diff --git a/code/core/src/main/java/org/apache/tamaya/core/propertysource/EnvironmentPropertySource.java b/code/core/src/main/java/org/apache/tamaya/core/propertysource/EnvironmentPropertySource.java
index c8c1aa3..841d432 100644
--- a/code/core/src/main/java/org/apache/tamaya/core/propertysource/EnvironmentPropertySource.java
+++ b/code/core/src/main/java/org/apache/tamaya/core/propertysource/EnvironmentPropertySource.java
@@ -19,6 +19,7 @@
 package org.apache.tamaya.core.propertysource;
 
 import org.apache.tamaya.spi.PropertySource;
+import org.apache.tamaya.spi.PropertyValue;
 
 import java.util.Map;
 
@@ -46,8 +47,8 @@ public class EnvironmentPropertySource implements PropertySource {
     }
 
     @Override
-    public String get(String key) {
-        return getProperties().get(key);
+    public PropertyValue get(String key) {
+        return PropertyValue.of(key, System.getenv(key), getName());
     }
 
     @Override

http://git-wip-us.apache.org/repos/asf/incubator-tamaya/blob/0be037b8/code/core/src/main/java/org/apache/tamaya/core/propertysource/SystemPropertySource.java
----------------------------------------------------------------------
diff --git a/code/core/src/main/java/org/apache/tamaya/core/propertysource/SystemPropertySource.java b/code/core/src/main/java/org/apache/tamaya/core/propertysource/SystemPropertySource.java
index 9093f25..80cd140 100644
--- a/code/core/src/main/java/org/apache/tamaya/core/propertysource/SystemPropertySource.java
+++ b/code/core/src/main/java/org/apache/tamaya/core/propertysource/SystemPropertySource.java
@@ -19,6 +19,8 @@
 package org.apache.tamaya.core.propertysource;
 
 import org.apache.tamaya.spi.PropertySource;
+import org.apache.tamaya.spi.PropertyValue;
+import org.apache.tamaya.spi.PropertyValueBuilder;
 
 import java.util.Collections;
 import java.util.HashMap;
@@ -69,8 +71,8 @@ public class SystemPropertySource implements PropertySource {
     }
 
     @Override
-    public String get(String key) {
-        return getProperties().get(key);
+    public PropertyValue get(String key) {
+        return PropertyValue.of(key, System.getProperty(key), getName());
     }
 
     @Override

http://git-wip-us.apache.org/repos/asf/incubator-tamaya/blob/0be037b8/code/core/src/test/java/org/apache/tamaya/core/internal/converters/ConverterTestsPropertySource.java
----------------------------------------------------------------------
diff --git a/code/core/src/test/java/org/apache/tamaya/core/internal/converters/ConverterTestsPropertySource.java b/code/core/src/test/java/org/apache/tamaya/core/internal/converters/ConverterTestsPropertySource.java
index 26ad140..c2fe2d3 100644
--- a/code/core/src/test/java/org/apache/tamaya/core/internal/converters/ConverterTestsPropertySource.java
+++ b/code/core/src/test/java/org/apache/tamaya/core/internal/converters/ConverterTestsPropertySource.java
@@ -19,6 +19,7 @@
 package org.apache.tamaya.core.internal.converters;
 
 import org.apache.tamaya.spi.PropertySource;
+import org.apache.tamaya.spi.PropertyValue;
 
 import java.util.Collections;
 import java.util.Map;
@@ -38,204 +39,204 @@ public class ConverterTestsPropertySource implements PropertySource{
     }
 
     @Override
-    public String get(String key) {
+    public PropertyValue get(String key) {
         switch(key){
             // Bytes
             case "tests.converter.byte.decimal":
-                return "101";
+                return PropertyValue.of(key, "101", getName());
             case "tests.converter.byte.octal":
-                return "02";
+                return PropertyValue.of(key, "02", getName());
             case "tests.converter.byte.hex.lowerX":
-                return "0x2F";
+                return PropertyValue.of(key, "0x2F", getName());
             case "tests.converter.byte.hex.upperX":
-                return "0X3F";
+                return PropertyValue.of(key, "0X3F", getName());
             case "tests.converter.byte.min":
-                return "min";
+                return PropertyValue.of(key, "min", getName());
             case "tests.converter.byte.max":
-                return "MAX_Value";
+                return PropertyValue.of(key, "MAX_Value", getName());
             // Boolean
             case "tests.converter.boolean.y1":
-                return "y";
+                return PropertyValue.of(key, "y", getName());
             case "tests.converter.boolean.y2":
-                return "Y";
+                return PropertyValue.of(key, "Y", getName());
             case "tests.converter.boolean.yes1":
-                return "yes";
+                return PropertyValue.of(key, "yes", getName());
             case "tests.converter.boolean.yes2":
-                return "Yes";
+                return PropertyValue.of(key, "Yes", getName());
             case "tests.converter.boolean.yes3":
-                return "yeS";
+                return PropertyValue.of(key, "yeS", getName());
             case "tests.converter.boolean.true1":
-                return "true";
+                return PropertyValue.of(key, "true", getName());
             case "tests.converter.boolean.true2":
-                return "True";
+                return PropertyValue.of(key, "True", getName());
             case "tests.converter.boolean.true3":
-                return "trUe";
+                return PropertyValue.of(key, "trUe", getName());
             case "tests.converter.boolean.t1":
-                return "t";
+                return PropertyValue.of(key, "t", getName());
             case "tests.converter.boolean.t2":
-                return "T";
+                return PropertyValue.of(key, "T", getName());
             case "tests.converter.boolean.n1":
-                return "n";
+                return PropertyValue.of(key, "n", getName());
             case "tests.converter.boolean.n2":
-                return "N";
+                return PropertyValue.of(key, "N", getName());
             case "tests.converter.boolean.no1":
-                return "no";
+                return PropertyValue.of(key, "no", getName());
             case "tests.converter.boolean.no2":
-                return "No";
+                return PropertyValue.of(key, "No", getName());
             case "tests.converter.boolean.no3":
-                return "nO";
+                return PropertyValue.of(key, "nO", getName());
             case "tests.converter.boolean.false1":
-                return "false";
+                return PropertyValue.of(key, "false", getName());
             case "tests.converter.boolean.false2":
-                return "False";
+                return PropertyValue.of(key, "False", getName());
             case "tests.converter.boolean.false3":
-                return "falSe";
+                return PropertyValue.of(key, "falSe", getName());
             case "tests.converter.boolean.f1":
-                return "f";
+                return PropertyValue.of(key, "f", getName());
             case "tests.converter.boolean.f2":
-                return "F";
+                return PropertyValue.of(key, "F", getName());
             // Character
             case "tests.converter.char.f":
-                return "f";
+                return PropertyValue.of(key, "f", getName());
             case "tests.converter.char.d":
-                return "'d'";
+                return PropertyValue.of(key, "'d'", getName());
             case "tests.converter.char.f-before":
-                return "  f";
+                return PropertyValue.of(key, "  f", getName());
             case "tests.converter.char.f-after":
-                return "f   ";
+                return PropertyValue.of(key, "f   ", getName());
             case "tests.converter.char.f-around":
-                return "   f      ";
+                return PropertyValue.of(key, "   f      ", getName());
             case "tests.converter.char.f-numeric":
-                return "101";
+                return PropertyValue.of(key, "101", getName());
             // currency
             case "tests.converter.currency.code1":
-                return "CHF";
+                return PropertyValue.of(key, "CHF", getName());
             case "tests.converter.currency.code2":
-                return "cHf";
+                return PropertyValue.of(key, "cHf", getName());
             case "tests.converter.currency.code3":
-                return "  CHF";
+                return PropertyValue.of(key, "  CHF", getName());
             case "tests.converter.currency.code4":
-                return "CHF   ";
+                return PropertyValue.of(key, "CHF   ", getName());
             case "tests.converter.currency.code5":
-                return "  CHF   ";
+                return PropertyValue.of(key, "  CHF   ", getName());
             case "tests.converter.currency.code-numeric1":
-                return "100";
+                return PropertyValue.of(key, "100", getName());
             case "tests.converter.currency.code-numeric2":
-                return "  100";
+                return PropertyValue.of(key, "  100", getName());
             case "tests.converter.currency.code-numeric3":
-                return "100  ";
+                return PropertyValue.of(key, "100  ", getName());
             case "tests.converter.currency.code-numeric4":
-                return "  100  ";
+                return PropertyValue.of(key, "  100  ", getName());
             case "tests.converter.currency.code-locale1":
-                return "DE";
+                return PropertyValue.of(key, "DE", getName());
             case "tests.converter.currency.code-locale2":
-                return "  DE";
+                return PropertyValue.of(key, "  DE", getName());
             case "tests.converter.currency.code-locale3":
-                return "DE  ";
+                return PropertyValue.of(key, "DE  ", getName());
             case "tests.converter.currency.code-locale4":
-                return "  DE  ";
+                return PropertyValue.of(key, "  DE  ", getName());
             //double
             case "tests.converter.double.decimal":
-                return "1.23456789";
+                return PropertyValue.of(key, "1.23456789", getName());
             case "tests.converter.double.decimalNegative":
-                return "-1.23456789";
+                return PropertyValue.of(key, "-1.23456789", getName());
             case "tests.converter.double.integer":
-                return "  100";
+                return PropertyValue.of(key, "  100", getName());
             case "tests.converter.double.hex1":
-                return " 0XFF";
+                return PropertyValue.of(key, " 0XFF", getName());
             case "tests.converter.double.hex2":
-                return "-0xFF  ";
+                return PropertyValue.of(key, "-0xFF  ", getName());
             case "tests.converter.double.hex3":
-                return "#FF";
+                return PropertyValue.of(key, "#FF", getName());
             case "tests.converter.double.octal":
-                return "0013";
+                return PropertyValue.of(key, "0013", getName());
             case "tests.converter.double.min":
-                return "MIN_Value";
+                return PropertyValue.of(key, "MIN_Value", getName());
             case "tests.converter.double.max":
-                return "max";
+                return PropertyValue.of(key, "max", getName());
             case "tests.converter.double.nan":
-                return "NAN";
+                return PropertyValue.of(key, "NAN", getName());
             case "tests.converter.double.pi":
-                return "positive_infinity";
+                return PropertyValue.of(key, "positive_infinity", getName());
             case "tests.converter.double.ni":
-                return "Negative_Infinity";
+                return PropertyValue.of(key, "Negative_Infinity", getName());
             //float
             case "tests.converter.float.decimal":
-                return "1.23456789";
+                return PropertyValue.of(key, "1.23456789", getName());
             case "tests.converter.float.decimalNegative":
-                return "-1.23456789";
+                return PropertyValue.of(key, "-1.23456789", getName());
             case "tests.converter.float.integer":
-                return "  100";
+                return PropertyValue.of(key, "  100", getName());
             case "tests.converter.float.hex1":
-                return " 0XFF";
+                return PropertyValue.of(key, " 0XFF", getName());
             case "tests.converter.float.hex2":
-                return "-0xFF  ";
+                return PropertyValue.of(key, "-0xFF  ", getName());
             case "tests.converter.float.hex3":
-                return "#FF";
+                return PropertyValue.of(key, "#FF", getName());
             case "tests.converter.float.octal":
-                return "0013";
+                return PropertyValue.of(key, "0013", getName());
             case "tests.converter.float.min":
-                return "MIN_Value";
+                return PropertyValue.of(key, "MIN_Value", getName());
             case "tests.converter.float.max":
-                return "max";
+                return PropertyValue.of(key, "max", getName());
             case "tests.converter.float.nan":
-                return "NAN";
+                return PropertyValue.of(key, "NAN", getName());
             case "tests.converter.float.pi":
-                return "positive_infinity";
+                return PropertyValue.of(key, "positive_infinity", getName());
             case "tests.converter.float.ni":
-                return "Negative_Infinity";
+                return PropertyValue.of(key, "Negative_Infinity", getName());
             // Integer
             case "tests.converter.integer.decimal":
-                return "101";
+                return PropertyValue.of(key, "101", getName());
             case "tests.converter.integer.octal":
-                return "02";
+                return PropertyValue.of(key, "02", getName());
             case "tests.converter.integer.hex.lowerX":
-                return "0x2F";
+                return PropertyValue.of(key, "0x2F", getName());
             case "tests.converter.integer.hex.upperX":
-                return "0X3F";
+                return PropertyValue.of(key, "0X3F", getName());
             case "tests.converter.integer.min":
-                return "min";
+                return PropertyValue.of(key, "min", getName());
             case "tests.converter.integer.max":
-                return "MAX_Value";
+                return PropertyValue.of(key, "MAX_Value", getName());
             // Long
             case "tests.converter.long.decimal":
-                return "101";
+                return PropertyValue.of(key, "101", getName());
             case "tests.converter.long.octal":
-                return "02";
+                return PropertyValue.of(key, "02", getName());
             case "tests.converter.long.hex.lowerX":
-                return "0x2F";
+                return PropertyValue.of(key, "0x2F", getName());
             case "tests.converter.long.hex.upperX":
-                return "0X3F";
+                return PropertyValue.of(key, "0X3F", getName());
             case "tests.converter.long.min":
-                return "min";
+                return PropertyValue.of(key, "min", getName());
             case "tests.converter.long.max":
-                return "MAX_Value";
+                return PropertyValue.of(key, "MAX_Value", getName());
             // Short
             case "tests.converter.short.decimal":
-                return "101";
+                return PropertyValue.of(key, "101", getName());
             case "tests.converter.short.octal":
-                return "02";
+                return PropertyValue.of(key, "02", getName());
             case "tests.converter.short.hex.lowerX":
-                return "0x2F";
+                return PropertyValue.of(key, "0x2F", getName());
             case "tests.converter.short.hex.upperX":
-                return "0X3F";
+                return PropertyValue.of(key, "0X3F", getName());
             case "tests.converter.short.min":
-                return "min";
+                return PropertyValue.of(key, "min", getName());
             case "tests.converter.short.max":
-                return "MAX_Value";
+                return PropertyValue.of(key, "MAX_Value", getName());
             // BigDecimal
             case "tests.converter.bd.decimal":
-                return "101";
+                return PropertyValue.of(key, "101", getName());
             case "tests.converter.bd.float":
-                return "101.36438746";
+                return PropertyValue.of(key, "101.36438746", getName());
             case "tests.converter.bd.big":
-                return "101666666666666662333337263723628763821638923628193612983618293628763";
+                return PropertyValue.of(key, "101666666666666662333337263723628763821638923628193612983618293628763", getName());
             case "tests.converter.bd.bigFloat":
-                return "1016666666666666623333372637236287638216389293628763.101666666666666662333337263723628763821638923628193612983618293628763";
+                return PropertyValue.of(key, "1016666666666666623333372637236287638216389293628763.101666666666666662333337263723628763821638923628193612983618293628763", getName());
             case "tests.converter.bd.hex.lowerX":
-                return "0x2F";
+                return PropertyValue.of(key, "0x2F", getName());
             case "tests.converter.bd.hex.upperX":
-                return "0X3F";
+                return PropertyValue.of(key, "0X3F", getName());
         }
         return null;
     }

http://git-wip-us.apache.org/repos/asf/incubator-tamaya/blob/0be037b8/code/core/src/test/java/org/apache/tamaya/core/propertysource/BasePropertySourceTest.java
----------------------------------------------------------------------
diff --git a/code/core/src/test/java/org/apache/tamaya/core/propertysource/BasePropertySourceTest.java b/code/core/src/test/java/org/apache/tamaya/core/propertysource/BasePropertySourceTest.java
index 8d3f086..8ab1baf 100644
--- a/code/core/src/test/java/org/apache/tamaya/core/propertysource/BasePropertySourceTest.java
+++ b/code/core/src/test/java/org/apache/tamaya/core/propertysource/BasePropertySourceTest.java
@@ -18,8 +18,9 @@
  */
 package org.apache.tamaya.core.propertysource;
 
-import org.apache.tamaya.core.propertysource.BasePropertySource;
 import org.apache.tamaya.spi.PropertySource;
+import org.apache.tamaya.spi.PropertyValue;
+import org.apache.tamaya.spi.PropertyValueBuilder;
 import org.junit.Assert;
 import org.junit.Test;
 
@@ -40,7 +41,7 @@ public class BasePropertySourceTest {
             }
 
             @Override
-            public String get(String key) {
+            public PropertyValue get(String key) {
                 return null;
             }
 
@@ -59,7 +60,7 @@ public class BasePropertySourceTest {
 
     @Test
     public void testGet() {
-        Assert.assertEquals("1000", new OverriddenOrdinalPropertySource().get(PropertySource.TAMAYA_ORDINAL));
+        Assert.assertEquals("1000", new OverriddenOrdinalPropertySource().get(PropertySource.TAMAYA_ORDINAL).get(PropertySource.TAMAYA_ORDINAL));
     }
 
     private static class OverriddenOrdinalPropertySource extends BasePropertySource {

http://git-wip-us.apache.org/repos/asf/incubator-tamaya/blob/0be037b8/code/core/src/test/java/org/apache/tamaya/core/propertysource/EnvironmentPropertySourceTest.java
----------------------------------------------------------------------
diff --git a/code/core/src/test/java/org/apache/tamaya/core/propertysource/EnvironmentPropertySourceTest.java b/code/core/src/test/java/org/apache/tamaya/core/propertysource/EnvironmentPropertySourceTest.java
index f9feb4b..a0f1093 100644
--- a/code/core/src/test/java/org/apache/tamaya/core/propertysource/EnvironmentPropertySourceTest.java
+++ b/code/core/src/test/java/org/apache/tamaya/core/propertysource/EnvironmentPropertySourceTest.java
@@ -45,7 +45,7 @@ public class EnvironmentPropertySourceTest {
     @Test
     public void testGet() throws Exception {
         for (Map.Entry<String, String> envEntry : System.getenv().entrySet()) {
-            assertEquals(envPropertySource.get(envEntry.getKey()), envEntry.getValue());
+            assertEquals(envPropertySource.get(envEntry.getKey()).get(envEntry.getKey()), envEntry.getValue());
         }
     }
 

http://git-wip-us.apache.org/repos/asf/incubator-tamaya/blob/0be037b8/code/core/src/test/java/org/apache/tamaya/core/propertysource/PropertiesFilePropertySourceTest.java
----------------------------------------------------------------------
diff --git a/code/core/src/test/java/org/apache/tamaya/core/propertysource/PropertiesFilePropertySourceTest.java b/code/core/src/test/java/org/apache/tamaya/core/propertysource/PropertiesFilePropertySourceTest.java
index 2028ceb..745feeb 100644
--- a/code/core/src/test/java/org/apache/tamaya/core/propertysource/PropertiesFilePropertySourceTest.java
+++ b/code/core/src/test/java/org/apache/tamaya/core/propertysource/PropertiesFilePropertySourceTest.java
@@ -18,7 +18,6 @@
  */
 package org.apache.tamaya.core.propertysource;
 
-import org.apache.tamaya.core.propertysource.SimplePropertySource;
 import org.apache.tamaya.spi.PropertySource;
 import org.junit.Assert;
 import org.junit.Test;
@@ -34,14 +33,16 @@ public class PropertiesFilePropertySourceTest {
     @Test
     public void testGetOrdinal() {
         Assert.assertEquals(0, testfilePropertySource.getOrdinal());
-        Assert.assertEquals(Integer.parseInt(overrideOrdinalPropertySource.get(PropertySource.TAMAYA_ORDINAL)), overrideOrdinalPropertySource.getOrdinal());
+        Assert.assertEquals(Integer.parseInt(overrideOrdinalPropertySource.get(PropertySource.TAMAYA_ORDINAL)
+                .get(PropertySource.TAMAYA_ORDINAL)),
+                overrideOrdinalPropertySource.getOrdinal());
     }
 
 
     @Test
     public void testGet() {
-        Assert.assertEquals("val3", testfilePropertySource.get("key3"));
-        Assert.assertEquals("myval5", overrideOrdinalPropertySource.get("mykey5"));
+        Assert.assertEquals("val3", testfilePropertySource.get("key3").get("key3"));
+        Assert.assertEquals("myval5", overrideOrdinalPropertySource.get("mykey5").get("mykey5"));
         Assert.assertNull(testfilePropertySource.get("nonpresentkey"));
     }
 

http://git-wip-us.apache.org/repos/asf/incubator-tamaya/blob/0be037b8/code/core/src/test/java/org/apache/tamaya/core/propertysource/SystemPropertySourceTest.java
----------------------------------------------------------------------
diff --git a/code/core/src/test/java/org/apache/tamaya/core/propertysource/SystemPropertySourceTest.java b/code/core/src/test/java/org/apache/tamaya/core/propertysource/SystemPropertySourceTest.java
index f0eaf68..4848ab7 100644
--- a/code/core/src/test/java/org/apache/tamaya/core/propertysource/SystemPropertySourceTest.java
+++ b/code/core/src/test/java/org/apache/tamaya/core/propertysource/SystemPropertySourceTest.java
@@ -18,8 +18,8 @@
  */
 package org.apache.tamaya.core.propertysource;
 
-import org.apache.tamaya.core.propertysource.SystemPropertySource;
 import org.apache.tamaya.spi.PropertySource;
+import org.apache.tamaya.spi.PropertyValue;
 import org.junit.Assert;
 import org.junit.Test;
 
@@ -55,10 +55,10 @@ public class SystemPropertySourceTest {
     public void testGet() throws Exception {
         String propertyKeyToCheck = System.getProperties().stringPropertyNames().iterator().next();
 
-        String property = testPropertySource.get(propertyKeyToCheck);
+        PropertyValue property = testPropertySource.get(propertyKeyToCheck);
         Assert.assertNotNull("Property '" + propertyKeyToCheck + "' is not present in " +
                 SystemPropertySource.class.getSimpleName(), property);
-        Assert.assertEquals(System.getProperty(propertyKeyToCheck), property);
+        Assert.assertEquals(System.getProperty(propertyKeyToCheck), property.getValue());
     }
 
     @Test

http://git-wip-us.apache.org/repos/asf/incubator-tamaya/blob/0be037b8/code/core/src/test/java/org/apache/tamaya/core/provider/JavaConfigurationProviderTest.java
----------------------------------------------------------------------
diff --git a/code/core/src/test/java/org/apache/tamaya/core/provider/JavaConfigurationProviderTest.java b/code/core/src/test/java/org/apache/tamaya/core/provider/JavaConfigurationProviderTest.java
index f099da4..c81ae32 100644
--- a/code/core/src/test/java/org/apache/tamaya/core/provider/JavaConfigurationProviderTest.java
+++ b/code/core/src/test/java/org/apache/tamaya/core/provider/JavaConfigurationProviderTest.java
@@ -48,7 +48,7 @@ public class JavaConfigurationProviderTest {
             String key = "confkey" + i;
             String value = "javaconf-value" + i;
 
-            Assert.assertEquals(value, propertySource.get(key));
+            Assert.assertEquals(value, propertySource.get(key).get(key));
 
             // check if we had our key in configuration.current
             Assert.assertTrue(ConfigurationProvider.getConfiguration().getProperties().containsKey(key));

http://git-wip-us.apache.org/repos/asf/incubator-tamaya/blob/0be037b8/code/core/src/test/java/org/apache/tamaya/core/testdata/TestPropertyFilter.java
----------------------------------------------------------------------
diff --git a/code/core/src/test/java/org/apache/tamaya/core/testdata/TestPropertyFilter.java b/code/core/src/test/java/org/apache/tamaya/core/testdata/TestPropertyFilter.java
index 6faa831..071cbb1 100644
--- a/code/core/src/test/java/org/apache/tamaya/core/testdata/TestPropertyFilter.java
+++ b/code/core/src/test/java/org/apache/tamaya/core/testdata/TestPropertyFilter.java
@@ -18,6 +18,7 @@
  */
 package org.apache.tamaya.core.testdata;
 
+import org.apache.tamaya.spi.FilterContext;
 import org.apache.tamaya.spi.PropertyFilter;
 
 import javax.annotation.Priority;
@@ -28,8 +29,8 @@ import javax.annotation.Priority;
 @Priority(100)
 public class TestPropertyFilter implements PropertyFilter{
     @Override
-    public String filterProperty(String key, String valueToBeFiltered) {
-        if("name4".equals(key)){
+    public String filterProperty(String valueToBeFiltered, FilterContext context) {
+        if("name4".equals(context.getKey())){
             return valueToBeFiltered + "(filtered)";
         }
         return valueToBeFiltered;

http://git-wip-us.apache.org/repos/asf/incubator-tamaya/blob/0be037b8/code/core/src/test/java/org/apache/tamaya/core/testdata/TestRemovingPropertyFilter.java
----------------------------------------------------------------------
diff --git a/code/core/src/test/java/org/apache/tamaya/core/testdata/TestRemovingPropertyFilter.java b/code/core/src/test/java/org/apache/tamaya/core/testdata/TestRemovingPropertyFilter.java
index 5a57ad1..7a5b7a8 100644
--- a/code/core/src/test/java/org/apache/tamaya/core/testdata/TestRemovingPropertyFilter.java
+++ b/code/core/src/test/java/org/apache/tamaya/core/testdata/TestRemovingPropertyFilter.java
@@ -19,6 +19,7 @@
 package org.apache.tamaya.core.testdata;
 
 import org.apache.tamaya.ConfigurationProvider;
+import org.apache.tamaya.spi.FilterContext;
 import org.apache.tamaya.spi.PropertyFilter;
 
 import javax.annotation.Priority;
@@ -29,11 +30,11 @@ import javax.annotation.Priority;
 @Priority(200)
 public class TestRemovingPropertyFilter implements PropertyFilter{
     @Override
-    public String filterProperty(String key, String valueToBeFiltered) {
-        if("name5".equals(key)){
+    public String filterProperty(String valueToBeFiltered, FilterContext context) {
+        if("name5".equals(context.getKey())){
             return null;
         }
-        else if("name3".equals(key)){
+        else if("name3".equals(context.getKey())){
             return "Mapped to name: " + ConfigurationProvider.getConfiguration().get("name");
         }
         return valueToBeFiltered;



[8/8] incubator-tamaya git commit: TAMAYA-136: Adding PropertyValue for PropertySource SPI. All changes and test fixes in all modules/examples relevant for release.

Posted by an...@apache.org.
TAMAYA-136: Adding PropertyValue for PropertySource SPI. All changes and test fixes in all modules/examples relevant for release.


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

Branch: refs/heads/master
Commit: d778cb81476f4f12f5d9b55a65edc686af38311b
Parents: 0be037b
Author: anatole <an...@apache.org>
Authored: Tue Feb 2 17:15:53 2016 +0100
Committer: anatole <an...@apache.org>
Committed: Tue Feb 2 17:15:53 2016 +0100

----------------------------------------------------------------------
 .../org/apache/tamaya/spi/FilterContext.java    |  19 +-
 .../org/apache/tamaya/spi/PropertySource.java   |   2 +-
 .../org/apache/tamaya/spi/PropertyValue.java    |   5 +-
 .../spi/PropertyValueCombinationPolicy.java     |   4 +-
 .../tamaya/core/internal/PropertyFiltering.java |   4 +-
 examples/8-remote-example/client/pom.xml        |   7 +-
 .../tamaya/examples/remote/client/Client.java   |   6 +-
 .../remote/client/RemotePropertySource.java     |  62 ---
 .../org.apache.tamaya.spi.PropertySource        |   2 +-
 examples/8-remote-example/server/pom.xml        |  91 +++-
 .../server/src/main/java/ExampleServer.java     |  33 ++
 .../remote/server/ClientScopeProvider.java      |  55 --
 .../tamaya/examples/remote/server/Start.java    |  63 ---
 .../org.apache.tamaya.server.spi.ScopeProvider  |  19 -
 .../server/src/main/resources/config-server.yml |  29 ++
 .../tamaya/builder/SimplePropertySource.java    |   7 +-
 .../builder/ConfigurationBuilderTest.java       |  46 +-
 .../builder/TestANonSPIPropertyFilter.java      |   3 +-
 .../builder/TestBNonSPIPropertyFilter.java      |   3 +-
 .../tamaya/builder/TestPropertyFilter.java      |   3 +-
 .../tamaya/builder/TestPropertySource.java      |   5 +-
 .../builder/TestPropertySourceProvider.java     |   9 +-
 .../builder/TestPropertySourceProviderB.java    |   9 +-
 .../tamaya/events/FrozenPropertySource.java     |   5 +-
 .../events/PropertySourceChangeBuilder.java     |  11 +-
 .../tamaya/events/FrozenPropertySourceTest.java |   2 +-
 modules/filter/pom.xml                          |  77 +++
 .../tamaya/filter/ConfigurationFilter.java      | 112 ++++
 .../tamaya/filter/DefaultMetadataFilter.java    |  42 ++
 .../tamaya/filter/ProgrammableFilter.java       | 111 ++++
 .../tamaya/filter/RegexPropertyFilter.java      |  56 ++
 .../org.apache.tamaya.spi.PropertyFilter        |  20 +
 .../format/FlattenedDefaultPropertySource.java  |   5 +-
 .../FlattenedDefaultPropertySourceTest.java     |  11 +-
 .../functions/ConfigWrappingPropertySource.java |   5 +-
 .../functions/ConfigurationFunctions.java       |  20 +-
 .../functions/EnrichedPropertySource.java       |   9 +-
 .../functions/FilteredPropertySource.java       |   5 +-
 .../tamaya/functions/MappedPropertySource.java  |   5 +-
 .../functions/MetaEnrichedPropertySource.java   |  91 ----
 .../functions/PropertySourceFunctions.java      |  37 +-
 .../functions/ValueMappedPropertySource.java    |   7 +-
 .../tamaya/inject/TestPropertySource.java       |   5 +-
 .../internal/DefaultDynamicValueTest.java       |   5 +-
 .../cdi/cfg/ProvidedPropertySource.java         |   5 +-
 .../integration/cdi/cfg/TestPropertySource.java |   5 +-
 .../org/apache/tamaya/etcd/EtcdAccessor.java    |  33 +-
 .../apache/tamaya/etcd/EtcdPropertySource.java  |  20 +-
 .../etcd/internal/EtcdConfigChangeRequest.java  |  43 +-
 .../apache/tamaya/json/JSONPropertySource.java  |   9 +-
 .../json/CommonJSONTestCaseCollection.java      |  45 +-
 .../tamaya/json/JSONPropertySourceTest.java     |   2 +-
 .../mutableconfig/ConfigChangeManager.java      |  23 +
 .../PropertiesFileConfigChangeRequest.java      |  13 +-
 .../XmlPropertiesFileConfigChangeRequest.java   |   7 +-
 .../spi/AbstractConfigChangeRequest.java        |   8 +
 .../mutableconfig/ConfigChangeManagerTest.java  |  14 +-
 modules/pom.xml                                 |   1 +
 .../tamaya/remote/BaseRemotePropertySource.java |   9 +-
 .../internal/ExpressionResolutionFilter.java    |   9 +-
 .../tamaya/resolver/MyTestPropertySource.java   |   5 +-
 .../AbstractPathPropertySourceProvider.java     |   9 +-
 .../AbstractPathPropertySourceProviderTest.java |   8 +-
 .../PathBasedPropertySourceProvider.java        |   6 +-
 modules/server/pom.xml                          |  91 +++-
 .../org/apache/tamaya/server/ConfigServer.java  |  50 --
 .../apache/tamaya/server/ConfigServiceApp.java  |  57 ++
 .../server/ConfigServiceConfiguration.java      |  41 ++
 .../tamaya/server/ConfigurationResource.java    | 321 ++++++++++++
 .../tamaya/server/FilteredConfigServlet.java    |  86 ---
 .../apache/tamaya/server/FullConfigServlet.java |  86 ---
 .../java/org/apache/tamaya/server/Server.java   |  46 --
 .../internal/DefaultConfigAdminService.java     | 136 -----
 .../server/internal/DefaultConfigService.java   | 137 -----
 .../tamaya/server/internal/MediaTypeUtil.java   |  58 ---
 .../server/internal/RestConfigAdminService.java | 133 -----
 .../server/internal/RestConfigService.java      | 103 ----
 .../tamaya/server/internal/SimpleServer.java    |  81 ---
 .../tamaya/server/spi/ConfigAdminService.java   |  48 --
 .../apache/tamaya/server/spi/ConfigService.java |  64 ---
 .../services/org.apache.tamaya.server.Server    |  19 -
 ....apache.tamaya.server.spi.ConfigAdminService |  19 -
 .../org.apache.tamaya.server.spi.ConfigService  |  19 -
 modules/server/src/main/resources/banner.txt    |  14 +
 .../server/src/main/resources/config-server.yml |  29 ++
 .../tamaya/server/ConfigServiceAppTest.java     |  32 ++
 .../org/apache/tamaya/server/EtcdAccessor.java  | 519 +++++++++++++++++++
 .../tamaya/spisupport/BasePropertySource.java   |   9 +-
 .../tamaya/spisupport/DefaultConfiguration.java |  16 +-
 .../tamaya/spisupport/PropertyFiltering.java    |   8 +-
 src/site/asciidoc/extensions/index.adoc         |  15 +-
 src/site/asciidoc/extensions/mod_filter.adoc    | 154 ++++++
 92 files changed, 2163 insertions(+), 1629 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/incubator-tamaya/blob/d778cb81/code/api/src/main/java/org/apache/tamaya/spi/FilterContext.java
----------------------------------------------------------------------
diff --git a/code/api/src/main/java/org/apache/tamaya/spi/FilterContext.java b/code/api/src/main/java/org/apache/tamaya/spi/FilterContext.java
index 7e81bd9..0cc4f5f 100644
--- a/code/api/src/main/java/org/apache/tamaya/spi/FilterContext.java
+++ b/code/api/src/main/java/org/apache/tamaya/spi/FilterContext.java
@@ -29,17 +29,22 @@ import java.util.Objects;
  * @see PropertyFilter
  */
 public class FilterContext {
-
+    /** The key. */
     private final String key;
     @Experimental
     private Map<String, String> configEntries = new HashMap();
+    @Experimental
+    private boolean singlePropertyScoped;
+
 
     /**
      * Creates a new FilterContext.
      * @param key the key under evaluation, not null.
+     * @param singlePropertyScope true, if the filtering is done only for one single property accessed explcitily.
      * @param configEntries the raw configuration data available in the current evaluation context, not null.
      */
-    public FilterContext(String key, Map<String,String> configEntries) {
+    public FilterContext(String key, Map<String,String> configEntries, boolean singlePropertyScope) {
+        this.singlePropertyScoped = singlePropertyScope;
         this.key = Objects.requireNonNull(key);
         this.configEntries.putAll(configEntries);
         this.configEntries = Collections.unmodifiableMap(this.configEntries);
@@ -57,6 +62,16 @@ public class FilterContext {
     }
 
     /**
+     * Method that determines if filtering is done for a single property accessed, or as part of call to
+     * {@code getProperties()}.
+     * @return true, if its scoped to a single property accessed.
+     */
+    @Experimental
+    public boolean isSinglePropertyScoped(){
+        return singlePropertyScoped;
+    }
+
+    /**
      * This map contains the following keys:
      * <ul>
      * <li>the original value <b>before</b> any filters were applied on it.</li>

http://git-wip-us.apache.org/repos/asf/incubator-tamaya/blob/d778cb81/code/api/src/main/java/org/apache/tamaya/spi/PropertySource.java
----------------------------------------------------------------------
diff --git a/code/api/src/main/java/org/apache/tamaya/spi/PropertySource.java b/code/api/src/main/java/org/apache/tamaya/spi/PropertySource.java
index 804adf5..ec2ef48 100644
--- a/code/api/src/main/java/org/apache/tamaya/spi/PropertySource.java
+++ b/code/api/src/main/java/org/apache/tamaya/spi/PropertySource.java
@@ -95,7 +95,7 @@ public interface PropertySource {
      * @return the property value map, where {@code map.get(key) == value}, including also any metadata. In case a
      * value is null, simply return {@code null}.
      */
-    Map<String,String> get(String key);
+    PropertyValue get(String key);
 
     /**
      * Access the current properties as Map. The resulting Map may not return all items accessible, e.g.

http://git-wip-us.apache.org/repos/asf/incubator-tamaya/blob/d778cb81/code/api/src/main/java/org/apache/tamaya/spi/PropertyValue.java
----------------------------------------------------------------------
diff --git a/code/api/src/main/java/org/apache/tamaya/spi/PropertyValue.java b/code/api/src/main/java/org/apache/tamaya/spi/PropertyValue.java
index 8d3559c..f56fa5d 100644
--- a/code/api/src/main/java/org/apache/tamaya/spi/PropertyValue.java
+++ b/code/api/src/main/java/org/apache/tamaya/spi/PropertyValue.java
@@ -97,9 +97,12 @@ public final class PropertyValue {
      * @param key the key, not null.
      * @param value the value.
      * @param source the source, typically the name of the {@link PropertySource} providing the value, not null.
-     * @return a new builder instance.
+     * @return a new property value instance, or null, if the value passed is null..
      */
     public static PropertyValue of(String key, String value, String source){
+        if(value==null){
+            return null;
+        }
         return new PropertyValue(key, value, source);
     }
 

http://git-wip-us.apache.org/repos/asf/incubator-tamaya/blob/d778cb81/code/api/src/main/java/org/apache/tamaya/spi/PropertyValueCombinationPolicy.java
----------------------------------------------------------------------
diff --git a/code/api/src/main/java/org/apache/tamaya/spi/PropertyValueCombinationPolicy.java b/code/api/src/main/java/org/apache/tamaya/spi/PropertyValueCombinationPolicy.java
index ad842d2..096b2a1 100644
--- a/code/api/src/main/java/org/apache/tamaya/spi/PropertyValueCombinationPolicy.java
+++ b/code/api/src/main/java/org/apache/tamaya/spi/PropertyValueCombinationPolicy.java
@@ -37,8 +37,8 @@ public interface PropertyValueCombinationPolicy {
 
         @Override
         public Map<String,String> collect(Map<String,String> currentValue, String key, PropertySource propertySource) {
-            Map<String,String> value = propertySource.get(key);
-            return value!=null && value.get(key)!=null?value:currentValue;
+            PropertyValue value = propertySource.get(key);
+            return value!=null?value.getConfigEntries():currentValue;
         }
 
     };

http://git-wip-us.apache.org/repos/asf/incubator-tamaya/blob/d778cb81/code/core/src/main/java/org/apache/tamaya/core/internal/PropertyFiltering.java
----------------------------------------------------------------------
diff --git a/code/core/src/main/java/org/apache/tamaya/core/internal/PropertyFiltering.java b/code/core/src/main/java/org/apache/tamaya/core/internal/PropertyFiltering.java
index f0d15bc..e16b056 100644
--- a/code/core/src/main/java/org/apache/tamaya/core/internal/PropertyFiltering.java
+++ b/code/core/src/main/java/org/apache/tamaya/core/internal/PropertyFiltering.java
@@ -57,7 +57,7 @@ public final class PropertyFiltering{
         for (int i = 0; i < MAX_FILTER_LOOPS; i++) {
             boolean changed = false;
             // Apply filters to values, prevent values filtered to null!
-            FilterContext filterContext = new FilterContext(key, configData);
+            FilterContext filterContext = new FilterContext(key, configData, false);
             for (PropertyFilter filter : configurationContext.getPropertyFilters()) {
                 String newValue = filter.filterProperty(result, filterContext);
                 if (newValue != null && !newValue.equals(result)) {
@@ -96,7 +96,7 @@ public final class PropertyFiltering{
         for (int i = 0; i < MAX_FILTER_LOOPS; i++) {
             AtomicInteger changes = new AtomicInteger();
             for (Map.Entry<String, String> entry : inputMap.entrySet()) {
-                FilterContext filterContext = new FilterContext(entry.getKey(), inputMap);
+                FilterContext filterContext = new FilterContext(entry.getKey(), inputMap, true);
                 for (PropertyFilter filter : configurationContext.getPropertyFilters()) {
                     final String k = entry.getKey();
                     final String v = entry.getValue();

http://git-wip-us.apache.org/repos/asf/incubator-tamaya/blob/d778cb81/examples/8-remote-example/client/pom.xml
----------------------------------------------------------------------
diff --git a/examples/8-remote-example/client/pom.xml b/examples/8-remote-example/client/pom.xml
index f90c126..6bab59b 100644
--- a/examples/8-remote-example/client/pom.xml
+++ b/examples/8-remote-example/client/pom.xml
@@ -46,7 +46,12 @@ under the License.
         </dependency>
         <dependency>
             <groupId>org.apache.tamaya.ext</groupId>
-            <artifactId>tamaya-remote</artifactId>
+            <artifactId>tamaya-etcd</artifactId>
+            <version>${project.version}</version>
+        </dependency>
+        <dependency>
+            <groupId>org.apache.tamaya.ext</groupId>
+            <artifactId>tamaya-filter</artifactId>
             <version>${project.version}</version>
         </dependency>
         <dependency>

http://git-wip-us.apache.org/repos/asf/incubator-tamaya/blob/d778cb81/examples/8-remote-example/client/src/main/java/org/apache/tamaya/examples/remote/client/Client.java
----------------------------------------------------------------------
diff --git a/examples/8-remote-example/client/src/main/java/org/apache/tamaya/examples/remote/client/Client.java b/examples/8-remote-example/client/src/main/java/org/apache/tamaya/examples/remote/client/Client.java
index 5eaba64..76bf407 100644
--- a/examples/8-remote-example/client/src/main/java/org/apache/tamaya/examples/remote/client/Client.java
+++ b/examples/8-remote-example/client/src/main/java/org/apache/tamaya/examples/remote/client/Client.java
@@ -54,7 +54,7 @@ public class Client {
         if(portValue==null){
             portValue = ConfigurationProvider.getConfiguration().get("client.port");
         }
-        int port = portValue!=null?Integer.parseInt(portValue):8080;
+        int port = portValue!=null?Integer.parseInt(portValue):8055;
         tomcat.setPort(port);
         File base = new File(System.getProperty("java.io.tmpdir")+"/"+getClientId());
         if(!base.exists()){
@@ -84,9 +84,9 @@ public class Client {
      * @return the client identifier to be used.
      */
     public static String getClientId() {
-        String clientId = System.getenv("CLIENT_ID");
+        String clientId = System.getenv("ENV_CLIENT_ID");
         if(clientId == null){
-            clientId = System.getProperty("clientId");
+            clientId = System.getProperty("ENV_CLIENT_ID");
         }
         if(clientId == null){
             clientId = "default";

http://git-wip-us.apache.org/repos/asf/incubator-tamaya/blob/d778cb81/examples/8-remote-example/client/src/main/java/org/apache/tamaya/examples/remote/client/RemotePropertySource.java
----------------------------------------------------------------------
diff --git a/examples/8-remote-example/client/src/main/java/org/apache/tamaya/examples/remote/client/RemotePropertySource.java b/examples/8-remote-example/client/src/main/java/org/apache/tamaya/examples/remote/client/RemotePropertySource.java
deleted file mode 100644
index 9990874..0000000
--- a/examples/8-remote-example/client/src/main/java/org/apache/tamaya/examples/remote/client/RemotePropertySource.java
+++ /dev/null
@@ -1,62 +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.examples.remote.client;
-
-import org.apache.tamaya.remote.BaseRemotePropertySource;
-
-import java.net.MalformedURLException;
-import java.net.URL;
-import java.util.Arrays;
-import java.util.Collection;
-import java.util.Collections;
-import java.util.logging.Level;
-import java.util.logging.Logger;
-
-/**
- * Property Resource, which reads configuration dat from the (local) configuration server. Normally also the config
- * server should be configured, e.g. using system or environment properties.
- */
-public class RemotePropertySource extends BaseRemotePropertySource{
-    /** Current remote property source default ordinal. */
-    private static final int REMOTE_ORDINAL = 15000;
-
-    @Override
-    public int getDefaultOrdinal(){
-        return REMOTE_ORDINAL;
-    }
-
-    @Override
-    protected Collection<URL> getAccessURLs() {
-        try {
-            String configServerUrl = System.getenv("CONFIG_SERVER");
-            if(configServerUrl==null){
-                configServerUrl = System.getProperty("configServer");
-            }
-            if(configServerUrl==null){
-                configServerUrl = "http://localhost:8888/config?scope=CLIENT&scopeId={clientId}&format=application/json";
-            }
-            System.out.println("Reading config from " + configServerUrl.replace("{clientId}", Client.getClientId()));
-            return Arrays.asList(new URL(configServerUrl.replace("{clientId}", Client.getClientId())));
-        } catch (MalformedURLException e) {
-            Logger.getLogger(getClass().getName()).log(Level.WARNING, "Failed to configure remote config location,", e);
-            return Collections.emptySet();
-        }
-    }
-
-}

http://git-wip-us.apache.org/repos/asf/incubator-tamaya/blob/d778cb81/examples/8-remote-example/client/src/main/resources/META-INF/services/org.apache.tamaya.spi.PropertySource
----------------------------------------------------------------------
diff --git a/examples/8-remote-example/client/src/main/resources/META-INF/services/org.apache.tamaya.spi.PropertySource b/examples/8-remote-example/client/src/main/resources/META-INF/services/org.apache.tamaya.spi.PropertySource
index 63d9a5b..a2a4042 100644
--- a/examples/8-remote-example/client/src/main/resources/META-INF/services/org.apache.tamaya.spi.PropertySource
+++ b/examples/8-remote-example/client/src/main/resources/META-INF/services/org.apache.tamaya.spi.PropertySource
@@ -16,4 +16,4 @@
 # specific language governing permissions and limitations
 # under the License.
 #
-org.apache.tamaya.examples.remote.client.RemotePropertySource
\ No newline at end of file
+#org.apache.tamaya.examples.remote.client.RemotePropertySource
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/incubator-tamaya/blob/d778cb81/examples/8-remote-example/server/pom.xml
----------------------------------------------------------------------
diff --git a/examples/8-remote-example/server/pom.xml b/examples/8-remote-example/server/pom.xml
index 1965bd3..5c5f97c 100644
--- a/examples/8-remote-example/server/pom.xml
+++ b/examples/8-remote-example/server/pom.xml
@@ -33,22 +33,103 @@ under the License.
 
     <dependencies>
         <dependency>
-            <groupId>org.apache.tamaya</groupId>
-            <artifactId>tamaya-core</artifactId>
+            <groupId>org.apache.tamaya.ext</groupId>
+            <artifactId>tamaya-server</artifactId>
             <version>${project.version}</version>
         </dependency>
         <dependency>
             <groupId>org.apache.tamaya</groupId>
             <artifactId>tamaya-api</artifactId>
             <version>${project.version}</version>
+            <scope>compile</scope>
         </dependency>
         <dependency>
-            <groupId>org.apache.tamaya.ext</groupId>
-            <artifactId>tamaya-server</artifactId>
+            <groupId>org.apache.tamaya</groupId>
+            <artifactId>tamaya-core</artifactId>
             <version>${project.version}</version>
+            <scope>compile</scope>
         </dependency>
-
     </dependencies>
 
+    <build>
+        <plugins>
+            <plugin>
+                <groupId>com.spotify</groupId>
+                <artifactId>docker-maven-plugin</artifactId>
+                <version>0.3.258</version>
+                <configuration>
+                    <imageName>apache/tamaya/examples-server</imageName>
+                    <imageTags>
+                        <imageTag>${project.version}</imageTag>
+                    </imageTags>
+                    <baseImage>java:8-jre</baseImage>
+                    <entryPoint>["java", "-jar", "/${project.build.finalName}.jar", "server", "/config-server.yml"]</entryPoint>
+                    <exposes>
+                        <expose>8080</expose>
+                    </exposes>
+                    <resources>
+                        <resource>
+                            <targetPath>/</targetPath>
+                            <directory>${project.build.directory}</directory>
+                            <include>${project.build.finalName}.jar</include>
+                        </resource>
+                        <resource>
+                            <targetPath>/</targetPath>
+                            <directory>${project.build.directory}/classes</directory>
+                            <include>config-server.yml</include>
+                        </resource>
+                    </resources>
+                </configuration>
+            </plugin>
+            <plugin>
+                <groupId>org.apache.maven.plugins</groupId>
+                <artifactId>maven-jar-plugin</artifactId>
+                <version>2.4</version>
+                <configuration>
+                    <archive>
+                        <manifest>
+                            <addDefaultImplementationEntries>true</addDefaultImplementationEntries>
+                        </manifest>
+                    </archive>
+                </configuration>
+            </plugin>
+            <plugin>
+                <groupId>org.apache.maven.plugins</groupId>
+                <artifactId>maven-shade-plugin</artifactId>
+                <version>2.3</version>
+                <configuration>
+                    <createDependencyReducedPom>true</createDependencyReducedPom>
+                    <filters>
+                        <filter>
+                            <artifact>*:*</artifact>
+                            <excludes>
+                                <exclude>META-INF/*.SF</exclude>
+                                <exclude>META-INF/*.DSA</exclude>
+                                <exclude>META-INF/*.RSA</exclude>
+                            </excludes>
+                        </filter>
+                    </filters>
+                </configuration>
+                <executions>
+                    <execution>
+                        <phase>package</phase>
+                        <goals>
+                            <goal>shade</goal>
+                        </goals>
+                        <configuration>
+                            <transformers>
+                                <transformer implementation="org.apache.maven.plugins.shade.resource.ServicesResourceTransformer"/>
+                                <transformer implementation="org.apache.maven.plugins.shade.resource.ManifestResourceTransformer">
+                                    <mainClass>org.apache.tamaya.server.ConfigServiceApp</mainClass>
+                                </transformer>
+                            </transformers>
+                        </configuration>
+                    </execution>
+                </executions>
+            </plugin>
+        </plugins>
+    </build>
+
+
 
 </project>

http://git-wip-us.apache.org/repos/asf/incubator-tamaya/blob/d778cb81/examples/8-remote-example/server/src/main/java/ExampleServer.java
----------------------------------------------------------------------
diff --git a/examples/8-remote-example/server/src/main/java/ExampleServer.java b/examples/8-remote-example/server/src/main/java/ExampleServer.java
new file mode 100644
index 0000000..ad55480
--- /dev/null
+++ b/examples/8-remote-example/server/src/main/java/ExampleServer.java
@@ -0,0 +1,33 @@
+/*
+ * 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.
+ */
+
+import org.apache.tamaya.server.ConfigServiceApp;
+
+/**
+ * Created by atsticks on 22.01.16.
+ */
+public class ExampleServer {
+
+    private ExampleServer(){}
+
+    public static void main(String... args) throws Exception{
+        ConfigServiceApp.main("server", "./src/main/resources/config-server.yml");
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/incubator-tamaya/blob/d778cb81/examples/8-remote-example/server/src/main/java/org/apache/tamaya/examples/remote/server/ClientScopeProvider.java
----------------------------------------------------------------------
diff --git a/examples/8-remote-example/server/src/main/java/org/apache/tamaya/examples/remote/server/ClientScopeProvider.java b/examples/8-remote-example/server/src/main/java/org/apache/tamaya/examples/remote/server/ClientScopeProvider.java
deleted file mode 100644
index 12dc82d..0000000
--- a/examples/8-remote-example/server/src/main/java/org/apache/tamaya/examples/remote/server/ClientScopeProvider.java
+++ /dev/null
@@ -1,55 +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.examples.remote.server;
-
-import org.apache.tamaya.ConfigOperator;
-import org.apache.tamaya.Configuration;
-import org.apache.tamaya.functions.ConfigurationFunctions;
-import org.apache.tamaya.server.spi.ScopeProvider;
-
-
-/**
- * Implementation of a {@link ScopeProvider} that registers a {@link ConfigOperator} that
- * filters out and combines a configuration subsection identified by
- * {@code client.default, client.<CLIENTID>}.
- */
-public class ClientScopeProvider implements ScopeProvider{
-
-    /**
-     * Access the unique scope name.
-     * @return the unique scope name.
-     */
-    public String getScopeType(){
-            return "CLIENT";
-    }
-
-    @Override
-    public ConfigOperator getScope(final String scopeId) {
-        return new ConfigOperator() {
-            @Override
-            public Configuration operate(Configuration c) {
-                return ConfigurationFunctions.combine("Scoped Config CLIENT="+scopeId,
-                        c.with(ConfigurationFunctions.sectionRecursive(true, "client.default")),
-                        c.with(ConfigurationFunctions.sectionRecursive(true, "client." + scopeId))
-                );
-            }
-        };
-
-    }
-}

http://git-wip-us.apache.org/repos/asf/incubator-tamaya/blob/d778cb81/examples/8-remote-example/server/src/main/java/org/apache/tamaya/examples/remote/server/Start.java
----------------------------------------------------------------------
diff --git a/examples/8-remote-example/server/src/main/java/org/apache/tamaya/examples/remote/server/Start.java b/examples/8-remote-example/server/src/main/java/org/apache/tamaya/examples/remote/server/Start.java
deleted file mode 100644
index f4372cf..0000000
--- a/examples/8-remote-example/server/src/main/java/org/apache/tamaya/examples/remote/server/Start.java
+++ /dev/null
@@ -1,63 +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.examples.remote.server;
-
-
-import org.apache.tamaya.server.Server;
-
-
-/**
- * Main class to start the server part of this example. Usage:
- * <pre>
- *     java org.apache.tamaya.examples.remote.server.Start [-Dport=1234]
- * </pre>
- * The optional port value hereby overrides any port value received from the remote configuration.
- * By default port 8888 is used.
- */
-public class Start {
-
-    /**
-     * Utility class only.
-     */
-    private Start(){}
-
-    /**
-     * Mein methods. Usage:
-     * <pre>
-     *     java org.apache.tamaya.examples.remote.server.Start [-Dport=1234]
-     * </pre>
-     * The optional port value hereby overrides any port value received from the remote configuration.
-     * By default port 8888 is used.
-     * @param args the args passed.
-     */
-    public static void main(String... args){
-        // init configuration
-        String portValue = System.getProperty("port");
-        int port = portValue!=null?Integer.parseInt(portValue):8888;
-        try {
-            System.out.println("Starting server with port " + port);
-            Server server = org.apache.tamaya.server.ConfigServer.createServer();
-            server.start(port);
-        } catch (Exception e) {
-            e.printStackTrace();
-            System.exit(-1);
-        }
-    }
-
-}

http://git-wip-us.apache.org/repos/asf/incubator-tamaya/blob/d778cb81/examples/8-remote-example/server/src/main/resources/META-INF/services/org.apache.tamaya.server.spi.ScopeProvider
----------------------------------------------------------------------
diff --git a/examples/8-remote-example/server/src/main/resources/META-INF/services/org.apache.tamaya.server.spi.ScopeProvider b/examples/8-remote-example/server/src/main/resources/META-INF/services/org.apache.tamaya.server.spi.ScopeProvider
deleted file mode 100644
index 52e219c..0000000
--- a/examples/8-remote-example/server/src/main/resources/META-INF/services/org.apache.tamaya.server.spi.ScopeProvider
+++ /dev/null
@@ -1,19 +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 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.examples.remote.server.ClientScopeProvider
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/incubator-tamaya/blob/d778cb81/examples/8-remote-example/server/src/main/resources/config-server.yml
----------------------------------------------------------------------
diff --git a/examples/8-remote-example/server/src/main/resources/config-server.yml b/examples/8-remote-example/server/src/main/resources/config-server.yml
new file mode 100644
index 0000000..446351f
--- /dev/null
+++ b/examples/8-remote-example/server/src/main/resources/config-server.yml
@@ -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 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.
+#
+
+scope: java
+server:
+  applicationConnectors:
+  - type: http
+    port: 4001
+  adminConnectors:
+  - type: http
+    port: 4099
+
+

http://git-wip-us.apache.org/repos/asf/incubator-tamaya/blob/d778cb81/modules/builder/src/main/java/org/apache/tamaya/builder/SimplePropertySource.java
----------------------------------------------------------------------
diff --git a/modules/builder/src/main/java/org/apache/tamaya/builder/SimplePropertySource.java b/modules/builder/src/main/java/org/apache/tamaya/builder/SimplePropertySource.java
index 0d5561e..085bd9a 100644
--- a/modules/builder/src/main/java/org/apache/tamaya/builder/SimplePropertySource.java
+++ b/modules/builder/src/main/java/org/apache/tamaya/builder/SimplePropertySource.java
@@ -19,6 +19,7 @@
 package org.apache.tamaya.builder;
 
 import org.apache.tamaya.spi.PropertySource;
+import org.apache.tamaya.spi.PropertyValue;
 
 import java.util.HashMap;
 import java.util.Map;
@@ -42,10 +43,10 @@ public class SimplePropertySource implements PropertySource {
 
     @Override
     public int getOrdinal(){
-        String configuredOrdinal = get(TAMAYA_ORDINAL);
+        PropertyValue configuredOrdinal = get(TAMAYA_ORDINAL);
         if(configuredOrdinal!=null){
             try{
-                return Integer.parseInt(configuredOrdinal);
+                return Integer.parseInt(configuredOrdinal.getValue());
             } catch(Exception e){
                 Logger.getLogger(getClass().getName()).log(Level.WARNING,
                         "Configured Ordinal is not an int number: " + configuredOrdinal, e);
@@ -64,7 +65,7 @@ public class SimplePropertySource implements PropertySource {
     }
 
     @Override
-    public String get(String key) {
+    public PropertyValue get(String key) {
         return null;
     }
 

http://git-wip-us.apache.org/repos/asf/incubator-tamaya/blob/d778cb81/modules/builder/src/test/java/org/apache/tamaya/builder/ConfigurationBuilderTest.java
----------------------------------------------------------------------
diff --git a/modules/builder/src/test/java/org/apache/tamaya/builder/ConfigurationBuilderTest.java b/modules/builder/src/test/java/org/apache/tamaya/builder/ConfigurationBuilderTest.java
index d48fe08..43196f7 100644
--- a/modules/builder/src/test/java/org/apache/tamaya/builder/ConfigurationBuilderTest.java
+++ b/modules/builder/src/test/java/org/apache/tamaya/builder/ConfigurationBuilderTest.java
@@ -103,7 +103,7 @@ public class ConfigurationBuilderTest {
         PropertySource source = mock(PropertySource.class, NOT_MOCKED_ANSWER);
 
         doReturn("one").when(source).getName();
-        doReturn("a").when(source).get("keyOfA");
+        doReturn(PropertyValue.of("keyOfA","a", "test")).when(source).get("keyOfA");
         doReturn(100).when(source).getOrdinal();
 
         ConfigurationBuilder builder = new ConfigurationBuilder().addPropertySources(source);
@@ -121,12 +121,12 @@ public class ConfigurationBuilderTest {
         PropertySource sourceOne = mock(PropertySource.class, NOT_MOCKED_ANSWER);
 
         doReturn("one").when(sourceOne).getName();
-        doReturn("b").when(sourceOne).get("keyOfA");
+        doReturn(PropertyValue.of("keyOfA","b", "test")).when(sourceOne).get("keyOfA");
         doReturn(10).when(sourceOne).getOrdinal();
 
         PropertySource sourceTwo = mock(PropertySource.class, NOT_MOCKED_ANSWER);
         doReturn("two").when(sourceTwo).getName();
-        doReturn("a").when(sourceTwo).get("keyOfA");
+        doReturn(PropertyValue.of("keyOfA","a", "test")).when(sourceTwo).get("keyOfA");
         doReturn(10).when(sourceTwo).getOrdinal();
 
         ConfigurationBuilder builder = new ConfigurationBuilder().addPropertySources(sourceOne)
@@ -167,12 +167,12 @@ public class ConfigurationBuilderTest {
         PropertySource sourceOne = mock(PropertySource.class, NOT_MOCKED_ANSWER);
 
         doReturn("one").when(sourceOne).getName();
-        doReturn("b").when(sourceOne).get("keyOfA");
+        doReturn(PropertyValue.of("keyOfA","b", "test")).when(sourceOne).get("keyOfA");
         doReturn(10).when(sourceOne).getOrdinal();
 
         PropertySource sourceTwo = mock(PropertySource.class, NOT_MOCKED_ANSWER);
         doReturn("two").when(sourceTwo).getName();
-        doReturn("a").when(sourceTwo).get("keyOfA");
+        doReturn(PropertyValue.of("keyOfA","a", "test")).when(sourceTwo).get("keyOfA");
         doReturn(20).when(sourceTwo).getOrdinal();
 
         ConfigurationBuilder builder = new ConfigurationBuilder().addPropertySources(sourceOne)
@@ -191,12 +191,12 @@ public class ConfigurationBuilderTest {
         PropertySource sourceOne = mock(PropertySource.class, NOT_MOCKED_ANSWER);
 
         doReturn("one").when(sourceOne).getName();
-        doReturn("b").when(sourceOne).get("keyOfA");
+        doReturn(PropertyValue.of("keyOfA","b", "test")).when(sourceOne).get("keyOfA");
         doReturn(30).when(sourceOne).getOrdinal();
 
         PropertySource sourceTwo = mock(PropertySource.class, NOT_MOCKED_ANSWER);
         doReturn("two").when(sourceTwo).getName();
-        doReturn("a").when(sourceTwo).get("keyOfA");
+        doReturn(PropertyValue.of("keyOfA","a", "test")).when(sourceTwo).get("keyOfA");
         doReturn(20).when(sourceTwo).getOrdinal();
 
         ConfigurationBuilder builder = new ConfigurationBuilder().addPropertySources(sourceOne, sourceTwo);
@@ -215,13 +215,13 @@ public class ConfigurationBuilderTest {
 
         doReturn("one").when(sourceOne).getName();
         doReturn(null).when(sourceOne).get(anyString());
-        doReturn("b").when(sourceOne).get("b");
+        doReturn(PropertyValue.of("b","b", "test")).when(sourceOne).get("b");
         doReturn(30).when(sourceOne).getOrdinal();
 
         PropertySource sourceTwo = mock(PropertySource.class, NOT_MOCKED_ANSWER);
         doReturn("two").when(sourceTwo).getName();
         doReturn(null).when(sourceTwo).get(anyString());
-        doReturn("a").when(sourceTwo).get("a");
+        doReturn(PropertyValue.of("a","a", "test")).when(sourceTwo).get("a");
         doReturn(30).when(sourceTwo).getOrdinal();
 
         ConfigurationBuilder builder = new ConfigurationBuilder().addPropertySources(sourceOne)
@@ -239,13 +239,13 @@ public class ConfigurationBuilderTest {
 
         doReturn("one").when(sourceOne).getName();
         doReturn(null).when(sourceOne).get(anyString());
-        doReturn("b").when(sourceOne).get("b");
+        doReturn(PropertyValue.of("b","b", "test")).when(sourceOne).get("b");
         doReturn(30).when(sourceOne).getOrdinal();
 
         PropertySource sourceTwo = mock(PropertySource.class, NOT_MOCKED_ANSWER);
         doReturn("two").when(sourceTwo).getName();
         doReturn(null).when(sourceTwo).get(anyString());
-        doReturn("a").when(sourceTwo).get("a");
+        doReturn(PropertyValue.of("a","a", "test")).when(sourceTwo).get("a");
         doReturn(30).when(sourceTwo).getOrdinal();
 
         ConfigurationBuilder builder = new ConfigurationBuilder().addPropertySources(sourceOne, null, sourceTwo);
@@ -285,7 +285,7 @@ public class ConfigurationBuilderTest {
         PropertySource source = mock(PropertySource.class, NOT_MOCKED_ANSWER);
 
         doReturn("source").when(source).getName();
-        doReturn("A").when(source).get("key");
+        doReturn(PropertyValue.of("key","A", "test")).when(source).get("key");
         doReturn(100).when(source).getOrdinal();
 
         ConfigurationBuilder builder = new ConfigurationBuilder();
@@ -315,7 +315,7 @@ public class ConfigurationBuilderTest {
         PropertySource source = mock(PropertySource.class, NOT_MOCKED_ANSWER);
 
         doReturn("source").when(source).getName();
-        doReturn("A").when(source).get("key");
+        doReturn(PropertyValue.of("key","A", "test")).when(source).get("key");
         doReturn(100).when(source).getOrdinal();
 
         ConfigurationBuilder builder = new ConfigurationBuilder();
@@ -345,7 +345,7 @@ public class ConfigurationBuilderTest {
         PropertySource source = mock(PropertySource.class, NOT_MOCKED_ANSWER);
 
         doReturn("source").when(source).getName();
-        doReturn("A").when(source).get("key");
+        doReturn(PropertyValue.of("key","A", "test")).when(source).get("key");
         doReturn(100).when(source).getOrdinal();
 
         ConfigurationBuilder builder = new ConfigurationBuilder();
@@ -378,7 +378,7 @@ public class ConfigurationBuilderTest {
     public void canAddNonSPIPropertyFilter() {
         PropertySource source = mock(PropertySource.class, NOT_MOCKED_ANSWER);
 
-        doReturn("M").when(source).get("key");
+        doReturn(PropertyValue.of("key","M", "test")).when(source).get("key");
         doReturn("source").when(source).getName();
 
         ConfigurationBuilder builder = new ConfigurationBuilder();
@@ -397,7 +397,7 @@ public class ConfigurationBuilderTest {
     public void canAddNonSPIPropertyFiltersViaConsecutiveCalls() {
         PropertySource source = mock(PropertySource.class, NOT_MOCKED_ANSWER);
 
-        doReturn("M").when(source).get("key");
+        doReturn(PropertyValue.of("key","M", "test")).when(source).get("key");
         doReturn("source").when(source).getName();
 
         ConfigurationBuilder builder = new ConfigurationBuilder();
@@ -418,7 +418,7 @@ public class ConfigurationBuilderTest {
     public void canAddMultipleNonSPIPropertyFiltersWhileOneIsNull() {
         PropertySource source = mock(PropertySource.class, NOT_MOCKED_ANSWER);
 
-        doReturn("M").when(source).get("key");
+        doReturn(PropertyValue.of("key","M", "test")).when(source).get("key");
         doReturn("source").when(source).getName();
 
         ConfigurationBuilder builder = new ConfigurationBuilder();
@@ -440,7 +440,7 @@ public class ConfigurationBuilderTest {
     public void overhandedNullPropertyFilterIsSafelyHandled() {
         PropertySource source = mock(PropertySource.class, NOT_MOCKED_ANSWER);
 
-        doReturn("M").when(source).get("key");
+        doReturn(PropertyValue.of("key","M", "test")).when(source).get("key");
         doReturn("source").when(source).getName();
 
         ConfigurationBuilder builder = new ConfigurationBuilder();
@@ -460,7 +460,7 @@ public class ConfigurationBuilderTest {
     public void canAddMultipleNonSPIPropertyFilter() {
         PropertySource source = mock(PropertySource.class, NOT_MOCKED_ANSWER);
 
-        doReturn("M").when(source).get("key");
+        doReturn(PropertyValue.of("key","M", "test")).when(source).get("key");
         doReturn("source").when(source).getName();
 
         ConfigurationBuilder builder = new ConfigurationBuilder();
@@ -574,7 +574,7 @@ public class ConfigurationBuilderTest {
         PropertySource source = mock(PropertySource.class, NOT_MOCKED_ANSWER);
 
         doReturn("source").when(source).getName();
-        doReturn("A").when(source).get("key");
+        doReturn(PropertyValue.of("key","A", "test")).when(source).get("key");
         doReturn(100).when(source).getOrdinal();
 
         ConfigurationBuilder builder = new ConfigurationBuilder().addPropertySources(source)
@@ -591,7 +591,7 @@ public class ConfigurationBuilderTest {
         PropertySource source = mock(PropertySource.class, NOT_MOCKED_ANSWER);
 
         doReturn("source").when(source).getName();
-        doReturn("A").when(source).get("key");
+        doReturn(PropertyValue.of("key","A", "test")).when(source).get("key");
         doReturn(100).when(source).getOrdinal();
 
         ConfigurationBuilder builder = new ConfigurationBuilder().addPropertySources(source)
@@ -667,7 +667,7 @@ public class ConfigurationBuilderTest {
         PropertySource source = mock(PropertySource.class, NOT_MOCKED_ANSWER);
 
         doReturn("source").when(source).getName();
-        doReturn("A").when(source).get("key");
+        doReturn(PropertyValue.of("key","A", "test")).when(source).get("key");
         doReturn(100).when(source).getOrdinal();
 
         ConfigurationBuilder builder = new ConfigurationBuilder();
@@ -708,7 +708,7 @@ public class ConfigurationBuilderTest {
         PropertySource source = mock(PropertySource.class, NOT_MOCKED_ANSWER);
 
         doReturn("source").when(source).getName();
-        doReturn("A").when(source).get("key");
+        doReturn(PropertyValue.of("key","A", "test")).when(source).get("key");
         doReturn(100).when(source).getOrdinal();
 
         ConfigurationBuilder builder = new ConfigurationBuilder();

http://git-wip-us.apache.org/repos/asf/incubator-tamaya/blob/d778cb81/modules/builder/src/test/java/org/apache/tamaya/builder/TestANonSPIPropertyFilter.java
----------------------------------------------------------------------
diff --git a/modules/builder/src/test/java/org/apache/tamaya/builder/TestANonSPIPropertyFilter.java b/modules/builder/src/test/java/org/apache/tamaya/builder/TestANonSPIPropertyFilter.java
index e113010..896e0bc 100644
--- a/modules/builder/src/test/java/org/apache/tamaya/builder/TestANonSPIPropertyFilter.java
+++ b/modules/builder/src/test/java/org/apache/tamaya/builder/TestANonSPIPropertyFilter.java
@@ -18,11 +18,12 @@
  */
 package org.apache.tamaya.builder;
 
+import org.apache.tamaya.spi.FilterContext;
 import org.apache.tamaya.spi.PropertyFilter;
 
 public class TestANonSPIPropertyFilter implements PropertyFilter {
     @Override
-    public String filterProperty(String key, String value) {
+    public String filterProperty(String value, FilterContext context) {
         String result = value;
 
         if (!result.contains(("ABC"))) {

http://git-wip-us.apache.org/repos/asf/incubator-tamaya/blob/d778cb81/modules/builder/src/test/java/org/apache/tamaya/builder/TestBNonSPIPropertyFilter.java
----------------------------------------------------------------------
diff --git a/modules/builder/src/test/java/org/apache/tamaya/builder/TestBNonSPIPropertyFilter.java b/modules/builder/src/test/java/org/apache/tamaya/builder/TestBNonSPIPropertyFilter.java
index 2ce81fc..a9c0ac2 100644
--- a/modules/builder/src/test/java/org/apache/tamaya/builder/TestBNonSPIPropertyFilter.java
+++ b/modules/builder/src/test/java/org/apache/tamaya/builder/TestBNonSPIPropertyFilter.java
@@ -18,11 +18,12 @@
  */
 package org.apache.tamaya.builder;
 
+import org.apache.tamaya.spi.FilterContext;
 import org.apache.tamaya.spi.PropertyFilter;
 
 public class TestBNonSPIPropertyFilter implements PropertyFilter {
     @Override
-    public String filterProperty(String key, String value) {
+    public String filterProperty(String value, FilterContext context) {
         String result = value;
 
         if (!result.contains(("XYZ"))) {

http://git-wip-us.apache.org/repos/asf/incubator-tamaya/blob/d778cb81/modules/builder/src/test/java/org/apache/tamaya/builder/TestPropertyFilter.java
----------------------------------------------------------------------
diff --git a/modules/builder/src/test/java/org/apache/tamaya/builder/TestPropertyFilter.java b/modules/builder/src/test/java/org/apache/tamaya/builder/TestPropertyFilter.java
index 80c4cb3..e22fca8 100644
--- a/modules/builder/src/test/java/org/apache/tamaya/builder/TestPropertyFilter.java
+++ b/modules/builder/src/test/java/org/apache/tamaya/builder/TestPropertyFilter.java
@@ -18,11 +18,12 @@
  */
 package org.apache.tamaya.builder;
 
+import org.apache.tamaya.spi.FilterContext;
 import org.apache.tamaya.spi.PropertyFilter;
 
 public class TestPropertyFilter implements PropertyFilter {
     @Override
-    public String filterProperty(String key, String value) {
+    public String filterProperty(String value, FilterContext context) {
         String result = value;
 
         if (!result.contains(("inBerlin"))) {

http://git-wip-us.apache.org/repos/asf/incubator-tamaya/blob/d778cb81/modules/builder/src/test/java/org/apache/tamaya/builder/TestPropertySource.java
----------------------------------------------------------------------
diff --git a/modules/builder/src/test/java/org/apache/tamaya/builder/TestPropertySource.java b/modules/builder/src/test/java/org/apache/tamaya/builder/TestPropertySource.java
index e30c244..f1ebfea 100644
--- a/modules/builder/src/test/java/org/apache/tamaya/builder/TestPropertySource.java
+++ b/modules/builder/src/test/java/org/apache/tamaya/builder/TestPropertySource.java
@@ -20,6 +20,7 @@ package org.apache.tamaya.builder;
 
 import org.apache.tamaya.core.propertysource.BasePropertySource;
 import org.apache.tamaya.spi.PropertySource;
+import org.apache.tamaya.spi.PropertyValue;
 
 import java.util.Collections;
 import java.util.Hashtable;
@@ -47,8 +48,8 @@ public class TestPropertySource  extends BasePropertySource
     }
 
     @Override
-    public String get(String key) {
-        return getProperties().get(key);
+    public PropertyValue get(String key) {
+        return PropertyValue.of(key, getProperties().get(key), getName());
     }
 
     @Override

http://git-wip-us.apache.org/repos/asf/incubator-tamaya/blob/d778cb81/modules/builder/src/test/java/org/apache/tamaya/builder/TestPropertySourceProvider.java
----------------------------------------------------------------------
diff --git a/modules/builder/src/test/java/org/apache/tamaya/builder/TestPropertySourceProvider.java b/modules/builder/src/test/java/org/apache/tamaya/builder/TestPropertySourceProvider.java
index 0dcd68c..5a2f400 100644
--- a/modules/builder/src/test/java/org/apache/tamaya/builder/TestPropertySourceProvider.java
+++ b/modules/builder/src/test/java/org/apache/tamaya/builder/TestPropertySourceProvider.java
@@ -21,6 +21,7 @@ package org.apache.tamaya.builder;
 import org.apache.tamaya.core.propertysource.BasePropertySource;
 import org.apache.tamaya.spi.PropertySource;
 import org.apache.tamaya.spi.PropertySourceProvider;
+import org.apache.tamaya.spi.PropertyValue;
 
 import java.util.ArrayList;
 import java.util.Collection;
@@ -54,8 +55,8 @@ public class TestPropertySourceProvider
         }
 
         @Override
-        public String get(String key) {
-            return getProperties().get(key);
+        public PropertyValue get(String key) {
+            return PropertyValue.of(key, getProperties().get(key), getName());
         }
 
         @Override
@@ -73,8 +74,8 @@ public class TestPropertySourceProvider
         }
 
         @Override
-        public String get(String key) {
-            return getProperties().get(key);
+        public PropertyValue get(String key) {
+            return PropertyValue.of(key, getProperties().get(key), getName());
         }
 
         @Override

http://git-wip-us.apache.org/repos/asf/incubator-tamaya/blob/d778cb81/modules/builder/src/test/java/org/apache/tamaya/builder/TestPropertySourceProviderB.java
----------------------------------------------------------------------
diff --git a/modules/builder/src/test/java/org/apache/tamaya/builder/TestPropertySourceProviderB.java b/modules/builder/src/test/java/org/apache/tamaya/builder/TestPropertySourceProviderB.java
index e06c75c..9cfe725 100644
--- a/modules/builder/src/test/java/org/apache/tamaya/builder/TestPropertySourceProviderB.java
+++ b/modules/builder/src/test/java/org/apache/tamaya/builder/TestPropertySourceProviderB.java
@@ -21,6 +21,7 @@ package org.apache.tamaya.builder;
 import org.apache.tamaya.core.propertysource.BasePropertySource;
 import org.apache.tamaya.spi.PropertySource;
 import org.apache.tamaya.spi.PropertySourceProvider;
+import org.apache.tamaya.spi.PropertyValue;
 
 import java.util.ArrayList;
 import java.util.Collection;
@@ -54,8 +55,8 @@ public class TestPropertySourceProviderB
         }
 
         @Override
-        public String get(String key) {
-            return getProperties().get(key);
+        public PropertyValue get(String key) {
+            return PropertyValue.of(key,getProperties().get(key), getName());
         }
 
         @Override
@@ -73,8 +74,8 @@ public class TestPropertySourceProviderB
         }
 
         @Override
-        public String get(String key) {
-            return getProperties().get(key);
+        public PropertyValue get(String key) {
+            return PropertyValue.of(key, getProperties().get(key), getName());
         }
 
         @Override

http://git-wip-us.apache.org/repos/asf/incubator-tamaya/blob/d778cb81/modules/events/src/main/java/org/apache/tamaya/events/FrozenPropertySource.java
----------------------------------------------------------------------
diff --git a/modules/events/src/main/java/org/apache/tamaya/events/FrozenPropertySource.java b/modules/events/src/main/java/org/apache/tamaya/events/FrozenPropertySource.java
index a8167f2..81e6dca 100644
--- a/modules/events/src/main/java/org/apache/tamaya/events/FrozenPropertySource.java
+++ b/modules/events/src/main/java/org/apache/tamaya/events/FrozenPropertySource.java
@@ -19,6 +19,7 @@
 package org.apache.tamaya.events;
 
 import org.apache.tamaya.spi.PropertySource;
+import org.apache.tamaya.spi.PropertyValue;
 
 import java.io.Serializable;
 import java.util.Collections;
@@ -81,8 +82,8 @@ public final class FrozenPropertySource implements PropertySource, Serializable
     }
 
     @Override
-    public String get(String key) {
-        return this.properties.get(key);
+    public PropertyValue get(String key) {
+        return PropertyValue.of(key, this.properties.get(key), getName());
     }
 
     @Override

http://git-wip-us.apache.org/repos/asf/incubator-tamaya/blob/d778cb81/modules/events/src/main/java/org/apache/tamaya/events/PropertySourceChangeBuilder.java
----------------------------------------------------------------------
diff --git a/modules/events/src/main/java/org/apache/tamaya/events/PropertySourceChangeBuilder.java b/modules/events/src/main/java/org/apache/tamaya/events/PropertySourceChangeBuilder.java
index cefa4f4..0858fdb 100644
--- a/modules/events/src/main/java/org/apache/tamaya/events/PropertySourceChangeBuilder.java
+++ b/modules/events/src/main/java/org/apache/tamaya/events/PropertySourceChangeBuilder.java
@@ -19,6 +19,7 @@
 package org.apache.tamaya.events;
 
 import org.apache.tamaya.spi.PropertySource;
+import org.apache.tamaya.spi.PropertyValue;
 
 import java.beans.PropertyChangeEvent;
 import java.util.ArrayList;
@@ -95,19 +96,19 @@ public final class PropertySourceChangeBuilder {
     public static Collection<PropertyChangeEvent> compare(PropertySource map1, PropertySource map2) {
         List<PropertyChangeEvent> changes = new ArrayList<>();
         for (Map.Entry<String, String> en : map1.getProperties().entrySet()) {
-            String val = map2.get(en.getKey());
+            PropertyValue val = map2.get(en.getKey());
             if (val == null) {
                 changes.add(new PropertyChangeEvent(map1, en.getKey(), null, en.getValue()));
             } else if (!val.equals(en.getValue())) {
-                changes.add(new PropertyChangeEvent(map1, en.getKey(), val, en.getValue()));
+                changes.add(new PropertyChangeEvent(map1, en.getKey(), val.getValue(), en.getValue()));
             }
         }
         for (Map.Entry<String, String> en : map2.getProperties().entrySet()) {
-            String val = map1.get(en.getKey());
+            PropertyValue val = map1.get(en.getKey());
             if (val == null) {
                 changes.add(new PropertyChangeEvent(map1, en.getKey(), en.getValue(), null));
             } else if (!val.equals(en.getValue())) {
-                changes.add(new PropertyChangeEvent(map1, en.getKey(), en.getValue(), val));
+                changes.add(new PropertyChangeEvent(map1, en.getKey(), en.getValue(), val.getValue()));
             }
         }
         return changes;
@@ -170,7 +171,7 @@ public final class PropertySourceChangeBuilder {
      * @return the builder for chaining.
      */
     public PropertySourceChangeBuilder remove(String key, String... otherKeys) {
-        String oldValue = this.source.get(key);
+        PropertyValue oldValue = this.source.get(key);
         if (oldValue == null) {
             this.delta.remove(key);
         }

http://git-wip-us.apache.org/repos/asf/incubator-tamaya/blob/d778cb81/modules/events/src/test/java/org/apache/tamaya/events/FrozenPropertySourceTest.java
----------------------------------------------------------------------
diff --git a/modules/events/src/test/java/org/apache/tamaya/events/FrozenPropertySourceTest.java b/modules/events/src/test/java/org/apache/tamaya/events/FrozenPropertySourceTest.java
index 0c61e0b..1431228 100644
--- a/modules/events/src/test/java/org/apache/tamaya/events/FrozenPropertySourceTest.java
+++ b/modules/events/src/test/java/org/apache/tamaya/events/FrozenPropertySourceTest.java
@@ -58,7 +58,7 @@ public class FrozenPropertySourceTest {
         PropertySource ps = FrozenPropertySource.of(myPS);
         assertNotNull(ps);
         for (Map.Entry<String, String> e : myPS.getProperties().entrySet()) {
-            assertEquals(ps.get(e.getKey()), e.getValue());
+            assertEquals(ps.get(e.getKey()).getValue(), e.getValue());
         }
     }
 

http://git-wip-us.apache.org/repos/asf/incubator-tamaya/blob/d778cb81/modules/filter/pom.xml
----------------------------------------------------------------------
diff --git a/modules/filter/pom.xml b/modules/filter/pom.xml
new file mode 100644
index 0000000..2480950
--- /dev/null
+++ b/modules/filter/pom.xml
@@ -0,0 +1,77 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+Licensed to the Apache Software Foundation (ASF) under one
+or more contributor license agreements.  See the NOTICE file
+distributed with this work for additional information
+regarding copyright ownership.  The ASF licenses this file
+to you under the Apache License, Version 2.0 (the
+"License"); you may not use this file except in compliance
+with the License.  You may obtain a copy current the License at
+
+   http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing,
+software distributed under the License is distributed on an
+"AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+KIND, either express or implied.  See the License for the
+specific language governing permissions and limitations
+under the License.
+-->
+<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
+    <modelVersion>4.0.0</modelVersion>
+
+    <parent>
+        <groupId>org.apache.tamaya.ext</groupId>
+        <artifactId>tamaya-extensions</artifactId>
+        <version>0.2-incubating-SNAPSHOT</version>
+    </parent>
+
+    <artifactId>tamaya-filter</artifactId>
+    <name>Apache Tamaya Modules - Adaptive Configuration Filtering</name>
+    <packaging>bundle</packaging>
+
+    <properties>
+        <jdkVersion>1.7</jdkVersion>
+    </properties>
+
+    <dependencies>
+        <dependency>
+            <groupId>org.apache.tamaya</groupId>
+            <artifactId>tamaya-api</artifactId>
+            <version>${project.version}</version>
+            <scope>provided</scope>
+        </dependency>
+        <dependency>
+            <groupId>org.apache.tamaya</groupId>
+            <artifactId>tamaya-core</artifactId>
+            <version>${project.version}</version>
+            <scope>provided</scope>
+        </dependency>
+        <dependency>
+            <groupId>junit</groupId>
+            <artifactId>junit</artifactId>
+        </dependency>
+    </dependencies>
+
+    <build>
+        <plugins>
+            <plugin>
+                <groupId>org.apache.felix</groupId>
+                <artifactId>maven-bundle-plugin</artifactId>
+                <extensions>true</extensions>
+                <configuration>
+                    <instructions>
+                        <Export-Package>
+                            org.apache.tamaya.filter,
+                        </Export-Package>
+                        <!--<Private-Package>-->
+                            <!--org.apache.tamaya.events.internal-->
+                        <!--</Private-Package>-->
+                    </instructions>
+                </configuration>
+            </plugin>
+        </plugins>
+    </build>
+
+    
+</project>
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/incubator-tamaya/blob/d778cb81/modules/filter/src/main/java/org/apache/tamaya/filter/ConfigurationFilter.java
----------------------------------------------------------------------
diff --git a/modules/filter/src/main/java/org/apache/tamaya/filter/ConfigurationFilter.java b/modules/filter/src/main/java/org/apache/tamaya/filter/ConfigurationFilter.java
new file mode 100644
index 0000000..99ab27f
--- /dev/null
+++ b/modules/filter/src/main/java/org/apache/tamaya/filter/ConfigurationFilter.java
@@ -0,0 +1,112 @@
+/*
+ * 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.filter;
+
+import org.apache.tamaya.spi.FilterContext;
+import org.apache.tamaya.spi.PropertyFilter;
+
+
+/**
+ * Hereby
+ * <ul>
+ *     <li><b>Single</b> filters are applied only when values are explicitly accessed. This is useful, e.g. for
+ *     filtering passwords into clear text variants. Nevertheless metadata keys hidden on map level must be
+ *     accessible (=not filtered) when accessed as single values.</li>
+ *     <li><b>Map</b> filters are applied when values are filtered as part of a full properties access.
+ *     Often filtering in these cases is more commonly applied, e.g. you dont want to show up all kind of metadata.
+ *     </li>
+ *     For both variants individual filter rules can be applied here. All filters configured are managed on a
+ *     thread-local level, so this class is typically used to temporarely filter out some values. Do not forget to
+ *     restore its state, when not using a thread anymore (especially important in multi-threaded environments), not
+ *     doing so will create nasty side effects of configuration not being visisble depending on the thread
+ *     active.
+ * </ul>
+ */
+public final class ConfigurationFilter implements PropertyFilter{
+
+    static final ThreadLocal<Boolean> THREADED_METADATA_FILTERED = new ThreadLocal<Boolean>(){
+        @Override
+        protected Boolean initialValue() {
+            return Boolean.TRUE;
+        }
+    };
+
+    private static final ThreadLocal<ProgrammableFilter> THREADED_MAP_FILTERS = new ThreadLocal<ProgrammableFilter>(){
+        @Override
+        protected ProgrammableFilter initialValue() {
+            return new ProgrammableFilter();
+        }
+    };
+
+    private static final ThreadLocal<ProgrammableFilter> THREADED_SINGLE_FILTERS = new ThreadLocal<ProgrammableFilter>(){
+        @Override
+        protected ProgrammableFilter initialValue() {
+            return new ProgrammableFilter();
+        }
+    };
+
+    /**
+     * Seactivates metadata filtering also on global map access for this thread.
+     * @see #clearFilters()
+     * @param active true,to enable metadata filtering (default).
+     */
+    public static void setMetadataFilter(boolean active){
+        THREADED_METADATA_FILTERED.set(active);
+    }
+
+    /**
+     * Access the filtering configuration that is used for filtering single property values accessed.
+     * @return the filtering config, never null.
+     */
+    public static ProgrammableFilter getSingleFilters(){
+        return THREADED_SINGLE_FILTERS.get();
+    }
+
+    /**
+     * Access the filtering configuration that is used for filtering configuration properties accessed as full
+     * map.
+     * @return the filtering config, never null.
+     */
+    public static ProgrammableFilter getMapFilters(){
+        return THREADED_MAP_FILTERS.get();
+    }
+
+    /**
+     * Removes all programmable filters active on the current thread.
+     */
+    public static void clearFilters(){
+        THREADED_MAP_FILTERS.get().clearFilters();
+        THREADED_SINGLE_FILTERS.get().clearFilters();
+        THREADED_METADATA_FILTERED.set(true);
+    }
+
+    @Override
+    public String filterProperty(String valueToBeFiltered, FilterContext context) {
+        if(!context.isSinglePropertyScoped()){
+            for(PropertyFilter pred: THREADED_MAP_FILTERS.get().getFilters()){
+                valueToBeFiltered = pred.filterProperty(valueToBeFiltered, context);
+            }
+        }else{
+            for(PropertyFilter pred: THREADED_SINGLE_FILTERS.get().getFilters()){
+                valueToBeFiltered = pred.filterProperty(valueToBeFiltered, context);
+            }
+        }
+        return valueToBeFiltered;
+    }
+}

http://git-wip-us.apache.org/repos/asf/incubator-tamaya/blob/d778cb81/modules/filter/src/main/java/org/apache/tamaya/filter/DefaultMetadataFilter.java
----------------------------------------------------------------------
diff --git a/modules/filter/src/main/java/org/apache/tamaya/filter/DefaultMetadataFilter.java b/modules/filter/src/main/java/org/apache/tamaya/filter/DefaultMetadataFilter.java
new file mode 100644
index 0000000..389d9fa
--- /dev/null
+++ b/modules/filter/src/main/java/org/apache/tamaya/filter/DefaultMetadataFilter.java
@@ -0,0 +1,42 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.tamaya.filter;
+
+import org.apache.tamaya.spi.FilterContext;
+import org.apache.tamaya.spi.PropertyFilter;
+
+/**
+ * Default property filter that hides metadta entries starting with an '_', similar ti {@code etcd}.
+ */
+public final class DefaultMetadataFilter implements PropertyFilter{
+    @Override
+    public String filterProperty(String valueToBeFiltered, FilterContext context) {
+        if(context.isSinglePropertyScoped()){
+            // When accessing keys explicitly, do not hide anything.
+            return valueToBeFiltered;
+        }
+        if(ConfigurationFilter.THREADED_METADATA_FILTERED.get()) {
+            if (context.getKey().startsWith("_")) {
+                // Hide metadata entries.
+                return null;
+            }
+        }
+        return valueToBeFiltered;
+    }
+}

http://git-wip-us.apache.org/repos/asf/incubator-tamaya/blob/d778cb81/modules/filter/src/main/java/org/apache/tamaya/filter/ProgrammableFilter.java
----------------------------------------------------------------------
diff --git a/modules/filter/src/main/java/org/apache/tamaya/filter/ProgrammableFilter.java b/modules/filter/src/main/java/org/apache/tamaya/filter/ProgrammableFilter.java
new file mode 100644
index 0000000..8589faa
--- /dev/null
+++ b/modules/filter/src/main/java/org/apache/tamaya/filter/ProgrammableFilter.java
@@ -0,0 +1,111 @@
+/*
+ * 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.filter;
+
+import org.apache.tamaya.spi.FilterContext;
+import org.apache.tamaya.spi.PropertyFilter;
+
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.List;
+
+/**
+ * A set of property filter and accessor methods.
+ */
+public final class ProgrammableFilter implements PropertyFilter{
+    /** The filters. */
+    private List<PropertyFilter> filters = new ArrayList<>();
+
+    /**
+     * Add a filter.
+     * @param filter the filter.
+     */
+    public void addFilter(PropertyFilter filter){
+        filters.add(filter);
+    }
+
+    /**
+     * Adds a filter at given position.
+     * @param pos the position.
+     * @param filter the filter.
+     */
+    public void addFilter(int pos, PropertyFilter filter){
+        filters.add(pos, filter);
+    }
+
+    /**
+     * Removes a filter at a given position.
+     * @param pos the position.
+     * @return the filter removed, or null.
+     */
+    public PropertyFilter removeFilter(int pos){
+        return filters.remove(pos);
+    }
+
+    /**
+     * Clears all filters.
+     */
+    public void clearFilters(){
+        filters.clear();
+    }
+
+    /**
+     * Set the filters.
+     * @param filters the filters to be applied.
+     */
+    public void setFilters(PropertyFilter... filters){
+        setFilters(Arrays.asList(filters));
+    }
+
+    /**
+     * Set the filters.
+     * @param filters the filters to be applied.
+     */
+    public void setFilters(Collection<PropertyFilter> filters) {
+        filters.clear();
+        filters.addAll(filters);
+    }
+
+    /**
+     * Get all filters.
+     * @return all filters.
+     */
+    public List<PropertyFilter> getFilters(){
+        return Collections.unmodifiableList(filters);
+    }
+
+    @Override
+    public String filterProperty(String valueToBeFiltered, FilterContext context) {
+        for(PropertyFilter filter:filters){
+            valueToBeFiltered = filter.filterProperty(valueToBeFiltered, context);
+        }
+        return valueToBeFiltered;
+    }
+
+    @Override
+    public String toString() {
+        return "FilterConfig{" +
+                "filters=" + filters +
+                '}';
+    }
+
+
+}

http://git-wip-us.apache.org/repos/asf/incubator-tamaya/blob/d778cb81/modules/filter/src/main/java/org/apache/tamaya/filter/RegexPropertyFilter.java
----------------------------------------------------------------------
diff --git a/modules/filter/src/main/java/org/apache/tamaya/filter/RegexPropertyFilter.java b/modules/filter/src/main/java/org/apache/tamaya/filter/RegexPropertyFilter.java
new file mode 100644
index 0000000..616f2cf
--- /dev/null
+++ b/modules/filter/src/main/java/org/apache/tamaya/filter/RegexPropertyFilter.java
@@ -0,0 +1,56 @@
+/*
+ * 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.filter;
+
+import org.apache.tamaya.spi.FilterContext;
+import org.apache.tamaya.spi.PropertyFilter;
+
+import java.util.Objects;
+
+/**
+ * Predicate filtering using a regex expression operating on the key.
+ */
+public final class RegexPropertyFilter implements PropertyFilter{
+    /** The expression used to filter. */
+    private String expression;
+
+    /**
+     * Creates a new regex filter expression.
+     * @param expression the reged expression, not null.
+     */
+    public RegexPropertyFilter(String expression){
+        this.expression = Objects.requireNonNull(expression);
+    }
+
+    @Override
+    public String filterProperty(String valueToBeFiltered, FilterContext context) {
+        if(context.getKey().matches(expression)){
+            return null;
+        }
+        return valueToBeFiltered;
+    }
+
+    @Override
+    public String toString() {
+        return "RegexPredicate{" +
+                "expression='" + expression + '\'' +
+                '}';
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/incubator-tamaya/blob/d778cb81/modules/filter/src/main/resources/META-INF/services/org.apache.tamaya.spi.PropertyFilter
----------------------------------------------------------------------
diff --git a/modules/filter/src/main/resources/META-INF/services/org.apache.tamaya.spi.PropertyFilter b/modules/filter/src/main/resources/META-INF/services/org.apache.tamaya.spi.PropertyFilter
new file mode 100644
index 0000000..630c222
--- /dev/null
+++ b/modules/filter/src/main/resources/META-INF/services/org.apache.tamaya.spi.PropertyFilter
@@ -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.filter.ConfigurationFilter
+org.apache.tamaya.filter.DefaultMetadataFilter
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/incubator-tamaya/blob/d778cb81/modules/formats/src/main/java/org/apache/tamaya/format/FlattenedDefaultPropertySource.java
----------------------------------------------------------------------
diff --git a/modules/formats/src/main/java/org/apache/tamaya/format/FlattenedDefaultPropertySource.java b/modules/formats/src/main/java/org/apache/tamaya/format/FlattenedDefaultPropertySource.java
index 4680981..9d2097f 100644
--- a/modules/formats/src/main/java/org/apache/tamaya/format/FlattenedDefaultPropertySource.java
+++ b/modules/formats/src/main/java/org/apache/tamaya/format/FlattenedDefaultPropertySource.java
@@ -19,6 +19,7 @@
 package org.apache.tamaya.format;
 
 import org.apache.tamaya.spi.PropertySource;
+import org.apache.tamaya.spi.PropertyValue;
 
 import java.util.Collections;
 import java.util.HashMap;
@@ -101,8 +102,8 @@ public class FlattenedDefaultPropertySource implements PropertySource {
     }
 
     @Override
-    public String get(String key) {
-        return properties.get(key);
+    public PropertyValue get(String key) {
+        return PropertyValue.of(key, properties.get(key), getName());
     }
 
     @Override

http://git-wip-us.apache.org/repos/asf/incubator-tamaya/blob/d778cb81/modules/formats/src/test/java/org/apache/tamaya/format/FlattenedDefaultPropertySourceTest.java
----------------------------------------------------------------------
diff --git a/modules/formats/src/test/java/org/apache/tamaya/format/FlattenedDefaultPropertySourceTest.java b/modules/formats/src/test/java/org/apache/tamaya/format/FlattenedDefaultPropertySourceTest.java
index b53d367..adc94f6 100644
--- a/modules/formats/src/test/java/org/apache/tamaya/format/FlattenedDefaultPropertySourceTest.java
+++ b/modules/formats/src/test/java/org/apache/tamaya/format/FlattenedDefaultPropertySourceTest.java
@@ -67,14 +67,13 @@ public class FlattenedDefaultPropertySourceTest {
     @Test
     public void testGet() throws Exception {
         FlattenedDefaultPropertySource ps = new FlattenedDefaultPropertySource(createConfigurationData("test2"));
-        assertEquals("aValue", ps.get("a"));
-        assertNotNull(ps.get("section1.sectionKey1"));
-        assertNotNull(ps.get("section2.sectionKey1"));
-        assertNull(ps.get("sectionKey1"));
+        assertEquals("aValue", ps.get("a").get("a"));
+        assertNotNull(ps.get("section1.sectionKey1").get("section1.sectionKey1"));
+        assertNotNull(ps.get("section2.sectionKey1").get("section2.sectionKey1"));
         assertNull(ps.get("sectionKey1"));
         ps = new FlattenedDefaultPropertySource(createConfigurationDataNoDefault("test2"));
-        assertEquals("sectionValue11", ps.get("section1.sectionKey1"));
-        assertEquals("sectionValue21", ps.get("section2.sectionKey1"));
+        assertEquals("sectionValue11", ps.get("section1.sectionKey1").get("section1.sectionKey1"));
+        assertEquals("sectionValue21", ps.get("section2.sectionKey1").get("section2.sectionKey1"));
         assertNull(ps.get("a"));
         assertNull(ps.get("section1"));
     }

http://git-wip-us.apache.org/repos/asf/incubator-tamaya/blob/d778cb81/modules/functions/src/main/java/org/apache/tamaya/functions/ConfigWrappingPropertySource.java
----------------------------------------------------------------------
diff --git a/modules/functions/src/main/java/org/apache/tamaya/functions/ConfigWrappingPropertySource.java b/modules/functions/src/main/java/org/apache/tamaya/functions/ConfigWrappingPropertySource.java
index 0c8f7a6..83a628a 100644
--- a/modules/functions/src/main/java/org/apache/tamaya/functions/ConfigWrappingPropertySource.java
+++ b/modules/functions/src/main/java/org/apache/tamaya/functions/ConfigWrappingPropertySource.java
@@ -20,6 +20,7 @@ package org.apache.tamaya.functions;
 
 import org.apache.tamaya.Configuration;
 import org.apache.tamaya.spi.PropertySource;
+import org.apache.tamaya.spi.PropertyValue;
 
 import java.util.Map;
 import java.util.Objects;
@@ -58,8 +59,8 @@ final class ConfigWrappingPropertySource implements PropertySource {
     }
 
     @Override
-    public String get(String key) {
-        return config.get(key);
+    public PropertyValue get(String key) {
+        return PropertyValue.of(key, config.get(key), getName());
     }
 
     @Override

http://git-wip-us.apache.org/repos/asf/incubator-tamaya/blob/d778cb81/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 57815fe..5effaa7 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
@@ -193,7 +193,7 @@ public final class ConfigurationFunctions {
      * @return true, if the entry is exact in this section
      */
     public static boolean isKeyInSection(String key, String sectionKey) {
-        return key.startsWith(sectionKey);
+        return sectionKey.isEmpty() || key.startsWith(sectionKey);
     }
 
     /**
@@ -399,12 +399,10 @@ public final class ConfigurationFunctions {
             @Override
             public String query(Configuration config) {
                 Map<String, String> props = new TreeMap<>(config.getProperties());
-                props.put("{meta}type", "Configuration");
-                props.put("{meta}class", config.getClass().getName());
-                props.put("{meta}timestamp", String.valueOf(System.currentTimeMillis()));
+                props.put("__timestamp", String.valueOf(System.currentTimeMillis()));
                 if(info!=null) {
                     for (Map.Entry<String, String> en : info.entrySet()) {
-                        props.put("{meta}info." + escape(en.getKey()), escape(en.getValue()));
+                        props.put("__" + escape(en.getKey()), escape(en.getValue()));
                     }
                 }
                 StringBuilder builder = new StringBuilder(400).append("{\n");
@@ -443,12 +441,10 @@ public final class ConfigurationFunctions {
             @Override
             public String query(Configuration config) {
                 Map<String, String> props = new TreeMap<>(config.getProperties());
-                props.put("{meta}type", "Configuration");
-                props.put("{meta}class", config.getClass().getName());
-                props.put("{meta}timestamp", String.valueOf(System.currentTimeMillis()));
+                props.put("__timestamp", String.valueOf(System.currentTimeMillis()));
                 if(info!=null) {
                     for (Map.Entry<String, String> en : info.entrySet()) {
-                        props.put("{meta}info." + escape(en.getKey()), escape(en.getValue()));
+                        props.put("__" + escape(en.getKey()), escape(en.getValue()));
                     }
                 }
                 StringBuilder builder = new StringBuilder(400);
@@ -481,12 +477,10 @@ public final class ConfigurationFunctions {
             @Override
             public String query(Configuration config) {
                 Map<String, String> props = new TreeMap<>(config.getProperties());
-                props.put("{meta}type", "Configuration");
-                props.put("{meta}class", config.getClass().getName());
-                props.put("{meta}timestamp", String.valueOf(System.currentTimeMillis()));
+                props.put("__timestamp", String.valueOf(System.currentTimeMillis()));
                 if(info!=null) {
                     for (Map.Entry<String, String> en : info.entrySet()) {
-                        props.put("{meta}info." + escape(en.getKey()), escape(en.getValue()));
+                        props.put("__" + escape(en.getKey()), escape(en.getValue()));
                     }
                 }
                 StringBuilder builder = new StringBuilder(400).append("Configuration:\n");

http://git-wip-us.apache.org/repos/asf/incubator-tamaya/blob/d778cb81/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
index 309424d..de48fa8 100644
--- a/modules/functions/src/main/java/org/apache/tamaya/functions/EnrichedPropertySource.java
+++ b/modules/functions/src/main/java/org/apache/tamaya/functions/EnrichedPropertySource.java
@@ -19,6 +19,7 @@
 package org.apache.tamaya.functions;
 
 import org.apache.tamaya.spi.PropertySource;
+import org.apache.tamaya.spi.PropertyValue;
 
 import java.util.HashMap;
 import java.util.Map;
@@ -60,19 +61,19 @@ class EnrichedPropertySource implements PropertySource {
     }
 
     @Override
-    public String get(String key) {
+    public PropertyValue get(String key) {
         if (overriding) {
             String val = addedProperties.get(key);
             if (val != null) {
-                return val;
+                return PropertyValue.of(key, val, getName());
             }
             return basePropertySource.get(key);
         }
-        String val = basePropertySource.get(key);
+        PropertyValue val = basePropertySource.get(key);
         if (val != null) {
             return val;
         }
-        return addedProperties.get(key);
+        return PropertyValue.of(key, addedProperties.get(key), getName());
 
     }
 

http://git-wip-us.apache.org/repos/asf/incubator-tamaya/blob/d778cb81/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
index 657656b..7eccdee 100644
--- a/modules/functions/src/main/java/org/apache/tamaya/functions/FilteredPropertySource.java
+++ b/modules/functions/src/main/java/org/apache/tamaya/functions/FilteredPropertySource.java
@@ -19,6 +19,7 @@
 package org.apache.tamaya.functions;
 
 import org.apache.tamaya.spi.PropertySource;
+import org.apache.tamaya.spi.PropertyValue;
 
 import java.util.HashMap;
 import java.util.Map;
@@ -53,8 +54,8 @@ class FilteredPropertySource implements PropertySource {
     }
 
     @Override
-    public String get(String key) {
-        return getProperties().get(key);
+    public PropertyValue get(String key) {
+        return PropertyValue.of(key, getProperties().get(key), getName());
     }
 
     @Override



[3/8] incubator-tamaya git commit: Added Tamaya banner on startup.

Posted by an...@apache.org.
Added Tamaya banner on startup.


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

Branch: refs/heads/master
Commit: eba49d80e0428c83a9afd848fbab033d357d5388
Parents: 2eef8a5
Author: anatole <an...@apache.org>
Authored: Tue Feb 2 10:32:16 2016 +0100
Committer: anatole <an...@apache.org>
Committed: Tue Feb 2 10:32:16 2016 +0100

----------------------------------------------------------------------
 .../api/src/main/java/org/apache/tamaya/ConfigurationProvider.java | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/incubator-tamaya/blob/eba49d80/code/api/src/main/java/org/apache/tamaya/ConfigurationProvider.java
----------------------------------------------------------------------
diff --git a/code/api/src/main/java/org/apache/tamaya/ConfigurationProvider.java b/code/api/src/main/java/org/apache/tamaya/ConfigurationProvider.java
index 3bf42e2..fabe0a8 100644
--- a/code/api/src/main/java/org/apache/tamaya/ConfigurationProvider.java
+++ b/code/api/src/main/java/org/apache/tamaya/ConfigurationProvider.java
@@ -43,7 +43,7 @@ public final class ConfigurationProvider {
         }
         BufferedReader reader = null;
         try{
-            URL url = ConfigurationProvider.class.getResource("/banner.txt");
+            URL url = ConfigurationProvider.class.getResource("/tamaya-banner.txt");
             if(url!=null){
                 reader = new BufferedReader(new InputStreamReader(url.openStream(), "UTF-8"));
                 StringBuilder b = new StringBuilder();


[2/8] incubator-tamaya git commit: TAMAYA-138: Adding Experimental annotation.

Posted by an...@apache.org.
TAMAYA-138: Adding Experimental annotation.


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

Branch: refs/heads/master
Commit: 2eef8a5820e9a00ea182659091a2100dd2e8a1e3
Parents: 13f69da
Author: anatole <an...@apache.org>
Authored: Tue Feb 2 10:22:02 2016 +0100
Committer: anatole <an...@apache.org>
Committed: Tue Feb 2 10:22:02 2016 +0100

----------------------------------------------------------------------
 .../main/java/org/apache/tamaya/spi/Experimental.java    | 11 +++++------
 .../main/java/org/apache/tamaya/spi/FilterContext.java   |  6 +++---
 2 files changed, 8 insertions(+), 9 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/incubator-tamaya/blob/2eef8a58/code/api/src/main/java/org/apache/tamaya/spi/Experimental.java
----------------------------------------------------------------------
diff --git a/code/api/src/main/java/org/apache/tamaya/spi/Experimental.java b/code/api/src/main/java/org/apache/tamaya/spi/Experimental.java
index dc3dfec..9831820 100644
--- a/code/api/src/main/java/org/apache/tamaya/spi/Experimental.java
+++ b/code/api/src/main/java/org/apache/tamaya/spi/Experimental.java
@@ -18,16 +18,15 @@
  */
 package org.apache.tamaya.spi;
 
-import java.lang.annotation.ElementType;
-import java.lang.annotation.Retention;
-import java.lang.annotation.RetentionPolicy;
-import java.lang.annotation.Target;
+import java.lang.annotation.*;
 
 /**
  * This is a simple annotation for flaging out functionality or features the Tamaya team is not sure if it is already
  * stabilized, so use it with some caution.
  */
-@Retention(RetentionPolicy.SOURCE)
-@Target({ElementType.METHOD, ElementType.ANNOTATION_TYPE, ElementType.FIELD, ElementType.TYPE})
+@Retention(RetentionPolicy.RUNTIME)
+@Inherited
+@Target({ElementType.METHOD, ElementType.ANNOTATION_TYPE, ElementType.CONSTRUCTOR, ElementType.FIELD,
+        ElementType.TYPE})
 public @interface Experimental {
 }

http://git-wip-us.apache.org/repos/asf/incubator-tamaya/blob/2eef8a58/code/api/src/main/java/org/apache/tamaya/spi/FilterContext.java
----------------------------------------------------------------------
diff --git a/code/api/src/main/java/org/apache/tamaya/spi/FilterContext.java b/code/api/src/main/java/org/apache/tamaya/spi/FilterContext.java
index 8371df7..105d7f4 100644
--- a/code/api/src/main/java/org/apache/tamaya/spi/FilterContext.java
+++ b/code/api/src/main/java/org/apache/tamaya/spi/FilterContext.java
@@ -32,7 +32,7 @@ import java.util.Objects;
 public class FilterContext {
 
     private final String key;
-    @org.apache.tamaya.Experimental
+    @Experimental
     private Map<String, String> metaEntries = new HashMap();
 
     /**
@@ -76,7 +76,7 @@ public class FilterContext {
      *
      * @return the configuration instance, or null.
      */
-    @org.apache.tamaya.Experimental
+    @Experimental
     public Map<String, String> getMetaEntries() {
         return metaEntries;
     }
@@ -86,7 +86,7 @@ public class FilterContext {
      * access. For both scenarios filtering may be different.
      * @return true, if it is a directly accessed key.
      */
-    @org.apache.tamaya.Experimental
+    @Experimental
     public boolean isSingleAccessedProperty(){
         return this.metaEntries.size()==1;
     }


[6/8] incubator-tamaya git commit: TAMAYA-136: Adding PropertyValue for PropertySource SPI. All changes and test fixes in all modules/examples relevant for release.

Posted by an...@apache.org.
http://git-wip-us.apache.org/repos/asf/incubator-tamaya/blob/d778cb81/modules/server/src/main/java/org/apache/tamaya/server/internal/DefaultConfigAdminService.java
----------------------------------------------------------------------
diff --git a/modules/server/src/main/java/org/apache/tamaya/server/internal/DefaultConfigAdminService.java b/modules/server/src/main/java/org/apache/tamaya/server/internal/DefaultConfigAdminService.java
deleted file mode 100644
index 47500d1..0000000
--- a/modules/server/src/main/java/org/apache/tamaya/server/internal/DefaultConfigAdminService.java
+++ /dev/null
@@ -1,136 +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.server.internal;
-
-import org.apache.tamaya.ConfigurationProvider;
-import org.apache.tamaya.TypeLiteral;
-import org.apache.tamaya.server.spi.ConfigAdminService;
-import org.apache.tamaya.spi.PropertyConverter;
-import org.apache.tamaya.spi.PropertyFilter;
-import org.apache.tamaya.spi.PropertySource;
-import org.apache.tamaya.spi.PropertyValueCombinationPolicy;
-
-import javax.servlet.http.HttpServletRequest;
-import javax.ws.rs.core.MediaType;
-import java.util.ArrayList;
-import java.util.List;
-
-
-/**
- * Implementation of the ConfigProviderService backend interface for serving configuration.
- */
-public class DefaultConfigAdminService implements ConfigAdminService {
-    @Override
-    public String formatCombinationPolicy(MediaType mediaType, PropertyValueCombinationPolicy propertyValueCombinationPolicy, HttpServletRequest request) {
-        return null;
-    }
-
-    @Override
-    public String formatPropertyConverter(MediaType mediaType, List<PropertyConverter> propertyConverter, HttpServletRequest request) {
-        return null;
-    }
-
-    @Override
-    public String formatPropertyFilter(MediaType mediaType, String filterClass, HttpServletRequest request) {
-        return null;
-    }
-
-    @Override
-    public String formatPropertySource(MediaType mediaType, String sourceId, String sourceClass, HttpServletRequest request) {
-        return null;
-    }
-
-    @Override
-    public List<PropertyConverter> collectPropertyConverters(String converterClass, String targetType) {
-        List<PropertyConverter> result = new ArrayList<>();
-        TypeLiteral type = null;
-        if(targetType!=null){
-            try {
-                type = TypeLiteral.of(Class.forName(targetType));
-            } catch (ClassNotFoundException e) {
-                e.printStackTrace();
-            }
-        }
-        List<PropertyConverter> list = ConfigurationProvider.getConfigurationContext().getPropertyConverters(type);
-        for(PropertyConverter conv:list){
-            if(converterClass!=null && !conv.getClass().getName().matches(converterClass)){
-                continue;
-            }
-            if(targetType!=null && !conv.getClass().getName().matches(converterClass)){
-                continue;
-            }
-            result.add(conv);
-        }
-        return result;
-    }
-
-    @Override
-    public List<PropertyFilter> collectPropertyFilters(String filterClass) {
-        List<PropertyFilter> result = new ArrayList<>();
-        for(PropertyFilter conv:ConfigurationProvider.getConfigurationContext().getPropertyFilters()){
-            if(filterClass!=null && !conv.getClass().getName().matches(filterClass)){
-                continue;
-            }
-            result.add(conv);
-        }
-        return result;
-    }
-
-    @Override
-    public List<PropertySource> collectPropertySources(String sourceId, String sourceClass) {
-        List<PropertySource> result = new ArrayList<>();
-        for(PropertySource conv:ConfigurationProvider.getConfigurationContext().getPropertySources()){
-            if(sourceClass!=null && !conv.getClass().getName().matches(sourceClass)){
-                continue;
-            }
-            if(sourceId!=null && !conv.getName().matches(sourceId)) {
-                continue;
-            }
-            result.add(conv);
-        }
-        return result;
-    }
-
-//    @Override
-//    public String getConfigurationWithPath(String path, MediaType mediaType, String scope, String scopeId, HttpServletRequest request){
-//        Map<String,String> requestInfo = new HashMap<>();
-//        requestInfo.put("filter",path);
-//        requestInfo.put("timestamp", String.valueOf(System.currentTimeMillis()));
-//        requestInfo.put("format", mediaType.toString());
-//        if(scope!=null && scopeId!=null){
-//            return getScopedConfigurationWithPath(scope, scopeId, path, request, mediaType, requestInfo);
-//        }
-//        Configuration config = ConfigurationProvider.getConfiguration()
-//                .with(ConfigurationFunctions.sectionsRecursive(path.split(",")));
-//        if(mediaType.equals(MediaType.APPLICATION_JSON_TYPE)) {
-//            return config.query(ConfigurationFunctions.jsonInfo(requestInfo));
-//        }
-//        if(mediaType.equals(MediaType.APPLICATION_XML_TYPE)) {
-//            return config.query(ConfigurationFunctions.xmlInfo(requestInfo));
-//        }
-//        if(mediaType.equals(MediaType.TEXT_HTML_TYPE)) {
-//            return config.query(ConfigurationFunctions.htmlInfo(requestInfo));
-//        }
-//        if(mediaType.equals(MediaType.TEXT_PLAIN_TYPE)) {
-//            return config.query(ConfigurationFunctions.textInfo(requestInfo));
-//        }
-//        return null;
-//    }
-
-}

http://git-wip-us.apache.org/repos/asf/incubator-tamaya/blob/d778cb81/modules/server/src/main/java/org/apache/tamaya/server/internal/DefaultConfigService.java
----------------------------------------------------------------------
diff --git a/modules/server/src/main/java/org/apache/tamaya/server/internal/DefaultConfigService.java b/modules/server/src/main/java/org/apache/tamaya/server/internal/DefaultConfigService.java
deleted file mode 100644
index 5bb4132..0000000
--- a/modules/server/src/main/java/org/apache/tamaya/server/internal/DefaultConfigService.java
+++ /dev/null
@@ -1,137 +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.server.internal;
-
-import org.apache.tamaya.Configuration;
-import org.apache.tamaya.ConfigurationProvider;
-import org.apache.tamaya.functions.ConfigurationFunctions;
-import org.apache.tamaya.server.spi.ConfigService;
-import org.apache.tamaya.server.spi.ScopeManager;
-
-import javax.servlet.http.HttpServletRequest;
-import javax.ws.rs.core.MediaType;
-import java.util.HashMap;
-import java.util.Map;
-
-
-/**
- * Implementation of the ConfigProviderService backend interface for serving configuration.
- */
-public class DefaultConfigService implements ConfigService {
-
-    @Override
-    public String getConfigurationWithPath(String path, MediaType mediaType, String scope, String scopeId, HttpServletRequest request){
-        Map<String,String> requestInfo = new HashMap<>();
-        requestInfo.put("filter",path);
-        requestInfo.put("timestamp", String.valueOf(System.currentTimeMillis()));
-        requestInfo.put("format", mediaType.toString());
-        if(scope!=null && scopeId!=null){
-            return getScopedConfigurationWithPath(scope, scopeId, path, request, mediaType, requestInfo);
-        }
-        Configuration config = ConfigurationProvider.getConfiguration()
-                .with(ConfigurationFunctions.sectionsRecursive(path.split(",")));
-        if(mediaType.equals(MediaType.APPLICATION_JSON_TYPE)) {
-            return config.query(ConfigurationFunctions.jsonInfo(requestInfo));
-        }
-        if(mediaType.equals(MediaType.APPLICATION_XML_TYPE)) {
-            return config.query(ConfigurationFunctions.xmlInfo(requestInfo));
-        }
-        if(mediaType.equals(MediaType.TEXT_HTML_TYPE)) {
-            return config.query(ConfigurationFunctions.htmlInfo(requestInfo));
-        }
-        if(mediaType.equals(MediaType.TEXT_PLAIN_TYPE)) {
-            return config.query(ConfigurationFunctions.textInfo(requestInfo));
-        }
-        return null;
-    }
-
-    @Override
-    public String getConfiguration(MediaType mediaType, String scope, String scopeId, HttpServletRequest request) {
-        Map<String,String> requestInfo = new HashMap<>();
-        requestInfo.put("timestamp", String.valueOf(System.currentTimeMillis()));
-        if(scope!=null && scopeId!=null){
-            return getScopedConfiguration(scope, scopeId, request, mediaType, requestInfo);
-        }
-        Configuration config = ConfigurationProvider.getConfiguration();
-        if(mediaType.equals(MediaType.APPLICATION_JSON_TYPE)) {
-            return config.query(ConfigurationFunctions.jsonInfo(requestInfo));
-        }
-        if(mediaType.equals(MediaType.APPLICATION_XML_TYPE)) {
-            return config.query(ConfigurationFunctions.xmlInfo(requestInfo));
-        }
-        if(mediaType.equals(MediaType.TEXT_HTML_TYPE)) {
-            return config.query(ConfigurationFunctions.htmlInfo(requestInfo));
-        }
-        if(mediaType.equals(MediaType.TEXT_PLAIN_TYPE)) {
-            return config.query(ConfigurationFunctions.textInfo(requestInfo));
-        }
-        return null;
-    }
-
-    private String getScopedConfigurationWithPath(String scope, String scopeId, String path, HttpServletRequest request,
-                                                  MediaType mediaType, Map<String,String> requestInfo) {
-        requestInfo.put("scope", scope);
-        requestInfo.put("scopeId", scopeId);
-        Configuration config = ConfigurationProvider.getConfiguration()
-                .with(ScopeManager.getScope(scope, scopeId)).with(ConfigurationFunctions.sectionsRecursive(path.split(",")));
-        if(mediaType.equals(MediaType.APPLICATION_JSON_TYPE)) {
-            return config.query(ConfigurationFunctions.jsonInfo(requestInfo));
-        }
-        if(mediaType.equals(MediaType.APPLICATION_XML_TYPE)) {
-            return config.query(ConfigurationFunctions.xmlInfo(requestInfo));
-        }
-        if(mediaType.equals(MediaType.TEXT_HTML_TYPE)) {
-            return config.query(ConfigurationFunctions.htmlInfo(requestInfo));
-        }
-        if(mediaType.equals(MediaType.TEXT_PLAIN_TYPE)) {
-            return config.query(ConfigurationFunctions.textInfo(requestInfo));
-        }
-        return null;
-    }
-
-    private String getScopedConfiguration(String scope, String scopeId, HttpServletRequest request, MediaType mediaType,
-                                          Map<String,String> requestInfo) {
-        requestInfo.put("scope", scope);
-        requestInfo.put("scopeId", scopeId);
-        Configuration config = ConfigurationProvider.getConfiguration().with(ScopeManager.getScope(scope, scopeId));
-        if(mediaType.equals(MediaType.APPLICATION_JSON_TYPE)) {
-            return config.query(ConfigurationFunctions.jsonInfo(requestInfo));
-        }
-        if(mediaType.equals(MediaType.APPLICATION_XML_TYPE)) {
-            return config.query(ConfigurationFunctions.xmlInfo(requestInfo));
-        }
-        if(mediaType.equals(MediaType.TEXT_HTML_TYPE)) {
-            return config.query(ConfigurationFunctions.htmlInfo(requestInfo));
-        }
-        if(mediaType.equals(MediaType.TEXT_PLAIN_TYPE)) {
-            return config.query(ConfigurationFunctions.textInfo(requestInfo));
-        }
-        return null;
-    }
-
-    @Override
-    public void updateConfiguration(String payload, HttpServletRequest request) {
-        throw new UnsupportedOperationException("UPDATE Configuration: Not implemented");
-    }
-
-    @Override
-    public void deleteConfiguration(String paths, HttpServletRequest request) {
-        throw new UnsupportedOperationException("DELETE Configuration: Not implemented");
-    }
-}

http://git-wip-us.apache.org/repos/asf/incubator-tamaya/blob/d778cb81/modules/server/src/main/java/org/apache/tamaya/server/internal/MediaTypeUtil.java
----------------------------------------------------------------------
diff --git a/modules/server/src/main/java/org/apache/tamaya/server/internal/MediaTypeUtil.java b/modules/server/src/main/java/org/apache/tamaya/server/internal/MediaTypeUtil.java
deleted file mode 100644
index 3c5a31c..0000000
--- a/modules/server/src/main/java/org/apache/tamaya/server/internal/MediaTypeUtil.java
+++ /dev/null
@@ -1,58 +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.server.internal;
-
-import javax.ws.rs.core.MediaType;
-
-/**
- * Simple utility class.
- */
-public final class MediaTypeUtil {
-    /** Singleton constructor. */
-    private MediaTypeUtil(){}
-
-    /**
-     * Compares the given MIME type String and tries to evaluate the MIME type matching best.
-     * Currently it select one of application/xml, application/json, text/plain and text/html.
-     * if none is matching application/json is returned by default.
-     * @param formats the formats to check.
-     * @return the selected MediaType
-     */
-    public static MediaType getMediaType(String... formats) {
-        for(String format:formats) {
-            if (format.equalsIgnoreCase(MediaType.APPLICATION_XML)) {
-                return MediaType.APPLICATION_XML_TYPE;
-            } else if (format.equalsIgnoreCase(MediaType.APPLICATION_JSON)) {
-                return MediaType.APPLICATION_JSON_TYPE;
-            } else if (format.equalsIgnoreCase(MediaType.TEXT_HTML)) {
-                return MediaType.TEXT_HTML_TYPE;
-            } else if (format.equalsIgnoreCase(MediaType.TEXT_PLAIN)) {
-                return MediaType.TEXT_PLAIN_TYPE;
-            }
-        }
-        for(String format:formats) {
-            if (format.contains(MediaType.APPLICATION_XML)) {
-                return MediaType.APPLICATION_XML_TYPE;
-            } else if (format.contains(MediaType.APPLICATION_JSON)) {
-                return MediaType.APPLICATION_JSON_TYPE;
-            }
-        }
-        return MediaType.APPLICATION_JSON_TYPE;
-    }
-}

http://git-wip-us.apache.org/repos/asf/incubator-tamaya/blob/d778cb81/modules/server/src/main/java/org/apache/tamaya/server/internal/RestConfigAdminService.java
----------------------------------------------------------------------
diff --git a/modules/server/src/main/java/org/apache/tamaya/server/internal/RestConfigAdminService.java b/modules/server/src/main/java/org/apache/tamaya/server/internal/RestConfigAdminService.java
deleted file mode 100644
index e7f9090..0000000
--- a/modules/server/src/main/java/org/apache/tamaya/server/internal/RestConfigAdminService.java
+++ /dev/null
@@ -1,133 +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.server.internal;
-
-import org.apache.tamaya.ConfigurationProvider;
-import org.apache.tamaya.server.spi.ConfigAdminService;
-import org.apache.tamaya.spi.PropertyConverter;
-import org.apache.tamaya.spi.PropertyFilter;
-import org.apache.tamaya.spi.PropertySource;
-import org.apache.tamaya.spi.ServiceContextManager;
-
-import javax.servlet.http.HttpServletRequest;
-import javax.ws.rs.GET;
-import javax.ws.rs.Path;
-import javax.ws.rs.Produces;
-import javax.ws.rs.core.Context;
-import javax.ws.rs.core.HttpHeaders;
-import javax.ws.rs.core.MediaType;
-import javax.ws.rs.core.Response;
-import java.util.List;
-
-
-/**
- * Implementation of the JAX-RS interface for serving configuration.
- */
-public class RestConfigAdminService {
-
-    private final ConfigAdminService adminService = ServiceContextManager.getServiceContext()
-            .getService(ConfigAdminService.class);
-
-    @GET
-    @Path("/config/admin/source")
-    @Produces({MediaType.APPLICATION_XML, MediaType.APPLICATION_JSON, MediaType.WILDCARD})
-    public String getPropertySource(@Context HttpServletRequest request){
-        MediaType mediaType = MediaTypeUtil.getMediaType(request.getParameter("format"), request.getHeader(HttpHeaders.ACCEPT));
-        String sourceId = request.getParameter("name");
-        String sourceClass = request.getParameter("class");
-        List<PropertySource> propertySources = adminService.collectPropertySources(sourceId, sourceClass);
-        try {
-            String response = adminService.formatPropertySource(mediaType, sourceId, sourceClass, request);
-            if(response!=null){
-                Response.status(Response.Status.OK).header(HttpHeaders.CONTENT_ENCODING, "utf-8").type(mediaType);
-                return response;
-            }
-            Response.status(Response.Status.BAD_REQUEST).header(HttpHeaders.CONTENT_ENCODING, "utf-8");
-            return propertySources.toString();
-        } catch(Exception e){
-            Response.status(Response.Status.INTERNAL_SERVER_ERROR);
-            return null;
-        }
-    }
-
-    @GET
-    @Path("/config/admin/filter")
-    @Produces({MediaType.APPLICATION_XML, MediaType.APPLICATION_JSON, MediaType.WILDCARD})
-    public String getPropertyFilter(@Context HttpServletRequest request){
-        MediaType mediaType = MediaTypeUtil.getMediaType(request.getParameter("format"), request.getHeader(HttpHeaders.ACCEPT));
-        String filterClass = request.getParameter("class");
-        List<PropertyFilter> propertyFilter = adminService.collectPropertyFilters(filterClass);
-        try {
-            String response = adminService.formatPropertyFilter(mediaType, filterClass, request);
-            if(response!=null){
-                Response.status(Response.Status.OK).header(HttpHeaders.CONTENT_ENCODING, "utf-8").type(mediaType);
-                return response;
-            }
-            Response.status(Response.Status.BAD_REQUEST).header(HttpHeaders.CONTENT_ENCODING, "utf-8");
-            return propertyFilter.toString();
-        } catch(Exception e){
-            Response.status(Response.Status.INTERNAL_SERVER_ERROR);
-            return null;
-        }
-    }
-
-    @GET
-    @Path("/config/admin/converter")
-    @Produces({MediaType.APPLICATION_XML, MediaType.APPLICATION_JSON, MediaType.WILDCARD})
-    public String getPropertyConverter(@Context HttpServletRequest request){
-        MediaType mediaType = MediaTypeUtil.getMediaType(request.getParameter("format"), request.getHeader(HttpHeaders.ACCEPT));
-        String converterClass = request.getParameter("class");
-        String targetType = request.getParameter("target");
-        List<PropertyConverter> propertyConverter = adminService.collectPropertyConverters(converterClass, targetType);
-        try {
-            String response = adminService.formatPropertyConverter(mediaType, propertyConverter, request);
-            if(response!=null){
-                Response.status(Response.Status.OK).header(HttpHeaders.CONTENT_ENCODING, "utf-8").type(mediaType);
-                return response;
-            }
-            Response.status(Response.Status.BAD_REQUEST).header(HttpHeaders.CONTENT_ENCODING, "utf-8");
-            return propertyConverter.toString();
-        } catch(Exception e){
-            Response.status(Response.Status.INTERNAL_SERVER_ERROR);
-            return null;
-        }
-    }
-
-
-    @GET
-    @Path("/config/admin/combination")
-    @Produces({MediaType.APPLICATION_XML, MediaType.APPLICATION_JSON, MediaType.WILDCARD})
-    public String getCombinationPolicy(@Context HttpServletRequest request){
-        MediaType mediaType = MediaTypeUtil.getMediaType(request.getParameter("format"), request.getHeader(HttpHeaders.ACCEPT));
-        try {
-            String response = adminService.formatCombinationPolicy(mediaType, ConfigurationProvider.getConfigurationContext().getPropertyValueCombinationPolicy(), request);
-            if(response!=null){
-                Response.status(Response.Status.OK).header(HttpHeaders.CONTENT_ENCODING, "utf-8").type(mediaType);
-                return response;
-            }
-            Response.status(Response.Status.BAD_REQUEST).header(HttpHeaders.CONTENT_ENCODING, "utf-8");
-            return null;
-        } catch(Exception e){
-            Response.status(Response.Status.INTERNAL_SERVER_ERROR);
-            return null;
-        }
-    }
-
-
-}

http://git-wip-us.apache.org/repos/asf/incubator-tamaya/blob/d778cb81/modules/server/src/main/java/org/apache/tamaya/server/internal/RestConfigService.java
----------------------------------------------------------------------
diff --git a/modules/server/src/main/java/org/apache/tamaya/server/internal/RestConfigService.java b/modules/server/src/main/java/org/apache/tamaya/server/internal/RestConfigService.java
deleted file mode 100644
index 6e16c61..0000000
--- a/modules/server/src/main/java/org/apache/tamaya/server/internal/RestConfigService.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.server.internal;
-
-import org.apache.tamaya.server.spi.ConfigService;
-import org.apache.tamaya.spi.ServiceContextManager;
-
-import javax.servlet.http.HttpServletRequest;
-import javax.ws.rs.DELETE;
-import javax.ws.rs.GET;
-import javax.ws.rs.PUT;
-import javax.ws.rs.Path;
-import javax.ws.rs.PathParam;
-import javax.ws.rs.Produces;
-import javax.ws.rs.core.Context;
-import javax.ws.rs.core.HttpHeaders;
-import javax.ws.rs.core.MediaType;
-import javax.ws.rs.core.Response;
-
-
-/**
- * Implementation of the JAX-RS interface for serving configuration.
- */
-public class RestConfigService {
-
-    private final ConfigService configService = ServiceContextManager.getServiceContext()
-            .getService(ConfigService.class);
-
-    @GET
-    @Path("/config/filtered/{path}")
-    @Produces({MediaType.APPLICATION_XML, MediaType.APPLICATION_JSON, MediaType.TEXT_HTML, MediaType.TEXT_PLAIN, MediaType.WILDCARD})
-    public String getConfigurationWithPath(@PathParam("path") String path,
-                                    @Context HttpServletRequest request){
-        MediaType mediaType = MediaTypeUtil.getMediaType(request.getParameter("format"), request.getHeader(HttpHeaders.ACCEPT));
-        String scope = request.getParameter("scope");
-        String scopeId = request.getParameter("scopeId");
-        try {
-            String response = configService.getConfigurationWithPath(path, mediaType, scope, scopeId, request);
-            if(response!=null){
-                Response.status(Response.Status.OK).header(HttpHeaders.CONTENT_ENCODING, "utf-8").type(mediaType);
-            }else {
-                Response.status(Response.Status.BAD_REQUEST);
-            }
-            return response;
-        } catch(Exception e){
-            Response.status(Response.Status.INTERNAL_SERVER_ERROR);
-            return null;
-        }
-    }
-
-
-
-    @GET
-    @Path("/config")
-    @Produces({MediaType.APPLICATION_XML, MediaType.APPLICATION_JSON, MediaType.TEXT_HTML, MediaType.TEXT_PLAIN, MediaType.WILDCARD})
-    public String getConfiguration(@Context HttpServletRequest request) {
-        MediaType mediaType = MediaTypeUtil.getMediaType(request.getParameter("format"), request.getHeader(HttpHeaders.ACCEPT));
-        String scope = request.getParameter("scope");
-        String scopeId = request.getParameter("scopeId");
-        try {
-            String response = configService.getConfiguration(mediaType, scope, scopeId, request);
-            if(response!=null){
-                Response.status(Response.Status.OK).header(HttpHeaders.CONTENT_ENCODING, "utf-8").type(mediaType);
-            }else {
-                Response.status(Response.Status.BAD_REQUEST);
-            }
-            return response;
-        } catch(Exception e){
-            Response.status(Response.Status.INTERNAL_SERVER_ERROR);
-            return null;
-        }
-    }
-
-    @Path("/config/update")
-    @PUT
-    public String updateConfiguration(String payload, @Context HttpServletRequest request) {
-        Response.status(Response.Status.INTERNAL_SERVER_ERROR);
-        return "UPDATE Configuration: Not implemented";
-    }
-
-    @Path("/config/delete")
-    @DELETE
-    public String deleteConfiguration(String paths, @Context HttpServletRequest request) {
-        Response.status(Response.Status.INTERNAL_SERVER_ERROR);
-        return "DELETE Configuration: Not implemented";
-    }
-}

http://git-wip-us.apache.org/repos/asf/incubator-tamaya/blob/d778cb81/modules/server/src/main/java/org/apache/tamaya/server/internal/SimpleServer.java
----------------------------------------------------------------------
diff --git a/modules/server/src/main/java/org/apache/tamaya/server/internal/SimpleServer.java b/modules/server/src/main/java/org/apache/tamaya/server/internal/SimpleServer.java
deleted file mode 100644
index ee37118..0000000
--- a/modules/server/src/main/java/org/apache/tamaya/server/internal/SimpleServer.java
+++ /dev/null
@@ -1,81 +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.server.internal;
-
-
-import org.apache.cxf.jaxrs.JAXRSServerFactoryBean;
-import org.apache.tamaya.server.Server;
-
-/**
- * CXF based implementation of a JAX-RS server, serving the {@link DefaultConfigService} service.
- */
-public class SimpleServer implements Server {
-    /** The CXF endpoint. */
-    private org.apache.cxf.endpoint.Server cxfEndpoint;
-
-    /**
-     * Starts the CXF server under the port.
-     * @param port the port.
-     */
-    public void start(int port) {
-        if(cxfEndpoint!=null){
-            if(cxfEndpoint.isStarted()){
-                return;
-            }
-            // start it at the end...
-        } else {
-            JAXRSServerFactoryBean sf = new JAXRSServerFactoryBean();
-            sf.setServiceBeanObjects(new RestConfigService());
-            sf.setAddress("http://localhost:" + port + "/");
-            cxfEndpoint = sf.create();
-        }
-        cxfEndpoint.start();
-    }
-
-    /**
-     * Returns the current started state.
-     * @return true, if the server is started.
-     */
-    public boolean isStarted(){
-        if(cxfEndpoint!=null){
-            return cxfEndpoint.isStarted();
-        }
-        return false;
-    }
-
-    /**
-     * Stops the server if running.
-     */
-    public void stop(){
-        if(cxfEndpoint!=null){
-            cxfEndpoint.stop();
-        }
-    }
-
-    /**
-     * Destroy the server.
-     */
-    public void destroy(){
-        if(cxfEndpoint!=null){
-            cxfEndpoint.destroy();
-            cxfEndpoint = null;
-        }
-    }
-
-}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/incubator-tamaya/blob/d778cb81/modules/server/src/main/java/org/apache/tamaya/server/spi/ConfigAdminService.java
----------------------------------------------------------------------
diff --git a/modules/server/src/main/java/org/apache/tamaya/server/spi/ConfigAdminService.java b/modules/server/src/main/java/org/apache/tamaya/server/spi/ConfigAdminService.java
deleted file mode 100644
index 97a67a0..0000000
--- a/modules/server/src/main/java/org/apache/tamaya/server/spi/ConfigAdminService.java
+++ /dev/null
@@ -1,48 +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.server.spi;
-
-import org.apache.tamaya.spi.PropertyConverter;
-import org.apache.tamaya.spi.PropertyFilter;
-import org.apache.tamaya.spi.PropertySource;
-import org.apache.tamaya.spi.PropertyValueCombinationPolicy;
-
-import javax.servlet.http.HttpServletRequest;
-import javax.ws.rs.core.MediaType;
-import java.util.List;
-
-/**
- * Configuration backend used by the Tamaya server module.
- */
-public interface ConfigAdminService {
-
-    String formatCombinationPolicy(MediaType mediaType, PropertyValueCombinationPolicy propertyValueCombinationPolicy, HttpServletRequest request);
-
-    String formatPropertyConverter(MediaType mediaType, List<PropertyConverter> propertyConverter, HttpServletRequest request);
-
-    String formatPropertyFilter(MediaType mediaType, String filterClass, HttpServletRequest request);
-
-    String formatPropertySource(MediaType mediaType, String sourceId, String sourceClass, HttpServletRequest request);
-
-    List<PropertyConverter> collectPropertyConverters(String converterClass, String targetType);
-
-    List<PropertyFilter> collectPropertyFilters(String filterClass);
-
-    List<PropertySource> collectPropertySources(String sourceId, String sourceClass);
-}

http://git-wip-us.apache.org/repos/asf/incubator-tamaya/blob/d778cb81/modules/server/src/main/java/org/apache/tamaya/server/spi/ConfigService.java
----------------------------------------------------------------------
diff --git a/modules/server/src/main/java/org/apache/tamaya/server/spi/ConfigService.java b/modules/server/src/main/java/org/apache/tamaya/server/spi/ConfigService.java
deleted file mode 100644
index 1c6e76d..0000000
--- a/modules/server/src/main/java/org/apache/tamaya/server/spi/ConfigService.java
+++ /dev/null
@@ -1,64 +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.server.spi;
-
-import javax.servlet.http.HttpServletRequest;
-import javax.ws.rs.core.MediaType;
-
-/**
- * Configuration backend used by the Tamaya server module.
- */
-public interface ConfigService {
-
-    /**
-     * Accessor to get a filtered configuration representation.
-     * @param path the comma separated paths to be filtered, e.g. {@code java,sub}.
-     * @param format the MIME type required, or the client's ACCEPT header field contents.
-     * @param scope the target scope, or null.
-     * @param scopeId the target scopeId, or null.
-     * @param request the current HTTP request.
-     * @return the output String to be returned to the caller.
-     */
-    String getConfigurationWithPath(String path, MediaType format, String scope, String scopeId, HttpServletRequest request);
-
-    /**
-     * Accessor to get a unfiltered configuration representation.
-     * @param format the MIME type required, or the client's ACCEPT header field contents.
-     * @param scope the target scope, or null.
-     * @param scopeId the target scopeId, or null.
-     * @param request the current HTTP request.
-     * @return the output String to be returned to the caller.
-     */
-    String getConfiguration(MediaType format, String scope, String scopeId, HttpServletRequest request);
-
-    /**
-     * Update the current configuration.
-     * @param payload the payload containing the config entries to be updated.
-     * @param request the current HTTP request.
-     */
-    void updateConfiguration(String payload, HttpServletRequest request);
-
-    /**
-     * Deletes the current configuration.
-     * @param paths the (multiple) comma seperated keys, or paths to be deleted. Paths can be fully qualified keys
-     *              or regular expressions identifying the keys to be removed, e.g. {@code DEL /config/a.b.*,a.c}.
-     * @param request the current HTTP request.
-     */
-    void deleteConfiguration(String paths, HttpServletRequest request);
-}

http://git-wip-us.apache.org/repos/asf/incubator-tamaya/blob/d778cb81/modules/server/src/main/resources/META-INF/services/org.apache.tamaya.server.Server
----------------------------------------------------------------------
diff --git a/modules/server/src/main/resources/META-INF/services/org.apache.tamaya.server.Server b/modules/server/src/main/resources/META-INF/services/org.apache.tamaya.server.Server
deleted file mode 100644
index c1f546a..0000000
--- a/modules/server/src/main/resources/META-INF/services/org.apache.tamaya.server.Server
+++ /dev/null
@@ -1,19 +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 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.server.internal.SimpleServer
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/incubator-tamaya/blob/d778cb81/modules/server/src/main/resources/META-INF/services/org.apache.tamaya.server.spi.ConfigAdminService
----------------------------------------------------------------------
diff --git a/modules/server/src/main/resources/META-INF/services/org.apache.tamaya.server.spi.ConfigAdminService b/modules/server/src/main/resources/META-INF/services/org.apache.tamaya.server.spi.ConfigAdminService
deleted file mode 100644
index b9b735a..0000000
--- a/modules/server/src/main/resources/META-INF/services/org.apache.tamaya.server.spi.ConfigAdminService
+++ /dev/null
@@ -1,19 +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 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.server.internal.DefaultConfigAdminService
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/incubator-tamaya/blob/d778cb81/modules/server/src/main/resources/META-INF/services/org.apache.tamaya.server.spi.ConfigService
----------------------------------------------------------------------
diff --git a/modules/server/src/main/resources/META-INF/services/org.apache.tamaya.server.spi.ConfigService b/modules/server/src/main/resources/META-INF/services/org.apache.tamaya.server.spi.ConfigService
deleted file mode 100644
index 0e52e0f..0000000
--- a/modules/server/src/main/resources/META-INF/services/org.apache.tamaya.server.spi.ConfigService
+++ /dev/null
@@ -1,19 +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 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.server.internal.DefaultConfigService
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/incubator-tamaya/blob/d778cb81/modules/server/src/main/resources/banner.txt
----------------------------------------------------------------------
diff --git a/modules/server/src/main/resources/banner.txt b/modules/server/src/main/resources/banner.txt
new file mode 100644
index 0000000..4e2714b
--- /dev/null
+++ b/modules/server/src/main/resources/banner.txt
@@ -0,0 +1,14 @@
+
+ █████╗ ██████╗  █████╗  ██████╗██╗  ██╗███████╗    ████████╗ █████╗ ███╗   ███╗ █████╗ ██╗   ██╗ █████╗
+██╔══██╗██╔══██╗██╔══██╗██╔════╝██║  ██║██╔════╝    ╚══██╔══╝██╔══██╗████╗ ████║██╔══██╗╚██╗ ██╔╝██╔══██╗
+███████║██████╔╝███████║██║     ███████║█████╗         ██║   ███████║██╔████╔██║███████║ ╚████╔╝ ███████║
+██╔══██║██╔═══╝ ██╔══██║██║     ██╔══██║██╔══╝         ██║   ██╔══██║██║╚██╔╝██║██╔══██║  ╚██╔╝  ██╔══██║
+██║  ██║██║     ██║  ██║╚██████╗██║  ██║███████╗       ██║   ██║  ██║██║ ╚═╝ ██║██║  ██║   ██║   ██║  ██║
+╚═╝  ╚═╝╚═╝     ╚═╝  ╚═╝ ╚═════╝╚═╝  ╚═╝╚══════╝       ╚═╝   ╚═╝  ╚═╝╚═╝     ╚═╝╚═╝  ╚═╝   ╚═╝   ╚═╝  ╚═╝
+                            ███████╗███████╗██████╗ ██╗   ██╗███████╗██████╗
+                            ██╔════╝██╔════╝██╔══██╗██║   ██║██╔════╝██╔══██╗
+                            ███████╗█████╗  ██████╔╝██║   ██║█████╗  ██████╔╝
+                            ╚════██║██╔══╝  ██╔══██╗╚██╗ ██╔╝██╔══╝  ██╔══██╗
+                            ███████║███████╗██║  ██║ ╚████╔╝ ███████╗██║  ██║
+                            ╚══════╝╚══════╝╚═╝  ╚═╝  ╚═══╝  ╚══════╝╚═╝  ╚═╝
+

http://git-wip-us.apache.org/repos/asf/incubator-tamaya/blob/d778cb81/modules/server/src/main/resources/config-server.yml
----------------------------------------------------------------------
diff --git a/modules/server/src/main/resources/config-server.yml b/modules/server/src/main/resources/config-server.yml
new file mode 100644
index 0000000..7d3dbe8
--- /dev/null
+++ b/modules/server/src/main/resources/config-server.yml
@@ -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 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.
+#
+
+scope: java
+
+server:
+  applicationConnectors:
+  - type: http
+    port: 4001
+  adminConnectors:
+  - type: http
+    port: 4099
+

http://git-wip-us.apache.org/repos/asf/incubator-tamaya/blob/d778cb81/modules/server/src/test/java/org/apache/tamaya/server/ConfigServiceAppTest.java
----------------------------------------------------------------------
diff --git a/modules/server/src/test/java/org/apache/tamaya/server/ConfigServiceAppTest.java b/modules/server/src/test/java/org/apache/tamaya/server/ConfigServiceAppTest.java
new file mode 100644
index 0000000..5f7163d
--- /dev/null
+++ b/modules/server/src/test/java/org/apache/tamaya/server/ConfigServiceAppTest.java
@@ -0,0 +1,32 @@
+/*
+ * 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.server;
+
+//import static org.junit.Assert.*;
+
+/**
+ * Created by atsticks on 22.01.16.
+ */
+public class ConfigServiceAppTest {
+
+//    @org.junit.Test
+//    public void testMain() throws Exception {
+//
+//    }
+}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/incubator-tamaya/blob/d778cb81/modules/server/src/test/java/org/apache/tamaya/server/EtcdAccessor.java
----------------------------------------------------------------------
diff --git a/modules/server/src/test/java/org/apache/tamaya/server/EtcdAccessor.java b/modules/server/src/test/java/org/apache/tamaya/server/EtcdAccessor.java
new file mode 100644
index 0000000..1c8e94b
--- /dev/null
+++ b/modules/server/src/test/java/org/apache/tamaya/server/EtcdAccessor.java
@@ -0,0 +1,519 @@
+///*
+// * 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.etcd;
+//
+//import org.apache.http.HttpEntity;
+//import org.apache.http.HttpStatus;
+//import org.apache.http.NameValuePair;
+//import org.apache.http.client.config.RequestConfig;
+//import org.apache.http.client.entity.UrlEncodedFormEntity;
+//import org.apache.http.client.methods.CloseableHttpResponse;
+//import org.apache.http.client.methods.HttpDelete;
+//import org.apache.http.client.methods.HttpGet;
+//import org.apache.http.client.methods.HttpPut;
+//import org.apache.http.impl.client.CloseableHttpClient;
+//import org.apache.http.impl.client.HttpClients;
+//import org.apache.http.message.BasicNameValuePair;
+//import org.apache.http.util.EntityUtils;
+//
+//import javax.json.Json;
+//import javax.json.JsonArray;
+//import javax.json.JsonObject;
+//import javax.json.JsonReader;
+//import javax.json.JsonReaderFactory;
+//import java.io.IOException;
+//import java.io.StringReader;
+//import java.util.ArrayList;
+//import java.util.HashMap;
+//import java.util.List;
+//import java.util.Map;
+//import java.util.logging.Level;
+//import java.util.logging.Logger;
+//
+///**
+// * Accessor for reading/writing an etcd endpoint.
+// */
+//public class EtcdAccessor {
+//
+//    private static final Logger LOG = Logger.getLogger(EtcdAccessor.class.getName());
+//
+//    /** Timeout in seconds. */
+//    private int timeout = 2;
+//    /** Property that make Johnzon accept commentc. */
+//    public static final String JOHNZON_SUPPORTS_COMMENTS_PROP = "org.apache.johnzon.supports-comments";
+//    /** The JSON reader factory used. */
+//    private final JsonReaderFactory readerFactory = initReaderFactory();
+//
+//    /** Initializes the factory to be used for creating readers. */
+//    private JsonReaderFactory initReaderFactory() {
+//        Map<String, Object> config = new HashMap<>();
+//        config.put(JOHNZON_SUPPORTS_COMMENTS_PROP, true);
+//        return Json.createReaderFactory(config);
+//    }
+//
+//    /** The base server url. */
+//    private final String serverURL;
+//    /** The http client. */
+//    private CloseableHttpClient httpclient = HttpClients.createDefault();
+//
+//    /**
+//     * Creates a new instance with the basic access url.
+//     * @param server server url, e.g. {@code http://127.0.0.1:4001}, not null.
+//     */
+//    public EtcdAccessor(String server){
+//        this(server, 2);
+//    }
+//
+//    public EtcdAccessor(String server, int timeout) {
+//        this.timeout = timeout;
+//        if(server.endsWith("/")){
+//            serverURL = server.substring(0, server.length()-1);
+//        } else{
+//            serverURL = server;
+//        }
+//
+//    }
+//
+//    /**
+//     * Get the etcd server version.
+//     * @return the etcd server version, never null.
+//     */
+//    public String getVersion(){
+//        CloseableHttpResponse response = null;
+//        String version = "<ERROR>";
+//        try {
+//            CloseableHttpClient httpclient = HttpClients.createDefault();
+//            HttpGet httpGet = new HttpGet(serverURL + "/version");
+//            httpGet.setConfig(RequestConfig.copy(RequestConfig.DEFAULT).setSocketTimeout(timeout)
+//                    .setConnectionRequestTimeout(timeout).setConnectTimeout(timeout).build());
+//            response = httpclient.execute(httpGet);
+//            HttpEntity entity;
+//            if (response.getStatusLine().getStatusCode() == HttpStatus.SC_OK) {
+//                entity = response.getEntity();
+//                // and ensure it is fully consumed
+//                version = EntityUtils.toString(entity);
+//                EntityUtils.consume(entity);
+//            }
+//            return version;
+//        } catch(Exception e){
+//            LOG.log(Level.INFO, "Error getting etcd version from: " + serverURL, e);
+//        } finally {
+//            if(response!=null){
+//                try {
+//                    response.close();
+//                } catch (IOException e) {
+//                    LOG.log(Level.WARNING, "Failed to close http response", e);
+//                }
+//            }
+//        }
+//        return version;
+//    }
+//
+//    /**
+//     * Ask etcd for s aingle key, value pair. Hereby the response returned from etcd:
+//     * <pre>
+//     * {
+//         "action": "get",
+//         "node": {
+//         "createdIndex": 2,
+//         "key": "/message",
+//         "modifiedIndex": 2,
+//         "value": "Hello world"
+//         }
+//     * }
+//     * </pre>
+//     * is mapped to:
+//     * <pre>
+//     *     key=value
+//     *     _key.source=[etcd]http://127.0.0.1:4001
+//     *     _key.createdIndex=12
+//     *     _key.modifiedIndex=34
+//     *     _key.ttl=300
+//     *     _key.expiration=...
+//     * </pre>
+//     * @param key the requested key
+//     * @return the mapped result, including meta-entries.
+//     */
+//    public Map<String,String> get(String key){
+//        CloseableHttpResponse response = null;
+//        Map<String,String> result = new HashMap<>();
+//        try {
+//            HttpGet httpGet = new HttpGet(serverURL + "/v2/keys/"+key);
+//            httpGet.setConfig(RequestConfig.copy(RequestConfig.DEFAULT).setSocketTimeout(timeout)
+//                    .setConnectionRequestTimeout(timeout).setConnectTimeout(timeout).build());
+//            response = httpclient.execute(httpGet);
+//            if (response.getStatusLine().getStatusCode() == HttpStatus.SC_OK) {
+//                HttpEntity entity = response.getEntity();
+//                JsonReader reader = readerFactory.createReader(new StringReader(EntityUtils.toString(entity)));
+//                JsonObject o = reader.readObject();
+//                JsonObject node = o.getJsonObject("node");
+//                result.put(key, node.getString("value"));
+//                result.put("_" + key +".source", "[etcd]"+serverURL);
+//                if(node.containsKey("createdIndex")) {
+//                    result.put("_" + key +".createdIndex", String.valueOf(node.getInt("createdIndex")));
+//                }
+//                if(node.containsKey("modifiedIndex")) {
+//                    result.put("_" + key +".modifiedIndex", String.valueOf(node.getInt("modifiedIndex")));
+//                }
+//                if(node.containsKey("expiration")) {
+//                    result.put("_" + key +".expiration", String.valueOf(node.getString("expiration")));
+//                }
+//                if(node.containsKey("ttl")) {
+//                    result.put("_" + key +".ttl", String.valueOf(node.getInt("ttl")));
+//                }
+//                EntityUtils.consume(entity);
+//            }else{
+//                result.put("_" + key +".NOT_FOUND.target", "[etcd]"+serverURL);
+//            }
+//        } catch(Exception e){
+//            LOG.log(Level.INFO, "Error reading key '"+key+"' from etcd: " + serverURL, e);
+//            result.put("_ERROR", "Error reading key '"+key+"' from etcd: " + serverURL + ": " + e.toString());
+//        } finally {
+//            if(response!=null){
+//                try {
+//                    response.close();
+//                } catch (IOException e) {
+//                    LOG.log(Level.WARNING, "Failed to close http response", e);
+//                }
+//            }
+//        }
+//        return result;
+//    }
+//
+//    /**
+//     * Creates/updates an entry in etcd without any ttl set.
+//     * @see #set(String, String, Integer)
+//     * @param key the property key, not null
+//     * @param value the value to be set
+//     * @return the result map as described above.
+//     */
+//    public Map<String,String> set(String key, String value){
+//        return set(key, value, null);
+//    }
+//
+//    /**
+//     * Creates/updates an entry in etcd. The response as follows:
+//     * <pre>
+//     *     {
+//     "action": "set",
+//     "node": {
+//     "createdIndex": 3,
+//     "key": "/message",
+//     "modifiedIndex": 3,
+//     "value": "Hello etcd"
+//     },
+//     "prevNode": {
+//     "createdIndex": 2,
+//     "key": "/message",
+//     "value": "Hello world",
+//     "modifiedIndex": 2
+//     }
+//     }
+//     * </pre>
+//     * is mapped to:
+//     * <pre>
+//     *     key=value
+//     *     _key.source=[etcd]http://127.0.0.1:4001
+//     *     _key.createdIndex=12
+//     *     _key.modifiedIndex=34
+//     *     _key.ttl=300
+//     *     _key.expiry=...
+//     *      // optional
+//     *     _key.prevNode.createdIndex=12
+//     *     _key.prevNode.modifiedIndex=34
+//     *     _key.prevNode.ttl=300
+//     *     _key.prevNode.expiration=...
+//     * </pre>
+//     * @param key the property key, not null
+//     * @param value the value to be set
+//     * @param ttlSeconds the ttl in seconds (optional)
+//     * @return the result map as described above.
+//     */
+//    public Map<String,String> set(String key, String value, Integer ttlSeconds){
+//        CloseableHttpResponse response = null;
+//        Map<String,String> result = new HashMap<>();
+//        try{
+//            HttpPut put = new HttpPut(serverURL + "/v2/keys/"+key);
+//            put.setConfig(RequestConfig.copy(RequestConfig.DEFAULT).setSocketTimeout(timeout)
+//                    .setConnectionRequestTimeout(timeout).setConnectTimeout(timeout).build());
+//            List<NameValuePair> nvps = new ArrayList<>();
+//            nvps.add(new BasicNameValuePair("value", value));
+//            if(ttlSeconds!=null){
+//                nvps.add(new BasicNameValuePair("ttl", ttlSeconds.toString()));
+//            }
+//            put.setEntity(new UrlEncodedFormEntity(nvps));
+//            response = httpclient.execute(put);
+//            if (response.getStatusLine().getStatusCode() == HttpStatus.SC_CREATED ||
+//                    response.getStatusLine().getStatusCode() == HttpStatus.SC_OK) {
+//                HttpEntity entity = response.getEntity();
+//                JsonReader reader = readerFactory.createReader(new StringReader(EntityUtils.toString(entity)));
+//                JsonObject o = reader.readObject();
+//                JsonObject node = o.getJsonObject("node");
+//                if(node.containsKey("createdIndex")) {
+//                    result.put("_" + key +".createdIndex", String.valueOf(node.getInt("createdIndex")));
+//                }
+//                if(node.containsKey("modifiedIndex")) {
+//                    result.put("_" + key +".modifiedIndex", String.valueOf(node.getInt("modifiedIndex")));
+//                }
+//                if(node.containsKey("expiration")) {
+//                    result.put("_" + key +".expiration", String.valueOf(node.getString("expiration")));
+//                }
+//                if(node.containsKey("ttl")) {
+//                    result.put("_" + key +".ttl", String.valueOf(node.getInt("ttl")));
+//                }
+//                result.put(key, node.getString("value"));
+//                result.put("_" + key +".source", "[etcd]"+serverURL);
+//                if(node.containsKey("prevNode")){
+//                    JsonObject prevNode = node.getJsonObject("prevNode");
+//                    if (prevNode.containsKey("createdIndex")) {
+//                        result.put("_" + key +".prevNode.createdIndex", String.valueOf(prevNode.getInt("createdIndex")));
+//                    }
+//                    if (prevNode.containsKey("modifiedIndex")) {
+//                        result.put("_" + key +".prevNode.modifiedIndex", String.valueOf(prevNode.getInt("modifiedIndex")));
+//                    }
+//                    if(prevNode.containsKey("expiration")) {
+//                        result.put("_" + key +".prevNode.expiration", String.valueOf(prevNode.getString("expiration")));
+//                    }
+//                    if(prevNode.containsKey("ttl")) {
+//                        result.put("_" + key +".prevNode.ttl", String.valueOf(prevNode.getInt("ttl")));
+//                    }
+//                    result.put("_" + key +".prevNode.value", prevNode.getString("value"));
+//                }
+//                EntityUtils.consume(entity);
+//            }
+//        } catch(Exception e){
+//            LOG.log(Level.INFO, "Error writing to etcd: " + serverURL, e);
+//            result.put("_ERROR", "Error writing '"+key+"' to etcd: " + serverURL + ": " + e.toString());
+//        } finally {
+//            if(response!=null){
+//                try {
+//                    response.close();
+//                } catch (IOException e) {
+//                    LOG.log(Level.WARNING, "Failed to close http response", e);
+//                }
+//            }
+//        }
+//        return result;
+//    }
+//
+//
+//    /**
+//     * Deletes a given key. The response is as follows:
+//     * <pre>
+//     *     _key.source=[etcd]http://127.0.0.1:4001
+//     *     _key.createdIndex=12
+//     *     _key.modifiedIndex=34
+//     *     _key.ttl=300
+//     *     _key.expiry=...
+//     *      // optional
+//     *     _key.prevNode.createdIndex=12
+//     *     _key.prevNode.modifiedIndex=34
+//     *     _key.prevNode.ttl=300
+//     *     _key.prevNode.expiration=...
+//     *     _key.prevNode.value=...
+//     * </pre>
+//     * @param key the key to be deleted.
+//     * @return the response mpas as described above.
+//     */
+//    public Map<String,String> delete(String key){
+//        CloseableHttpResponse response = null;
+//        Map<String,String> result = new HashMap<>();
+//        try{
+//            HttpDelete delete = new HttpDelete(serverURL + "/v2/keys/"+key);
+//            delete.setConfig(RequestConfig.copy(RequestConfig.DEFAULT).setSocketTimeout(timeout)
+//                    .setConnectionRequestTimeout(timeout).setConnectTimeout(timeout).build());
+//            response = httpclient.execute(delete);
+//            if (response.getStatusLine().getStatusCode() == HttpStatus.SC_OK) {
+//                HttpEntity entity = response.getEntity();
+//                JsonReader reader = readerFactory.createReader(new StringReader(EntityUtils.toString(entity)));
+//                JsonObject o = reader.readObject();
+//                JsonObject node = o.getJsonObject("node");
+//                if(node.containsKey("createdIndex")) {
+//                    result.put("_" + key +".createdIndex", String.valueOf(node.getInt("createdIndex")));
+//                }
+//                if(node.containsKey("modifiedIndex")) {
+//                    result.put("_" + key +".modifiedIndex", String.valueOf(node.getInt("modifiedIndex")));
+//                }
+//                if(node.containsKey("expiration")) {
+//                    result.put("_" + key +".expiration", String.valueOf(node.getString("expiration")));
+//                }
+//                if(node.containsKey("ttl")) {
+//                    result.put("_" + key +".ttl", String.valueOf(node.getInt("ttl")));
+//                }
+//                if(o.containsKey("prevNode")){
+//                    JsonObject prevNode = o.getJsonObject("prevNode");
+//                    if (prevNode.containsKey("createdIndex")) {
+//                        result.put("_" + key +".prevNode.createdIndex", String.valueOf(prevNode.getInt("createdIndex")));
+//                    }
+//                    if (prevNode.containsKey("modifiedIndex")) {
+//                        result.put("_" + key +".prevNode.modifiedIndex", String.valueOf(prevNode.getInt("modifiedIndex")));
+//                    }
+//                    if(prevNode.containsKey("expiration")) {
+//                        result.put("_" + key +".prevNode.expiration", String.valueOf(prevNode.getString("expiration")));
+//                    }
+//                    if(prevNode.containsKey("ttl")) {
+//                        result.put("_" + key +".prevNode.ttl", String.valueOf(prevNode.getInt("ttl")));
+//                    }
+//                    result.put("_" + key +".prevNode.value", prevNode.getString("value"));
+//                }
+//                EntityUtils.consume(entity);
+//            }
+//        } catch(Exception e){
+//            LOG.log(Level.INFO, "Error deleting key '"+key+"' from etcd: " + serverURL, e);
+//            result.put("_ERROR", "Error deleting '"+key+"' from etcd: " + serverURL + ": " + e.toString());
+//        } finally {
+//            if(response!=null){
+//                try {
+//                    response.close();
+//                } catch (IOException e) {
+//                    LOG.log(Level.WARNING, "Failed to close http response", e);
+//                }
+//            }
+//        }
+//        return result;
+//    }
+//
+//    /**
+//     * Get all properties for the given directory key recursively.
+//     * @see #getProperties(String, boolean)
+//     * @param directory the directory entry
+//     * @return the properties and its metadata
+//     */
+//    public Map<String,String> getProperties(String directory){
+//        return getProperties(directory, true);
+//    }
+//
+//    /**
+//     * Access all properties.
+//     * The response of:
+//     * <pre>
+//    {
+//    "action": "get",
+//    "node": {
+//        "key": "/",
+//        "dir": true,
+//        "nodes": [
+//            {
+//                "key": "/foo_dir",
+//                "dir": true,
+//                "modifiedIndex": 2,
+//                "createdIndex": 2
+//            },
+//            {
+//                "key": "/foo",
+//                "value": "two",
+//                "modifiedIndex": 1,
+//                "createdIndex": 1
+//            }
+//        ]
+//    }
+//}
+//     </pre>
+//     is mapped to a regular Tamaya properties map as follows:
+//     <pre>
+//     *    key1=myvalue
+//     *     _key1.source=[etcd]http://127.0.0.1:4001
+//     *     _key1.createdIndex=12
+//     *     _key1.modifiedIndex=34
+//     *     _key1.ttl=300
+//     *     _key1.expiration=...
+//     *
+//     *      key2=myvaluexxx
+//     *     _key2.source=[etcd]http://127.0.0.1:4001
+//     *     _key2.createdIndex=12
+//     *
+//     *      key3=val3
+//     *     _key3.source=[etcd]http://127.0.0.1:4001
+//     *     _key3.createdIndex=12
+//     *     _key3.modifiedIndex=2
+//     * </pre>
+//     */
+//    public Map<String,String> getProperties(String directory, boolean recursive){
+//        CloseableHttpResponse response = null;
+//        Map<String,String> result = new HashMap<>();
+//        try{
+//            HttpGet get = new HttpGet(serverURL + "/v2/keys/"+directory+"?recursive="+recursive);
+//            get.setConfig(RequestConfig.copy(RequestConfig.DEFAULT).setSocketTimeout(timeout)
+//                    .setConnectionRequestTimeout(timeout).setConnectTimeout(timeout).build());
+//            response = httpclient.execute(get);
+//            if (response.getStatusLine().getStatusCode() == HttpStatus.SC_OK) {
+//                HttpEntity entity = response.getEntity();
+//                JsonReader reader = readerFactory.createReader(new StringReader(EntityUtils.toString(entity)));
+//                JsonObject o = reader.readObject();
+//                JsonObject node = o.getJsonObject("node");
+//                if(node!=null){
+//                    addNodes(result, node);
+//                }
+//                EntityUtils.consume(entity);
+//            }
+//        } catch(Exception e){
+//            LOG.log(Level.INFO, "Error reading properties for '"+directory+"' from etcd: " + serverURL, e);
+//            result.put("_ERROR", "Error reading properties for '"+directory+"' from etcd: " + serverURL + ": " + e.toString());
+//        } finally {
+//            if(response!=null){
+//                try {
+//                    response.close();
+//                } catch (IOException e) {
+//                    LOG.log(Level.WARNING, "Failed to close http response", e);
+//                }
+//            }
+//        }
+//        return result;
+//    }
+//
+//    /**
+//     * Recursively read out all key/values from this etcd JSON array.
+//     * @param result map with key, values and metadata.
+//     * @param node the node to parse.
+//     */
+//    private void addNodes(Map<String, String> result, JsonObject node) {
+//        if(!node.containsKey("dir") || "false".equals(node.get("dir").toString())) {
+//            String key = node.getString("key").substring(1);
+//            result.put(key, node.getString("value"));
+//            if (node.containsKey("createdIndex")) {
+//                result.put("_" + key + ".createdIndex", String.valueOf(node.getInt("createdIndex")));
+//            }
+//            if (node.containsKey("modifiedIndex")) {
+//                result.put("_" + key + ".modifiedIndex", String.valueOf(node.getInt("modifiedIndex")));
+//            }
+//            if (node.containsKey("expiration")) {
+//                result.put("_" + key + ".expiration", String.valueOf(node.getString("expiration")));
+//            }
+//            if (node.containsKey("ttl")) {
+//                result.put("_" + key + ".ttl", String.valueOf(node.getInt("ttl")));
+//            }
+//            result.put("_" + key +".source", "[etcd]"+serverURL);
+//        } else {
+//            JsonArray nodes = node.getJsonArray("nodes");
+//            if (nodes != null) {
+//                for (int i = 0; i < nodes.size(); i++) {
+//                    addNodes(result, nodes.getJsonObject(i));
+//                }
+//            }
+//        }
+//    }
+//
+//    /**
+//     * Access the server root URL used by this accessor.
+//     * @return
+//     */
+//    public String getUrl() {
+//        return serverURL;
+//    }
+//}

http://git-wip-us.apache.org/repos/asf/incubator-tamaya/blob/d778cb81/modules/spi-support/src/main/java/org/apache/tamaya/spisupport/BasePropertySource.java
----------------------------------------------------------------------
diff --git a/modules/spi-support/src/main/java/org/apache/tamaya/spisupport/BasePropertySource.java b/modules/spi-support/src/main/java/org/apache/tamaya/spisupport/BasePropertySource.java
index 91496ce..2a6b47e 100644
--- a/modules/spi-support/src/main/java/org/apache/tamaya/spisupport/BasePropertySource.java
+++ b/modules/spi-support/src/main/java/org/apache/tamaya/spisupport/BasePropertySource.java
@@ -19,6 +19,7 @@
 package org.apache.tamaya.spisupport;
 
 import org.apache.tamaya.spi.PropertySource;
+import org.apache.tamaya.spi.PropertyValue;
 
 import java.util.logging.Level;
 import java.util.logging.Logger;
@@ -48,10 +49,10 @@ public abstract class BasePropertySource implements PropertySource{
 
     @Override
     public int getOrdinal() {
-        String configuredOrdinal = get(TAMAYA_ORDINAL);
+        PropertyValue configuredOrdinal = get(TAMAYA_ORDINAL);
         if(configuredOrdinal!=null){
             try{
-                return Integer.parseInt(configuredOrdinal);
+                return Integer.parseInt(configuredOrdinal.get(TAMAYA_ORDINAL));
             } catch(Exception e){
                 Logger.getLogger(getClass().getName()).log(Level.WARNING,
                         "Configured Ordinal is not an int number: " + configuredOrdinal, e);
@@ -69,8 +70,8 @@ public abstract class BasePropertySource implements PropertySource{
     }
 
     @Override
-    public String get(String key) {
-        return getProperties().get(key);
+    public PropertyValue get(String key) {
+        return PropertyValue.of(key, getProperties().get(key), getName());
     }
 
     @Override

http://git-wip-us.apache.org/repos/asf/incubator-tamaya/blob/d778cb81/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 a72dc36..fdf5814 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
@@ -27,6 +27,7 @@ import org.apache.tamaya.spi.ConfigurationContext;
 import org.apache.tamaya.spi.ConversionContext;
 import org.apache.tamaya.spi.PropertyConverter;
 import org.apache.tamaya.spi.PropertySource;
+import org.apache.tamaya.spi.PropertyValue;
 import org.apache.tamaya.spi.PropertyValueCombinationPolicy;
 
 import java.util.ArrayList;
@@ -70,7 +71,11 @@ public class DefaultConfiguration implements Configuration {
      */
     @Override
     public String get(String key) {
-        return PropertyFiltering.applyFilter(key, evaluteRawValue(key), configurationContext);
+        PropertyValue configData = evaluteRawValue(key);
+        if(configData==null){
+            return null;
+        }
+        return PropertyFiltering.applyFilter(key, configData.getConfigEntries(), configurationContext);
     }
 
     /**
@@ -78,15 +83,18 @@ public class DefaultConfiguration implements Configuration {
      * @param key the key, not null.
      * @return the value, before filtering is applied.
      */
-    protected String evaluteRawValue(String key) {
+    protected PropertyValue evaluteRawValue(String key) {
         List<PropertySource> propertySources = configurationContext.getPropertySources();
-        String unfilteredValue = null;
+        Map<String,String> unfilteredValue = null;
         PropertyValueCombinationPolicy combinationPolicy = this.configurationContext
                 .getPropertyValueCombinationPolicy();
         for (PropertySource propertySource : propertySources) {
             unfilteredValue = combinationPolicy.collect(unfilteredValue, key, propertySource);
         }
-        return unfilteredValue;
+        if(unfilteredValue==null){
+            return null;
+        }
+        return PropertyValue.of(key, unfilteredValue.get(key), unfilteredValue.get("_"+key+".source"));
     }
 
 

http://git-wip-us.apache.org/repos/asf/incubator-tamaya/blob/d778cb81/modules/spi-support/src/main/java/org/apache/tamaya/spisupport/PropertyFiltering.java
----------------------------------------------------------------------
diff --git a/modules/spi-support/src/main/java/org/apache/tamaya/spisupport/PropertyFiltering.java b/modules/spi-support/src/main/java/org/apache/tamaya/spisupport/PropertyFiltering.java
index 5fa15fe..7d4d9e1 100644
--- a/modules/spi-support/src/main/java/org/apache/tamaya/spisupport/PropertyFiltering.java
+++ b/modules/spi-support/src/main/java/org/apache/tamaya/spisupport/PropertyFiltering.java
@@ -19,6 +19,7 @@
 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;
@@ -47,13 +48,14 @@ public final class PropertyFiltering{
      */
     private PropertyFiltering(){}
 
-    public static String applyFilter(String key, String unfilteredValue, ConfigurationContext configurationContext) {
+    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(key, unfilteredValue);
+                String newValue = filter.filterProperty(unfilteredValue, new FilterContext(key, configData, true));
                 if (newValue != null && !newValue.equals(unfilteredValue)) {
                     changed = true;
                     if (LOG.isLoggable(Level.FINEST)) {
@@ -93,7 +95,7 @@ public final class PropertyFiltering{
                     final String k = entry.getKey();
                     final String v = entry.getValue();
 
-                    String newValue = filter.filterProperty(k, v);
+                    String newValue = filter.filterProperty(k, new FilterContext(k, inputMap, false));
                     if (newValue != null && !newValue.equals(v)) {
                         changes.incrementAndGet();
                         LOG.finest("Filter - " + k + ": " + v + " -> " + newValue + " by " + filter);

http://git-wip-us.apache.org/repos/asf/incubator-tamaya/blob/d778cb81/src/site/asciidoc/extensions/index.adoc
----------------------------------------------------------------------
diff --git a/src/site/asciidoc/extensions/index.adoc b/src/site/asciidoc/extensions/index.adoc
index 113efbf..fa3a02f 100644
--- a/src/site/asciidoc/extensions/index.adoc
+++ b/src/site/asciidoc/extensions/index.adoc
@@ -43,13 +43,12 @@ Mature extensions have a stable API and SPI, similar to the API and Implementati
 |=======
 |_Artifact_                                 |_Description_                                |_Links_
 |                                           | N/A: currently no extensions have reached that maturity level.  | -
-|+org.apache.tamaya.ext:tamaya-resolver+      |Provides placeholder and dynamic resolution functionality for configuration values.  |link:mod_resolver.html[Documentation]
 |+org.apache.tamaya.ext:tamaya-formats+       |Provides an abstract model for configuration formats   |link:mod_formats.html[Documentation]
 |+org.apache.tamaya.ext:tamaya-functions+     |Provides several functional extension points.          |link:mod_functions.html[Documentation]
+|+org.apache.tamaya.ext:tamaya-json+          |Provides format support for JSON based configuration.  |link:mod_json.html[Documentation]
 |+org.apache.tamaya.ext:tamaya-optional+      |Lets a Tamaya configuration to be used as an optional project extension only.  |link:mod_optional.html[Documentation]
+|+org.apache.tamaya.ext:tamaya-resolver+      |Provides placeholder and dynamic resolution functionality for configuration values.  |link:mod_resolver.html[Documentation]
 |+org.apache.tamaya.ext:tamaya-spi-support+   |Tamaya support module for SPI implementation.          |link:mod_spi-support.html[Documentation]
-|+org.apache.tamaya.ext:tamaya-json+          |Provides format support for JSON based configuration.  |link:mod_json.html[Documentation]
-|+org.apache.tamaya.ext:tamaya-mutable-config+|Provides API/SPI for writing configuration             |link:mod_mutable_config.html[Documentation]
 |=======
 
 
@@ -64,14 +63,16 @@ NOTE All extensions currently run on Java 7 as well as on Java 8.
 |=======
 |_Artifact_                                   |_Description_                                          |_Links_
 |+org.apache.tamaya.ext:tamaya-builder+       |Provides a fluent-style builder for configurations     | link:mod_builder.html[Documentation]
-|+org.apache.tamaya.ext:tamaya-resources+     |Provides ant-style resource path resolution  |link:mod_resources.html[Documentation]
+|+org.apache.tamaya.ext:tamaya-classloader-support+  |Manages Tamaya configuration and services considering classloading hierarchies.  |link:mod_classloader_support.html[Documentation]
 |+org.apache.tamaya.ext:tamaya-events+        |Provides support for publishing configuration changes  |link:mod_events.html[Documentation]
+|+org.apache.tamaya.ext:tamaya-filter+        |Provides a programmatic filter for config entries.     | link:mod_filter.html[Documentation]
 |+org.apache.tamaya.ext:tamaya-injection+     |Provides configuration injection services and congiruation template support.  |link:mod_injection.html[Documentation]
-|+org.apache.tamaya.ext:tamaya-model+         |Provides support documenting ang validating configuration during runtime.  |link:mod_model.html[Documentation]
 |+org.apache.tamaya.ext:tamaya-management+    |Provides JMX support for inspecting configuration.     |link:mod_management.html[Documentation]
+|+org.apache.tamaya.ext:tamaya-model+         |Provides support documenting ang validating configuration during runtime.  |link:mod_model.html[Documentation]
+|+org.apache.tamaya.ext:tamaya-mutable-config+|Provides API/SPI for writing configuration             |link:mod_mutable_config.html[Documentation]
 |+org.apache.tamaya.ext:tamaya-remote+        |Provides remote configuration support.                 |link:mod_remote.html[Documentation]
-|+org.apache.tamaya.ext:tamaya-server+        |Lets a Tamaya configuration instance provide scoped configuration as a http service.     |link:mod_server.html[Documentation]
-|+org.apache.tamaya.ext:tamaya-classloader-support+  |Manages Tamaya configuration and services considering classloading hierarchies.  |link:mod_classloader_support.html[Documentation]
+|+org.apache.tamaya.ext:tamaya-resources+     |Provides ant-style resource path resolution  |link:mod_resources.html[Documentation]
+|+org.apache.tamaya.ext:tamaya-server+        |Lets a Tamaya configuration instance provide scoped configuration as a REST service.     |link:mod_server.html[Documentation]
 |=======
 
 == Integrations

http://git-wip-us.apache.org/repos/asf/incubator-tamaya/blob/d778cb81/src/site/asciidoc/extensions/mod_filter.adoc
----------------------------------------------------------------------
diff --git a/src/site/asciidoc/extensions/mod_filter.adoc b/src/site/asciidoc/extensions/mod_filter.adoc
new file mode 100644
index 0000000..1b810b8
--- /dev/null
+++ b/src/site/asciidoc/extensions/mod_filter.adoc
@@ -0,0 +1,154 @@
+// 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.
+
+= Apache Tamaya -- Extension: Integration with etcd (Core OS)
+
+:name: Tamaya
+:rootpackage: org.apache.tamaya.filter
+:title: Apache Tamaya Extension: Progrmmatic filtering of config entries
+:revdate: January 2016
+:authorinitials: ATR
+:author: Anatole Tresch
+:email: <an...@apache.org>
+:source-highlighter: coderay
+:website: http://tamaya.incubator.apache.org/
+:toc:
+:toc-placement: manual
+:encoding: UTF-8
+:numbered:
+
+'''
+
+<<<
+
+toc::[]
+
+<<<
+:numbered!:
+<<<
+[[Optional]]
+== COnfiguration Filtering (Extension Module)
+=== Overview
+
+The Tamaya filter module provides a simple singleton accessor that allows to explicitly add +PropertyFilter+ instances
+active on the current thread only. This can be very useful in many scenarios. Additionally this module adds
+standard filters that hide metadata entries when the full configuration map is accessed. When keys are accessed
+explcitily no filtering is applied and everything is visible.
+
+=== Compatibility
+
+The module is based on Java 7, so it will not run on Java 7 and beyond.
+
+
+=== Installation
+
+To benefit from configuration builder support you only must add the corresponding dependency to your module:
+
+[source, xml]
+-----------------------------------------------
+<dependency>
+  <groupId>org.apache.tamaya.ext</groupId>
+  <artifactId>tamaya-filter</artifactId>
+  <version>{tamayaVersion}</version>
+</dependency>
+-----------------------------------------------
+
+
+=== The Extensions Provided
+
+Tamaya Filter comes basically with 1 artifact:
+
+* The +org.apache.tamaya.filter.ConfigurationFilter+ provides several static methods to register +PropertyFilter+
+instances on the current thread.
+* The +org.apache.tamaya.filter.DefaultMetdataFilter+ is a +PropertyFilter+ with hides all entries starting with
+ an underscore ('_'), when a full property map is accessed.
+
+
+=== The ConfigurationFilter
+
+The accessor mentioned implements the API for for adding 1PropertyFilters+ to the current thread (as thread local):
+
+[source, java]
+-----------------------------------------------
+public final class ConfigurationFilter implements PropertyFilter{
+
+    ...
+
+    /**
+     * Seactivates metadata filtering also on global map access for this thread.
+     * @see #clearFilters()
+     * @param active true,to enable metadata filtering (default).
+     */
+    public static void setMetadataFilter(boolean active);
+
+    /**
+     * Access the filtering configuration that is used for filtering single property values accessed.
+     * @return the filtering config, never null.
+     */
+    public static ProgrammableFilter getSingleFilters();
+
+    /**
+     * Access the filtering configuration that is used for filtering configuration properties accessed as full
+     * map.
+     * @return the filtering config, never null.
+     */
+    public static ProgrammableFilter getMapFilters();
+
+    /**
+     * Removes all programmable filters active on the current thread.
+     */
+    public static void clearFilters();
+
+    ...
+
+}
+-----------------------------------------------
+
+For using regular expression when filtering configuration keys a corresponding implementation of a +PropertyFilter+
+is part of this module, So you can add a customized filter as follows:
+
+[source, java]
+-----------------------------------------------
+try{
+    ConfigurationFilter.getMapFilters().addFilter(new RegexPropertyFilter("\\_.*"));
+
+    // do your code with filtering active
+}
+finally{
+    // cleanup
+    ConfigurationFilter.clearFilters();
+}
+-----------------------------------------------
+
+The +ProgrammableFilter+ is a simple structure just providing some handy accessors to the dynamic thread-local
+managed filters:
+
+[source, java]
+-----------------------------------------------
+public final class ProgrammableFilter implements PropertyFilter{
+
+    public void addFilter(PropertyFilter filter);
+    public void addFilter(int pos, PropertyFilter filter);
+    public PropertyFilter removeFilter(int pos);
+    public void clearFilters();
+    public void setFilters(PropertyFilter... filters);
+    public void setFilters(Collection<PropertyFilter> filters);
+    public List<PropertyFilter> getFilters();
+
+}
+-----------------------------------------------
+


[4/8] incubator-tamaya git commit: TAMAYA-136: Adding PropertyValue for PropertySource SPI.

Posted by an...@apache.org.
TAMAYA-136: Adding PropertyValue for PropertySource SPI.


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

Branch: refs/heads/master
Commit: 80432aeb74f64e1d0f8a9cb22c7ebd88f8e7681c
Parents: eba49d8
Author: anatole <an...@apache.org>
Authored: Tue Feb 2 15:16:02 2016 +0100
Committer: anatole <an...@apache.org>
Committed: Tue Feb 2 15:16:02 2016 +0100

----------------------------------------------------------------------
 .../org/apache/tamaya/spi/FilterContext.java    | 107 +++----------------
 .../org/apache/tamaya/spi/PropertySource.java   |   6 +-
 .../org/apache/tamaya/spi/PropertyValue.java    |  63 +++++++++--
 .../apache/tamaya/spi/PropertyValueBuilder.java |  15 +--
 .../spi/PropertyValueCombinationPolicy.java     |  15 +--
 .../tamaya/spi/PropertyValueBuilderTest.java    |  33 ++++--
 .../apache/tamaya/spi/PropertyValueTest.java    |   9 +-
 7 files changed, 113 insertions(+), 135 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/incubator-tamaya/blob/80432aeb/code/api/src/main/java/org/apache/tamaya/spi/FilterContext.java
----------------------------------------------------------------------
diff --git a/code/api/src/main/java/org/apache/tamaya/spi/FilterContext.java b/code/api/src/main/java/org/apache/tamaya/spi/FilterContext.java
index 105d7f4..7e81bd9 100644
--- a/code/api/src/main/java/org/apache/tamaya/spi/FilterContext.java
+++ b/code/api/src/main/java/org/apache/tamaya/spi/FilterContext.java
@@ -24,25 +24,25 @@ import java.util.Map;
 import java.util.Objects;
 
 /**
- * A conversion context containing all the required values for implementing conversion. Use the included #Builder
- * for creating new instances of. This class is thread-safe to use. Adding supported formats is synchronized.
+ * A filter context containing all the required values for implementing filtering.
  *
- * @see PropertyConverter
+ * @see PropertyFilter
  */
 public class FilterContext {
 
     private final String key;
     @Experimental
-    private Map<String, String> metaEntries = new HashMap();
+    private Map<String, String> configEntries = new HashMap();
 
     /**
-     * Private constructor used from builder.
-     *
-     * @param builder the builder, not null.
+     * Creates a new FilterContext.
+     * @param key the key under evaluation, not null.
+     * @param configEntries the raw configuration data available in the current evaluation context, not null.
      */
-    protected FilterContext(Builder builder) {
-        this.key = builder.key;
-        this.metaEntries.putAll(builder.metaEntries);
+    public FilterContext(String key, Map<String,String> configEntries) {
+        this.key = Objects.requireNonNull(key);
+        this.configEntries.putAll(configEntries);
+        this.configEntries = Collections.unmodifiableMap(this.configEntries);
     }
 
     /**
@@ -77,97 +77,16 @@ public class FilterContext {
      * @return the configuration instance, or null.
      */
     @Experimental
-    public Map<String, String> getMetaEntries() {
-        return metaEntries;
-    }
-
-    /**
-     * Property to check, if the entry filtered is actually accessed as single value, or as part of a full Map
-     * access. For both scenarios filtering may be different.
-     * @return true, if it is a directly accessed key.
-     */
-    @Experimental
-    public boolean isSingleAccessedProperty(){
-        return this.metaEntries.size()==1;
+    public Map<String, String> getConfigEntries() {
+        return configEntries;
     }
 
     @Override
     public String toString() {
         return "FilterContext{" +
                 "key='" + key + '\'' +
-                ", metaEntries=" + metaEntries +
+                ", configEntries=" + configEntries +
                 '}';
     }
 
-    /**
-     * Builder to create new instances of {@link FilterContext}.
-     */
-    public static final class Builder {
-        /**
-         * The accessed key, or null.
-         */
-        private String key;
-        private Map<String, String> metaEntries = new HashMap();
-
-        /**
-         * Creates a new Builder instance.
-         *
-         * @param key the requested key, may be null.
-         */
-        public Builder(String key, String value) {
-            this(key, Collections.<String, String>emptyMap());
-            metaEntries.put(key, value);
-        }
-
-        /**
-         * Creates a new Builder instance.
-         *
-         * @param metaData the configuration, not null.
-         * @param key      the requested key, may be null.
-         */
-        public Builder(String key, Map<String, String> metaData) {
-            this.key = key;
-            this.metaEntries.putAll(metaData);
-        }
-
-        /**
-         * Sets the key.
-         *
-         * @param key the key, not null.
-         * @return the builder instance, for chaining
-         */
-        public Builder setKey(String key) {
-            this.key = Objects.requireNonNull(key);
-            return this;
-        }
-
-        /**
-         * Sets the configuration.
-         *
-         * @param metaProperties the meta configuration, not null
-         * @return the builder instance, for chaining
-         */
-        public Builder setMetaProperties(Map<String, String> metaProperties) {
-            this.metaEntries.putAll(Objects.requireNonNull(metaProperties));
-            return this;
-        }
-
-        /**
-         * Builds a new context instance.
-         *
-         * @return a new context, never null.
-         */
-        public FilterContext build() {
-            return new FilterContext(this);
-        }
-
-
-        @Override
-        public String toString() {
-            return "Builder{" +
-                    "key='" + key + '\'' +
-                    ", metaEntries=" + metaEntries +
-                    '}';
-        }
-    }
 }

http://git-wip-us.apache.org/repos/asf/incubator-tamaya/blob/80432aeb/code/api/src/main/java/org/apache/tamaya/spi/PropertySource.java
----------------------------------------------------------------------
diff --git a/code/api/src/main/java/org/apache/tamaya/spi/PropertySource.java b/code/api/src/main/java/org/apache/tamaya/spi/PropertySource.java
index 14765eb..804adf5 100644
--- a/code/api/src/main/java/org/apache/tamaya/spi/PropertySource.java
+++ b/code/api/src/main/java/org/apache/tamaya/spi/PropertySource.java
@@ -92,10 +92,10 @@ public interface PropertySource {
      * Access a property.
      *
      * @param key the property's key, not null.
-     * @return the property value, including also its metadata. In case a value is null it is valid to return
-     * {#code null} here.
+     * @return the property value map, where {@code map.get(key) == value}, including also any metadata. In case a
+     * value is null, simply return {@code null}.
      */
-    PropertyValue get(String key);
+    Map<String,String> get(String key);
 
     /**
      * Access the current properties as Map. The resulting Map may not return all items accessible, e.g.

http://git-wip-us.apache.org/repos/asf/incubator-tamaya/blob/80432aeb/code/api/src/main/java/org/apache/tamaya/spi/PropertyValue.java
----------------------------------------------------------------------
diff --git a/code/api/src/main/java/org/apache/tamaya/spi/PropertyValue.java b/code/api/src/main/java/org/apache/tamaya/spi/PropertyValue.java
index 5529005..8d3559c 100644
--- a/code/api/src/main/java/org/apache/tamaya/spi/PropertyValue.java
+++ b/code/api/src/main/java/org/apache/tamaya/spi/PropertyValue.java
@@ -18,26 +18,41 @@
  */
 package org.apache.tamaya.spi;
 
+import java.util.Collections;
 import java.util.HashMap;
 import java.util.Map;
+import java.util.Objects;
 
 /**
- * Class modelling the result of a request for a property value.
+ * Class modelling the result of a request for a property value. A property value is basically identified by its key.
+ * There might be reasons, where one want to further analyze, which PropertySources provided a value and which not, so
+ * it is possible to create a PropertyValue with a null value. Nevertheless in all cases the provider source (typically
+ * the name of the PropertySource) must be set.
  */
 public final class PropertyValue {
     /** The requested key. */
     private String key;
-    /** The value found. */
-    private String value;
     /** Additional metadata provided by thhe provider. */
-    private Map<String,String> contextData;
+    private Map<String,String> configEntries = new HashMap<>();
 
     PropertyValue(PropertyValueBuilder builder){
         this.key = builder.key;
-        this.value = builder.value;
         if(builder.contextData!=null) {
-            this.contextData = new HashMap<>(builder.contextData);
+            this.configEntries.putAll(builder.contextData);
         }
+        this.configEntries.put(key, Objects.requireNonNull(builder.value));
+    }
+
+    /**
+     * Creates a new instance
+     * @param key the key, not null.
+     * @param value the value, not null.
+     * @param source the source, typically the name of the {@link PropertySource} providing the value, not null.
+     */
+    private PropertyValue(String key, String value, String source){
+        this.key = Objects.requireNonNull(key, "key is required.");
+        this.configEntries.put(key, value);
+        this.configEntries.put("_"+key+".source", Objects.requireNonNull(source, "source is required."));
     }
 
     /**
@@ -54,20 +69,46 @@ public final class PropertyValue {
      * {@link PropertySource#get(String)}.
      */
     public String getValue() {
-        return value;
+        return configEntries.get(key);
     }
 
-    public Map<String, String> getContextData() {
-        return contextData;
+    /**
+     * Creates a full configuration map for this key, value pair and all its meta context data. This map
+     * is also used for subsequent processing, like value filtering.
+     * @return the property value entry map.
+     */
+    public Map<String, String> getConfigEntries() {
+        return Collections.unmodifiableMap(configEntries);
     }
 
     /**
      * Creates a new builder instance.
      * @param key the key, not null.
      * @param value the value.
+     * @param source the source, typically the name of the {@link PropertySource} providing the value, not null.
      * @return a new builder instance.
      */
-    public static PropertyValueBuilder builder(String key, String value){
-        return new PropertyValueBuilder(key, value);
+    public static PropertyValueBuilder builder(String key, String value, String source){
+        return new PropertyValueBuilder(key, value, source);
+    }
+
+    /**
+     * Creates a new PropertyValue without any metadata..
+     * @param key the key, not null.
+     * @param value the value.
+     * @param source the source, typically the name of the {@link PropertySource} providing the value, not null.
+     * @return a new builder instance.
+     */
+    public static PropertyValue of(String key, String value, String source){
+        return new PropertyValue(key, value, source);
+    }
+
+    /**
+     * Access the given key from this value. Valid keys are the key or any meta-context key.
+     * @param key the key, not null.
+     * @return the value found, or null.
+     */
+    public String get(String key) {
+        return this.configEntries.get(key);
     }
 }

http://git-wip-us.apache.org/repos/asf/incubator-tamaya/blob/80432aeb/code/api/src/main/java/org/apache/tamaya/spi/PropertyValueBuilder.java
----------------------------------------------------------------------
diff --git a/code/api/src/main/java/org/apache/tamaya/spi/PropertyValueBuilder.java b/code/api/src/main/java/org/apache/tamaya/spi/PropertyValueBuilder.java
index d75130b..349ee6c 100644
--- a/code/api/src/main/java/org/apache/tamaya/spi/PropertyValueBuilder.java
+++ b/code/api/src/main/java/org/apache/tamaya/spi/PropertyValueBuilder.java
@@ -31,16 +31,17 @@ public class PropertyValueBuilder {
     /** The property value. */
     String value;
     /** additional metadata entries (optional). */
-    Map<String,String> contextData;
+    Map<String,String> contextData = new HashMap<>();
 
     /**
      * Create a new builder instance, for a given
      * @param value the value, not null. If a value is null {@link PropertySource#get(String)} should return
      * {@code null}.
      */
-    public PropertyValueBuilder(String key, String value) {
+    public PropertyValueBuilder(String key, String value, String source) {
         this.key = Objects.requireNonNull(key);
         this.value = Objects.requireNonNull(value);
+        this.contextData.put("_" + key + ".source", Objects.requireNonNull(source));
     }
 
     /**
@@ -63,11 +64,7 @@ public class PropertyValueBuilder {
      * @return the builder for chaining.
      */
     public PropertyValueBuilder setContextData(Map<String, String> contextData) {
-        if(this.contextData==null){
-            this.contextData = new HashMap<>();
-        } else{
-            this.contextData.clear();
-        }
+        this.contextData.clear();
         for(Map.Entry<String,String> en:contextData.entrySet()) {
             this.contextData.put("_"+this.key+'.'+en.getKey(), en.getValue());
         }
@@ -81,9 +78,6 @@ public class PropertyValueBuilder {
      * @return the builder for chaining.
      */
     public PropertyValueBuilder addContextData(String key, Object value) {
-        if(this.contextData==null){
-            this.contextData = new HashMap<>();
-        }
         this.contextData.put("_"+this.key+'.'+key, String.valueOf(Objects.requireNonNull(value)));
         return this;
     }
@@ -99,6 +93,7 @@ public class PropertyValueBuilder {
     @Override
     public String toString() {
         return "PropertyValueBuilder{" +
+                "key='" + key + '\'' +
                 "value='" + value + '\'' +
                 ", contextData=" + contextData +
                 '}';

http://git-wip-us.apache.org/repos/asf/incubator-tamaya/blob/80432aeb/code/api/src/main/java/org/apache/tamaya/spi/PropertyValueCombinationPolicy.java
----------------------------------------------------------------------
diff --git a/code/api/src/main/java/org/apache/tamaya/spi/PropertyValueCombinationPolicy.java b/code/api/src/main/java/org/apache/tamaya/spi/PropertyValueCombinationPolicy.java
index 11726f5..ad842d2 100644
--- a/code/api/src/main/java/org/apache/tamaya/spi/PropertyValueCombinationPolicy.java
+++ b/code/api/src/main/java/org/apache/tamaya/spi/PropertyValueCombinationPolicy.java
@@ -18,6 +18,8 @@
  */
 package org.apache.tamaya.spi;
 
+import java.util.Map;
+
 /**
  * Policy that determines how the final value of a configuration entry is evaluated. An instances of this
  * interface can be registered to get control how multiple PropertySources are combined. This is useful in cases
@@ -34,9 +36,9 @@ public interface PropertyValueCombinationPolicy {
     PropertyValueCombinationPolicy DEFAULT_OVERRIDING_COLLECTOR = new PropertyValueCombinationPolicy(){
 
         @Override
-        public String collect(String currentValue, String key, PropertySource propertySource) {
-            PropertyValue value = propertySource.get(key);
-            return value!=null?value.getValue():currentValue;
+        public Map<String,String> collect(Map<String,String> currentValue, String key, PropertySource propertySource) {
+            Map<String,String> value = propertySource.get(key);
+            return value!=null && value.get(key)!=null?value:currentValue;
         }
 
     };
@@ -47,7 +49,8 @@ public interface PropertyValueCombinationPolicy {
      * when the full configuration property map is accessed by calling
      * {@link org.apache.tamaya.Configuration#getProperties()}.
      *
-     * @param currentValue the current value, including null.
+     * @param currentValue the current value, including metadata entries. If no such key is present the current value
+     *                     is null.
      *                     The collector should either combine the existing value with value from {@code currentValue}
      *                     or replace the value in {@code currentValue} with {@code valueRead}, hereby returning the
      *                     result to be used as new {@code currentValue}.
@@ -56,8 +59,8 @@ public interface PropertyValueCombinationPolicy {
      *                       may be evaluated for additional meta-data, how the given values are to be combined.
      *                       Note that the value returned by a PropertySource can be null. In that case
      *                       {@code currentValue} should be returned in almost all cases.
-     * @return the value to be used for future evaluation.
+     * @return the value to be used for future evaluation, including metadata entries.
      */
-    String collect(String currentValue, String key, PropertySource propertySource);
+    Map<String,String> collect(Map<String,String> currentValue, String key, PropertySource propertySource);
 
 }

http://git-wip-us.apache.org/repos/asf/incubator-tamaya/blob/80432aeb/code/api/src/test/java/org/apache/tamaya/spi/PropertyValueBuilderTest.java
----------------------------------------------------------------------
diff --git a/code/api/src/test/java/org/apache/tamaya/spi/PropertyValueBuilderTest.java b/code/api/src/test/java/org/apache/tamaya/spi/PropertyValueBuilderTest.java
index 7c8f349..5fdec2d 100644
--- a/code/api/src/test/java/org/apache/tamaya/spi/PropertyValueBuilderTest.java
+++ b/code/api/src/test/java/org/apache/tamaya/spi/PropertyValueBuilderTest.java
@@ -31,8 +31,28 @@ import static org.junit.Assert.*;
 public class PropertyValueBuilderTest {
 
     @Test
+    public void testKey() throws Exception {
+        PropertyValueBuilder b = new PropertyValueBuilder("k", "v", "testKey");
+        PropertyValue val = b.build();
+        assertEquals(val.getKey(),"k");
+    }
+
+    @Test
+    public void testValue() throws Exception {
+        PropertyValueBuilder b = new PropertyValueBuilder("k", "v", "testValue");
+        PropertyValue val = b.build();
+        assertEquals(val.getValue(),"v");
+        assertEquals(val.getConfigEntries().get("k"),"v");
+    }
+
+    @Test(expected=NullPointerException.class)
+    public void testKeyNullValue() throws Exception {
+        new PropertyValueBuilder("k", null, "testKeyNullValue");
+    }
+
+    @Test
     public void testSetContextData() throws Exception {
-        PropertyValueBuilder b = new PropertyValueBuilder("k", "v");
+        PropertyValueBuilder b = new PropertyValueBuilder("k", "v", "testSetContextData");
         Map<String,String> context = new HashMap<>();
         context.put("source", "testSetContextData");
         context.put("ts", String.valueOf(System.currentTimeMillis()));
@@ -41,8 +61,8 @@ public class PropertyValueBuilderTest {
         b.setContextData(context);
         context.remove("y");
         b.setContextData(context);
-        Map<String,String> contextData = b.build().getContextData();
-        assertEquals(contextData.size(), context.size());
+        PropertyValue contextData = b.build();
+        assertEquals(contextData.getConfigEntries().size(), context.size()+1);
         assertEquals(contextData.get("_k.source"), "testSetContextData");
         assertNotNull(contextData.get("_k.ts"));
         assertNull(contextData.get("_k.y"));
@@ -50,13 +70,12 @@ public class PropertyValueBuilderTest {
 
     @Test
     public void testAddContextData() throws Exception {
-        PropertyValueBuilder b = new PropertyValueBuilder("k", "v");
-        b.addContextData("source", "testAddContextData");
+        PropertyValueBuilder b = new PropertyValueBuilder("k", "v", "testAddContextData");
         b.addContextData("ts", System.currentTimeMillis());
         b.addContextData("y", "yValue");
         b.addContextData("y", "y2");
-        Map<String,String> contextData = b.build().getContextData();
-        assertEquals(contextData.size(), 3);
+        PropertyValue contextData = b.build();
+        assertEquals(contextData.getConfigEntries().size(), 4);
         assertEquals(contextData.get("_k.source"), "testAddContextData");
         assertNotNull(contextData.get("_k.ts"));
         assertEquals(contextData.get("_k.y"), "y2");

http://git-wip-us.apache.org/repos/asf/incubator-tamaya/blob/80432aeb/code/api/src/test/java/org/apache/tamaya/spi/PropertyValueTest.java
----------------------------------------------------------------------
diff --git a/code/api/src/test/java/org/apache/tamaya/spi/PropertyValueTest.java b/code/api/src/test/java/org/apache/tamaya/spi/PropertyValueTest.java
index 48fd23f..c6909ab 100644
--- a/code/api/src/test/java/org/apache/tamaya/spi/PropertyValueTest.java
+++ b/code/api/src/test/java/org/apache/tamaya/spi/PropertyValueTest.java
@@ -29,23 +29,24 @@ public class PropertyValueTest {
 
     @Test
     public void testGetKey() throws Exception {
-        PropertyValue pv = PropertyValue.builder("k", "v").build();
+        PropertyValue pv = PropertyValue.builder("k", "v", "testGetKey").build();
         assertEquals("k", pv.getKey());
     }
 
     @Test
     public void testGetValue() throws Exception {
-        PropertyValue pv = PropertyValue.builder("k", "v").build();
+        PropertyValue pv = PropertyValue.builder("k", "v", "testGetKey").build();
         assertEquals("v", pv.getValue());
     }
 
     @Test
     public void testGetContextData() throws Exception {
-        PropertyValue pv = PropertyValue.builder("k", "v")
+        PropertyValue pv = PropertyValue.builder("k", "v", "testGetKey")
                 .addContextData("k", "v2").build();
         assertEquals("v", pv.getValue());
         assertEquals("k", pv.getKey());
-        assertEquals("v2", pv.getContextData().get("_k.k"));
+        assertEquals("v2", pv.get("_k.k"));
+        assertEquals("testGetKey", pv.get("_k.source"));
     }
 
 }
\ No newline at end of file