| <?xml version="1.0"?> |
| <!-- |
| Copyright 2004-2005 The Apache Software Foundation |
| |
| Licensed 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 and Hierarchical Structured Data 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. It also discusses using Hierarchical |
| and Structured datasets. |
| </p> |
| |
| <subsection name="The configuration definition file"> |
| <p> |
| When a single configuration file is the only |
| source of configuration data it is very simple to |
| load it using a <code>PropertiesConfiguration</code> object |
| (this is the class that handles files of this type). 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>. |
| </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 defines a large amount of methods for |
| querying properties. The most generic one is |
| <code>getProperty()</code>, which returns an object, but there |
| are lots of other methods that return other datatypes. In our |
| example the property we have defined has a string value, so we |
| would use the <code>getString()</code> method. |
| </p> |
| <p> |
| All of these methods have in common that they expect a property |
| key as argument. Here the name of the searched property must |
| be provided in exact the same way as it is contained in the |
| properties file. To obtain the value of the background color |
| property that is defined in the properties file shown earlier |
| the following code fragment can be used: |
| </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="A XML configuration file"> |
| <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> |
| (As becomes obvious, this tutorial does not bother with good |
| design of XML documents, the example file should rather |
| demonstrate the different ways of accessing properties.) |
| This XML document should be stored under the name |
| <code>gui.xml</code> in the same directory as the so far |
| created configuration files. |
| </p> |
| </subsection> |
| <subsection name="Overriding properties"> |
| <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. The following fragment shows how the |
| new properties can be accessed: |
| </p> |
| <source><![CDATA[ |
| String backColor = config.getString("color.background"); |
| String textColor = config.getString("color.text"); |
| String linkNormal = config.getString("color.link[@normal]"); |
| int rowsPerPage = config.getInt("rowsPerPage"); |
| ]]></source> |
| <p> |
| This listing demonstrates some important points of constructing |
| keys for accessing properties load from XML documents: |
| <ul> |
| <li> |
| Nested elements are accessed using a dot notation. In |
| the example document there is an element |
| <code><text></code> in the body of the |
| <code><color></code> element. The corresponding |
| key is <code>color.text</code>. |
| </li> |
| <li> |
| The root element is ignored when constructing keys. In |
| the example you do not write |
| <code>gui-definition.color.text</code>, but only |
| <code>color.text</code>. |
| </li> |
| <li> |
| Attributes of XML elements are accessed in a XPath like |
| notation. |
| </li> |
| </ul> |
| </p> |
| <p> |
| There is one problem with the example code fragement: It queries |
| the value of the <code>color.background</code> property, but |
| this is defined in both the properties and the XML file and - |
| to make things worse - with different values. Which value will |
| be returned by the corresponding 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> |
| </body> |
| |
| </document> |