| :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. |