http://git-wip-us.apache.org/repos/asf/incubator-tamaya-site/blob/ede865e4/content/documentation/api.adoc ---------------------------------------------------------------------- diff --git a/content/documentation/api.adoc b/content/documentation/api.adoc new file mode 100644 index 0000000..1dd1d41 --- /dev/null +++ b/content/documentation/api.adoc @@ -0,0 +1,687 @@ +:jbake-type: page +:jbake-status: published + +[[CoreDesign]] +== Apache Tamaya: API + +Though Tamaya is a very powerful and flexible solution there are basically only a few simple core concepts required +that are the base of all the other mechanisms. As a starting point we recommend you read the corresponding +llink:HighLevelDesign.html[High Level Design Documentation] + +[[API]] +== The Tamaya API +The API provides the artifacts as described in the link:HighLevelDesign.html[High Level Design Documentation], which are: + +* A simple but complete SE *API* for accessing key/value based _Configuration_: + ** +Configuration+ hereby models configuration, the main interface of Tamaya. +Configuration+ provides + *** access to literal key/value pairs. + *** functional extension points (+with, query+) using a unary +ConfigOperator+ or + a function +ConfigurationQuery<T>+. + ** +ConfigurationProvider+ provides with +getConfiguration()+ the static entry point for accessing configuration. + ** +ConfigException+ defines a runtime exception for usage by the configuration system. + ** +TypeLiteral+ provides a possibility to type safely define the target type to be returned by a registered + +PropertyProvider+. + ** +PropertyConverter+, which defines conversion of configuration values (String) into any required target type. + +* Additionally the *SPI* provides: + ** _PropertySource:_ is the the SPI for adding configuration data. A +PropertySource+ hereby + *** is designed as a minimalistic interface that be implemented by any kind of data provider (local or remote) + *** provides single access for key/value pairs in raw format as String key/values only (+getPropertyValue+). + *** can optionally support scanning of its provided values, implementing +getProperties()+. + ** _PropertySourceProvider:_ allows to register multiple property sources dynamically, e.g. all config files found in + file system folder.. + ** +ConfigurationProviderSpi+ defines the SPI that is used as a backing bean for the +ConfigurationProvider+ + singleton. + ** +PropertyFilter+, which allows filtering of property values prior getting returned to the caller. + ** +PropertyValueCombinationPolicy+ optionally can be registered to change the way how different key/value + pairs are combined to build up the final +Configuration+ passed over to the filters registered. + ** +ConfigurationContext+, which provides a container for all the artifacts needed to build up a +Configuration+. + For example a context contains the property sources, property filters, converters and combination policy used. + Also the ordering of the property sources is defined by the context. A context instance given a + +Configuration+ can be created by calling +ConfigurationProvider.createConfiguration(context);+. + ** Similarly a +ConfigurationContext+ can be created using a +ConfigurationContextBuilder+. This builder can be + obtained calling +ConfigurationProvider.getConfigurationContextBuilder();+. + ** +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 packages of the API: + +* +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. + + + +[[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: + +[source,java] +.Interface Configuration +-------------------------------------------- +public interface Configuration{ + String get(String key); + String getOrDefault(String key, String value); + <T> T get(String key, Class<T> type); + <T> T getOrDefault(String key, Class<T> type, T defaultValue); + <T> T get(String key, TypeLiteral<T> type); + <T> T getOrDefault(String key, TypeLiteral<T> type, T defaultValue); + Map<String,String> getProperties(); + + // extension points + Configuration with(ConfigOperator operator); + <T> T query(ConfigQuery<T> query); + + ConfigurationContext getContext(); +} +-------------------------------------------- + +Hereby + +* +<T> T get(String, Class<T>)+ provides type safe accessors for all basic wrapper types of the JDK. +* +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. +* +getOrDefault+ allows to pass default values as needed, returned if the requested value evaluated to +null+. + +The class +TypeLiteral+ is basically similar to the same class provided with CDI: + +[source,java] +-------------------------------------------- +public class TypeLiteral<T> implements Serializable { + + [...] + + protected TypeLiteral(Type type) { + this.type = type; + } + + protected TypeLiteral() { } + + public static <L> TypeLiteral<L> of(Type type){...} + public static <L> TypeLiteral<L> of(Class<L> type){...} + + public final Type getType() {...} + public final Class<T> getRawType() {...} + + public static Type getGenericInterfaceTypeParameter(Class<?> clazz, Class<?> interfaceType){...} + public static Type getTypeParameter(Class<?> clazz, Class<?> interfaceType){...} + + [...] +} +-------------------------------------------- + +Instances of +Configuration+ can be accessed from the +ConfigurationProvider+ singleton: + +[source,java] +.Accessing Configuration +-------------------------------------------- +Configuration config = ConfigurationProvider.getConfiguration(); +-------------------------------------------- + +Hereby the singleton is backed up by an instance of +ConfigurationProviderSpi+. + + +[[PropertyConverter]] +==== Property Type Conversion + +As illustrated in the previous section, +Configuration+ also to access non String types. Nevertheless internally +all properties are strictly 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>{ + T convert(String value, ConversionContext context); + //X TODO Collection<String> getSupportedFormats(); +} +-------------------------------------------- + +The +ConversionContext+ contains additional meta-information for the accessed key, inclusing the key'a name and +additional metadata. + ++PropertyConverter+ instances can be implemented and registered by default using the +ServiceLoader+. Hereby +a configuration String value is passed to all registered converters for a type in order of their annotated +@Priority+ +value. The first non-null result of a converter is then returned as the current configuration value. + +Access to converters is provided by the current +ConfigurationContext+, which is accessible from +the +ConfigurationProvider+ singleton. + + +[[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+ and +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 = ConfigurationProvider.getConfiguration().query(ConfigSecurity::targetSecurityContext); +-------------------------------------------- + +NOTE: +ConfigSecurity+ is an arbitrary class only for demonstration purposes. + + +Operator calls basically look similar: + +[source,java] +.Applying a +ConfigurationOperator+ using a lambda expression: +-------------------------------------------- +Configuration secured = ConfigurationProvider.getConfiguration() + .with((config) -> + config.get("foo")!=null?; + FooFilter.apply(config): + config); +-------------------------------------------- + + +[[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] +-------------------------------------------- +// Functional Interface +public interface PropertyFilter{ + String filterProperty(String value, FilterContext context); +} +-------------------------------------------- + +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. +* +FilterContext+ provides additional metdata, inclusing the key accessed, which is useful in many use cases. + +This method is called each time a single entry is accessed, and for each property in a full properties result. + + +[[PropertyValueCombinationPolicy]] +==== Interface PropertyValueCombinationPolicy + +This interface can be implemented optional. It can be used to adapt the way how property key/value pairs are combined to +build up the final Configuration to be passed over to the +PropertyFilters+. The default implementation is just +overriding all values read before with the new value read. Nevertheless for collections and other use cases it is +often useful to have alternate combination policies in place, e.g. for combining values from previous sources with the +new value. Finally looking at the method's signature it may be surprising to find a +Map+ for the value. The basic +value hereby is defined by +currentValue.get(key)+. Nevertheless the +Map+ may also contain additional meta entries, +which may be considered by the policy implementation. + +[source,java] +-------------------------------------------- +// FunctionalInterface +public interface PropertyValueCombinationPolicy{ + + PropertyValueCombinationPolicy DEFAULT_OVERRIDING_COLLECTOR = + new PropertyValueCombinationPolicy(){ + @Override + public Map<String,String> collect(Map<String,String> currentValue, String key, + PropertySource propertySource) { + PropertyValue value = propertySource.get(key); + return value!=null?value.getConfigEntries():currentValue; + } + }; + + String collect(Map<String,String> currentValue currentValue, String key, + PropertySource propertySource); + +} +-------------------------------------------- + + +[[ConfigurationContext]] +==== The Configuration Context + +A +Configuration+ is created from a +ConfigurationContext+, which is +accessible from +Configuration.getContext()+: + +[source,java] +.Accessing the current +ConfigurationContext+ +-------------------------------------------- +ConfigurationContext context = ConfigurationProvider.getConfiguration().getContext(); +-------------------------------------------- + +The +ConfigurationContext+ provides access to the internal artifacts that determine the final +Configuration+ and +also defines the ordering of the property sources, filters and converters contained: + +* +PropertySources+ registered (including the PropertySources provided from +PropertySourceProvider+ instances). +* +PropertyFilters+ registered, which filter values before they are returned to the client +* +PropertyConverter+ instances that provide conversion functionality for converting String values to any other types. +* the current +PropertyValueCombinationPolicy+ that determines how property values from different PropertySources are + combined to the final property value returned to the client. + + +[[Mutability]] +==== Changing the current Configuration Context + +A +ConfigurationContext+ is not mutable once it is created. In many cases mutability is also not needed. Nevertheless +there are use cases where the current +ConfigurationContext+ (and +consequently +Configuration+) must be adapted: + +* New configuration files where detected in a folder observed by Tamaya. +* Remote configuration, e.g. stored in a database or alternate ways has been updated and the current system must + be adapted to these changes. +* The overall configuration context is manually setup by the application logic. +* Within unit testing alternate configuration setup should be setup to meet the configuration requirements of the + tests executed. + +In such cases the +ConfigurationContext+ must be changed, meaning it must be possible: + +* to add or remove +PropertySource+ instances +* to add or remove +PropertyFilter+ instances +* to add or remove +PropertyConverter+ instances +* to redefine the current +PropertyValueCombinationPolicy+ instances. + +This can be achieved by obtaining an instance of +ConfigurationContextBuilder+. Instances of this builder can be +accessed either + +* calling +ConfigurationContext.toBuilder()+, hereby returning a builder instance preinitialized with the values from the + current +ConfigurationContext+. +* calling +ConfigurationProvider.getConfigurationContextBuilder()+. + +[source,java] +.Accessing a +ConfigurationContextBuilder+ +-------------------------------------------- +ConfigurationContextBuilder preinitializedContextBuilder = ConfigurationProvider.getConfiguration().getContext().toBuilder(); +ConfigurationContextBuilder emptyContextBuilder = ConfigurationProvider.getConfigurationContextBuilder(); +-------------------------------------------- + +With such a builder a new +ConfigurationContext+ can be created and then applied: + +[source,java] +.Creating and applying a new +ConfigurationContext+ +-------------------------------------------- +ConfigurationContext context = ConfigurationProvider.getConfiguration().getContext() + .toBuilder(); + .addPropertySources(new MyPropertySource()) + .addPropertyFilter(new MyFilter()) + .build(); +-------------------------------------------- + +Hereby the builder provides several methods for adding, removing of property sources and also operations +for programmatically change the property sourcepriorities, e.g. + +[source,java] +.Chain manipulation using +ConfigurationContextBuilder+ +-------------------------------------------- +PropertySource propertySource = builder.getPropertySource("sourceId"); + +// changing the priority of a property source. The ordinal value hereby is not considered. +// Instead the position of the property source within the chain is changed. +builder.decreasePriority(propertySource); + +// Alternately a comparator expression can be passed to establish the defined ordering... +builder.sortPropertyFilters(MyFilterComparator::compare); +-------------------------------------------- + +Finally if the new context is ready a new configuration can be created, or the context is applied to the +current configuration. + +[source,java] +.Creating and applying a new +ConfigurationContext+ +-------------------------------------------- +ConfigurationContext context = builder.build(); + +// Creates a new matching Configuration instance +Configuration newConfig = ConfigurationProvider.createConfiguration(context); + +// Apply the new context to replace the current configuration: +ConfigurationProvider.setConfigurationContext(context); +-------------------------------------------- + +Hereby +ConfigurationProvider.setConfigurationContext(context)+ can throw an +UnsupportedOperationException+. +This can be checked by calling the method +boolean ConfigurationProvider.isConfigurationContextSettable()+. + + +[[ConfigurationProviderSpi]] +==== Implementing and Managing Configuration + +One of the most important SPI in Tamaya if the +ConfigurationProviderSpi+ interface, which is backing up the ++ConfigurationProvider+ singleton. Implementing this class allows + +* to fully determine the implementation class for +Configuration+ +* to manage the current +ConfigurationContext+ in the scope and granularity required. +* to provide access to the right +Configuration/ConfigurationContext+ based on the current runtime context. +* Performing changes as set with the current +ConfigurationContextBuilder+. + += Interface ConfigurationContextBuilder + +include::temp-properties-files-for-site/attributes.adoc[] + +[[BuilderCore]] +== Interface ConfigurationContextBuilder +=== Overview + +The Tamaya builder module provides a generic (one time) builder for creating +Configuration+ instances, +e.g. as follows: + +[source,java] +--------------------------------------------------------------- +ConfigurationBuilder builder = new ConfigurationBuilder(); +// do something +Configuration config = builder.build(); +--------------------------------------------------------------- + +Basically the builder allows to create configuration instances completely independent of the current configuration +setup. This gives you full control on the +Configuration+ setup. + + +=== Supported Functionality + +The builder allows you to add +PropertySource+ instances: + +[source,java] +---------------------------------------------------------------- +ConfigurationContextBuilder builder = ConfigurationProvider.getConfigurationContextBuilder(); +builder.addPropertySources(sourceOne, sourceTwo, sourceThree +Configuration config = ConfigurationProvider.createConfiguration(builder.build()); +---------------------------------------------------------------- + +Hereby the ordering of the propertysources is not changed, regardless of the ordinals provided +by the property sources. This allows alternate ordering policies easily being implemented because +creating a configuration based on a configuration context is already implemented and provided by the core +API. + +Similarly you can add filters: + +[source,java] +---------------------------------------------------------------- +builder.addPropertyFilters(new MyConfigFilter()); +---------------------------------------------------------------- + +...or +PropertySourceProvider+ instances: + +[source,java] +---------------------------------------------------------------- +builder.addPropertySourceProvider(new MyPropertySourceProvider()); +---------------------------------------------------------------- + + + +[[ServiceContext]] +==== The ServiceContext + +The +ServiceContext+ is also a very important SPI, which allows to define how components are loaded in Tamaya. +The +ServiceContext+ hereby defines access methods to obtain components, whereas itself it is available from the ++ServiceContextManager+ singleton: + +[source,java] +.Accessing the +ServiceContext+ +-------------------------------------------- +ServiceContext serviceContext = ServiceContextManager.getServiceContext(); + +public interface ServiceContext{ + int ordinal(); + <T> T getService(Class<T> serviceType); + <T> List<T> getServices(Class<T> serviceType); +} +-------------------------------------------- + +With the +ServiceContext+ a component can be accessed in two different ways: + +. access as as a single property. Hereby the registered instances (if multiple) are sorted by priority and then finally + the most significant instance is returned only. +. access all items given its type. This will return (by default) all instances loadedable from the current + runtime context, ordered by priority, hereby the most significant components added first. + + +## Examples +### Accessing Configuration + +_Configuration_ is obtained from the ConfigurationProvider singleton: + +[source,java] +.Accessing +Configuration+ +-------------------------------------------- +Configuration config = ConfigurationProvider.getConfiguration(); +-------------------------------------------- + +Many users in a SE context will probably only work with _Configuration_, since it offers all functionality +needed for basic configuration with a very lean memory and runtime footprint. In Java 7 access to the keys is +very similar to *Map<String,String>*, whereas in Java 8 additionally usage of _Optional_ is supported: + +[source,java] +-------------------------------------------- +Configuration config = ConfigurationProvider.getConfiguration(); +String myKey = config.get("myKey"); // may return null +int myLimit = config.get("all.size.limit", int.class); +-------------------------------------------- + + +### Environment and System Properties + +By default environment and system properties are included into the _Configuration_. So we can access the current +_PROMPT_ environment variable as follows: + +[source,java] +-------------------------------------------- +String prompt = ConfigurationProvider.getConfiguration().get("PROMPT"); +-------------------------------------------- + +Similary the system properties are directly applied to the _Configuration_. So if we pass the following system +property to our JVM: + +[source,java] +-------------------------------------------- +java ... -Duse.my.system.answer=yes +-------------------------------------------- + +we can access it as follows: + +[source,java] +-------------------------------------------- +boolean useMySystem = ConfigurationProvider.getConfiguration().get("use.my.system.answer", boolean.class); +-------------------------------------------- + + +### Adding a Custom Configuration + +Adding a classpath based configuration is simply as well: just implement an according _PropertySource_. With the +_tamaya-spi-support_ module you just have to perform a few steps: + +. Define a PropertySource as follows: + +[source,java] +-------------------------------------------- + public class MyPropertySource extends PropertiesResourcePropertySource{ + + public MyPropertySource(){ + super(ClassLoader.getSystemClassLoader().getResource("META-INF/cfg/myconfig.properties"), DEFAULT_ORDINAL); + } + } +-------------------------------------------- + +Then register +MyPropertySource+ using the +ServiceLoader+ by adding the following file: + +[source,listing] +-------------------------------------------- +META-INF/services/org.apache.tamaya.spi.PropertySource +-------------------------------------------- + +...containing the following line: + +[source,listing] +-------------------------------------------- +com.mypackage.MyPropertySource +-------------------------------------------- + + +[[APIImpl]] +== API Implementation + +The API is implemented by the Tamaya _Core_module. Refer to the link:Core.html[Core documentation] for +further details.
http://git-wip-us.apache.org/repos/asf/incubator-tamaya-site/blob/ede865e4/content/documentation/core.adoc ---------------------------------------------------------------------- diff --git a/content/documentation/core.adoc b/content/documentation/core.adoc new file mode 100644 index 0000000..139eade --- /dev/null +++ b/content/documentation/core.adoc @@ -0,0 +1,214 @@ +:jbake-type: page +:jbake-status: published + +[[Core]] +== Tamaya Core Implementation +=== Overview + +Tamaya Core provides an implementation of the link:API.html[Tamaya Configuration API] and adds additional functionality +and building blocks for supporting SPI implementations. + +Tamaya Core contains the following artifacts: + +* Implementations of +Configuration, ConfigurationContext, ConfigurationContextBuilder+ ConfigurationProviderSpi+ +* A +java.util.ServiceLoader+ based +ServiceContext+ implementation. Hereby it implements component priorization based + on the +@Priority+ annotations. +* A PropertyConverterManager+ that loads and stores references to all the preconfigured +PropertyConverter+ instances +hereby providing type conversion for all important types. +* A simple default configuration setup using the current classpath and an optional staging variable. +* It collects all +PropertySource+ and +PropertySourceProvider+ instances registered with the +ServiceLoader+ and + registers them in the global +ConfigurationContext+ +* It provides a +ConfigurationContextBuilder+ implementation (class +DefaultConfigurationContextBuilder+) and allows + changing the current +ConfigurationContext+. + +The overall size of the library is very small. All required components are implemented and registered, so basically the +Core module is a complete configuration solution. Nevertheless it is also very minimalistic, but fortunately is flexible +enough to be extended/accommodated with additional features as needed, such as + +* placeholder and resolution mechanisms +* dynamic resource path lookup, e.g. with ant styled patterns +* configuration injection and configuration templates +* abstraction for reusable formats +* integration with other existing solutions +* configuration and configuration isolation targeting Java EE +* dynamic configuration and configuration updates +* Configuration management extensions +* remote configuration +* and more + +For details about the extension modules available and their functionality refer to the link:modules.html[extension user guide]. + + +[[CorePropertyConverters]] +=== Default PropertyConverters in Core + +As mentioned the Core module delivers several default +PropertyConverter+ instances out of the box. Find below the +listing of converters automatically registered with the Core module: + +[width="100%",frame="1",options="header",grid="all"] +|======= +|_Target Type_ |_Class Name_ |_Supported Formats_ +|java.math.BigDecimal |BigDecimalConverter |1.2345, 0xFF +|java.math.BigInteger |BigIntegerConverter |0xFF, 1234 +|java.ui.lang.Boolean |BooleanConverter |true, false, T, F, 1 ,0 +|java.ui.lang.Byte |ByteConverter |0xFF, MIN_VALUE, MAX_VALUE, 123 +|java.ui.lang.Character |CharConverter |0xFF, 'a', 'H', 123 +|java.ui.lang.Class |ClassConverter |<fully qualified class name> +|java.util.Currency |CurrencyConverter |CHF, 123 +|java.ui.lang.Double |DoubleConverter |1, 0xFF, 1.2334, NaN, NEGATIVE_INFITIY, POSITIVE_INFINITY, MIN_VALUE, MAX_VALUE +|_Enums_ |EnumConverter |<Enum item name> +|java.ui.lang.Float |FloatConverter |1, 0xFF, 1.2334, NaN, NEGATIVE_INFITIY, POSITIVE_INFINITY, MIN_VALUE, MAX_VALUE +|java.ui.lang.Integer |IntegerConverter |1, 0xD3, MIN_VALUE, MAX_VALUE +|LocalDate |LocalDateConverter |<Date as defined by LocalDate.parse(String) +|LocalTime |LocalTimeConverter |<Time as defined by LocalTime.parse(String) +|LocalDateTime |LocalDateTimeConverter |<LocalDateTime as defined by LocalDateTime.parse(String)> +|java.ui.lang.Long |LongConverter |1, 0xD3, MIN_VALUE, MAX_VALUE +|java.ui.lang.Number |NumberConverter |1, 0xFF, 1.2334, NaN, NEGATIVE_INFITIY, POSITIVE_INFINITY +|java.ui.lang.Short |ShortConverter |1, 0xD3, MIN_VALUE, MAX_VALUE +|java.net.URI |URIConverter |http://localhost:2020/testresource?api=true +|java.net.URL |URLConverter |http://localhost:2020/testresource?api=true +|ZoneId |ZoneIdConverter |Europe/Zurich +|======= + + +=== Registering PropertyConverters + +Additional +PropertyConverters+ can be implemented easily. It is recommended to register then using the +java.util.ServiceLoader+, +meaning you add a file under +META-INF/service/org.apache.tamaya.spi.PropertyConverter+ containing the fully qualified +class names of the converters to be registered (one line per each). + +Alternatively you can also use a +ConfigurationContextBuilder+ to add additional converters programmatically. + +NOTE: API Implementations can be read-only thus not allowing adding additional converters programmatically. + + +[[ComponentLoadingAndPriorization]] +=== Component Loading and Priorization + +Tamaya Core in general loads all components using the +java.util.ServiceLoader+ mechanism. This means that new components +must be registered by adding a file under +META-INF/service/<myInterfaceName>+ containing the fully qualified +implementation class names of the components to be registered (one line per each). +The +ServiceLoader+ itself does not provide any functionality for overriding or ordering of components. Tamaya +core adds this functionality by the possibility to add +@Priority+ annotations to the components registered. +By default, and if no annotation is added +0+ is used as priority. Hereby higher values preceed lower values, meaning + +* if a singleton component is accessed from the current +ServiceContext+ the component with the higher value + effectively _overrides/replaces_ any component with lower values. +* if a collection of components is obtained from the +ServiceContext+ the components are ordered in order, where the + ones with higher priority are before components with lower priority. +* if priorities match Tamaya Core additionally sorts them using the simple class name. This ensures that ordering is + still defined and predictable in almost all scenarios. + +NOTE: Sorting the property sources based on their ordinal value is only the default ordering principle applied. By implementing + your own implementation of +ConfigurationProviderSpi+ you can apply a different logic: + + +[[RegisteringPropertySources]] +=== Registering Property Sources + +PropertySources that provide configuration properties are registered as ordinary components as described in the previous +section. Nevertheless the priority is not managed based on +@Priority+ annotations, but based on an explicit ++int getOrdinal()+ method. This allows to define the ordinal/priority of a +PropertySource+ explicitly. This is useful +due to several reasons: + +* it allows to define the ordinal as part of the configuration, thus allowing new overriding property sources being + added easily. +* it allows to define the ordinal dynamically, e.g. based on the configuration location, the time of loading or + whatever may be appropriate. + + +[[CorePropertySources]] +== Configuration Setup in Core + +Tamaya Core provides a minimal configuration setting, that allows you to configure SE +applications already easily. Basically configuration is built up by default as follows: + +. Read environment properties and add them prefixed with +env.+ +. Read all files found at +META-INF/javaconfiguration.properties+ + and +META-INF/javaconfiguration.xml+ + + +=== Overview of Registered Default Property Sources and Providers + +The Tamaya Core implementation provides a couple of default +PropertySource+ implementations, which are automatically +registered. They are all in the package +org.apache.tamaya.core.propertysource+ and ++org.apache.tamaya.core.provider+: + +[width="100%",frame="1",options="header",grid="all"] +|======= +|_Type_ |_Class Name_ |_Ordinal Used_ +|META-INF/javaconfiguration.properties |JavaConfigurationProvider |0 +|META-INF/javaconfiguration.xml |JavaConfigurationProvider |0 +|Environment Properties |EnvironmentPropertySource |300 +|System Properties |SystemPropertySource |400 +|======= + + +=== Abstract Class PropertiesFilePropertySource + +The abstract class +PropertiesFilePropertySource+ can be used for implementing a +PropertySource+ based on a +URL+ +instance that points to a +.properites+ file. It requires a +URL+ to be passed on the constructor: + +[source,java] +-------------------------------------------- +PropertiesFilePropertySource(URL url); +-------------------------------------------- + + +==== Abstract Class PropertiesPropertySource + +The abstract class +PropertiesPropertySource+ can be used for implementing a +PropertySource+ based on a +Properties+ +instance. It requires a +PropertySource+ to be passed on the constructor: + +[source,java] +-------------------------------------------- +PropertiesPropertySource(Properties properties); +-------------------------------------------- + + +==== Abstract Class BasePropertySource + +The abstract class +BasePropertySource+ can be used for implementing custom +PropertySource+ classes. It requires only +one method to implemented: + +[source,java] +.Implementing a PropertySource using BasePropertySource +-------------------------------------------- +public class MyPropertySource extends BasePropertySource{ + + public String getName(){ + // return a unique name for the property source, e.g. based on the underlying resource. This name also + // allows to access the property source later + } + + public Map<String, String> getProperties(){ + // Get a map with all properties provided by this property source + // If the property source is not scannable, the map returned may be empty. + // In the ladder case the +boolean isScannale()+ must be overridden, since + // by default property sources are assumed to be scannable. + } + +} +-------------------------------------------- + +By default the ordinal of the property sources will be 1000, unless the key +tamaya.ordinal+ asdefined in ++PropertySource.TAMAYA_ORDINAL+ is present in the current +PropertySource+. Of course it is also possible to override +the inherited +protected void initializeOrdinal(final int defaultOrdinal)+, or directly +int getOrdinal()+. + + +[[CorePropertySourceProviders]] +=== Default PropertySourceProvider in Core + +With +org.apache.tamaya.core.provider.JavaConfigurationProvider+ there is also a default +PropertySourceProvider+ +present that loads all .properties files found at +META-INF/javaconfiguration.properties+ +and +META-INF/javaconfiguration.xml+. + + +[[Extensions]] +== Adding Extensions + +The Core module only implements the link:API.html[API]. Many users require/wish additional functionality from a +configuration system. Fortunately there are numerous extensions available that add further functionality. +Loading extensions hereby is trivial: you only are required to add the corresponding dependency to the classpath. + +For detailed information on the extensions available refer to the link:extensions.html[extensions documentation]. http://git-wip-us.apache.org/repos/asf/incubator-tamaya-site/blob/ede865e4/content/documentation/extensions.adoc ---------------------------------------------------------------------- diff --git a/content/documentation/extensions.adoc b/content/documentation/extensions.adoc new file mode 100644 index 0000000..a95f22f --- /dev/null +++ b/content/documentation/extensions.adoc @@ -0,0 +1,62 @@ +:jbake-type: page +:jbake-status: published + +== Apache Tamaya: Extension Modules + +toc::[] + +=== Mature Extensions + +Mature extensions have a stable API and SPI, similar to the API and Implementations provided. + +[width="100%",frame="1",options="header",grid="all"] +|======= +|_Artifact_ |_Description_ |_Links_ +| | N/A: currently no extensions have reached that maturity level. | - +|+org.apache.tamaya.ext:tamaya-formats+ |Provides an abstract model for configuration formats |link:extensions/mod_formats.html[Documentation] +|+org.apache.tamaya.ext:tamaya-functions+ |Provides several functional extension points. |link:extensions/mod_functions.html[Documentation] +|+org.apache.tamaya.ext:tamaya-json+ |Provides format support for JSON based configuration. |link:extensions/mod_json.html[Documentation] +|+org.apache.tamaya.ext:tamaya-optional+ |Lets a Tamaya configuration to be used as an optional project extension only. |link:extensions/mod_optional.html[Documentation] +|+org.apache.tamaya.ext:tamaya-resolver+ |Provides placeholder and dynamic resolution functionality for configuration values. |link:extensions/mod_resolver.html[Documentation] +|+org.apache.tamaya.ext:tamaya-events+ |Provides support for publishing configuration changes |link:extensions/mod_events.html[Documentation] +|+org.apache.tamaya.ext:tamaya-filter+ |Provides a programmatic filter for config entries. | link:extensions/mod_filter.html[Documentation] +|+org.apache.tamaya.ext:tamaya-injection-api+ |Provides Tamaya's injection annotations API. |link:extensions/mod_injection.html[Documentation] +|+org.apache.tamaya.ext:tamaya-injection+ |Provides configuration injection services and congiruation template support. |link:extensions/mod_injection.html[Documentation] +|+org.apache.tamaya.ext:tamaya-injection-cdi+ | Java EE/standalone compliant CDI integration using CDI for injection. | link:extensions/mod_cdi.html[Documentation] +|+org.apache.tamaya.ext:tamaya-injection-cdi-se+ | Java EE/standalone compliant CDI integration using Tamaya SE injection mechanism. | link:extensions/mod_cdi.html[Documentation] +|+org.apache.tamaya.ext:tamaya-mutable-config+|Provides API/SPI for writing configuration |link:extensions/mod_mutable_config.html[Documentation] +|+org.apache.tamaya.ext:tamaya-spi-support+ |Tamaya support module for SPI implementation. |link:extensions/mod_spi-support.html[Documentation] +|+org.apache.tamaya.ext:tamaya-resources+ |Provides ant-style resource path resolution |link:extensions/mod_resources.html[Documentation] +|+org.apache.tamaya.ext:tamaya-yaml+ |Support for using yaml as a configuration format. |link:extensions/mod_yaml.html[Documentation] +|+org.apache.tamaya.ext:tamaya-collections+ |Collections support. |link:extensions/mod_collections.html[Documentation] +|+org.apache.tamaya.ext:tamaya-spring+ | Integration for Spring / Spring Boot. | link:extensions/mod_spring.html[Documentation] +|======= + + +=== Extensions Sandbox + +Extensions in _draft state_ rather experimental or not yet very mature. API changes may occurr at any time +and the may also have severe issues. So use at your own risk or join and help us getting them stable and +well tested! + +NOTE: All extensions currently run on Java 7 as well as on Java 8. + +[width="100%",frame="1",options="header",grid="all"] +|======= +|_Artifact_ |_Description_ |_Links_ +|+org.apache.tamaya.ext:tamaya-commons+ |Combines Tamaya's Format Abstraction with Apache Commons. | - +|+org.apache.tamaya.ext:tamaya-jodatime+ |Provides support for JodaTime. | link:extensions/mod_jodatime.html[Documentation] +|+org.apache.tamaya.ext:tamaya-classloader-support+ |Manages Tamaya configuration and services considering classloading hierarchies. |link:extensions/mod_classloader_support.html[Documentation] +|+org.apache.tamaya.ext:tamaya-management+ |Provides JMX support for inspecting configuration. |link:extensions/mod_management.html[Documentation] +|+org.apache.tamaya.ext:tamaya-metamodel+ |Provides support defining configuration using XML based meta-configuration. |link:extensions/mod_metamodel.html[Documentation] +|+org.apache.tamaya.ext:tamaya-validation+ |Provides support for XML based meta-configuration allowing to validate configuration read. |link:extensions/mod_validation.html[Documentation] +|+org.apache.tamaya.ext:tamaya-usagetracker+ |Provides support tracking of configuration usage and the consumer locations consuming configuration. |link:extensions/mod_usagetracker.html[Documentation] +|+org.apache.tamaya.ext:tamaya-camel+ | Integration for Apache Camel. | link:extensions/mod_camel.html[Documentation] +|+org.apache.tamaya.ext:tamaya-osgi+ | Integration for OSGI containers. | link:extensions/mod_osgi.html[Documentation] +|+org.apache.tamaya.ext:tamaya-consul+ | Integration with consul clusters. | link:extensions/mod_consul.html[Documentation] +|+org.apache.tamaya.ext:tamaya-etcd+ | Integration with etcd clusters. | link:extensions/mod_etcd.html[Documentation] +|+org.apache.tamaya.ext:tamaya-configured-sysprops+ | Allows Tamaya to integrate with +System.getProperties()+. | link:extensions/mod_sysprops.html[Documentation] +|+org.apache.tamaya.ext:tamaya-remote+ |Provides remote configuration support. |link:extensions/mod_remote.html[Documentation] +|+org.apache.tamaya.ext:tamaya-server+ |Lets a Tamaya configuration instance provide scoped configuration as a REST service. |link:extensions/mod_server.html[Documentation] +|+org.apache.tamaya.ext:tamaya-ui+ |Provides a web UI for a VM running Tamaya. |link:extensions/mod_ui.html[Documentation] +|======= http://git-wip-us.apache.org/repos/asf/incubator-tamaya-site/blob/ede865e4/content/documentation/extensions/mod_builder.adoc ---------------------------------------------------------------------- diff --git a/content/documentation/extensions/mod_builder.adoc b/content/documentation/extensions/mod_builder.adoc new file mode 100644 index 0000000..a589374 --- /dev/null +++ b/content/documentation/extensions/mod_builder.adoc @@ -0,0 +1,83 @@ +:jbake-type: page +:jbake-status: published + += Apache Tamaya -- Extension: Builder + +[[BuilderCore]] +== Tamaya Builder (Extension Module) +=== Overview + +The Tamaya builder module provides a generic (one time) builder for creating +Configuration+ instances, +e.g. as follows: + +[source,java] +--------------------------------------------------------------- +ConfigurationBuilder builder = new ConfigurationBuilder(); +// do something +Configuration config = builder.build(); +--------------------------------------------------------------- + +Basically the builder allows to create configuration instances completely independent of the current configuration +setup. This gives you full control on the +Configuration+ setup. + +=== Compatibility + +The module is based on Java 7, so it will run on Java 7 and does +not require Java 8. The +ConfigurationProvider+ +as defined by the API, provides a builder instance for +ConfigurationContext+ +in a similar way. A +Configuration+ can also be created by passing an instance of a +ConfigurationContext+: + + +=== Installation + +To benefit from configuration builder support you only must add the corresponding +dependency to your module: + +[source,xml,subs="verbatim,attributes"] +----------------------------------------------- +<dependency> + <groupId>org.apache.tamaya.ext</groupId> + <artifactId>tamaya-builder</artifactId> + <version>{tamaya_version}</version> +</dependency> +----------------------------------------------- + +=== Supported Functionality + +The builder allows you to add +PropertySource+ instances: + +[source,java] +---------------------------------------------------------------- +ConfigurationBuilder builder = new ConfigurationBuilder(); +builder.addPropertySources(sourceOne).addPropertySources(sourceTwo); +Configuration config = builder.build(); +---------------------------------------------------------------- + +Similarly you can add filters: + +[source,java] +---------------------------------------------------------------- +builder.addPropertyFilters(new MyConfigFilter()); +---------------------------------------------------------------- + +...or +PropertySourceProvider+ instances: + +[source,java] +---------------------------------------------------------------- +builder.addPropertySourceProvider(new MyPropertySourceProvider()); +---------------------------------------------------------------- + +Also the builder module allows to include/exclude any filters and property source already known to the current ++ConfigurationContext+: + +[source,java] +---------------------------------------------------------------- +builder.disableProvidedPropertyConverters(); +builder.enableProvidedPropertyConverters(); + +builder.disableProvidedPropertyFilters(); +builder.enableProvidedPropertyFilters(); + +builder.disableProvidedPropertySources(); +builder.enableProvidedPropertySources(); +---------------------------------------------------------------- http://git-wip-us.apache.org/repos/asf/incubator-tamaya-site/blob/ede865e4/content/documentation/extensions/mod_camel.adoc ---------------------------------------------------------------------- diff --git a/content/documentation/extensions/mod_camel.adoc b/content/documentation/extensions/mod_camel.adoc new file mode 100644 index 0000000..9690dda --- /dev/null +++ b/content/documentation/extensions/mod_camel.adoc @@ -0,0 +1,129 @@ +:jbake-type: page +:jbake-status: published + += Apache Tamaya -- Extension: Integration with Apache Camel + +toc::[] + + +[[Optional]] +== Integration with Apache Camel (Extension Module) +=== Overview + +The Tamaya Camel integration module provides different artifacts which allows integration of Apachae Tamaya +configuration with Apache Camel. + + +=== Compatibility + +The module is based on Java 7, so it will not run on Java 7 and beyond. + + +=== Installation + +To benefit from configuration builder support you only must add the corresponding dependency to your module: + +[source, xml] +----------------------------------------------- +<dependency> + <groupId>org.apache.tamaya.ext</groupId> + <artifactId>tamaya-camel</artifactId> + <version>{tamaya_version}</version> +</dependency> +----------------------------------------------- + + +=== The Extensions Provided + +Camel integration comes basically with three artifacts: + +* A Camel +ResolverFunction+ implementation adding explicit property resolution + (+org.apache.tamaya.integration.camel.TamayaPropertyResolver+). +* A Camel +PropertiesComponent+ implementation, which allows implicitly preconfigures the resolvers from above and + additionally allows using Tamaya configuration as Camel _overrides_ + (+org.apache.tamaya.integration.camel.TamayaPropertiesComponent+). + + +=== Configuring using Camel Java DSL + +Camel integration using Java DSL is basically simple: + +[source, java] +----------------------------------------------- +import org.apache.tamaya.integration.camel.TamayaPropertiesComponent; + +camelContext.addComponent("properties", new TamayaPropertiesComponent()); +----------------------------------------------- + +Given so you can then use +cfg+ or +tamaya+ as prefix for resolving entries with Tamaya as follows: + +[source, java] +----------------------------------------------- +RouteBuilder builder = new RouteBuilder() { + public void configure() { + from("direct:hello1").transform().simple("{{cfg:message}}"); + } +}; +camelContext.addRoutes(builder); +builder = new RouteBuilder() { + public void configure() { + from("direct:hello2").transform().simple("{{tamaya:message}}"); + } +}; +camelContext.addRoutes(builder); +----------------------------------------------- + + +Optionally you can also configure +TamayaPropertiesComponent+ that all currently known Tamaya properties are used +as Camel overrides, meaning they are evaluated prior to all other available resolver functions in the Camel ++PropertiesComponent+: + +[source, java] +----------------------------------------------- +TamayaPropertiesComponent props = new TamayaPropertiesComponent(); +props.setTamayaOverrides(true); +----------------------------------------------- + + +=== Configuring using Camel XML DSL + +Camel integration using XML DSL is basically very similar. You just have to add the +properties+ component as bean +as well. All other configuration parameters (e.g. file URIs are similar supported). In the example code below we +again use Tamaya as the main configuration solutions only using Camel's default behaviour as a fallback: + +[source, xml] +----------------------------------------------- +<beans xmlns="http://www.springframework.org/schema/beans" + xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" + xsi:schemaLocation=" + http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd + http://camel.apache.org/schema/spring http://camel.apache.org/schema/spring/camel-spring.xsd + "> + + <routeContext id="myCoolRoutes" xmlns="http://camel.apache.org/schema/spring"> + <route id="r1"> + <from uri="direct:hello1"/> + <transform> + <simple>{{message}}</simple> + </transform> + </route> + <route id="r2"> + <from uri="direct:hello2"/> + <transform> + <simple>{{cfg:message}}</simple> + </transform> + </route> + <route id="r3"> + <from uri="direct:hello3"/> + <transform> + <simple>{{tamaya:message}}</simple> + </transform> + </route> + </routeContext> + + <bean id="properties" class="org.apache.tamaya.integration.camel.TamayaPropertiesComponent"> + <property name="tamayaOverrides" value="true"/> + </bean> + +</beans> +----------------------------------------------- http://git-wip-us.apache.org/repos/asf/incubator-tamaya-site/blob/ede865e4/content/documentation/extensions/mod_cdi.adoc ---------------------------------------------------------------------- diff --git a/content/documentation/extensions/mod_cdi.adoc b/content/documentation/extensions/mod_cdi.adoc new file mode 100644 index 0000000..c49a61c --- /dev/null +++ b/content/documentation/extensions/mod_cdi.adoc @@ -0,0 +1,217 @@ +:jbake-type: page +:jbake-status: published + += Apache Tamaya -- Extension: Classloader Isolation Support + +toc::[] + + +[[Remote]] +== Tamaya CDI Integration (Extension Modules) +=== Overview + +Apache Tamaya currently provides two implementations for integration with CDI extensions implementing similar +functionality as described in this document: + +* Loading of CDI managed SPI components as configuration extensions such as +PropertySources, PropertySourceProviders, + PropertyFilters, etc+. This also includes SPI defined by any Tamaya submodules. +* Implement and enable Tamaya's configuration injection services with CDI. + +Hereby there are two implementations provided: + +* +tamaya-cdi-ee+ implements injection by using CDI's injection mechanism to inject configuration values into the + beans managed by the CDI systems. +* +tamaya-cdi-se+ implements injection by integrating the +tamaya-injection+ SE based injection module (also used + for Spring and OSGI injection) with CDI. Injection hereby is performed by the Tamaya SE module, whereas + beans and injection control overall are still managed by CDI. +* One difference, of course, is that +tamaya-se+ also provides an SE compatible API (+ConfigurationInjection, + ConfigurationInjector+), which is not available, when using the purely Java EE based variant. + +The annotations used for all injection functionality in Tamaya is defined as a separate module. This allows you to +code against the injection API without dependency on the concrete injection implementation. As a consequence your +components will be compatible regardless if deployed in a pure SE, a Java EE (CDI) or OSGI or Spring environment: + +----------------------------------------------- +<dependency> + <groupId>org.apache.tamaya.ext</groupId> + <artifactId>tamaya-injection-api</artifactId> + <version>{tamaya_version}</version> +</dependency> +----------------------------------------------- + + +=== Compatibility + +Both modules are based on Java 7, so they will not run on Java 7 and beyond. + + +=== Installation + +To benefit from Tamaya CDI integration you only must one of the following dependencies to your module. Ensure that +you never have installed both CDI extensions at the same time because this may be lead to unforseen side-effects. + +.CDI Pure Application Configuration +[source, xml] +----------------------------------------------- +<dependency> + <groupId>org.apache.tamaya.ext</groupId> + <artifactId>tamaya-cdi-ee</artifactId> + <version>{tamaya_version}</version> +</dependency> +----------------------------------------------- + +.CDI enhanced with Tamaya SE Application Configuration +[source, xml] +----------------------------------------------- +<dependency> + <groupId>org.apache.tamaya.ext</groupId> + <artifactId>tamaya-cdi-se</artifactId> + <version>{tamaya_version}</version> +</dependency> +----------------------------------------------- + +Both components will auto-register its components and override the default +ServicceContext+ in use. Additionally they +register CDI extensions that implement Configuration injection as described before. + +IMPORTANT: Never install Tamaya's +tamaya-cdi-se+ and +tamaya-cdi-ee+ on the same system, since unpredictable side + effects could occur. + +=== Registering CDI managed components into the Application's ConfigurationContext + +As mentioned both modules allow to provide Tamaya SPI extensions modules as ordinary CDI managed beans. By default +extensions should be registered using +@Singleton+ or +@ApplicationScoped+ scope annotations. So you can define/deploy +additional application specific +PropertySources+ and other artifacts simply by defining a CDI managed bean implementing +the required SPI interface: + +[source, java] +-------------------------------------------------------- +@Singleton +public class TestPropertySource implements PropertySource{ + + final Map<String,String> config = new HashMap<>(); + + public TestPropertySource(){ + config.put("a.b.c.key1", "keys current a.b.c.key1"); + config.put("a.b.c.key2", "keys current a.b.c.key2"); + config.put("{"+getName()+"}source", getClass().getName()); + } + + @Override + public int getOrdinal() { + return 10; + } + + @Override + public String getName() { + return getClass().getName(); + } + + @Override + public String get(String key) { + return config.get(key); + } + + @Override + public Map<String, String> getProperties() { + return config; + } + + @Override + public boolean isScannable() { + return true; + } +} +-------------------------------------------------------- + +Note that for many SPI's there is a priority mechanism using +@Priority+ annotations in place. +The +ServiceContext+ implementation combines the components registered with the ones loaded from the +ServiceLoader+ +mechanism hereby considering classloaser hierarchies. + + +=== Annotating your Classes + +Basically annotating your classes is stright forward. +@Config+ defines an additional CDI qualifier that is, depending +on the module deployed, handled by a CDI producer (+tamaya-cdi-ee+) or the Tamaya SE injection mechanism $ +(+tamaya-cdi-se+). All types injected by this module are injected using _dependent scope_. + + +[source, java] +-------------------------------------------------------- +@RequestScoped +public class ConfiguredClass{ + + @Config + private String testProperty; + + @Config({"a.b.c.key1","a.b.c.key2","a.b.c.key3"}) + @ConfigDefault("The current \\${JAVA_HOME} env property is ${env:JAVA_HOME}.") + String value1; + + @Config({"foo","a.b.c.key2"}) + private String value2; + + @Config + @ConfigDefault("N/A") + private String runtimeVersion; + + @Config + @ConfigDefault("${sys:java.version}") + private String javaVersion2; + + @Config + @ConfigDefault("5") + private Integer int1; + + ... + +} +-------------------------------------------------------- + +=== Advanced Use Cases + +Beside basic configuration Tamaya also covers additional requirements: + +* _Reading multiple keys, where the first successful one is determining the value of the configuration, is + simply possible, by adding multiple keys to the +@Configy+ annotation. + E.g. for trying first +a.b+ and then +new.b+ you would configure it as follows: + +[source,java] +-------------------------------------------------------------------------------------- +@Config({"a.b", "new.b"} +private String value; +-------------------------------------------------------------------------------------- + +* When you must apply a +ConfigOperator+ to your config, before reading the configuration, you can + configure one as follows: + +[source,java] +-------------------------------------------------------------------------------------- +@Config({"a.b", "new.b"} +@WithConfigOperator(MyOperator.class) +private String value; +-------------------------------------------------------------------------------------- + +* When you must apply a some special conversion, or you use a type that is not registered + for conversion, you can configure a custom converter to be applied as follows: + +[source,java] +-------------------------------------------------------------------------------------- +@Config({"a.b", "new.b"} +@WithPropertyConverter(MyConverter.class) +private MySpecialFooType value; +-------------------------------------------------------------------------------------- + +* Often multiple keys in a class belong to the same root section. So instead of copying this to + every entry you can define the most common root sections in the type's header: + +[source,java] +-------------------------------------------------------------------------------------- +@ConfigDefaultSections({"aaaa", "new"}); +public class MyType{ + +@Config({"b", "[legacy.bKey]"} // lookups: "aaaa.b", "new.b", legacy.bKey +private String value; +-------------------------------------------------------------------------------------- + +In the example above +legacy.bKey+ defines an absolute key, which is not combined with any defined +default section parts. http://git-wip-us.apache.org/repos/asf/incubator-tamaya-site/blob/ede865e4/content/documentation/extensions/mod_classloader_support.adoc ---------------------------------------------------------------------- diff --git a/content/documentation/extensions/mod_classloader_support.adoc b/content/documentation/extensions/mod_classloader_support.adoc new file mode 100644 index 0000000..9a2d0df --- /dev/null +++ b/content/documentation/extensions/mod_classloader_support.adoc @@ -0,0 +1,75 @@ +:jbake-type: page +:jbake-status: published + += Apache Tamaya -- Extension: Classloader Isolation Support + +toc::[] + +[[Remote]] +== Tamaya Classloader Aware ServiceContext (Extension Module) +=== Overview + +The Tamaya classloader support provides an alternative implementation of +java.util.ServiceLoader+, which is aware +of classloaders, hereby preventing multiple loading of components within a classloader hierarchy. + + +=== Compatibility + +The module is based on Java 7, so it will not run on Java 7 and beyond. + + +=== Installation + +To benefit from configuration server support you only must add the corresponding dependency to your module: + +[source, xml] +----------------------------------------------- +<dependency> + <groupId>org.apache.tamaya.ext</groupId> + <artifactId>tamaya-classloader-support</artifactId> + <version>{tamaya_version}</version> +</dependency> +----------------------------------------------- + +The component will auto.register its components and override the default +ServicceContext+ in use by default +with an instance of type +org.apache.tamaya.clsupport.internal.CLAwareServiceContext+. This implementation returns +a priority of +10+. + +=== How it works + +Basically the component manages a +Map+ of all classloaders encountered. When services are accessed, the component +will evaluate the services as follows: + +* the component walks up the class loader hierarchy. +* in a next step the hierarchy is traversed down from the parent to the current classloader. Hereby it is checked + if the service list for the required type has been loaded already. If not the service configuration files are + evaluated. +* This configuration file evaluation will ignore all resources already loaded by any of the already traversed parent + classloaders. +* For each configuration file newly visible to the classloader currently traversed, the corresponding services are + loaded unleyy, the same service class already has been loaded by one its parent classloaders or another file + loaded with this classloader. +* Finally all services found are returned as the full collection of services valid for the given context (classloader). + +This ensures no service is loaded multiple times, even when it is referenced multiple times in several service +configurations. Additionally every service is loaded on the classloader where it is also declared the first time. + + +=== Control Logging + +The service component by default only logs errors. But it is possible to change this by reconfiguring the logging +levels on the following logging names/path: +org.apache.tamaya.clsupport.internal.CLAwareServiceContext+ + +* _INFO_ logs additional info on the services accessed. +* _FINEST_ logs additional info on the services scanned and selected. + + +=== Classloader Aware Configuration + +The mechanism above is used to provide a classloader aware implementation of +ConfigurationContext+ +(+org.apache.tamaya.clsupport.internal.CLAwareConfigurationContext+). Similarly to the service variants +this class provides a context implementation that manages the core configuration aspects considering classloading +hierarchies: + +* +PropertySource+, +PropertySourceProviders+ +* +PropertyFilters+, +PropertyCombinationPolicy+ http://git-wip-us.apache.org/repos/asf/incubator-tamaya-site/blob/ede865e4/content/documentation/extensions/mod_collections.adoc ---------------------------------------------------------------------- diff --git a/content/documentation/extensions/mod_collections.adoc b/content/documentation/extensions/mod_collections.adoc new file mode 100644 index 0000000..e758756 --- /dev/null +++ b/content/documentation/extensions/mod_collections.adoc @@ -0,0 +1,232 @@ +:jbake-type: page +:jbake-status: published + += Apache Tamaya -- Extension: Collection Support + +toc::[] + +[[Optional]] +== Tamaya Collection Support (Extension Module) +=== Overview + +All configuration in Tamaya is expressed as simple key, value pairs. Nevertheless this concept allows similarly +the modelling of collection typed values such as lists, sets, maps or simple collections of things. The Tamaya +Collections extension adds this functionality to the Tamaya eco-system. + +=== Compatibility + +The module is based on Java 7, so it will not run on Java 7 and beyond. + + +=== Installation + +To use Tamaya collection support you only must add the corresponding dependency to your module: + +[source, xml] +----------------------------------------------- +<dependency> + <groupId>org.apache.tamaya.ext</groupId> + <artifactId>tamaya-collections</artifactId> + <version>{tamaya_version}</version> +</dependency> +----------------------------------------------- + + +=== Overview + +Tamaya Collections adds +PropertyConverter+ implementations that are able to access configuration data +as lists, maps or sets. By default this works out of the box as easy as accessing any other type of +configuration data, e.g. + +[source, java] +----------------------------------------------- +Configuration config = ConfigurationProvider.getConfiguration(); + +// Without any content specification, a list of String is returned. +List<String> simpleList = config.get("my.list.config.entry", List.class); + +// Using a TypeLiteral allows to use every convertible sub type supported by the system. +List<Integer> intList = config.get("my.list.config.entry", new TypeLiteral<List<Integer>>(){}); +----------------------------------------------- + +Configuration in that case, by default, is a simple comma-separated list of entries, e.g. + +[source, properties] +----------------------------------------------- +my.list.config.entry=1,34454,23,344545,3445 +----------------------------------------------- + +Additionally the module allows adding additional meta-entries, which allows to tweak some of the +inner-workings, e.g. + +* using your own +PropertyConverter+ implementation for parsing entries. +* specifying a custom separator String to be used to split the items (default is {{','}}. +* specifying a custom separator String to be used to split key/value paris when parsing map entries. +* specifying the implementation type of the collection instance to be returned. +* specifying if the resulting collection should be returned as a modifiable collection. + +=== Supported Types + +This module supports the following types: + +* +java.util.Collection+ +* +java.util.List+ +* +java.util.ArrayList+ +* +java.util.LinkedList+ +* +java.util.Set+ +* +java.util.SortedSet+ +* +java.util.TreeSet+ +* +java.util.HashSet+ +* +java.util.Map+ +* +java.util.SortedMap+ +* +java.util.HashMap+ +* +java.util.TreeMap+ + +Hereby the type is determined primarly by the parameter type accessed, e.g. ++config.get("mylist", ArrayList.class)+ will always return an +ArrayList+ +as result. + +==== Configuring the target implementation type + +Tamaya Collections allows you to configure the target collection type by adding the +following meta-configuration entry (shown for the +mylist+ entry). Hereby the package part +java.util.+ +can be ommitted: + +[ source, properties] +----------------------------------------------- +mylist=a,b,c +_mylist.collection-type=LinkedList +----------------------------------------------- + +When calling +config.get("mylist", ArrayList.class)+ this parameter does not have any effect, so you will still +get an +ArrayList+ as a result. However when you call +config.get("mylist", List.class)+ you will +get a +LinkedList+ as implementation type. + +This mechanism similarly applies to all kind of collections, so you can use it similarly to define the implementation +type returned when accessing +List+, +Map+ or +Collection+. + + +=== Collecting Configuration Entries instead of Overriding + +By default Tamaya applies always an overriding +CombinationPolicy+, where only the configuration entry for +the most significant configuration entry is used. In case of collections (and maybe also other use cases), +overriding is not always the mechanism of choice. E.g. when you want to have all entries added to your +configuration to be *combined* to a new entry containing all values provided by any property sources. + +Therefore Tamaya Collections also provides a more sophistiated +CombinationPolicy+ (automatically configured) +that allows to adapt the way how configuration entries are combined. All you must do is declaring +the mechanism to be applied by an according meta-configuration parameter, e.g. for +my.list+ your config may +look as follows: + +[source, properties] +----------------------------------------------- +# from PropertSource 1 +my.list=1,2,3 + +# from PropertSource 2 +my.list=4,5,6 + +# without any additional meta-info these entries would be combined to +my.list=4,5,6 +----------------------------------------------- + +With Tamaya Collections you can now configure the combination policy as follows: + +[source, properties] +----------------------------------------------- +# use one of the default policies: override / collect +_my.list.combination-policy=collect + +# use an custom CombinationPolicy to combine the values +_my.list.combination-policy=com.mycomp.app.MyCombincationPolicy +----------------------------------------------- + +So declaring the +collect+ policy the resulting raw output of the entry looks as follows: + +[source, properties] +----------------------------------------------- +# result when applying the collect policy: +my.list=1,2,3,4,5,6 +----------------------------------------------- + +The customizable policy mechanism of Tamaya Collections also honors the +item-separator+ meta-configuration +parameter explained later in this document. + + +=== Format of Collection Configuration + +By default collections are modelled as simple String values, that are tokenized into individual parts using a +defined +item-separator+ (by default +','+). So a given configuration entry of +1,2,3+ is mapped to +"1","2","3". +If the target context type is something different than String the smae conversion logic is used as when mapping +configuration parameters directly to non-String target types (implemented as +PropertyConverter+ classes, manahed +within the current +ConfigurationContext+. The procedure is identical for all collection types, including +Map+ types, +with the difference that each token in the list is parsed once more for separating it into a +key+ and a +value+. +The default separator for map entries hereby is +"::"+. Map keys, as of now, are always of type +String+, whereas +for values the same logic is applied as for non-map collection types. + +[source, properties] +----------------------------------------------- +# a list, using the default format +list=1,2,3,4,5,6 + +# a map, using the default format +map=a::b, c::d +----------------------------------------------- + +==== Trimming of entries + +By default all tokens parsed are trimmed _before_ adding them to the final collection. In case of map entries this is +also the case for key/value entries. So the following configuration results in the identical values for ++list1,list2+ and +map1,map2+: + +[source, properties] +----------------------------------------------- +# a list, using the default format +list1=1,2,3,4,5,6 +list2=1, 2, 3, 4, 5, 6 + +# a map, using the default format +map1=a::b, c::d +map2=a :: b, c :: d +----------------------------------------------- + +Nevertheless truncation can be controlled by the usage of brackets, e.g. the last list or map entry will have a single +space character as value: + +[source, properties] +----------------------------------------------- +# a list, with a ' ' value at the end +list3=1, 2, 3, 4, 5, [ ] + +# a map, with a ' ' value for key '0' +map3=1 :: a, 2 :: b, 0::[ ] +----------------------------------------------- + +Hereby +\[+ escapes the sequence. + + +==== Customizing the format + +The item and entry separators (by default +','+ and +"::"+) can be customized by setting corresponding meta-data +entries as follows, resulting in the same values as in the prevoius listing: + +[source, properties] +----------------------------------------------- +# a list, with a ' ' value at the end +list3=1__2__3__ 4__ 5__[ ] +_list3.item-separator=__ + +# a map, with a ' ' value for key '0' +map3=1->a, 2->b, 0->[ ] +_map3.map-entry-separator=-> +----------------------------------------------- + +Of course these settings also can be combined: + +[source, properties] +----------------------------------------------- +# a reformatted map +redefined-map=0==none | 1==single | 2==any +_redefined-map.map-entry-separator=== +_redefined-map.item-separator=| +----------------------------------------------- http://git-wip-us.apache.org/repos/asf/incubator-tamaya-site/blob/ede865e4/content/documentation/extensions/mod_consul.adoc ---------------------------------------------------------------------- diff --git a/content/documentation/extensions/mod_consul.adoc b/content/documentation/extensions/mod_consul.adoc new file mode 100644 index 0000000..4407ed3 --- /dev/null +++ b/content/documentation/extensions/mod_consul.adoc @@ -0,0 +1,59 @@ +:jbake-type: page +:jbake-status: published + += Apache Tamaya -- Extension: Integration with consul (Hashicorp) + +toc::[] + + +[[Optional]] +== Integration with consul (Extension Module) +=== Overview + +The Tamaya consul integration module provides different artifacts which allows integration of Apachae Tamaya +configuration with consul. Basically the module supports read-only integration (as a +ConsulPropertySource+ as well +as a support for +MutableConfiguration+ as defined by the +tamaya-mutable-config+ extension module. + + +=== Compatibility + +The module is based on Java 7, so it will not run on Java 7 and beyond. + + +=== Installation + +To benefit from configuration builder support you only must add the corresponding dependency to your module: + +[source, xml] +----------------------------------------------- +<dependency> + <groupId>org.apache.tamaya.ext</groupId> + <artifactId>tamaya-consul</artifactId> + <version>{tamaya_version}</version> +</dependency> +----------------------------------------------- + + +=== The Extensions Provided + +Consul integration comes basically with 2 artifacts: + +* The +org.apache.tamaya.etcd.ConsulPropertySource+ is a +PropertySource+ with a default ordinal of 100 and the name + 'consul', which is automatically registered. +* If the +tamaya-mutable-config+ module is loaded it is possible to write property values back into the consul cluster, + by accessing a +MutableConfiguration+ using the URI +config:consul+. + + +=== The ConsulPropertySource + +The +ConsulPropertySource+ is automatically registered and allows the consul servers to be used to be configured. This +enables to use e.g. in Docker environments the docker environment configuration mechanisms to configure Tamaya running +in microservice containers to connect with the according consul cluster: + +* The property source reads the +tamaya.consul.urls+ system and environment property to evaluate possible etcd servers + (comma separated), which can be connected to. On error the API just performs a Round-Robin through the list of + configured servers. Without any configuration +http://127.0.0.1:2400+ is used. If no connection to any consul + server can be established a warning will be logged, but deployment will not fail. +* The +ConsulPropertySource+ finally also allows the values read from the consul cluster to be mapped to prefixed + context. This can be activated by setting the +-Dtamaya.consul.prefix=<PREFIX>+ system property. E.g. when the prefix is + set to +cluster-config.+ a consul key of +host:known/all+ is mapped to +cluster-config.host:known/all+. http://git-wip-us.apache.org/repos/asf/incubator-tamaya-site/blob/ede865e4/content/documentation/extensions/mod_environment.adoc ---------------------------------------------------------------------- diff --git a/content/documentation/extensions/mod_environment.adoc b/content/documentation/extensions/mod_environment.adoc new file mode 100644 index 0000000..c0224a1 --- /dev/null +++ b/content/documentation/extensions/mod_environment.adoc @@ -0,0 +1,42 @@ +:jbake-type: page +:jbake-status: published + += Apache Tamaya -- Extension: Classloader Isolation Support + +toc::[] + + +[[Remote]] +== Tamaya Environment Model (Extension Module) +=== Overview + +The Tamaya Environment extension adds a simple PropertySourceProvider that evaluates a List of environment context and +combines them in the given order into an (optional) root context within the system's configuration. + + +=== Compatibility + +The module is based on Java 7, so it will not run on Java 7 and beyond. + + +=== Installation + +To benefit from Tamaya Environment Model you only must add the corresponding dependency to your module: + +[source, xml] +----------------------------------------------- +<dependency> + <groupId>org.apache.tamaya.ext</groupId> + <artifactId>tamaya-envionment</artifactId> + <version>{tamaya_version}</version> +</dependency> +----------------------------------------------- + + +=== How it Works + +tbd + +=== Reusable Base Classes + +tbd