tamaya-commits mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From anat...@apache.org
Subject [10/11] incubator-tamaya git commit: Initial import from GitHub. Added PGP public key.
Date Wed, 26 Nov 2014 18:07:15 GMT
http://git-wip-us.apache.org/repos/asf/incubator-tamaya/blob/cf59ebbd/api/src/main/asciidoc/tasks.adoc
----------------------------------------------------------------------
diff --git a/api/src/main/asciidoc/tasks.adoc b/api/src/main/asciidoc/tasks.adoc
new file mode 100644
index 0000000..2bfb3ef
--- /dev/null
+++ b/api/src/main/asciidoc/tasks.adoc
@@ -0,0 +1,399 @@
+Apache Tamaya - Possible Tasks
+==============================
+:name: Tamaya
+:rootpackage: org.apache.tamaya
+:title: Apache Tamaya
+:revnumber: 0.1-SNAPSHOT
+:revremark: Draft
+:revdate: October 2014
+:longversion: {revnumber} ({revremark}) {revdate}
+:authorinitials: ATR
+:author: Anatole Tresch
+:email: <atsticks@gmail.com>
+:source-highlighter: coderay
+:website: http://tamaya.apache.org/
+:iconsdir: {imagesdir}/icons
+:toc:
+:toc-placement: manual
+:icons:
+:encoding: UTF-8
+:numbered:
+
+'''
+
+<<<
+
+-> add image : : https://raw.githubusercontent.com/JavaConfig/config-api/master/src/main/asciidoc/images/javaconfig.jpg[]
+
+toc::[]
+
+<<<
+:numbered!:
+-----------------------------------------------------------
+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.
+-----------------------------------------------------------
+
+:numbered:
+
+<<<
+
+== Introduction
+
+== What is Tamaya
+
+{name} is the Apache standard for flexible and powerful configuration. Objective is to provide flavors for
+Java SE, ME as well as to ship with powerful features for Java EE and Cloud Solutions. All functions provided
+is build on top of a small but very powerful, flexible and extendible API. This API is implemented by a core implementation,
+which then can be extended or adapted for use in different runtime scenarios, such as SE, ME, EE, Spring, OSGI
+and more. Similarly additional modules may be provided that help also existing solution to be plugged into
+{name}, so you can start right away using {name} without having to rebuild/change your existing application.
+
+== Main Features of {name}
+
+The main features of {name} currently are
+
+* *A simple key/value store*, named +PropertyProvider+ (simply called "provider").
+* Simple *built-in meta-data model*, that allows to easily attach metadata to a provider or single property keys.
+* Support for *different configuration formats*.
+* Support for *different configuration locations*, including remote locations.
+* Powerful and flexible *options to combine providers to new composite providers* using different combination policies.
+* The *Configuration model* adds additional features:
+** *Type Adapters* allow to convert configuration into any required target type.
+** *Built-in support* for all basic Java types.
+* *Contextual, hierarchical and multi-layered environment model*. The model is rather simple, but nevertheless
+  powerful enough to map complex layered runtime environments such as Java EE or multi-tenant SaaS solutions.
+* *Configurable System Properties* allow to tweak system properties to behave contextually.
+* *Templates* provide a type safe configuration mechanism where an annotated interface is implemented by the
+  configuration system, providing data from an underlying configuration.
+* *Configuration Injection* allows configured values to be directly injected into the bean's configured.
+* *Loading Policies* allow to control how configuration changes are reflected on the configured beans.
+* *Configuration Operators and Queries* can be used to easily implement advanced features such as *Views,
+  Security Constraints and Filters*.
+* Provider and configuration changes can be observed by registering *PropertyChangeListeners*.
+* Configurations are *versioned*, so remote pull scenarios can be implemented very efficiently.
+* The system supports *multiple configurations* identified by name.
+* The configuration system provides a powerful management console for reading and updating of configuration.
+* The system also supports distributed configuration scenarios by leveraging existing solutions, such as Memcached,
+  Hazelcast or Zookeper.
+* The system is built on "Java 8 features*.
+* A *Java 7 Backport* is provided.
+
+=== Purpose of this Document
+
+The document should help to organize people and ideas around the Apache Tamaya Library. It list possible features,
+ideas and tasks that need to be done. Everybody can have a look at and see, where hos contribution and capabilities
+would fit best.
+
+== Basics
+
+=== Styles, Logo
+
+The project requires
+
+* a good Apache styled logo and
+* CSS styles as needed,
+* an initial web page,
+* a twitter account
+* ...
+
+=== Infrastructure
+
+We should setup all needed infrastructure
+* code repos
+* project modules (including module sites)
+* coding and documentation guidelines
+* automatic builds (CI), included automatic coverage and sonar quality checks.
+* a docker image or appliance, with everything setup, so contributors can easily
+  start contributing...
+* ...
+
+== Main Features
+
+=== Metadata Model
+
+Currently +MetaInfo+ models metadata as a separate constuct. It has been shown that this leads to more complex
+handling when creating composites and makes the API overall more complex. The idea is to model metadata as simple
+key/value pairs, that are part of the provider/configuration data as well, but handled separately. Metadata hereby
+is identified by a starting '_' character in its key. For example refer to the following configuration properties:
+
+[source,listing]
+.Basic Properties
+----------------------------------------------------------------
+a.b.Foo=foo
+a.b.Bar=bar
+a.AnyOther=whatelse
+Something=none
+----------------------------------------------------------------
+
+Now we can model meta-data as follows:
+
+[source,listing]
+.Metadata Properties
+----------------------------------------------------------------
+[a.b].info=An area info
+[a.b.Foo].auth=role1,role2
+[a.b.Foo].encrypt=PGP
+[a.b.Foo].sensitive=true
+[].info=This is a test configuration example.
+----------------------------------------------------------------
+
+The above would model the following:
+
+* The area +a.b+ has the meta property +info+.
+* The entry +a.b.Foo+ has three meta properties +auth,encrypt+ and +sensitive+. These could be interpreted by a security
+  view and used to encrypt the values returned by the configuration instance, if not the current user has one of the
+  specified roles.
+* The last meta data defines an attribute +info+ for the whole provider/configuration (the root area).
+
+Given that the overall entries would be as follows:
+
+[source,listing]
+.Full Properties with Meta Properties
+----------------------------------------------------------------
+[a.b].info=An area info
+a.b.Foo=foo
+[a.b.Foo].auth=role1,role2
+[a.b.Foo].encrypt=PGP
+[a.b.Foo].sensitive=true
+a.b.Bar=bar
+[].info=This is a test configuration example.
+a.AnyOther=whatelse
+Something=none
+----------------------------------------------------------------
+
+The current +MetaInfo+ class could be adapted, so it is reading data from the underlying configuration/provider,
+instead of its own datastructure. This would make a later mapping of configuration and its metadata into DB table, JSON
+etc, much more easier.
+The providers on the other side may suppress any metadata from ordinary output, such
+as +toString()+, Similarly accessing metadata using the official config API (+get, getOrDefault, getAreas+ etc)
+should be disabled. The +MetaInfoBuilder+ must probably as well adapted or redesigned.
+
+=== Collection Support
+
+Add a key/value based model for mapping collections such as sets, maps, list. Implement according adapters.
+In combination with the metadata model above this could be something like:
+
+[source,listing]
+.Collection Support
+----------------------------------------------------------------
+mySet=[a,b,c,d,e\,e,f]
+[mySet].type=set
+#optional define the implementation class
+[mySet].class=java.util.TreeSet
+
+myList=[a,b,c,d,e\,e,f]
+[myList].type=list
+#optional define the implementation class
+[myList].class=java.util.ArrayList
+
+myMap=[a:aa,b:bb,c:cc,d:dd,e:e\,e,f:ff]
+[myMap].type=map
+#optional define the implementation class
+[myMap].class=java.util.TreeMap
+
+#Finally we could also add support for non String based types
+myTypedSet=[1,2,3,4.5,6,7.10.123]
+[myTypedSet].contentClass=java.lang.Double
+myTypedList=[CHF 10.20, EUR 12.20, BTC 0.002]
+[myTypedList].contentType=org.javamoney.moneta.FastMoney
+myTypedMap=[CHF:CHF 10.20, EUR:EUR 12.20, BTC:BTC 0.002]
+[myTypedMap].contentTypes=javax.money.CurrencyUnit,javax.money.MonetaryAmount
+----------------------------------------------------------------
+
+
+=== Management Service
+
+A JMX/Restful API should be designed and built that exposes configuration information. Access should be secured, e.g.
+using OAuth or other security mechasnisms.
+
+=== Management Client
+
+A nice web-based client to manage configuration data would be nice as well. This also includes a UI for creating new
+configurations.
+
+=== Mapping Configuration to a Database
+
+A flexible mechanism should be implemented that allows the use of databases (SQL/JPA as well as non-SQL) for
+storing/retreiving/managing configuration:
+
+* JPA, Hibernate
+* MongoDB
+* ...
+
+=== Integration with OSGI
+
+Examples are to be created and tested, where OSGI is used as the basic runtime platform, e.g. Apache Felix, but as well
+others.
+
+=== Integration with Jigsaw
+
+Once Jigsaw is mature and in a usable (still early) stage, examples are to be created and tested, where OSGI is used as
+the basic runtime platform, e.g. Apache Felix, but as well others.
+
+== Distributed/Remote Configuration Support
+
+=== Configuration Server
+
+A configuration server should be implemented that provides access to configurations and triggers updates to registered
+clients (push). Similarly a poull model should be supported, where clients can asl for the current version id of a certain
+configuration and reload it if necessary.
+
+=== Configuration Distribution Policies
+
+Different configuration distribution policies should be defined any implemented, e.g. distributed cache, restful services,
+web services, EJB/RMI calls, asynchronous queues, publish/subsribe models, ...
+
+=== Dynamic Service Lookup
+
+Configuration Servers and Clients should bea ble to locate each other in different ways:
+
+* with fixed configured IPs, or IP ranges
+* using a dynamic service location protocol like
+** SLP
+** Distributed Maps/Datagrids
+** Apache Zookeeper
+
+=== Configuration Client
+
+A subset of the API would be created that exposes only a well defined subset, of exactly one configuration targeted
+to a certain instance, VM or whatever. The client should be connectable to a server in different ways (see configuration
+distributiont policies).
+
+=== Preferences Support
+
+Write a +PreferencesFactory+ for +java.util.preferences+.
+
+== Third Party Integration
+
+=== Integration with Deltaspike Config
+
+Integration with Deltaspike Config should be implemented and discussed with Deltaspike guys.
+
+=== Integration with Spring
+
+A {name} module should be created that allows Spring to be used either as client or configuration provider.
+
+=== Integration with Jetty
+
+A {name} module should be created that allows a Jetty instance to be deployed and started that is (completely)
+configured based on configuration server.
+
+=== Integration with Tomcat
+
+A {name} module should be created that allows a Tomcat instance to be deployed and started that is (completely)
+configured based on configuration server.
+
+=== Configuration of Java EE
+
+In the Java EE area there would be several options:
+
+=== Configuration of Application Servers (administrative resources)
+
+It should be possible to start a application server instance remotely and configure all administrative resources and the
+deployments based on the configuration service, server to be considered maybe
+
+* Wildfly
+* IBM
+* Weblogic
+* Glassfish
+* Apache Geronimo
+
+==== Configuration of CDI
+
+Implement a CDI extension that controls CDI based on configuration:
+* Add beans
+* Remove (veto) beans
+* Add/remove interceptors
+* Add/remove decorators
+* Activate alternatives
+* ...
+
+==== Configuration of Bean Validation
+
+* Add configurable validators.
+* Configure bean validation based on configuration
+* ...
+
+=== JNDI Support
+
+Write a +JCA+ adapter to provide configuration data through JNDI.
+
+==== Configure JSF
+
+Use the JSF +XML Document+ event to completely configure JSF.
+
+==== Configure Web Services
+
+Provide a WebServiceProviderFactory that may be configured.
+
+==== Configure JPA
+
+Provide an implementation that allows configuration of persistence units. Talk with JPA EG people to see if we can
+get an SPI to hook in a stadardized way.
+
+==== Configure EJBs
+
+Provide an implementation that allows configuration of EJBs and MDBs:
+
+* Register beans
+* Unregister/disable beans
+* Intercept beans
+* Support Configuration Injection (in the worst case using a standard Interceptor, provide supporting artifacts to
+  help developers to achive this easily).
+* Talk with EE8 Umbrella EG (Bill Shanon, Linda DeMichels) on a feasible SPI for EE8, if possible join the EG.
+
+==== Configure ...
+
+Just think of any Java EE aspects that might be worth to be configured. If it can be done, e.g. by managing CDI managed
+resources, it might be easy. For others it is a good idea to discuss things with our matter of experts...
+
+== Special Goodies
+
+=== Maintenance Mode Servlet Filter
+
+Provide a servlet filter that is capable of switching to maintenance mode, based on configuration. Similarly also a forwarding
+servlet could be useful, wehere only request based on configuration are forwarded, other might be rejected or dropped
+as configured.
+
+=== Dynamic Camel Routes
+
+Provides dynamic (configurable) Camel routes, e.g. usable within ServiceMix or standalone.
+
+=== Dynamic CXF
+
+Provides dynamic (configurable) CXF adapters, e.g. usable within ServiceMix or standalone.
+
+=== Configurable Apache MQ
+
+Provides an implementation for configuring Apache MQ.
+
+=== Dynamic Logging
+
+Provide a dynamic solution, where logging systems are configured (handlers, log levels etc), e.g. for
+
+* slf4j
+* log4j
+* JUL
+
+Also interesting is a feature that allows to dynamically log on a more finer level depending on a concrete
+subject/user, session id or server or ...
+
+=== Dynamic ...
+
+Interested to see what other ideas are around. Let us know!
+

http://git-wip-us.apache.org/repos/asf/incubator-tamaya/blob/cf59ebbd/api/src/main/java/org/apache/tamaya/ConfigChangeSet.java
----------------------------------------------------------------------
diff --git a/api/src/main/java/org/apache/tamaya/ConfigChangeSet.java b/api/src/main/java/org/apache/tamaya/ConfigChangeSet.java
new file mode 100644
index 0000000..25b503b
--- /dev/null
+++ b/api/src/main/java/org/apache/tamaya/ConfigChangeSet.java
@@ -0,0 +1,172 @@
+/*
+ * 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;
+
+import java.beans.PropertyChangeEvent;
+import java.util.*;
+
+/**
+ * Event that contains a set of changes that were applied or could be applied.
+ * This class is immutable and thread-safe. To create instances use
+ * {@link ConfigChangeSetBuilder}.
+ *
+ * Created by Anatole on 22.10.2014.
+ */
+public final class ConfigChangeSet {
+    /** The base property provider/configuration. */
+    private PropertyProvider propertyProvider;
+    /** The base version, usable for optimistic locking. */
+    private String baseVersion;
+    /** The recorded changes. */
+    private Map<String,PropertyChangeEvent> changes = new HashMap<>();
+
+    /**
+     * Constructor used by {@link ConfigChangeSetBuilder}.
+     * @param propertyProvider The base property provider/configuration, not null.
+     * @param baseVersion The base version, usable for optimistic locking.
+     * @param changes The recorded changes, not null.
+     */
+    ConfigChangeSet(PropertyProvider propertyProvider, String baseVersion, Collection<PropertyChangeEvent> changes) {
+        this.propertyProvider = Objects.requireNonNull(propertyProvider);
+        this.baseVersion = baseVersion;
+        changes.forEach((c) -> this.changes.put(c.getPropertyName(), c));
+    }
+
+    /**
+     * Get the underlying property provider/configuration.
+     * @return the underlying property provider/configuration, never null.
+     */
+    public PropertyProvider getPropertyProvider(){
+        return this.propertyProvider;
+    }
+
+    /**
+     * Get the base version, usable for optimistic locking.
+     * @return the base version.
+     */
+    public String getBaseVersion(){
+        return baseVersion;
+    }
+
+    /**
+     * Get the changes recorded.
+     * @return the recorded changes, never null.
+     */
+    public Collection<PropertyChangeEvent> getEvents(){
+        return Collections.unmodifiableCollection(this.changes.values());
+    }
+
+    /**
+     * Access the number of removed entries.
+     * @return the number of removed entries.
+     */
+    public int getRemovedSize() {
+        return (int) this.changes.values().stream().filter((e) -> e.getNewValue() == null).count();
+    }
+
+    /**
+     * Access the number of added entries.
+     * @return the number of added entries.
+     */
+    public int getAddedSize() {
+        return (int) this.changes.values().stream().filter((e) -> e.getOldValue() == null).count();
+    }
+
+    /**
+     * Access the number of updated entries.
+     * @return the number of updated entries.
+     */
+    public int getUpdatedSize() {
+        return (int) this.changes.values().stream().filter((e) -> e.getOldValue()!=null && e.getNewValue()!=null).count();
+    }
+
+
+    /**
+     * Checks if the given key was removed.
+     * @param key the target key, not null.
+     * @return true, if the given key was removed.
+     */
+    public boolean isRemoved(String key) {
+        PropertyChangeEvent change = this.changes.get(key);
+        return change != null && change.getNewValue() == null;
+    }
+
+    /**
+     * Checks if the given key was added.
+     * @param key the target key, not null.
+     * @return true, if the given key was added.
+     */
+    public boolean isAdded(String key) {
+        PropertyChangeEvent change = this.changes.get(key);
+        return change != null && change.getOldValue() == null;
+    }
+
+    /**
+     * Checks if the given key was updated.
+     * @param key the target key, not null.
+     * @return true, if the given key was updated.
+     */
+    public boolean isUpdated(String key) {
+        PropertyChangeEvent change = this.changes.get(key);
+        return change != null && change.getOldValue() != null && change.getNewValue() != null;
+    }
+
+    /**
+     * Checks if the given key is added, or updated AND NOT removed.
+     * @param key the target key, not null.
+     * @return true, if the given key was added, or updated BUT NOT removed.
+     */
+    public boolean containsKey(String key) {
+        PropertyChangeEvent change = this.changes.get(key);
+        return change != null && change.getNewValue() != null;
+    }
+
+    /**
+     * CHecks if the current change set does not contain any changes.
+     * @return tru, if the change set is empty.
+     */
+    public boolean isEmpty(){
+        return this.changes.isEmpty();
+    }
+
+    /**
+     * Applies all changes to the given map instance.
+     * @param map the target map.never null.
+     */
+    public void applyChangesTo(Map<String, String> map) {
+        for(Map.Entry<String,PropertyChangeEvent> en: this.changes.entrySet()){
+            if(en.getValue().getNewValue() == null){
+                map.remove(en.getKey());
+            }
+            else{
+                map.put(en.getKey(), (String)en.getValue().getNewValue());
+            }
+        }
+    }
+
+
+    @Override
+    public String toString() {
+        return "ConfigChangeSet{" +
+                "properties=" + propertyProvider +
+                ", baseVersion=" + baseVersion +
+                ", changes=" + changes +
+                '}';
+    }
+}

http://git-wip-us.apache.org/repos/asf/incubator-tamaya/blob/cf59ebbd/api/src/main/java/org/apache/tamaya/ConfigChangeSetBuilder.java
----------------------------------------------------------------------
diff --git a/api/src/main/java/org/apache/tamaya/ConfigChangeSetBuilder.java b/api/src/main/java/org/apache/tamaya/ConfigChangeSetBuilder.java
new file mode 100644
index 0000000..0d30764
--- /dev/null
+++ b/api/src/main/java/org/apache/tamaya/ConfigChangeSetBuilder.java
@@ -0,0 +1,323 @@
+/*
+ * 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;
+
+import java.beans.PropertyChangeEvent;
+import java.util.*;
+
+/**
+ * Models a set of changes to be applied to a configuration/property provider.  Such a set can be applied
+ * to any {@link PropertyProvider} instance. If the provider is mutable it may check the
+ * version given and apply the changes to the provider/configuration, including triggering of regarding
+ * change events.
+ *
+ * Created by Anatole on 06.09.2014.
+ */
+public final class ConfigChangeSetBuilder {
+    /** The recorded changes. */
+    final SortedMap<String, PropertyChangeEvent> delta = new TreeMap<>();
+    /** The underlying configuration/provider. */
+    PropertyProvider source;
+    /** The base version, if any. Used for optimistic version checking. */
+    String baseVersion;
+
+    /**
+     * Constructor.
+     * @param source the underlying configuration/provider, not null.
+     * @param baseVersion the base version, used for optimistic version checking.
+     */
+    private ConfigChangeSetBuilder(PropertyProvider source, String baseVersion) {
+        Objects.requireNonNull(source);
+        this.source = source;
+        this.baseVersion= baseVersion;
+    }
+
+    /**
+     * Creates a new instance of this builder.
+     * @param source the underlying property provider/configuration, not null.
+     * @param baseVersion the base version to be used.
+     * @return the builder for chaining.
+     */
+    public static ConfigChangeSetBuilder of(PropertyProvider source, String baseVersion) {
+        return new ConfigChangeSetBuilder(source, baseVersion);
+    }
+
+    /**
+     * Creates a new instance of this builder.
+     * @param configuration the base configuration, not null.
+     * @return the builder for chaining.
+     */
+    public static ConfigChangeSetBuilder of(Configuration configuration) {
+        return new ConfigChangeSetBuilder(configuration, configuration.getVersion());
+    }
+
+    /**
+     * Add a change as a {@link java.beans.PropertyChangeEvent}.
+     * @param changeEvent the change event.
+     * @return the builder for chaining.
+     */
+    public ConfigChangeSetBuilder addChange(PropertyChangeEvent changeEvent) {
+        Objects.requireNonNull(changeEvent);
+        this.delta.put(changeEvent.getPropertyName(), changeEvent);
+        return this;
+    }
+
+    /**
+     * This method records all changes to be applied to the base property provider/configuration to
+     * achieve the given target state.
+     * @param newState the new target state, not null.
+     * @return the builder for chaining.
+     */
+    public ConfigChangeSetBuilder addChanges(PropertyProvider newState) {
+        compare(newState, this.source).forEach((c) -> this.delta.put(c.getPropertyName(), c));
+        return this;
+    }
+
+    /**
+     * Get the current values, also considering any changes recorded within this change set.
+     * @param key the key of the entry, not null.
+     * @return the value, or null.
+     */
+    public String get(String key) {
+        PropertyChangeEvent change = this.delta.get(key);
+        if(change!=null && !(change.getNewValue()==null)){
+            return (String)change.getNewValue();
+        }
+        return null;
+    }
+
+    /**
+     * Marks the given key(s) from the configuration/properties to be removed.
+     * @param key the key of the entry, not null.
+     * @param otherKeys additional keys to be removed (convenience), not null.
+     * @return the builder for chaining.
+     */
+    public ConfigChangeSetBuilder remove(String key, String... otherKeys) {
+        String oldValue = this.source.get(key).orElse(null);
+        if(oldValue==null){
+            this.delta.remove(key);
+        }
+        this.delta.put(key, new PropertyChangeEvent(this.source, key, oldValue, null));
+        for(String addKey:otherKeys){
+            oldValue = this.source.get(addKey).orElse(null);
+            if(oldValue==null){
+                this.delta.remove(addKey);
+            }
+            this.delta.put(addKey, new PropertyChangeEvent(this.source, addKey, oldValue, null));
+        }
+        return this;
+    }
+
+    /**
+     * Applies the given value.
+     * @param key the key of the entry, not null.
+     * @param value the value to be applied, not null.
+     * @return the builder for chaining.
+     */
+    public ConfigChangeSetBuilder put(String key, String value) {
+        this.delta.put(key, new PropertyChangeEvent(this.source, key, this.source.get(key).orElse(null), Objects.requireNonNull(value)));
+        return this;
+    }
+
+    /**
+     * Applies the given value.
+     * @param key the key of the entry, not null.
+     * @param value the value to be applied, not null.
+     * @return the builder for chaining.
+     */
+    public ConfigChangeSetBuilder put(String key, Boolean value) {
+        this.delta.put(key, new PropertyChangeEvent(this.source, key, this.source.get(key).orElse(null), Objects.requireNonNull(value).toString()));
+        return this;
+    }
+
+    /**
+     * Applies the given value.
+     * @param key the key of the entry, not null.
+     * @param value the value to be applied, not null.
+     * @return the builder for chaining.
+     */
+    public ConfigChangeSetBuilder put(String key, Byte value) {
+        this.delta.put(key, new PropertyChangeEvent(this.source, key, this.source.get(key).orElse(null), Objects.requireNonNull(value).toString()));
+        return this;
+    }
+
+    /**
+     * Applies the given value.
+     * @param key the key of the entry, not null.
+     * @param value the value to be applied, not null.
+     * @return the builder for chaining.
+     */
+    public ConfigChangeSetBuilder put(String key, Character value) {
+        this.delta.put(key, new PropertyChangeEvent(this.source, key, this.source.get(key).orElse(null), Objects.requireNonNull(value).toString()));
+        return this;
+    }
+
+    /**
+     * Applies the given value.
+     * @param key the key of the entry, not null.
+     * @param value the value to be applied, not null.
+     * @return the builder for chaining.
+     */
+    public ConfigChangeSetBuilder put(String key, Short value) {
+        this.delta.put(key, new PropertyChangeEvent(this.source, key, this.source.get(key).orElse(null), Objects.requireNonNull(value).toString()));
+        return this;
+    }
+
+    /**
+     * Applies the given value.
+     * @param key the key of the entry, not null.
+     * @param value the value to be applied, not null.
+     * @return the builder for chaining.
+     */
+    public ConfigChangeSetBuilder put(String key, Integer value) {
+        this.delta.put(key, new PropertyChangeEvent(this.source, key, this.source.get(key).orElse(null), Objects.requireNonNull(value).toString()));
+        return this;
+    }
+
+    /**
+     * Applies the given value.
+     * @param key the key of the entry, not null.
+     * @param value the value to be applied, not null.
+     * @return the builder for chaining.
+     */
+    public ConfigChangeSetBuilder put(String key, Long value) {
+        this.delta.put(key, new PropertyChangeEvent(this.source, key, this.source.get(key).orElse(null), Objects.requireNonNull(value).toString()));
+        return this;
+    }
+
+    /**
+     * Applies the given value.
+     * @param key the key of the entry, not null.
+     * @param value the value to be applied, not null.
+     * @return the builder for chaining.
+     */
+    public ConfigChangeSetBuilder put(String key, Float value) {
+        this.delta.put(key, new PropertyChangeEvent(this.source, key, this.source.get(key).orElse(null), Objects.requireNonNull(value).toString()));
+        return this;
+    }
+
+    /**
+     * Applies the given value.
+     * @param key the key of the entry, not null.
+     * @param value the value to be applied, not null.
+     * @return the builder for chaining.
+     */
+    public ConfigChangeSetBuilder put(String key, Double value) {
+        this.delta.put(key, new PropertyChangeEvent(this.source, key, this.source.get(key).orElse(null), Objects.requireNonNull(value).toString()));
+        return this;
+    }
+
+    /**
+     * Applies the given value.
+     * @param key the key of the entry, not null.
+     * @param value the value to be applied, not null.
+     * @return the builder for chaining.
+     */
+    public ConfigChangeSetBuilder put(String key, Object value) {
+        this.delta.put(key, new PropertyChangeEvent(this.source, key, this.source.get(key).orElse(null), Objects.requireNonNull(value).toString()));
+        return this;
+    }
+
+    /**
+     * Apply all the given values to the base configuration/properties.
+     * @param changes the changes to be applied, not null.
+     * @return the builder for chaining.
+     */
+    public ConfigChangeSetBuilder putAll(Map<String,String> changes) {
+        changes.forEach((k,v) ->
+                this.delta.put(k, new PropertyChangeEvent(this.source, k, this.source.get(k).orElse(null), v)));
+        return this;
+    }
+
+    /**
+     * This method will create a change set that clears all entries from the given base configuration/properties.
+     * @return the builder for chaining.
+     */
+    public ConfigChangeSetBuilder clear() {
+        this.delta.clear();
+        this.source.toMap().forEach((k,v) ->
+                this.delta.put(k, new PropertyChangeEvent(this.source, k, v, null)));
+        return this;
+    }
+
+    /**
+     * Checks if the change set is empty, i.e. does not contain any changes.
+     * @return true, if the set is empty.
+     */
+    public boolean isEmpty(){
+        return this.delta.isEmpty();
+    }
+
+    /**
+     * Resets this change set instance. This will clear all changes done to this set, so the
+     * set will be empty.
+     */
+    public void reset(){
+        this.delta.clear();
+    }
+
+    /**
+     * Builds the corresponding change set.
+     * @return the new change set, never null.
+     */
+    public ConfigChangeSet build() {
+        return new ConfigChangeSet(this.source, baseVersion, Collections.unmodifiableCollection(this.delta.values()));
+    }
+
+    /**
+     * Compares the two property providers/configurations and creates a collection of all changes
+     * that must be appied to render {@code map1} into {@code map2}.
+     * @param map1 the source map, not null.
+     * @param map2 the target map, not null.
+     * @return a collection of change events, never null.
+     */
+    public static Collection<PropertyChangeEvent> compare(PropertyProvider map1, PropertyProvider map2) {
+        List<PropertyChangeEvent> changes = new ArrayList<>();
+        for (Map.Entry<String, String> en : map1.toMap().entrySet()) {
+            Optional<String> val = map2.get(en.getKey());
+            if(!val.isPresent()) {
+                changes.add(new PropertyChangeEvent(map1, en.getKey(), null, en.getValue()));
+            }
+            else if(!val.get().equals(en.getValue())){
+                changes.add(new PropertyChangeEvent(map1, en.getKey(), val.get(), en.getValue()));
+            }
+        }
+        for (Map.Entry<String, String> en : map2.toMap().entrySet()) {
+            Optional<String> val = map1.get(en.getKey());
+            if(!val.isPresent()) {
+                changes.add(new PropertyChangeEvent(map1, en.getKey(), null, en.getValue()));
+            }
+            else if(!val.equals(en.getValue())){
+                changes.add(new PropertyChangeEvent(map1, en.getKey(), val.get(), en.getValue()));
+            }
+        }
+        return changes;
+    }
+
+    /*
+     * (non-Javadoc)
+     * @see java.lang.Object#toString()
+     */
+    @Override
+    public String toString() {
+        return "PropertyChangeEventBuilder [source=" + source + ", " +
+                ", delta=" + delta + "]";
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/incubator-tamaya/blob/cf59ebbd/api/src/main/java/org/apache/tamaya/ConfigException.java
----------------------------------------------------------------------
diff --git a/api/src/main/java/org/apache/tamaya/ConfigException.java b/api/src/main/java/org/apache/tamaya/ConfigException.java
new file mode 100644
index 0000000..bac2ef4
--- /dev/null
+++ b/api/src/main/java/org/apache/tamaya/ConfigException.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;
+
+/**
+ * Exception class (runtime exception) for configuration issues.
+ */
+public class ConfigException extends RuntimeException{
+
+    private static final long serialVersionUID = -5886094818057522680L;
+
+    /**
+     * Creates a new configuration exception.
+     * @param message the exception message, not null.
+     */
+    public ConfigException(String message){
+        super(message);
+    }
+
+    /**
+     * Creates a new configuration exception.
+     * @param message the exception message, not null.
+     * @param t the throwable.
+     */
+    public ConfigException(String message, Throwable t){
+        super(message, t);
+    }
+}

http://git-wip-us.apache.org/repos/asf/incubator-tamaya/blob/cf59ebbd/api/src/main/java/org/apache/tamaya/ConfigOperator.java
----------------------------------------------------------------------
diff --git a/api/src/main/java/org/apache/tamaya/ConfigOperator.java b/api/src/main/java/org/apache/tamaya/ConfigOperator.java
new file mode 100644
index 0000000..a59712b
--- /dev/null
+++ b/api/src/main/java/org/apache/tamaya/ConfigOperator.java
@@ -0,0 +1,37 @@
+/*
+ * 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;
+
+
+/**
+ * Interface for an filter/operator that converts a configured String into another String. One typical
+ * use case would the the decryption of an encrypted configuration value.
+ */
+@FunctionalInterface
+public interface ConfigOperator{
+
+    /**
+     * Method that creates a Configuration from another Configuration. This can be used for implementing
+     * views, security constraints or for overriding/inheriting of configuration.
+     * @param config The target configuration to be operated, never nnull.
+     * @return the operated configuration, never null.
+     */
+    Configuration operate(Configuration config);
+
+}

http://git-wip-us.apache.org/repos/asf/incubator-tamaya/blob/cf59ebbd/api/src/main/java/org/apache/tamaya/ConfigQuery.java
----------------------------------------------------------------------
diff --git a/api/src/main/java/org/apache/tamaya/ConfigQuery.java b/api/src/main/java/org/apache/tamaya/ConfigQuery.java
new file mode 100644
index 0000000..c296d12
--- /dev/null
+++ b/api/src/main/java/org/apache/tamaya/ConfigQuery.java
@@ -0,0 +1,37 @@
+/*
+ * 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;
+
+
+/**
+ * Interface for an query that converts a Configuration into another object. One typical
+ * use cases would creating a complex configuration parameter type from a Configuration instance or
+ * constraint views on configuration.
+ */
+@FunctionalInterface
+public interface ConfigQuery<T>{
+
+    /**
+     * Queries the given configuration.
+     * @param config the configuration to be wuiried, not null.
+     * @return the result T.
+     */
+    T query(Configuration config);
+
+}

http://git-wip-us.apache.org/repos/asf/incubator-tamaya/blob/cf59ebbd/api/src/main/java/org/apache/tamaya/Configuration.java
----------------------------------------------------------------------
diff --git a/api/src/main/java/org/apache/tamaya/Configuration.java b/api/src/main/java/org/apache/tamaya/Configuration.java
new file mode 100644
index 0000000..a23f44c
--- /dev/null
+++ b/api/src/main/java/org/apache/tamaya/Configuration.java
@@ -0,0 +1,376 @@
+/*
+ * 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;
+
+import com.sun.javafx.scene.control.behavior.OptionalBoolean;
+
+import java.beans.PropertyChangeListener;
+import java.util.*;
+import java.util.function.Predicate;
+import java.util.stream.Collectors;
+
+/**
+ * A configuration models a aggregated set of properties, identified by a unique key, but adds higher level access functions to
+ * a {@link PropertyProvider}. Hereby in most cases a configuration is a wrapper around a composite
+ * {@link PropertyProvider} instance, which may combine multiple child providers in well defined tree like structure,
+ * where nodes define logically the rules of priority, filtering, combination and overriding.
+ * <br/>
+ * <h3>Implementation Requirements</h3>
+ * Implementations of this interface must be
+ * <ul>
+ * <li>Thread safe.
+ * <li>Immutable
+ * </ul>
+ * It is not recommended that implementations also are serializable, since the any configuration can be <i>freezed</i>
+ * by reading out its complete configuration map into a serializable and remotable structure. This helps significantly
+ * simplifying the development of this interface, e.g. for being backed up by systems and stores that are not part of
+ * this library at all.
+ */
+public interface Configuration extends PropertyProvider{
+
+    /**
+     * Get the property value as {@link Boolean}.
+     *
+     * @param key the property's absolute, or relative path, e.g. {@code
+     *            a/b/c/d.myProperty}.
+     * @return the property's value.
+     */
+    default OptionalBoolean getBoolean(String key){
+        Optional<Boolean> val = get(key, Boolean.class);
+        if(val.isPresent()){
+            if(val.get()){
+                return OptionalBoolean.TRUE;
+            }
+            return OptionalBoolean.FALSE;
+        }
+        return OptionalBoolean.ANY;
+    }
+
+    /**
+     * Get the property value as {@link Integer}.
+     *
+     * @param key the property's absolute, or relative path, e.g. @code
+     *            a/b/c/d.myProperty}.
+     * @return the property's value.
+     */
+    default OptionalInt getInteger(String key){
+        Optional<Integer> val = get(key, Integer.class);
+        if(val.isPresent()){
+            return OptionalInt.of(val.get());
+        }
+        return OptionalInt.empty();
+    }
+
+
+    /**
+     * Get the property value as {@link Long}.
+     *
+     * @param key the property's absolute, or relative path, e.g. @code
+     *            a/b/c/d.myProperty}.
+     * @return the property's value.
+     */
+    default OptionalLong getLong(String key){
+        Optional<Long> val = get(key, Long.class);
+        if(val.isPresent()){
+            return OptionalLong.of(val.get());
+        }
+        return OptionalLong.empty();
+    }
+
+
+    /**
+     * Get the property value as {@link Double}.
+     *
+     * @param key the property's absolute, or relative path, e.g. @code
+     *            a/b/c/d.myProperty}.
+     * @return the property's value.
+     * @throws IllegalArgumentException if no such property exists.
+     */
+    default OptionalDouble getDouble(String key){
+
+        Optional<Double> val = get(key, Double.class);
+        if(val.isPresent()){
+            return OptionalDouble.empty().of(val.get());
+        }
+        return OptionalDouble.empty();
+    }
+
+
+    /**
+     * Get the property value as type {@code Class<T>}.
+     * <p>
+     * If {@code Class<T>} is not one of
+     * {@code Boolean, Short, Integer, Long, Float, Double, BigInteger,
+     * BigDecimal, String} , an according adapter must be
+     * available to perform the conversion from {@link String} to
+     * {@code Class<T>}.
+     *
+     * @param key     the property's absolute, or relative path, e.g. @code
+     *                a/b/c/d.myProperty}.
+     * @param adapter the PropertyAdapter to perform the conversion from
+     *                {@link String} to {@code Class<T>}, not {@code null}.
+     * @return the property's value.
+     * @throws IllegalArgumentException if the value could not be converted to the required target
+     *                                  type, or no such property exists.
+     */
+    default <T> Optional<T> getAdapted(String key, PropertyAdapter<T> adapter){
+        Optional<String> value = get(key);
+        if(value.isPresent()) {
+            return Optional.ofNullable(adapter.adapt(value.get()));
+        }
+        return Optional.empty();
+    }
+
+
+    /**
+     * Get the property value as type T. This will implicitly require a corresponding {@link
+     * PropertyAdapter} to be available that is capable of providing type T
+     * from the given String value.
+     *
+     * @param key          the property's absolute, or relative path, e.g. @code
+     *                     a/b/c/d.myProperty}.
+     * @param type         The target type required, not null.
+     * @return the property's value.
+     * @throws IllegalArgumentException if the value could not be converted to the required target
+     *                                  type.
+     */
+    <T> Optional<T> get(String key, Class<T> type);
+
+    /**
+     * Return a set with all fully qualifies area names.
+     *
+     * @return s set with all areas, never {@code null}.
+     */
+    default Set<String> getAreas(){
+        final Set<String> areas = new HashSet<>();
+        this.keySet().forEach(s -> {
+            int index = s.lastIndexOf('.');
+            if(index > 0){
+                areas.add(s.substring(0, index));
+            }
+            else{
+                areas.add("<root>");
+            }
+        });
+        return areas;
+    }
+
+    /**
+     * Return a set with all fully qualified area names, containing the transitive closure also including all
+     * subarea names, regardless if properties are accessible or not.
+     *
+     * @return s set with all transitive areas, never {@code null}.
+     */
+    default Set<String> getTransitiveAreas(){
+        final Set<String> transitiveAreas = new HashSet<>();
+        getAreas().forEach(s -> {
+            int index = s.lastIndexOf('.');
+            if (index < 0) {
+                transitiveAreas.add("<root>");
+            } else {
+                while (index > 0) {
+                    s = s.substring(0, index);
+                    transitiveAreas.add(s);
+                    index = s.lastIndexOf('.');
+                }
+            }
+        });
+        return transitiveAreas;
+    }
+
+    /**
+     * Return a set with all fully qualified area names, containing only the
+     * areas that match the predicate and have properties attached
+     *
+     * @param predicate A predicate to deternine, which areas should be returned, not {@code null}.
+     * @return s set with all areas, never {@code null}.
+     */
+    default Set<String> getAreas(final Predicate<String> predicate){
+        return getAreas().stream().filter(predicate).collect(Collectors.toCollection(TreeSet::new));
+    }
+
+    /**
+     * Return a set with all fully qualified area names, containing the transitive closure also including all
+     * subarea names, regardless if properties are accessible or not.
+     *
+     * @param predicate A predicate to deternine, which areas should be returned, not {@code null}.
+     * @return s set with all transitive areas, never {@code null}.
+     */
+    default Set<String> getTransitiveAreas(Predicate<String> predicate){
+        return getTransitiveAreas().stream().filter(predicate).collect(Collectors.toCollection(TreeSet::new));
+    }
+
+    /**
+     * Allows to evaluate if an area exists.
+     *
+     * @param key the configuration area (sub)path.
+     * @return {@code true}, if such a node exists.
+     */
+    default boolean containsArea(String key){
+        return getAreas().contains(key);
+    }
+
+    /**
+     * Extension point for adjusting configuration.
+     *
+     * @param operator A configuration operator, e.g. a filter, or an adjuster
+     *                 combining configurations.
+     * @return the new adjusted configuration, never {@code null}.
+     */
+    default Configuration with(ConfigOperator operator){
+        return operator.operate(this);
+    }
+
+    /**
+     * Query some value from a configuration.
+     *
+     * @param query the query, never {@code null}.
+     * @return the result
+     */
+    default <T> T query(ConfigQuery<T> query){
+        return query.query(this);
+    }
+
+    /**
+     * Field that allows property providers to be versioned, meaning that each change on a provider requires this value
+     * to be incremented by one. This can be easily used to implement versioning (and optimistic locking)
+     * in distributed (remote) usage scenarios.
+     * @return the version of the current instance, or 'N/A'.
+     */
+    default String getVersion(){return "N/A";}
+
+    /**
+     * Add a ConfigChangeListener to this configuration instance.
+     * @param l the listener, not null.
+     */
+    void addPropertyChangeListener(PropertyChangeListener l);
+
+    /**
+     * Removes a ConfigChangeListener to this configuration instance.
+     * @param l the listener, not null.
+     */
+    void removePropertyChangeListener(PropertyChangeListener l);
+
+    /**
+     * Allows to check if a configuration with a given name is defined.
+     *
+     * @param name the configuration's name, not null, not empty.
+     * @return true, if such a configuration is defined.
+     */
+    public static boolean isDefined(String name){
+        return ConfigurationManager.isConfigurationDefined(name);
+    }
+
+    /**
+     * Access a configuration by name.
+     *
+     * @param name the configuration's name, not null, not empty.
+     *             @param template the annotated configuration's
+     *                             template interface, not null.
+     * @return the corresponding Configuration instance, never null.
+     * @throws ConfigException if no such configuration is defined.
+     */
+    public static <T> T of(String name, Class<T> template){
+        return ConfigurationManager.getConfiguration(name, template);
+    }
+
+
+    /**
+     * Access a configuration by name.
+     *
+     * @param name the configuration's name, not null, not empty.
+     * @return the corresponding Configuration instance, never null.
+     * @throws ConfigException if no such configuration is defined.
+     */
+    public static Configuration of(String name){
+        return ConfigurationManager.getConfiguration(name);
+    }
+
+    /**
+     * Access a configuration.
+     *
+     * @return the corresponding Configuration instance, never null.
+     * @throws ConfigException if no such configuration is defined.
+     */
+    public static Configuration of(){
+        return ConfigurationManager.getConfiguration();
+    }
+
+    /**
+     * Access a typed configuration, based on the default configuration.
+     *
+     * @param type the annotated configuration type (could be an interface or
+     *             a non abstract class), not null.
+     * @return the corresponding typed Configuration instance, never null.
+     * @throws ConfigException if the configuration could not be resolved.
+     */
+    public static <T> T of(Class<T> type){
+        return ConfigurationManager.getConfiguration(type);
+    }
+
+    /**
+     * Configures an instance, by resolving and injecting the configuration
+     * entries.
+     *
+     * @param instance the instance with configuration annotations, not null.
+     * @return the corresponding typed Configuration instance, never null.
+     * @throws ConfigException if the configuration could not be resolved.
+     */
+    public static void configure(Object instance){
+        ConfigurationManager.configure(instance);
+    }
+
+    /**
+     * Evaluate the current expression based on the current configuration valid.
+     *
+     * @param expression the expression, not null.
+     * @return the evaluated config expression.
+     */
+    public static String evaluateValue(String expression){
+        return ConfigurationManager.evaluateValue(expression);
+    }
+
+    /**
+     * Evaluate the current expression based on the current configuration valid.
+     *
+     * @param config     The configuration to be used for evluating, not null.
+     * @param expression the expression, not null.
+     * @return the evaluated config expression.
+     */
+    public static String evaluateValue(Configuration config, String expression){
+        return ConfigurationManager.evaluateValue(config, expression);
+    }
+
+    /**
+     * Adds a (global) {@link java.beans.PropertyChangeListener} instance that listens to all kind of config changes.
+     * @param listener the {@link java.beans.PropertyChangeListener} instance to be added, not null.
+     */
+    public static void addGlobalPropertyChangeListener(PropertyChangeListener listener){
+        ConfigurationManager.addPropertyChangeListener(listener);
+    }
+
+    /**
+     * Removes a (global) {@link java.beans.PropertyChangeListener} instance that listens to all kind of config changes,
+     * if one is currently registered.
+     * @param listener the {@link java.beans.PropertyChangeListener} instance to be removed, not null.
+     */
+    public static void removeGlobalPropertyChangeListener(PropertyChangeListener listener){
+        ConfigurationManager.removePropertyChangeListener(listener);
+    }
+}

http://git-wip-us.apache.org/repos/asf/incubator-tamaya/blob/cf59ebbd/api/src/main/java/org/apache/tamaya/ConfigurationManager.java
----------------------------------------------------------------------
diff --git a/api/src/main/java/org/apache/tamaya/ConfigurationManager.java b/api/src/main/java/org/apache/tamaya/ConfigurationManager.java
new file mode 100644
index 0000000..67d4ccb
--- /dev/null
+++ b/api/src/main/java/org/apache/tamaya/ConfigurationManager.java
@@ -0,0 +1,161 @@
+/*
+ * 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;
+
+import org.apache.tamaya.spi.Bootstrap;
+import org.apache.tamaya.spi.ConfigurationManagerSingletonSpi;
+
+import java.beans.PropertyChangeListener;
+import java.util.Optional;
+
+/**
+ * Singleton accessor for accessing {@link Configuration} instances and
+ * proxied configuration templates.
+ */
+final class ConfigurationManager{
+    /**
+     * The backing SPI instance.
+     */
+    private static final ConfigurationManagerSingletonSpi configManagerSingletonSpi = loadConfigServiceSingletonSpi();
+
+    /**
+     * Private singleton constructor.
+     */
+    private ConfigurationManager(){
+    }
+
+    /**
+     * Method to initially load the singleton SPI from the {@link org.apache.tamaya.spi.Bootstrap} mechanism.
+     * The instance loaded will be used until the VM is shutdown. In case use cases require more flexibility
+     * it should be transparently implemented in the SPI implementation. This singleton will simply delegate calls
+     * and not cache any responses.
+     *
+     * @return the SPI, never null.
+     */
+    private static ConfigurationManagerSingletonSpi loadConfigServiceSingletonSpi(){
+        return Bootstrap.getService(ConfigurationManagerSingletonSpi.class);
+    }
+
+    /**
+     * Allows to check if a configuration with a given name is defined.
+     *
+     * @param name the configuration's name, not null, not empty.
+     * @return true, if such a configuration is defined.
+     */
+    public static boolean isConfigurationDefined(String name){
+        return Optional.of(configManagerSingletonSpi).get().isConfigurationDefined(name);
+    }
+
+    /**
+     * Access a configuration by name.
+     *
+     * @param name the configuration's name, not null, not empty.
+     *             @param template the annotated configuration's
+     *                             template interface, not null.
+     * @return the corresponding Configuration instance, never null.
+     * @throws ConfigException if no such configuration is defined.
+     */
+    public static <T> T getConfiguration(String name, Class<T> template){
+        return Optional.of(configManagerSingletonSpi).get().getConfiguration(name, template);
+    }
+
+
+    /**
+     * Access a configuration by name.
+     *
+     * @param name the configuration's name, not null, not empty.
+     * @return the corresponding Configuration instance, never null.
+     * @throws ConfigException if no such configuration is defined.
+     */
+    public static Configuration getConfiguration(String name){
+        return Optional.of(configManagerSingletonSpi).get().getConfiguration(name);
+    }
+
+    /**
+     * Access a configuration.
+     *
+     * @return the corresponding Configuration instance, never null.
+     * @throws ConfigException if no such configuration is defined.
+     */
+    public static Configuration getConfiguration(){
+        return Optional.of(configManagerSingletonSpi).get().getConfiguration();
+    }
+
+    /**
+     * Access a typed configuration, based on the default configuration.
+     *
+     * @param type the annotated configuration type (could be an interface or
+     *             a non abstract class), not null.
+     * @return the corresponding typed Configuration instance, never null.
+     * @throws ConfigException if the configuration could not be resolved.
+     */
+    public static <T> T getConfiguration(Class<T> type){
+        return Optional.of(configManagerSingletonSpi).get().getConfiguration(type);
+    }
+
+    /**
+     * Configures an instance, by resolving and injecting the configuration
+     * entries.
+     *
+     * @param instance the instance with configuration annotations, not null.
+     * @return the corresponding typed Configuration instance, never null.
+     * @throws ConfigException if the configuration could not be resolved.
+     */
+    public static void configure(Object instance){
+        Optional.of(configManagerSingletonSpi).get().configure(instance);
+    }
+
+    /**
+     * Evaluate the current expression based on the current configuration valid.
+     *
+     * @param expression the expression, not null.
+     * @return the evaluated config expression.
+     */
+    public static String evaluateValue(String expression){
+        return evaluateValue(getConfiguration(), expression);
+    }
+
+    /**
+     * Evaluate the current expression based on the current configuration valid.
+     *
+     * @param config     The configuration to be used for evluating, not null.
+     * @param expression the expression, not null.
+     * @return the evaluated config expression.
+     */
+    public static String evaluateValue(Configuration config, String expression){
+        return Optional.of(configManagerSingletonSpi).get().evaluateValue(config, expression);
+    }
+
+    /**
+     * Adds a (global) {@link java.beans.PropertyChangeListener} instance that listens to all kind of config changes.
+     * @param listener the {@link java.beans.PropertyChangeListener} instance to be added, not null.
+     */
+    public static void addPropertyChangeListener(PropertyChangeListener listener){
+        Optional.of(configManagerSingletonSpi).get().addPropertyChangeListener(listener);
+    }
+
+    /**
+     * Removes a (global) {@link java.beans.PropertyChangeListener} instance that listens to all kind of config changes,
+     * if one is currently registered.
+     * @param listener the {@link java.beans.PropertyChangeListener} instance to be removed, not null.
+     */
+    public static void removePropertyChangeListener(PropertyChangeListener listener){
+        Optional.of(configManagerSingletonSpi).get().removePropertyChangeListener(listener);
+    }
+}

http://git-wip-us.apache.org/repos/asf/incubator-tamaya/blob/cf59ebbd/api/src/main/java/org/apache/tamaya/Environment.java
----------------------------------------------------------------------
diff --git a/api/src/main/java/org/apache/tamaya/Environment.java b/api/src/main/java/org/apache/tamaya/Environment.java
new file mode 100644
index 0000000..3523083
--- /dev/null
+++ b/api/src/main/java/org/apache/tamaya/Environment.java
@@ -0,0 +1,167 @@
+/*
+ * 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;
+
+import java.util.List;
+import java.util.Map;
+import java.util.Optional;
+import java.util.Set;
+
+/**
+ * Models a runtime environment. Instances of this class are used to
+ * evaluate the correct configuration artifacts.<br/>
+ * <h3>Implementation Requirements</h3>
+ * <p>
+ * Implementations of this interface must be
+ * <ul>
+ * <li>Thread safe.
+ * <li>Immutable
+ * <li>serializable
+ * </ul>
+ */
+public interface Environment extends StageSupplier, Iterable<Environment>{
+
+    /**
+     * Get a unique type (within this VM) for this environment.
+     * Types represent the environment level within the hierarchy
+     * of possible environments, e.g. {@code system, ear, webapp, tenant}.
+     */
+    String getEnvironmentType();
+
+    /**
+     * Get a unique name (in combination with the environment type within this VM)
+     * for this environment instance.
+     * Where a human readable name is available this would be preferable
+     * over a technical key/UUID.
+     * @return a unique id for this environment, when comined with the environment type.
+     */
+    String getEnvironmentId();
+
+    /**
+     * Access a property.
+     * @param key the property's key, not null.
+     * @return the property's value.
+     */
+    Optional<String> get(String key);
+
+    /**
+     * Checks if a property is defined.
+     * @param key the property's key, not null.
+     * @return true, if the property is existing.
+     */
+    boolean containsKey(String key);
+
+    /**
+     * Access a property.
+     * @param key the property's key, not null.
+     * @return the property's value.
+     */
+    default String getOrDefault(String key, String defaultValue){
+        return get(key).orElse(defaultValue);
+    }
+
+    /**
+     * Access the set of property keys, defined by this provider.
+     * @return the key set, never null.
+     */
+    Set<String> keySet();
+
+    /**
+     * Get an qualified path to this environment instance, by appending the
+     * current environment id and type (in backets) with the ones of its parent and so on, e.g.
+     * <code>root[system].HumanOne[ear].rest[webapp].atsticks[user]</code>
+     * @return the qualified path of this environment instance
+     */
+    String getContext();
+
+    /**
+     * Get the parent context.
+     * @return the parent context, or null.
+     */
+    Environment getParentEnvironment();
+
+    /**
+     * Access the environment as Map.
+     * @return the Map instance containing the environments properties, never null.
+     */
+    Map<String,String> toMap();
+
+    /**
+     * Get the current {@link org.apache.tamaya.Environment}. The environment is used to determine the current runtime state, which
+     * is important for returning the correct configuration.
+     * @return the current Environment, never null.
+     */
+    public static Environment of(){
+        return EnvironmentManager.getEnvironment();
+    }
+
+    /**
+     * Get the current root (startup/machine/VM) {@link org.apache.tamaya.Environment}.
+     * @return the current root Environment, never null.
+     */
+    public static Environment getRootEnvironment(){
+        return EnvironmentManager.getRootEnvironment();
+    }
+
+    /**
+     * Evaluate the overall chain of possible environments.
+     * @return the hierarchy chain of possible Environments.
+     */
+    public static List<String> getEnvironmentTypeOrder(){
+        return EnvironmentManager.getEnvironmentTypeOrder();
+    }
+
+    /**
+     * Evaluate the current type chain of environments.
+     * @return the current type chain of Environments.
+     */
+    public static List<String> getEnvironmentHierarchy(){
+        return EnvironmentManager.getEnvironmentHierarchy();
+    }
+
+    /**
+     * Get a environment of the given environment type and context.
+     * @param environmentType the target type, not null.
+     * @param contextId the target context, not null.
+     * @return the corresponding environment, if available.
+     */
+    public static Optional<Environment> getEnvironment(String environmentType, String contextId){
+        return EnvironmentManager.getEnvironment(environmentType, contextId);
+    }
+
+    /**
+     * Get the currently known environment contexts of a given environment type.
+     * @param environmentType the target environment type.
+     * @return the corresponding environment contexts known, never null.
+     */
+    public static Set<String> getEnvironmentContexts(String environmentType){
+        return EnvironmentManager.getEnvironmentContexts(environmentType);
+    }
+
+    /**
+     * Allows to check, if the czurrent environment type is one of the current active environment types.
+     * @param environmentType the environment type to be queried.
+     * @return true, if the czurrent environment type is one of the current active environment types.
+     */
+    public static boolean isEnvironmentActive(String environmentType){
+        return EnvironmentManager.isEnvironmentActive(environmentType);
+    }
+
+
+}

http://git-wip-us.apache.org/repos/asf/incubator-tamaya/blob/cf59ebbd/api/src/main/java/org/apache/tamaya/EnvironmentManager.java
----------------------------------------------------------------------
diff --git a/api/src/main/java/org/apache/tamaya/EnvironmentManager.java b/api/src/main/java/org/apache/tamaya/EnvironmentManager.java
new file mode 100644
index 0000000..7de86a6
--- /dev/null
+++ b/api/src/main/java/org/apache/tamaya/EnvironmentManager.java
@@ -0,0 +1,136 @@
+/*
+ * 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;
+
+import org.apache.tamaya.spi.Bootstrap;
+import org.apache.tamaya.spi.EnvironmentManagerSingletonSpi;
+
+import java.util.List;
+import java.util.Optional;
+import java.util.Set;
+
+
+/**
+ * Singleton accessor class for the current environment.
+ */
+final class EnvironmentManager{
+
+    private static final EnvironmentManagerSingletonSpi environmentManagerSingletonSpi = loadContextProviderSpi();
+
+    /**
+     * Private singleton constructor.
+     */
+    private EnvironmentManager(){}
+
+    /**
+     * Method to load the environment SPI during initial load.
+     * @return the EnvironmentProviderSpi SPI, never null.
+     */
+    private static EnvironmentManagerSingletonSpi loadContextProviderSpi(){
+        return Bootstrap.getService(EnvironmentManagerSingletonSpi.class);
+    }
+
+    /**
+     * Get the current {@link Environment}. The environment is used to determine the current runtime state, which
+     * is important for returning the correct configuration.
+     * @return the current Environment, never null.
+     */
+    public static Environment getEnvironment(){
+        return Optional.ofNullable(environmentManagerSingletonSpi).orElseThrow(
+                () -> new IllegalStateException("No SPI loaded.")
+        ).getEnvironment();
+    }
+
+    /**
+     * Get the current root (startup/machine/VM) {@link Environment}.
+     * @return the current root Environment, never null.
+     */
+    public static Environment getRootEnvironment(){
+        return Optional.ofNullable(environmentManagerSingletonSpi).orElseThrow(
+                () -> new IllegalStateException("No SPI loaded.")
+        ).getRootEnvironment();
+    }
+
+    /**
+     * Evaluate the overall chain of possible environments.
+     * @return the hierarchy chain of possible Environments.
+     */
+    public static List<String> getEnvironmentTypeOrder(){
+        return Optional.ofNullable(environmentManagerSingletonSpi).orElseThrow(
+                () -> new IllegalStateException("No SPI loaded.")
+        ).getEnvironmentTypeOrder();
+    }
+
+    /**
+     * Evaluate the current type chain of environments.
+     * @return the current type chain of Environments.
+     */
+    public static List<String> getEnvironmentHierarchy(){
+        return Optional.ofNullable(environmentManagerSingletonSpi).orElseThrow(
+                () -> new IllegalStateException("No SPI loaded.")
+        ).getEnvironmentHierarchy();
+    }
+
+    /**
+     * Get the current environment of the given environment type.
+     * @param environmentType the target type.
+     * @return the corresponding environment
+     * @throws IllegalArgumentException if not such type is present or active.
+     */
+    public static Optional<Environment> getEnvironment(String environmentType){
+        return Optional.ofNullable(environmentManagerSingletonSpi).orElseThrow(
+                () -> new IllegalStateException("No SPI loaded.")
+        ).getEnvironment(environmentType);
+    }
+
+    /**
+     * Get a environment of the given environment type and context.
+     * @param environmentType the target type, not null.
+     * @param contextId the target context, not null.
+     * @return the corresponding environment, if available.
+     */
+    public static Optional<Environment> getEnvironment(String environmentType, String contextId){
+        return Optional.ofNullable(environmentManagerSingletonSpi).orElseThrow(
+                () -> new IllegalStateException("No SPI loaded.")
+        ).getEnvironment(environmentType, contextId);
+    }
+
+    /**
+     * Get the currently known environment contexts of a given environment type.
+     * @param environmentType the target environment type.
+     * @return the corresponding environment contexts known, never null.
+     */
+    public static Set<String> getEnvironmentContexts(String environmentType){
+        return Optional.ofNullable(environmentManagerSingletonSpi).orElseThrow(
+                () -> new IllegalStateException("No SPI loaded.")
+        ).getEnvironmentContexts(environmentType);
+    }
+
+    /**
+     * Allows to check, if the czurrent environment type is one of the current active environment types.
+     * @param environmentType the environment type to be queried.
+     * @return true, if the czurrent environment type is one of the current active environment types.
+     */
+    public static boolean isEnvironmentActive(String environmentType){
+        return Optional.ofNullable(environmentManagerSingletonSpi).orElseThrow(
+                () -> new IllegalStateException("No SPI loaded.")
+        ).isEnvironmentActive(environmentType);
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/incubator-tamaya/blob/cf59ebbd/api/src/main/java/org/apache/tamaya/MetaInfo.java
----------------------------------------------------------------------
diff --git a/api/src/main/java/org/apache/tamaya/MetaInfo.java b/api/src/main/java/org/apache/tamaya/MetaInfo.java
new file mode 100644
index 0000000..8be9122
--- /dev/null
+++ b/api/src/main/java/org/apache/tamaya/MetaInfo.java
@@ -0,0 +1,69 @@
+/*
+ * 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;
+
+import java.util.*;
+
+/**
+ * Simple class to represent configuration meta information. Metainformation can be related to the holw
+ * configuration or some if its entries.
+ */
+public final class MetaInfo{
+
+    private final Map<String, String> metaInfo = new HashMap<>();
+
+    MetaInfo(MetaInfoBuilder builder){
+        Objects.requireNonNull(builder);
+        this.metaInfo.putAll(builder.map);
+    }
+
+    public static MetaInfo of(String info){
+        return MetaInfoBuilder.of(info).build();
+    }
+
+    public String get(String key){
+        return this.metaInfo.get(key);
+
+    }
+    public Set<String> keySet(){
+        return this.metaInfo.keySet();
+    }
+
+    public Map<? extends String,? extends String> toMap(){
+        return Collections.unmodifiableMap(this.metaInfo);
+    }
+
+    @Override
+    public String toString(){
+        StringBuilder b = new StringBuilder("MetaInfo[");
+        for(Map.Entry<String,String> en:metaInfo.entrySet()){
+            b.append(escape(en.getKey())).append('=').append(escape(en.getValue())).append(", ");
+        }
+        if(!metaInfo.isEmpty()){
+            b.setLength(b.length()-2);
+        }
+        b.append(']');
+        return b.toString();
+    }
+
+    static String escape(String val){
+        return val.replaceAll("=", "\\\\=").replaceAll("\\[", "\\\\[").replaceAll("]", "\\\\]").replaceAll("\\,", "\\\\,");
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/incubator-tamaya/blob/cf59ebbd/api/src/main/java/org/apache/tamaya/MetaInfoBuilder.java
----------------------------------------------------------------------
diff --git a/api/src/main/java/org/apache/tamaya/MetaInfoBuilder.java b/api/src/main/java/org/apache/tamaya/MetaInfoBuilder.java
new file mode 100644
index 0000000..7c527bc
--- /dev/null
+++ b/api/src/main/java/org/apache/tamaya/MetaInfoBuilder.java
@@ -0,0 +1,162 @@
+/*
+ * 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;
+
+import java.util.Arrays;
+import java.util.Map;
+import java.util.Objects;
+import java.util.concurrent.ConcurrentHashMap;
+
+/**
+ * Builder class to create new instances of {@lin MetaInfo}.
+ */
+public final class MetaInfoBuilder{
+
+    public static final String METAINFO = "_metainfo";
+    public static final String TIMESTAMP = "timestamp";
+    public static final String CONTEXT = "context";
+    public static final String NAME = "name";
+    public static final String INFO = "info";
+    public static final String TYPE = "type";
+    public static final String SOURCE = "source";
+    public static final String ENVIRONMENT = "environment";
+    public static final String SOURCE_EXPRESSION = "source-expression";
+
+    Map<String,String> map = new ConcurrentHashMap<>();
+
+    private MetaInfoBuilder(MetaInfo metaInfo){
+        if(metaInfo!=null){
+            this.map.putAll(metaInfo.toMap());
+        }
+    }
+
+    public static MetaInfoBuilder of(MetaInfo metaInfo){
+        return new MetaInfoBuilder(metaInfo);
+    }
+
+    public static MetaInfoBuilder of(String info){
+        return new MetaInfoBuilder(null).setInfo(info);
+    }
+
+    public static MetaInfoBuilder of(){
+        return new MetaInfoBuilder(null);
+    }
+
+    public MetaInfoBuilder withName(String name){
+        Objects.requireNonNull(name);
+        map.put(NAME, name);
+        return this;
+    }
+
+    public MetaInfoBuilder setName(String name){
+        Objects.requireNonNull(name);
+        map.put(NAME, name);
+        return this;
+    }
+
+    public MetaInfoBuilder setType(String type){
+        Objects.requireNonNull(type);
+        map.put(TYPE, type);
+        return this;
+    }
+
+    public MetaInfoBuilder setInfo(String info){
+        Objects.requireNonNull(info);
+        map.put(INFO, info);
+        return this;
+    }
+
+    public MetaInfoBuilder setSources(String... sources){
+        Objects.requireNonNull(sources);
+        map.put(SOURCE, Arrays.toString(sources));
+        return this;
+    }
+
+    public MetaInfoBuilder setMetaInfo(String key, String metaInfo){
+        Objects.requireNonNull(metaInfo);
+        Objects.requireNonNull(key);
+        map.put(key + '.' + METAINFO, metaInfo);
+        return this;
+    }
+
+    public MetaInfoBuilder setMetaInfo(String metaInfo){
+        if(metaInfo!=null){
+            Objects.requireNonNull(metaInfo);
+            map.put(METAINFO, metaInfo);
+        }
+        return this;
+    }
+
+    public MetaInfoBuilder setMetaInfo(MetaInfo metaInfo){
+        if(metaInfo!=null){
+            Objects.requireNonNull(metaInfo);
+            map.putAll(metaInfo.toMap());
+        }
+        return this;
+    }
+
+    public MetaInfoBuilder setSourceExpressions(String... sourceExpressions){
+        Objects.requireNonNull(sourceExpressions);
+        map.put(SOURCE_EXPRESSION, Arrays.toString(sourceExpressions));
+        return this;
+    }
+
+    public MetaInfoBuilder setTimestamp(long timestamp){
+        map.put(TIMESTAMP, String.valueOf(timestamp));
+        return this;
+    }
+
+    public MetaInfoBuilder setContext(String context){
+        Objects.requireNonNull(context);
+        map.put(CONTEXT, context);
+        return this;
+    }
+
+    public MetaInfoBuilder setEnvironment(Environment configurationContext){
+        Objects.requireNonNull(configurationContext);
+        map.put(ENVIRONMENT, configurationContext.toString());
+        return this;
+    }
+
+    public MetaInfoBuilder set(String key, String value){
+        Objects.requireNonNull(key);
+        Objects.requireNonNull(value);
+        map.put(key, value);
+        return this;
+    }
+
+    public MetaInfo build(){
+        return new MetaInfo(this);
+    }
+
+    @Override
+    public String toString(){
+        StringBuilder b = new StringBuilder("MetaInfoBuilder[");
+        for(Map.Entry<String,String> en:map.entrySet()){
+            b.append(MetaInfo.escape(en.getKey())).append('=').append(MetaInfo.escape(en.getValue())).append(", ");
+        }
+        if(!map.isEmpty()){
+            b.setLength(b.length()-2);
+        }
+        b.append(']');
+        return b.toString();
+    }
+
+
+}

http://git-wip-us.apache.org/repos/asf/incubator-tamaya/blob/cf59ebbd/api/src/main/java/org/apache/tamaya/PropertyAdapter.java
----------------------------------------------------------------------
diff --git a/api/src/main/java/org/apache/tamaya/PropertyAdapter.java b/api/src/main/java/org/apache/tamaya/PropertyAdapter.java
new file mode 100644
index 0000000..6666907
--- /dev/null
+++ b/api/src/main/java/org/apache/tamaya/PropertyAdapter.java
@@ -0,0 +1,34 @@
+/*
+ * 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;
+
+
+/**
+ * Interface for an adapter that converts a configured String into something else.
+ */
+public interface PropertyAdapter<T>{
+
+    /**
+     * Adapt the given configuration value to the required target type.
+     * @param value
+     * @return
+     */
+    T adapt(String value);
+
+}

http://git-wip-us.apache.org/repos/asf/incubator-tamaya/blob/cf59ebbd/api/src/main/java/org/apache/tamaya/PropertyAdapters.java
----------------------------------------------------------------------
diff --git a/api/src/main/java/org/apache/tamaya/PropertyAdapters.java b/api/src/main/java/org/apache/tamaya/PropertyAdapters.java
new file mode 100644
index 0000000..2103f60
--- /dev/null
+++ b/api/src/main/java/org/apache/tamaya/PropertyAdapters.java
@@ -0,0 +1,93 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.tamaya;
+
+import org.apache.tamaya.annot.WithPropertyAdapter;
+import org.apache.tamaya.spi.Bootstrap;
+import org.apache.tamaya.spi.PropertyAdaptersSingletonSpi;
+import java.util.Optional;
+
+/**
+ * Singleton accessor that provides {@link PropertyAdapter} instance, usable for converting String
+ * based configuration entries into any other target types.
+ */
+public final class PropertyAdapters{
+    /** The SPI finally registered backing this singleton. */
+    private static final PropertyAdaptersSingletonSpi propertyAdaptersSingletonSpi = loadConfigAdapterProviderSpi();
+
+    /**
+     * Method that loads the singleton backing bean from the {@link org.apache.tamaya.spi.Bootstrap} component.
+     * @return the PropertyAdaptersSingletonSpi, never null.
+     */
+    private static PropertyAdaptersSingletonSpi loadConfigAdapterProviderSpi(){
+        return Bootstrap.getService(PropertyAdaptersSingletonSpi.class);
+    }
+
+    /**
+     * Orivate singleton constructor.
+     */
+    private PropertyAdapters(){}
+
+    /**
+     * Registers a new PropertyAdapter for the given target type, hereby replacing any existing adapter for
+     * this type.
+     * @param targetType The target class, not null.
+     * @param adapter The adapter, not null.
+     * @param <T> The target type
+     * @return any adapter replaced with the new adapter, or null.
+     */
+    public static <T> PropertyAdapter<T> register(Class<T> targetType, PropertyAdapter<T> adapter){
+        return Optional.of(propertyAdaptersSingletonSpi).get().register(targetType, adapter);
+    }
+
+    /**
+     * Get an adapter converting to the given target type.
+     * @param targetType the target type class
+     * @return true, if the given target type is supported.
+     */
+    public static boolean isTargetTypeSupported(Class<?> targetType){
+        return Optional.of(propertyAdaptersSingletonSpi).get().isTargetTypeSupported(targetType);
+    }
+
+    /**
+     * Get an adapter converting to the given target type.
+     * @param targetType the target type class
+     * @param <T> the target type
+     * @return the corresponding adapter, never null.
+     * @throws ConfigException if the target type is not supported.
+     */
+    public static  <T> PropertyAdapter<T> getAdapter(Class<T> targetType){
+        return getAdapter(targetType, null);
+    }
+
+    /**
+     * Get an adapter converting to the given target type.
+     * @param targetType the target type class
+     * @param annotation the {@link org.apache.tamaya.annot.WithPropertyAdapter} annotation, or null. If the annotation is not null and
+     *                   defines an overriding adapter, this instance is created and returned.
+     * @param <T> the target type
+     * @return the corresponding adapter, never null.
+     * @throws ConfigException if the target type is not supported, or the overriding adapter cannot be
+     * instantiated.
+     */
+    public static  <T> PropertyAdapter<T> getAdapter(Class<T> targetType, WithPropertyAdapter annotation){
+        return Optional.of(propertyAdaptersSingletonSpi).get().getAdapter(targetType, annotation);
+    }
+
+}


Mime
View raw message