tamaya-commits mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From anat...@apache.org
Subject [6/7] incubator-tamaya git commit: Reimplemented (also simjplified) Tamaya core completely based on latest JSR API. Moved prior Tamaya API into compat module.
Date Sun, 10 Dec 2017 22:07:14 GMT
http://git-wip-us.apache.org/repos/asf/incubator-tamaya/blob/d0e14ed7/code/compat/src/main/java/org/apache/tamaya/spi/ConversionContext.java
----------------------------------------------------------------------
diff --git a/code/compat/src/main/java/org/apache/tamaya/spi/ConversionContext.java b/code/compat/src/main/java/org/apache/tamaya/spi/ConversionContext.java
new file mode 100644
index 0000000..22c4d5b
--- /dev/null
+++ b/code/compat/src/main/java/org/apache/tamaya/spi/ConversionContext.java
@@ -0,0 +1,266 @@
+/*
+ * 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.apache.tamaya.Configuration;
+
+import java.lang.reflect.AnnotatedElement;
+import java.util.ArrayList;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Objects;
+import java.util.Set;
+
+/**
+ * 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 ConversionContext {
+
+    private final Configuration configuration;
+    private final String key;
+    private final TypeLiteral<?> targetType;
+    private final AnnotatedElement annotatedElement;
+    private final List<String> supportedFormats = new ArrayList<>();
+    private final ConfigurationContext configurationContext;
+
+    /**
+     * Private constructor used from builder.
+     * @param builder the builder, not {@code null}.
+     */
+    protected ConversionContext(Builder builder){
+        this.key = builder.key;
+        this.annotatedElement = builder.annotatedElement;
+        this.targetType = builder.targetType;
+        this.supportedFormats.addAll(builder.supportedFormats);
+        this.configuration = builder.configuration;
+        this.configurationContext = builder.configurationContext;
+    }
+
+    /**
+     * 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;
+    }
+
+    /**
+     * Get the target type required.
+     * @return the target type required.
+     */
+    public TypeLiteral<?> getTargetType(){
+        return targetType;
+    }
+
+    /**
+     * Get the annotated element, if conversion is performed using injection mechanisms.
+     * @return the annotated element, or {@code null}.
+     */
+    public AnnotatedElement getAnnotatedElement(){
+        return annotatedElement;
+    }
+
+    /**
+     * Get the configuration, which is targeted.
+     * @return the configuration instance, or {@code null}.
+     */
+    public Configuration getConfiguration(){
+        return configuration;
+    }
+
+    /**
+     * Allows to add information on the supported/tried formats, which can be shown to the user, especially when
+     * conversion failed. Adding of formats is synchronized, all formats are added in order to the overall list.
+     * This means formats should be passed in order of precedence.
+     * @param converterType the converters, which implements the formats provided.
+     * @param formatDescriptors the format descriptions in a human readable form, e.g. as regular expressions.
+     */
+    public void addSupportedFormats(@SuppressWarnings("rawtypes") Class<? extends PropertyConverter> converterType, String... formatDescriptors){
+        synchronized (supportedFormats){
+            for(String format: formatDescriptors) {
+                supportedFormats.add(format + " (" + converterType.getSimpleName() + ")");
+            }
+        }
+    }
+
+    /**
+     * Get the supported/tried formats in precedence order. The contents of this method depends on the
+     * {@link PropertyConverter} instances involved in a conversion.
+     * @return the supported/tried formats, never {@code null}.
+     */
+    public List<String> getSupportedFormats(){
+        synchronized (supportedFormats){
+            return new ArrayList<>(supportedFormats);
+        }
+    }
+
+    @Override
+    public String toString() {
+        return "ConversionContext{" +
+                "configuration=" + configuration +
+                ", key='" + key + '\'' +
+                ", targetType=" + targetType +
+                ", annotatedElement=" + annotatedElement +
+                ", supportedFormats=" + supportedFormats +
+                '}';
+    }
+
+    public ConfigurationContext getConfigurationContext() {
+        return configurationContext;
+    }
+
+    /**
+     * Builder to create new instances of {@link ConversionContext}.
+     */
+    public static final class Builder{
+        /** The backing configuration. */
+        private Configuration configuration;
+        /** The configuration context. */
+        private ConfigurationContext configurationContext;
+        /** The accessed key, or null. */
+        private String key;
+        /** The target type. */
+        private TypeLiteral<?> targetType;
+        /** The injection target (only set with injection used). */
+        private AnnotatedElement annotatedElement;
+        /** The ordered list of formats tried. */
+        private final Set<String> supportedFormats = new HashSet<>();
+
+        /**
+         * Creates a new Builder instance.
+         * @param targetType the target type
+         */
+        public Builder(TypeLiteral<?> targetType) {
+            this(null, null, null, targetType);
+        }
+
+        /**
+         * Creates a new Builder instance.
+         * @param key the requested key, may be null.
+         * @param targetType the target type
+         */
+        public Builder(String key, TypeLiteral<?> targetType) {
+            this(null, null, key, targetType);
+        }
+
+        /**
+         * Creates a new Builder instance.
+         * @param configuration the configuration, not {@code null}.
+         * @param configurationContext configuration context, not {@code null}.
+         * @param key the requested key, may be {@code null}.
+         * @param targetType the target type
+         */
+        public Builder(Configuration configuration, ConfigurationContext configurationContext, String key, TypeLiteral<?> targetType){
+            this.key = key;
+            this.configuration = configuration;
+            this.configurationContext = configurationContext;
+            this.targetType = Objects.requireNonNull(targetType);
+        }
+
+        /**
+         * Sets the key.
+         * @param key the key, not {@code null}.
+         * @return the builder instance, for chaining
+         */
+        public Builder setKey(String key){
+            this.key = Objects.requireNonNull(key);
+            return this;
+        }
+
+        /**
+         * Sets the configuration.
+         * @param configuration the configuration, not {@code null}
+         * @return the builder instance, for chaining
+         */
+        public Builder setConfiguration(Configuration configuration){
+            this.configuration = Objects.requireNonNull(configuration);
+            return this;
+        }
+
+        /**
+         * Sets the configuration.
+         * @param configurationContext the configuration, not {@code null}
+         * @return the builder instance, for chaining
+         */
+        public Builder setConfigurationContext(ConfigurationContext configurationContext){
+            this.configurationContext = Objects.requireNonNull(configurationContext);
+            return this;
+        }
+
+        /**
+         * Sets the annotated element, when configuration is injected.
+         * @param annotatedElement the annotated element, not {@code null}
+         * @return the builder instance, for chaining
+         */
+        public Builder setAnnotatedElement(AnnotatedElement annotatedElement){
+            this.annotatedElement = Objects.requireNonNull(annotatedElement);
+            return this;
+        }
+
+        /**
+         * Sets the target type explicitly. This is required in some rare cases, e.g. injection of {@code Provider}
+         * instances, where the provider's result type must be produced.
+         * @param targetType the
+         * @return the builder for chaining.
+         */
+        public Builder setTargetType(@SuppressWarnings("rawtypes") TypeLiteral targetType) {
+            this.targetType = Objects.requireNonNull(targetType);
+            return this;
+        }
+
+        /**
+         * Add the formats provided by a {@link PropertyConverter}. This method should be called by each converters
+         * performing/trying conversion, so the user can be given feedback on the supported formats on failure.
+         * @param converterType the converters type, not {@code null}.
+         * @param formatDescriptors the formats supported in a human readable form, e.g. as regular expressions.
+         * @return the builder instance, for chaining
+         */
+        public Builder addSupportedFormats(@SuppressWarnings("rawtypes") Class<? extends PropertyConverter> converterType, String... formatDescriptors){
+            for(String format: formatDescriptors) {
+                supportedFormats.add(format + " (" + converterType.getSimpleName() + ")");
+            }
+            return this;
+        }
+
+        /**
+         * Builds a new context instance.
+         * @return a new context, never null.
+         */
+        public ConversionContext build(){
+            return new ConversionContext(this);
+        }
+
+        @Override
+        public String toString() {
+            return "Builder{" +
+                    "configuration=" + configuration +
+                    "context=" + configurationContext +
+                    ", key='" + key + '\'' +
+                    ", targetType=" + targetType +
+                    ", annotatedElement=" + annotatedElement +
+                    ", supportedFormats=" + supportedFormats +
+                    '}';
+        }
+
+    }
+}

