tamaya-commits mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From anat...@apache.org
Subject [6/9] incubator-tamaya git commit: TAMAYA-19: Code cleanup.
Date Sat, 06 Dec 2014 01:03:28 GMT
http://git-wip-us.apache.org/repos/asf/incubator-tamaya/blob/0eef8f37/core/src/main/java/org/apache/tamaya/core/internal/SubtractingPropertyProvider.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/tamaya/core/internal/SubtractingPropertyProvider.java b/core/src/main/java/org/apache/tamaya/core/internal/SubtractingPropertyProvider.java
deleted file mode 100644
index 9a76cdc..0000000
--- a/core/src/main/java/org/apache/tamaya/core/internal/SubtractingPropertyProvider.java
+++ /dev/null
@@ -1,76 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements.  See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership.  The ASF licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License.  You may obtain a copy of the License at
- *
- *   http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing,
- * software distributed under the License is distributed on an
- * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- * KIND, either express or implied.  See the License for the
- * specific language governing permissions and limitations
- * under the License.
- */
-package org.apache.tamaya.core.internal;
-
-import org.apache.tamaya.ConfigChangeSet;
-import org.apache.tamaya.MetaInfoBuilder;
-import org.apache.tamaya.PropertyProvider;
-import org.apache.tamaya.core.properties.AbstractPropertyProvider;
-
-import java.util.*;
-import java.util.stream.Collectors;
-
-class SubtractingPropertyProvider extends AbstractPropertyProvider {
-
-    private static final long serialVersionUID = 4301042530074932562L;
-    private PropertyProvider unit;
-    private List<PropertyProvider> subtrahends;
-
-    public SubtractingPropertyProvider(PropertyProvider configuration, List<PropertyProvider> subtrahends){
-        super(MetaInfoBuilder.of(configuration.getMetaInfo()).setType("sutracted").build());
-        Objects.requireNonNull(configuration);
-        this.unit = configuration;
-        this.subtrahends = new ArrayList<>(subtrahends);
-    }
-
-    private boolean filter(Map.Entry<String,String> entry){
-        for(PropertyProvider prov: subtrahends){
-            if(prov.containsKey(entry.getKey())){
-                return false;
-            }
-        }
-        return true;
-    }
-
-    @Override
-    public Map<String,String> toMap(){
-        return this.unit.toMap().entrySet().stream().filter(this::filter).collect(Collectors.toMap(
-                (en) -> en.getKey(),
-                (en) -> en.getValue()
-        ));
-    }
-
-    @Override
-    public ConfigChangeSet load(){
-        unit.load();
-        return super.load();
-    }
-
-    /**
-     * Apply a config change to this item. Hereby the change must be related to the same instance.
-     * @param change the config change
-     * @throws org.apache.tamaya.ConfigException if an unrelated change was passed.
-     * @throws UnsupportedOperationException when the configuration is not writable.
-     */
-    @Override
-    public void apply(ConfigChangeSet change){
-        this.unit.apply(change);
-    }
-
-}

http://git-wip-us.apache.org/repos/asf/incubator-tamaya/blob/0eef8f37/core/src/main/java/org/apache/tamaya/core/internal/SystemPropertiesPropertyProvider.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/tamaya/core/internal/SystemPropertiesPropertyProvider.java b/core/src/main/java/org/apache/tamaya/core/internal/SystemPropertiesPropertyProvider.java
deleted file mode 100644
index 3f3760a..0000000
--- a/core/src/main/java/org/apache/tamaya/core/internal/SystemPropertiesPropertyProvider.java
+++ /dev/null
@@ -1,53 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements.  See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership.  The ASF licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License.  You may obtain a copy of the License at
- *
- *   http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing,
- * software distributed under the License is distributed on an
- * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- * KIND, either express or implied.  See the License for the
- * specific language governing permissions and limitations
- * under the License.
- */
-package org.apache.tamaya.core.internal;
-
-import org.apache.tamaya.MetaInfoBuilder;
-import org.apache.tamaya.core.env.ConfiguredSystemProperties;
-import org.apache.tamaya.core.properties.AbstractPropertyProvider;
-
-import java.util.Collections;
-import java.util.HashMap;
-import java.util.Map;
-import java.util.Properties;
-
-class SystemPropertiesPropertyProvider extends AbstractPropertyProvider {
-
-
-    private static final long serialVersionUID = -5935940312707001199L;
-
-    public SystemPropertiesPropertyProvider(){
-        super(MetaInfoBuilder.of().setType("sys-properties").build());
-    }
-
-    @Override
-    public Map<String,String> toMap(){
-        Properties sysProps = System.getProperties();
-        if(sysProps instanceof ConfiguredSystemProperties){
-            sysProps = ((ConfiguredSystemProperties)sysProps).getInitialProperties();
-        }
-        Map<String,String> props = new HashMap<>();
-        for (Map.Entry<Object,Object> en : sysProps.entrySet()) {
-            props.put(en.getKey().toString(), en.getValue().toString());
-        }
-        return Collections.unmodifiableMap(props);
-    }
-
-
-}

http://git-wip-us.apache.org/repos/asf/incubator-tamaya/blob/0eef8f37/core/src/main/java/org/apache/tamaya/core/internal/UriBasedPropertyProvider.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/tamaya/core/internal/UriBasedPropertyProvider.java b/core/src/main/java/org/apache/tamaya/core/internal/UriBasedPropertyProvider.java
deleted file mode 100644
index 5f006fc..0000000
--- a/core/src/main/java/org/apache/tamaya/core/internal/UriBasedPropertyProvider.java
+++ /dev/null
@@ -1,83 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements.  See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership.  The ASF licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License.  You may obtain a copy of the License at
- *
- *   http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing,
- * software distributed under the License is distributed on an
- * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- * KIND, either express or implied.  See the License for the
- * specific language governing permissions and limitations
- * under the License.
- */
-package org.apache.tamaya.core.internal;
-
-import org.apache.tamaya.AggregationPolicy;
-import org.apache.tamaya.ConfigException;
-import org.apache.tamaya.MetaInfo;
-import org.apache.tamaya.MetaInfoBuilder;
-import org.apache.tamaya.core.config.ConfigurationFormats;
-import org.apache.tamaya.core.properties.AbstractPropertyProvider;
-import org.apache.tamaya.core.spi.ConfigurationFormat;
-
-import java.net.URI;
-import java.util.*;
-
-/**
- * Created by Anatole on 16.10.2014.
- */
-final class URIBasedPropertyProvider extends AbstractPropertyProvider {
-
-    private List<URI> uris = new ArrayList<>();
-    private Map<String,String> properties = new HashMap<>();
-    private AggregationPolicy aggregationPolicy;
-
-    public URIBasedPropertyProvider(MetaInfo metaInfo, List<URI> uris, AggregationPolicy aggregationPolicy) {
-        super(metaInfo);
-        this.uris.addAll(Objects.requireNonNull(uris));
-        this.aggregationPolicy = Objects.requireNonNull(aggregationPolicy);
-        init();
-    }
-
-    private void init(){
-        List<String> sources = new ArrayList<>();
-        for(URI uri : uris){
-            ConfigurationFormat format = ConfigurationFormats.getFormat(uri);
-            if(format != null){
-                try{
-                    Map<String, String> read = format.readConfiguration(uri);
-                    sources.add(uri.toString());
-                    read.forEach((k, v) -> {
-                        String newValue = aggregationPolicy.aggregate(k, properties.get(k), v);
-                        if(newValue==null) {
-                            properties.remove(k);
-                        }
-                        else {
-                            properties.put(k, newValue);
-                        }
-                    });
-                }
-                catch(ConfigException e){
-                    throw e;
-                }
-                catch(Exception e){
-                    e.printStackTrace();
-                }
-            }
-        }
-        MetaInfoBuilder metaInfoBuilder = MetaInfoBuilder.of(getMetaInfo());
-        metaInfo = metaInfoBuilder
-                .setSources(sources.toString()).build();
-    }
-
-    @Override
-    public Map<String, String> toMap() {
-        return properties;
-    }
-}

