tamaya-commits mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From anat...@apache.org
Subject [13/21] incubator-tamaya git commit: - Minimalized current API for further discussions.
Date Fri, 15 Jul 2016 12:04:39 GMT
http://git-wip-us.apache.org/repos/asf/incubator-tamaya/blob/43468987/modules/builder/src/main/java/org/apache/tamaya/builder/spi/ConfigurationContextBuilder.java
----------------------------------------------------------------------
diff --git a/modules/builder/src/main/java/org/apache/tamaya/builder/spi/ConfigurationContextBuilder.java b/modules/builder/src/main/java/org/apache/tamaya/builder/spi/ConfigurationContextBuilder.java
new file mode 100644
index 0000000..5dfda4f
--- /dev/null
+++ b/modules/builder/src/main/java/org/apache/tamaya/builder/spi/ConfigurationContextBuilder.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.builder.spi;
+
+import org.apache.tamaya.TypeLiteral;
+
+import java.util.Collection;
+
+/**
+ * A builder for creating new or adapting instances of {@link ConfigurationContext}.
+ * Builders can be obtained in exactly two ways:
+ * <ol>
+ *     <li>By accessing a preinitialized builder from an existing {@link ConfigurationContext},
+ *     by calling {@link ConfigurationContext#toBuilder()}.</li>
+ *     <li>By accessing an empty builder instance from
+ *     {@link org.apache.tamaya.ConfigurationProvider#getConfigurationContextBuilder()}.</li>
+ * </ol>
+ * After all changes are applied to a builder a new {@link ConfigurationContext} instance can
+ * be created and can be applied by calling
+ * {@link org.apache.tamaya.ConfigurationProvider#setConfigurationContext(ConfigurationContext)}.
+ * 
+ */
+
+/* @todo This is some Javadoc which is outdated. I am not sure if I can deleted it. The author
+ *       should take care. Oliver B. Fischer, 2015-12-23
+ * Since this method can
+ * throw an UnsupportedOperationException, you should check before if changing the current ConfigurationContext
+ * programmatically is supported by calling
+ * {@link org.apache.tamaya.ConfigurationProvider#is}.
+ */
+public interface ConfigurationContextBuilder {
+
+    /**
+     * Init this builder instance with the given {@link ConfigurationContext} instance. This
+     * method will replace any existing data in the current builder with the data contained in the given
+     * {@link ConfigurationContext}.
+     *
+     * @param context the {@link ConfigurationContext} instance to be used, not null.
+     * @return this builder, for chaining, never null.
+     */
+    ConfigurationContextBuilder setContext(ConfigurationContext context);
+
+    /**
+     * This method can be used for programmatically adding {@link PropertySource}s.
+     * It is not needed for normal 'usage' by end users, but only for Extension Developers!
+     *
+     * @param propertySourcesToAdd the PropertySources to add
+     * @return this builder, for chaining, never null.
+     */
+    ConfigurationContextBuilder addPropertySources(PropertySource... propertySourcesToAdd);
+
+    /**
+     * This method can be used for programmatically adding {@link PropertySource}s.
+     * It is not needed for normal 'usage' by end users, but only for Extension Developers!
+     *
+     * @param propertySourcesToAdd the PropertySources to add
+     * @return this builder, for chaining, never null.
+     */
+    ConfigurationContextBuilder addPropertySources(Collection<PropertySource> propertySourcesToAdd);
+
+    /**
+     * This method can be used for programmatically adding {@link PropertySource}s.
+     * It is not needed for normal 'usage' by end users, but only for Extension Developers!
+     *
+     * @param propertySourcesNames the PropertySource names of the sources to remove
+     * @return this builder, for chaining, never null.
+     */
+    ConfigurationContextBuilder removePropertySources(String... propertySourcesNames);
+
+    /**
+     * This method can be used for programmatically adding {@link PropertySource}s.
+     * It is not needed for normal 'usage' by end users, but only for Extension Developers!
+     *
+     * @param propertySourcesNames the PropertySource names of the sources to remove
+     * @return this builder, for chaining, never null.
+     */
+    ConfigurationContextBuilder removePropertySources(Collection<String> propertySourcesNames);
+
+    /**
+     * Adds the given PropertyFilter instances.
+     *
+     * @param filters the filters to add
+     * @return this builder, for chaining, never null.
+     */
+    ConfigurationContextBuilder addPropertyFilters(PropertyFilter... filters);
+
+    /**
+     * Adds the given PropertyFilter instances.
+     *
+     * @param filters the filters to add
+     * @return this builder, for chaining, never null.
+     */
+    ConfigurationContextBuilder addPropertyFilters(Collection<PropertyFilter> filters);
+
+    /**
+     * Removes the given PropertyFilter instances.
+     *
+     * @param filters the filters to remove
+     * @return this builder, for chaining, never null.
+     */
+    ConfigurationContextBuilder removePropertyFilters(PropertyFilter... filters);
+
+    /**
+     * Removes the given PropertyFilter instances.
+     *
+     * @param filters the filters to remove
+     * @return this builder, for chaining, never null.
+     */
+    ConfigurationContextBuilder removePropertyFilters(Collection<PropertyFilter> filters);
+
+    /**
+     * This method can be used for programmatically adding {@link PropertyConverter}s.
+     * It is not needed for normal 'usage' by end users, but only for Extension Developers!
+     *
+     * @param <T> the type of the type literal
+     * @param typeToConvert     the type for which the converter is for
+     * @param propertyConverter the PropertyConverters to add for this type
+     * @return this builder, for chaining, never null.
+     */
+    <T> ConfigurationContextBuilder addPropertyConverter(TypeLiteral<T> typeToConvert,
+                                                         PropertyConverter<T> propertyConverter);
+
+    /**
+     * Removes the given PropertyConverter instances.
+     *
+     * @param typeToConvert the type which the converter is for
+     * @param converters    the converters to remove
+     * @return this builder, for chaining, never null.
+     */
+    ConfigurationContextBuilder removePropertyConverters(TypeLiteral<?> typeToConvert,
+                                                         PropertyConverter<?>... converters);
+
+    /**
+     * Removes the given PropertyConverter instances.
+     *
+     * @param typeToConvert the type which the converter is for
+     * @param converters    the converters to remove
+     * @return this builder, for chaining, never null.
+     */
+    ConfigurationContextBuilder removePropertyConverters(TypeLiteral<?> typeToConvert,
+                                                         Collection<PropertyConverter<?>> converters);
+
+    /**
+     * Sets the {@link PropertyValueCombinationPolicy} used to evaluate the final
+     * property values.
+     *
+     * @param policy the {@link PropertyValueCombinationPolicy} used, not null
+     * @return this builder, for chaining, never null.
+     */
+    ConfigurationContextBuilder setPropertyValueCombinationPolicy(PropertyValueCombinationPolicy policy);
+
+    /**
+     * Builds a {@link ConfigurationContext} based on the data set.
+     * @return final context with the current builder's properties.
+     */
+    ConfigurationContext build();
+
+}

