Skip to content

IvanTrendafilov/Confucius

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

53 Commits
 
 
 
 
 
 
 
 
 
 

Repository files navigation

Confucius - lightweight configuration

A lightweight Java configuration library and a drop-in replacement for java.util.Properties. Confucius is the easiest way to add configuration to your application. It is licensed under the Apache License, Version 2.0.

Why use Confucius?

  • a fluent API to access key-value pairs, as well as lists
  • meticulously tested - with 84 test cases and 97% branch coverage
  • support for a powerful context-based Properties file format
  • support for the standard Java Properties file format
  • automatically load configuration from a specified Properties file or InputStream
  • use a single Properties file to wire multiple app instances via contexts
  • tiny, yet powerful - only 16K on disk
  • no XML required... unless you use Maven

Getting started

Four steps are required to get started with Confucius.

First, you need the Confucius jar file on your classpath. Confucius is available from Maven Central, so add to your pom.xml (or manually download, if need be):

    <dependency>
        <groupId>org.trendafilov.confucius</groupId>
        <artifactId>confucius</artifactId>
        <version>1.2.2</version>
    </dependency>

Second, define your configuration file. In this example, we will showcase the recommended context-based Properties format with three contexts, including the mandatory Default context. By convention, a Confucius Properties file has a .cfg extension.

Alternatively, you can supply any existing standard Java Properties file, but you will not be able to take advantage of context-driven configuration.

shop.cfg:

[Default]
slogan  = The best bagels store in town.
bagels  = plain, cinnamon raisin, chocolate

[NY]
slogan  = NY bagel place - Try them to love them.
bagels  = plain, plain /w cream cheese, whole wheat 

[SF]
slogan  = The Round Food Experience(tm).

Note: the SF context is missing the bagels key. This is intentional and will cause the value of the bagels property to be inherited from the Default context.

Third, reference the configuration keys in your code.

BagelShop.java:

package org.trendafilov.confucius.examples.bagels;

import org.trendafilov.confucius.*;

public class BagelShop {
    
    public static void main(String[] args) {
        Configurable config = Configuration.getInstance();
        System.out.println("Hello and welcome to our store. " + config.getStringValue("slogan"));
        System.out.println("Today's selection: " + config.getStringList("bagels"));
    }
}

Finally, to launch the resulting application, specify the conf.properties and conf.context system properties using the -D switch, as follows:

Referencing the NY context:

$ java -Dconf.properties=`pwd`/shop.cfg -Dconf.context=NY -cp *.jar org.trendafilov.confucius.examples.bagels.BagelShop

Hello and welcome to our store. NY bagel place - Try them to love them.
Today's selection: [plain, plain /w cream cheese, whole wheat]

Referencing the SF context:

$ java -Dconf.properties=`pwd`/shop.cfg -Dconf.context=SF -cp *.jar org.trendafilov.confucius.examples.bagels.BagelShop

Hello and welcome to our store. The Round Food Experience(tm).
Today's selection: [plain, cinnamon raisin, chocolate]

Without specifying a context:

$ java -Dconf.properties=`pwd`/shop.cfg -cp *.jar org.trendafilov.confucius.examples.bagels.BagelShop

Hello and welcome to our store. The best bagels store in town.
Today's selection: [plain, cinnamon raisin, chocolate]

Examples are available at Confucius-examples.

FAQ

Q: How do I get the documentation?
A: Ideally, you will be referencing the documentation as assisted by your IDE. If you need to look at an HTML version of the javadoc, please checkout the project and execute mvn javadoc:javadoc.

Q: I want to see configuration information in my log files. How?
A: Confucius exposes logging via SLF4J. To enable it, please place the desired binding on your classpath, as instructed here.

Q: I want to inject a Configurable instance via a dependency injection framework. How do I do this correctly?
A: DI containers should control the scope of the Configurable singleton. Therefore, please wire the InjectableConfiguration object instead of Configuration with your DI framework of choice.

Q: Please summarise how context-based Properties files work?
A: At a minimum, you must specify a Default context section. Its contents are always processed and are processed first. Each context section contains a list of key-value pairs. Additional contexts may be defined - if so, you should specify which context should be processed via the conf.context property. Please note - the values of keys which already exist in Default will be overriden. Furthermore, it is possible to define variable substitutions, including substitutions which span the Default and the user-specified context.

Q: Please explain variable substitution?
A: Sure, here is an example:

...
name            = John Smith
home.address    = 22 Main street
mailing.address = ${home.address}
...

the value mailing.address is set to be whatever the value of home.address is.
In general, you could also assign variables to other variables and there is no limit on the depth of variable references. Circular definitions are unresolvable and will be treated as literals.

Q: I need to use a standard existing Java properties file, how do I set this up?
A: There is no special setup required. Just set the conf.properties property to the file path, as usual.

Q: Why not just use java.util.Properties?
A: Confucius aims to fix a lot of the issues present in that class (extends Hashtable, no clean way to interpolate with a HashMap, doesn't use generics, manual type conversions required, and so on) and adds several powerful features, whilst still maintaining the simplicity of the Properties concept and compatibility with existing configuration files.

Q: Why NoXML? XML is much more expressive and powerful.
A: Indeed, it is! XML is a great tool for the right tasks. Nevertheless, for the vast majority of applications, XML configuration adds more complexity than value. This results in configuration files which are difficult to understand, cumbersome to update, and hard to maintain. For example, if we were to translate the Confucius properties file from the example above to XML, we might end up with something like this:

config.xml:

<configuration>
    <Default>
        <property name="slogan">
            <value>The best bagels store in town.</value>
        </property>
        <util:list name="bagels">
            <value>plain</value>
            <value>cinnamon raisin</value>
            <value>chocolate</value>
        </util:list>
    </Default>
    <NY>
        <property name="slogan">
            <value>NY bagel place - Try them to love them.</value>
        </property>
        <util:list name="bagels">
            <value>plain</value>
            <value>plain /w cream cheese</value>
            <value>whole wheat</value>
        </util:list>
    </NY>
    <SF>
        <property name="slogan">
            <value>The Round Food Experience(tm).</value>
        </property>
        <util:list name="bagels"> <!-- no inheritance -->
            <value>plain</value>
            <value>cinnamon raisin</value>
            <value>chocolate</value>
        </util:list>
    </SF>
</configuration>

Even in this trivial example, the corresponding XML file has grown notably large. Confucius aims to capture the 90% case and save you time.

Support, questions, contributions

Please open a ticket and we will discuss.

Contributors

  • Bartłomiej Dudała @bartlomiej-dudala. Work on support for InputStreams in InjectableConfiguration.