http://git-wip-us.apache.org/repos/asf/incubator-tamaya/blob/0eef8f37/core/src/main/java/org/apache/tamaya/core/internal/WeakConfigListenerManager.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/tamaya/core/internal/WeakConfigListenerManager.java b/core/src/main/java/org/apache/tamaya/core/internal/WeakConfigListenerManager.java
deleted file mode 100644
index 5fb3241..0000000
--- a/core/src/main/java/org/apache/tamaya/core/internal/WeakConfigListenerManager.java
+++ /dev/null
@@ -1,104 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements.  See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership.  The ASF licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License.  You may obtain a copy of the License at
- *
- *   http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing,
- * software distributed under the License is distributed on an
- * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- * KIND, either express or implied.  See the License for the
- * specific language governing permissions and limitations
- * under the License.
- */
-package org.apache.tamaya.core.internal;
-
-import org.apache.tamaya.core.properties.Store;
-
-
-import java.beans.PropertyChangeEvent;
-import java.beans.PropertyChangeListener;
-import java.util.Map;
-import java.util.concurrent.ConcurrentHashMap;
-import java.util.logging.Level;
-import java.util.logging.Logger;
-
-/**
- * Simple listener container that only holds weak references on the listeners.
- */
-public class WeakConfigListenerManager{
-
-    private static final Logger LOG = Logger.getLogger(WeakConfigListenerManager.class.getName());
-    private Map<String,Store<PropertyChangeListener>> changeListeners = new ConcurrentHashMap<>();
-
-
-    private void addPropertyChangeListener(PropertyChangeListener l, String... configIds){
-        for(String configId : configIds){
-            Store<PropertyChangeListener> items = changeListeners.get(configId);
-            if(items != null){
-                synchronized(items){
-                    items.add(l);
-                }
-            }
-        }
-    }
-
-    private void removePropertyChangeListener(PropertyChangeListener l, String... configIds){
-        for(String configId : configIds){
-            Store<PropertyChangeListener> items = changeListeners.get(configId);
-            if(items != null){
-                items.remove(l);
-            }
-        }
-    }
-
-    private void publishPropertyChangeEventToGlobalListeners(PropertyChangeEvent evt){
-        Store<PropertyChangeListener> items = changeListeners.get("_globalConfigChangeListeners");
-        if(items != null){
-            synchronized(items){
-                for(PropertyChangeListener l : items){
-                    try{
-                        l.propertyChange(evt);
-                    }
-                    catch(Exception e){
-                        LOG.log(Level.SEVERE, e, () -> "Error thrown by PropertyChangeListener: " + l);
-                    }
-                }
-
-            }
-        }
-    }
-
-
-    public void publishPropertyChangeEvent(PropertyChangeEvent evt, String configId){
-        Store<PropertyChangeListener> items = changeListeners.get(configId);
-        if(items != null){
-            synchronized(items){
-                for(PropertyChangeListener l : items){
-                    try{
-                        l.propertyChange(evt);
-                    }
-                    catch(Exception e){
-                        LOG.log(Level.SEVERE, e, () -> "Error thrown by ConfigChangeListener: " + l);
-                    }
-                }
-
-            }
-        }
-        publishPropertyChangeEventToGlobalListeners(evt);
-    }
-
-
-    @Override
-    public String toString(){
-        return "WeakConfigListenerManager{" +
-                "changeListeners=" + changeListeners +
-                '}';
-    }
-
-}

http://git-wip-us.apache.org/repos/asf/incubator-tamaya/blob/0eef8f37/core/src/main/java/org/apache/tamaya/core/internal/config/ConfigTemplateInvocationHandler.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/tamaya/core/internal/config/ConfigTemplateInvocationHandler.java b/core/src/main/java/org/apache/tamaya/core/internal/config/ConfigTemplateInvocationHandler.java
new file mode 100644
index 0000000..ef9de86
--- /dev/null
+++ b/core/src/main/java/org/apache/tamaya/core/internal/config/ConfigTemplateInvocationHandler.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.core.internal.config;
+
+import org.apache.tamaya.Configuration;
+import org.apache.tamaya.core.internal.inject.ConfiguredType;
+
+import java.lang.reflect.InvocationHandler;
+import java.lang.reflect.Method;
+import java.util.Objects;
+
+/**
+ * Created by Anatole on 17.10.2014.
+ */
+class ConfigTemplateInvocationHandler implements InvocationHandler {
+
+    private Configuration config;
+    private ConfiguredType type;
+
+    public ConfigTemplateInvocationHandler(Class<?> type, Configuration config) {
+        this.config = Objects.requireNonNull(config);
+        this.type = new ConfiguredType(Objects.requireNonNull(type));
+        if(!type.isInterface()){
+            throw new IllegalArgumentException("Can only proxy interfaces as configuration templates.");
+        }
+    }
+
+    @Override
+    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
+        if("toString".equals(method.getName())){
+            return "Configured Proxy -> " + this.type.getType().getName();
+        }
+        return this.type.getConfiguredValue(method, args);
+    }
+}