http://git-wip-us.apache.org/repos/asf/incubator-tamaya/blob/43468987/modules/builder/src/main/java/org/apache/tamaya/builder/spi/ConfigurationProviderSpi.java
----------------------------------------------------------------------
diff --git a/modules/builder/src/main/java/org/apache/tamaya/builder/spi/ConfigurationProviderSpi.java b/modules/builder/src/main/java/org/apache/tamaya/builder/spi/ConfigurationProviderSpi.java
new file mode 100644
index 0000000..2769d0a
--- /dev/null
+++ b/modules/builder/src/main/java/org/apache/tamaya/builder/spi/ConfigurationProviderSpi.java
@@ -0,0 +1,76 @@
+/*
+ * 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.builder.spi;
+
+import org.apache.tamaya.Configuration;
+
+/**
+ * SPI that must be implemented to provide the component that manages all {@link org.apache.tamaya.Configuration}
+ * instances in a system. In SE this may be a true singleton containing exact one {@link org.apache.tamaya.Configuration}
+ * instance, whereas in Java EE and other more complex environments instances may be returned depending the current
+ * runtime context.
+ */
+public interface ConfigurationProviderSpi {
+
+    /**
+     * Access the current {@link org.apache.tamaya.Configuration}.
+     *
+     * @return the current {@link org.apache.tamaya.Configuration} instance, never null.
+     */
+    Configuration getConfiguration();
+
+    /**
+     * Get access to the current {@link ConfigurationContext}.
+     *
+     * @return the current {@link ConfigurationContext}, never null.
+     * @deprecated Will be removed in favour of {@link Configuration#getContext()}.
+     */
+    @Deprecated
+    ConfigurationContext getConfigurationContext();
+
+    /**
+     * This method allows to replace the current {@link ConfigurationContext} with a new
+     * instance. This can be used to update the context with a new one, e.g. because some of the configuration
+     * data has changed and must be updated. It is the responsibility of the ConfigurationProvider to trigger
+     * corresponding update event for the current {@link ConfigurationContext} or
+     * {@link org.apache.tamaya.Configuration}.
+     *
+     * @param context the new ConfigurationContext to be applied.
+     * @throws java.lang.UnsupportedOperationException if the current provider is read-only.
+     */
+    void setConfigurationContext(ConfigurationContext context);
+
+    /**
+     * Method that allows to determine if a new {@link ConfigurationContext} can be applied
+     * programmatically.
+     *
+     * @return true, if {@link #setConfigurationContext(ConfigurationContext)} is supported
+     * by the current implementation.
+     * @see #setConfigurationContext(ConfigurationContext)
+     */
+    boolean isConfigurationContextSettable();
+
+    /**
+     * Creates a new {@link ConfigurationContextBuilder} instance.
+     *
+     * @return a new {@link ConfigurationContextBuilder}, never null.
+     */
+    ConfigurationContextBuilder getConfigurationContextBuilder();
+
+}

