Using a Configuration Factory

This section explains how a ConfigurationFactory object is setup that provides access to a collection of different configuration sources.

The configuration definition file

When a single configuration file (e.g. a properties file) is the only source of configuration data it is very simple to load it using the specific configuration class that deals with the corresponding format (e.g. PropertiesConfiguration for properties files or XMLConfiguration for XML files). But because we think that later other sources will be added (otherwise this example section would be too silly) we will use a ConfigurationFactory object to load it.

ConfigurationFactory allows to combine multiple configuration sources. The properties defined in these sources can then be accessed as if they were defined in a single configuration file. To make use of this we have to create a XML file which tells the factory from which sources the properties are to be collected. The following listing shows the content of this file:

<?xml version="1.0" encoding="ISO-8859-1" ?>

<configuration>
  <properties fileName="usergui.properties"/>
</configuration>

Definition files for ConfigurationFactory are normal XML files. The root element must be named configuration. It can contain different sub elements that specify the configuration sources to load. The properties element is one of these; it is used to include properties files.

For this example we store the definition file for ConfigurationFactory in the same directory as the properties file and call it config.xml. The properties file used in this example is the same as in the section about properties files.

Setting up a ConfigurationFactory

Now we have to create a ConfigurationFactory object and let it read this definition file. This is quite simple: Just create a new instance and set the name of the definition file with the setConfigurationFileName() method.

ConfigurationFactory factory = new ConfigurationFactory();
URL configURL = new File("config.xml").toURL();
factory.setConfigurationFileName(configURL.toString());
Configuration config = factory.getConfiguration();

As this code fragment shows the file name passed to the factory can be a full URL. This is also the recommended way of specifying the file because it provides the greatest flexibility and a consistent way of handling relative file names found in the definition file.

Here we assumed the configuration definition file to be located in the current directory. It is also possible (and probably a better approach) to load the file from the class path. This could be done as follows:

ConfigurationFactory factory = new ConfigurationFactory();
URL configURL = getClass().getResource("/config.xml");
factory.setConfigurationURL(configURL);
Configuration config = factory.getConfiguration();

Accessing properties

Whatever way we used to load the configuration factory, we should now have a Configuration object that was returned by the factory's getConfiguration() method. This object is actually an instance of the CompositeConfiguration class, a specific implementation of the Configuration interface that is able to deal with multiple contained configuration objects. Of course this class provides all the getter methods defined in the Configuration interface, so for accessing a string property for instance we would use the getString() method:

String backColor = config.getString("color.background");

Multiple configuration sources

Using ConfigurationFactory to collect configuration sources does not make much sense if there is only one source to be loaded. So let's add another one! This time we will embedd a XML file.

Overriding properties

Many applications use the popular XML format for storing configuration information. So it is no wonder that Configuration also supports this type of configuration sources. In general each XML document can be used to define configuration settings. We start here with a rather simple one:

<?xml version="1.0" encoding="ISO-8859-1" ?>
<gui-definition>
  <colors>
    <background>#808080</background>
    <text>#000000</text>
    <header>#008000</header>
    <link normal="#000080" visited="#800080"/>
  </colors>
  <rowsPerPage>15</rowsPerPage>
</gui-definition>

To make this XML document part of our global configuration we have to modify our configuration definition file to also include the new file. For XML documents the element xml can be used so that we have now:

<?xml version="1.0" encoding="ISO-8859-1" ?>

<configuration>
  <properties fileName="usergui.properties"/>
  <xml fileName="gui.xml"/>
</configuration>

The code for setting up the ConfigurationFactory object remains the same. From the Configuration object returned by the factory the new properties can be accessed in the usual way.

There is one problem with this example configuration setup: The color.background property is defined in both the properties and the XML file, and - to make things worse - with different values. Which value will be returned by a call to getString()?