http://git-wip-us.apache.org/repos/asf/incubator-tamaya/blob/d0e14ed7/code/compat/src/main/java/org/apache/tamaya/spi/FilterContext.java
----------------------------------------------------------------------
diff --git a/code/compat/src/main/java/org/apache/tamaya/spi/FilterContext.java b/code/compat/src/main/java/org/apache/tamaya/spi/FilterContext.java
new file mode 100644
index 0000000..2851697
--- /dev/null
+++ b/code/compat/src/main/java/org/apache/tamaya/spi/FilterContext.java
@@ -0,0 +1,140 @@
+/*
+ * 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.apache.tamaya.Configuration;
+
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.Map;
+import java.util.Objects;
+
+/**
+ * A filter context containing all the required values for implementing filtering.
+ *
+ * @see PropertyFilter
+ */
+public class FilterContext {
+    /** The key. */
+    private final PropertyValue value;
+    /** The current context. */
+    private final ConfigurationContext context;
+    @Experimental
+    private Map<String, PropertyValue> configEntries = new HashMap<>();
+    @Experimental
+    private boolean singlePropertyScoped;
+
+
+    /**
+     * Creates a new FilterContext, for filtering of a multi value access
+     * using {@link Configuration#getProperties()}.
+     *
+     * @param value the value under evaluation, not {@code null}.
+     * @param configEntries the raw configuration data available in the
+     *                      current evaluation context, not {@code null}.
+     * @param context the current context, not {@code null}.
+     */
+    public FilterContext(PropertyValue value, Map<String,PropertyValue> configEntries, ConfigurationContext context) {
+        Objects.requireNonNull(value, "Value must not be null.");
+        Objects.requireNonNull(configEntries, "Initial configuration entries must be not null.");
+        Objects.requireNonNull(context, "Context must be not null.");
+
+        this.singlePropertyScoped = false;
+        this.value = Objects.requireNonNull(value);
+        this.context = Objects.requireNonNull(context);
+        this.configEntries.putAll(configEntries);
+        this.configEntries = Collections.unmodifiableMap(this.configEntries);
+    }
+
+    /**
+     * Creates a new FilterContext, for filtering of a single value access
+     * using {@link Configuration#getProperties()}.
+     * @param value the value under evaluation, not {@code null}.
+     * @param context the current context, not {@code null}.
+     */
+    public FilterContext(PropertyValue value, ConfigurationContext context) {
+        Objects.requireNonNull(value, "Value must not be null.");
+        Objects.requireNonNull(context, "Context must be not null.");
+
+        this.singlePropertyScoped = true;
+        this.context = Objects.requireNonNull(context);
+        this.value = Objects.requireNonNull(value);
+        this.configEntries = Collections.unmodifiableMap(this.configEntries);
+    }
+
+    /**
+     * Get the current context.
+     * @return the current context, not {@code null}.
+     */
+    public ConfigurationContext getContext(){
+        return context;
+    }
+
+    /**
+     * Get the property value under evaluation. 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 PropertyValue getProperty() {
+        return value;
+    }
+
+    /**
+     * 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>
+     * <li>all values starting with an {@code _<key>.}, for example {@code a.value}
+     * 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.</li>
+     * </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).
+     * 
+     * Finally, when a single property is accessed, e.g. by calling {@code Configuration.get(String)}.
+     *
+     * @return the configuration instance, or null.
+     */
+    @Experimental
+    public Map<String, PropertyValue> getConfigEntries() {
+        return configEntries;
+    }
+
+    @Override
+    public String toString() {
+        return "FilterContext{value='" + value + "', configEntries=" + configEntries.keySet() + '}';
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/incubator-tamaya/blob/d0e14ed7/code/compat/src/main/java/org/apache/tamaya/spi/PropertyConverter.java
----------------------------------------------------------------------
diff --git a/code/compat/src/main/java/org/apache/tamaya/spi/PropertyConverter.java b/code/compat/src/main/java/org/apache/tamaya/spi/PropertyConverter.java
new file mode 100644
index 0000000..ab96b6b
--- /dev/null
+++ b/code/compat/src/main/java/org/apache/tamaya/spi/PropertyConverter.java
@@ -0,0 +1,44 @@
+/*
+ * 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;
+
+/**
+ * Interface for an property that converts a configured String into something else.
+ * This is used for implementing type conversion from a property (String) to a certain target
+ * type. Hereby the target type can be multi-value (e.g. collections) or complex if needed.
+ * 
+ * @param <T> the type of the type literal
+ */
+@FunctionalInterface
+public interface PropertyConverter<T>{
+
+    /**
+     * Convert the given configuration keys from its String representation into the required target type.
+     * The context instance passed also allows to add a list of supported formats, which is very handy in case a
+     * value could not be converted. This list of supported formats can then shown to the user to give some hints
+     * how a value could be configured.
+     * 
+     * @param value configuration key that needs to be converted
+     * @param context the {@link ConversionContext}, containing the String value and the requested configuration key.
+     * @return converted keys
+     * @see ConversionContext#addSupportedFormats(Class, String...)
+     */
+    T convert(String value, ConversionContext context);
+
+}

http://git-wip-us.apache.org/repos/asf/incubator-tamaya/blob/d0e14ed7/code/compat/src/main/java/org/apache/tamaya/spi/PropertyFilter.java
----------------------------------------------------------------------
diff --git a/code/compat/src/main/java/org/apache/tamaya/spi/PropertyFilter.java b/code/compat/src/main/java/org/apache/tamaya/spi/PropertyFilter.java
new file mode 100644
index 0000000..3054496
--- /dev/null
+++ b/code/compat/src/main/java/org/apache/tamaya/spi/PropertyFilter.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;
+
+
+/**
+ * <p>Interface for filtering the current map of properties during the evaluation of the chain of PropertySources.
+ * Filters can be registered using the {@link org.apache.tamaya.spi.ServiceContext}. The ordinal
+ * hereby is defined by the corresponding {@code @Priority} annotation.</p>
+ * <p>Filters </p>
+ */
+@FunctionalInterface
+public interface PropertyFilter {
+
+    /**
+     * <p>Maps the current {@code valueToBeFiltered} value to a new value. The resulting value will be used as the result
+     * passed to the user.</p>
+     * <p>If a filter is currently not available, it should just pass the input map to the method's
+     * output.</p>
+     * <p>Returning {@code null} will remove the entry.</p>
+     * <h3>Implementation specification</h3>
+     * Implementations of this class must be
+     * <ul>
+     *     <li>reentrant</li>
+     *     <li>thread-safe</li>
+     * </ul>
+     * @param value the value to be filtered, which also can be {@code null} if removed by another filter.
+     * @param context the filter context, not {@code null}.
+     * @return the filtered value, or {@code null} if the value should be removed alltogether.
+     * @see PropertyValue
+     * @see PropertyValueBuilder
+     */
+    PropertyValue filterProperty(PropertyValue value, FilterContext context);
+
+}

http://git-wip-us.apache.org/repos/asf/incubator-tamaya/blob/d0e14ed7/code/compat/src/main/java/org/apache/tamaya/spi/PropertySource.java
----------------------------------------------------------------------
diff --git a/code/compat/src/main/java/org/apache/tamaya/spi/PropertySource.java b/code/compat/src/main/java/org/apache/tamaya/spi/PropertySource.java
new file mode 100644
index 0000000..e38e278
--- /dev/null
+++ b/code/compat/src/main/java/org/apache/tamaya/spi/PropertySource.java
@@ -0,0 +1,174 @@
+/*
+* 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.apache.tamaya.Configuration;
+
+import java.util.Collections;
+import java.util.Map;
+
+
+/**
+ * <p>This interface models a provider that serves configuration properties. The contained
+ * properties may be read from a Map of single or several sources (composite).
+ * PropertySources are the building blocks of the final configuration. </p>
+ * <h3>Implementation Requirements</h3>
+ * <p>Implementations of this interface must be</p>
+ * <ul>
+ * <li>Thread safe.</li>
+ * </ul>
+ *
+ * <p>A PropertySourceProvider will get picked up via the
+ * {@link java.util.ServiceLoader} mechanism and can be registered via
+ * {@code META-INF/services/org.apache.tamaya.spi.PropertySource}
+ * </p>
+ * <p>
+ * If you like to addSources multiple PropertySources at the same time
+ * you can use the {@link org.apache.tamaya.spi.PropertySourceProvider}
+ * interface.
+ * </p>
+ */
+public interface PropertySource {
+
+    /**
+     * property name to override default tamaya ordinals
+     */
+    String TAMAYA_ORDINAL = "tamaya.ordinal";
+
+    /**
+     * A resusable instance of an empty PropertySource.
+     */
+    PropertySource EMPTY = new PropertySource() {
+
+        @Override
+        public int getOrdinal() {
+            return Integer.MIN_VALUE;
+        }
+
+        @Override
+        public String getName() {
+            return "<empty>";
+        }
+
+        @Override
+        public PropertyValue get(String key) {
+            return null;
+        }
+
+        @Override
+        public Map<String, PropertyValue> getProperties() {
+            return Collections.emptyMap();
+        }
+
+        @Override
+        public boolean isScannable() {
+            return false;
+        }
+
+        @Override
+        public String toString(){
+            return "PropertySource.EMPTY";
+        }
+    };
+
+
+    /**
+     * The ordinal value is the default ordering parameter which definines the default order of
+     * auto-discovered property sources. Ordering of property sources is important since values
+     * from property sources with higher ordinal values override values from less significant
+     * property sources.
+     *
+     * By default Tamaya includes the following property sources:
+     * <ol>
+     *     <li>Properties file values (/META-INF/javaconfiguration.properties) (ordinal 100)</li>
+     *     <li>JNDI values (ordinal 200, only when adding the {@code tamaya-jndi} extension module)</li>
+     *     <li>Environment properties (ordinal 300)</li>
+     *     <li>System properties (ordinal 1000)</li>
+     * </ol>
+     *
+     * <p><b>Important Hints for custom implementations</b>:</p>
+     * <p>
+     * If a custom implementation should be invoked <b>before</b> the default implementations, use a value &gt; 1000
+     * </p>
+     * <p>
+     * If a custom implementation should be invoked <b>after</b> the default implementations, use a value &lt; 100
+     * </p>
+     *
+     * <p>Reordering of the default order of the config-sources:</p>
+     * <p>Example: If the properties file/s should be used <b>before</b> the other implementations,
+     * you have to configure an ordinal &gt; 1000. That means, you have to add e.g. tamaya.ordinal=401 to
+     * /META-INF/javaconfiguration.properties . Hint: In case of property files every file is handled as independent
+     * config-source, but all of them have ordinal 400 by default (and can be reordered in a fine-grained manner.</p>
+     *
+     * In cases where it is not possible to change a config sources ordinal value, you may have several options:
+     * <ul>
+     *     <li>you can addSources an alternate implementation of {@link PropertyValueCombinationPolicy}.</li>
+     *     <li>you can use a {@link ConfigurationContextBuilder} to redefine the source order and finally use
+     *     {@link org.apache.tamaya.ConfigurationProvider#setConfiguration(Configuration)} to
+     *     change the current default {@link Configuration}.</li>
+     *     <li>finally, the imeplementor of this API may define alternate mechanism to reconfigure an ordinal
+     *     in a vendor specific way.</li>
+     * </ul>
+     * @return the 'importance' aka ordinal of the configured values. The higher, the more important.
+     */
+    int getOrdinal();
+
+
+    /**
+     * Get the name of the property source. The name should be unique for the type of source, whereas the id is used
+     * to ensure unique identity, either locally or remotely.
+     * @return the configuration's name, never {@code null}.
+     */
+    String getName();
+
+    /**
+     * Access a property.
+     *
+     * @param key the property's key, not {@code null}.
+     * @return the property value map, where {@code map.get(key) == value}, including also any metadata. In case a
+     * value is null, simply return {@code null}.
+     */
+    PropertyValue get(String key);
+
+    /**
+     * Access the current properties as Set. The resulting Map may not return all items accessible, e.g.
+     * when the underlying storage does not support iteration of its entries.
+     {@code null}
+     * @return the corresponding map, never null.
+     */
+    Map<String, PropertyValue> getProperties();
+
+    /**
+     * Determines if this config source can be scanned for its list of properties.
+     *
+     * <p>
+     * PropertySources which are not scannable might not be able to find all the
+     * configured values to provide via {@link #getProperties()}. This might happen
+     * if the underlying storage doesn't support listing.
+     * </p>
+     *
+     * @return {@code true} if this PropertySource can be scanned for its list of properties,
+     *         {@code false} if it cannot/should not be scanned.
+     */
+    default boolean isScannable(){
+        return true;
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/incubator-tamaya/blob/d0e14ed7/code/compat/src/main/java/org/apache/tamaya/spi/PropertySourceProvider.java
----------------------------------------------------------------------
diff --git a/code/compat/src/main/java/org/apache/tamaya/spi/PropertySourceProvider.java b/code/compat/src/main/java/org/apache/tamaya/spi/PropertySourceProvider.java
new file mode 100644
index 0000000..aa09ad8
--- /dev/null
+++ b/code/compat/src/main/java/org/apache/tamaya/spi/PropertySourceProvider.java
@@ -0,0 +1,61 @@
+/*
+ * 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.Collection;
+import java.util.Collections;
+
+/**
+ * <p>Implement this interfaces to provide a PropertySource provider which
+ * is able to addSources multiple PropertySources. This is e.g. needed if
+ * there are multiple property files of a given config file name.</p>
+ * 
+ * <p>If a PropertySource like JNDI only exists once, then there is no need
+ * to implement it via the PropertySourceProvider but should directly
+ * expose a {@link PropertySource}.</p>
+ *
+ * <p>A PropertySourceProvider will get picked up via the
+ * {@link java.util.ServiceLoader} mechanism and must get registered via
+ * META-INF/services/org.apache.tamaya.spi.PropertySourceProvider</p>
+ */
+@FunctionalInterface
+public interface PropertySourceProvider {
+
+    /**
+     * A resusable instance of an empty PropertySource.
+     */
+    PropertySourceProvider EMPTY = new PropertySourceProvider() {
+
+        @Override
+        public Collection<PropertySource> getPropertySources() {
+            return Collections.emptySet();
+        }
+
+        @Override
+        public String toString(){
+            return "PropertySourceProvider(empty)";
+        }
+    };
+
+    /**
+     * @return For each e.g. property file, we return a single PropertySource
+     *         or an empty list if no PropertySource exists.
+     */
+    Collection<PropertySource> getPropertySources();
+}

http://git-wip-us.apache.org/repos/asf/incubator-tamaya/blob/d0e14ed7/code/compat/src/main/java/org/apache/tamaya/spi/PropertyValue.java
----------------------------------------------------------------------
diff --git a/code/compat/src/main/java/org/apache/tamaya/spi/PropertyValue.java b/code/compat/src/main/java/org/apache/tamaya/spi/PropertyValue.java
new file mode 100644
index 0000000..c538de7
--- /dev/null
+++ b/code/compat/src/main/java/org/apache/tamaya/spi/PropertyValue.java
@@ -0,0 +1,232 @@
+/*
+ * 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.io.Serializable;
+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. 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 implements Serializable{
+    private static final long serialVersionUID = 1L;
+    /** The requested key. */
+    private String key;
+    /** The value. */
+    private String value;
+    /** The source of the value. */
+    private String source;
+    /** Additional metadata provided by the provider. */
+    private Map<String,String> metaEntries = new HashMap<>();
+
+    PropertyValue(PropertyValueBuilder builder){
+        this.key = Objects.requireNonNull(builder.key);
+        this.value = builder.value;
+        this.source = Objects.requireNonNull(builder.source);
+        if(builder.metaEntries !=null) {
+            this.metaEntries.putAll(builder.metaEntries);
+        }
+    }
+
+    /**
+     * Creates a new instance
+     * @param key the key, not {@code null}.
+     * @param value the value, not {@code null}.
+     * @param source the source, typically the name of the {@link PropertySource} providing
+     *               the value, not {@code null}.
+     */
+    private PropertyValue(String key, String value, String source){
+        this.key = Objects.requireNonNull(key, "Key is required.");
+        this.value = Objects.requireNonNull(value, "Value is required.");
+        this.source = Objects.requireNonNull(source, "Source is required.");
+    }
+
+    /**
+     * The requested key.
+     * @return the, key never {@code null}.
+     */
+    public String getKey() {
+        return key;
+    }
+
+    /**
+     * The source.
+     * @return the source, which provided the value, not {@code null}.
+     * @see PropertySource#getName() .
+     */
+    public String getSource() {
+        return this.source;
+    }
+
+
+    /**
+     * 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 this.value;
+    }
+
+    /**
+     * 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> getMetaEntries() {
+        return Collections.unmodifiableMap(metaEntries);
+    }
+
+    /**
+     * Creates a new builder instance.
+     * @param key the key, not {@code null}.
+     * @param source the source, typically the name of the {@link PropertySource}
+     *               providing the value, not {@code null}.
+     * @return a new builder instance.
+     */
+    public static PropertyValueBuilder builder(String key, String source){
+        Objects.requireNonNull(key, "Key must be given.");
+        Objects.requireNonNull(source, "Source must be given");
+
+        return new PropertyValueBuilder(key, source);
+    }
+
+    /**
+     * Creates a new builder instance.
+     * @param key the key, not {@code null}.
+     * @param value the property value, not {@code null}.
+     * @param source the source, typically the name of the {@link PropertySource}
+     *               providing the value, not {@code null}.
+     * @return a new builder instance.
+     */
+    public static PropertyValueBuilder builder(String key, String value, String source) {
+        Objects.requireNonNull(key, "Key must be given.");
+        Objects.requireNonNull(value, "Value must be given");
+        Objects.requireNonNull(source, "Source must be given.");
+
+        return new PropertyValueBuilder(key, value, source);
+    }
+
+
+    /**
+     * Creates a new PropertyValue without any metadata..
+     * @param key the key, not {@code null}.
+     * @param value the value.
+     * @param source the source, typically the name of the {@link PropertySource}
+     *               providing the value, not  {@code null}.
+     * @return a new property value instance, or {@code null},
+     *         if the value passed is {@code null}..
+     */
+    public static PropertyValue of(String key, String value, String source) {
+        if (value==null) {
+            return null;
+        }
+        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 {@code null}.
+     * @return the value found, or {@code null}.
+     */
+    public String getMetaEntry(String key) {
+        return this.metaEntries.get(Objects.requireNonNull(key));
+    }
+
+    /**
+     * Creates a new builder instance based on this item.
+     * @return a new builder, never null.
+     */
+    public PropertyValueBuilder toBuilder() {
+        return new PropertyValueBuilder(this.getKey(), this.getSource())
+                .setValue(this.getValue())
+        .setMetaEntries(this.metaEntries);
+    }
+
+    @Override
+    public boolean equals(Object o) {
+        if (this == o) return true;
+        if (!(o instanceof PropertyValue)) return false;
+        PropertyValue that = (PropertyValue) o;
+        return Objects.equals(getKey(), that.getKey()) &&
+                Objects.equals(getValue(), that.getValue()) &&
+                Objects.equals(getSource(), that.getSource()) &&
+                Objects.equals(getMetaEntries(), that.getMetaEntries());
+    }
+
+    @Override
+    public int hashCode() {
+        return Objects.hash(getKey(), getValue(), getSource(),
+                getMetaEntries());
+    }
+
+    @Override
+    public String toString() {
+        return "PropertyValue{" +
+                "key='" + key + '\'' +
+                ", value='" + value + '\'' +
+                ", source='" + source + '\'' +
+                (metaEntries.isEmpty()?"":", metaEntries=" + metaEntries) +
+                '}';
+    }
+
+    /**
+     * Maps a map of {@code Map<String,String>} to a {@code Map<String,PropertyValue>}.
+     * @param config the String based map, not {@code null}.
+     * @param source the source name, not {@code null}.
+     * @return the corresponding value based map.
+     */
+    public static Map<String,PropertyValue> map(Map<String, String> config, String source) {
+        Map<String,PropertyValue> result = new HashMap<>(config.size());
+        for(Map.Entry<String,String> en:config.entrySet()){
+            result.put(en.getKey(), PropertyValue.of(en.getKey(), en.getValue(), source));
+        }
+        return result;
+    }
+
+    /**
+     * Maps a map of {@code Map<String,String>} to a {@code Map<String,PropertyValue>}.
+     *
+     * @param config the String based map, not {@code null}.
+     * @param source the source name, not {@code null}.
+     * @param metaData additional metadata, not {@code null}.
+     * @return the corresponding value based map.
+     */
+    public static Map<String,PropertyValue> map(Map<String, String> config, String source,
+                                                Map<String,String> metaData) {
+        Objects.requireNonNull(config, "Config must be given.");
+        Objects.requireNonNull(source, "Source must be given.");
+        Objects.requireNonNull(metaData, "Meta data must be given.");
+
+        Map<String,PropertyValue> result = new HashMap<>(config.size());
+
+        for(Map.Entry<String,String> en:config.entrySet()){
+            PropertyValue value = new PropertyValueBuilder(en.getKey(), source).setValue(en.getValue())
+                                                                               .addMetaEntries(metaData).build();
+            result.put(en.getKey(), value);
+        }
+        return result;
+    }
+}

http://git-wip-us.apache.org/repos/asf/incubator-tamaya/blob/d0e14ed7/code/compat/src/main/java/org/apache/tamaya/spi/PropertyValueBuilder.java
----------------------------------------------------------------------
diff --git a/code/compat/src/main/java/org/apache/tamaya/spi/PropertyValueBuilder.java b/code/compat/src/main/java/org/apache/tamaya/spi/PropertyValueBuilder.java
new file mode 100644
index 0000000..af01987
--- /dev/null
+++ b/code/compat/src/main/java/org/apache/tamaya/spi/PropertyValueBuilder.java
@@ -0,0 +1,196 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.tamaya.spi;
+
+import java.util.Collections;
+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;
+    /** The property vaoue source. */
+    String source;
+    /** additional metadata entries (optional). */
+    Map<String,String> metaEntries = new HashMap<>();
+
+    /**
+     * Create a new builder instance, for a given set of parameters.
+     * Before calling build at least a {@link #value} and its {@link #source}
+     * must be set.
+     */
+    PropertyValueBuilder(String key){
+        this.key = Objects.requireNonNull(key);
+    }
+
+    /**
+     * Create a new builder instance, for a given set of parameters.
+     * @param key to access a property value, not  {@code null}.
+     * @param source property source.
+     */
+    PropertyValueBuilder(String key, String source) {
+        this.key = Objects.requireNonNull(key);
+        this.source = Objects.requireNonNull(source);
+    }
+
+    /**
+     * Create a new builder instance, for a given set of parameters.
+     *
+     * @param key to access a property value.
+     * @param value the value, not {@code null}. If a value is  {@code null}
+     *              {@link PropertySource#get(String)} should return {@code null}.
+     * @param source property source.
+     */
+    PropertyValueBuilder(String key, String value, String source) {
+        this.key = Objects.requireNonNull(key);
+        this.value = value;
+        this.source = Objects.requireNonNull(source);
+    }
+
+    /**
+     * Replaces/sets the context data.
+     * @param metaEntries the context data to be applied, not {@code null}.
+     * @return the builder for chaining.
+     */
+    public PropertyValueBuilder setMetaEntries(Map<String, String> metaEntries) {
+        this.metaEntries.clear();
+        this.metaEntries.putAll(metaEntries);
+        return this;
+    }
+
+    /**
+     * Add an additional context data information.
+     * @param key the context data key, not {@code null}.
+     * @param value the context value, not {@code null} (will be converted to String).
+     * @return the builder for chaining.
+     */
+    public PropertyValueBuilder addMetaEntry(String key, Object value) {
+        Objects.requireNonNull(key, "Meta key must be given.");
+        Objects.requireNonNull(value, "Meta value must be given.");
+
+        this.metaEntries.put(key, String.valueOf(value));
+        return this;
+    }
+
+    /**
+     * Adds the context data given.
+     * @param metaEntries the context data to be applied, not {@code null}.
+     * @return the builder for chaining.
+     */
+    public PropertyValueBuilder addMetaEntries(Map<String, String> metaEntries) {
+        this.metaEntries.putAll(metaEntries);
+        return this;
+    }
+
+    /**
+     * Removes a meta entry.
+     * @param key the entry's key, not {@code null}.
+     * @return the builder for chaining.
+     */
+    public PropertyValueBuilder removeMetaEntry(String key) {
+        Objects.requireNonNull(key, "Key must be given.");
+
+        this.metaEntries.remove(key);
+        return this;
+    }
+
+    /**
+     * Get the value's context data.
+     * @return the context data, not {@code null}.
+     */
+    public Map<String,String> getMetaEntries() {
+        return Collections.unmodifiableMap(this.metaEntries);
+    }
+
+    /**
+     * Changes the entry's key, mapping also corresponding context entries.
+     * @param key the new key, not {@code null}.
+     * @return the builder for chaining.
+     */
+    public PropertyValueBuilder mapKey(String key) {
+        // todo obf if (1==1) throw new RuntimeException("No tests written.");
+        Map<String,String> newContext = new HashMap<>();
+        for(Map.Entry<String,String> en:this.metaEntries.entrySet()){
+            if(en.getKey().startsWith("_"+this.key)){
+                newContext.put("_"+key+'.'+ en.getKey().substring(this.key.length()+1), en.getValue());
+            }else{
+                newContext.put(en.getKey(), en.getValue());
+            }
+        }
+        this.metaEntries = newContext;
+        this.key = key;
+        return this;
+    }
+
+    /**
+     * Sets a new key.
+     * @param key the new key, not {@code null}.
+     * @return the builder for chaining.
+     */
+    public PropertyValueBuilder setKey(String key) {
+        this.key = Objects.requireNonNull(key);
+        return this;
+    }
+
+    /**
+     * Sets a new value.
+     * @param value the new value, not {@code null}.
+     * @return the builder for chaining.
+     */
+    public PropertyValueBuilder setValue(String value) {
+        this.value = Objects.requireNonNull(value, "Value must be given.");
+
+        return this;
+    }
+
+    /**
+     * Sets a new source.
+     * @param source the new source, not {@code null}.
+     * @return the builder for chaining.
+     */
+    public PropertyValueBuilder setSource(String source) {
+        // todo obf if (1==1) throw new RuntimeException("No tests written.");
+        this.source = Objects.requireNonNull(source);
+        return this;
+    }
+
+    /**
+     * Creates a new immutable {@link PropertyValue}.
+     * @return a new immutable {@link PropertyValue}, never {@code null}.
+     */
+    public PropertyValue build(){
+        return new PropertyValue(this);
+    }
+
+    @Override
+    public String toString() {
+        return "PropertyValueBuilder{" +
+                "key='" + key + '\'' +
+                "value='" + value + '\'' +
+                ", metaEntries=" + metaEntries +
+                '}';
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/incubator-tamaya/blob/d0e14ed7/code/compat/src/main/java/org/apache/tamaya/spi/PropertyValueCombinationPolicy.java
----------------------------------------------------------------------
diff --git a/code/compat/src/main/java/org/apache/tamaya/spi/PropertyValueCombinationPolicy.java b/code/compat/src/main/java/org/apache/tamaya/spi/PropertyValueCombinationPolicy.java
new file mode 100644
index 0000000..14640e6
--- /dev/null
+++ b/code/compat/src/main/java/org/apache/tamaya/spi/PropertyValueCombinationPolicy.java
@@ -0,0 +1,71 @@
+/*
+ * 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;
+
+
+/**
+ * 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
+ * where the default overriding policy as implemented in {@link #DEFAULT_OVERRIDING_POLICY} is not matching
+ * the need of the current application, e.g. then entries containing multiple values should be combined to new
+ * values instead of overridden.
+ */
+public interface PropertyValueCombinationPolicy {
+
+    /**
+     * Default overriding collector, where each existing entry ({@code current} is overridden by a subsequent non-null
+     * entry evaluated by {@code propertySource.get(key)}.
+     */
+    PropertyValueCombinationPolicy DEFAULT_OVERRIDING_POLICY = new PropertyValueCombinationPolicy(){
+
+        @Override
+        public PropertyValue collect(PropertyValue currentValue, String key, PropertySource propertySource) {
+            PropertyValue value = propertySource.get(key);
+            return value!=null?value:currentValue;
+        }
+    };
+
+    /**
+     * @deprecated Use {@linkplain #DEFAULT_OVERRIDING_POLICY} instead. Will be removed in 1.0.
+     */
+    @Deprecated
+    PropertyValueCombinationPolicy DEFAULT_OVERRIDING_COLLECTOR = DEFAULT_OVERRIDING_POLICY;
+
+
+        /**
+     * Method that is called for each value evaluated by a PropertySource for the given key. This method is called
+     * either when a single key is accessed, e.g. by calling {@code org.apache.tamaya.Configuration.getXXX}, but also
+     * when the full configuration property map is accessed by calling
+     * {@link org.apache.tamaya.Configuration#getProperties()}.
+     *
+     * @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}.
+     * @param key The current key to be evaluated.
+     * @param propertySource The PropertySource that may return an value for the given key. The PropertySource given
+     *                       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, including metadata entries.
+     */
+    PropertyValue collect(PropertyValue currentValue, String key, PropertySource propertySource);
+
+}

http://git-wip-us.apache.org/repos/asf/incubator-tamaya/blob/d0e14ed7/code/compat/src/main/java/org/apache/tamaya/spi/package-info.java
----------------------------------------------------------------------
diff --git a/code/compat/src/main/java/org/apache/tamaya/spi/package-info.java b/code/compat/src/main/java/org/apache/tamaya/spi/package-info.java
new file mode 100644
index 0000000..49dbab9
--- /dev/null
+++ b/code/compat/src/main/java/org/apache/tamaya/spi/package-info.java
@@ -0,0 +1,24 @@
+/*
+ * 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.
+ */
+
+/**
+ * This package contains the Apache Tamaya SPI artifacts.
+ */
+@org.osgi.annotation.versioning.Version("0.4")
+package org.apache.tamaya.spi;
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/incubator-tamaya/blob/d0e14ed7/code/compat/src/main/java/org/apache/tamaya/spisupport/ConfigValueEvaluator.java
----------------------------------------------------------------------
diff --git a/code/compat/src/main/java/org/apache/tamaya/spisupport/ConfigValueEvaluator.java b/code/compat/src/main/java/org/apache/tamaya/spisupport/ConfigValueEvaluator.java
new file mode 100644
index 0000000..92fd614
--- /dev/null
+++ b/code/compat/src/main/java/org/apache/tamaya/spisupport/ConfigValueEvaluator.java
@@ -0,0 +1,48 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.tamaya.spisupport;
+
+import org.apache.tamaya.spi.ConfigurationContext;
+import org.apache.tamaya.spi.PropertyValue;
+
+import java.util.Map;
+
+
+/**
+ * Component SPI which encapsulates the evaluation of a single or full <b>raw</b>value
+ * for a {@link ConfigurationContext}.
+ */
+public interface ConfigValueEvaluator {
+
+    /**
+     * Evaluates single value using a {@link ConfigurationContext}.
+     * @param key the config key, not null.
+     * @param context the context, not null.
+     * @return the value, or null.
+     */
+    PropertyValue evaluteRawValue(String key, ConfigurationContext context);
+
+    /**
+     * Evaluates all property values from a {@link ConfigurationContext}.
+     * @param context the context, not null.
+     * @return the value, or null.
+     */
+    Map<String, PropertyValue> evaluateRawValues(ConfigurationContext context);
+
+}

http://git-wip-us.apache.org/repos/asf/incubator-tamaya/blob/d0e14ed7/code/compat/src/main/java/org/apache/tamaya/spisupport/DefaultConfigValueEvaluator.java
----------------------------------------------------------------------
diff --git a/code/compat/src/main/java/org/apache/tamaya/spisupport/DefaultConfigValueEvaluator.java b/code/compat/src/main/java/org/apache/tamaya/spisupport/DefaultConfigValueEvaluator.java
new file mode 100644
index 0000000..d50ed7d
--- /dev/null
+++ b/code/compat/src/main/java/org/apache/tamaya/spisupport/DefaultConfigValueEvaluator.java
@@ -0,0 +1,70 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.tamaya.spisupport;
+
+import org.apache.tamaya.spi.ConfigurationContext;
+import org.apache.tamaya.spi.PropertyFilter;
+import org.apache.tamaya.spi.PropertySource;
+import org.apache.tamaya.spi.PropertyValue;
+
+import java.util.HashMap;
+import java.util.Map;
+
+
+/**
+ * Implementation of the Configuration API. This class uses the current {@link ConfigurationContext} to evaluate the
+ * chain of {@link PropertySource} and {@link PropertyFilter}
+ * instance to evaluate the current Configuration.
+ */
+public class DefaultConfigValueEvaluator implements ConfigValueEvaluator{
+
+    @Override
+    public PropertyValue evaluteRawValue(String key, ConfigurationContext context) {
+        PropertyValue unfilteredValue = null;
+        for (PropertySource propertySource : context.getPropertySources()) {
+            unfilteredValue = context.getPropertyValueCombinationPolicy().
+                    collect(unfilteredValue, key, propertySource);
+        }
+        if(unfilteredValue==null || unfilteredValue.getValue()==null){
+            return null;
+        }
+        return unfilteredValue;
+    }
+
+    @Override
+    public Map<String, PropertyValue> evaluateRawValues(ConfigurationContext context) {
+        Map<String, PropertyValue> result = new HashMap<>();
+        for (PropertySource propertySource : context.getPropertySources()) {
+            for (Map.Entry<String,PropertyValue> propEntry: propertySource.getProperties().entrySet()) {
+                PropertyValue unfilteredValue = result.get(propEntry.getKey());
+                unfilteredValue = context.getPropertyValueCombinationPolicy().
+                        collect(unfilteredValue, propEntry.getKey(), propertySource);
+                if(unfilteredValue!=null){
+                    result.put(unfilteredValue.getKey(), unfilteredValue);
+                }
+            }
+        }
+        return result;
+    }
+
+    @Override
+    public String toString() {
+        return "DefaultConfigEvaluator{}";
+    }
+}

http://git-wip-us.apache.org/repos/asf/incubator-tamaya/blob/d0e14ed7/code/compat/src/main/java/org/apache/tamaya/spisupport/DefaultConfiguration.java
----------------------------------------------------------------------
diff --git a/code/compat/src/main/java/org/apache/tamaya/spisupport/DefaultConfiguration.java b/code/compat/src/main/java/org/apache/tamaya/spisupport/DefaultConfiguration.java
new file mode 100644
index 0000000..bdbd09c
--- /dev/null
+++ b/code/compat/src/main/java/org/apache/tamaya/spisupport/DefaultConfiguration.java
@@ -0,0 +1,281 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.tamaya.spisupport;
+
+import org.apache.tamaya.ConfigException;
+import org.apache.tamaya.ConfigOperator;
+import org.apache.tamaya.ConfigQuery;
+import org.apache.tamaya.Configuration;
+import org.apache.tamaya.spi.TypeLiteral;
+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 org.apache.tamaya.spi.ServiceContextManager;
+
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.Objects;
+import java.util.logging.Level;
+import java.util.logging.Logger;
+
+/**
+ * Implementation of the Configuration API. This class uses the current {@link ConfigurationContext} to evaluate the
+ * chain of {@link PropertySource} and {@link org.apache.tamaya.spi.PropertyFilter}
+ * instance to evaluate the current Configuration.
+ */
+public class DefaultConfiguration implements Configuration {
+    /**
+     * The logger.
+     */
+    private static final Logger LOG = Logger.getLogger(DefaultConfiguration.class.getName());
+
+    /**
+     * The current {@link ConfigurationContext} of the current instance.
+     */
+    private final ConfigurationContext configurationContext;
+
+    /**
+     * EvaluationStrategy
+     */
+    private ConfigValueEvaluator configEvaluator = loadConfigValueEvaluator();
+
+    private ConfigValueEvaluator loadConfigValueEvaluator() {
+        ConfigValueEvaluator eval = null;
+        try{
+            eval = ServiceContextManager.getServiceContext()
+                    .getService(ConfigValueEvaluator.class);
+        }catch(Exception e){
+            LOG.log(Level.WARNING, "Failed to load ConfigValueEvaluator from ServiceContext, using default.", e);
+        }
+        if(eval==null){
+            eval = new DefaultConfigValueEvaluator();
+        }
+        return eval;
+    }
+
+
+    /**
+     * Constructor.
+     * @param configurationContext The configuration Context to be used.
+     */
+    public DefaultConfiguration(ConfigurationContext configurationContext){
+        this.configurationContext = Objects.requireNonNull(configurationContext);
+    }
+
+    /**
+     * Get a given value, filtered with the context's filters as needed.
+     * @param key the property's key, not null.
+     * @return the filtered value, or null.
+     */
+    @Override
+    public String get(String key) {
+        Objects.requireNonNull(key, "Key must not be null.");
+
+        PropertyValue value = configEvaluator.evaluteRawValue(key, configurationContext);
+        if(value==null || value.getValue()==null){
+            return null;
+        }
+        value = PropertyFiltering.applyFilter(value, configurationContext);
+        if(value!=null){
+            return value.getValue();
+        }
+        return null;
+    }
+
+    /**
+     * Evaluates the raw value using the context's PropertyValueCombinationPolicy.
+     * @param key the key, not null.
+     * @return the value, before filtering is applied.
+     */
+    protected PropertyValue evaluteRawValue(String key) {
+        List<PropertySource> propertySources = configurationContext.getPropertySources();
+        PropertyValue filteredValue = null;
+        PropertyValueCombinationPolicy combinationPolicy = this.configurationContext
+                .getPropertyValueCombinationPolicy();
+        for (PropertySource propertySource : propertySources) {
+            filteredValue = combinationPolicy.collect(filteredValue, key, propertySource);
+        }
+        return filteredValue;
+    }
+
+
+    @Override
+    public String getOrDefault(String key, String defaultValue) {
+        Objects.requireNonNull(key, "Key must not be null.");
+
+        String val = get(key);
+        if(val==null){
+            return defaultValue;
+        }
+        return val;
+    }
+
+    @Override
+    public <T> T getOrDefault(String key, Class<T> type, T defaultValue) {
+        Objects.requireNonNull(key, "Key must not be null.");
+        Objects.requireNonNull(type, "Target type must not be null");
+
+        T val = get(key, type);
+        if(val==null){
+            return defaultValue;
+        }
+        return val;
+    }
+
+    /**
+     * Get the current properties, composed by the loaded {@link PropertySource} and filtered
+     * by registered {@link org.apache.tamaya.spi.PropertyFilter}.
+     *
+     * @return the final properties.
+     */
+    @Override
+    public Map<String, String> getProperties() {
+        Map<String, PropertyValue> filtered = PropertyFiltering.applyFilters(
+                configEvaluator.evaluateRawValues(configurationContext),
+                configurationContext);
+        Map<String,String> result = new HashMap<>();
+        for(PropertyValue val:filtered.values()){
+            if(val.getValue()!=null) {
+                result.put(val.getKey(), val.getValue());
+                // TODO: Discuss metadata handling...
+                result.putAll(val.getMetaEntries());
+            }
+        }
+        return result;
+    }
+
+
+    /**
+     * Accesses the current String value for the given key and tries to convert it
+     * using the {@link PropertyConverter} instances provided by the current
+     * {@link ConfigurationContext}.
+     *
+     * @param key  the property's absolute, or relative path, e.g. @code
+     *             a/b/c/d.myProperty}, never {@code null}.
+     * @param type The target type required, not {@code null}.
+     * @param <T>  the value type
+     * @return the converted value, never {@code null}.
+     */
+    @Override
+    public <T> T get(String key, Class<T> type) {
+        return get(key, TypeLiteral.of(type));
+    }
+
+    /**
+     * Accesses the current String value for the given key and tries to convert it
+     * using the {@link PropertyConverter} instances provided by the current
+     * {@link ConfigurationContext}.
+     *
+     * @param key  the property's absolute, or relative path, e.g. @code
+     *             a/b/c/d.myProperty}.
+     * @param type The target type required, not null.
+     * @param <T>  the value type
+     * @return the converted value, never null.
+     */
+    @Override
+    public <T> T get(String key, TypeLiteral<T> type) {
+        Objects.requireNonNull(key, "Key must not be null.");
+        Objects.requireNonNull(type, "Target type must not be null");
+
+        return convertValue(key, get(key), type);
+    }
+
+    @SuppressWarnings("unchecked")
+	protected <T> T convertValue(String key, String value, TypeLiteral<T> type) {
+        if (value != null) {
+            List<PropertyConverter<T>> converters = configurationContext.getPropertyConverters(type);
+            ConversionContext context = new ConversionContext.Builder(this, this.configurationContext, key, type)
+                    .build();
+            for (PropertyConverter<T> converter : converters) {
+                try {
+                    T t = converter.convert(value, context);
+                    if (t != null) {
+                        return t;
+                    }
+                } catch (Exception e) {
+                    LOG.log(Level.FINEST, "PropertyConverter: " + converter + " failed to convert value: " + value, e);
+                }
+            }
+            // if the target type is a String, we can return the value, no conversion required.
+            if(type.equals(TypeLiteral.of(String.class))){
+                return (T)value;
+            }
+            // unsupported type, throw an exception
+            throw new ConfigException("Unparseable config value for type: " + type.getRawType().getName() + ": " + key +
+                    ", supported formats: " + context.getSupportedFormats());
+        }
+        return null;
+    }
+
+    @Override
+    public <T> T getOrDefault(String key, TypeLiteral<T> type, T defaultValue) {
+        Objects.requireNonNull(key);
+        Objects.requireNonNull(type);
+
+        T val = get(key, type);
+        if(val==null){
+            return defaultValue;
+        }
+        return val;
+    }
+
+    @Override
+    public Configuration with(ConfigOperator operator) {
+        return operator.operate(this);
+    }
+
+    @Override
+    public <T> T query(ConfigQuery<T> query) {
+        return query.query(this);
+    }
+
+    @Override
+    public ConfigurationContext getContext() {
+        return this.configurationContext;
+    }
+
+    @Override
+    public boolean equals(Object o) {
+        if (this == o) return true;
+        if (o == null || getClass() != o.getClass()) return false;
+
+        DefaultConfiguration that = (DefaultConfiguration) o;
+
+        if (!configurationContext.equals(that.configurationContext)) return false;
+        return configEvaluator.getClass().equals(that.configEvaluator.getClass());
+    }
+
+    @Override
+    public int hashCode() {
+        int result = configurationContext.hashCode();
+        result = 31 * result + configEvaluator.getClass().hashCode();
+        return result;
+    }
+
+    @Override
+    public String toString() {
+        return "Configuration{\n " +
+                configurationContext +
+                '}';
+    }
+}

http://git-wip-us.apache.org/repos/asf/incubator-tamaya/blob/d0e14ed7/code/compat/src/main/java/org/apache/tamaya/spisupport/DefaultConfigurationBuilder.java
----------------------------------------------------------------------
diff --git a/code/compat/src/main/java/org/apache/tamaya/spisupport/DefaultConfigurationBuilder.java b/code/compat/src/main/java/org/apache/tamaya/spisupport/DefaultConfigurationBuilder.java
new file mode 100644
index 0000000..1b3f1ce
--- /dev/null
+++ b/code/compat/src/main/java/org/apache/tamaya/spisupport/DefaultConfigurationBuilder.java
@@ -0,0 +1,239 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License.
+ */
+package org.apache.tamaya.spisupport;
+
+import org.apache.tamaya.Configuration;
+import org.apache.tamaya.spi.*;
+import org.apache.tamaya.spi.ConfigurationBuilder;
+
+import java.util.Collection;
+import java.util.Comparator;
+import java.util.List;
+import java.util.Map;
+
+
+/**
+ * Default implementation of {@link ConfigurationBuilder}.
+ */
+public class DefaultConfigurationBuilder implements ConfigurationBuilder {
+
+    protected final DefaultConfigurationContextBuilder contextBuilder;
+
+    /**
+     * Creates a new builder instance.
+     */
+    public DefaultConfigurationBuilder() {
+        this.contextBuilder = new DefaultConfigurationContextBuilder();
+    }
+
+    /**
+     * Creates a new builder instance.
+     */
+    public DefaultConfigurationBuilder(ConfigurationContext context) {
+        this.contextBuilder = new DefaultConfigurationContextBuilder(context);
+    }
+
+    /**
+     * Creates a new builder instance initializing it with the given context.
+     * @param configuration the configuration to be used, not null.
+     */
+    public DefaultConfigurationBuilder(Configuration configuration) {
+        this.contextBuilder = new DefaultConfigurationContextBuilder(configuration.getContext());
+    }
+
+    /**
+     * Allows to set configuration context during unit tests.
+     */
+    public ConfigurationBuilder setConfiguration(Configuration configuration) {
+        this.contextBuilder.setContext(configuration.getContext());
+        return this;
+    }
+
+
+    @Override
+    public ConfigurationBuilder setContext(ConfigurationContext context) {
+        this.contextBuilder.setContext(context);
+        return this;
+    }
+
+    @Override
+    public ConfigurationBuilder addPropertySources(PropertySource... sources){
+        this.contextBuilder.addPropertySources(sources);
+        return this;
+    }
+
+    @Override
+    public ConfigurationBuilder addPropertySources(Collection<PropertySource> sources){
+        this.contextBuilder.addPropertySources(sources);
+        return this;
+    }
+
+    public ConfigurationBuilder addDefaultPropertyFilters() {
+        this.contextBuilder.addDefaultPropertyFilters();
+        return this;
+    }
+
+    public ConfigurationBuilder addDefaultPropertySources() {
+        this.contextBuilder.addDefaultPropertySources();
+        return this;
+    }
+
+    public ConfigurationBuilder addDefaultPropertyConverters() {
+        this.contextBuilder.addDefaultPropertyConverters();
+        return this;
+    }
+
+    @Override
+    public ConfigurationBuilder removePropertySources(PropertySource... propertySources) {
+        this.contextBuilder.removePropertySources(propertySources);
+        return this;
+    }
+
+    @Override
+    public ConfigurationBuilder removePropertySources(Collection<PropertySource> propertySources) {
+        this.contextBuilder.removePropertySources(propertySources);
+        return this;
+    }
+
+    @Override
+    public List<PropertySource> getPropertySources() {
+        return this.contextBuilder.getPropertySources();
+    }
+
+    @Override
+    public ConfigurationBuilder increasePriority(PropertySource propertySource) {
+        this.contextBuilder.increasePriority(propertySource);
+        return this;
+    }
+
+    @Override
+    public ConfigurationBuilder decreasePriority(PropertySource propertySource) {
+        this.contextBuilder.decreasePriority(propertySource);
+        return this;
+    }
+
+    @Override
+    public ConfigurationBuilder highestPriority(PropertySource propertySource) {
+        this.contextBuilder.highestPriority(propertySource);
+        return this;
+    }
+
+    @Override
+    public ConfigurationBuilder lowestPriority(PropertySource propertySource) {
+        this.contextBuilder.lowestPriority(propertySource);
+        return this;
+    }
+
+    @Override
+    public ConfigurationBuilder addPropertyFilters(Collection<PropertyFilter> filters){
+        this.contextBuilder.addPropertyFilters(filters);
+        return this;
+    }
+
+    @Override
+    public ConfigurationBuilder addPropertyFilters(PropertyFilter... filters){
+        this.contextBuilder.addPropertyFilters(filters);
+        return this;
+    }
+
+    @Override
+    public ConfigurationBuilder removePropertyFilters(PropertyFilter... filters) {
+        this.contextBuilder.removePropertyFilters(filters);
+        return this;
+    }
+
+    @Override
+    public ConfigurationBuilder removePropertyFilters(Collection<PropertyFilter> filters) {
+        this.contextBuilder.removePropertyFilters(filters);
+        return this;
+    }
+
+
+    @Override
+    public <T> ConfigurationBuilder removePropertyConverters(TypeLiteral<T> typeToConvert,
+                                                                    PropertyConverter<T>... converters) {
+        this.contextBuilder.removePropertyConverters(typeToConvert, converters);
+        return this;
+    }
+
+    @Override
+    public <T> ConfigurationBuilder removePropertyConverters(TypeLiteral<T> typeToConvert,
+                                                                    Collection<PropertyConverter<T>> converters) {
+        this.contextBuilder.removePropertyConverters(typeToConvert, converters);
+        return this;
+    }
+
+    @Override
+    public ConfigurationBuilder removePropertyConverters(TypeLiteral<?> typeToConvert) {
+        this.contextBuilder.removePropertyConverters(typeToConvert);
+        return this;
+    }
+
+
+    @Override
+    public ConfigurationBuilder setPropertyValueCombinationPolicy(PropertyValueCombinationPolicy combinationPolicy){
+        this.contextBuilder.setPropertyValueCombinationPolicy(combinationPolicy);
+        return this;
+    }
+
+    @Override
+    public <T> ConfigurationBuilder addPropertyConverters(TypeLiteral<T> type, PropertyConverter<T>... propertyConverters){
+        this.contextBuilder.addPropertyConverters(type, propertyConverters);
+        return this;
+    }
+
+    @Override
+    public <T> ConfigurationBuilder addPropertyConverters(TypeLiteral<T> type, Collection<PropertyConverter<T>> propertyConverters){
+        this.contextBuilder.addPropertyConverters(type, propertyConverters);
+        return this;
+    }
+
+    /**
+     * Builds a new configuration based on the configuration of this builder instance.
+     *
+     * @return a new {@link org.apache.tamaya.Configuration configuration instance},
+     *         never {@code null}.
+     */
+    @Override
+    public Configuration build() {
+        return new DefaultConfiguration(this.contextBuilder.build());
+    }
+
+    @Override
+    public ConfigurationBuilder sortPropertyFilter(Comparator<PropertyFilter> comparator) {
+        this.contextBuilder.sortPropertyFilter(comparator);
+        return this;
+    }
+
+    @Override
+    public ConfigurationBuilder sortPropertySources(Comparator<PropertySource> comparator) {
+        this.contextBuilder.sortPropertySources(comparator);
+        return this;
+    }
+
+    @Override
+    public List<PropertyFilter> getPropertyFilters() {
+        return this.contextBuilder.getPropertyFilters();
+    }
+
+    @Override
+    public Map<TypeLiteral<?>, Collection<PropertyConverter<?>>> getPropertyConverter() {
+        return this.contextBuilder.getPropertyConverter();
+    }
+}


Mime
View raw message