http://git-wip-us.apache.org/repos/asf/incubator-tamaya-site/blob/3d91bad5/content/extensions/mod_cdi.adoc ---------------------------------------------------------------------- diff --git a/content/extensions/mod_cdi.adoc b/content/extensions/mod_cdi.adoc new file mode 100644 index 0000000..db86633 --- /dev/null +++ b/content/extensions/mod_cdi.adoc @@ -0,0 +1,233 @@ +// 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. + += Apache Tamaya -- Extension: Classloader Isolation Support +:jbake-type: page +:jbake-status: published + +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>{tamayaVersion}</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>{tamayaVersion}</version> +</dependency> +----------------------------------------------- + +.CDI enhanced with Tamaya SE Application Configuration +[source, xml] +----------------------------------------------- +<dependency> + <groupId>org.apache.tamaya.ext</groupId> + <artifactId>tamaya-cdi-se</artifactId> + <version>{tamayaVersion}</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/3d91bad5/content/extensions/mod_classloader_support.adoc ---------------------------------------------------------------------- diff --git a/content/extensions/mod_classloader_support.adoc b/content/extensions/mod_classloader_support.adoc new file mode 100644 index 0000000..7b93a4b --- /dev/null +++ b/content/extensions/mod_classloader_support.adoc @@ -0,0 +1,91 @@ +// 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. + += Apache Tamaya -- Extension: Classloader Isolation Support +:jbake-type: page +:jbake-status: published + +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>{tamayaVersion}</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/3d91bad5/content/extensions/mod_collections.adoc ---------------------------------------------------------------------- diff --git a/content/extensions/mod_collections.adoc b/content/extensions/mod_collections.adoc new file mode 100644 index 0000000..61e5553 --- /dev/null +++ b/content/extensions/mod_collections.adoc @@ -0,0 +1,248 @@ +// 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. + += Apache Tamaya -- Extension: Collection Support +:jbake-type: page +:jbake-status: published + +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>{tamayaVersion}</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/3d91bad5/content/extensions/mod_consul.adoc ---------------------------------------------------------------------- diff --git a/content/extensions/mod_consul.adoc b/content/extensions/mod_consul.adoc new file mode 100644 index 0000000..f29a2e1 --- /dev/null +++ b/content/extensions/mod_consul.adoc @@ -0,0 +1,75 @@ +// 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. + += Apache Tamaya -- Extension: Integration with consul (Hashicorp) +:jbake-type: page +:jbake-status: published + +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>{tamayaVersion}</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/3d91bad5/content/extensions/mod_environment.adoc ---------------------------------------------------------------------- diff --git a/content/extensions/mod_environment.adoc b/content/extensions/mod_environment.adoc new file mode 100644 index 0000000..df889ed --- /dev/null +++ b/content/extensions/mod_environment.adoc @@ -0,0 +1,58 @@ +// 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. + += Apache Tamaya -- Extension: Classloader Isolation Support +:jbake-type: page +:jbake-status: published + +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>{tamayaVersion}</version> +</dependency> +----------------------------------------------- + + +=== How it Works + +tbd + +=== Reusable Base Classes + +tbd http://git-wip-us.apache.org/repos/asf/incubator-tamaya-site/blob/3d91bad5/content/extensions/mod_etcd.adoc ---------------------------------------------------------------------- diff --git a/content/extensions/mod_etcd.adoc b/content/extensions/mod_etcd.adoc new file mode 100644 index 0000000..4bad2a0 --- /dev/null +++ b/content/extensions/mod_etcd.adoc @@ -0,0 +1,205 @@ +// 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. + += Apache Tamaya -- Extension: Integration with etcd (Core OS) +:jbake-type: page +:jbake-status: published + +toc::[] + + +[[Optional]] +== Integration with etcd (Extension Module) +=== Overview + +The Tamaya etcd integration module provides different artifacts which allows integration of Apachae Tamaya +configuration with etcd. Basically the module supports read-only integration (as a +EtcdPropertySource+ 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-etcd</artifactId> + <version>{tamayaVersion}</version> +</dependency> +----------------------------------------------- + + +=== The Extensions Provided + +ETcd integration comes basically with 2 artifacts: + +* The +org.apache.tamaya.etcd.EtcdAccessor+ can be configured with a an url targeting an etcd server's REST endpoint root. + (+org.apache.tamaya.etcd.EtcdAccessor+). The accessor basically provides a simple Java API for communicating + with etcd server. The accessor hereby allows reading of single properties, or whole subtrees. Also the basic non + atomic write methods are implemented. +* The +org.apache.tamaya.etcd.EtcdPropertySource+ is a +PropertySource+ with a default ordinal of 100 and the name + 'etcd', which is automatically registered. +* If the +tamaya-mutable-config+ module is loaded it is possible to write property values back into the etcd cluster, + by accessing a +MutableConfiguration+ using the URI +config:etcd+. + +=== The EtcdAccessor + +The accessor mentioned implements the basic read and write API for communicating with an etcd configuration cluster. +Hereby the accessor also provides etcd specific data such as +createdIndex, modifiedIndex, ttl+ in the +Map+ +returned. Hereby the concept of etcd is used where keys starting with an '_' will be hidden from the overall +properties map, being only directly/explicitly accessible: + +[source, java] +----------------------------------------------- +public class EtcdAccessor { + + /** + * Creates a new instance with the basic access url. + * @param server server url, e.g. {@code http://127.0.0.1:4001}. + * @throws MalformedURLException + */ + public EtcdAccessor(String server) throws MalformedURLException; + + /** + * Get the etcd server version. + * @return the etcd server version, never null. + */ + public String getVersion(); + + /** + * Ask etcd for s aingle key, value pair. Hereby the response returned from etcd: + * <pre> + * key=value + * _key.source=[etcd]http://127.0.0.1:4001 + * _key.createdIndex=12 + * _key.modifiedIndex=34 // optional + * _key.ttl=300 // optional + * _key.expiration=... // optional + * </pre> + * @param key the requested key + * @return the mapped result, including meta-entries. + */ + public Map<String,String> get(String key); + + /** + * Creates/updates an entry in etcd without any ttl set. + * The response is as follows: + * <pre> + * key=value + * _key.source=[etcd]http://127.0.0.1:4001 + * _key.createdIndex=12 + * _key.modifiedIndex=34 // optional + * _key.prevNode.createdIndex=12 // optional + * _key.prevNode.modifiedIndex=34 // optional + * </pre> + * @param key the property key, not null + * @param value the value to be set + * @return the result map as described above. + */ + public Map<String,String> set(String key, String value); + + /** + * Creates/updates an entry in etcd. The response is as follows: + * <pre> + * key=value + * _key.source=[etcd]http://127.0.0.1:4001 + * _key.createdIndex=12 + * _key.modifiedIndex=34 // optional + * _key.ttl=300 // optional + * _key.expiry=... // optional + * _key.prevNode.createdIndex=12 // optional + * _key.prevNode.modifiedIndex=34 // optional + * _key.prevNode.ttl=300 // optional + * _key.prevNode.expiration=... // optional + * </pre> + * @param key the property key, not null + * @param value the value to be set + * @param ttlSeconds the ttl in seconds (optional) + * @return the result map as described above. + */ + public Map<String,String> set(String key, String value, Integer ttlSeconds); + + + /** + * Deletes a given key. The response is as follows: + * <pre> + * _key.source=[etcd]http://127.0.0.1:4001 + * _key.createdIndex=12 + * _key.modifiedIndex=34 + * _key.ttl=300 // optional + * _key.expiry=... // optional + * _key.prevNode.createdIndex=12 // optional + * _key.prevNode.modifiedIndex=34 // optional + * _key.prevNode.ttl=300 // optional + * _key.prevNode.expiration=... // optional + * _key.prevNode.value=... // optional + * </pre> + * @param key the key to be deleted. + * @return the response mpas as described above. + */ + public Map<String,String> delete(String key); + + + /** + * Access regular Tamaya properties map as follows: + * <pre> + * key1=myvalue + * _key1.source=[etcd]http://127.0.0.1:4001 + * _key1.createdIndex=12 + * _key1.modifiedIndex=34 // optional + * _key1.ttl=300 // optional + * _key1.expiration=... // optional + * + * key2=myvaluexxx + * _key2.source=[etcd]http://127.0.0.1:4001 + * _key2.createdIndex=12 + * + * key3=val3 + * _key3.source=[etcd]http://127.0.0.1:4001 + * _key3.createdIndex=12 + * _key3.modifiedIndex=2 + * </pre> + */ + public Map<String,String> getProperties(String directory, boolean recursive); + +} +----------------------------------------------- + + +=== The EtcdPropertySource + +The +EtcdPropertySource+ is automatically registered and allows to configure the etcd servers to be used. 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 etcd cluster: + +* The property source reads the +tamaya.etcd.server.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:4001+ is used. If no connection to any etcd + server can be established a warning will be logged, but deployment will not fail. +* Additinoally also the + accessor allows to configure the socket/connection timeouts by setting +tamaya.etcd.timeout+ in seconds either as + system or environment property. +* The +EtcdPropertySource+ finally also allows the values read from the etcd cluster to be mapped to prefixed + context. This can be activated by setting the +-Dtamaya.etcd.prefix=<PREFIX>+ system property. E.g. when the prefix is + set to +cluster-config.+ a etcd 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/3d91bad5/content/extensions/mod_events.adoc ---------------------------------------------------------------------- diff --git a/content/extensions/mod_events.adoc b/content/extensions/mod_events.adoc new file mode 100644 index 0000000..30da423 --- /dev/null +++ b/content/extensions/mod_events.adoc @@ -0,0 +1,372 @@ +// 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. + += Apache Tamaya -- Extension: Events +:jbake-type: page +:jbake-status: published + +toc::[] + + +[[Core]] +== Tamaya Events (Extension Module) +=== Overview + +Tamaya Events is an extension module. Refer to the link:modules.html[extensions documentation] for further details +about modules. + +Tamaya Events provides an abstraction for events like change events, when configuration has bee changed. + +=== Compatibility + +The module is based on Java 7, so it can be used with Java 7 and beyond. + +=== Installation + +To benefit from configuration event support you only must add the corresponding dependency to your module: + +[source, xml] +----------------------------------------------- +<dependency> + <groupId>org.apache.tamaya.ext</groupId> + <artifactId>tamaya-events</artifactId> + <version>{tamayaVersion}</version> +</dependency> +----------------------------------------------- + +=== Core Architecture + +The core of the module are the +ConfigEventListener+ interface and the +ConfigEvent+ class, which defines an abstraction +for event handling and observation: + +[source,java] +.ConfigEvent +-------------------------------------------- +public final interface ConfigEvent<T> { + + Class<T> getResourceType(); + T getResource(); + String getVersion(); + long getTimestamp(); +} + +// @FunctionalInterface +public interface ConfigEventListener { + + void onConfigEvent(ConfigEvent<?> event); + +} +-------------------------------------------- + +This mechanism can now be used to propagate configuration changes to all interested stakeholders. Hereby the payloed +can be basically arbitrary as long as it implements the +ConfigEvent+ interface. The next sections +give more details on the the provided event implementations and abstractions that are used to implement such +features. + + +=== Modelling Configuration Changes + +This module provides a serializable and thread-safe abstraction modlling a configuration change. A change hereby may +be + +* additional configuration entries +* removed configuration entries +* changes on entries + +This is also reflected in the +ChangeType+ enum + +[source,java] +------------------------------------------------------- +public enum ChangeType { + NEW, + DELETED, + UPDATED, +} +------------------------------------------------------- + +This enum type is used within the +ConfigurationChange+ class, which implements the event sent for a changed ++Configuration+: + +[source,java] +------------------------------------------------------- +public final class ConfigurationChange implements ConfigEvent<Configuration>, Serializable{ + + public static ConfigurationChange emptyChangeSet(Configuration configuration); + + @Override + public Configuration getResource(); + @Override + public Class<Configuration> getResourceType(); + @Override + public String getVersion(); + @Override + public long getTimestamp(); + @Override + public long getTimestamp(); + + // Event specific methods + + public Collection<PropertyChangeEvent> getChanges(); + public int getRemovedSize(); + public int getAddedSize(); + public int getUpdatedSize(); + + public boolean isKeyAffected(String key); + public boolean isRemoved(String key); + public boolean isAdded(String key); + public boolean isUpdated(String key); + public boolean containsKey(String key); + public boolean isEmpty(); +} + +------------------------------------------------------- + +New instances of this class hereby are created using a fluent builder: + +[source,java] +------------------------------------------------------- +Configuration config = ...; +ConfigurationChange change = ConfigurationChangeBuilder.of(config) + .addChange("MyKey", "newValue") + .removeKeys("myRemovedKey").build(); +------------------------------------------------------- + +Also it is possible to directly compare 2 instances of configurations to create a matching +ConfigurationChange+ +instance: + +[source,java] +Comparing 2 configurations +------------------------------------------------------- +Configuration config = ...; +Configuration changedConfig = ...; +ConfigurationChange change = ConfigurationChangeBuilder.of(config) + .addChanges(changedConfig).build(); +------------------------------------------------------- + +So a +ConfigurationChange+ allows you to evaluate the changes on a configuration. This allows you to listen to changes +and react in your client code as useful, once you encounter changes that are relevant to you, e.g. by reconfiguring +your component. Of course, your code has to register itself to listen for appropriate changes by implementing +a +ConfigEventListener+: + +[source,java] +.Implementing a ConfigChangeListener +------------------------------------------------------- +public final class MyConfigChangeListener implements ConfigChangeListener<ConfigurationChange>{ + + private Configuration config = ConfigurationProvider.getConfiguration(); + + public void onConfigEvent(ConfigEvent<?> event){ + if(event.getResourceTspe()==Configuration.class){ + if(event.getConfiguration()==config){ + // do something + } + } + } + +} +------------------------------------------------------- + +You can *register* your implementation in 2 ways: + +. Manually by calling +ConfigEventManager.addListener(new MyConfigChangeListener())+ +. Automatically by registering your listener using the +ServiceLoader+ under + +META-INF/services/org.apache.tamaya.events.ConfigEventListener+ + + +=== Modelling PropertySource Changes + +Beside that a whole configuration changes, also +PropertySource+ instance can change, e.g. by a configuration file +edited on the fly. This is similarly to a +ConfigurationChange+ reflected by the classes +PropertySourceChange, +PropertySourceChangeBuilder+. + + +=== Modelling Configuration Context Changes + +The +ConfigurationContext+ models the container that manages all subcomponents that are used to define and +evalaute a +Configuration+. In the case where configuration is dynamically loaded, e.g. by observing changes on a +file folder, the +ConfigurationContext+ may change, so a corresponding +ConfigurationContextChange+ event is +defined: + +[source,java] +------------------------------------------------------- +public final class ConfigurationContextChange implements ConfigEvent<ConfigurationContext>, Serializable{ + + public static ConfigurationContextChange emptyChangeSet(); + + @Override + public ConfigurationContext getResource(); + @Override + public Class<ConfigurationContext> getResourceType(); + @Override + public String getVersion(); + @Override + public long getTimestamp(); + + // specific methods + public Collection<PropertySourceChange> getPropertySourceChanges(); + public Collection<PropertySourceChange> getPropertySourceUpdates(); + public Collection<PropertySource> getRemovedPropertySources(); + public Collection<PropertySource> getAddedPropertySources(); + public Collection<PropertySource> getUpdatedPropertySources(); + public boolean isAffected(PropertySource propertySource); + public boolean isEmpty(); +} +------------------------------------------------------- + +Similar to the +ConfigurationChange+ class you also must use a +ConfigurationContextChangeBuilder+ to create instances +of +ConfigurationContextChange+. + +=== The ConfigEventManager Singleton + +Main entry point of the events module is the +ConfigEventManager+ singleton class, which provides static accessor +methods to the extension's functionality: + +[source,java] +------------------------------------------------------- +public final class ConfigEventManager { + + private ConfigEventManager() {} + + public static void addListener(ConfigEventListener l); + public static <T extends ConfigEvent> void addListener(ConfigEventListener l, Class<T> eventType); + public static void removeListener(ConfigEventListener l); + public static <T extends ConfigEvent> void removeListener(ConfigEventListener l, Class<T> eventType); + public static <T extends ConfigEvent> + Collection<? extends ConfigEventListener> getListeners(); + public static <T extends ConfigEvent> + Collection<? extends ConfigEventListener> getListeners(Class<T> type); + + public static <T> void fireEvent(ConfigEvent<?> event); + public static <T> void fireEventAsynch(ConfigEvent<?> event); + + public static void enableChangeMonitoring(boolean enable); + public static boolean isChangeMonitoring(); + public long getChangeMonitoringPeriod(); + public void setChangeMonitoringPeriod(long millis); + +} +------------------------------------------------------- + +Looking at the methods listed above you see that there is more functionality worth to be mentioned: + +* +ConfigCHangeListeners+ can be registered either _globally_ or for a certain _event type_ only. +* +ConfigEvents+ can be published within the same thread, or asynchronously. + + +==== Monitoring of configuration changes + +The +ConfigEventManager+ also supports active monitoring of the current configuration to trigger corresponding change +events to listeners registered. This feature is activated by default, but can be deactivated optionally. Nevertheless +this feature is quite handy, since regularly polling your local +Configuration+ for any kind of changes is much +more simpler than implementing change management on the +PropertySource+ level. With this feature you can easily +implement also remote property source, which can deliver different configuration based on any changes done remotedly +on another node in your system. If such a change happened Tamaya identifies it and triggers corresponding ++ConfigurationChange" events automatically. Similarly changes in a configuration tree, can actively identified and +broadcasted to the targeting nodes automatically. + + +=== Freezing Configurations and PropertySources + ++Configuration+ instances as well as +PropertySources+ are explicitly not required to be serializable. To enable easy +serialization of these types as well as to fix a current state (e.g. for later comparison with a newly loaded instance) +Tamaya allows to *freeze* instances of these types. Freezing hereby means + +* all key/values are read-out by calling the +getProperties()+ method. +* a meta data entry is added of the form +[meta]frozenAt=223273777652325677+, whichdefines the UTC timestamp in + milliseconds when this instance was frozen. + +In code this is done easily as follows: + +[source,java] +.Freezing the current Configuration +-------------------------------------------------- +Configuration frozenConfig = FrozenConfiguration.of(ConfigurationProvider.getConfiguration()); +-------------------------------------------------- + +... and similarly for a +PropertySource+: + +[source,java] +.Freezing the current Configuration +-------------------------------------------------- +PropertySource frozenSource = FrozenPropertySource.of(ConfigurationProvider.getConfiguration()); +-------------------------------------------------- + + +=== Modelling of an observing PropertySourceProvider. + +In Tamaya configuration data is provided by instances of +PropertySource+, which in case of a configuration directory +may be provided by an implementation of +PropertySourceProvider+, which produces one +PropertySource+ (at least) per +file detected. The events module provides a base provider implementation that + +* observes all changes in a +Path+ +* tries to reevaluate corresponding resources based on the +ConfigurationFormats+ supported. +* it creates an instance of +ConfigurationContextChange+ reflecting the changed +ConfigurationContext+ and triggers + this event by calling +ConfigEventManager.fireEvent(contextChange);+. + +Additionally this module registers an instance of +ConfigEventListener<ConfigurationContextChange+>+, which listenes to +these events. If such an event is triggered the listener tries to apply the changes by + +. accessing the current +Configuration+ and its +ConfigurationContext+ +. checking if the event is affecting the current +ConfigurationContext+. +. in the case the current context is affected, based on the current +ConfigurationContext+ a new context is created, + whereas + .. all +PropertySources+ provided by this provider implementation type are removed. + .. the new +PropertySources+ loaded are added. +. Finally the listener tries to apply the new +ConfigurationContext+ by calling the corresponding API methods of the + +ConfigurationProvider+: + +[source,java] +-------------------------------------------------- +try { + ConfigurationProvider.setConfigurationContext(newContext); +} catch (Exception e) { + LOG.log(Level.INFO, "Failed to update the current ConfigurationContext due to config model changes", e); +} +-------------------------------------------------- + +So if the current +ConfigurationProvider+ supports reloading of the current +ConfigurationContext+ this will apply the +changes to the current +Configuration+. Otherwise the change is logged, but no further actions are taken. + + +=== SPIs + +This component also defines an additional SPI, which allows to adapt the implementation of the main +ConfigEventManager+ +singleton. This enables, for example, using external eventing systems, such as CDI, instead of the default provided +simple SE based implementation. As normal, implementation mus be registered using the current +ServiceContext+ +active, by default using the Java +ServiceLoader+ mechanism. + +[source,java] +.SPI: ConfigEventSpi +-------------------------------------------------- +public interface ConfigEventManagerSpi { + + <T> void addListener(ConfigEventListener l); + <T extends ConfigEvent> void addListener(ConfigEventListener l, Class<T> eventType); + void removeListener(ConfigEventListener l); + <T extends ConfigEvent> void removeListener(ConfigEventListener l, Class<T> eventType); + Collection<? extends ConfigEventListener> getListeners(); + Collection<? extends ConfigEventListener> getListeners(Class<? extends ConfigEvent> eventType); + + void fireEvent(ConfigEvent<?> event); + void fireEventAsynch(ConfigEvent<?> event); + + long getChangeMonitoringPeriod(); + void setChangeMonitoringPeriod(long millis); + boolean isChangeMonitorActive(); + void enableChangeMonitor(boolean enable); +} +-------------------------------------------------- http://git-wip-us.apache.org/repos/asf/incubator-tamaya-site/blob/3d91bad5/content/extensions/mod_filter.adoc ---------------------------------------------------------------------- diff --git a/content/extensions/mod_filter.adoc b/content/extensions/mod_filter.adoc new file mode 100644 index 0000000..30c950d --- /dev/null +++ b/content/extensions/mod_filter.adoc @@ -0,0 +1,135 @@ +// 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. + += Apache Tamaya -- Extension: Integration with etcd (Core OS) +:jbake-type: page +:jbake-status: published + +toc::[] + + +[[Optional]] +== COnfiguration Filtering (Extension Module) +=== Overview + +The Tamaya filter module provides a simple singleton accessor that allows to explicitly add +PropertyFilter+ instances +active on the current thread only. This can be very useful in many scenarios. Additionally this module adds +standard filters that hide metadata entries when the full configuration map is accessed. When keys are accessed +explcitily no filtering is applied and everything is visible. + +=== 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-filter</artifactId> + <version>{tamayaVersion}</version> +</dependency> +----------------------------------------------- + + +=== The Extensions Provided + +Tamaya Filter comes basically with 1 artifact: + +* The +org.apache.tamaya.filter.ConfigurationFilter+ provides several static methods to register +PropertyFilter+ +instances on the current thread. +* The +org.apache.tamaya.filter.DefaultMetdataFilter+ is a +PropertyFilter+ with hides all entries starting with + an underscore ('_'), when a full property map is accessed. + + +=== The ConfigurationFilter + +The accessor mentioned implements the API for for adding 1PropertyFilters+ to the current thread (as thread local): + +[source, java] +----------------------------------------------- +public final class ConfigurationFilter implements PropertyFilter{ + + ... + + /** + * Seactivates metadata filtering also on global map access for this thread. + * @see #clearFilters() + * @param active true,to enable metadata filtering (default). + */ + public static void setMetadataFilter(boolean active); + + /** + * Access the filtering configuration that is used for filtering single property values accessed. + * @return the filtering config, never null. + */ + public static ProgrammableFilter getSingleFilters(); + + /** + * Access the filtering configuration that is used for filtering configuration properties accessed as full + * map. + * @return the filtering config, never null. + */ + public static ProgrammableFilter getMapFilters(); + + /** + * Removes all programmable filters active on the current thread. + */ + public static void clearFilters(); + + ... + +} +----------------------------------------------- + +For using regular expression when filtering configuration keys a corresponding implementation of a +PropertyFilter+ +is part of this module, So you can add a customized filter as follows: + +[source, java] +----------------------------------------------- +try{ + ConfigurationFilter.getMapFilters().addFilter(new RegexPropertyFilter("\\_.*")); + + // do your code with filtering active +} +finally{ + // cleanup + ConfigurationFilter.clearFilters(); +} +----------------------------------------------- + +The +ProgrammableFilter+ is a simple structure just providing some handy accessors to the dynamic thread-local +managed filters: + +[source, java] +----------------------------------------------- +public final class ProgrammableFilter implements PropertyFilter{ + + public void addFilter(PropertyFilter filter); + public void addFilter(int pos, PropertyFilter filter); + public PropertyFilter removeFilter(int pos); + public void clearFilters(); + public void setFilters(PropertyFilter... filters); + public void setFilters(Collection<PropertyFilter> filters); + public List<PropertyFilter> getFilters(); + +} +----------------------------------------------- http://git-wip-us.apache.org/repos/asf/incubator-tamaya-site/blob/3d91bad5/content/extensions/mod_formats.adoc ---------------------------------------------------------------------- diff --git a/content/extensions/mod_formats.adoc b/content/extensions/mod_formats.adoc new file mode 100644 index 0000000..1cd1679 --- /dev/null +++ b/content/extensions/mod_formats.adoc @@ -0,0 +1,243 @@ +// 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. + += Apache Tamaya -- Extension: Formats +:jbake-type: page +:jbake-status: published + +toc::[] + + +[[Core]] +== Tamaya Formats (Extension Module) +=== Overview + +Tamaya Formats is an extension module. Refer to the link:modules.html[extensions documentation] for further details. + +Tamaya Formats provides an abstraction for configuration formats provding the following benefits: + +* Parsing of resources in can be implemented separately from interpreting the different aspects/parts parsed. As an + example a file format can define different sections. Depending on the company specific semantics of the sections + a different set of +PropertySource+ instances must be created. +* Similarly the configuration abstraction can also be used as an interface for integrating Tamaya with alternate + frameworks that provide logic for reading configuration files, such as Apache commons.configuration. + +=== Compatibility + +The module is based on Java 7, so it can be used with Java 7 and beyond. + +=== Installation + +To benefit from dynamic value resolution you only must add the corresponding dependency to your module: + +[source, xml] +----------------------------------------------- +<dependency> + <groupId>org.apache.tamaya.ext</groupId> + <artifactId>tamaya-formats</artifactId> + <version>{tamayaVersion}</version> +</dependency> +----------------------------------------------- + +The module automatically registers an according +PropertyFilter+ that is automatically called, whenever a value +is accessed. + +=== The Idea + +Formats should be reusable, meaning you should have to write a format parser only once and then be able to map the data read into whatever +data structure (in our cases: property sources). + +==== ConfigurationData + +Configuration formats can be very different. Some are simpley key/value pairs, whereas other also consist of multiple sections (e.g. ini-files) or +hierarchical data (e.g. yaml, xml). This is solved in Tamaya by mapping the configuration read into a normalized intermediary format called ++ConfigurationData+: + +[source,java] +.ConfigurationData +------------------------------------------------------- +public final class ConfigurationData { + + public ConfigurationFormat getFormat(); + public String getResource(); + + public Set<String> getSectionNames(); + public Map<String,String> getSection(String name); + public Map<String,Map<String,String>> getSections(); + + public boolean hasDefaultProperties(); + public Map<String,String> getDefaultProperties(); + + public Map<String,String> getCombinedProperties(); + public boolean hasCombinedProperties(); + + public boolean isEmpty(); +} +------------------------------------------------------- + +In detail the data read from a file is organized into _sections_ as follows: + +* with +getResource()+ and +getFormat()+ the underlying resource and the format that read this data can be accessed. +* properties can be owned by + ** named sections + ** an (unnamed) default section +* each section section contains a map of properties. Hereby the same key can be part of the default section and multiple + named sections, depending on the configuration format. +* The method +getSectionNames()+ returns a set of all section names. +* With +getSection(String name)+ a named section can be accessed. +* With +getDefaultSection()+ the default section can be accessed. +* With +getCombinedProperties()+ a flattened entry map can be accessed built up (by default) out of + ** all entries from the default section, without any changes. + ** all entries from named sections, where the key for each entry is prefix with the section name and a dot separator. +* The configuration format used determines the mapping of configuration data read into this structure. The format + implementation can as well provide alternate implementations of how the data read should be mapped into the + combined properties map. + +Now for the conversion of +ConfigurationData+ into a +PropertySource+ different default approaches are used: + +. The +ConfigurationFormat+ that read the data can provide the (combined) properties accessible from + +getProperties()+ explcitly, which can be used to initialize a single +PropertySource+ containing the data read. +. If the format did not set the final properties, but only a default section is present this default section + can be directly returned as combined properties. +. In all other cases a properties can be uniquely mapped into one single properties Map, by prefixing all keys of each + section present with the (unique) section name and a '.' separator. + +Nevertheless, depending on the context, where a configuration source was read (classloader, time, source etc.) the +resulting +PropertySource+ can have different semnatics, especially for the +PropertySources+ ordinal. Also section +names may be mapped into different ordinals instead of using them as key prefixes (e.g. imagine configuration formats +with a 'default', 'main', and 'overrides' sections). For such more complex or custom cases no useful default mapping +can be defined. In such cases this functionality must be implemented in a _mapData_ method, which converts +the normalized +ConfigData+ read to the appropriate collection of +PropertySource+ instances: + + +==== ConfigurationFormat + +A ConfigurationFormat is basically an abstraction that reads a configuration resource (modelled by an InputStream) and +creates a corresponding +ConfigurationData+ instance. + +[source,java] +------------------------------------------------------- +public interface ConfigurationFormat { + + public String getName(); + boolean accepts(URL url); + ConfigurationData readConfiguration(String resource, InputStream inputStream); +} +------------------------------------------------------- + + +Normally you need to map the resulting +ConfigurationData+ to one or multiple +PropertySources+. In case, where the +properties provided match exactly the extected properties a +FlattenedDefaultPropertySource+ is provided out-of-the-box. +If the exact mapping must be overridden, you can simply override the property source's initialize method to adapt the +mapping: + +[source,java] +------------------------------------------------------- +ConfigurationData data = ...; +FlattenedDefaultPropertySource ps = new FlattenedDefaultPropertySource(data){ + protected Map<String, String> populateData(ConfigurationData data) { + ... + } +}; +------------------------------------------------------- + + +=== How to tranform ConfigurationData into a PropertySource + +The Tamaya main building block for configuration properties is the +PropertySource+ interface. You have several +options to implement this tranformation: + +. You can simply map the properties returned by +getCombinedProperties()+ and use them as properties returned by a + wrapping property source. Since this use case is common for all kind of non hierarchic configuration formats it + is directly supported by the +FlattenedDefaultPropertySource+ class. +. When the +ConfigurationFormat+ is more complex, multiple 'sections' are common. What a section exactly is depends on + the concrete format only. The +ConfigurationFormat+ should provide detailed information how the data read is + mapped to default properties and sections and how it is assembled into the +combinedProperties+ map. Also here + the +FlattenedDefaultPropertySource+ class can help you with its default mapping. Nevertheless in some cases it is + necessary to write an explicit mapping, e.g. when + . different sections must be mapped to multiple +PropertySources+, with optionally fixed ordinals. + . sections must be cross-checked and combined into new properties, or into several +PropertySources+. + . other complex mapping requirements apply. + +=== Examples + +==== Mapping ini-Files + +Consider the following ini-file: + +[source,listing] +.Example.ini +------------------------------------------------------- +a=valA +a.b=valB + +[section1] +aa=sectionValA +aa.b.c=SectionValC + +[section2] +a=val2Section2 +------------------------------------------------------- + +This file content coud be mapped to the following structure: + +[source,listing] +.Mapping of Example.ini +------------------------------------------------------- +a=valA +a.b=valB +section1.valA=sectionValA +section1.a.b.c=SectionValC +section2.a=val2Section2 +------------------------------------------------------- + +Nevertheless from the +ConfigurationData+ instance a more complex algorithm can access all the different parts: + +* the_default_ properties (a, a.b) +* the section +section1+, with properties +aa, aa.b.c+ +* the section +section2+, qith properties +a+ + + +==== Mapping xml-Files + +The same concept can also be applied to xml-files. Consider the following configuration file: + +[source,xml] +.Example.conf +------------------------------------------------------- +<config> + <default> + <a>valA</a> + <a.b>valB</a.B> + </default> + + <section id="section1"> + <param id="aa">sectionValA</aa> + <param id="aa.b.c">SectionValC</aa.b.c> + </section> + <section id="section2"> + <param id="a">val2Section2</aa> + </section> +</config> +------------------------------------------------------- + +This file basically describes the same configuration as the ini-based version we have seen before. The formats +module hereby ships with 3 format classes: + +* +PropertiesFormat+ providing support for .properties files. +* +PropertiesXmlFormat+ providing support for xml.property files. +* +IniConfiguratonFormat+ providing support for xml.property files. http://git-wip-us.apache.org/repos/asf/incubator-tamaya-site/blob/3d91bad5/content/extensions/mod_functions.adoc ---------------------------------------------------------------------- diff --git a/content/extensions/mod_functions.adoc b/content/extensions/mod_functions.adoc new file mode 100644 index 0000000..a7e891c --- /dev/null +++ b/content/extensions/mod_functions.adoc @@ -0,0 +1,124 @@ +// 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. + += Apache Tamaya -- Extension: Functions +:jbake-type: page +:jbake-status: published + +toc::[] + +[[Core]] +== Tamaya Functions (Extension Module) +=== Overview + +Tamaya Functions is an extension module. Refer to the link:modules.html[extensions documentation] for further details. + +Tamaya Functions provides several functional extensions using the +ConfigOperator,ConfigQuery+ extension points. Most +functional extension are accessible from the +ConfigurationFunction+ singleton. When importing its methods statically +one can use the methods to achieve some interesting effects, e.g. + +[source,java] +------------------------------------------------------------------- +import static org.apache.tamaya.functions.ConfigurationFunctions.*; + +Set<String> sections = ConfigurationProvider.getConfiguration().with(areas("a", false).with(transitiveAreas()); +------------------------------------------------------------------- + +The expression above returns all fully qualified section names that are child sections of the root section 'a'. +So given the entries +a.b.entry1, a.b.entry2, a.a.entry3, a.b.c.entry4+ the reult would be +a, a.a, a.b, a.b.c+. + +=== Compatibility + +The module is based on Java 7, so it can be used with Java 7 and beyond. + +=== Installation + +For using the functionality shown in this document you only must add the corresponding dependency to your module: + +[source, xml] +----------------------------------------------- +<dependency> + <groupId>org.apache.tamaya.ext</groupId> + <artifactId>tamaya-functions</artifactId> + <version>{tamayaVersion}</version> +</dependency> +----------------------------------------------- + + +=== The Provided Functions + +==== Functions on +ConfigurationFunctions+ + +The following sections explain the provided functions defined by +ConfigurationFunctions+ singleton. + +* *ConfigOperator filter(PropertyMatcher matcher)* creates a +ConfigOperator+ that creates a +Configuration+ + containing only keys that are selected by the given _matcher predicate_. The +PropertyMatcher+ hereby allows to evaluate not only + the _key_, but also the _value_. +* *ConfigOperator map(KeyMapper keyMapper)* creates a +ConfigOperator+ that maps the keys as defined + by the given _keyMapper_. +* *ConfigOperator section(String section)* creates a +ConfigOperator+ that creates a +Configuration+ containing only + entries that are direct or indirect members of the given section. +* *ConfigOperator section(String areaKey, boolean stripKeys)* creates a +ConfigOperator+ that creates a +Configuration+ + containing only entries that are direct or indirect members of the given section. Hereby _stripKeys_ allows to determine + if the returned entries should be relative to the search criteria {{stripKeys=true}} or absolute keys. +* *isKeyInSection(String section, String sectionKey)* allows to easily determine if a given _key_ is a direct or indirect member + of a given section. +* *boolean isKeyInSections(String key, String... sectionKeys)* allows to easily determine if one key of given + _key_ is a direct or indirect member of at least one of the given _sectionKeys_. +* *ConfigQuery<Set<String>> sections()* allows to query all the contained fully qualified section names (the ones that + also have parameters present). +* *ConfigQuery<Set<String>> transitiveSections()* allows to query all the contained fully qualified section names, + including the transitive closure of sections. +* *ConfigQuery<Set<String>> sections(final Predicate<String> predicate)* allows to query all the contained fully + qualified section names that are selected by the given _predicate_. +* *ConfigQuery<Set<String>> sections(final Predicate<String> predicate)* allows to query all the contained fully + qualified section names that are selected by the given _predicate_, including the transitive closure of sections + identified. +* *ConfigOperator sectionsRecursive(String... sectionKeys)* provides a +ConfigOperator+ that filters all sections identified + by the given _sectionKeys_ and its child sections. +* *ConfigOperator sectionRecursive(final boolean stripKeys, final String... sectionKeys)* provides a +ConfigOperator+ + that filters all sections identified by the given _sectionKeys_ and its child sections. _stripKeys_ allows to + determine if the resulting configuration should be relative to the selected areas ({{stripKeys=true}}) or + absolute (filtering only). +* *ConfigQuery<String> jsonInfo()* returns a query that converts a +Configuration+ into a JSON formatted +String+ + representation. + + +==== Functions on +PropertySourceFunctions+ + +The following sections explain the provided functions defined by +PropertySourceFunctions+ singleton. + +* *PropertySource addMetaData(PropertySource propertySource, Map<String,String> metaData)* Creates a new +PropertySource+ + with the given metadata added. +* *boolean isKeyInSection(String key, String sectionKey)* Checks if the given _key_ is a direct or indirect member of + one of the given _sectionKey_. +* *boolean isKeyInSections(String key, String... sectionKeys)* Checks if the given _key_ is a direct or indirect member of + one of one of the given _sectionKeys_. +* *Set<String> sections(Map<String, String> properties)* Extracts the sections from the given properties. +* *Set<String> transitiveSections(Map<String, String> properties)* Extracts the transitive sections from the given + properties. +* *Set<String> sections(Map<String, String> properties, final Predicate<String> predicate)* Extracts the sections + from the given properties, also filtering with the given predicate. +* *Set<String> transitiveSections(Map<String, String> properties, Predicate<String> predicate)* Extracts the transitive + sections from the given properties, also filtering with the given predicate. +* *Map<String,String> sectionsRecursive(Map<String, String> properties, String... sectionKeys)* Creates w +PropertySource+ + only containing the sections that a direct or indirect children of the given _sectionKeys_. +* *Map<String,String> sectionRecursive(Map<String, String> properties, boolean stripKeys, String... sectionKeys)* Creates w +PropertySource+ + only containing the sections that a direct or indirect children of the given _sectionKeys_. With _stripKeys_ one can + select of the returned values should be relative to its selection of be fully qualified. +* *String stripSectionKeys(String key, String... sectionKeys)* This function strips away the matching section key as given + in _sectionKeys_ from a given _key_.