http://git-wip-us.apache.org/repos/asf/incubator-tamaya/blob/0eef8f37/core/src/main/java/org/apache/tamaya/core/internal/config/DefaultConfigurationManagerSingletonSpi.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/tamaya/core/internal/config/DefaultConfigurationManagerSingletonSpi.java b/core/src/main/java/org/apache/tamaya/core/internal/config/DefaultConfigurationManagerSingletonSpi.java
new file mode 100644
index 0000000..6aa41ad
--- /dev/null
+++ b/core/src/main/java/org/apache/tamaya/core/internal/config/DefaultConfigurationManagerSingletonSpi.java
@@ -0,0 +1,151 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.tamaya.core.internal.config;
+
+import org.apache.tamaya.PropertyProviderBuilder;
+import org.apache.tamaya.core.internal.el.DefaultExpressionEvaluator;
+import org.apache.tamaya.core.internal.inject.ConfigurationInjector;
+import org.apache.tamaya.core.spi.ConfigurationProviderSpi;
+import org.apache.tamaya.core.spi.ExpressionEvaluator;
+
+import org.apache.tamaya.ConfigException;
+import org.apache.tamaya.Configuration;
+import org.apache.tamaya.spi.Bootstrap;
+import org.apache.tamaya.spi.ConfigurationManagerSingletonSpi;
+
+import java.lang.annotation.Annotation;
+import java.lang.reflect.Proxy;
+import java.util.Map;
+import java.util.Optional;
+import java.util.concurrent.ConcurrentHashMap;
+
+
+public class DefaultConfigurationManagerSingletonSpi implements ConfigurationManagerSingletonSpi {
+
+    private Map<String, ConfigurationProviderSpi> configProviders = new ConcurrentHashMap<>();
+
+    private ExpressionEvaluator expressionEvaluator = loadEvaluator();
+
+    private ExpressionEvaluator loadEvaluator() {
+        ExpressionEvaluator eval = Bootstrap.getService(ExpressionEvaluator.class, null);
+        if (eval == null) {
+            eval = new DefaultExpressionEvaluator();
+        }
+        return eval;
+    }
+
+    public DefaultConfigurationManagerSingletonSpi() {
+        for (ConfigurationProviderSpi spi : Bootstrap.getServices(ConfigurationProviderSpi.class)) {
+            configProviders.put(spi.getConfigName(), spi);
+        }
+    }
+
+    @Override
+    public <T> T getConfiguration(String name, Class<T> type) {
+        ConfigurationProviderSpi provider = configProviders.get(name);
+        if (provider == null) {
+            if(DefaultConigProvider.DEFAULT_CONFIG_NAME.equals(name)){
+                provider = new DefaultConigProvider();
+                configProviders.put(DefaultConigProvider.DEFAULT_CONFIG_NAME, provider);
+            }
+            else{
+                throw new ConfigException("No such config: " + name);
+            }
+        }
+        Configuration config = provider.getConfiguration();
+        if (config == null) {
+            throw new ConfigException("No such config: " + name);
+        }
+        if (Configuration.class.equals(type)) {
+            return (T) config;
+        }
+        return createAdapterProxy(config, type);
+    }
+
+    /**
+     * Creates a proxy implementing the given target interface.
+     *
+     * @param config the configuration to be used for providing values.
+     * @param type   the target interface.
+     * @param <T>    the target interface type.
+     * @return the corresponding implementing proxy, never null.
+     */
+    private <T> T createAdapterProxy(Configuration config, Class<T> type) {
+        ClassLoader cl = Optional.ofNullable(Thread.currentThread()
+                .getContextClassLoader()).orElse(getClass().getClassLoader());
+        return (T)Proxy.newProxyInstance(cl,new Class[]{type}, new ConfigTemplateInvocationHandler(type, config));
+    }
+
+    @Override
+    public void configure(Object instance) {
+        ConfigurationInjector.configure(instance);
+    }
+
+    private String getConfigId(Annotation... qualifiers) {
+        if (qualifiers == null || qualifiers.length == 0) {
+            return "";
+        }
+        StringBuilder b = new StringBuilder();
+        for (Annotation annot : qualifiers) {
+            b.append('[');
+            b.append(annot.annotationType().getName());
+            b.append(':');
+            b.append(annot.toString());
+            b.append(']');
+        }
+        return b.toString();
+    }
+
+    @Override
+    public String evaluateValue(Configuration config, String expression) {
+        return expressionEvaluator.evaluate(expression);
+    }
+
+    @Override
+    public boolean isConfigurationDefined(String name) {
+        ConfigurationProviderSpi spi = this.configProviders.get(name);
+        return spi != null;
+    }
+
+    /**
+     * This config provider is loaded if no
+     */
+    private static final class DefaultConigProvider implements ConfigurationProviderSpi{
+        private static final String DEFAULT_CONFIG_NAME = "default";
+
+        private Configuration defaultConfig = PropertyProviderBuilder.create(DEFAULT_CONFIG_NAME)
+                .addEnvironmentProperties()
+                .addPaths("META-INF/cfg/default/**/*.properties","META-INF/cfg/default/**/*.xml","META-INF/cfg/default/**/*.ini")
+                .addPaths("META-INF/cfg/config/**/*.properties","META-INF/cfg/config/**/*.xml","META-INF/cfg/config/**/*.ini")
+                .addSystemProperties()
+                .addPaths("META-INF/cfg/fixed/**/*.properties","META-INF/cfg/fixed/**/*.xml","META-INF/cfg/fixed/**/*.ini")
+                .build().toConfiguration();
+
+        @Override
+        public String getConfigName() {
+            return DEFAULT_CONFIG_NAME;
+        }
+
+        @Override
+        public Configuration getConfiguration() {
+            return defaultConfig;
+        }
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/incubator-tamaya/blob/0eef8f37/core/src/main/java/org/apache/tamaya/core/internal/config/EnvPropertiesConfigProvider.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/tamaya/core/internal/config/EnvPropertiesConfigProvider.java b/core/src/main/java/org/apache/tamaya/core/internal/config/EnvPropertiesConfigProvider.java
new file mode 100644
index 0000000..08abed7
--- /dev/null
+++ b/core/src/main/java/org/apache/tamaya/core/internal/config/EnvPropertiesConfigProvider.java
@@ -0,0 +1,49 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.tamaya.core.internal.config;
+
+import org.apache.tamaya.PropertyProviderBuilder;
+import org.apache.tamaya.core.spi.ConfigurationProviderSpi;
+
+import org.apache.tamaya.Configuration;
+
+/**
+ * Provides a {@link org.apache.tamaya.Configuration} named 'environment.properties'
+ * containing the current environment properties.
+ *
+ * Created by Anatole on 29.09.2014.
+ */
+public class EnvPropertiesConfigProvider implements ConfigurationProviderSpi{
+
+    private Configuration envConfig;
+
+    public EnvPropertiesConfigProvider(){
+        envConfig = PropertyProviderBuilder.create("environment.properties").addEnvironmentProperties().build().toConfiguration();
+    }
+
+    @Override
+    public String getConfigName(){
+        return "environment.properties";
+    }
+
+    @Override
+    public Configuration getConfiguration(){
+        return envConfig;
+    }
+}

http://git-wip-us.apache.org/repos/asf/incubator-tamaya/blob/0eef8f37/core/src/main/java/org/apache/tamaya/core/internal/config/SystemPropertiesConfigProvider.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/tamaya/core/internal/config/SystemPropertiesConfigProvider.java b/core/src/main/java/org/apache/tamaya/core/internal/config/SystemPropertiesConfigProvider.java
new file mode 100644
index 0000000..d8314f8
--- /dev/null
+++ b/core/src/main/java/org/apache/tamaya/core/internal/config/SystemPropertiesConfigProvider.java
@@ -0,0 +1,49 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.tamaya.core.internal.config;
+
+import org.apache.tamaya.PropertyProviderBuilder;
+import org.apache.tamaya.core.spi.ConfigurationProviderSpi;
+
+import org.apache.tamaya.Configuration;
+
+/**
+ * Provides a {@link org.apache.tamaya.Configuration} named 'system.properties'
+ * containing the current system properties.
+ *
+ * Created by Anatole on 29.09.2014.
+ */
+public class SystemPropertiesConfigProvider implements ConfigurationProviderSpi{
+
+    private Configuration systemConfig;
+
+    public SystemPropertiesConfigProvider(){
+        systemConfig = PropertyProviderBuilder.create("environment.properties").addSystemProperties().build().toConfiguration();
+    }
+
+    @Override
+    public String getConfigName(){
+        return "system.properties";
+    }
+
+    @Override
+    public Configuration getConfiguration(){
+        return systemConfig;
+    }
+}

http://git-wip-us.apache.org/repos/asf/incubator-tamaya/blob/0eef8f37/core/src/main/java/org/apache/tamaya/core/internal/config/WeakConfigListenerManager.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/tamaya/core/internal/config/WeakConfigListenerManager.java b/core/src/main/java/org/apache/tamaya/core/internal/config/WeakConfigListenerManager.java
new file mode 100644
index 0000000..a65c042
--- /dev/null
+++ b/core/src/main/java/org/apache/tamaya/core/internal/config/WeakConfigListenerManager.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.core.internal.config;
+
+import org.apache.tamaya.core.properties.Store;
+
+
+import java.beans.PropertyChangeEvent;
+import java.beans.PropertyChangeListener;
+import java.util.Map;
+import java.util.concurrent.ConcurrentHashMap;
+import java.util.logging.Level;
+import java.util.logging.Logger;
+
+/**
+ * Simple listener container that only holds weak references on the listeners.
+ */
+public class WeakConfigListenerManager{
+
+    private static final Logger LOG = Logger.getLogger(WeakConfigListenerManager.class.getName());
+    private Map<String,Store<PropertyChangeListener>> changeListeners = new ConcurrentHashMap<>();
+
+
+    private void addPropertyChangeListener(PropertyChangeListener l, String... configIds){
+        for(String configId : configIds){
+            Store<PropertyChangeListener> items = changeListeners.get(configId);
+            if(items != null){
+                synchronized(items){
+                    items.add(l);
+                }
+            }
+        }
+    }
+
+    private void removePropertyChangeListener(PropertyChangeListener l, String... configIds){
+        for(String configId : configIds){
+            Store<PropertyChangeListener> items = changeListeners.get(configId);
+            if(items != null){
+                items.remove(l);
+            }
+        }
+    }
+
+    private void publishPropertyChangeEventToGlobalListeners(PropertyChangeEvent evt){
+        Store<PropertyChangeListener> items = changeListeners.get("_globalConfigChangeListeners");
+        if(items != null){
+            synchronized(items){
+                for(PropertyChangeListener l : items){
+                    try{
+                        l.propertyChange(evt);
+                    }
+                    catch(Exception e){
+                        LOG.log(Level.SEVERE, e, () -> "Error thrown by PropertyChangeListener: " + l);
+                    }
+                }
+
+            }
+        }
+    }
+
+
+    public void publishPropertyChangeEvent(PropertyChangeEvent evt, String configId){
+        Store<PropertyChangeListener> items = changeListeners.get(configId);
+        if(items != null){
+            synchronized(items){
+                for(PropertyChangeListener l : items){
+                    try{
+                        l.propertyChange(evt);
+                    }
+                    catch(Exception e){
+                        LOG.log(Level.SEVERE, e, () -> "Error thrown by ConfigChangeListener: " + l);
+                    }
+                }
+
+            }
+        }
+        publishPropertyChangeEventToGlobalListeners(evt);
+    }
+
+
+    @Override
+    public String toString(){
+        return "WeakConfigListenerManager{" +
+                "changeListeners=" + changeListeners +
+                '}';
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/incubator-tamaya/blob/0eef8f37/core/src/main/java/org/apache/tamaya/core/internal/el/DefaultExpressionEvaluator.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/tamaya/core/internal/el/DefaultExpressionEvaluator.java b/core/src/main/java/org/apache/tamaya/core/internal/el/DefaultExpressionEvaluator.java
new file mode 100644
index 0000000..b42d568
--- /dev/null
+++ b/core/src/main/java/org/apache/tamaya/core/internal/el/DefaultExpressionEvaluator.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.el;
+
+import org.apache.tamaya.ConfigException;
+import org.apache.tamaya.Configuration;
+import org.apache.tamaya.spi.Bootstrap;
+import org.apache.tamaya.core.spi.ExpressionEvaluator;
+import org.apache.tamaya.core.spi.ExpressionResolver;
+
+import java.util.*;
+import java.util.concurrent.ConcurrentHashMap;
+
+/**
+ * Created by Anatole on 28.09.2014.
+ */
+public final class DefaultExpressionEvaluator implements ExpressionEvaluator{
+
+    private Map<String, ExpressionResolver> resolvers = new ConcurrentHashMap<>();
+
+    private ExpressionResolver defaultResolver;
+
+    public DefaultExpressionEvaluator() {
+        for(ExpressionResolver resolver: Bootstrap.getServices(ExpressionResolver.class)){
+            resolvers.put(resolver.getResolverId(), resolver);
+        }
+        defaultResolver = Bootstrap.getService(ExpressionResolver.class);
+    }
+
+    /**
+     * Resolves an expression in the form current <code>${resolverId:expression}</code>. The expression can be
+     * part current any type current literal text. Also multiple expression, with different resolver ids are supported.
+     * All control characters (${}\) can be escaped.<br>
+     * So all the following are valid expressions:
+     * <ul>
+     * <li><code>${resolverId:expression}</code></li>
+     * <li><code>bla bla ${resolverId:expression}</code></li>
+     * <li><code>${resolverId:expression} bla bla</code></li>
+     * <li><code>bla bla ${resolverId:expression} bla bla</code></li>
+     * <li><code>${resolverId:expression}${resolverId2:expression2}</code></li>
+     * <li><code>foo ${resolverId:expression}${resolverId2:expression2}</code></li>
+     * <li><code>foo ${resolverId:expression} bar ${resolverId2:expression2}</code></li>
+     * <li><code>${resolverId:expression}foo${resolverId2:expression2}bar</code></li>
+     * <li><code>foor${resolverId:expression}bar${resolverId2:expression2}more</code></li>
+     * <li><code>\${resolverId:expression}foo${resolverId2:expression2}bar</code> (first expression is escaped).</li>
+     * </ul>
+     *
+     * @param expression the expression to be evaluated, not null
+     * @return the evaluated expression.
+     * @throws org.apache.tamaya.ConfigException if resolution fails.
+     */
+    @Override
+    public String evaluate(String expression) {
+        StringTokenizer tokenizer = new StringTokenizer(expression, "${}\\", true);
+        boolean escaped = false;
+        StringBuilder resolvedValue = new StringBuilder();
+        StringBuilder current = new StringBuilder();
+        while (tokenizer.hasMoreTokens()) {
+            String token = tokenizer.nextToken();
+            if (escaped) {
+                switch (token) {
+                    case "n":
+                        current.append("\n");
+                        break;
+                    case "r":
+                        current.append("\r");
+                        break;
+                    case "t":
+                        current.append("\t");
+                        break;
+                    default:
+                        current.append(token);
+                        break;
+                }
+                escaped = false;
+                continue;
+            }
+            switch (token) {
+                case "\\":
+                    escaped = true;
+                    break;
+                case "$":
+                    if (current.length() > 0) {
+                        resolvedValue.append(current);
+                        current.setLength(0);
+                    }
+                    if (!"{".equals(tokenizer.nextToken())) {
+                        throw new ConfigException("Invalid expression encountered: " + expression);
+                    }
+                    String subExpression = tokenizer.nextToken();
+                    if (!"}".equals(tokenizer.nextToken())) {
+                        throw new ConfigException("Invalid expression encountered: " + expression);
+                    }
+                    // evalute subexpression
+                    current.append(evaluteInternal(subExpression));
+                    break;
+                default:
+                    current.append(token);
+            }
+        }
+        if (current.length() > 0) {
+            resolvedValue.append(current);
+        }
+        return resolvedValue.toString();
+    }
+
+    private String evaluteInternal(String subExpression) {
+        int sepPos = subExpression.indexOf(':');
+        if (sepPos > 0) {
+            String refID = subExpression.substring(0, sepPos);
+            String expression = subExpression.substring(sepPos + 1);
+            return Optional.ofNullable(this.resolvers.get(refID)).orElseThrow(
+                    () -> new ConfigException("Resolver not found: " + refID + " in " + subExpression)
+            ).resolve(expression);
+        } else {
+            return Optional.ofNullable(this.defaultResolver).orElseThrow(
+                    () -> new ConfigException("No default Resolver set, but required by " + subExpression)
+            ).resolve(subExpression);
+        }
+    }
+
+
+}

http://git-wip-us.apache.org/repos/asf/incubator-tamaya/blob/0eef8f37/core/src/main/java/org/apache/tamaya/core/internal/el/ELResolver.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/tamaya/core/internal/el/ELResolver.java b/core/src/main/java/org/apache/tamaya/core/internal/el/ELResolver.java
deleted file mode 100644
index 1dc7277..0000000
--- a/core/src/main/java/org/apache/tamaya/core/internal/el/ELResolver.java
+++ /dev/null
@@ -1,159 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements.  See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership.  The ASF licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License.  You may obtain a copy of the License at
- *
- *   http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing,
- * software distributed under the License is distributed on an
- * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- * KIND, either express or implied.  See the License for the
- * specific language governing permissions and limitations
- * under the License.
- */
-//package org.apache.tamaya.core.internal.el;
-//
-//import org.apache.tamaya.Configuration;
-//import org.apache.tamaya.Environment;
-//import org.apache.tamaya.core.spi.ExpressionResolver;
-//
-//import javax.el.*;
-//import java.lang.reflect.Method;
-//import java.util.HashMap;
-//import java.util.Map;
-//import java.util.Objects;
-//import java.util.Properties;
-//
-///**
-// * Created by Anatole on 28.09.2014.
-// */
-//public final class ELResolver implements ExpressionResolver{
-//
-//    private ExpressionFactory factory;
-//
-//
-//    @Override
-//    public String getResolverId() {
-//        return "el";
-//    }
-//
-//    @Override
-//    public String resolve(String expression){
-//        if(factory==null){
-//            Properties props = new Properties();
-//            props.setProperty("javax.el.ExpressionFactory", "org.apache.el.ExpressionFactoryImpl");
-//            ExpressionFactory tmpFactory = null;
-//            try {
-//                tmpFactory = ExpressionFactory.newInstance(props);
-//            } catch ( RuntimeException e ) {
-//                System.err.println("Error creating EL expression factory.");
-//            }
-//            factory = tmpFactory;
-//        }
-//        ConfigurationContext context = new ConfigurationContext();
-//        Configuration config = Configuration.current();
-//        Objects.requireNonNull(config);
-//        context.bind("config", config);
-//        context.bind("env", Environment.current());
-//        context.bind("system.env", System.getenv());
-//        context.bind("system.prop", System.getProperties());
-//        ValueExpression converted = factory.createValueExpression(context, expression, Object.class );
-//        return String.valueOf(converted.getValue(context));
-//
-//    }
-//
-//    private class ConfigurationContext extends ELContext{
-//
-//        private final BeanELResolver resolver = new BeanELResolver();
-//        private final FunctionMapper functionMapper = new NoopFunctionMapper();
-//        private final VariableMapper variableMapper = new VariableMapperImpl();
-//        private final Map<String,ValueExpression> variables = new HashMap<>();
-//
-//        @Override
-//        public javax.el.ELResolver getELResolver(){
-//            return resolver;
-//        }
-//
-//        @Override
-//        public FunctionMapper getFunctionMapper(){
-//            return functionMapper;
-//        }
-//
-//        @Override
-//        public VariableMapper getVariableMapper(){
-//            return variableMapper;
-//        }
-//
-//        public void bind(final String variable, final Object obj){
-//            variables.put(variable, new ValueExpression(){
-//                @Override
-//                public Object getValue(ELContext elContext){
-//                    return obj;
-//                }
-//
-//                @Override
-//                public void setValue(ELContext elContext, Object o){
-//                    // ignore
-//                }
-//
-//                @Override
-//                public boolean isReadOnly(ELContext elContext){
-//                    return true;
-//                }
-//
-//                @Override
-//                public Class<?> getType(ELContext elContext){
-//                    return variable.getClass();
-//                }
-//
-//                @Override
-//                public Class<?> getExpectedType(){
-//                    return variable.getClass();
-//                }
-//
-//                @Override
-//                public String getExpressionString(){
-//                    return null;
-//                }
-//
-//                @Override
-//                public boolean equals(Object o){
-//                    return false;
-//                }
-//
-//                @Override
-//                public int hashCode(){
-//                    return 0;
-//                }
-//
-//                @Override
-//                public boolean isLiteralText(){
-//                    return false;
-//                }
-//            });
-//        }
-//
-//        private class VariableMapperImpl extends VariableMapper{
-//            public ValueExpression resolveVariable(String s){
-//                return variables.get(s);
-//            }
-//
-//            public ValueExpression setVariable(String s, ValueExpression valueExpression){
-//                return (variables.put(s, valueExpression));
-//            }
-//        }
-//
-//        private class NoopFunctionMapper extends FunctionMapper{
-//            public Method resolveFunction(String s, String s1){
-//                return null;
-//            }
-//        }
-//
-//    }
-//
-//}

http://git-wip-us.apache.org/repos/asf/incubator-tamaya/blob/0eef8f37/core/src/main/java/org/apache/tamaya/core/internal/env/ClassLoaderDependentApplicationEnvironmentProvider.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/tamaya/core/internal/env/ClassLoaderDependentApplicationEnvironmentProvider.java b/core/src/main/java/org/apache/tamaya/core/internal/env/ClassLoaderDependentApplicationEnvironmentProvider.java
index 14ea12f..24785e9 100644
--- a/core/src/main/java/org/apache/tamaya/core/internal/env/ClassLoaderDependentApplicationEnvironmentProvider.java
+++ b/core/src/main/java/org/apache/tamaya/core/internal/env/ClassLoaderDependentApplicationEnvironmentProvider.java
@@ -21,13 +21,13 @@ package org.apache.tamaya.core.internal.env;
 import org.apache.tamaya.Environment;
 import org.apache.tamaya.core.config.ConfigurationFormats;
 import org.apache.tamaya.core.env.EnvironmentBuilder;
+import org.apache.tamaya.core.resource.Resource;
 import org.apache.tamaya.spi.Bootstrap;
 import org.apache.tamaya.core.spi.ConfigurationFormat;
 import org.apache.tamaya.core.spi.EnvironmentProvider;
-import org.apache.tamaya.core.spi.ResourceLoader;
+import org.apache.tamaya.core.resource.ResourceLoader;
 
 
-import java.net.URI;
 import java.util.*;
 import java.util.concurrent.ConcurrentHashMap;
 import java.util.logging.Level;
@@ -44,9 +44,10 @@ public class ClassLoaderDependentApplicationEnvironmentProvider implements Envir
 
     private static  final Logger LOG = Logger.getLogger(ClassLoaderDependentApplicationEnvironmentProvider.class.getName());
 
-    private static final String WARID_PROP = "org.apache.tamaya.env.applicationId";
+    private static final String WARID_PROP = "environment.applicationId";
 
     private Map<ClassLoader, Environment> environments = new ConcurrentHashMap<>();
+    private Map<ClassLoader, Boolean> environmentAvailable = new ConcurrentHashMap<>();
     private Map<String, Environment> environmentsByAppId = new ConcurrentHashMap<>();
 
     @Override
@@ -60,9 +61,15 @@ public class ClassLoaderDependentApplicationEnvironmentProvider implements Envir
         if(cl==null){
             return false;
         }
-        List<URI> propertyUris = Bootstrap.getService(ResourceLoader.class).getResources(cl,
-                "classpath*:META-INF/env/application.properties", "classpath*:META-INF/env/application.xml", "classpath*:META-INF/env/application.ini");
-        return !propertyUris.isEmpty();
+        Boolean available = this.environmentAvailable.get(cl);
+        if(available!=null && !available){
+            return false;
+        }
+        List<Resource> propertyUris = Bootstrap.getService(ResourceLoader.class).getResources(cl,
+                "classpath:META-INF/env/application.properties", "classpath:META-INF/env/application.xml", "classpath:META-INF/env/application.ini");
+        available = !propertyUris.isEmpty();
+        this.environmentAvailable.put(cl, available);
+        return available.booleanValue();
     }
 
     @Override
@@ -75,18 +82,18 @@ public class ClassLoaderDependentApplicationEnvironmentProvider implements Envir
         if(environment!=null){
             return environment;
         }
-        List<URI> propertyUris = Bootstrap.getService(ResourceLoader.class).getResources(cl,
-                "classpath*:META-INF/env/application.properties", "classpath*:META-INF/env/application.xml", "classpath*:META-INF/env/application.ini");
+        List<Resource> propertyUris = Bootstrap.getService(ResourceLoader.class).getResources(cl,
+                "classpath:META-INF/env/application.properties", "classpath:META-INF/env/application.xml", "classpath:META-INF/env/application.ini");
         Map<String,String> data = new HashMap<>();
 
-        for(URI uri:propertyUris){
+        for(Resource resource:propertyUris){
             try{
-                ConfigurationFormat format = ConfigurationFormats.getFormat(uri);
-                Map<String,String> read = format.readConfiguration(uri);
+                ConfigurationFormat format = ConfigurationFormats.getFormat(resource);
+                Map<String,String> read = format.readConfiguration(resource);
                 data.putAll(read);
             }
             catch(Exception e){
-                LOG.log(Level.SEVERE, e, () -> "Error reading application environment data fromMap " + uri);
+                LOG.log(Level.SEVERE, e, () -> "Error reading application environment data fromMap " + resource);
             }
         }
         String applicationId = data.getOrDefault(WARID_PROP, cl.toString());
@@ -94,7 +101,7 @@ public class ClassLoaderDependentApplicationEnvironmentProvider implements Envir
         builder.setParent(parentEnvironment);
         builder.set("classloader.type", cl.getClass().getName());
         builder.set("classloader.info", cl.toString());
-        Set<URI> uris = new HashSet<>();
+        Set<Resource> uris = new HashSet<>();
         uris.addAll(propertyUris);
         builder.set("environment.sources", uris.toString());
         builder.setAll(data);

http://git-wip-us.apache.org/repos/asf/incubator-tamaya/blob/0eef8f37/core/src/main/java/org/apache/tamaya/core/internal/env/ClassLoaderDependentEarEnvironmentProvider.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/tamaya/core/internal/env/ClassLoaderDependentEarEnvironmentProvider.java b/core/src/main/java/org/apache/tamaya/core/internal/env/ClassLoaderDependentEarEnvironmentProvider.java
index 7251896..6e8c3df 100644
--- a/core/src/main/java/org/apache/tamaya/core/internal/env/ClassLoaderDependentEarEnvironmentProvider.java
+++ b/core/src/main/java/org/apache/tamaya/core/internal/env/ClassLoaderDependentEarEnvironmentProvider.java
@@ -22,13 +22,13 @@ import org.apache.tamaya.Environment;
 import org.apache.tamaya.Stage;
 import org.apache.tamaya.core.config.ConfigurationFormats;
 import org.apache.tamaya.core.env.EnvironmentBuilder;
+import org.apache.tamaya.core.resource.Resource;
 import org.apache.tamaya.spi.Bootstrap;
 import org.apache.tamaya.core.spi.ConfigurationFormat;
 import org.apache.tamaya.core.spi.EnvironmentProvider;
-import org.apache.tamaya.core.spi.ResourceLoader;
+import org.apache.tamaya.core.resource.ResourceLoader;
 
 
-import java.net.URI;
 import java.util.*;
 import java.util.concurrent.ConcurrentHashMap;
 import java.util.logging.Level;
@@ -47,9 +47,10 @@ public class ClassLoaderDependentEarEnvironmentProvider implements EnvironmentPr
 
     private static  final Logger LOG = Logger.getLogger(ClassLoaderDependentEarEnvironmentProvider.class.getName());
 
-    private static final String EARID_PROP = "org.apache.tamaya.core.env.earId";
+    private static final String EARID_PROP = "environment.earId";
 
     private Map<ClassLoader, Environment> environments = new ConcurrentHashMap<>();
+    private Map<ClassLoader, Boolean> environmentAvailable = new ConcurrentHashMap<>();
     private Map<String, Environment> environmentsByEarId = new ConcurrentHashMap<>();
 
     @Override
@@ -63,9 +64,15 @@ public class ClassLoaderDependentEarEnvironmentProvider implements EnvironmentPr
         if(cl==null){
             return false;
         }
-        List<URI> propertyUris = Bootstrap.getService(ResourceLoader.class).getResources(cl,
-                "classpath*:META-INF/env/ear.properties", "classpath*:META-INF/env/ear.xml", "classpath*:META-INF/env/ear.ini");
-        return !propertyUris.isEmpty();
+        Boolean available = this.environmentAvailable.get(cl);
+        if(available!=null && !available){
+            return false;
+        }
+        List<Resource> propertyUris = Bootstrap.getService(ResourceLoader.class).getResources(cl,
+                "classpath:META-INF/env/ear.properties", "classpath:META-INF/env/ear.xml", "classpath:META-INF/env/ear.ini");
+        available = !propertyUris.isEmpty();
+        this.environmentAvailable.put(cl, available);
+        return available.booleanValue();
     }
 
     @Override
@@ -78,18 +85,18 @@ public class ClassLoaderDependentEarEnvironmentProvider implements EnvironmentPr
         if(environment!=null){
             return environment;
         }
-        List<URI> propertyUris = Bootstrap.getService(ResourceLoader.class).getResources(cl,
-                "classpath*:META-INF/env/ear.properties", "classpath*:META-INF/env/ear.xml", "classpath*:META-INF/env/ear.ini");
+        List<Resource> resources = Bootstrap.getService(ResourceLoader.class).getResources(cl,
+                "classpath:META-INF/env/ear.properties", "classpath:META-INF/env/ear.xml", "classpath:META-INF/env/ear.ini");
         Map<String,String> data = new HashMap<>();
 
-        for(URI uri:propertyUris){
+        for(Resource resource:resources){
             try{
-                ConfigurationFormat format = ConfigurationFormats.getFormat(uri);
-                Map<String,String> read = format.readConfiguration(uri);
+                ConfigurationFormat format = ConfigurationFormats.getFormat(resource);
+                Map<String,String> read = format.readConfiguration(resource);
                 data.putAll(read);
             }
             catch(Exception e){
-                LOG.log(Level.SEVERE, e, () -> "Error reading ear environment data fromMap " + uri);
+                LOG.log(Level.SEVERE, e, () -> "Error reading ear environment data fromMap " + resource);
             }
         }
         String earId = data.getOrDefault(EARID_PROP, cl.toString());
@@ -102,9 +109,9 @@ public class ClassLoaderDependentEarEnvironmentProvider implements EnvironmentPr
         }
         builder.set("classloader.type", cl.getClass().getName());
         builder.set("classloader.info", cl.toString());
-        Set<URI> uris = new HashSet<>();
-        uris.addAll(propertyUris);
-        builder.set("environment.sources", uris.toString());
+        Set<Resource> resourceSet = new HashSet<>();
+        resourceSet.addAll(resources);
+        builder.set("environment.sources", resourceSet.toString());
         builder.setAll(data);
         environment = builder.build();
         this.environments.put(cl, environment);

http://git-wip-us.apache.org/repos/asf/incubator-tamaya/blob/0eef8f37/core/src/main/java/org/apache/tamaya/core/internal/env/DefaultStagesSingletonSpi.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/tamaya/core/internal/env/DefaultStagesSingletonSpi.java b/core/src/main/java/org/apache/tamaya/core/internal/env/DefaultStagesSingletonSpi.java
new file mode 100644
index 0000000..bcac458
--- /dev/null
+++ b/core/src/main/java/org/apache/tamaya/core/internal/env/DefaultStagesSingletonSpi.java
@@ -0,0 +1,109 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.tamaya.core.internal.env;
+
+import org.apache.tamaya.Stage;
+import org.apache.tamaya.core.env.StageBuilder;
+import org.apache.tamaya.spi.StagesSingletonSpi;
+
+import java.util.Collection;
+import java.util.Map;
+import java.util.concurrent.ConcurrentHashMap;
+
+/**
+ * Created by Anatole on 12.11.2014.
+ */
+public class DefaultStagesSingletonSpi implements StagesSingletonSpi{
+
+
+    public DefaultStagesSingletonSpi(){
+        addStage(StageBuilder.create("Development").build());
+        addStage(StageBuilder.create("Test").build());
+        addStage(StageBuilder.create("Integration").build());
+        addStage(StageBuilder.create("Staging").build());
+        addStage(StageBuilder.create("Production").build());
+    }
+
+    /**
+     * All the stages known.
+     */
+    private static final Map<String, Stage> stages = new ConcurrentHashMap<>();
+
+    @Override
+    public Stage getDevelopmentStage() {
+        return getStage("Development");
+    }
+
+    @Override
+    public Stage getTestStage() {
+        return getStage("Test");
+    }
+
+    @Override
+    public Stage getIntegrationStage() {
+        return getStage("Integration");
+    }
+
+    @Override
+    public Stage getStagingStage() {
+        return getStage("Staging");
+    }
+
+    @Override
+    public Stage getProductionStage() {
+        return getStage("Production");
+    }
+
+    /**
+     * Get a stage by name. If not present, create a new stage.
+     *
+     * @param name the stage's name.
+     * @return tge stage instance, never null.
+     */
+    public Stage getStage(String name) {
+        Stage stage = stages.get(name);
+        if (stage == null) {
+            throw new IllegalArgumentException("No such state: " + name);
+        }
+        return stage;
+    }
+
+    /**
+     * Adds a new stage.
+     *
+     * @param stage the new stage instance.
+     * @throws IllegalStateException if a stage with the same name is already existing.
+     */
+    public void addStage(Stage stage) {
+        Stage existing = stages.putIfAbsent(stage.getName(), stage);
+        if (existing != null) {
+            throw new IllegalStateException("A stage named '" + stage.getName() + "' already exists: " + existing);
+        }
+    }
+
+    /**
+     * Access all the stages currently defined.
+     *
+     * @return the current stages, never null.
+     */
+    public Collection<Stage> getStages() {
+        return stages.values();
+    }
+
+}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/incubator-tamaya/blob/0eef8f37/core/src/main/java/org/apache/tamaya/core/internal/env/SystemClassLoaderEnvironmentProvider.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/tamaya/core/internal/env/SystemClassLoaderEnvironmentProvider.java b/core/src/main/java/org/apache/tamaya/core/internal/env/SystemClassLoaderEnvironmentProvider.java
index 9c6ecbe..a7ea106 100644
--- a/core/src/main/java/org/apache/tamaya/core/internal/env/SystemClassLoaderEnvironmentProvider.java
+++ b/core/src/main/java/org/apache/tamaya/core/internal/env/SystemClassLoaderEnvironmentProvider.java
@@ -22,13 +22,13 @@ import org.apache.tamaya.Environment;
 import org.apache.tamaya.Stage;
 import org.apache.tamaya.core.config.ConfigurationFormats;
 import org.apache.tamaya.core.env.EnvironmentBuilder;
+import org.apache.tamaya.core.resource.Resource;
 import org.apache.tamaya.spi.Bootstrap;
 import org.apache.tamaya.core.spi.ConfigurationFormat;
 import org.apache.tamaya.core.spi.EnvironmentProvider;
-import org.apache.tamaya.core.spi.ResourceLoader;
+import org.apache.tamaya.core.resource.ResourceLoader;
 
 
-import java.net.URI;
 import java.util.*;
 import java.util.logging.Level;
 import java.util.logging.Logger;
@@ -59,17 +59,17 @@ public class SystemClassLoaderEnvironmentProvider implements EnvironmentProvider
         if(env!=null){
             return env;
         }
-        List<URI> propertyUris = Bootstrap.getService(ResourceLoader.class).getResources(ClassLoader.getSystemClassLoader(),
-                "classpath*:META-INF/env/system.properties", "classpath*:META-INF/env/system.xml", "classpath*:META-INF/env/system.ini");
+        List<Resource> propertyResources = Bootstrap.getService(ResourceLoader.class).getResources(ClassLoader.getSystemClassLoader(),
+                "classpath:META-INF/env/system.properties", "classpath:META-INF/env/system.xml", "classpath:META-INF/env/system.ini");
         EnvironmentBuilder builder = EnvironmentBuilder.of("system", getEnvironmentType());
-        for(URI uri:propertyUris){
+        for(Resource resource:propertyResources){
             try{
-                ConfigurationFormat format = ConfigurationFormats.getFormat(uri);
-                Map<String,String> data = format.readConfiguration(uri);
+                ConfigurationFormat format = ConfigurationFormats.getFormat(resource);
+                Map<String,String> data = format.readConfiguration(resource);
                 builder.setAll(data);
             }
             catch(Exception e){
-                LOG.log(Level.SEVERE, e, () -> "Error readong environment data fromMap " + uri);
+                LOG.log(Level.INFO, e, () -> "Could not read environment data from " + resource);
             }
         }
         builder.setParent(parentEnvironment);
@@ -81,9 +81,9 @@ public class SystemClassLoaderEnvironmentProvider implements EnvironmentProvider
         builder.setStage(stage);
         builder.set("classloader.type", ClassLoader.getSystemClassLoader().getClass().getName());
         builder.set("classloader.info", ClassLoader.getSystemClassLoader().toString());
-        Set<URI> uris = new HashSet<>();
-        uris.addAll(propertyUris);
-        builder.set("environment.sources", uris.toString());
+        Set<Resource> resourceSet = new HashSet<>();
+        resourceSet.addAll(propertyResources);
+        builder.set("environment.sources", resourceSet.toString());
         env = builder.build();
         this.environments.put("system", env);
         return env;

http://git-wip-us.apache.org/repos/asf/incubator-tamaya/blob/0eef8f37/core/src/main/java/org/apache/tamaya/core/internal/format/DefaultConfigFormatsSingletonSpi.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/tamaya/core/internal/format/DefaultConfigFormatsSingletonSpi.java b/core/src/main/java/org/apache/tamaya/core/internal/format/DefaultConfigFormatsSingletonSpi.java
index 124b4fd..69ec180 100644
--- a/core/src/main/java/org/apache/tamaya/core/internal/format/DefaultConfigFormatsSingletonSpi.java
+++ b/core/src/main/java/org/apache/tamaya/core/internal/format/DefaultConfigFormatsSingletonSpi.java
@@ -18,10 +18,10 @@
  */
 package org.apache.tamaya.core.internal.format;
 
+import org.apache.tamaya.core.resource.Resource;
 import org.apache.tamaya.core.spi.ConfigurationFormat;
 import org.apache.tamaya.core.spi.ConfigurationFormatsSingletonSpi;
 
-import java.net.URI;
 import java.util.*;
 
 import org.apache.tamaya.spi.Bootstrap;
@@ -59,7 +59,7 @@ public final class DefaultConfigFormatsSingletonSpi implements ConfigurationForm
         return result;
     }
 
-	public ConfigurationFormat getFormat(URI resource) {
+	public ConfigurationFormat getFormat(Resource resource) {
         Objects.requireNonNull(resource);
         try {
             for (ConfigurationFormat configFormat : Bootstrap.getServices(ConfigurationFormat.class)) {

http://git-wip-us.apache.org/repos/asf/incubator-tamaya/blob/0eef8f37/core/src/main/java/org/apache/tamaya/core/internal/format/IniFormat.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/tamaya/core/internal/format/IniFormat.java b/core/src/main/java/org/apache/tamaya/core/internal/format/IniFormat.java
index cb76d95..1647d92 100644
--- a/core/src/main/java/org/apache/tamaya/core/internal/format/IniFormat.java
+++ b/core/src/main/java/org/apache/tamaya/core/internal/format/IniFormat.java
@@ -18,6 +18,7 @@
  */
 package org.apache.tamaya.core.internal.format;
 
+import org.apache.tamaya.core.resource.Resource;
 import org.apache.tamaya.core.spi.ConfigurationFormat;
 
 
@@ -25,7 +26,6 @@ import org.apache.tamaya.ConfigException;
 import java.io.BufferedReader;
 import java.io.InputStream;
 import java.io.InputStreamReader;
-import java.net.URI;
 import java.util.HashMap;
 import java.util.Map;
 import java.util.logging.Level;
@@ -42,16 +42,16 @@ public class IniFormat implements ConfigurationFormat{
     }
 
     @Override
-    public boolean isAccepted(URI resource){
-        String path = resource.getPath();
+    public boolean isAccepted(Resource resource){
+        String path = resource.getFilename();
         return path != null && path.endsWith(".ini");
     }
 
     @Override
-    public Map<String,String> readConfiguration(URI resource){
+    public Map<String,String> readConfiguration(Resource resource){
         Map<String,String> result = new HashMap<>();
-        if(isAccepted(resource)){
-            try(InputStream is = resource.toURL().openStream()){
+        if(isAccepted(resource) && resource.exists()){
+            try(InputStream is = resource.getInputStream()){
                 BufferedReader reader = new BufferedReader(new InputStreamReader(is));
                 String line = reader.readLine();
                 int lineNum = 0;
@@ -63,7 +63,10 @@ public class IniFormat implements ConfigurationFormat{
                         line = reader.readLine();
                         continue;
                     }
-                    if(line.startsWith("[")){
+                    if(line.trim().startsWith("#")){
+                        // comment
+                    }
+                    else if(line.startsWith("[")){
                         int end = line.indexOf(']');
                         if(end < 0){
                             throw new ConfigException(
@@ -86,7 +89,7 @@ public class IniFormat implements ConfigurationFormat{
                 }
             }
             catch(Exception e){
-                LOG.log(Level.SEVERE, e, () -> "Error reading configuration: " + resource);
+                LOG.log(Level.SEVERE, e, () -> "Could not read configuration: " + resource);
             }
         }
         return result;

http://git-wip-us.apache.org/repos/asf/incubator-tamaya/blob/0eef8f37/core/src/main/java/org/apache/tamaya/core/internal/format/PropertiesFormat.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/tamaya/core/internal/format/PropertiesFormat.java b/core/src/main/java/org/apache/tamaya/core/internal/format/PropertiesFormat.java
index 3496476..d64fa11 100644
--- a/core/src/main/java/org/apache/tamaya/core/internal/format/PropertiesFormat.java
+++ b/core/src/main/java/org/apache/tamaya/core/internal/format/PropertiesFormat.java
@@ -19,36 +19,39 @@
 package org.apache.tamaya.core.internal.format;
 
 import java.io.InputStream;
-import java.net.URI;
 import java.util.Collections;
 import java.util.Map;
 import java.util.Properties;
+import java.util.logging.Level;
+import java.util.logging.Logger;
 
+import org.apache.tamaya.core.resource.Resource;
 import org.apache.tamaya.core.spi.ConfigurationFormat;
 
 public class PropertiesFormat implements ConfigurationFormat{
 
+    private final static Logger LOG = Logger.getLogger(PropertiesFormat.class.getName());
+
     @Override
     public String getFormatName(){
         return "properties";
     }
 
     @Override
-	public boolean isAccepted(URI resource) {
-		String path = resource.getPath();
+	public boolean isAccepted(Resource resource) {
+		String path = resource.getFilename();
 		return path != null && path.endsWith(".properties");
 	}
 
 	@Override
-	public Map<String,String> readConfiguration(URI resource) {
-		if (isAccepted(resource)) {
-			try (InputStream is = resource.toURL().openStream()) {
+	public Map<String,String> readConfiguration(Resource resource) {
+		if (isAccepted(resource) && resource.exists()) {
+			try (InputStream is = resource.getInputStream()) {
 				Properties p = new Properties();
 				p.load(is);
 				return Map.class.cast(p);
 			} catch (Exception e) {
-				// TODO Auto-generated catch block
-				e.printStackTrace();
+                LOG.log(Level.FINEST, e, () -> "Failed to read config from resource: " + resource);
 			}
 		}
 		return Collections.emptyMap();

http://git-wip-us.apache.org/repos/asf/incubator-tamaya/blob/0eef8f37/core/src/main/java/org/apache/tamaya/core/internal/format/PropertiesXmlFormat.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/tamaya/core/internal/format/PropertiesXmlFormat.java b/core/src/main/java/org/apache/tamaya/core/internal/format/PropertiesXmlFormat.java
index c1d3fbd..3322407 100644
--- a/core/src/main/java/org/apache/tamaya/core/internal/format/PropertiesXmlFormat.java
+++ b/core/src/main/java/org/apache/tamaya/core/internal/format/PropertiesXmlFormat.java
@@ -18,38 +18,41 @@
  */
 package org.apache.tamaya.core.internal.format;
 
+import org.apache.tamaya.core.resource.Resource;
 import org.apache.tamaya.core.spi.ConfigurationFormat;
 
 import java.io.InputStream;
-import java.net.URI;
 import java.util.Collections;
 import java.util.Map;
 import java.util.Properties;
+import java.util.logging.Level;
+import java.util.logging.Logger;
 
 
 public class PropertiesXmlFormat implements ConfigurationFormat{
 
+    private final static Logger LOG = Logger.getLogger(PropertiesXmlFormat.class.getName());
+
     @Override
     public String getFormatName(){
         return "xml-properties";
     }
 
     @Override
-    public boolean isAccepted(URI resource){
-        String path = resource.getPath();
+    public boolean isAccepted(Resource resource){
+        String path = resource.getFilename();
         return path != null && path.endsWith(".xml");
     }
 
     @Override
-    public Map<String,String> readConfiguration(URI resource) {
-        if (isAccepted(resource)) {
-            try (InputStream is = resource.toURL().openStream()) {
+    public Map<String,String> readConfiguration(Resource resource) {
+        if (isAccepted(resource) && resource.exists()) {
+            try (InputStream is = resource.getInputStream()) {
                 Properties p = new Properties();
                 p.loadFromXML(is);
                 return Map.class.cast(p);
             } catch (Exception e) {
-                // TODO Auto-generated catch block
-                e.printStackTrace();
+                LOG.log(Level.FINEST, e, () -> "Failed to read config from resource: " + resource);
             }
         }
         return Collections.emptyMap();

http://git-wip-us.apache.org/repos/asf/incubator-tamaya/blob/0eef8f37/core/src/main/java/org/apache/tamaya/core/internal/properties/AggregatedPropertyProvider.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/tamaya/core/internal/properties/AggregatedPropertyProvider.java b/core/src/main/java/org/apache/tamaya/core/internal/properties/AggregatedPropertyProvider.java
new file mode 100644
index 0000000..237374d
--- /dev/null
+++ b/core/src/main/java/org/apache/tamaya/core/internal/properties/AggregatedPropertyProvider.java
@@ -0,0 +1,122 @@
+/*
+ * 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.properties;
+
+import org.apache.tamaya.*;
+import org.apache.tamaya.core.properties.AbstractPropertyProvider;
+
+import java.util.*;
+
+/**
+ * Implementation for a {@link org.apache.tamaya.PropertyProvider} that is an aggregate current
+ * multiple child instances. Controlled by an {@link org.apache.tamaya.AggregationPolicy} the
+ * following aggregations are supported:
+ * <ul>
+ * <li><b>IGNORE_DUPLICATES: </b>Ignore all overrides.</li>
+ * <li><b>: </b></li>
+ * <li><b>: </b></li>
+ * <li><b>: </b></li>
+ * </ul>
+ */
+class AggregatedPropertyProvider extends AbstractPropertyProvider {
+
+    private static final long serialVersionUID = -1419376385695224799L;
+	private AggregationPolicy policy = AggregationPolicy.COMBINE;
+	private List<PropertyProvider> units = new ArrayList<PropertyProvider>();
+    private PropertyProvider mutableProvider;
+
+    /**
+     * Creates a new instance.
+     * @param mutableProvider the provider instance that would be used for delegating
+     *                        change requests.
+     * @param policy
+     *            The aggregation policy to be used.
+     * @param propertyMaps
+     *            The property sets to be included.
+     */
+	public AggregatedPropertyProvider(MetaInfo metaInfo, PropertyProvider mutableProvider, AggregationPolicy policy, List<PropertyProvider> propertyMaps) {
+        super(MetaInfoBuilder.of(metaInfo).setType("aggregated").build());
+        Objects.requireNonNull(policy);
+        this.policy = policy;
+		units.addAll(propertyMaps);
+        this.mutableProvider = mutableProvider;
+	}
+
+	/**
+	 * Get the {@link AggregationPolicy} for this instance.
+	 * 
+	 * @return the {@link AggregationPolicy}, never {@code null}.
+	 */
+	public AggregationPolicy getAggregationPolicy() {
+		return policy;
+	}
+
+	/**
+	 * Return the names current the {@link org.apache.tamaya.PropertyProvider} instances to be
+	 * aggregated in this instance, in the order current precedence (the first are
+	 * the weakest).
+	 * 
+	 * @return the ordered list current aggregated scope identifiers, never
+	 *         {@code null}.
+	 */
+	public List<PropertyProvider> getConfigurationUnits() {
+		return Collections.unmodifiableList(units);
+	}
+
+    /**
+     * Apply a config change to this item. Hereby the change must be related to the same instance.
+     * @param change the config change
+     * @throws org.apache.tamaya.ConfigException if an unrelated change was passed.
+     * @throws UnsupportedOperationException when the configuration is not writable.
+     */
+    @Override
+    public void apply(ConfigChangeSet change){
+        if(mutableProvider!=null)
+            mutableProvider.apply(change);
+        else
+            super.apply(change);
+    }
+
+    @Override
+    public Map<String,String> toMap() {
+		Map<String, String> value = new HashMap<>();
+        for (PropertyProvider unit : units) {
+            for (Map.Entry<String, String> entry : unit.toMap()
+                    .entrySet()) {
+                String valueToAdd = this.policy.aggregate(entry.getKey(), value.get(entry.getKey()), entry.getValue());
+                if(valueToAdd==null){
+                    value.remove(entry.getKey());
+                }
+                else{
+                    value.put(entry.getKey(), valueToAdd);
+                }
+            }
+        }
+        return value;
+	}
+
+    @Override
+	public ConfigChangeSet load() {
+		for (PropertyProvider unit : units) {
+			unit.load();
+		}
+        return super.load();
+	}
+
+}

http://git-wip-us.apache.org/repos/asf/incubator-tamaya/blob/0eef8f37/core/src/main/java/org/apache/tamaya/core/internal/properties/ClasspathPropertyProvider.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/tamaya/core/internal/properties/ClasspathPropertyProvider.java b/core/src/main/java/org/apache/tamaya/core/internal/properties/ClasspathPropertyProvider.java
new file mode 100644
index 0000000..dc71c1a
--- /dev/null
+++ b/core/src/main/java/org/apache/tamaya/core/internal/properties/ClasspathPropertyProvider.java
@@ -0,0 +1,150 @@
+/*
+ * 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.properties;
+
+import org.apache.tamaya.ConfigChangeSet;
+import org.apache.tamaya.MetaInfo;
+import org.apache.tamaya.core.properties.AbstractPropertyProvider;
+import org.apache.tamaya.core.properties.ClasspathModulePropertyProvider;
+
+import java.util.*;
+
+public class ClasspathPropertyProvider extends AbstractPropertyProvider {
+
+    private static final long serialVersionUID = -2193109047946712701L;
+    private Map<ClassLoader,ClasspathModulePropertyProvider> configs = new HashMap<>();
+	private String[] resources;
+
+	public ClasspathPropertyProvider(MetaInfo metaInfo, String... resources) {
+        super(metaInfo);
+        Objects.requireNonNull(resources);
+        this.resources = resources;
+	}
+
+
+    @Override
+    public Map<String,String> toMap(){
+        return new Map<String,String>(){
+
+            @Override
+            public int size(){
+                return getLoaderDependentDelegate().size();
+            }
+
+            @Override
+            public boolean isEmpty(){
+                return getLoaderDependentDelegate().isEmpty();
+            }
+
+            @Override
+            public boolean containsKey(Object key){
+                return getLoaderDependentDelegate().containsKey(key);
+            }
+
+            @Override
+            public boolean containsValue(Object value){
+                return getLoaderDependentDelegate().containsValue(value);
+            }
+
+            @Override
+            public String get(Object key){
+                return getLoaderDependentDelegate().get(key);
+            }
+
+            @Override
+            public String put(String key, String value){
+                return getLoaderDependentDelegate().put(key,value);
+            }
+
+            @Override
+            public String remove(Object key){
+                return getLoaderDependentDelegate().remove(key);
+            }
+
+            @Override
+            public void putAll(Map<? extends String,? extends String> m){
+                getLoaderDependentDelegate().putAll(m);
+            }
+
+            @Override
+            public void clear(){
+                getLoaderDependentDelegate().clear();
+            }
+
+            @Override
+            public Set<String> keySet(){
+                return getLoaderDependentDelegate().keySet();
+            }
+
+            @Override
+            public Collection<String> values(){
+                return getLoaderDependentDelegate().values();
+            }
+
+            @Override
+            public Set<Entry<String,String>> entrySet(){
+                return getLoaderDependentDelegate().entrySet();
+            }
+
+        };
+    }
+
+	private Map<String, String> getLoaderDependentDelegate() {
+		Map<String, String> props = new HashMap<>();
+		ClassLoader cl = Thread.currentThread().getContextClassLoader();
+		if (cl == null) {
+			cl = getClass().getClassLoader();
+		}
+		while (cl != null) {
+			ClasspathModulePropertyProvider cfg = this.configs.get(cl);
+			if (cfg == null) {
+				cfg = new ClasspathModulePropertyProvider(cl, this.resources);
+				this.configs.put(cl, cfg);
+			}
+			props.putAll(cfg.toMap());
+			cl = cl.getParent();
+		}
+		return props;
+	}
+
+	@Override
+	public ConfigChangeSet load() {
+		Map<String, String> props = new HashMap<>();
+		ClassLoader cl = Thread.currentThread().getContextClassLoader();
+		if (cl == null) {
+			cl = getClass().getClassLoader();
+		}
+		while (cl != null) {
+			ClasspathModulePropertyProvider cfg = this.configs.get(cl);
+			if (cfg != null) {
+				cfg.load();
+			}
+			cl = cl.getParent();
+		}
+        return super.load();
+	}
+
+    @Override
+    public String toString(){
+        return "ClasspathPropertyProvider{" +
+                "configs=" + configs +
+                ", resources=" + Arrays.toString(resources) +
+                '}';
+    }
+}

http://git-wip-us.apache.org/repos/asf/incubator-tamaya/blob/0eef8f37/core/src/main/java/org/apache/tamaya/core/internal/properties/ContextualPropertyProvider.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/tamaya/core/internal/properties/ContextualPropertyProvider.java b/core/src/main/java/org/apache/tamaya/core/internal/properties/ContextualPropertyProvider.java
new file mode 100644
index 0000000..a8e473a
--- /dev/null
+++ b/core/src/main/java/org/apache/tamaya/core/internal/properties/ContextualPropertyProvider.java
@@ -0,0 +1,177 @@
+/*
+ * 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.properties;
+
+import org.apache.tamaya.*;
+
+import java.util.Map;
+import java.util.Objects;
+import java.util.Optional;
+import java.util.Set;
+import java.util.concurrent.ConcurrentHashMap;
+import java.util.function.Supplier;
+
+/**
+ * Created by Anatole on 12.04.2014.
+ */
+class ContextualPropertyProvider implements PropertyProvider{
+
+    private volatile Map<String,PropertyProvider> cachedMaps = new ConcurrentHashMap<>();
+
+    private Supplier<PropertyProvider> mapSupplier;
+    private Supplier<String> isolationKeySupplier;
+    private MetaInfo metaInfo;
+
+    /**
+     * Creates a new contextual PropertyMap. Contextual maps delegate to different instances current PropertyMap depending
+     * on the keys returned fromMap the isolationP
+     *
+     * @param mapSupplier
+     * @param isolationKeySupplier
+     */
+    public ContextualPropertyProvider(MetaInfo metaInfo, Supplier<PropertyProvider> mapSupplier, Supplier<String> isolationKeySupplier){
+        if(metaInfo==null){
+            this.metaInfo = MetaInfoBuilder.of().setType("contextual").set("mapSupplier", mapSupplier.toString())
+                    .set("isolationKeySupplier", isolationKeySupplier.toString()).build();
+        }
+        else{
+            this.metaInfo = MetaInfoBuilder.of(metaInfo).setType("contextual").set("mapSupplier", mapSupplier.toString())
+                    .set("isolationKeySupplier", isolationKeySupplier.toString()).build();
+        }
+        Objects.requireNonNull(mapSupplier);
+        Objects.requireNonNull(isolationKeySupplier);
+        this.mapSupplier = mapSupplier;
+        this.isolationKeySupplier = isolationKeySupplier;
+    }
+
+    /**
+     * This method provides the contextual Map for the current environment. Hereby, ba default, for each different
+     * key returned by the #isolationKeySupplier a separate PropertyMap instance is acquired fromMap the #mapSupplier.
+     * If the map supplier returns an instance it is cached in the local #cachedMaps.
+     *
+     * @return the current contextual PropertyMap.
+     */
+    protected PropertyProvider getContextualMap(){
+        String environmentKey = this.isolationKeySupplier.get();
+        if(environmentKey == null){
+            return PropertyProvider.EMPTY_PROVIDER;
+        }
+        PropertyProvider map = this.cachedMaps.get(environmentKey);
+        if(map == null){
+            synchronized(cachedMaps){
+                map = this.cachedMaps.get(environmentKey);
+                if(map == null){
+                    map = this.mapSupplier.get();
+                    if(map == null){
+                        return PropertyProvider.EMPTY_PROVIDER;
+                    }
+                    this.cachedMaps.put(environmentKey, map);
+                }
+            }
+        }
+        return map;
+    }
+
+    @Override
+    public ConfigChangeSet load(){
+        return getContextualMap().load();
+    }
+
+    @Override
+    public boolean containsKey(String key){
+        return getContextualMap().containsKey(key);
+    }
+
+    @Override
+    public Map<String,String> toMap(){
+        return getContextualMap().toMap();
+    }
+
+    @Override
+    public MetaInfo getMetaInfo(){
+        return this.metaInfo;
+    }
+
+    @Override
+    public Optional<String> get(String key){
+        return getContextualMap().get(key);
+    }
+
+    @Override
+    public Set<String> keySet(){
+        return getContextualMap().keySet();
+    }
+
+    /**
+     * Apply a config change to this item. Hereby the change must be related to the same instance.
+     * @param change the config change
+     * @throws org.apache.tamaya.ConfigException if an unrelated change was passed.
+     * @throws UnsupportedOperationException when the configuration is not writable.
+     */
+    @Override
+    public void apply(ConfigChangeSet change){
+        getContextualMap().apply(change);
+    }
+
+    /**
+     * Access a cached PropertyMap.
+     *
+     * @param key the target environment key as returned by the environment key supplier, not null.
+     * @return the corresponding PropertyMap, or null.
+     */
+    public PropertyProvider getCachedMap(String key){
+        return this.cachedMaps.get(key);
+    }
+
+    /**
+     * Access the set current currently loaded/cached maps.
+     *
+     * @return the set current cached map keys, never null.
+     */
+    public Set<String> getCachedMapKeys(){
+        return this.cachedMaps.keySet();
+    }
+
+    /**
+     * Access the supplier for environment key, determining map isolation.
+     *
+     * @return the environment key supplier instance, not null.
+     */
+    public Supplier<String> getIsolationKeySupplier(){
+        return this.isolationKeySupplier;
+    }
+
+    /**
+     * Access the supplier for new PropertyMap instances.
+     *
+     * @return the PropertyMap supplier instance, not null.
+     */
+    public Supplier<PropertyProvider> getMapSupplier(){
+        return this.mapSupplier;
+    }
+
+    @Override
+    public String toString(){
+        return "ContextualMap{" +
+                "cachedMaps(key)=" + cachedMaps.keySet() +
+                ", mapSupplier=" + mapSupplier +
+                ", isolationKeySupplier=" + isolationKeySupplier +
+                '}';
+    }
+}


Mime
View raw message