:jbake-type: page
:jbake-status: published

= Apache Tamaya - Extension: Resolver

[[Resolver]]
== Tamaya Resolver (Extension Module)

Tamaya _Resolver_ is an extension module. Refer to the link:../extensions.html[extensions documentation] for further details.


=== What functionality this module provides ?

Tamaya _Resolver_ is an extension module. Refer to the link:../extensions.html[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.


=== Compatibility

The module is based on Java 8.


=== Installation

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

[source, xml, subs=attributes+]
-----------------------------------------------
<dependency>
  <groupId>org.apache.tamaya.ext</groupId>
  <artifactId>tamaya-resolver</artifactId>
  <version>{tamaya_version}</version>
</dependency>
-----------------------------------------------

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


=== Available Resolvers

Currently the module defines the following resolvers:

.Available Resolvers
[cols="<.1,<.2,<.1"]
|=======
| _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}

|=======


=== Explicit Expression Resolution

The resolvers registered are normall running implicitly, when corresponding placeholders are used in configuration
values. Additionally the expression resolution functionality can also used explcitly:

[source,java]
---------------
public final class Resolver {

    public static Resolver getInstance();
    public static Resolver getInstance(ClassLoader classLoader);

    public String evaluateExpression(String key, String value);
    public String evaluateExpression(String key, String value, ClassLoader classLoader);
    public String evaluateExpression(String value);
    public String evaluateExpression(String value, boolean maskNotFound);
}
---------------

=== SPI: Implementing your own Resolvers

The module also provides a small 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
[source, java]
-----------------------------------------------
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:

[source,listing]
-----------------------------------------------
blabla ${decrypt:myname}
blabla ${decrypt:myname} foo blabla ${decrypt:myname}
-----------------------------------------------

Hereby evaluation is repeated 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:

[source, java]
-----------------------------------------------
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 you should be fine with
the default implementation in place.
