2017-11-25

Tamaya Collections Support (Extension Module)

Tamaya Collections is an extension module. Refer to the extensions documentation for further details.

What functionality this module provides ?

All configuration in Tamaya is expressed as simple key, value pairs. Nevertheless this concept allows similarly the modelling of collection typed values such as lists, sets, maps or simple collections of things. The Tamaya Collections extension adds this functionality to the Tamaya eco-system.

Compatibility

The module is based on Java 7, so it will not run on Java 7 and beyond.

Installation

To use Tamaya collection support you only must add the corresponding dependency to your module:

<dependency>
  <groupId>org.apache.tamaya.ext</groupId>
  <artifactId>tamaya-collections</artifactId>
  <version>{tamaya_version}</version>
</dependency>

Overview

Tamaya Collections adds PropertyConverter implementations that are able to access configuration data as lists, maps or sets. By default this works out of the box as easy as accessing any other type of configuration data, e.g.

Configuration config = ConfigurationProvider.getConfiguration();

// Without any content specification, a list of String is returned.
List<String> simpleList = config.get("my.list.config.entry", List.class);

// Using a TypeLiteral allows to use every convertible sub type supported by the system.
List<Integer> intList = config.get("my.list.config.entry", new TypeLiteral<List<Integer>>(){});

Configuration in that case, by default, is a simple comma-separated list of entries, e.g.

my.list.config.entry=1,34454,23,344545,3445

Additionally the module allows adding additional meta-entries, which allows to tweak some of the inner-workings, e.g.

  • using your own PropertyConverter implementation for parsing entries.

  • specifying a custom separator to split the items (default is {{','}}.

  • specifying a custom separator to split key/value pairs when parsing map entries.

  • specifying the implementation type of the collection item to be returned.

  • specifying the implementation type of the collection to be returned.

Supported Types

This module currently supports the following types:

  • java.util.Collection

  • java.util.List

  • java.util.ArrayList

  • java.util.LinkedList

  • java.util.Set

  • java.util.SortedSet

  • java.util.TreeSet

  • java.util.HashSet

  • java.util.Map

  • java.util.SortedMap

  • java.util.HashMap

  • java.util.TreeMap

Hereby the collection type is determined by the parameter type accessed, e.g. config.get("mylist", ArrayList.class) will always return an ArrayList as result.

Note
This means that depending on your use case you can access different collection types based on the same configuration values, as long as their is a PropertyConverter that can convert the raw configuration value to the required target type.

Configuring the target implementation type

Tamaya Collections allows you to configure the default target collection type by adding the following meta-configuration entry (shown for the mylist entry). Hereby the package part java.util. can be ommitted:

mylist=a,b,c
_mylist.collection-type=LinkedList

When calling config.get("mylist", ArrayList.class) this parameter does not have any effect, so you will still get an ArrayList as a result. However when you call config.get("mylist", List.class) you will get a LinkedList as implementation type.

This mechanism similarly applies to all kind of collections, so you can use it similarly to define the implementation type returned when accessing List, Map or Collection.

Collecting Configuration Entries instead of Overriding

By default Tamaya applies always an overriding CombinationPolicy, where only the configuration entry for the most significant configuration entry is used. In case of collections (and maybe also other use cases), overriding is not always the mechanism of choice. E.g. when you want to have all entries added to your configuration to be combined to a new entry containing all values provided by any property sources.

Therefore Tamaya Collections also provides a more sophistiated CombinationPolicy (automatically configured) that allows to adapt the way how configuration entries are combined. All you must do is declaring the mechanism to be applied by an according meta-configuration parameter, e.g. for my.list your config may look as follows:

# from PropertSource 1
my.list=1,2,3

# from PropertSource 2, with higher precedence
my.list=4,5,6

# without any additional meta-info these entries would be combined to
my.list=4,5,6

With Tamaya Collections you can now configure the combination policy as follows:

# use one of the default policies: override / collect
_my.list.combination-policy=collect

# or use your own custom CombinationPolicy to combine the values
_my.list.combination-policy=com.mycomp.app.MyCombincationPolicy

So declaring the collect policy the resulting raw output of the entry looks as follows:

# result when applying the collect policy:
my.list=1,2,3,4,5,6

The customizable policy mechanism of Tamaya Collections also honors the item-separator meta-configuration parameter explained later in this document.

Format of Collection Configuration

By default collections are modelled as simple String values, that are tokenized into individual parts using a defined item-separator (by default ','). So a given configuration entry of 1,2,3 is mapped to "1","2","3". If the target context type is something different than String the smae conversion logic is used as when mapping configuration parameters directly to non-String target types (implemented as +PropertyConverter classes, manahed within the current ConfigurationContext. The procedure is identical for all collection types, including Map types, with the difference that each token in the list is parsed once more for separating it into a key and a value. The default separator for map entries hereby is "::". Map keys, as of now, are always of type String, whereas for values the same logic is applied as for non-map collection types.

# a list, using the default format
list=1,2,3,4,5,6

# a map, using the default format
map=a::b, c::d

Trimming of entries

By default all tokens parsed are trimmed before adding them to the final collection. In case of map entries this is also the case for key/value entries. So the following configuration results in the identical values for list1,list2 and map1,map2:

# a list, using the default format
list1=1,2,3,4,5,6
list2=1, 2, 3, 4, 5, 6

# a map, using the default format
map1=a::b, c::d
map2=a :: b, c :: d

Nevertheless truncation can be controlled by the usage of brackets, e.g. the last list or map entry will have a single space character as value:

# a list, with a ' ' value at the end
list3=1, 2, 3, 4, 5, [ ]

# a map, with a ' ' value for key '0'
map3=1 :: a, 2 :: b, 0::[ ]

Hereby \[ escapes the sequence.

Customizing the format

The item and entry separators (by default ',' and "::") can be customized by setting corresponding meta-data entries as follows, resulting in the same values as in the prevoius listing:

# a list, with a ' ' value at the end
list3=1__2__3__ 4__ 5__[ ]
_list3.item-separator=__

# a map, with a ' ' value for key '0'
map3=1->a, 2->b, 0->[ ]
_map3.map-entry-separator=->

Of course these settings also can be combined:

# a reformatted map
redefined-map=0==none | 1==single | 2==any
_redefined-map.map-entry-separator===
_redefined-map.item-separator=|