Apache Tamaya -- API
====================
:name: Tamaya
:rootpackage: org.apache.tamaya
:title: Apache Tamaya
:revnumber: 0.1-SNAPSHOT
:revremark: Incubator
:revdate: January 2014
:longversion: {revnumber} ({revremark}) {revdate}
:authorinitials: ATR
:author: Anatole Tresch
:email: <anatole@apache.org>
:source-highlighter: coderay
:website: http://tamaya.incubator.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:
[[API]]
== The Tamaya API
=== Overview
Though Tamaya is a very powerful and flexible solution there are basically only a few simple core concepts required
that build the base of all the other mechanisms:

The API provides these artifacts, which are:

* A simple but complete SE *API* for accessing key/value based _Configuration_:
  ** _Configuration_ hereby models configuration and as well provides the static entry point to access configuration.
     _Configuration_ provides
     *** access to literal key/value pairs.
     *** functional extension points (+with,query+) based un +UnaryOperator<Configuration>+ (operator) and +Function<Configuration,T>+ (query).
  ** +ConfigProvider+ provides static access to the current +Configuration+ (default configuration)
  ** +ConfigException+ defines a runtime exception for usage by the configuration system.

* Additionally the *SPI* provides:
  ** _PropertySource:_ is the the SPI for adding configuration data. A +PropertySource+
     hereby
     *** is designed as a minimalistic data interface to be implemented by any kind of data providers (local or remote)
     *** provides data key/value pairs in raw format as String key/values only
     *** can optionally support scanning of its provided values
  ** _PropertySourceProvider:_ allows to add property sources dynamically.
  ** +PropertyConverter+, which defines conversion of String values into any required target types.
  ** +PropertyFilter+, which allows filtering of property values prior getting returned to the caller.
  ** +ConfigurationContext+, which provides the container that contains the property sources and filters that form a
     configuration.
  ** +ServiceContext+, which provides access to the components loaded, depending on the current runtime stack.
  ** +ServiceContextManager+ provides static access to the +ServiceContext+ loaded..

This is also reflected in the main parts of the API, which is quite small:

* +org.apache.tamaya+ contains the main API abstractions used by users.
* +org.apache.tamaya.spi+ contains the SPI interfaces to be implemented by implementations and the +ServiceContext+
  mechanism.

=== Compatibility

The Tamaya API basically is compatible with Java 7 and Java 8. Java 8 additionally introduces additional methods
hereby leveraging the newly added Java 8 +Optional+ features and _default_ methods.

[[APIKeyValues]]
=== Key/Value Pairs

Basically configuration is a very generic concept. Therefore it should be modelled in a generic way. The most simple
and most commonly used approach are simple literal key/value pairs. So the core building block of {name} are key/value pairs.
You can think of a common +.properties+ file, e.g.

[source,properties]
.A simple properties file
--------------------------------------------
a.b.c=cVal
a.b.c.1=cVal1
a.b.c.2=cVal2
a=aVal
a.b=abVal
a.b2=abVal
--------------------------------------------

Now you can use +java.util.Properties+ to read this file and access the corresponding properties, e.g.

[source,properties]
--------------------------------------------
Properties props = new Properties();
props.readProperties(...);
String val = props.getProperty("a.b.c");
val = props.getProperty("a.b.c.1");
...
--------------------------------------------

==== Why Using Strings Only

There are good reason to keep of non String-values as core storage representation of configuration. Mostly
there are several huge advantages:

* Strings are simple to understand
* Strings are human readable and therefore easy to prove for correctness
* Strings can easily be used within different language, different VMs, files or network communications.
* Strings can easily be compared and manipulated
* Strings can easily be searched, indexed and cached
* It is very easy to provide Strings as configuration, which gives much flexibility for providing configuration in
  production as well in testing.
* and more...

On the other side there are also disadvantages:

* Strings are inherently not type safe, they do not provide validation out of the box for special types, such as
numbers, dates etc.
* In many cases you want to access configuration in a typesafe way avoiding conversion to the target types explicitly
  throughout your code.
* Strings are neither hierarchical nor multi-valued, so mapping hierarchical and collection structures requires some
  extra efforts.

Nevertheless most of these advantages can be mitigated easily, hereby still keeping all the benefits from above:

* Adding type safe adapters on top of String allow to add any type easily, that can be directly mapped out of Strings.
  This includes all common base types such as numbers, dates, time, but also timezones, formatting patterns and more.
* Also multi-valued, complex and collection types can be defined as a corresponding +PropertyAdapter+ knows how to
  parse and create the target instance required.
* String s also can be used as references pointing to other locations and formats, where configuration is
  accessible.

[[API Configuration]]
=== Configuration

+Configuration+ is the main API provided by Tamaya. It allows reading of single property values or the whole
property map, but also supports type safe access.

==== Configuration (Java 7)