http://git-wip-us.apache.org/repos/asf/incubator-tamaya/blob/43468987/modules/builder/src/main/java/org/apache/tamaya/builder/spi/ConversionContext.java
----------------------------------------------------------------------
diff --git a/modules/builder/src/main/java/org/apache/tamaya/builder/spi/ConversionContext.java b/modules/builder/src/main/java/org/apache/tamaya/builder/spi/ConversionContext.java
new file mode 100644
index 0000000..298e8bc
--- /dev/null
+++ b/modules/builder/src/main/java/org/apache/tamaya/builder/spi/ConversionContext.java
@@ -0,0 +1,255 @@
+/*
+ * 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.builder.spi;
+
+import org.apache.tamaya.Configuration;
+import org.apache.tamaya.TypeLiteral;
+
+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 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 null.
+     */
+    public AnnotatedElement getAnnotatedElement(){
+        return annotatedElement;
+    }
+
+    /**
+     * Get the configuration, which is targeted.
+     * @return the configuration instance, or 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 converter, which implements the formats provided.
+     * @param formatDescriptors the format descriptions in a human readable form, e.g. as regular expressions.
+     */
+    public void addSupportedFormats(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 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 final 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 null.
+         * @param configurationContext configuration context, not null.
+         * @param key the requested key, may be 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 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 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 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 null
+         * @return the builder instance, for chaining
+         */
+        public Builder setAnnotatedElement(AnnotatedElement annotatedElement){
+            this.annotatedElement = Objects.requireNonNull(annotatedElement);
+            return this;
+        }
+
+        /**
+         * Add the formats provided by a {@link PropertyConverter}. This method should be called by each converter
+         * performing/trying conversion, so the user can be given feedback on the supported formats on failure.
+         * @param converterType the converter type, not 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(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/43468987/modules/builder/src/main/java/org/apache/tamaya/builder/spi/Experimental.java
----------------------------------------------------------------------
diff --git a/modules/builder/src/main/java/org/apache/tamaya/builder/spi/Experimental.java b/modules/builder/src/main/java/org/apache/tamaya/builder/spi/Experimental.java
new file mode 100644
index 0000000..bbbbb61
--- /dev/null
+++ b/modules/builder/src/main/java/org/apache/tamaya/builder/spi/Experimental.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.builder.spi;
+
+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.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/43468987/modules/builder/src/main/java/org/apache/tamaya/builder/spi/FilterContext.java
----------------------------------------------------------------------
diff --git a/modules/builder/src/main/java/org/apache/tamaya/builder/spi/FilterContext.java b/modules/builder/src/main/java/org/apache/tamaya/builder/spi/FilterContext.java
new file mode 100644
index 0000000..0c4a838
--- /dev/null
+++ b/modules/builder/src/main/java/org/apache/tamaya/builder/spi/FilterContext.java
@@ -0,0 +1,104 @@
+/*
+ * 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.builder.spi;
+
+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 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, boolean singlePropertyScope) {
+        this.singlePropertyScoped = singlePropertyScope;
+        this.key = Objects.requireNonNull(key);
+        this.configEntries.putAll(configEntries);
+        this.configEntries = Collections.unmodifiableMap(this.configEntries);
+    }
+
+    /**
+     * 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;
+    }
+
+    /**
+     * 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, String> getConfigEntries() {
+        return configEntries;
+    }
+
+    @Override
+    public String toString() {
+        return "FilterContext{key='" + key + "', configEntries=" + configEntries + '}';
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/incubator-tamaya/blob/43468987/modules/builder/src/main/java/org/apache/tamaya/builder/spi/PropertyConverter.java
----------------------------------------------------------------------
diff --git a/modules/builder/src/main/java/org/apache/tamaya/builder/spi/PropertyConverter.java b/modules/builder/src/main/java/org/apache/tamaya/builder/spi/PropertyConverter.java
new file mode 100644
index 0000000..83f6644
--- /dev/null
+++ b/modules/builder/src/main/java/org/apache/tamaya/builder/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.builder.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 multivalued (e.g. collections) or complex if needed.
+ * 
+ * @param <T> the type of the type literal
+ */
+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/43468987/modules/builder/src/main/java/org/apache/tamaya/builder/spi/PropertyFilter.java
----------------------------------------------------------------------
diff --git a/modules/builder/src/main/java/org/apache/tamaya/builder/spi/PropertyFilter.java b/modules/builder/src/main/java/org/apache/tamaya/builder/spi/PropertyFilter.java
new file mode 100644
index 0000000..681f35e
--- /dev/null
+++ b/modules/builder/src/main/java/org/apache/tamaya/builder/spi/PropertyFilter.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.builder.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 ServiceContext}. The ordinal
+ * hereby is defined by the corresponding {@code @Priority} annotation.</p>
+ * <p>Filters </p>
+ */
+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 null.
+     * @return the filtered value, or {@code null} if the value should be removed alltogether.
+     */
+    String filterProperty(String value, FilterContext context);
+
+}

