# Apache Tamaya — Extension: Configuration Server

## Tamaya Configuration Server (Extension Module)

### Overview

The Tamaya server module provides support for providing scoped configuration using a http server serving JSON formatted configuration properties.

### Compatibility

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

### Installation

To benefit from configuration server support you only must add the corresponding dependency to your module:

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

### Providing configuration using the Tamaya Built-in Configuration Server

THe most simple way for providing onfiguration ist to start the internal server:

    Server server = org.apache.tamaya.server.ConfigServer.createServer();
    server.start(port);

This will start a simple server instance that serves the following URL patterns:

- GET /config provides access to the full configuration tree.

- GET /config/filtered/${path} let you filter the configuration returned using regular expression (comma separated). E.g. /config/filtered/java,sun will return all configuration entries starting with java and sun.

Additionally the server module has the following options implemented, which can be passed as additional, optional parameters:

- format allows to define the target format. By default the ACCEPT header of the http request is checked, but this setting can be explicitly controlled by passing tis parameter explicitly. The value is the expected MIME type to be returned. By default the service supports the following types (refer to the SPI section later in this document for options to adapt this):

  - text/html

  - text/plain

  - application/xml

  - text/json

- scope,scopeId allows to use a server-side preconfigured filter/combination policy to be applied for evaluating the entries to be returned. Hereby the scopeId paramter allows to address a certain scope. As an example think of a scope ?scope=CLIENT&scopeId=client1 to be passed as request parameters. This tells the server module to lookup a configured scope named 'CLIENT' and access a ConfigOperator for the given scopeId 'client1'. The returned operator then can filter and combine any kind of entries to the required client configuration (for client1). Refer to the scopes section for more details.

### Using the Configuration Servlets

Additionally to the fully built-in solution, it is also possible to integrate the Tamaya server module with a standard Java EE servlet container. Tamaya provides 2 servlet implementations:

- the servlet org.apache.tamaya.server.FilteredConfigServlet can be used to register access to configurations that also support filtering of the keys. The URL looks like

    http(s)://HOST/SERVLET_CONTEXT/PATHS?params

    where
      HOST            = host name incl port, e.g. 127.0.0.2:234
      SERVLET_CONTEXT = the base context and servlet context, e.g. /client/config/filtered
      PATHS           = A comma separated number of key paths to be filtered for being returned, e.g.
                        java,sun,client
      params          = the optional parameters (scope, scopeId and format)

- the servlet org.apache.tamaya.server.FullConfigServlet can be used to register access to configurations that alwyas returns all items known. The URL looks like

    http(s)://HOST/SERVLET_CONTEXT?params

    where
      HOST            = host name incl port, e.g. 127.0.0.2:234
      SERVLET_CONTEXT = the base context and servlet context, e.g. /client/config/filtered
      params          = the optional parameters (scope, scopeId and format)

#### Formatting used by Default

The server module formats the configuration returned by default in thw following variants:

Formatting for text/json

    {
      "java.vendor.url": "http://java.oracle.com/",
      "java.vendor.url.bug": "http://bugreport.sun.com/bugreport/",
      "java.vm.info": "mixed mode",
      "java.vm.name": "Java HotSpot(TM) 64-Bit Server VM",
      "java.vm.specification.name": "Java Virtual Machine Specification",
      "java.vm.specification.vendor": "Oracle Corporation",
      "java.vm.specification.version": "1.8",
      "java.vm.vendor": "Oracle Corporation",
      "java.vm.version": "25.45-b02",
      "sun.arch.data.model": "64",
      "sun.boot.class.path": "C:\apps\jdk18\jre\lib\resources.jar;C:\apps\jdk18\jre\lib\rt.jar;C:\apps\jdk18\jre\lib\sunrsasign.jar;C:\apps\jdk18\jre\lib\jsse.jar;C:\apps\jdk18\jre\lib\jce.jar;C:\apps\jdk18\jre\lib\charsets.jar;C:\apps\jdk18\jre\lib\jfr.jar;C:\apps\jdk18\jre\classes",
      "sun.boot.library.path": "C:\apps\jdk18\jre\bin",
      "sun.cpu.endian": "little",
      "sun.cpu.isalist": "amd64",
      "sun.desktop": "windows",
      "sun.io.unicode.encoding": "UnicodeLittle",
      "sun.java.command": "com.intellij.rt.execution.application.AppMain org.apache.tamaya.examples.remote.server.Start",
      "sun.java.launcher": "SUN_STANDARD",
      "sun.jnu.encoding": "Cp1252",
      "sun.management.compiler": "HotSpot 64-Bit Tiered Compilers",
      "sun.os.patch.level": "",
      "{meta}class": "org.apache.tamaya.functions.FilteredConfiguration",
      "{meta}info.filter": "java.v,sun",
      "{meta}info.format": "application/json",
      "{meta}info.timestamp": "1441463200571",
      "{meta}timestamp": "1441463200571",
      "{meta}type": "Configuration"
    }