The minimal API defined for Java version earlier than Java 8 looks as follows:

[source,java]
.Interface Configuration in Java 7
--------------------------------------------
public interface Configuration{
    String get(String key);
    <T> T get(String key, Class<T> type);
    Map<String,String> getProperties();

    // extension points
    default Configuration with(ConfigOperator operator);
    default <T> T query(ConfigQuery<T> query);
}
--------------------------------------------

Hereby

* +<T> T get(String, Class<T>)+ provides type safe accessors for all basic wrapper types of the JDK. Basically all this
  methods delegate to the +get(String, PropertyConverter)+ method, additionally passing the required +PropertyConverter+.
* +get(String, PropertyConverter)+ allow accessing any type, hereby also passing a +PropertyConverter+ explicitly
  that converts  the configured literal value to the type required.
* +with, query+ provide the extension points for adding additional functionality.
* +getProperties()+ provides access to all key/values, whereas entries from non scannable property sources may not
  be included.

==== Configuration (Java 8)

The API for Java 8 adds additional support for optionals and a static accessor +current()+, which replaces the
+ConfigurationProvider+ accessor singleton from Java 7.

[source,java]
.Interface Configuration in Java 8
--------------------------------------------
public interface Configuration extends PropertySource{
    // java 7 inherited methods
    String get(String key);
    <T> T get(String key, Class<T> type);
    Map<String,String> getProperties();

    // extension points
    default Configuration with(ConfigOperator operator);
    default <T> T query(ConfigQuery<T> query);

    // new java 8 optional support
    default Optional<Boolean> getBoolean(String key);
    default OptionalInt getInteger(String key);
    default OptionalLong getLong(String key);
    default OptionalDouble getDouble(String key);
    default <T> Optional<T> getOptional(String key, PropertyConverter<T> adapter);
    <T> Optional<T> getOptional(String key, Class<T> type);

    static Configuration current();
}
--------------------------------------------

Hereby

* +get(String)+ and +getOptional(String)+ provide easy access to any kind of configuration properties in their
  String format.
* +get(String, Class), getOptional(String, Class)+ and +getOptional(String, PropertyConverter)+ provide type safe
  access to configuration properties. If a +PropertyConverter+ is passed, it will replace any predefined standard
  converters defined for the type. By default several +PropertyConverter+ instances can be registered for a given
  target type. The are managed in an ordered list, whereas the ordering is defined by +@Priority+ annotations
  on the converters.
* +getProperties()+ gives access to all known (=scannable) properties.
* +with, query+ provide the extension points for adding additional functionality modelled by +ConfigOperator,
  ConfigQuery+.
* +current()+ returns the _current_ +Configuration+


[[PropertyConverter]]
==== Property Converters

As illustrated in the previous section, +Configuration+ also to access non String types. Nevertheless internally
all properties are strictly is modelled as pure Strings only, so non String types must be derived by converting the
configured String values into the required target type. This is achieved with the help of +PropertyConverters+:

[source,java]
--------------------------------------------
public interface PropertyConverter<T>{
    Class<T> getTargetType();
    T convert(String value);
    //X TODO Collection<String> getSupportedFormats();
}
--------------------------------------------

+PropertyConverter+ instances can be implemented and registered by default using the +ServiceLoader+. Hereby
a configuration values is passed to all registered converters for a type in order or their annotated +@Priority+
value. The first non-null result of a converter is then returned as the current configuration value.

Also worth mentioning is the fact, that the +PropertyConverter+ to be used can also be explicitly defined, when
a configuration value is accessed, by using the method
+<T> T Configuration#getOptional(String, PropertyConverter<T> converter)+.

Access to converters is given by the +ConfigurationContext+ (see <<SPI>>).

[[ExtensionPoints]]
=== Extension Points

We are well aware of the fact that this library will not be able to cover all kinds of use cases. Therefore
we have added functional extension mechanisms to +Configuration+ that were used in other areas of the Java eco-system
as well:

* +with(ConfigOperator operator)+ allows to pass arbitrary unary functions that take and return instances of
  +Configuration+. Operators can be used to cover use cases such as filtering, configuration views, security
  interception and more.
* +query(ConfigQuery query)+ allows to apply a function returning any kind of result based on a
  +Configuration+ instance. Queries are used for accessing/deriving any kind of data based on of a +Configuration+
  instance, e.g. accessing a +Set<String>+ of root keys present.

Both interfaces hereby are functional interfaces. Because of backward compatibility with Java 7 we did not use
+UnaryOperator, Function+ from the +java.util.function+ package. Nevertheless usage is similar, so you can
use Lambdas and method references in Java 8:

[source,java]
.Applying a +ConfigurationQuery+ using a method reference
--------------------------------------------
ConfigSecurity securityContext = Configuration.current().query(ConfigSecurity::targetSecurityContext);
--------------------------------------------

