blob: a8a44c0207e1aaa98225bfc99b51e2049c16902b [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 Basic Features</title>
<author email="oheger@apache.org">Oliver Heger</author>
</properties>
<body>
<section name="Basic features and AbstractConfiguration">
<p>
The <code>Configuration</code> interface defines a whole bunch of methods.
Implementing these methods all from scratch can be quite hard. Because of
that the <code><a href="apidocs/org/apache/commons/configuration/AbstractConfiguration.html">
AbstractConfiguration</a></code> class exists. This class serves as a
common base class for most of the <code>Configuration</code> implementations
in <em>Commons Configuration</em> and provides a great deal of the
functionality required by the interface. So for creating a custom
<code>Configuration</code> implementation this class will be a good
starting point.
</p>
<p>
In addition to base implementations for lots of the methods declared in
the <code>Configuration</code> interface the <code>AbstractConfiguration</code>
class provides some other handy and convenient features. Because this
class is at the very root of the class hierarchy in <em>Commons
Configuration</em> these features are available in most of the specific
implementations of the <code>Configuration</code> interface provided by
this library. We will cover some of these basic features in this section.
</p>
<subsection name="Handling of missing properties">
<p>
What is a configuration object supposed to do if you pass in a key to one
of its get methods that does not map to an existing property? Well, the
default behavior as implemented in <code>AbstractConfiguration</code> is
to return <b>null</b> if the return value is an object type. For primitive
types as return values returning <b>null</b> (or any other special
value) is not possible, so in this case a <code>NoSuchElementException</code>
is thrown:
</p>
<source><![CDATA[
// This will probably return null
String strValue = config.getString("NonExistingProperty");
// This might throw an exception
long longValue = config.getLong("NonExistingProperty");
]]></source>
<p>
For object types like <code>String</code>, <code>BigDecimal</code>, or
<code>BigInteger</code> this default behavior can be changed: If the
<code>setThrowExceptionOnMissing()</code> method is called with an
argument of <b>true</b>, these methods will behave like their primitive
counter parts and also throw an exception if the passed in property key
cannot be resolved.
</p>
<p>
<em>Note:</em> Unfortunately support for the <code>throwExceptionOnMissing</code>
property is not always consistent: The methods <code>getList()</code> and
<code>getStringArray()</code> do not evaluate this flag, but return an
empty list or array if the requested property cannot be found. Maybe this
behavior will be changed in a future major release.
</p>
</subsection>
<subsection name="List handling">
<p>
With <code>getList()</code> and <code>getStringArray()</code> the
<code>Configuration</code> interface defines methods for dealing with
properties that have multiple values. When a configuration source (e.g.
a properties file, an XML document, or a JNDI context) is processed the
corresponding <code>Configuration</code> implementation detects such
properties with multiple values and ensures that the data is correctly
stored.
</p>
<p>
When modifying properties the <code>addProperty()</code> and
<code>setProperty()</code> methods of <code>AbstractConfiguration</code>
also implement special list handling. The property value that is passed
to these methods can be a list or an array resulting in a property
with multiple values. If the property value is a string, it is checked
whether it contains the <em>list delimiter character</em>. If this is
the case, the string is splitted, and its single parts are added one
by one. The list delimiter character is the comma by default. It is
also taken into account when the configuration source is loaded
(i.e. string values of properties will be checked whether they contain
this delimiter). By using the <code>setListDelimiter()</code>
method you can set it to a different character. Here are some examples:
</p>
<source>
// Change the list delimiter character to a slash
config.setListDelimiter('/');
// Now add some properties
config.addProperty("greeting", "Hello, how are you?");
config.addProperty("colors.pie",
new String[] { "#FF0000", "#00FF00", "#0000FF" });
config.addProperty("colors.graph", "#808080/#00FFCC/#6422FF");
// Access data
String salut = config.getString("greeting");
List colPie = config.getList("colors.pie");
String[] colGraph = config.getStringArray("colors.graph");
String firstPieColor = config.getString("colors.pie");
</source>
<p>
In this example the list delimiter character is changed from a comma
to a slash. Because of this the <code>greeting</code> property won't
be splitted, but remains a single string. The string passed as value
for the <code>colors.graph</code> property in opposite contains the
new delimiter character and thus will result in a property with three
values.
</p>
<p>
Of interest is also the last line of the example fragment. Here the
<code>getString()</code> method is called for a property that has
multiple values. This call will return the first value of the list.
</p>
<p>
If you want to change the list delimiter character for all configuration
objects, you can use the static <code>setDefaultListDelimiter()</code>
method of <code>AbstractConfiguration</code>. It is also possible to
disable splitting of string properties at all for a Configuration
instance by calling its <code>setDelimiterParsingDisabled()</code>
method with a value of <b>true</b>.
</p>
</subsection>
<subsection name="Variable Interpolation">
<p>
If you are familiar with Ant or Maven, you have most certainly already encountered
the variables (like <code>${token}</code>) that are automatically expanded when the
configuration file is loaded. Commons Configuration supports this feature as well,
here is an example (we use a properties file in this example, but other
configuration sources work the same way; you can learn more about
properties files in the chapter <a href="howto_properties.html">Properties
files</a>):
</p>
<source>
application.name = Killer App
application.version = 1.6.2
application.title = ${application.name} ${application.version}
</source>
<p>
If you now retrieve the value for the <code>application.title</code>
property, the result will be <code>Killer App 1.6.2</code>. So per default
variables are interpreted as the keys of other properties. This is only a
special case, the general syntax of a variable name is
<code>${prefix:name}</code>. The prefix tells Commons Configuration that
the variable is to evaluated in a certain context. We have already seen
that the context is the current configuration instance if the prefix is
missing. The following other prefix names are supported by default:
<table border="1">
<tr>
<th>Prefix</th>
<th>Description</th>
</tr>
<tr>
<td valign="top">sys</td>
<td>This prefix marks a variable to be a system property. Commons
Configuration will search for a system property with the given name and
replace the variable by its value. This is a very easy means for
accessing the values of system properties in every configuration
implementation.</td>
</tr>
<tr>
<td valign="top">const</td>
<td>The <code>const</code> prefix indicates that a variable is to be
interpreted as a constant member field of a class (i.e. a field with the
<b>static final</b> modifiers). The name of the variable must be of the form
<code>&lt;full qualified class name&gt;.&lt;field name&gt;</code>. The
specified class will be loaded and the value of this field will be
obtained.</td>
</tr>
</table>
Here are some examples (again using properties syntax):
</p>
<source><![CDATA[
user.file = ${sys:user.home}/settings.xml
action.key = ${const:java.awt.event.KeyEvent.VK_CANCEL}
]]></source>
<p>
If a variable cannot be resolved, e.g. because the name is invalid or an
unknown prefix is used, it won't be replaced, but is returned as is
including the dollar sign and the curly braces.
</p>
</subsection>
<subsection name="Customizing interpolation">
<p>
This sub section goes a bit behind the scenes of interpolation and
explains some approaches how you can add your own interpolation facilities.
Under the hood interpolation is implemented using the
<code>StrSubstitutor</code> class of the <code>text</code> package of
<a href="http://jakarta.apache.org/commons/lang/">Commons Lang</a>. This
class uses objects derived from the <code>StrLookup</code> class for
resolving variables. <code>StrLookup</code> defines a simple
<code>lookup()</code> method that must be implemented by custom
implementations; it expects the name of a variable as argument and
returns the corresponding value (further details can be found in the
documentation of Commons Lang). The standard prefixes for variables we
have covered so far are indeed realized by special classes derived from
<code>StrLookup</code>.
</p>
<p>
It is now possible to create your own implementation of <code>StrLookup</code>
and make it available for all configuration objects under a custom
prefix. We will show how this can be achieved. The first step is to
create a new class derived from <code>StrLookup</code>, which must
implement the <code>lookup()</code> method. As an example we implement a
rather dull lookup object that simply returns a kind of &quot;echo&quot;
for the variable passed in:
</p>
<source><![CDATA[
import org.apache.commons.lang.text.StrLookup;
public class EchoLookup extends StrLookup
{
public String lookup(String varName)
{
return "Value of variable " + varName;
}
}
]]></source>
<p>
Now we want this class to be called for variables with the prefix
<code>echo</code>. For this purpose the <code>EchoLookup</code> class
has to be registered at the
<code><a href="apidocs/org/apache/commons/configuration/interpol/ConfigurationInterpolator.html">
ConfigurationInterpolator</a></code> class with the desired prefix.
<code>ConfigurationInterpolator</code> implements a thin wrapper over the
<code>StrLookup</code> API defined by Commons Lang. It has a static
<code>registerGlobalLookup()</code> method, which we have to call as
follows:
</p>
<source><![CDATA[
// Place this code somewhere in an initialization section of your application
ConfigurationInterpolator.registerGlobalLookup("echo", new EchoLookup());
]]></source>
<p>
Each <code>AbstractConfiguration</code> object that is created after this
line is executed will contain the new lookup class and can thus resolve
variables of the form <code>${echo:my_variable}</code>.
</p>
<p>
Each instance of <code>AbstractConfiguration</code> is associated with a
<code>ConfigurationInterpolator</code> object. This object is created by
the <code>createInterpolator()</code> method on first access of one of
the interpolation features. By overriding this method even deeper
intervention in the interpolation mechanism is possible. For instance
a custom implementation can add further lookup objects to the interpolator,
which are then only used by this configuration instance.
</p>
</subsection>
</section>
</body>
</document>