http://git-wip-us.apache.org/repos/asf/incubator-tamaya/blob/43468987/modules/builder/src/main/java/org/apache/tamaya/builder/spi/PropertySource.java
----------------------------------------------------------------------
diff --git a/modules/builder/src/main/java/org/apache/tamaya/builder/spi/PropertySource.java b/modules/builder/src/main/java/org/apache/tamaya/builder/spi/PropertySource.java
new file mode 100644
index 0000000..91added
--- /dev/null
+++ b/modules/builder/src/main/java/org/apache/tamaya/builder/spi/PropertySource.java
@@ -0,0 +1,158 @@
+/*
+* 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.builder.spi;
+
+
+import java.util.Collections;
+import java.util.Map;
+
+
+/**
+ * <p>This interface models a provider that serves configuration properties. The contained
+ * properties may be read fromMap 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
+ * META-INF/services/PropertySource
+ * </p>
+ * <p>
+ * If you like to register multiple PropertySources at the same time
+ * you can use the {@link 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, String> getProperties() {
+            return Collections.emptyMap();
+        }
+
+        @Override
+        public boolean isScannable() {
+            return false;
+        }
+
+        @Override
+        public String toString(){
+            return "PropertySource.EMPTY";
+        }
+    };
+
+
+    /**
+     * Lookup order:
+     * TODO rethink whole default PropertySources and ordering:
+     * TODO introduce default values or constants for ordinals
+     * <ol>
+     *     <li>System properties (ordinal 400)</li>
+     *     <li>Environment properties (ordinal 300)</li>
+     *     <li>JNDI values (ordinal 200)</li>
+     *     <li>Properties file values (/META-INF/applicationConfiguration.properties) (ordinal 100)</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; 400
+     * </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; 400. That means, you have to add e.g. deltaspike_ordinal=401 to
+     * /META-INF/apache-deltaspike.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>
+     *
+     * @return the 'importance' aka ordinal of the configured values. The higher, the more important.
+     * //X TODO think about making this a default method which returns default priority
+     */
+    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 null.
+     */
+    String getName();
+
+    /**
+     * Access a property.
+     *
+     * @param key the property's key, not 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 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.
+     */
+    Map<String,String> 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 can e.g. 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 should not be scanned.
+     */
+    boolean isScannable();
+
+}

http://git-wip-us.apache.org/repos/asf/incubator-tamaya/blob/43468987/modules/builder/src/main/java/org/apache/tamaya/builder/spi/PropertySourceProvider.java
----------------------------------------------------------------------
diff --git a/modules/builder/src/main/java/org/apache/tamaya/builder/spi/PropertySourceProvider.java b/modules/builder/src/main/java/org/apache/tamaya/builder/spi/PropertySourceProvider.java
new file mode 100644
index 0000000..91decf7
--- /dev/null
+++ b/modules/builder/src/main/java/org/apache/tamaya/builder/spi/PropertySourceProvider.java
@@ -0,0 +1,60 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.tamaya.builder.spi;
+
+import java.util.Collection;
+import java.util.Collections;
+
+/**
+ * <p>Implement this interfaces to provide a PropertySource provider which
+ * is able to register 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/PropertySourceProvider</p>
+ */
+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/43468987/modules/builder/src/main/java/org/apache/tamaya/builder/spi/PropertyValue.java
----------------------------------------------------------------------
diff --git a/modules/builder/src/main/java/org/apache/tamaya/builder/spi/PropertyValue.java b/modules/builder/src/main/java/org/apache/tamaya/builder/spi/PropertyValue.java
new file mode 100644
index 0000000..a0b0bd0
--- /dev/null
+++ b/modules/builder/src/main/java/org/apache/tamaya/builder/spi/PropertyValue.java
@@ -0,0 +1,117 @@
+/*
+ * 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.builder.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. 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;
+    /** Additional metadata provided by the provider. */
+    private Map<String,String> configEntries = new HashMap<>();
+
+    PropertyValue(PropertyValueBuilder builder){
+        this.key = builder.key;
+        if(builder.contextData!=null) {
+            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."));
+    }
+
+    /**
+     * 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 configEntries.get(key);
+    }
+
+    /**
+     * 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, 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 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);
+    }
+
+    /**
+     * 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/43468987/modules/builder/src/main/java/org/apache/tamaya/builder/spi/PropertyValueBuilder.java
----------------------------------------------------------------------
diff --git a/modules/builder/src/main/java/org/apache/tamaya/builder/spi/PropertyValueBuilder.java b/modules/builder/src/main/java/org/apache/tamaya/builder/spi/PropertyValueBuilder.java
new file mode 100644
index 0000000..791d182
--- /dev/null
+++ b/modules/builder/src/main/java/org/apache/tamaya/builder/spi/PropertyValueBuilder.java
@@ -0,0 +1,103 @@
+/*
+ * 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.builder.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 = new HashMap<>();
+
+    /**
+     * Create a new builder instance, for a given set of parameters.
+     * @param key to access a property value.
+     * @param value the value, not null. If a value is null {@link PropertySource#get(String)} should return
+     * {@code null}.
+     * @param source property source.
+     */
+    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));
+    }
+
+    /**
+     * 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) {
+        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) {
+        this.contextData.put("_"+this.key+'.'+key, String.valueOf(Objects.requireNonNull(value, "Meta value is null.")));
+        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{" +
+                "key='" + key + '\'' +
+                "value='" + value + '\'' +
+                ", contextData=" + contextData +
+                '}';
+    }
+}

http://git-wip-us.apache.org/repos/asf/incubator-tamaya/blob/43468987/modules/builder/src/main/java/org/apache/tamaya/builder/spi/PropertyValueCombinationPolicy.java
----------------------------------------------------------------------
diff --git a/modules/builder/src/main/java/org/apache/tamaya/builder/spi/PropertyValueCombinationPolicy.java b/modules/builder/src/main/java/org/apache/tamaya/builder/spi/PropertyValueCombinationPolicy.java
new file mode 100644
index 0000000..9eac1f8
--- /dev/null
+++ b/modules/builder/src/main/java/org/apache/tamaya/builder/spi/PropertyValueCombinationPolicy.java
@@ -0,0 +1,66 @@
+/*
+ * 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.builder.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
+ * where the default overriding policy as implemented in {@link #DEFAULT_OVERRIDING_COLLECTOR} 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_COLLECTOR = new PropertyValueCombinationPolicy(){
+
+        @Override
+        public Map<String,String> collect(Map<String,String> currentValue, String key, PropertySource propertySource) {
+            PropertyValue value = propertySource.get(key);
+            return value!=null?value.getConfigEntries():currentValue;
+        }
+
+    };
+
+    /**
+     * 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.
+     */
+    Map<String,String> collect(Map<String,String> currentValue, String key, PropertySource propertySource);
+
+}

