1. Tamaya Resolver (Extension Module)

1.1. Overview

Tamaya Resolver is an extension module. Refer to the extensions documentation for further details about modules.

Tamaya Resolver provides a dynamic resolution mechanism, which allows to use UNIX-styled (${...} placeholder expressions in your configuration values. The resolver hereby supports transitive resolution and also prevents cycles to loop endlessly.

1.2. Compatibility

The module is based on Java 7, so it can be used with Java 7 and beyond.

1.3. Installation

To benefit from dynamic value resolution you only must add the corresponding dependency to your module:

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

The module automatically registers an according PropertyFilter that is automatically called, whenever a value is accessed.

1.4. Available Resolvers

Currently the module defined the following resolvers:

Table 1. Available Resolvers

Expression

Description

Example

conf:<configKey>

Reads another configKey and replaces the expression with the value found.

conf-ref=${conf:anotherConf.entryKey}

resource:<resourceRef>

Reads a resource from the current classpath and replaces the expression with the given text content.

cp-ref=${resource:Testresource.txt}

file:<fileRef>

Reads a resource from the current classpath and replaces the expression with the given text content.

file-ref=${file:c:\myFile.txt}

url:<url>

Reads an URL and replaces the expression with the given text content.

url-ref=${url:http://www.google.com}

1.5. SPI: Implementing your own Resolvers

The module also provides an easy but powerful SPI for adding your own resolver implementations. Basically the first and most important thing to do is implementing the ExpressionResolver interface:

Implementing a Custom Resolver
public class PwdDecrypter implements ExpressionResolver {

  @Override
  public String getResolverPrefix(){
     return "decrypt:";
  }

  @Override
  public String evaluate(String expression){
    return decrypt(expression);
  }

  private String decrypt(String s){
    ...
  }
}

Basically that is all you must do, after having registered the class with the ServiceLoader it will be found and loaded by the implementation. With that all expressions that start with the given prefix are passed to the resolver, so all the following expressions will be sent to the implementation:

blabla ${decrypt:myname}
blabla ${decrypt:myname} foo blabla ${decrypt:myname}

Hereby evaluation is repeasted until no further change of values could be detetced. In case of a endless loop the evaluation is broken after a (configurable) number of cycles.

Under the hood instances of ExpressionResolver are managed by an implementation of the ExpressionEvaluator interface:

public interface ExpressionEvaluator {
    /**
     * Evaluates the current expression.
     * @param key the key, not null.
     * @param value the value to be filtered/evaluated.
     * @return the filtered/evaluated value, including null.
     */
    String evaluateExpression(String key, String value);
}

Implementing and registering this interface gives you full control, but in most cases yhou should be fine with the default implementation in place.