http://git-wip-us.apache.org/repos/asf/incubator-tamaya-site/blob/ede865e4/content/documentation/extensions/mod_etcd.adoc ---------------------------------------------------------------------- diff --git a/content/documentation/extensions/mod_etcd.adoc b/content/documentation/extensions/mod_etcd.adoc new file mode 100644 index 0000000..149d843 --- /dev/null +++ b/content/documentation/extensions/mod_etcd.adoc @@ -0,0 +1,189 @@ +:jbake-type: page +:jbake-status: published + += Apache Tamaya -- Extension: Integration with etcd (Core OS) + +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>{tamaya_version}</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/ede865e4/content/documentation/extensions/mod_events.adoc ---------------------------------------------------------------------- diff --git a/content/documentation/extensions/mod_events.adoc b/content/documentation/extensions/mod_events.adoc new file mode 100644 index 0000000..c0a3809 --- /dev/null +++ b/content/documentation/extensions/mod_events.adoc @@ -0,0 +1,278 @@ +:jbake-type: page +:jbake-status: published + += Apache Tamaya -- Extension: Events + +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 been 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>{tamaya_version}</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 payload +can be basically arbitrary as long as it implements the +ConfigEvent+ interface. The next sections +give more details on the the provided event types and their usage. + + +=== 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 + + +The most important event modelled is 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(); + + // 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 can be 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 +ConfigurationChange+ that +reflect the differences between the two configurations: + +[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. For listening to configuration changes you must implement the ++ConfigEventListener+ functional interface: + +[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+ instances can change, e.g. by a configuration file +edited on the fly. This is similarly to a +ConfigurationChange+ reflected by the classes +PropertySourceChange, +PropertySourceChangeBuilder+. + + +=== 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: + +* Adding/removing of +ConfigChangeListener+ instances, either globally or per event type. +* Firing configuration events synchronously or asyncronously (mostly called by framework code). +* Configuring the monitor that periodically checks for changes on the global +Configuration+ provided + by +ConfigurationProvider.getConfiguration()+. + +[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); + +} +------------------------------------------------------- + + +==== 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 deactivated by default, but can be enabled by calling ++ConfigEventManager.enableChangeMonitoring(true);+. This feature avoids regularly polling your local +Configuration+ for +any kind of changes. If a change has been encountered Tamaya identifies it and triggers corresponding ++ConfigurationChange+ events 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 a +Configuration+'s *current state can be frozen* (e.g. for later comparison with a newly +loaded version). Freezing hereby means + +* all key/values are read-out by calling the +getProperties()+ method. +* a meta data entry is added of the form +_frozenAt=223273777652325677+, whichdefines the UTC timestamp in + milliseconds when this instance was frozen. +* if not already defined an +_id+ property will be added to the +Configuration+ containing the + identifier of the configuration. + +In code freezing is a no-brainer: + +[source,java] +.Freezing the current Configuration +-------------------------------------------------- +Configuration config = ConfigurationProvider.getConfiguration(); +Configuration frozenConfig = FrozenConfiguration.of(config); +-------------------------------------------------- + +... and similarly for a +PropertySource+: + +[source,java] +.Freezing the current Configuration +-------------------------------------------------- +PropertySource propertySource = ...; +PropertySource frozenSource = FrozenPropertySource.of(propertySource); +-------------------------------------------------- + + + +=== 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 must 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); +} +-------------------------------------------------- + + +Summarizing with the events module you can easily observe configuration changes, record the +state of any configuration and compare configuration states to create and publish related +change events. http://git-wip-us.apache.org/repos/asf/incubator-tamaya-site/blob/ede865e4/content/documentation/extensions/mod_filter.adoc ---------------------------------------------------------------------- diff --git a/content/documentation/extensions/mod_filter.adoc b/content/documentation/extensions/mod_filter.adoc new file mode 100644 index 0000000..670faa0 --- /dev/null +++ b/content/documentation/extensions/mod_filter.adoc @@ -0,0 +1,119 @@ +:jbake-type: page +:jbake-status: published + += Apache Tamaya -- Extension: User Filtering + +toc::[] + + +[[Optional]] +== User 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 +explicitily 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>{tamaya_version}</version> +</dependency> +----------------------------------------------- + + +=== The Extensions Provided + +Tamaya Filter comes basically with 3 artifacts: + +* 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 +PropertyFilters+ 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 setFilterMetadata(boolean active); + + /** + * Access the filtering configuration that is used for filtering single property values accessed. + * @return the filtering config, never null. + */ + public static FilterContext getSingleFilterContext(); + + /** + * Access the filtering configuration that is used for filtering configuration properties accessed as full + * map. + * @return the filtering config, never null. + */ + public static FilterContext 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 myFilter()); + + // do your code with filtering active +} +finally { + // cleanup + ConfigurationFilter.clearFilters(); +} +----------------------------------------------- + +The +FilterContext+ is a simple structure just providing some handy accessors to the dynamic thread-local +managed filters: + +[source, java] +----------------------------------------------- +public final class FilterContext implements PropertyFilter { + + public void addIncludes(PropertyFilter filter); + public void addExcludes(int pos, PropertyFilter filter); + public PropertyFilter removeFilter(int pos); + public void clearFilters(); + public void setIncludes(PropertyFilter... filters); + public void setExcludes(Collection<PropertyFilter> filters); + public List<PropertyFilter> getFilters(); + +} +----------------------------------------------- http://git-wip-us.apache.org/repos/asf/incubator-tamaya-site/blob/ede865e4/content/documentation/extensions/mod_formats.adoc ---------------------------------------------------------------------- diff --git a/content/documentation/extensions/mod_formats.adoc b/content/documentation/extensions/mod_formats.adoc new file mode 100644 index 0000000..401a755 --- /dev/null +++ b/content/documentation/extensions/mod_formats.adoc @@ -0,0 +1,206 @@ +:jbake-type: page +:jbake-status: published + += Apache Tamaya -- Extension: Formats + +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>{tamaya_version}</version> +</dependency> +----------------------------------------------- + + +=== 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 simple 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 boolean hasDefaultProperties(); + public Map<String,String> getDefaultProperties(); + public Map<String,String> getCombinedProperties(); + + 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. This is a convenience method. +* 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 '::' 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. + + +==== 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 { + + String getName(); + boolean accepts(URL url); + ConfigurationData readConfiguration(String resource, InputStream inputStream); +} +------------------------------------------------------- + + +=== How to tranform ConfigurationData into a PropertySource + +For for the conversion of +ConfigurationData+ into a +PropertySource+ different approaches can be useful: + +. The +ConfigurationFormat+ that reads the data can provides all properties read either as sectioned properties + or/and as default properties. The most simple cases is, where all properties have been added as 'default' + properties. In this case the default properties can be used as the property sources properties without any change. +. If the format did also add section based properties, the combined properties returned can be used, hereby + replacing the '::' separator with a '.' separator. +. In all other cases a custom mapping is useful, which can be acomplished by using the +MappedConfigurationDataPropertySource+ + and overriding the +Map<String,String> populateData(ConfigurationData data)+ method. + +In most cases the usage of a +FlattenedDefaultPropertySource+, is a good choice to start. This class +provides a convenient default mapping and also allows to customized the mapping easily: + +[source,java] +------------------------------------------------------- +ConfigurationData data = ...; +FlattenedDefaultPropertySource ps = new FlattenedDefaultPropertySource(data){ + protected Map<String, String> populateData(ConfigurationData data) { + ... + } +}; +------------------------------------------------------- + +Nevertheless, depending on the context, where a configuration source was read (classloader, time, source etc.) the +resulting properties can have different semnatics, especially different priorities. 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 simple mapping +can be defined. Consequently the functionality mapping the normalized +ConfigurationData+ read to the +appropriate collection of +PropertySource+ instances must be implemented. + + +=== 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/ede865e4/content/documentation/extensions/mod_functions.adoc ---------------------------------------------------------------------- diff --git a/content/documentation/extensions/mod_functions.adoc b/content/documentation/extensions/mod_functions.adoc new file mode 100644 index 0000000..6e2c172 --- /dev/null +++ b/content/documentation/extensions/mod_functions.adoc @@ -0,0 +1,108 @@ +:jbake-type: page +:jbake-status: published + += Apache Tamaya -- Extension: Functions + +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>{tamaya_version}</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_. http://git-wip-us.apache.org/repos/asf/incubator-tamaya-site/blob/ede865e4/content/documentation/extensions/mod_injection.adoc ---------------------------------------------------------------------- diff --git a/content/documentation/extensions/mod_injection.adoc b/content/documentation/extensions/mod_injection.adoc new file mode 100644 index 0000000..941351e --- /dev/null +++ b/content/documentation/extensions/mod_injection.adoc @@ -0,0 +1,430 @@ +:jbake-type: page +:jbake-status: published + += Apache Tamaya -- Extension: Injection + +toc::[] + + +[[Core]] +== Tamaya Injection (Extension Module) +=== Overview + +Tamaya Injection is an extension module. Refer to the link:modules.html[extensions documentation] for further details +about modules. + +Tamaya Injection provides functionality for injecting configured values into beans, or creating configuration +template instances. + +Inversion of Control (aka IoC/the Hollywood Principle) has proven to be very useful and effective in avoiding boilerplate +code. In Java there are different frameworks available that all provide IoC mechanisms. Unfortunately IoC is not a +built-in language feature. So for a portable solution that works also in Java SE Tamaya itself has to provide the +according injection services. This module adds this functionality to Tamaya. + +=== Compatibility + +The module is based on Java 7, so it can be used with Java 7 and beyond. + +=== Installation + +Basically Tamaya's injection API is deployed as API artifact: + +[source, xml] +----------------------------------------------- +<dependency> + <groupId>org.apache.tamaya.ext</groupId> + <artifactId>tamaya-injection-api</artifactId> + <version>{tamaya_version}</version> +</dependency> +----------------------------------------------- + +To use injection with Java SE you must add the corresponding dependency to your module: + +[source, xml] +----------------------------------------------- +<dependency> + <groupId>org.apache.tamaya.ext</groupId> + <artifactId>tamaya-injection</artifactId> + <version>{tamaya_version}</version> +</dependency> +----------------------------------------------- + +Similarly there are other injection implementations available, targetig platforms such as + +* Spring, Spring Boot +* Java EE/CDI +* OSGI, Apache Felix/Apache Karaf + + +=== Core Concepts + +Basically you annotate fields or methods in your beans with +@Config+ to enable configuration injection. Tamaya +additionally defines further annotations that allo you to define additional aspects such as default values, custom +converters etc. The following example illustrates the basic functionality: +code snippet: + +[source,java] +.Annotated Example Class +-------------------------------------------- +package foo.bar; + +public class ConfiguredClass { + + // resolved by default, using property name, class and package name: foo.bar.ConfiguredClass.testProperty + private String testProperty; + + // Trying to resolve mutiple keys, with a default value, if none could be resolved + @Config({"a.b.c.key1","a.b.legacyKey",area1.key2"}, defaultValue="The current \\${JAVA_HOME} env property is ${env:JAVA_HOME}.") + String value1; + + // Typical case + @Config("a.b.c.key2") + private int value2; + + // resolved by default as foo.bar.ConfiguredClass.accessUrl + // Using a (default) String -> URL converter + @Config(defaultValue="http://127.0.0.1:8080/res/api/v1/info.json") + private URL accessUrl; + + // Config injection disabled for this property + @NoConfig + private Integer int1; + + // Overriding the String -> BigDecimal converter with a custom implementation. + @Config("BD") + @WithPropertyConverter(MyBigDecimalRoundingAdapter.class) + private BigDecimal bigNumber; + + ... +} +-------------------------------------------- + + +When configuring data or configuration classes it is also possible to auto-inject the fields identified. For activating +this feature a class must be annotated with +@ConfigAutoInject+: + +[source, java] +. An autoinjected bean class +-------------------------------------------- +package a.b; + +@ConfigAutoInject +public final class Tenant { + private int id; + private String name; + private String description; + @NoConfig // prevents auto injection for this field + private String id2; + + public int getId(){ + return id; + } + public String getName(){ + return name; + } + public String getDescription(){ + return description; + } +} +-------------------------------------------- + +These examples do not show all possibilities provided. Configuring instance of these +class using Tamaya is very simple: Just pass the instance to Tamaya to let +Tamaya inject the configuration (or throw a +ConfigException+, if this is not possible): + +[source,java] +.Configuring the +ConfiguredClass+ Instance +-------------------------------------------- +ConfiguredClass classInstance = new ConfiguredClass(); +ConfigurationInjector.configure(configuredClass); + +Tenant tenant = new Tenant(); +ConfigurationInjector.configure(tenant); +-------------------------------------------- + +NOTE: Configuration injection works similarly, when used with other integration modules, e.g. when Tamaya is used +with CDI, Spring or within an OSGI container. For further details refer also to the corresponding integration module's +documentation. + + +=== The Annotations in detail +==== The ConfigurationInjector + +The +ConfigurationInjector+ interface provides methods that allow any kind of instances to be configured +by passing the instances to +T ConfigurationInjector.getInstance().configure(T);+. The classes passed +hereby must not be annotated with +@Config+ for being configurable. By default Tamaya +tries to determine configuration for each property of an instance passed, using the following resolution policy: + +Given a class +a.b.MyClass+ and a field +myField+ it would try to look up the following keys: +[source, listing] +-------------------------------------------- +a.b.MyClass.myField +a.b.MyClass.my-field +MyClass.myField +MyClass.my-field +myField +my-field +-------------------------------------------- + +So given the following properties: + +[source, properties] +-------------------------------------------- +a.b.Tenant.id=1234 +Tenant.description=Any kind of tenant. +name=<unnamed> +-------------------------------------------- + + +==== Accessing Supplier instances + +In many cases you want to create a supplier that simply creates instances that are correctly configured as defined +by the current context. This can be done using +Suppliers+: + +[source, java] +-------------------------------------------- +Supplier<Tenant> configuredTenantSupplier = ConfigurationInjector.getInstance().getConfiguredSupplier( + new Supplier<Tenant>(){ + public Tenant get(){ + return new Tenant(); + } +}); +-------------------------------------------- + +With Java 8 it's even more simple: + +[source, java] +-------------------------------------------- +Supplier<Tenant> configuredTenantSupplier = ConfigurationInjector.getInstance().getConfiguredSupplier( + Tenant::new); +-------------------------------------------- + +Hereby this annotation can be used in multiple ways and combined with other annotations such as ++@WithLoadPolicy+, +@WithConfigOperator+, +@WithPropertyConverter+. + +==== Minimal Example + +To illustrate the mechanism below the most simple variant of a configured class is given: + +[source,java] +.Most simple configured class +-------------------------------------------- +pubic class ConfiguredItem{ + @Config + private String aValue; +} +-------------------------------------------- + +When this class is configured, e.g. by passing it to +ConfigurationInjector.getInstance().configure(Object)+, +the following is happening: + +* The current valid +Configuration+ is evaluated by calling +Configuration cfg = ConfigurationProvider.getConfiguration();+ +* The current property value (String) is evaluated by calling +cfg.get("aValue");+ for each possible key (mutliple + keys are possible). +* if not successful, an error is thrown (+ConfigException+) +* On success, since no type conversion is involved, the value is injected. + +==== Using @DefaultValue + +In the next example we explicitly define the property value: +[source,java] +-------------------------------------------- +pubic class ConfiguredItem{ + + @Config(value={"aValue", "a.b.value","a.b.deprecated.value"}, defaultValue="${env:java.version}") + private String aValue; +} +-------------------------------------------- + +==== Inject a DynamicValue Property + +Within this example we evaluate a dynamic value. This mechanism allows you to listen for configuration changes and to +commit new values exactly, when convenient for you. + +[source,java] +-------------------------------------------- +pubic class ConfiguredItem{ + + @Config(value={"aValue", "a.b.value","a.b.deprecated.value"}, defaultValue="${env:java.version}") + private DynamicValue aValue; +} +-------------------------------------------- + +The +DynamicValue+ provides you the following functionality: + +[source,java] +-------------------------------------------- +public interface DynamicValue<T> { + + enum UpdatePolicy{ + IMMEDIATE, + EXPLCIT, + NEVER, + LOG_AND_DISCARD + } + + T get(); + T getNewValue(); + T evaluateValue(); + T commitAndGet(); + void commit(); + void discard(); + boolean updateValue(); + + void setUpdatePolicy(UpdatePolicy updatePolicy); + UpdatePolicy getUpdatePolicy(); + void addListener(PropertyChangeListener l); + void removeListener(PropertyChangeListener l); + + boolean isPresent(); + T orElse(T other); + // Enabled with Java 8 + // T orElseGet(ConfiguredItemSupplier<? extends T> other); + // <X extends Throwable> T orElseThrow(ConfiguredItemSupplier<? extends X> exceptionSupplier) throws X; + +} +-------------------------------------------- + +Summarizing this class looks somehow similar to the new +Optional+ class added with Java 8. It provides +a wrapper class around a configured instance. Additionally this class provides functionality that gives +active control, to manage a configured value based on a ++LoadingPolicy+: + +* +IMMEDEATE+ means that when the configuration system detects a change on the underlying value, the new value + is automatically applied without any further notice. +* +EXPLICIT+ means that a new configuration value is signalled by setting the +newValue+ property. if +getNewValue()+ + returns a non null value, the new value can be applied by calling +commit()+. You can always access the newest value, + hereby implicitly applying it, by accessing it via +commitAndGet()+. Also it is possible ti ignore a change by calling + +discard()+. +* +NEVER+ means the configured value is evaluated once and never updated. All changes are silently discarded. +* +LOG_AND_DISCARD+ similar to +NEVER+, but changes are logged before they are discarded. + +Summarizing a +DynamicValue+ allows you + +* to reload actively updates of configured values. +* update implicitly or explicitly all changes on the value. +* add listeners that observe changes of a certain value. + +Dynamic values also allow on-the-fly reevaluation of the value by calling +evaluateValue()+. Hereby the value of the +instance is not changed. + + +==== Ommitting Injection using @NoConfig + +Adding the @NoConfig annotation prevents a field or method to be auto-injected from +configuration. This is especially useful, if a type is annotated as @ConfigAutoInject with auto-confiuration +turned on as follows: + +[source,java] +-------------------------------------------- +@ConfigAutoInject +pubic class ConfiguredItem{ + + @NoConfig + private transient int sum; + + private String a; + private String b; + Private String c; +} +-------------------------------------------- + +In this case the fields +a,b,c+ are configured, whereas the field +sum+ is ignored regarding +configuration. + +==== Adding custom operators using @WithConfigOperator + +The @WithConfigOperator annotation allows you define a class of type +ConfigOperator+, to being applied +to the final +Configuration+, BEFORE the value is injected. This can be used for various use cases, e.g. +filtering or validating the visible properties for a certain use case. + +[source,java] +-------------------------------------------- + +@WithConfigOperator(MyConfigView.class) +pubic class ConfiguredItem{ + + @Config + private String a; + +} +-------------------------------------------- + + +==== Adding custom property converters using @WithPropertyConverter + +The @WithPropertyConverter annotation allows you to define a class of type +PropertyConverter+, to be applied +on a property configured to convert the String value to the expected injected type. This can be used for +various use cases, e.g. adding custom formats, config models, decryption. + +[source,java] +-------------------------------------------- + +pubic class ConfiguredItem{ + + @WithPropertyConverter(MyPropertyConverter.class) + @Config + private String a; + +} +-------------------------------------------- + + +==== Defining the loading policy to be applied to configured values using @WithLoadPolicy + +The @WithLoadPolicy annotation allows to define the loading behaviour to be applied. The +LoadPolicy+ +enum hereby defines the various loading modes. + +[source,java] +-------------------------------------------- + +@WithLoadPolicy(LoadPolicy.NEVER) +pubic class BootTimeStableConfig{ + + @WithPropertyConverter(MyPropertyConverter.class) + @Config + private String a; + +} +-------------------------------------------- + + +=== Configuration Events + +Similar to CDI Tamaya publishes Configuration events, when instances were configured. It depends on the effective +event backend in use, if and how events are published: + +* when you have the CDI extension active events are published using the default CDI event mechanism. +* in all other scenarios events are delegated to the +tamaya-events+ module, if available, +* if no event delegation is available no events are published. + +The event published is very simple: + +[source,java] +-------------------------------------------- +public interface ConfiguredType { + Class getType(); + String getName(); + Collection<ConfiguredField> getConfiguredFields(); + Collection<ConfiguredMethod> getConfiguredMethods(); + void configure(Object instance, Configuration config); +} + + +public interface ConfiguredField { + Class<?> getType(); + Collection<String> getConfiguredKeys(); + String getName(); + String getSignature(); + Field getAnnotatedField(); + void configure(Object instance, Configuration config); +} + +public interface ConfiguredMethod { + Collection<String> getConfiguredKeys(); + Class<?>[] getParameterTypes(); + Method getAnnotatedMethod(); + String getName(); + String getSignature(); + void configure(Object instance, Configuration config); +} +---------------------------------------- http://git-wip-us.apache.org/repos/asf/incubator-tamaya-site/blob/ede865e4/content/documentation/extensions/mod_jodatime.adoc ---------------------------------------------------------------------- diff --git a/content/documentation/extensions/mod_jodatime.adoc b/content/documentation/extensions/mod_jodatime.adoc new file mode 100644 index 0000000..4ebae7a --- /dev/null +++ b/content/documentation/extensions/mod_jodatime.adoc @@ -0,0 +1,48 @@ +:jbake-type: page +:jbake-status: published + += Apache Tamaya -- Extension: JodaTime + +toc::[] + +[[Core]] +== Tamaya JodaTime (Extension Module) + +=== Overview + +Tamaya JodaTime is an extension module to support the usage of http://www.joda.org/joda-time/[Joda-Time] +in conjunction with Tamaya. Tamaya JodaTime defines some additional property +converters to retrieve Joda-Time types from a given configuration. + +Refer to the link:modules.html[extensions documentation] for further details +about modules. + +tools to locate resources in your classpath or file system based on descriptive +ant-styled resource patterns. To use this module add the following dependency: + +[source, listing] +----------------------------------------------- +<dependency> + <grooupId>org.apache.tamaya.ext</groupId> + <artifactId>tamaya-jodatime</artifactId> + <version>{tamaya_version}</version> +</dependency> +----------------------------------------------- + +After adding this dependency to your project you can retrieve +Joda-Time based values directly from a given configuration. + +[source,java] +----------------------------------------------- +Configuration configuration = ConfigurationProvider.getConfiguration(); + +DateTime pit = configuration.get("pointInTime", DateTime.class) +----------------------------------------------- + +=== Specifying date and time values + +To be written. + +=== Specifing periods and durations + +To be written. http://git-wip-us.apache.org/repos/asf/incubator-tamaya-site/blob/ede865e4/content/documentation/extensions/mod_json.adoc ---------------------------------------------------------------------- diff --git a/content/documentation/extensions/mod_json.adoc b/content/documentation/extensions/mod_json.adoc new file mode 100644 index 0000000..66c12fa --- /dev/null +++ b/content/documentation/extensions/mod_json.adoc @@ -0,0 +1,62 @@ +:jbake-type: page +:jbake-status: published + += Apache Tamaya -- Extension: Builder + +toc::[] + + +[[BuilderCore]] +== Tamaya JSON (Extension Module) +=== Overview + +The Tamaya json module provides support for reading configuration using JSON format: + + +=== Compatibility + +The module is based on Java 7, so it will 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-json</artifactId> + <version>{tamaya_version}</version> +</dependency> +----------------------------------------------- + +This extension also transitively requires the +tamaya.formats+ module. + +=== Reading configuration in JSON + +For reading JSON based onfiguration most easily a +JSONFormat+ can be provided: + +[source, java] +----------------------------------------------- +ConfigurationData dataRead = ConfigurationFormats.readConfig( + getClassLoader().getResource("myFileConfig.json"), new JSONFormat())); +----------------------------------------------- + +=== Examples + +The JSON module adds instances of +ConfigurationFormat+ so JSON configuration can be read and mapped to the +according property maps. E.g. the following file is a simple and correct JSON configuration: + +[source,listing] +---------------------------------------------------------------- +{ + "a" : "A", + "b" : "B", + "c" : "C", + "d" : { + "o" : "O", + "p" : "P" + } +} +---------------------------------------------------------------- http://git-wip-us.apache.org/repos/asf/incubator-tamaya-site/blob/ede865e4/content/documentation/extensions/mod_management.adoc ---------------------------------------------------------------------- diff --git a/content/documentation/extensions/mod_management.adoc b/content/documentation/extensions/mod_management.adoc new file mode 100644 index 0000000..b912747 --- /dev/null +++ b/content/documentation/extensions/mod_management.adoc @@ -0,0 +1,92 @@ +:jbake-type: page +:jbake-status: published + += Apache Tamaya -- Extension: JMX Management Access + +toc::[] + + +[[ExtModel]] +== Tamaya Management (JMX Support) (Extension Module) +=== Overview + +The Tamaya management module provides support for registering a JMX management bean for accessing configuration. + +=== Compatibility + +The module is based on Java 7, so it will 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-management</artifactId> + <version>{tamaya_version}</version> +</dependency> +----------------------------------------------- + + +=== The ManagedConfigMBean bean + +The management model defines the MBean of type +ManagedConfigMBean+ as follows: + + +[source,java] +----------------------------------------------------------------------------- +public interface ManagedConfigMBean { + String getJsonConfigurationInfo(); + String getXmlConfigurationInfo(); + Map<String, String> getConfiguration(); + Map<String, String> getSection(String area, boolean recursive); + Set<String> getSections(); + Set<String> getTransitiveSections(); + boolean isSectionExisting(String area); + default boolean isSectionEmpty(String area); +} +----------------------------------------------------------------------------- + +* +getJsonConfigurationInfo,getXmlConfigurationInfo+ return a JSON or XML representation of the +current configuration. +* +getConfiguration+ access the current configuration properties. +* +getSection+ allows to extract all entries below a certain subkey. With _recursive_ the query + will not only return direct children, but also recursively walk down all subsection of the + given section key. +* +getSections+ returns all current known section names. +* +getTransitiveSections+ return all sections, but also adds all transitive subsection as single + entries to the set as well. +* +isSectionExisting+ and +isSectionEmpty+ allow for quering if entries are present under the given + section keys. + +=== Registering the ManagedConfigMBean + +For registering the current +ManagedConfigMBean+ instance to the current MBean platform server, the +following static methods are available: + +[source,java] +----------------------------------------------------------------------------- +public final class ConfigManagementSupport{ + + private JMXSupport(){} + + public static ObjectName registerMBean(); + public static ObjectName registerMBean(String context); + public static ObjectName unregisterMBean(); + public static ObjectName unregisterMBean(String context); +} +----------------------------------------------------------------------------- + +* +registerMBean+ creates a new +ManagedConfigMBean+ instance using the +ServiceContextManager+ + and registers it. Optionally an additional _context_ parameter can be passed, which allows + to register the management bean for different classloaders, e.g. for different + ears. +* +unregisterMBean+ does the oppsite than registering obviously. + +NOTE: The instance of +ManagedConfigMBean+ to be created and registered is evaluated by use og the + +ServiceContextManager+. So you can replace the bean implementation by registering your + overriding implementation using the current +ServiceContext+ (by default using + +java.util.ServiceLoader+ and +@Priority+ annotation. http://git-wip-us.apache.org/repos/asf/incubator-tamaya-site/blob/ede865e4/content/documentation/extensions/mod_metamodel-staged.adoc ---------------------------------------------------------------------- diff --git a/content/documentation/extensions/mod_metamodel-staged.adoc b/content/documentation/extensions/mod_metamodel-staged.adoc new file mode 100644 index 0000000..cf02806 --- /dev/null +++ b/content/documentation/extensions/mod_metamodel-staged.adoc @@ -0,0 +1,58 @@ +:jbake-type: page +:jbake-status: published + += Apache Tamaya -- Extension: Staged PropertySources + +toc::[] + + +[[Remote]] +== Tamaya Metamodel: Staged PropertySources (Extension Module) +=== Overview + +The Tamaya Staged PropertySources extension provides a base class and default implementation for loading +multistaged configuration easily from a common configuration location. + + +=== Compatibility + +The module is based on Java 7, so it will run on Java 7 and beyond. + + +=== Installation + +To benefit from Tamaya CDI integration you only must add the corresponding dependency to your module: + +[source, xml] +----------------------------------------------- +<dependency> + <groupId>org.apache.tamaya.ext.metamodels</groupId> + <artifactId>tamaya-metamodel.staged</artifactId> + <version>{tamaya_version}</version> +</dependency> +----------------------------------------------- + +The component will not register any components. The component basically provides the following options: + +* Use it as default configuration extension. Hereby you should define your stages in use by setting the + +env.STAGE+ system property with the stages to be loaded in order of precedence (most significant last), + e.g. +sys-env,DEFAULTS,TEST,DEVELOPMENT. _Additionally_ you must register + +org.apache.tamaya.staged.StagedConfigPropertiesProvider+ as in + +-------------------------------------------------------------- +META-INF +|_service + |_org.apache.tamaya.spi.PropertySourceProvider +-------------------------------------------------------------- + +Tamaya will then load .properties files from +System.getenv(), +classpath:DEFAULTS.properties, classpath:TEST.properties+ and ++classpath:DEVELOPMENT.properties+ + +* For more advanced requirements, such as alternate locations, patterns or formats, you can also extend one of the + provided classes (+org.apache.tamaya.staged.StagedConfigPropertiesProvider+, + ** +BaseStagedPropertySourceProvider+). Extending provides features such as: + + ** Defining a prefix for all entries provided/loaded. + ** Using alternate locations or formats. + ** Defining the ordinals used. http://git-wip-us.apache.org/repos/asf/incubator-tamaya-site/blob/ede865e4/content/documentation/extensions/mod_model.adoc ---------------------------------------------------------------------- diff --git a/content/documentation/extensions/mod_model.adoc b/content/documentation/extensions/mod_model.adoc new file mode 100644 index 0000000..e454eb1 --- /dev/null +++ b/content/documentation/extensions/mod_model.adoc @@ -0,0 +1,451 @@ +:jbake-type: page +:jbake-status: published + += Apache Tamaya -- Extension: Model Documentation and Validation + +toc::[] + + +[[ExtModel]] +== Tamaya Model Documentation and Validation (Extension Module) +=== Overview + +The Tamaya model module provides support for documenting configuration and validating configuration read and processed +against this model. Documentation and config models can be provided in different ways: + +* as separate meta-model documents +* by providers that check classes/packages for configuration annotations (planned) + + +=== 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-model</artifactId> + <version>{tamaya_version}</version> +</dependency> +----------------------------------------------- + + +=== Describing the Configuration Meta-Model + +Basically configuration is modelled using key, value-pairs. Looking at a keys ++a.b.c.param1+ and +a.b.c.param2+ the following concepts can be used to defined/describe +configuration: + +. the _configuration section:_ In our case this equals to +a.b.c+, which itself also includes the + transitive entries +a.b+ and +a+. +. the _configuration parameter:_ Basically parameters are adressed using their fully qualified names, + which equals to the containing section name and the relative parameter name, separated by the dor separator. + In the above example +a.b.c.param1+ and +a.b.c.param2+ are the fully qualified parameter names. + +Now with only these 2 concepts a simple configuration meta-model can be defined as + +* a meta-model's name, used just for grouping different meta-models and entries to better separate + descriptions, e.g. in a management console or generated configuration documentation site. +* a set of sections. +* a set of parameters. +* Both, sections (+.model.target=Section+) as well as parameter models (+.model.target=Parameter+) + ** can be modelled by a meta-data entry, by default +_my.config.key.model+. + ** may be required, or optional (+.model.required=true|false+) + ** may have an optional description +* Parameters additionally have + ** a _type_ (+.model.type=Classname+), described by the fully qualified class name, into which any configured (String) + value must be convertable into. If no type is configured +java.ui.lang.String+ is assumed as default. + ** an optional regular expression that can be used to validate the +String+ values returned from a + configuration (+.model.expression=regexpression+). + +Given these concepts a configuration can be fully described. Entries that are not contained in one of the given +sections (or its children), or parameters not described or marked as valid (e.g. for dynamic configModels of +a section), are called _undefined_. Undefined parameters should be grouped with its parent section. Each section, as +well as all parent sections, including transitive) of any parametet read, should similarly marked as undefined, if and +only if + +. the section itself is (directly) _undefined_ +. the section is not a _super section_ of a defined section. + +As en example the section definition of +a.b.c+ also implicitly includes the sections +a.b+ and +a+ to be defined +sections, despite the fact that section properties, such as description and custom configModels are not inherited to +its parent, or child section. + + +=== Defining Meta-Configuration Model + +The configuration meta-model is defined by simple configuration meta-data entries. The section for all model +configuration by default is called +model+, which results in entries such as +_my.config.key.model.target=Section+. +Within this section fully qualified configuration keys defines +which part of the configuration is targeted by certain entries. + +==== Defining Sections + +First we start to define some configuration sections, the example below starts with the most important +variants supported: + +[source,listing] +------------------------------------------------------------------------------- +# Metamodel information +_model.provider=ConfigModel Extension + +# org.mycompany.root (optional section) +_org.mycompany.root.model.target=Section +_org.mycompany.root.model.description=Root section defining my company configuration. + +# org.mycompany.security (required section) +_org.mycompany.security.model.target=Section +_org.mycompany.security.model.required=true +_org.mycompany.security.model.description=Security related settings.\ + refer for further details to XXX. + +# minmal section +_minimal.model.target=Section + +# custom validated section +_validated.model.target=Section +_validated.model.validator=org.apache.tamaya.model.TestValidator +------------------------------------------------------------------------------- + +Above +org.mycompany.root+ transitively defines 3 sections: + +* org +* org.mycompany +* org.mycompany.root + +All sections are optional. Additionally the model above also defines a required section +org.mycompany.security+. +Required sections are checked so the section is not empty. It is not checked for any specific parameter hereby, +only the existance of any child parameter is validated. + +The _class_ attribute has to be defined for any section definition, because if not set a model entry is, by default, +defined to be a parameter configModel entry. Given above the entry for the section +minimal+ shows such a minimal +entry. + ++validated+ defines a section, which is validated through a customizable validator. Hereby an ordered list of validators +can be provided, separated by commas. + + +==== Defining Parameters + +Similarly parameters also can be defined: + +[source,listing] +------------------------------------------------------------------------------- +# org.mycompany.root.name (required parameter) +_org.mycompany.root.name.model.target=Parameter +_org.mycompany.root.name.model.required=true +_org.mycompany.root.name.model.description=The company's name, also used in the application's main header. + +# org.mycompany.security (required parameters) +_org.mycompany.security.uid.model.required=true +_org.mycompany.security.uid.model.description=The user id. +_org.mycompany.security.realm.model.required=true +_org.mycompany.security.realm.model.validator=org.apache.tamaya.model.RealmValidator +_org.mycompany.security.realm.model.description=The security realm required. +_org.mycompany.security.tokenid.model.description=The token id, if the token service is used (optional). + +# A minmal parameter +_minimalClass.model.target=Class +------------------------------------------------------------------------------- + +Similarly as when defining section also parameter entries define transitively its containing sections. E.g. +the entry above for +org.mycompany.security.realm+ also defines the following sections (as optional). + +* org +* org.mycompany +* org.mycompany.security + +Additional entries for section, e.g. configModels to be done, can be added as described in the previous section, +but are optional. + +Since the parameter is the default type for model entries, a minmal parameter model entry only only needs it's +parameter type to be defined. In the example above we define a parameter +minimalClass+ of type +Class+. +Types hereby are fully qualified class names, whereas as 'java.ui.lang' for built-in language types can be +ommitted. + +==== Model Locations + +By default the configuration model can be defined at the following locations: + +* +classpath*:META-INF/configmodel.properties+, separate to the current +Configuration+. This functionality is enabled + by default, but can be disabled by adding +org.apache.tamaya.model.default.enabled=false+ to your current + +Configuration+. +* +implicitly as part of the current +Configuration+. THis can be disabled by setting + the +org.apache.tamaya.model.integrated.enabled+ configuration poarameter to +false+. +* customized by configuring the +org.apache.tamaya.model.resources+ in the current +Configuration+. This + parameter allows to define the locations from where the model extension is trying to read the + model configuration. If the _resources extension_ is available in your system it is used to + evaluate the locations. If not the default +Classloader.getResources+ command is issued. Also it + is required that the _formats extension_ is available, since this is used to effectively read the + data. This extension also allows you to use alternate representation formats such as +ini, xml, yml, json+. + + +=== Tracking Configuration Access + +The model module also allows tracking which code accesses configuration properties or configuration parameters. +It checks the stacktrace to evaluate the calling code location, hereby any unwanted packages can be implicitly +ommitted from the stacktrace. Also the maximal length of the stacktrace retained can be constraint in length. +The usages are recorded as +Usage+ instances. Hereby for each parameter accessed a corresponding +Usage+ +instance is created. It can be accessed by calling +Usage ConfigUsageStats.getUsage(String key)+. Usage +statistics for calling +Configuration.getProperties()+ can be obtained calling +Usage getUsageAllProps();+. + +Usage tracking is disabled by default. It can be enabled by calling +ConfigUsageStats.enableUsageTracking(true);+. ++ConfigUsageStats.isUsageTrackingEnabled()+ returns the current tracking status. + +The +Usage+ class itself provides access to further fainer grained usage data (+AccessDetail+) containing: + +* the access point (+fqn.ClassName#method(line: xxx)+). +* the number of accesses +* the first an last access +* the values read +* the access stacktrace (filtered by ignored packages). + +[source,java] +----------------------------------------------------------- +public final class Usage { + [...] + public String getKey(); + public void clearMetrics(); + public int getReferenceCount(); + public int getUsageCount(); + public Collection<AccessDetail> getAccessDetails(Class type); + public Collection<AccessDetail> getAccessDetails(Package pack); + public Collection<AccessDetail> getAccessDetails(String lookupExpression); + public Collection<AccessDetail> getAccessDetails(); + public void trackUsage(String value); + public void trackUsage(String value, int maxTraceLength); + + + public static final class AccessDetail { + [...] + public void clearStats(); + public long trackAccess(String value); + public long getAccessCount(); + public String getAccessPoint(); + public long getFirstAccessTS(); + public long getLastAccessTS(); + public String[] getStackTrace(); + public Map<Long, String> getTrackedValues(); + } + +} +----------------------------------------------------------- + +With +ConfigUsageStats.clearUsageStats()+ the collected statistics can be reset at any time. Summarizing the main +singleton for configuration statistics is defined as follows: + +[source,java] +----------------------------------------------------------- +public final class ConfigUsageStats{ + public static Set<String> getIgnoredUsagePackages(); + public static void addIgnoredUsagePackages(String... packageName); + public static void enableUsageTracking(boolean enabled); + public static Usage getUsage(String key); + public static Collection<Usage> getUsages(); + public static void clearUsageStats(); + public static Usage getUsageAllProperties(); + public static boolean isUsageTrackingEnabled(); + public static String getUsageInfo(); +} +----------------------------------------------------------- + +==== Customizing the Stacktrage for Usage Reporting + +The stacktrace tracked by the system can be customized in several ways: + +* +ConfigUsageStats.addIgnoredPackageNames(String...)+ allows to add additional ignored package names. +* With +Usage.setMaxTraceLength(int)+ the maximal size of the stacktraces logged can be set. Setting a + negative value will disable stacktrace logging completelely. + + +=== Accessing Usage Statistics + +Bascially usage statistics are available in two forms: + +* The +Usage/AccessDetail+ object tree can be accessed programmatically from the +ConfigUsageStats+ + singleton. +* With +ConfigUsageStats.getUsageInfo()+ also a textual representation of the usage statistics + can be obtained, as illustrated below (a snipped from the current test output): + +[source,listing] +----------------------------------------------------------- +Apache Tamaya Configuration Usage Metrics +========================================= +DATE: Sat Apr 30 21:51:09 CEST 2016 + +220 <<all>>: + - 220 <unknown/filtered/internal> , first=Sat Apr 30 21:51:09 CEST 2016, last=Sat Apr 30 21:51:09 CEST 2016 +3 java.version: + - 2 test.model.TestConfigAccessor#readProperty(line:43), first=Sat Apr 30 21:51:09 CEST 2016, last=Sat Apr 30 21:51:09 CEST 2016 + - 1 <unknown/filtered/internal> , first=Sat Apr 30 21:51:09 CEST 2016, last=Sat Apr 30 21:51:09 CEST 2016 + +----------------------------------------------------------- + + +==== Programmatic API + +Basically the configModel module provides a simple API to access the defined +ConfigModel+ instances and +validating the current +Configuration+ against the models as follows: + +[source,java] +----------------------------------------------------------- +public final class ConfigModelManager { + + private ConfigModelManager() {} + + public static Collection<ConfigModel> getModels(); + public static Collection<ConfigModel> findModels(ModelType type, String namePattern); + public static <T extends ConfigModel> T getModel(String name, Class<T> modelType); + public static Collection<ConfigModel> findModels(String namePattern); + + public static Collection<ValidationResult> validate(); + public static Collection<ValidationResult> validate(boolean showUndefined); + public static Collection<ValidationResult> validate(Configuration config); + public static Collection<ValidationResult> validate(Configuration config, boolean showUndefined); + + public static void registerMBean(); + public static void registerMBean(String context); + +} +----------------------------------------------------------- + +This singleton allows to validate the current or any +Configuration+ instance. All the ConfigModels read also are +available from the +getModels+ method. This models can be used to provide documentation, e.g. as part of a CLI interface +or shown on a documentation web server. + +A +ConfigModel+ hereby is defined as one single part of configuration, typically corresponding to a specific concern +of your system. As an example you can define different models for different modules or products plugged together. +With resolution mechanism in place you can also define a shared module that is targeted by multiple modules as a +single configuration source (e.g. for configuring the machine's IP address and subnet settings only once. + +[source,java] +----------------------------------------------------------- +public interface ConfigModel { + + ModelTarget getType(); + String getName(); + String getProvider(); + boolean isRequired(); + String getDescription(); + Collection<ValidationResult> validate(Configuration config); +} +----------------------------------------------------------- + + +Hereby +ModelTarget+ defines more details on the kind of model: + +[source,java] +----------------------------------------------------------- +public enum ModelTarget { + /** + * A configuration section. + */ + Section, + /** + * A configuration paramter. + */ + Parameter, + /** + * ConfigModel that is a container of other validations. + */ + Group +} +----------------------------------------------------------- + +A +ValidationResult+ models one validation executed by a +ConfigModel+ on a certain +Configuration+ instance: + +[source,java] +----------------------------------------------------------- +public final class ValidationResult { + + public static ValidationResult ofValid(ConfigModel configModel); + public static ValidationResult ofMissing(ConfigModel configModel); + public static ValidationResult ofMissing(ConfigModel configModel, String message); + public static ValidationResult ofError(ConfigModel configModel, String error); + public static ValidationResult ofWarning(ConfigModel configModel, String warning); + public static ValidationResult ofDeprecated(ConfigModel configModel, String alternateUsage); + public static ValidationResult ofDeprecated(ConfigModel configModel); + public static ValidationResult ofUndefined(final String key); + public static ValidationResult of(ConfigModel configModel, ValidationState result, String message); + + public ConfigModel getConfigModel(); + public ValidationState getResult(); + public String getMessage(), +} +----------------------------------------------------------- + +The result of a complete validation on a concrete +Configuration+ instance finally is mapped as a ++Collection<ValidationResult>+, refer to the methods on +ConfigModelManager+. + + +=== Auto-Documentation of Classes with Configuration Injection + +A special feature of this module is that it observes +ConfigEvent+ published through Tamaya'as event channel +(+tamaya-events+ module). If no metaconfiguration model is found the model manager by default automatically creates +models for all injected instances on the fly. In the case of CDI integration this happens typically during deployment +time, since CDI initializes during deployment time. Other runtime platforms, such as OSGI, may have rather different +behaviour. Nevertheless this means that after your system has been started you should have access to a complete +set of +ConfigModel+ instances that automatically document all the classes in your system that consume configuration +(through injection). + + +== Model SPI +=== Registering Configuration Models + +The model extension also provides an SPI where customized functionality can be added. The main abstraction hereby is +the +ModelProviderSpi+ interface, which allows any kind of additional config models to be added to the system: + +[source,java] +----------------------------------------------------------- +public interface ModelProviderSpi { + + Collection<ConfigModel> getConfigModels(); + +} +----------------------------------------------------------- + +New instances implementing this interface must be registered into the current +ServiceContext+, by default the ++ServiceLoader+ is used. + + +=== The ConfigUsageStatsSpi + +The methods for managing and tracking of configuration changes are similarly delegated to an +implementation of the +org.apache.tamaya.model.spi.ConfigUsageStatsSpi+ SPI. +By implementing this SPI and registerting it with the +ServiceContext+ the usage tracking +logic can be adapted or replaced. + +=== Other Utility Classes + +The module also provides further utility classes that may be useful for implementing models or testing: + +* +AbstractModel+ provides a base class that can be extended, when implementing +ConfigModel+. +* +AreaConfigModel+ provides a +ConfigModel+ implementation (with a corresponding +Builder+) to model the + requirement of certain configuration sections being present, or opionally present, in the model. +* +ParameterModel+ provides an implementation base class for validating parameters on existence and compliance + with a regular expression. +* +ConfigDocumentationMBean+ is the MBean registered that models similar functionality as +ConfigModelManager+. +* +ConfigModelGroup+ provides a +ConfigModel+ that groups several child models. +* +ConfigModelReader+ allows to read +ConfigModels+ from properties files as described at the beginning of this + document. + + +=== Switches to enable/disable functionality + +The model module provides different switches that can be used to activate or deactivate features: + +* +tamaya.model.integrated.enabled+ allows to deactivate reading inline metaconfiguration delivered with + the normal Tamaya Configuration. By default inline entries (+_.abcd.model.*+) are evaluated. +* +tamaya.model.default.enabled+ allows to deactivate reading metamodel information from + +classpath:META-INF/configmodel.properties+. By default it is active. +* +tamaya.model.resources+ allows to define additional resources (loaded through the resources extension), + that can be used to read metamodel information in any format using Tamaya's format module. +* the system property +tamaya.model.autoModelEvents+ allows to activate/deactivate the automatic + documentation of classes configured and published by Tamaya +ConfiguredType+ event instances (e.g. published by + Tamaya's injection modules).