http://git-wip-us.apache.org/repos/asf/incubator-tamaya/blob/43468987/modules/builder/src/main/java/org/apache/tamaya/builder/spi/ServiceContext.java
----------------------------------------------------------------------
diff --git a/modules/builder/src/main/java/org/apache/tamaya/builder/spi/ServiceContext.java b/modules/builder/src/main/java/org/apache/tamaya/builder/spi/ServiceContext.java
new file mode 100644
index 0000000..9fbfce8
--- /dev/null
+++ b/modules/builder/src/main/java/org/apache/tamaya/builder/spi/ServiceContext.java
@@ -0,0 +1,59 @@
+/*
+ * 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.builder.spi;
+
+import java.util.List;
+
+
+/**
+ * This class models the component that is managing the lifecycle current the
+ * services used by the Configuration API.
+ */
+public interface ServiceContext {
+
+    /**
+     * @return ordinal of the ServiceContext. The one with the highest ordinal will be taken.
+     */
+    int ordinal();
+
+    /**
+     * Access a service singleton via its type.
+     * If multiple implementations for the very serviceType exist then
+     * the one with the highest {@link javax.annotation.Priority} will be used.
+     *
+     * @param <T> the type of the service type.
+     * @param serviceType the service type.
+     * @return The instance to be used, or {@code null}
+     * @throws org.apache.tamaya.ConfigException if there are multiple service implementations with the maximum priority.
+     */
+    <T> T getService(Class<T> serviceType);
+
+    /**
+     * Access a list current services, given its type. The bootstrap mechanism should
+     * order the instance for precedence, hereby the most significant should be
+     * first in order.
+     *
+     * @param serviceType
+     *            the service type.
+     * @param <T> the type of the list element returned by this method
+     * @return The instance to be used, never {@code null}
+     */
+     <T> List<T> getServices(Class<T> serviceType);
+
+}

