blob: 818bdc557fb15d619bdc4295bdb75b7e57622b55 [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>File-based Configurations</title>
<author email="oheger@apache.org">Oliver Heger</author>
</properties>
<body>
<section name="File-based Configurations">
<p>
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 <code>java.io.File</code> objects,
relative or absolute path names, or URLs.
</p>
<p>
To provide a consistent way of dealing with configuration files in
Commons Configuration the <code><a href="apidocs/org/apache/commons/configuration/FileConfiguration.html">FileConfiguration</a></code>
interface exists. <code>FileConfiguration</code> defines a standard
API for accessing files and is implemented by many configuration
implementations, including <code>PropertiesConfiguration</code> and
<code>XMLConfiguration</code>.
</p>
<p>
In the following sections we take a closer look at the methods of the
<code>FileConfiguration</code> interface and how they are used.
</p>
<subsection name="Specifying the file">
<p>
The <code>FileConfiguration</code> interface contains several
methods for specifying the file to be loaded. The following variants
are supported:
<ul>
<li>With the <code>setFile()</code> method the data file can be
specified as a <code>java.io.File</code> object.</li>
<li>The <code>setURL()</code> takes a <code>java.net.URL</code>
as argument; the file will be loaded from this URL.</li>
<li>The methods <code>setFileName()</code> and <code>setBasePath()</code>
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.</li>
</ul>
</p>
<p>
While a <code>File</code> or a URL uniquely identify a file, the
situation is a bit ambigous 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):
<ul>
<li>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.</li>
<li>If the combination from base path and file name is an absolute
file name and this file exists, it will be loaded.</li>
<li>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.</li>
<li>If a file with the specified name exists in the user's home
directory, this file will be loaded.</li>
<li>Otherwise the file name is interpreted as a resource name, and
it is checked whether the data file can be loaded from the classpath.</li>
</ul>
If all these checks fail, a <code>ConfigurationException</code> will
be thrown.
</p>
</subsection>
<subsection name="Loading">
<p>
After the file name has been defined using one of the methods mentioned
above, the <code>load()</code> method can be called. This method tries
to locate the file and open it. If this fails, a <code>ConfigurationException</code>
is thrown.
</p>
<p>
The <code>FileConfiguration</code> interface defines multiple overloaded
<code>load()</code> 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 <code>java.io.File</code>, <code>java.net.URL</code>, string
(containing either an absolute or relative path), input stream, or
reader. When using these variants of the <code>load()</code> method
be aware of two things:
<ol>
<li>They do not change the configuration's file name. To do this
you have to explicitely call one of the setter methods.</li>
<li>The <code>load()</code> methods do not empty the
configuration before new data is loaded. This makes it easy to
construct union configurations by simply calling <code>load()</code>
multiple times. But if you want to reuse a <code>Configuration</code>
object and load a different file, remember to call the
<code>clear()</code> method first to ensure that old properties are
wiped out.</li>
</ol>
</p>
<p>
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 <code>load()</code>
method. So creating a file-based configuration object and loading its
content can be done in a single step.
</p>
</subsection>
<subsection name="Saving">
<p>
Saving is implemented analogously to loading: There is a no argument
<code>save()</code> method that will use the internal file name. Then
for each <code>load()</code> method a corresponding <code>save()</code>
method exists that will write the data contained in the configuration
to different targets.
</p>
<p>
An example for loading, manipulating, and saving a configuration
(based on a <a href="howto_properties.html"><code>PropertiesConfiguration</code></a>)
could look as follows:
</p>
<source>
PropertiesConfiguration config = new PropertiesConfiguration("usergui.properties");
config.setProperty("colors.background", "#000000);
config.save();
</source>
<p>
You can also save a copy of the configuration to another file:
</p>
<source>
PropertiesConfiguration config = new PropertiesConfiguration("usergui.properties");
config.setProperty("colors.background", "#000000);
config.save("usergui.backup.properties);
</source>
</subsection>
<subsection name="Automatic Saving">
<p>
If you want to ensure that every modification of a configuration
object is immideately written to disk, you can enable the automatic
saving mode. This is done through the <code>setAutoSave()</code>
method as shown in the following example:
</p>
<source>
PropertiesConfiguration config = new PropertiesConfiguration("usergui.properties");
config.setAutoSave(true);
config.setProperty("colors.background", "#000000); // the configuration is saved after this call
</source>
<p>
Be careful with this mode when you have many updates on your
configuration. This will lead to many I/O operations, too.
</p>
</subsection>
<subsection name="Automatic Reloading">
<p>
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 <em>reloading strategies</em> 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 <code><a href="apidocs/org/apache/commons/configuration/reloading/FileChangedReloadingStrategy.html">FileChangedReloadingStrategy</a></code>.
It can be set on a file-based configuration as follows:
</p>
<source>
PropertiesConfiguration config = new PropertiesConfiguration("usergui.properties");
config.setReloadingStrategy(new FileChangedReloadingStrategy());
</source>
<p>
<code>FileChangedReloadingStrategy</code> works as follows: On every
property access the configuration checks its associated reloading
strategy. <code>FileChangedReloadingStrategy</code> 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 <em>refresh delay</em> 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.
</p>
</subsection>
<subsection name="Managed Reloading">
<p>
<code>ManagedReloadingStrategy</code> is an alternative to automatic
reloading. It allows to hot-reload properties on a running application
but only when requested by admin. The <code>refresh()</code> method
will force a reload of the configuration source.
</p>
<p>
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 :
<source>
<![CDATA[
<!-- 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>
]]>
</source>
With this configuration, the JMX console will expose the
"myApp:bean=configuration" MBean and it's refresh operation.
</p>
</subsection>
</section>
</body>
</document>