Formatting for application/xml

    <configuration>
      <entry key="java.vendor.url">http://java.oracle.com/</entry>
      <entry key="java.vendor.url.bug">http://bugreport.sun.com/bugreport/</entry>
      <entry key="java.vm.info">mixed mode</entry>
      <entry key="java.vm.name">Java HotSpot(TM) 64-Bit Server VM</entry>
      <entry key="java.vm.specification.name">Java Virtual Machine Specification</entry>
      <entry key="java.vm.specification.vendor">Oracle Corporation</entry>
      <entry key="java.vm.specification.version">1.8</entry>
      <entry key="java.vm.vendor">Oracle Corporation</entry>
      <entry key="java.vm.version">25.45-b02</entry>
      <entry key="sun.arch.data.model">64</entry>
      <entry key="sun.boot.class.path">C:\apps\jdk18\jre\lib\resources.jar;C:\apps\jdk18\jre\lib\rt.jar;C:\apps\jdk18\jre\lib\sunrsasign.jar;C:\apps\jdk18\jre\lib\jsse.jar;C:\apps\jdk18\jre\lib\jce.jar;C:\apps\jdk18\jre\lib\charsets.jar;C:\apps\jdk18\jre\lib\jfr.jar;C:\apps\jdk18\jre\classes</entry>
      <entry key="sun.boot.library.path">C:\apps\jdk18\jre\bin</entry>
      <entry key="sun.cpu.endian">little</entry>
      <entry key="sun.cpu.isalist">amd64</entry>
      <entry key="sun.desktop">windows</entry>
      <entry key="sun.io.unicode.encoding">UnicodeLittle</entry>
      <entry key="sun.java.command">com.intellij.rt.execution.application.AppMain org.apache.tamaya.examples.remote.server.Start</entry>
      <entry key="sun.java.launcher">SUN_STANDARD</entry>
      <entry key="sun.jnu.encoding">Cp1252</entry>
      <entry key="sun.management.compiler">HotSpot 64-Bit Tiered Compilers</entry>
      <entry key="sun.os.patch.level"></entry>
      <entry key="{meta}class">org.apache.tamaya.functions.FilteredConfiguration</entry>
      <entry key="{meta}info.filter">java.v,sun</entry>
      <entry key="{meta}info.format">application/xml</entry>
      <entry key="{meta}info.timestamp">1441463383687</entry>
      <entry key="{meta}timestamp">1441463383687</entry>
      <entry key="{meta}type">Configuration</entry>
    </configuration>

Formatting for text/plain

    Configuration:
      java.vendor.url: http://java.oracle.com/,
      java.vendor.url.bug: http://bugreport.sun.com/bugreport/,
      java.vm.info: mixed mode,
      java.vm.name: Java HotSpot(TM) 64-Bit Server VM,
      java.vm.specification.name: Java Virtual Machine Specification,
      java.vm.specification.vendor: Oracle Corporation,
      java.vm.specification.version: 1.8,
      java.vm.vendor: Oracle Corporation,
      java.vm.version: 25.45-b02,
      sun.arch.data.model: 64,
      sun.boot.class.path: C:\apps\jdk18\jre\lib\resources.jar;C:\apps\jdk18\jre\lib\rt.jar;C:\apps\jdk18\jre\lib\sunrsasign.jar;C:\apps\jdk18\jre\lib\jsse.jar;C:\apps\jdk18\jre\lib\jce.jar;C:\apps\jdk18\jre\lib\charsets.jar;C:\apps\jdk18\jre\lib\jfr.jar;C:\apps\jdk18\jre\classes,
      sun.boot.library.path: C:\apps\jdk18\jre\bin,
      sun.cpu.endian: little,
      sun.cpu.isalist: amd64,
      sun.desktop: windows,
      sun.io.unicode.encoding: UnicodeLittle,
      sun.java.command: com.intellij.rt.execution.application.AppMain org.apache.tamaya.examples.remote.server.Start,
      sun.java.launcher: SUN_STANDARD,
      sun.jnu.encoding: Cp1252,
      sun.management.compiler: HotSpot 64-Bit Tiered Compilers,
      sun.os.patch.level: ,
      {meta}class: org.apache.tamaya.functions.FilteredConfiguration,
      {meta}info.filter: java.v,sun,
      {meta}info.format: text/plain,
      {meta}info.timestamp: 1441463082020,
      {meta}timestamp: 1441463082021,
      {meta}type: Configuration

