Using XML based ConfigurationsThis section explains how to use hierarchical and structured XML datasets. Hierarchical propertiesThe XML document we used in the section about ConfigurationFactory was quite simple. Because of its tree-like nature XML documents can represent data that is structured in many ways. This section explains how to deal with such structured documents. Structured XMLConsider the following scenario: An application operates on database tables and wants to load a definition of the database schema from its configuration. A XML document provides this information. It could look as follows: <?xml version="1.0" encoding="ISO-8859-1" ?> <database> <tables> <table tableType="system"> <name>users</name> <fields> <field> <name>uid</name> <type>long</type> </field> <field> <name>uname</name> <type>java.lang.String</type> </field> <field> <name>firstName</name> <type>java.lang.String</type> </field> <field> <name>lastName</name> <type>java.lang.String</type> </field> <field> <name>email</name> <type>java.lang.String</type> </field> </fields> </table> <table tableType="application"> <name>documents</name> <fields> <field> <name>docid</name> <type>long</type> </field> <field> <name>name</name> <type>java.lang.String</type> </field> <field> <name>creationDate</name> <type>java.util.Date</type> </field> <field> <name>authorID</name> <type>long</type> </field> <field> <name>version</name> <type>int</type> </field> </fields> </table> </tables> </database> This XML is quite self explanatory; there is an arbitrary number of table elements, each of it has a name and a list of fields. A field in turn consists of a name and a data type. To access the data stored in this document it must be included in the configuration definition file: <?xml version="1.0" encoding="ISO-8859-1" ?> <configuration> <properties fileName="usergui.properties"/> <xml fileName="gui.xml"/> <xml fileName="tables.xml"/> </configuration>
The additional
Because the document contains a list of tables some properties
are defined more than once. E.g. the configuration key
Multiple definitions of a property do not cause problems and are
supported by all classes of Configuration. If such a property
is queried using Object prop = config.getProperty("tables.table.name"); if(prop instanceof Collection) { System.out.println("Number of tables: " + ((Collection) prop).size()); }
An alternative to this code would be the Accessing structured properties
Okay, we can obtain a list with the name of all defined
tables. In the same way we can retrieve a list with the names
of all table fields: just pass the key
When working with such hierarchical structures the configuration keys
used to query properties can have an extended syntax. All components
of a key can be appended by a numerical value in parentheses that
determines the index of the affected property. So if we have two
We will now provide some configuration keys and show the results
of a
These examples should make the usage of indices quite clear. Because each configuration key can contain an arbitrary number of indices it is possible to navigate through complex structures of XML documents; each XML element can be uniquely identified.
Note: In earlier versions of Configuration there have been
two different Configuration classes for dealing with XML documents:
Adding new properties
So far we have learned how to use indices to avoid ambiguities when
querying properties. The same problem occurs when adding new
properties to a structured configuration. As an example let's
assume we want to add a new field to the second table. New properties
can be added to a configuration using the // Warning: This might cause trouble! config.addProperty("tables.table.fields.field.name", "size");
would not be sufficient because it does not contain all needed
information. How is such a statement processed by the
The following parts of the key are processed in exactly the same
manner. Under the selected ... <table tableType="application"> <name>documents</name> <fields> <field> <name>docid</name> <type>long</type> </field> <field> <name>name</name> <type>java.lang.String</type> </field> <field> <name>creationDate</name> <type>java.util.Date</type> </field> <field> <name>authorID</name> <type>long</type> </field> <field> <name>version</name> <name>size</name> <== Newly added property <type>int</type> </field> </fields> </table> </tables> </database>
This result is obviously not what was desired, but it demonstrates
how
If we want a different behavior, we must explicitely tell
config.addProperty("tables.table(1).fields.field(-1).name", "size"); config.addProperty("tables.table(1).fields.field.type", "int");
The first line in this fragment specifies that a new branch is
to be created for the // Add a new table element and define the name config.addProperty("tables.table(-1).name", "versions"); // Add a new field to the new table // (an index for the table is not necessary because the latest is used) config.addProperty("tables.table.fields.field(-1).name", "id"); config.addProperty("tables.table.fields.field.type", "int"); // Add another field to the new table config.addProperty("tables.table.fields.field(-1).name", "date"); config.addProperty("tables.table.fields.field.type", "java.sql.Date"); ...
For more information about adding properties to a hierarchical
configuration also have a look at the javadocs for
Union configuration
In an earlier section about the configuration definition file for
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. 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.
<?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> 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. <?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>
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
The
It is the
After these modifications have been performed the configuration obtained
from the
Note that it is also possible to override properties defined in an
|