# Apache Tamaya — Extension: Classloader Isolation Support

## Tamaya CDI Integration (Extension Modules)

### Overview

Apache Tamaya currently provides two implementations for integration with CDI extensions implementing similar functionality as described in this document:

- Loading of CDI managed SPI components as configuration extensions such as PropertySources, PropertySourceProviders, PropertyFilters, etc. This also includes SPI defined by any Tamaya submodules.

- Implement and enable Tamaya’s configuration injection services with CDI.

Hereby there are two implementations provided:

- tamaya-cdi-ee implements injection by using CDI’s injection mechanism to inject configuration values into the beans managed by the CDI systems.

- tamaya-cdi-se implements injection by integrating the tamaya-injection SE based injection module (also used for Spring and OSGI injection) with CDI. Injection hereby is performed by the Tamaya SE module, whereas beans and injection control overall are still managed by CDI.

- One difference, of course, is that tamaya-se also provides an SE compatible API (ConfigurationInjection, ConfigurationInjector), which is not available, when using the purely Java EE based variant.

The annotations used for all injection functionality in Tamaya is defined as a separate module. This allows you to code against the injection API without dependency on the concrete injection implementation. As a consequence your components will be compatible regardless if deployed in a pure SE, a Java EE (CDI) or OSGI or Spring environment:

    <dependency>
      <groupId>org.apache.tamaya.ext</groupId>
      <artifactId>tamaya-injection-api</artifactId>
      <version>{tamayaVersion}</version>
    </dependency>

### Compatibility

Both modules are based on Java 7, so they will not run on Java 7 and beyond.

### Installation

To benefit from Tamaya CDI integration you only must one of the following dependencies to your module. Ensure that you never have installed both CDI extensions at the same time because this may be lead to unforseen side-effects.

CDI Pure Application Configuration

    <dependency>
      <groupId>org.apache.tamaya.ext</groupId>
      <artifactId>tamaya-cdi-ee</artifactId>
      <version>{tamayaVersion}</version>
    </dependency>

CDI enhanced with Tamaya SE Application Configuration

    <dependency>
      <groupId>org.apache.tamaya.ext</groupId>
      <artifactId>tamaya-cdi-se</artifactId>
      <version>{tamayaVersion}</version>
    </dependency>

Both components will auto-register its components and override the default ServicceContext in use. Additionally they register CDI extensions that implement Configuration injection as described before.

Important | Never install Tamaya’s tamaya-cdi-se and tamaya-cdi-ee on the same system, since unpredictable side effects could occur.

### Registering CDI managed components into the Application’s ConfigurationContext

As mentioned both modules allow to provide Tamaya SPI extensions modules as ordinary CDI managed beans. By default extensions should be registered using @Singleton or @ApplicationScoped scope annotations. So you can define/deploy additional application specific PropertySources and other artifacts simply by defining a CDI managed bean implementing the required SPI interface:

    @Singleton
    public class TestPropertySource implements PropertySource{

        final Map<String,String> config = new HashMap<>();

        public TestPropertySource(){
            config.put("a.b.c.key1", "keys current a.b.c.key1");
            config.put("a.b.c.key2", "keys current a.b.c.key2");
            config.put("{"+getName()+"}source", getClass().getName());
        }

        @Override
        public int getOrdinal() {
            return 10;
        }

        @Override
        public String getName() {
            return getClass().getName();
        }

        @Override
        public String get(String key) {
            return config.get(key);
        }

        @Override
        public Map<String, String> getProperties() {
            return config;
        }

        @Override
        public boolean isScannable() {
            return true;
        }
    }

Note that for many SPI’s there is a priority mechanism using @Priority annotations in place. The ServiceContext implementation combines the components registered with the ones loaded from the ServiceLoader mechanism hereby considering classloaser hierarchies.

### Annotating your Classes

Basically annotating your classes is stright forward. @Config defines an additional CDI qualifier that is, depending on the module deployed, handled by a CDI producer (tamaya-cdi-ee) or the Tamaya SE injection mechanism $ (tamaya-cdi-se). All types injected by this module are injected using dependent scope.

    @RequestScoped
    public class ConfiguredClass{

        @Config
        private String testProperty;

        @Config({"a.b.c.key1","a.b.c.key2","a.b.c.key3"})
        @ConfigDefault("The current \\${JAVA_HOME} env property is ${env:JAVA_HOME}.")
        String value1;

        @Config({"foo","a.b.c.key2"})
        private String value2;

        @Config
        @ConfigDefault("N/A")
        private String runtimeVersion;

        @Config
        @ConfigDefault("${sys:java.version}")
        private String javaVersion2;

        @Config
        @ConfigDefault("5")
        private Integer int1;

        ...

    }

### Advanced Use Cases

Beside basic configuration Tamaya also covers additional requirements:

- _Reading multiple keys, where the first successful one is determining the value of the configuration, is simply possible, by adding multiple keys to the @Configy annotation. E.g. for trying first a.b and then new.b you would configure it as follows:

    @Config({"a.b", "new.b"}
    private String value;

- When you must apply a ConfigOperator to your config, before reading the configuration, you can configure one as follows:

    @Config({"a.b", "new.b"}
    @WithConfigOperator(MyOperator.class)
    private String value;

- When you must apply a some special conversion, or you use a type that is not registered for conversion, you can configure a custom converter to be applied as follows:

    @Config({"a.b", "new.b"}
    @WithPropertyConverter(MyConverter.class)
    private MySpecialFooType value;

- Often multiple keys in a class belong to the same root section. So instead of copying this to every entry you can define the most common root sections in the type’s header:

    @ConfigDefaultSections({"aaaa", "new"});
    public class MyType{

    @Config({"b", "[legacy.bKey]"} // lookups: "aaaa.b", "new.b", legacy.bKey
    private String value;

In the example above legacy.bKey defines an absolute key, which is not combined with any defined default section parts.