blob: 00b0686c1df6862108ad7d716ce2148e578eab3e [file] [log] [blame]
<?xml version="1.0"?>
<!--
Licensed to the Apache Software Foundation (ASF) under one or more
contributor license agreements. See the NOTICE file distributed with
this work for additional information regarding copyright ownership.
The ASF licenses this file to You under the Apache License, Version 2.0
(the "License"); you may not use this file except in compliance with
the License. You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
-->
<document>
<properties>
<title>Configuration Factory Howto</title>
<author email="oliver.heger@t-online.de">Oliver Heger</author>
</properties>
<body>
<section name="Using a Configuration Factory">
<p>
This section explains how a
<code>ConfigurationFactory</code> object is setup that provides access
to a collection of different configuration sources.
</p>
<subsection name="The configuration definition file">
<p>
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. <code>PropertiesConfiguration</code>
for properties files or <code>XMLConfiguration</code> 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
<code>ConfigurationFactory</code> object to load it.
</p>
<p>
<code>ConfigurationFactory</code> 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:
</p>
<source><![CDATA[
<?xml version="1.0" encoding="ISO-8859-1" ?>
<configuration>
<properties fileName="usergui.properties"/>
</configuration>
]]></source>
<p>
Definition files for <code>ConfigurationFactory</code> are
normal XML files. The root element must be named
<code>configuration</code>. It can contain different sub
elements that specify the configuration sources to load. The
<code>properties</code> element is one of these; it is used to
include properties files.
</p>
<p>
For this example we store the definition file for
<code>ConfigurationFactory</code> in the same directory as the
properties file and call it <code>config.xml</code>. The
properties file used in this example is the same as in the
section about <a href="howto_properties.html">properties
files</a>.
</p>
</subsection>
<subsection name="Setting up a ConfigurationFactory">
<p>
Now we have to create a <code>ConfigurationFactory</code>
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 <code>setConfigurationFileName()</code> method.
</p>
<source><![CDATA[
ConfigurationFactory factory = new ConfigurationFactory();
URL configURL = new File("config.xml").toURL();
factory.setConfigurationFileName(configURL.toString());
Configuration config = factory.getConfiguration();
]]></source>
<p>
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.
</p>
<p>
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:
</p>
<source><![CDATA[
ConfigurationFactory factory = new ConfigurationFactory();
URL configURL = getClass().getResource("/config.xml");
factory.setConfigurationURL(configURL);
Configuration config = factory.getConfiguration();
]]></source>
</subsection>
<subsection name="Accessing properties">
<p>
Whatever way we used to load the configuration factory, we
should now have a <code>Configuration</code> object that was
returned by the factory's <code>getConfiguration()</code>
method. This object is actually an instance of the
<code>CompositeConfiguration</code> class, a specific implementation
of the <code>Configuration</code> interface that is able to
deal with multiple contained configuration objects. Of course
this class provides all the getter methods defined in the
<code>Configuration</code> interface, so for accessing a
string property for instance we would use the <code>getString()</code> method:
</p>
<source><![CDATA[
String backColor = config.getString("color.background");
]]></source>
</subsection>
</section>
<section name="Multiple configuration sources">
<p>
Using <code>ConfigurationFactory</code> 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.
</p>
<subsection name="Overriding properties">
<p>
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:
</p>
<source><![CDATA[
<?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>
]]></source>
<p>
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 <code>xml</code>
can be used so that we have now:
</p>
<source><![CDATA[
<?xml version="1.0" encoding="ISO-8859-1" ?>
<configuration>
<properties fileName="usergui.properties"/>
<xml fileName="gui.xml"/>
</configuration>
]]></source>
<p>
The code for setting up the <code>ConfigurationFactory</code>
object remains the same. From the <code>Configuration</code>
object returned by the factory the new properties can be
accessed in the usual way.
</p>
<p>
There is one problem with this example configuration setup:
The <code>color.background</code> 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 <code>getString()</code>?
</p>
<p>
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 <code>color.background</code> property can
be found in the properties file the value specified there will
be returned (which happens to be <code>#FFFFFF</code>).
</p>
<p>
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 <code>ConfigurationFactory</code> 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).
</p>
</subsection>
<subsection name="Optional configuration sources">
<p>
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?
</p>
<p>
The default behavior of <code>ConfigurationFactory</code> is to
throw a <code>ConfigurationException</code> 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.
</p>
<p>
<code>ConfigurationFactory</code> supports such optional
configuration sources. For this purpose in the definition of a
(file based) configuration source the <code>optional</code>
attribute can be placed. An example of this is shown below:
</p>
<source><![CDATA[
<?xml version="1.0" encoding="ISO-8859-1" ?>
<configuration>
<properties fileName="usersettings.properties" optional="true"/>
<properties fileName="default.properties"/>
</configuration>
]]></source>
<p>
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, <code>ConfigurationFactory</code> will
not throw an exception, but only write a warning message to its
logger. Note that the <code>optional</code> attribute is absent
for the second properties file. Thus it is mandatory, and the
<code>getConfiguration()</code> method of
<code>ConfigurationFactory</code> would throw an exception if it
could not be found.
</p>
</subsection>
</section>
<section name="Union configuration">
<p>
In an earlier section about the configuration definition file for
<code>ConfigurationFactory</code> 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.
</p>
<p>
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 <a href="howto_xml.html">XMLConfiguration</a>.
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.
</p>
<p>
<code>ConfigurationFactory</code> 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 <code>tasktables.xml</code>:
</p>
<source><![CDATA[
<?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>
]]></source>
<p>
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.
</p>
<source><![CDATA[
<?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>
]]></source>
<p>
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 <code>override</code> or <code>additional</code>
section. The names of these sections already imply their purpose.
</p>
<p>
The <code>override</code> 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 <code>override</code> tags could have
been ommitted, but for sake of clearity it is recommended to use them
when there is also an <code>additional</code> section.
</p>
<p>
It is the <code>additonal</code> section that introduces a new behaviour.
All configuration sources listed here are combined to a union configuration.
In our example we have put two <code>xml</code> elements in this area
that load the available files with database table definitions. The syntax
of elements in the <code>additional</code> section is analogous to the
syntax described so far. The only difference is an additionally supported
<code>at</code> attribute that specifies the position in the logic union
configuration where the included properties are to be added. In this
example we set the <code>at</code> attribute of the second element to
<em>tables</em>. This is because the file starts with a <code>table</code>
element, but to be compatible with the other table definition file it should be
accessable under the key <code>tables.table</code>.
</p>
<p>
After these modifications have been performed the configuration obtained
from the <code>ConfigurationFactory</code> will allow access to three
database tables. A call of <code>config.getString("tables.table(2).name");</code>
will result in a value of <em>tasks</em>. In an analogous way it is possible
to retrieve the fields of the third table.
</p>
<p>
Note that it is also possible to override properties defined in an
<code>additonal</code> section. This can be done by placing a
configuration source in the <code>override</code> section that defines
properties that are also defined in one of the sources listed in the
<code>additional</code> section. The example does not make use of that.
Note also that the order of the <code>override</code> and
<code>additional</code> sections in a configuration definition file does
not matter. Sources in an <code>override</code> section are always treated with
higher priority (otherwise they could not override the values of other
sources).
</p>
</section>
<section name="The configuration definition file">
<p>
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 <code>ConfigurationFactory</code>.
</p>
<p>
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.
</p>
<p>
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:
</p>
<p>
<dl>
<dt>properties</dt>
<dd>
With this element properties files can be included. The name of
the file to load is specified using the <code>fileName</code>
attribute. Which configuration class is created by this tag
depends on the extension of the file to load: If the extension
is ".xml", a <code>XMLPropertiesConfiguration</code> object is
created, which is able to process the XML properties format
introduced in Java 5.0. Otherwise a <code>PropertiesConfiguration</code>
object is created, the default reader for properties files.
</dd>
<dt>xml</dt>
<dd>
The <code>xml</code> element can be used to load XML configuration
files. It also uses the <code>fileName</code> attribute to
determine the name of the file to load and creates an instance
of <code>XMLConfiguration</code>.
</dd>
<dt>jndi</dt>
<dd>
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 <code>JNDIConfiguration</code>
class. The <code>prefix</code> attribute can be used to
select a subset of the JNDI tree.
</dd>
<dt>plist</dt>
<dd>
The <code>plist</code> 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
<code>fileName</code> attribute. If a XML file is specified,
a <code>XMLPropertyListConfiguration</code> object is created
to process the file. Otherwise this task is delegated to a
<code>PropertyListConfiguration</code> instance.
</dd>
<dt>system</dt>
<dd>
With this element an instance of <code>SystemConfiguration</code>
is added to the resulting configuration allowing access to
system properties.
</dd>
</dl>
</p>
<p>
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.
</p>
<source><![CDATA[
<?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>
]]></source>
<subsection name="Setting further options">
<p>
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 <code>setEncoding()</code>
method, or an <code>XMLConfiguration</code> can be told to
perform validation by calling the <code>setValidating()</code>
method. How can such properties be set in a configuration definition
file?
</p>
<p>
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 <code>setEncoding()</code> method would be
<code>encoding</code>. The following example shows how a XML
document with a certain encoding and enabled validation can be
loaded:
</p>
<source><![CDATA[
<?xml version="1.0" encoding="ISO-8859-1" ?>
<configuration>
<xml fileName="test.xml" encoding="UTF-8" validating="true"/>
</configuration>
]]></source>
<p>
Using this mechanism many properties of configuration classes can
be set when they are used together with <code>ConfigurationFactory</code>.
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.
</p>
</subsection>
</section>
</body>
</document>