http://git-wip-us.apache.org/repos/asf/incubator-tamaya/blob/43468987/modules/builder/src/main/java/org/apache/tamaya/builder/spi/ServiceContextManager.java
----------------------------------------------------------------------
diff --git a/modules/builder/src/main/java/org/apache/tamaya/builder/spi/ServiceContextManager.java b/modules/builder/src/main/java/org/apache/tamaya/builder/spi/ServiceContextManager.java
new file mode 100644
index 0000000..3d0e136
--- /dev/null
+++ b/modules/builder/src/main/java/org/apache/tamaya/builder/spi/ServiceContextManager.java
@@ -0,0 +1,118 @@
+/*
+ * 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.builder.spi;
+
+import java.util.Objects;
+import java.util.ServiceLoader;
+import java.util.logging.Level;
+import java.util.logging.Logger;
+
+import org.apache.tamaya.ConfigException;
+
+
+/**
+ * This singleton provides access to the services available in the current {@link ServiceContext}. The
+ * behaviour can be adapted, by calling {@link ServiceContextManager#set(ServiceContext)} before accessing any
+ * services.
+ */
+public final class ServiceContextManager {
+
+    /** The logger used. */
+    private static final Logger LOG = Logger.getLogger(ServiceContextManager.class.getName());
+
+    /**
+     * The ServiceProvider used.
+     */
+    private static volatile ServiceContext serviceContextProviderDelegate;
+
+    /**
+     * Private singletons constructor.
+     */
+    private ServiceContextManager() {
+    }
+
+    /**
+     * Load the {@link ServiceContext} to be used.
+     *
+     * @return {@link ServiceContext} to be used for loading the services.
+     */
+    private static ServiceContext loadDefaultServiceProvider() {
+        ServiceContext highestServiceContext = null;
+        try {
+            int highestOrdinal = 0;
+            for (ServiceContext serviceContext : ServiceLoader.load(ServiceContext.class)) {
+                if(highestServiceContext==null){
+                    highestServiceContext = serviceContext;
+                }else if (serviceContext.ordinal() > highestOrdinal) {
+                    highestServiceContext = serviceContext;
+                    highestOrdinal = serviceContext.ordinal();
+                }
+            }
+        } catch (Exception e) {
+            throw new ConfigException("ServiceContext not loadable", e);
+        }
+        if (highestServiceContext==null){
+            throw new ConfigException("No ServiceContext found");
+        }
+        LOG.info("Using Service Context of type: " + highestServiceContext.getClass().getName());
+        return highestServiceContext;
+    }
+
+    /**
+     * Replace the current {@link ServiceContext} in use.
+     *
+     * @param serviceContextProvider the new {@link ServiceContext}, not null.
+     * @return the currently used context after setting it.
+     */
+    public static ServiceContext set(ServiceContext serviceContextProvider) {
+        ServiceContext currentContext = ServiceContextManager.serviceContextProviderDelegate;
+        Objects.requireNonNull(serviceContextProvider);
+
+        synchronized (ServiceContextManager.class) {
+            if (ServiceContextManager.serviceContextProviderDelegate == null) {
+                ServiceContextManager.serviceContextProviderDelegate = serviceContextProvider;
+                LOG.log(Level.INFO, "Using ServiceProvider: " + serviceContextProvider.getClass().getName());
+            } else {
+                LOG.log(Level.WARNING, "Replacing ServiceProvider " +
+                                ServiceContextManager.serviceContextProviderDelegate.getClass().getName() +
+                                " with: " + serviceContextProvider.getClass().getName());
+                ServiceContextManager.serviceContextProviderDelegate = serviceContextProvider;
+            }
+        }
+
+        return currentContext;
+    }
+
+    /**
+     * Ge {@link ServiceContext}. If necessary the {@link ServiceContext} will be laziliy loaded.
+     *
+     * @return the {@link ServiceContext} used.
+     */
+    public static ServiceContext getServiceContext() {
+        if (serviceContextProviderDelegate == null) {
+            synchronized (ServiceContextManager.class) {
+                if (serviceContextProviderDelegate == null) {
+                    serviceContextProviderDelegate = loadDefaultServiceProvider();
+                }
+            }
+        }
+        return serviceContextProviderDelegate;
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/incubator-tamaya/blob/43468987/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 07a72c5..54cab63 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
@@ -21,6 +21,7 @@ package org.apache.tamaya.builder;
 import org.apache.tamaya.ConfigException;
 import org.apache.tamaya.Configuration;
 import org.apache.tamaya.TypeLiteral;
+import org.apache.tamaya.builder.spi.*;
 import org.apache.tamaya.builder.util.types.CustomTypeA;
 import org.apache.tamaya.builder.util.types.CustomTypeB;
 import org.apache.tamaya.builder.util.types.CustomTypeC;

http://git-wip-us.apache.org/repos/asf/incubator-tamaya/blob/43468987/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 896e0bc..a2cc32d 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,8 +18,8 @@
  */
 package org.apache.tamaya.builder;
 
-import org.apache.tamaya.spi.FilterContext;
-import org.apache.tamaya.spi.PropertyFilter;
+import org.apache.tamaya.builder.spi.FilterContext;
+import org.apache.tamaya.builder.spi.PropertyFilter;
 
 public class TestANonSPIPropertyFilter implements PropertyFilter {
     @Override

http://git-wip-us.apache.org/repos/asf/incubator-tamaya/blob/43468987/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 a9c0ac2..78ddad3 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,8 +18,8 @@
  */
 package org.apache.tamaya.builder;
 
-import org.apache.tamaya.spi.FilterContext;
-import org.apache.tamaya.spi.PropertyFilter;
+import org.apache.tamaya.builder.spi.FilterContext;
+import org.apache.tamaya.builder.spi.PropertyFilter;
 
 public class TestBNonSPIPropertyFilter implements PropertyFilter {
     @Override

http://git-wip-us.apache.org/repos/asf/incubator-tamaya/blob/43468987/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 e22fca8..3b9a22b 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,8 +18,8 @@
  */
 package org.apache.tamaya.builder;
 
-import org.apache.tamaya.spi.FilterContext;
-import org.apache.tamaya.spi.PropertyFilter;
+import org.apache.tamaya.builder.spi.FilterContext;
+import org.apache.tamaya.builder.spi.PropertyFilter;
 
 public class TestPropertyFilter implements PropertyFilter {
     @Override

http://git-wip-us.apache.org/repos/asf/incubator-tamaya/blob/43468987/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 f1ebfea..8a0de2b 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
@@ -18,9 +18,8 @@
  */
 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 org.apache.tamaya.builder.propertysource.BasePropertySource;
+import org.apache.tamaya.builder.spi.PropertyValue;
 
 import java.util.Collections;
 import java.util.Hashtable;

http://git-wip-us.apache.org/repos/asf/incubator-tamaya/blob/43468987/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 5a2f400..a493ec3 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
@@ -18,10 +18,10 @@
  */
 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 org.apache.tamaya.builder.propertysource.BasePropertySource;
+import org.apache.tamaya.builder.spi.PropertySource;
+import org.apache.tamaya.builder.spi.PropertySourceProvider;
+import org.apache.tamaya.builder.spi.PropertyValue;
 
 import java.util.ArrayList;
 import java.util.Collection;

http://git-wip-us.apache.org/repos/asf/incubator-tamaya/blob/43468987/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 9cfe725..ab3eb33 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
@@ -18,10 +18,10 @@
  */
 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 org.apache.tamaya.builder.propertysource.BasePropertySource;
+import org.apache.tamaya.builder.spi.PropertySource;
+import org.apache.tamaya.builder.spi.PropertySourceProvider;
+import org.apache.tamaya.builder.spi.PropertyValue;
 
 import java.util.ArrayList;
 import java.util.Collection;

http://git-wip-us.apache.org/repos/asf/incubator-tamaya/blob/43468987/modules/builder/src/test/java/org/apache/tamaya/builder/internal/A.java
----------------------------------------------------------------------
diff --git a/modules/builder/src/test/java/org/apache/tamaya/builder/internal/A.java b/modules/builder/src/test/java/org/apache/tamaya/builder/internal/A.java
new file mode 100644
index 0000000..aaab601
--- /dev/null
+++ b/modules/builder/src/test/java/org/apache/tamaya/builder/internal/A.java
@@ -0,0 +1,29 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.tamaya.core.internal;
+
+/**
+ * Test class for testing transitively evaluated property converters.
+ */
+class A implements AutoCloseable{
+    @Override
+    public void close() throws Exception {
+
+    }
+}

http://git-wip-us.apache.org/repos/asf/incubator-tamaya/blob/43468987/modules/builder/src/test/java/org/apache/tamaya/builder/internal/B.java
----------------------------------------------------------------------
diff --git a/modules/builder/src/test/java/org/apache/tamaya/builder/internal/B.java b/modules/builder/src/test/java/org/apache/tamaya/builder/internal/B.java
new file mode 100644
index 0000000..31bafb6
--- /dev/null
+++ b/modules/builder/src/test/java/org/apache/tamaya/builder/internal/B.java
@@ -0,0 +1,29 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.tamaya.core.internal;
+
+/**
+ * Test class for testing transitively evaluated property converters.
+ */
+public class B extends A implements Runnable{
+    @Override
+    public void run() {
+
+    }
+}

http://git-wip-us.apache.org/repos/asf/incubator-tamaya/blob/43468987/modules/builder/src/test/java/org/apache/tamaya/builder/internal/C.java
----------------------------------------------------------------------
diff --git a/modules/builder/src/test/java/org/apache/tamaya/builder/internal/C.java b/modules/builder/src/test/java/org/apache/tamaya/builder/internal/C.java
new file mode 100644
index 0000000..fdd3476
--- /dev/null
+++ b/modules/builder/src/test/java/org/apache/tamaya/builder/internal/C.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.core.internal;
+
+import java.io.IOException;
+import java.nio.CharBuffer;
+
+/**
+ * Test class for testing transitively evaluated property converters.
+ */
+public class C extends B implements Readable{
+
+    private final String inValue;
+
+    public C(String inValue){
+        this.inValue = inValue;
+    }
+
+    @Override
+    public int read(CharBuffer cb) throws IOException {
+        return 0;
+    }
+
+    /**
+     * Returns the input value, set on creation. Used for test assertion.
+     * @return the in value.
+     */
+    public String getInValue() {
+        return inValue;
+    }
+
+    @Override
+    public String toString() {
+        return "C{" +
+                "inValue='" + inValue + '\'' +
+                '}';
+    }
+
+
+}

http://git-wip-us.apache.org/repos/asf/incubator-tamaya/blob/43468987/modules/builder/src/test/java/org/apache/tamaya/builder/internal/CTestConverter.java
----------------------------------------------------------------------
diff --git a/modules/builder/src/test/java/org/apache/tamaya/builder/internal/CTestConverter.java b/modules/builder/src/test/java/org/apache/tamaya/builder/internal/CTestConverter.java
new file mode 100644
index 0000000..159600c
--- /dev/null
+++ b/modules/builder/src/test/java/org/apache/tamaya/builder/internal/CTestConverter.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.core.internal;
+
+import org.apache.tamaya.builder.spi.ConversionContext;
+import org.apache.tamaya.builder.spi.PropertyConverter;
+
+/**
+ * Created by Anatole on 13.06.2015.
+ */
+public class CTestConverter implements PropertyConverter<C>{
+    @Override
+    public C convert(String value, ConversionContext context) {
+        return new C(value);
+    }
+}

http://git-wip-us.apache.org/repos/asf/incubator-tamaya/blob/43468987/modules/builder/src/test/java/org/apache/tamaya/builder/internal/DefaultServiceContextTest.java
----------------------------------------------------------------------
diff --git a/modules/builder/src/test/java/org/apache/tamaya/builder/internal/DefaultServiceContextTest.java b/modules/builder/src/test/java/org/apache/tamaya/builder/internal/DefaultServiceContextTest.java
new file mode 100644
index 0000000..e1fb048
--- /dev/null
+++ b/modules/builder/src/test/java/org/apache/tamaya/builder/internal/DefaultServiceContextTest.java
@@ -0,0 +1,139 @@
+/*
+ * 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.core.internal;
+
+import org.apache.tamaya.ConfigException;
+import org.apache.tamaya.builder.spi.ConfigurationProviderSpi;
+import org.junit.Assert;
+import org.junit.Test;
+
+import javax.annotation.Priority;
+import java.util.Collection;
+
+public class DefaultServiceContextTest {
+
+    /**
+     * context to test
+     */
+    private final DefaultServiceContext context = new DefaultServiceContext();
+
+
+    @Test
+    public void testGetService() {
+        ConfigurationProviderSpi providerSpi = context.getService(ConfigurationProviderSpi.class);
+        Assert.assertNotNull(providerSpi);
+        Assert.assertTrue(providerSpi instanceof DefaultConfigurationProvider);
+    }
+
+    @Test(expected = ConfigException.class)
+    public void testGetService_multipleServicesWithoutPriority_shouldThrowConfigException() {
+        context.getService(InvalidPriorityInterface.class);
+    }
+
+    @Test
+    public void testGetService_multipleService_shouldReturnServiceWithHighestPriority() {
+        MultiImplsInterface service = context.getService(MultiImplsInterface.class);
+
+        Assert.assertNotNull(service);
+        Assert.assertTrue(service instanceof MultiImpl2);
+    }
+
+    @Test
+    public void testGetService_noImpl_shouldReturnEmptyOpional() {
+        NoImplInterface service = context.getService(NoImplInterface.class);
+        Assert.assertNull(service);
+    }
+
+
+    @Test
+    public void testGetServices_shouldReturnServices() {
+        {
+            Collection<InvalidPriorityInterface> services = context.getServices(InvalidPriorityInterface.class);
+            Assert.assertNotNull(services);
+            Assert.assertEquals(2, services.size());
+
+            for (InvalidPriorityInterface service : services) {
+                Assert.assertTrue(service instanceof InvalidPriorityImpl1 || service instanceof InvalidPriorityImpl2);
+            }
+        }
+
+        {
+            Collection<MultiImplsInterface> services = context.getServices(MultiImplsInterface.class);
+            Assert.assertNotNull(services);
+            Assert.assertEquals(3, services.size());
+
+            for (MultiImplsInterface service : services) {
+                Assert.assertTrue(service instanceof MultiImpl1 ||
+                                          service instanceof MultiImpl2 ||
+                                          service instanceof MultiImpl3);
+            }
+        }
+    }
+
+    @Test
+    public void testGetServices_redundantAccessToServices() {
+        for(int i=0;i<10;i++){
+            Collection<InvalidPriorityInterface> services = context.getServices(InvalidPriorityInterface.class);
+            Assert.assertNotNull(services);
+            Assert.assertEquals(2, services.size());
+            for (InvalidPriorityInterface service : services) {
+                Assert.assertTrue(service instanceof InvalidPriorityImpl1 || service instanceof InvalidPriorityImpl2);
+            }
+        }
+    }
+
+    @Test
+    public void testGetServices_noImpl_shouldReturnEmptyList() {
+        Collection<NoImplInterface> services = context.getServices(NoImplInterface.class);
+        Assert.assertNotNull(services);
+        Assert.assertTrue(services.isEmpty());
+    }
+
+
+    // some test interfaces and classes
+
+    public interface InvalidPriorityInterface {
+    }
+
+    @Priority(value = 50)
+    public static class InvalidPriorityImpl1 implements InvalidPriorityInterface {
+    }
+
+    @Priority(value = 50)
+    public static class InvalidPriorityImpl2 implements InvalidPriorityInterface {
+    }
+
+
+    public interface MultiImplsInterface {
+    }
+
+    public static class MultiImpl1 implements MultiImplsInterface {
+    }
+
+    @Priority(value = 500)
+    public static class MultiImpl2 implements MultiImplsInterface {
+    }
+
+    @Priority(value = -10)
+    public static class MultiImpl3 implements MultiImplsInterface {
+    }
+
+    private interface NoImplInterface {
+    }
+}


Mime
View raw message