Skip to content

A configuration library designed as a provider of Apache Commons Configuration instances that can be updated at runtime.

License

Notifications You must be signed in to change notification settings

LableOrg/java-dynamicconfig

Repository files navigation

Dynamic Config

Dynamic Config is a Java configuration library designed to provide Apache Commons Configuration instances that can be updated at runtime.

Goals

This library is designed to provide a dynamic configuration resource suitable for use in multiple concurrent Java (web) applications running on multiple servers, where the configuration is provided from a central source. Although the core library is implementation agnostic, this project was designed to work with [https://zookeeper.apache.org/](Apache ZooKeeper).

We created this library to:

  • provide a simple way to manage runtime configuration parameters for Java web applications deployed on several Tomcat-servers from a single place
  • be able to update runtime configurations without the need to redeploy WAR archives

To create and update configuration resources we use a simple command line script deployed on a server accessible via SSH, but any tool or service that can update ZooKeeper nodes should work.

Usage examples

A set of minimal working examples is available here.

Bootstrapping Dynamic Config

Dynamic Config is designed to to be used in situations where multiple web applications are run on multiple Tomcat servers. In this distributed scenario Dynamic Config can be used with Apache ZooKeeper to provide the configuration sources. Alternatively, a local configuration file may be used. This approach implies that you have only one machine running a single instance of your application, or that you take care of distributing the configuration files yourself (e.g., via SSH).

Dynamic configuration with a YAML file on the local file system

If your (web) application runs on a single machine, configuration may be provided through a local YAML file. Add these Maven dependencies:

<properties>
  <dynamic.config.version>VERSION_HERE</dynamic.config.version>
</properties>

<dependencies>
  <dependency>
    <!-- Useful i -->
    <groupId>org.lable.oss.dynamicconfig</groupId>
    <artifactId>dynamic-config-servlet-util</artifactId>
    <version>${dynamic.config.version}</version>
  </dependency>
  <dependency>
    <groupId>org.lable.oss.dynamicconfig</groupId>
    <artifactId>dynamic-config-core</artifactId>
    <version>${dynamic.config.version}</version>
  </dependency>
  <dependency>
    <groupId>org.lable.oss.dynamicconfig.serialization</groupId>
    <artifactId>dynamic-config-serialization-yaml</artifactId>
    <version>${dynamic.config.version}</version>
  </dependency>
</dependencies>

To configure Dynamic Config, have your web server(s) provide these system properties to the web applications it serves:

System Property Example value
org.lable.oss.dynamicconfig.type file
org.lable.oss.dynamicconfig.appname config-file-name.yaml

Instead of statically configuring org.lable.oss.dynamicconfig.appname, you can also implement a ServletContextListener to use the name of the current web application context instead. This is documented below in the section on ZooKeeper.

Distributed configuration with YAML configuration resources stored in ZooKeeper

To use the ZooKeeper provider with YAML configuration resources, add the following Maven dependencies to your project. Set property dynamic.config.version to the current version of Dynamic Config:

<properties>
  <dynamic.config.version>VERSION_HERE</dynamic.config.version>
</properties>

<dependencies>
  <dependency>
    <groupId>org.lable.oss.dynamicconfig</groupId>
    <artifactId>servlet-util</artifactId>
    <version>${dynamic.config.version}</version>
  </dependency>
  <dependency>
    <groupId>org.lable.oss.dynamicconfig.provider</groupId>
    <artifactId>zookeeper</artifactId>
    <version>${dynamic.config.version}</version>
  </dependency>
  <dependency>
    <groupId>org.lable.oss.dynamicconfig.serialization</groupId>
    <artifactId>yaml</artifactId>
    <version>${dynamic.config.version}</version>
  </dependency>
</dependencies>

The simplest way to configure Dynamic Config when used from within a web application with the ZooKeeper provider, is to configure your web server(s) once to provide these system properties to the web applications it serves:

System Property Example value
org.lable.oss.dynamicconfig.zookeeper.znode /dynamicconfig
org.lable.oss.dynamicconfig.type zookeeper
org.lable.oss.dynamicconfig.zookeeper.quorum zk1,zk2,zk3
org.lable.oss.dynamicconfig.zookeeper.copy.quorum.to zookeeper.quorum

In addition to these properties, Dynamic Config needs to know the name of the specific configuration resource it should load. For a web application running in a servlet container such as Apache Tomcat, you can tell Dynamic Config to use the name of the current application context (which usually based on the name of the WAR archive).

Implement a ServletContextListener, register it in your web.xml, and call this ServletUtil method:

@Override
public void contextInitialized(ServletContextEvent event) {
    // [...]
    
    ServletUtil.setApplicationNameFromContext(event);

    // [...]
}

Now you can load the configuration instance by calling:

Configuration configuration = ConfigurationInitializer.configureFromProperties(new YamlDeserializer());

When the configuration resource is updated in the ZooKeeper quorum, this configuration instance will also be updated. In order to benefit from the updated configuration, consumers of the configuration instance should take care not to
cache the values retrieved from it.

Security

This approach assumes that all web applications on the web servers are managed by the same trusted group of people. Any web application that can reach your private ZooKeeper quorum can request any configuration source available there. If you have a ZooKeeper quorum running in your computing environment this is usually the case.

Organizing configuration files

This library currently supports only YAML as a configuration language (other languages that represent a tree of configuration parameters can be added by implementing HierarchicalConfigurationDeserializer). To provide a way to split up large configuration files, a custom YAML tag is supported.

For example, if the main configuration file is config/config.yaml:

extends:
  - defaults.yaml

settings:
  coffee: yes
  foo:
    number-of-foos: 5
    enabled: yes
  bar: !include bar/bar-settings.yaml

And these files (or nodes in the case of ZooKeeper) exist:

defaults.yaml:

settings:
  tea: yes
  milk: no
  coffee: no

bar/bar-settings.yaml:

number-of-bars: 3
enabled: yes

Then the resulting configuration tree looks like this:

extends:
  - defaults.yaml

settings:
  tea: yes
  milk: no
  coffee: yes
  foo:
    number-of-foos: 5
    enabled: yes
  bar:
    number-of-bars: 3
    enabled: yes

About

A configuration library designed as a provider of Apache Commons Configuration instances that can be updated at runtime.

Resources

License

Stars

Watchers

Forks

Packages

No packages published

Languages