NOTE: +ConfigSecurity+ is an arbitrary class only for demonstration purposes.

Or an operator calls basically looks quite similar:

[source,java]
.Applying a +ConfigurationOperator+ using a lambda expression:
--------------------------------------------
Configuration secured = Configuration.current()
                           .with((config) ->
                                 config.getOptional("foo").isPresent()?;
                                 FooFilter.apply(config):
                                 config);
--------------------------------------------

[[Mutability]]
==== Mutability

tbd


[[ConfigException]]
=== ConfigException

The class +ConfigException+ models the base *runtime* exception used by the configuration system.

[[SPI]]
== SPI

[[PropertySource]]
=== Interface PropertySource

We have seen that constraining configuration aspects to simple literal key/value pairs provides us with an easy to
understand, generic, flexible, yet expendable mechanism. Looking at the Java language features a +java.util.Map<String,
String>+ and +java.util.Properties+ basically model these aspects out of the box.

Though there are advantages in using these types as a model, there are some severe drawbacks, notably implementation
of these types is far not trivial and the collection API offers additional functionality not useful when aiming
for modelling simple property sources.

To render an implementation of a custom +PropertySource+ as convenient as possible only the following methods were
identified to be necessary:

[source,java]
--------------------------------------------
public interface PropertySource{
      int getOrdinal();
      String getName();
      String get(String key);
      boolean isScannable();
      Map<String, String> getProperties();
}
--------------------------------------------

Hereby

* +get+ looks similar to the methods on +Map+. It may return +null+ in case no such entry is available.
* +getProperties+ allows to extract all property data to a +Map<String,String>+. Other methods like +containsKey,
  keySet+ as well as streaming operations then can be applied on the returned +Map+ instance.
* But not in all scenarios a property source may be scannable, e.g. when looking up keys is very inefficient, it
  may not make sense to iterator over all keys to collect the corresponding properties.
  This can be evaluated by calling +isScannable()+. If a +PropertySource+ is defined as non scannable accesses to
  +getProperties()+ may not return all key/value pairs that would be available when accessed directly using the
  +String get(String)+ method.
* +getOrdinal()+ defines the ordinal of the +PropertySource+. Property sources are managed in an ordered chain, where
  property sources with higher ordinals override the ones with lower ordinals. If ordinal are the same, the natural
  ordering of the fulloy qualified class names of the property source implementations are used. The reason for
  not using +@Priority+ annotations is that property sources can define dynamically their ordinals, e.g. based on
  a property contained with the configuration itself.
* Finally +getName()+ returns a (unique) name that identifies the +PropertySource+ within the current
  +ConfigurationContext+.

This interface can be implemented by any kind of logic. It could be a simple in memory map, a distributed configuration
provided by a data grid, a database, the JNDI tree or other resources. Or it can be a combination of multiple
property sources with additional combination/aggregation rules in place.

+PropertySources+ are by default registered using the Java +ServiceLoader+ or the mechanism provided by the current
 active +ServiceContext+.


[[PropertySourceProvider]]
==== Interface PropertySourceProvider

Instances of this type can be used to register multiple instances of +PropertySource+.

[source,java]
--------------------------------------------
// @FunctionalInterface in Java 8
public interface PropertySourceProvider{
    Collection<PropertySource> getPropertySources();
}
--------------------------------------------

This allows to evaluate the property sources to be read/that are available dynamically. All property sources
are read out and added to the current chain of +PropertySource+ instances within the current +ConfigurationContext+,
refer also to [[ConfigurationContext]].

+PropertySourceProviders+ are by default registered using the Java +ServiceLoader+ or the mechanism provided by the current
 active +ServiceContext+.

[[PropertyFilter]]
==== Interface PropertyFilter

Also +PropertyFilters+ can be added to a +Configuration+. They are evaluated before a +Configuration+ instance is
passed to the user. Filters can hereby used for multiple purposes, such as

* resolving placeholders
* masking sensitive entries, such as passwords
* constraining visibility based on the current active user
* ...

+PropertyFilters+ are by default registered using the Java +ServiceLoader+ or the mechanism provided by the current
active +ServiceContext+. Similar to property sources they are managed in an ordered filter chain, based on the
applied +@Priority+ annotations.

A +PropertyFilter+ is defined as follows:

[source,java]
--------------------------------------------
// @FunctionalInterface in Java 8
public interface PropertyConverter{
    String filterProperty(String key, String valueToBeFiltered);
}
--------------------------------------------

Hereby:

* returning +null+ will remove the key from the final result
* non null values are used as the current value of the key. Nevertheless for resolving multi-step dependencies
  filter evaluation has to be continued as long as filters are still changing some of the values to be returned.
  To prevent possible endless loops after a defined number of loops evaluation is stopped.

This method is called each time a single entry is accessed, and for each property in a full properties result.