The answer is that the configuration sources are searched in the order they are defined in the configuration definition file. Here the properties file is included first, then comes the XML file. Because the color.background property can be found in the properties file the value specified there will be returned (which happens to be #FFFFFF).

It might not be obvious why it makes sense to define the value of one and the same property in multiple configuration sources. But consider the following scenario: An application comes with a set of default properties and allows the user to override some or all of them. This can now easy be realized by saving the user's settings in a file and the default settings in another. Then in the configuration definition file the file with the user settings is included first and after that the file with the default values. The application code that queries these settings need not be aware whether a property was overriden by the user. The ConfigurationFactory takes care that properties defined in the first file (the user file) are found; other properties which the user has not changed will still be returned from the second file (the defaults file).

Optional configuration sources

The example above with two configuration sources - one for user settings and one with default values - raises an interesting question: What will happen if the user has not defined specific properties yet? Or what if a new user starts our application for the first time and thus no user specific properties exist?

The default behavior of ConfigurationFactory is to throw a ConfigurationException exception if one of the sources defined in the configuration definition file cannot be loaded. For our example this behavior is not desired: the properties file with specific user settings is not required. If it cannot be loaded, the example application will still work because a complete set of configuration properties is defined in the second file.

ConfigurationFactory supports such optional configuration sources. For this purpose in the definition of a (file based) configuration source the optional attribute can be placed. An example of this is shown below:

<?xml version="1.0" encoding="ISO-8859-1" ?>

<configuration>
  <properties fileName="usersettings.properties" optional="true"/>
  <properties fileName="default.properties"/>
</configuration>

In this configuration definition file the first properties file with user specific settings is marked as optional. This means that if it cannot be loaded, ConfigurationFactory will not throw an exception, but only write a warning message to its logger. Note that the optional attribute is absent for the second properties file. Thus it is mandatory, and the getConfiguration() method of ConfigurationFactory would throw an exception if it could not be found.

Union configuration

In an earlier section about the configuration definition file for ConfigurationFactory it was stated that configuration files included first can override properties in configuraton files included later and an example use case for this behaviour was given. There may be times when there are other requirements.

Let's continue the example with the application that somehow process database tables and that reads the definitions of the affected tables from its configuration. This example and the corresponding XML configuration files were introduced in the section about XMLConfiguration. Now consider that this application grows larger and must be maintained by a team of developers. Each developer works on a separated set of tables. In such a scenario it would be problematic if the definitions for all tables would be kept in a single file. It can be expected that this file needs to be changed very often and thus can be a bottleneck for team development when it is nearly steadily checked out. It would be much better if each developer had an associated file with table definitions and all these information could be linked together at the end.

ConfigurationFactory provides support for such a use case, too. It is possible to specify in the configuration definition file that from a set of configuration sources a logic union configuration is to be constructed. Then all properties defined in the provided sources are collected and can be accessed as if they had been defined in a single source. To demonstrate this feature let us assume that a developer of the database application has defined a specific XML file with a table definition named tasktables.xml:

<?xml version="1.0" encoding="ISO-8859-1" ?>

<config>
  <table tableType="application">
    <name>tasks</name>
    <fields>
      <field>
        <name>taskid</name>
        <type>long</type>
      </field>
      <field>
        <name>name</name>
        <type>java.lang.String</type>
      </field>
      <field>
        <name>description</name>
        <type>java.lang.String</type>
      </field>
      <field>
        <name>responsibleID</name>
        <type>long</type>
      </field>
      <field>
        <name>creatorID</name>
        <type>long</type>
      </field>
      <field>
        <name>startDate</name>
        <type>java.util.Date</type>
      </field>
      <field>
        <name>endDate</name>
        <type>java.util.Date</type>
      </field>
    </fields>
  </table>
</config>

This file defines the structure of an additional table, which should be added to the so far existing table definitions. To achieve this the configuration definition file has to be changed: A new section is added that contains the include elements of all configuration sources which are to be combined.

<?xml version="1.0" encoding="ISO-8859-1" ?>
<!-- Configuration definition file that demonstrates the
     override and additional sections -->

<configuration>
  <override>
    <properties fileName="usergui.properties"/>
    <xml fileName="gui.xml"/>
  </override>
  
  <additional>
    <xml fileName="tables.xml"/>
    <xml fileName="tasktables.xml" at="tables"/>
  </additional>
</configuration>

Compared to the older versions of this file a couple of changes has been done. One major difference is that the elements for including configuration sources are no longer direct children of the root element, but are now contained in either an override or additional section. The names of these sections already imply their purpose.

The override section is not strictly necessary. Elements in this section are treated as if they were children of the root element, i.e. properties in the included configuration sources override properties in sources included later. So the override tags could have been ommitted, but for sake of clearity it is recommended to use them when there is also an additional section.

It is the additonal section that introduces a new behaviour. All configuration sources listed here are combined to a union configuration. In our example we have put two xml elements in this area that load the available files with database table definitions. The syntax of elements in the additional section is analogous to the syntax described so far. The only difference is an additionally supported at attribute that specifies the position in the logic union configuration where the included properties are to be added. In this example we set the at attribute of the second element to tables. This is because the file starts with a table element, but to be compatible with the other table definition file it should be accessable under the key tables.table.

After these modifications have been performed the configuration obtained from the ConfigurationFactory will allow access to three database tables. A call of config.getString("tables.table(2).name"); will result in a value of tasks. In an analogous way it is possible to retrieve the fields of the third table.

Note that it is also possible to override properties defined in an additonal section. This can be done by placing a configuration source in the override section that defines properties that are also defined in one of the sources listed in the additional section. The example does not make use of that. Note also that the order of the override and additional sections in a configuration definition file does not matter. Sources in an override section are always treated with higher priority (otherwise they could not override the values of other sources).

Configuration definition file reference

We have seen how to write configuration definition files for including properties and XML files. This section deals with other options that can be specified in such a definition file and that are evaluated by ConfigurationFactory.

From time to time the question is raised whether there is a document type definition that exactly defines the structure of a configuration definition file. Frankly, the answer is no. This is because for a future version of Commons Configuration it is planed to make the configuration definition files extensible, i.e. allow developers to register their own tags and corresponding implementations of the Configuration interface.

In the current version the set of supported XML elements is fixed. Below is a list of all supported tags and a description of each:

properties
With this element properties files can be included. The name of the file to load is specified using the fileName attribute. Which configuration class is created by this tag depends on the extension of the file to load: If the extension is ".xml", a XMLPropertiesConfiguration object is created, which is able to process the XML properties format introduced in Java 5.0. Otherwise a PropertiesConfiguration object is created, the default reader for properties files.
xml
The xml element can be used to load XML configuration files. It also uses the fileName attribute to determine the name of the file to load and creates an instance of XMLConfiguration.
jndi
As the name implies, with this element JNDI resources can be included in the resulting configuration. Under the hood this is done by an instance of the JNDIConfiguration class. The prefix attribute can be used to select a subset of the JNDI tree.
plist
The plist element allows to embedd configuration files in the NeXT / OpenStep or Mac OS X format. Again the name of the file to load is specified through the fileName attribute. If a XML file is specified, a XMLPropertyListConfiguration object is created to process the file. Otherwise this task is delegated to a PropertyListConfiguration instance.
system
With this element an instance of SystemConfiguration is added to the resulting configuration allowing access to system properties.

All of these elements can occur in a configuration definition file in arbitrary number and order. The following listing shows an example file using many of these tags.

<?xml version="1.0" encoding="ISO-8859-1" ?>

<configuration>
  <system/>
  <jndi prefix="java:comp/env"/>
  <properties fileName="test.properties"/>
  <xml fileName="test.xml"/>
  <properties fileName="test.properties.xml"/>
</configuration>

Setting further options

Many specialized configuration classes support initialization properties that influence the behavior of their instances. For example for file based configurations the encoding of the files to load can be specified using the setEncoding() method, or an XMLConfiguration can be told to perform validation by calling the setValidating() method. How can such properties be set in a configuration definition file?

Fortunately this is easy possible. For each XML element in a configuration definition file additional attributes can be specified that correspond to (bean) setter methods defined in the associated configuration class. To derive the name of an attribute from a setter method to be called, just drop the prefix "set" and make the first letter lower case. So for instance the attribute that invokes the setEncoding() method would be encoding. The following example shows how a XML document with a certain encoding and enabled validation can be loaded:

<?xml version="1.0" encoding="ISO-8859-1" ?>

<configuration>
  <xml fileName="test.xml" encoding="UTF-8" validating="true"/>
</configuration>

Using this mechanism many properties of configuration classes can be set when they are used together with ConfigurationFactory. To find out, which attributes are supported by a specific XML element, refer to the list in the previous section that explains, which configuration classes are used for which tags. In the JavaDoc of the corresponding class you can find the setter methods you can address by attributes.

Referencing system properties

Often the configuration definition files are contained in a distribution unit like a war file that should not be manipulated after packaging. The path names these files refer to need some way of making them externally customizable so that the packaging unit can be adoped to a special environment without repackaging. One way to achieve this is to allow system properties in the file names.

ConfigurationFactory supports a simple way of adding references to system properties to the configuration definition files. Below is an example that demonstrates this feature:

<?xml version="1.0" encoding="ISO-8859-1" ?>
<!-- A test configuration file for loading a file specified by a
     system property.
-->
<configuration>
  <properties fileName="${config.file}"/>
</configuration>

In this configuration definition file the name of the properties file to be loaded is specified by means of a variable (which is marked using the typical ${} syntax). When this file is parsed the name of the variable is looked up in the set of defined system properties. So to set a concrete file name for the properties file the config.file system property must be defined (e.g. by calling System.setProperty("config.file", "myfile.properties"); or using the -D command line switch when starting your Java application).