File-based Configurations
Often configuration properties are stored in files on the user's hard
disk, e.g. in .properties files or as XML documents. Configuration
classes that deal with such properties need to provide typical operations
like loading or saving files. The files to be processed can be specified
in several different flavors like java.io.File
objects,
relative or absolute path names, or URLs.
To provide a consistent way of dealing with configuration files in
Commons Configuration the FileConfiguration
interface exists. FileConfiguration
defines a standard
API for accessing files and is implemented by many configuration
implementations, including PropertiesConfiguration
and
XMLConfiguration
.
In the following sections we take a closer look at the methods of the
FileConfiguration
interface and how they are used.
Specifying the file
The FileConfiguration
interface contains several
methods for specifying the file to be loaded. The following variants
are supported:
- With the
setFile()
method the data file can be
specified as a java.io.File
object.
- The
setURL()
takes a java.net.URL
as argument; the file will be loaded from this URL.
- The methods
setFileName()
and setBasePath()
allows to specify the path of the data file. The base path is
important if relative paths are to be resolved based on this file.
While a File
or a URL uniquely identify a file, the
situation is a bit ambiguous when only a base path and a file name are
set. These can be arbitrary strings (even full URLs) whose exact
meaning must be detected when the file is loaded. For this purpose
file-based configurations perform the following checks (in this
order):
- If the combination from base path and file name is a full URL
that points to an existing file, this URL will be used to load
the file.
- If the combination from base path and file name is an absolute
file name and this file exists, it will be loaded.
- If the combination from base path and file name is a relative
file path that points to an existing file, this file will be loaded.
- If a file with the specified name exists in the user's home
directory, this file will be loaded.
- Otherwise the file name is interpreted as a resource name, and
it is checked whether the data file can be loaded from the classpath.
If all these checks fail, a ConfigurationException
will
be thrown.
Loading
After the file name has been defined using one of the methods mentioned
above, the load()
method can be called. This method tries
to locate the file and open it. If this fails, a ConfigurationException
is thrown.
The FileConfiguration
interface defines multiple overloaded
load()
methods. The one that takes no argument will
always operate on the file name that has been set earlier. All
other methods allow to specify the source to be loaded. This can be
done as java.io.File
, java.net.URL
, string
(containing either an absolute or relative path), input stream, or
reader. When using these variants of the load()
method
be aware of two things:
- They do not change the configuration's file name. To do this
you have to explicitly call one of the setter methods.
- The
load()
methods do not empty the
configuration before new data is loaded. This makes it easy to
construct union configurations by simply calling load()
multiple times. But if you want to reuse a Configuration
object and load a different file, remember to call the
clear()
method first to ensure that old properties are
wiped out.
File-based configurations typically define a set of constructors that
correspond to the various setter methods for defining the data file.
These constructors will set the file and then invoke the load()
method. So creating a file-based configuration object and loading its
content can be done in a single step.
Saving
Saving is implemented analogously to loading: There is a no argument
save()
method that will use the internal file name. Then
for each load()
method a corresponding save()
method exists that will write the data contained in the configuration
to different targets.
An example for loading, manipulating, and saving a configuration
(based on a PropertiesConfiguration
)
could look as follows:
PropertiesConfiguration config = new PropertiesConfiguration("usergui.properties");
config.setProperty("colors.background", "#000000");
config.save();
You can also save a copy of the configuration to another file:
PropertiesConfiguration config = new PropertiesConfiguration("usergui.properties");
config.setProperty("colors.background", "#000000");
config.save("usergui.backup.properties);
Automatic Saving
If you want to ensure that every modification of a configuration
object is immediately written to disk, you can enable the automatic
saving mode. This is done through the setAutoSave()
method as shown in the following example:
PropertiesConfiguration config = new PropertiesConfiguration("usergui.properties");
config.setAutoSave(true);
config.setProperty("colors.background", "#000000"); // the configuration is saved after this call
Be careful with this mode when you have many updates on your
configuration. This will lead to many I/O operations, too.
Automatic Reloading
A common issue with file-based configurations is to handle the
reloading of the data file when it changes. This is especially important
if you have long running applications and do not want to restart them
when a configuration file was updated. Commons Configuration has the
concept of so called reloading strategies that can be
associated with a file-based configuration. Such a strategy monitors
a configuration file and is able to detect changes. A default reloading
strategy is FileChangedReloadingStrategy
.
It can be set on a file-based configuration as follows:
PropertiesConfiguration config = new PropertiesConfiguration("usergui.properties");
config.setReloadingStrategy(new FileChangedReloadingStrategy());
FileChangedReloadingStrategy
works as follows: On every
property access the configuration checks its associated reloading
strategy. FileChangedReloadingStrategy
will then obtain
the last modification date of the configuration file and check whether
it has changed since the last access. If this is the case, a reload is
triggered. To avoid often disk access when multiple properties are
queried from the configuration, a refresh delay can be set on
the reloading strategy. This is a time in milli seconds with the meaning
that the reloading strategy will only once check the file's last
modification time in the period specified here.
Managed Reloading
ManagedReloadingStrategy
is an alternative to automatic
reloading. It allows to hot-reload properties on a running application
but only when requested by admin. The refresh()
method
will force a reload of the configuration source.
A typical use of this feature is to setup ManagedReloadingStrategy as
a JMX MBean. The following code sample uses Springframework
MBeanExporter to expose the ManagedReloadingStrategy to the JMX
console :
<!-- A file based configuration bean -->
<bean id="configuration" class="(...).PropertiesConfiguration">
<constructor-arg type="java.net.URL" value="file:${user.home}/custom.properties"/>
<property name="reloadingStrategy" ref="reloadingStrategy"/>
</bean>
<!-- The managed reloading strategy for the configuration bean -->
<bean id="reloadingStrategy" class="...ManagedReloadingStrategy"/>
<!-- The MBeanExporter that exposes reloadingStrategy to the JMX console -->
<bean id="mbeanMetadataExporter" class="org.springframework.jmx.export.MBeanExporter">
<property name="server" ref="mbeanServer"/>
<property name="beans">
<map>
<entry key="myApp:bean=configuration" value-ref="reloadingStrategy"/>
</map>
</property>
</bean>
With this configuration, the JMX console will expose the
"myApp:bean=configuration" MBean and it's refresh operation.