Formatting for application/html

    <html>
    <head><title>System Configuration</title></head>
    <body>
    <h1>Sysem Configuration</h1>
    <p>This view shows the system configuration of devbox-win at Sat Sep 05 16:30:59 CEST 2015.</p><pre>
    Configuration:
      java.vendor.url: http://java.oracle.com/,
      java.vendor.url.bug: http://bugreport.sun.com/bugreport/,
      java.vm.info: mixed mode,
      java.vm.name: Java HotSpot(TM) 64-Bit Server VM,
      java.vm.specification.name: Java Virtual Machine Specification,
      java.vm.specification.vendor: Oracle Corporation,
      java.vm.specification.version: 1.8,
      java.vm.vendor: Oracle Corporation,
      java.vm.version: 25.45-b02,
      sun.arch.data.model: 64,
      sun.boot.class.path: C:\apps\jdk18\jre\lib\resources.jar;C:\apps\jdk18\jre\lib\rt.jar;C:\apps\jdk18\jre\lib\sunrsasign.jar;C:\apps\jdk18\jre\lib\jsse.jar;C:\apps\jdk18\jre\lib\jce.jar;C:\apps\jdk18\jre\lib\charsets.jar;C:\apps\jdk18\jre\lib\jfr.jar;C:\apps\jdk18\jre\classes,
      sun.boot.library.path: C:\apps\jdk18\jre\bin,
      sun.cpu.endian: little,
      sun.cpu.isalist: amd64,
      sun.desktop: windows,
      sun.io.unicode.encoding: UnicodeLittle,
      sun.java.command: com.intellij.rt.execution.application.AppMain org.apache.tamaya.examples.remote.server.Start,
      sun.java.launcher: SUN_STANDARD,
      sun.jnu.encoding: Cp1252,
      sun.management.compiler: HotSpot 64-Bit Tiered Compilers,
      sun.os.patch.level: ,
      {meta}class: org.apache.tamaya.functions.FilteredConfiguration,
      {meta}info.filter: java.v,sun,
      {meta}info.format: text/html,
      {meta}info.timestamp: 1441463459653,
      {meta}timestamp: 1441463459654,
      {meta}type: Configuration

    </pre>
    </body>
    </html>

### SPI

#### Scopes

As mentioned earlier in this document scopes can be used to define the exact configuration tree to be returned, e.g. as a result of combining multiple sub trees. Following an example of the code to be written to return a configuration that combines common client default entries with client specific entries:

    public class ClientScopeProvider implements ScopeProvider{

        /**
         * Access the unique scope name.
         * @return the unique scope name.
         */
        public String getScopeType(){
                return "CLIENT";
        }

        @Override
        public ConfigOperator getScope(String scopeId) {
            return c ->
                    ConfigurationFunctions.combine("Scoped Config CLIENT="+scopeId,
                            c.with(ConfigurationFunctions.sectionRecursive(true, "client.default")),
                            c.with(ConfigurationFunctions.sectionRecursive(true, "client." + scopeId))
                    );
        }
    }

This class can be registered using the ServiceContext in place. By default the ServiceLoader is used, so you will have to add the following to META-INF/services/org.apache.tamaya.server.spi.ScopeProvider:

    my.full.packagename.ClientScopeProvider

#### Adapting the Way Configuration is Derived

Finally the effective readong and configuration handling logic can also be replaced or improved. This can be done by registering your own implementation of the interface ConfigProviderService:

    public interface ConfigProviderService {
        String getConfigurationWithPath(String path, String format, String scope, String scopeId, HttpServletRequest request);
        String getConfiguration(String format, String scope, String scopeId, HttpServletRequest request);
        void updateConfiguration(String payload, HttpServletRequest request);
        void deleteConfiguration(String paths, HttpServletRequest request);
    }

By default the ServiceContextManager uses the java.util.ServiceLoader for component loading, so to replace the default server code you must register a higher @Priority implementation.

#### Replacing the Built-In Server

We have seen earlier that starting a configuration server is pretty easy:

    Server server = org.apache.tamaya.server.ConfigServer.createServer();
    server.start(port);

Nevertheless one may want to replace the used implementation of Server. This can be done easily by simply registering an overriding implementation if the corresponding interface:

    public interface Server {
        void start(int port);
        boolean isStarted();
        void stop();
        void destroy();
    }

#### The ScopeManager Singleton

Finally whe implementing your own server, you might also benefit from the ScopeManager singleton. Basically this class loads all registered ScopeProvider and manages the configured scope instances:

    public final class ScopeManager {
        ...

        private ScopeManager(){}

        /**
         * Get the scope given its name.
         * @param scopeId the scope name
         * @return the scope matching
         * @throws ConfigException, if nos such scope is defined.
         */
        public static ConfigOperator getScope(String scopeId, String target);

        /**
         * Get the defined scope names.
         * @return the defined scope names, never null.
         */
        public static Set<String> getScopes();

    }