Confound

Simple and solid configuration foundation for Java.
https://confound.io/
Copyright © 2018 GlobalMentor, Inc. http://www.globalmentor.com/

Configuration

A Java application normally needs to be configured with parameters appropriate for its deployment environment, such as:

  • data directory
  • number of widgets to process per for batch
  • database connection string

Accessing a Configuration

Configuration Interface

interface Configuration … {
  //access methods are from parent Parameters interface
  String getString(String key);
  public int getInt(String key);
  public boolean getBoolean(String key);
  public Path getPath(String key);
  public URI getUri(String key);
  …
}

Get a Configuration

Access a configuration instance anywhere in your program or library.

Configuration config = Confound.getConfiguration();
URI homePage = config.getUri("home.page");
String dbConnectionUrl =
    config.getString("database.connection.url");
  //optional configuration parameters supported
boolean isDebug = config.getOptionalBoolean("debug")
    .orElse(false);

Local Configurations

Instead of an inflexible global static variable, Confound uses the Concern Separation Aspect Registrar (Csar), allowing different configurations to be configured for different program contexts.

https://csar.io/

Configuring Confound

Confound Dependency

<project>
  …
  <dependencies>
    …
    <dependency>
      <groupId>io.confound</groupId>
      <artifactId>confound</artifactId>
      <version>x.x.x</version>
    </dependency>
  </dependencies>
</project>

Automatic System and Environment Configuration

By default Confound.getConfiguration() will return a Configuration instance that supports environment variables, with fallback to system properties.

Environment variable case (e.g. FOO_BAR) is handled automatically!

String dbConnectionUrl = Confound.getConfiguration()
    .getString("database.connection.url");

Setting Environment Variables

DATABASE_CONNECTION_URL="jdbc:postgresql://localhost/db"

Setting System Properties

java … -Ddatabase.connection.url="jdbc:postgresql://localhost/db"

File Configurations

Confound File Dependency

<project>
  …
  <dependencies>
    …
    <dependency>
      <groupId>io.confound</groupId>
      <artifactId>confound-file</artifactId>
      <version>x.x.x</version>
    </dependency>
  </dependencies>
</project>

Specify Configuration File

//load configuration from ~/confound-demo/config.properties
Path configPath = Paths.get(
    System.getProperty("user.home"), ".confound-demo",
    "config.properties");
//a "managed" configuration is reloaded as needed
Configuration config = new ManagedConfiguration(
    FileSystemConfigurationManager.forPath(configPath));
Confound.setDefaultConfiguration(config);

Configuration Base Filename

//configuration discovery from ~/confound-demo/config.*
//supports properties files and XML properties files by default
Path configDirectory = Paths.get(
    System.getProperty("user.home"), ".confound-demo");
Configuration config = new ManagedConfiguration(
    FileSystemConfigurationManager
        .forBaseFilename(configDirectory, "config"));
Confound.setDefaultConfiguration(config);

File Configuration Fallback

//load configuration from ~/confound-demo/config.*
Path configDirectory = Paths.get(
    System.getProperty("user.home"), ".confound-demo");
Configuration fileConfig = new ManagedConfiguration(
    FileSystemConfigurationManager //defaults to "config"
        .forDirectory(configDirectory));
//system properties and environment variables can override,
//falling back to the file configuration
Configuration config = Confound
    .getSystemConfiguration(fileConfig);
Confound.setDefaultConfiguration(config);

Resources Configuration

//com.example.Foo
//configuration discovery in resources com/example/config.*
Configuration resourcesConfig = new ManagedConfiguration(
    ResourcesConfigurationManager.forResourceBaseName(Foo.class,
        "config"));

Confound.setDefaultConfiguration(resourcesConfig);

Resources Fallback

//configuration discovery in resources com/example/config.*
Configuration resourcesConfig = new ManagedConfiguration(
    ResourcesConfigurationManager.forClass(Foo.class));
//(optional) file system override
Configuration fileConfig = new ManagedConfiguration(
    FileSystemConfigurationManager
        .forDirectory(…), resourcesConfig);
//(optional) system properties / environment variables override
Configuration sysConfig = Confound.getSystemConfiguration(
    fileConfig)
Confound.setDefaultConfiguration(sysConfig);

Pluggable File Formats

<dependency>
  <groupId>io.confound</groupId>
  <artifactId>confound-file</artifactId>
  <version>x.x.x</version>
</dependency>
<dependency>
  <groupId>io.confound</groupId>
  <artifactId>config-file-format-xml-provider</artifactId>
  <version>x.x.x</version>
</dependency>

Simplified App Configuration

  1. Include confound-app-provider dependency.
  2. Set app.data.dir in system or environment.

Configuration file will be automatically discovered in ~/appDataDir. An absolute path is also supported.

Csar Configuration

Csar can transparently supply a concern to different areas of a probgram independently.

The Confound concern for configuration is io.confound.ConfigurationConcern.

Local Map Config Concern

Configuration localConfig = new ObjectMapConfiguration(
    Map.of("database.connection.url",
        "jdbc:postgresql://localhost/other-db"));
ConfigurationConcern localConfigConcern =
    new DefaultConfigurationConcern(localConfig);

Csar.run(localConfigConcern, () -> {
  Configuration config = Confound.getConfiguration();
  String dbUrl=config.getString("database.connection.url");
});

Coming Soon…

  • JNDI support.
  • File change detection and reloading.
  • Configuration references for string-based formats.
  • String interpolation.
  • Additional types.

The original version of this presentation was shown at the SouJava Campinas Java user group meeting on 2018-10-23.

Thanks to Cesar Augusto Nogueira and those at SouJava for the meeting and invitation.