Skip to content.

Sections
Home » Resource Center » Real-World Decision Support (RWDS) Journal » July 2002 - Volume 1, Issue 16 » Configuration Variable Capture Using Java and XML

Configuration Variable Capture Using Java and XML

 

by Manoj Sharma

Abstract

This article shows how XML can be used to capture configuration variable information, to facilitate application systems integration and deployment. Taking a sample Risk Management System with several component applications that need to be integrated as an example, the article shows how XML is well suited to encapsulate the configuration metadata. The article proceeds to show how simple parsing Programs based on the SAX and DOM interface and Data Binding can be used, to extract the configuration information from the XML file, and populate the desired configuration files with the relevant configuration variables. It then goes on to show how Data Binding can be used to achieve programmatic configuration setup, and modification of the same XML file. The Data Binding Utility used to illustrate Data Binding and its application in configuration management is Java Architecture for XML Binding (JAXB). The article concludes by listing the advantages and disadvantages of the XML approach to Configuration Management, and its impact on the role of the Application Systems Integration Engineer. The simple prototype explained in the article can be used as the foundation of a more sophisticated Software Configuration Management tool and the target audience for this article would be anyone involved in, or with an interest, in Software Applications Systems Integration and Java/XML related development and testing.

Introduction

In this article, a case is made for the capture of configuration variable data using XML, to facilitate application Systems Integration and Deployment. An XML based approach for managing configuration variables, and the advantages and disadvantages of such an approach are discussed, with the help of simple example implementations using Java and XML.

Application Integration Example

For the purposes of this article, consider a Risk Management System, which needs to be setup at a client site. The System has several applications (implemented on different platforms and using different languages) that need to be integrated at the client site. Amongst other things, a host of configuration variables and a number of different startup scripts would need to be managed by the Integration Engineer. In most cases, the configuration variables and the startup scripts would have dependencies on each other, and the startup scripts may need to be run in a certain order to enable all the applications within the System to run in synchronization.

Let us say our system has the following Applications - A Core Application Engine (CAE), a Data Server (DS), an Aggregation Engine (AE), a Data Warehouse (DW) and a few miscellaneous units like a Mapping Engine (ME) all of which need to be setup and run in a specific order and configuration.

Typically, the configuration variable information for these different applications would be stored in different configuration files depending on the platform they are being implemented on. For e.g. the .env and .cshrc files if using a UNIX System. In addition, there could be custom configuration files that are platform independent. Also depending on the platform there would be either batch/shell startup scripts for each of these applications. In most real world application deployment cases, considerable end user knowledge is required to setup and start a relatively complex System with multiple applications of this nature. It would entail setting up the relevant configuration variables in the appropriate configuration files and running the startup scripts in the right order. Further, any changes to be made in the configuration would require at the very least manual removal or modification of these configuration variables. More often than not there are dependencies within the applications and the modification of the configuration variables may not be an intuitive or simple task and will require a fairly in-depth knowledge of the system operation.

We will demonstrate with the use of a few simple programs how XML can be used to capture the structure and content of the different configuration variables.

Let us consider our sample Risk Management System once again. Take a few moments to study Table 1, which shows a listing of the Applications contained within and the configuration files, configuration variables and startup scripts that are needed by each of these Applications.

Consider the following Application configuration variable information for our Risk Management System (RMS)

PRODUCT CONFIGURATION FILE(S)
(NAME AND PATH)
CONFIGURATION VARIABLES
CoreApplicationEngine(CAE) ROOT/CoreApplicationEngine/.caerc CAE_HOME
CAEM_PATH
DataWarehouse(DW) ROOT/DW/.env LD_LIBRARY_PATH
DW_HOME
RMS_HOME
ROOT/DW/.cshrc DW_DIR
DataServer(DS) ROOT/DS/cfg/dsconfig DB_TYPE - Sybase etc
DB_NAME
PORT_1
PORT_2
HOSTNAME
ROOT/DS/.env

DB_NAME
PORT_1(to have the same default value in all cases)
PORT_2

MappingEngine(ME) ROOT/ME/cfg/meconfig PORT_1 (to have the same default value in all cases)
DB_NAME
DB_TYPE

Table 1. Product and Configuration Variable Information for the Sample Risk Management System

A study of Table 1. shows that there are dependencies between the configuration variables. For e.g.. PORT_1 needs to have the same value in three configuration files. Also, any changes in the configuration would necessitate the removal of configuration variables for e.g.. if the System were to be (temporarily) run without the Mapping Engine(ME) (i.e. not to be uninstalled, but simply not used in the new configuration) the configuration variables associated with it would need to be deleted. Any new Applications to be integrated would also entail at the very least addition of new configuration variables, which in turn may be linked to some of the existing variables.

XML Configuration Files

While any text file like a comma separated value (csv) file can be used to store the configuration information shown above, a brief look at the table above shows that it has a structure of its own. XML lends itself very well to structuring such content as configuration variable metadata. Further, XML is platform and language independent, and it is therefore possible using the XML file, to link together applications written in different languages for different platforms, using a Configuration Manager implemented using Java and XML technology. An interesting point regarding the use of XML configuration files is that they lend themselves well to remote configuration management.

A DTD (configuration.dtd) is suggested in Listing 1. to capture the structure of the configuration information shown in Table 1. The "productlist" element corresponds to the list of products listed above and it can contain one or more products that correspond to the "product" elements. Each product has a configuration, which in turn can contain one or more configuration files corresponding to the "configfile" elements. Each configuration file can contain a set of configuration variables viz. the "cfgvariables" element, which in turn contains one or more configuration variables corresponding to the "variable" elements. Each variable has a variable name "vname" element and a variable value "vvalue" element.

The "product", "configfile" and "variable" elements have attributes associated with them. These attributes uniquely identify each product, configuration file and variable respectively within their respective contexts.

Listing 2. is an outline of the actual XML file (configuration.xml) that is generated based on configuration.dtd (Listing 1.)and encapsulates the information shown in Table 1. above.

<!ELEMENT productlist (product)+>
<!ELEMENT product (configuration)>
<!ATTLIST product pname CDATA #REQUIRED>

<!ELEMENT configuration (configfile)+>

<!ELEMENT configfile (cfgvariables)>
<!ATTLIST configfile fname CDATA #REQUIRED>

<!ELEMENT cfgvariables (variable)+>

<!ELEMENT variable (vname,vvalue)>
<!ATTLIST variable number CDATA #REQUIRED>

<!ELEMENT vname (#PCDATA)>
<!ELEMENT vvalue (#PCDATA)*>

Listing 1. The DTD (configuration.dtd) for the Configuration Variable data

<?xml version="1.0" encoding="UTF-8" ?>

<!DOCTYPE productlist SYSTEM "configuration.dtd">

<productlist>

<product pname="CoreApplicationEngine">

<configuration>

<configfile fname="C:\\CoreApplicationEngine\\.caerc">

<cfgvariables>

<variable number = "1">

<vname> CAE_HOME </vname>

<vvalue> valuevariable11 </vvalue>

</variable>

<variable number = "2">

<vname> CAEM_PATH </vname>

<vvalue> valuevariable12 </vvalue>

</variable>

</cfgvariables>

</configfile>

</configuration>

</product>

<product pname="DataWarehouse">

<configuration>

<configfile fname="C:\\DW\\.cshrc">

<cfgvariables>

<variable number = "1">

<vname> DW_DIR </vname>

<vvalue> valuevariable21 </vvalue>

</variable>

</cfgvariables>

</configfile>

<configfile fname="C:\\DW\\.env">

<cfgvariables>

<variable number = "1">

<vname> LD_LIBRARY_PATH </vname>

<vvalue> valuevariable22 </vvalue>

</variable>

<variable number = "2">

…..

….

</variable>

<variable number = "3">

……

……

</variable>

</cfgvariables>

</configfile>

</configuration>

</product>

….

….

 

</productlist>

Listing 2. The outline of the XML file (configuration.xml) based on configuration.dtd

The configuration information of our System as shown in Table 1. is captured by configuration.xml shown in Listing 2. The dependency information between the configuration variables and the configuration files containing them is captured by the XML document, and all such checks are now made automatically within the XML file ,without any checking required by the Integration Engineer at the time of Integration.

Configuration Management using DOM and SAX based Parsers

Using the above configuration.xml file based on configuration.dtd we proceed to demonstrate two simple applications BasicDOM.java (Outline in Listing 3.), BasicSAX.java (Outline in Listing 4.) based on the DOM and SAX interface using the Apache Xerces Java parser for XML. These programs extracts the configuration variable information from the XML file shown above, populates the desired configuration files with the relevant configuration variables and their appropriate values and also makes a conditional check for the PORT_1 variable and ensure that it has the required value. Using a relatively simple set of programs as the one shown below, it is apparent that the onus on the Integration Engineer to configure the System is considerably reduced. All that he/she has to do, is modify a single XML file if the need to change a "Variable" value or add a "Product" arises.
All the Java Programs listed below have been implemented on the Java 2 Platform, SE v 1.4.0.

public class BasicDOM {

//Global variable(s)

RandomAccessFile File1;

 

public BasicDOM (String xmlFile){

 

DOMParser parser = new DOMParser();

 

// Parse the Document

// and traverse the DOM

try {

parser.parse(xmlFile);

Document document = parser.getDocument();

traverse (document);

} catch ……

//Error Handling logic

}

}

 

// Traverse DOM Tree recursively

private void traverse (Node node) {

try{

int type = node.getNodeType();

 

//Start of Core Element Node Processing Logic

if (type == Node.ELEMENT_NODE) {

if ((node.getNodeName()).equals("cfgvariables")) {

int length = (node.getChildNodes()).getLength();

String FileNameandPath = // Value of “fname” attribute of configfile

for (int i =0; i < length; i++) {

// Check the value of the "number" attribute of the "variable" node

// If it equals "1" open the RandomAccessFile

File1 = new RandomAccessFile(FileNameandPath, "rw");

}

// Loop until all the "variable" child nodes have been written

// to the RandomAccessFile just opened

for (int j =0; j < innerlength; j++) {

//Store the values of the “vname” and “vvalue”

//nodes in a string “TheNodeValue”

}

// Write to the specified configuration file

if (TheNodeName.equals("vname")) {

File1.writeBytes(TheNodeValue);

File1.writeBytes("=");

}

if (TheNodeName.equals("vvalue")) {

File1.writeBytes(TheNodeValue);

File1.writeBytes("\n");

}

……

……

}// End of Core Element Processing Logic

……

……

NodeList children = node.getChildNodes();

if (children != null) {

for (int i =0; i< children.getLength(); i++)

traverse (children.item(i));

}

} catch (

……

}

}//end of traverse method

 

// Main Method

public static void main (String[] args) {

BasicDOM basicDOM = new BasicDOM (args[0]);

}

}

Listing 3. Outline of the BasicDOM program logic to parse configuration.xml based on the DOM Interface

As seen in Listing 3. the recursive "traverse" method forms the core of the BasicDOM program. It contains all the relevant logic required to traverse the XML document and write the appropriate configuration information to the relevant configuration files.

public class BasicSAX extends DefaultHandler {

//Global Variables

String GlobalFileName;

RandomAccessFile File1;

……

 

/** The BasicSAX Constructor

* @param xmlFile The URI of the configuration.xml file to be parsed

*/

 

//Constructor

public BasicSAX (String xmlFile) {

// Create a new SAX Parser

SAXParser parser = new SAXParser();

//Set a Content Handler

parser.setContentHandler(this);

//Set the Error Handler

parser.setErrorHandler(this);

//parse the XML file

try {

parser.parse(xmlFile);

} catch

//Error Handling Logic

……

}

}

// Event Handlers

 

/** Custom Implementation of the startElement method provided by DefaultHandler

* The GlobalFileName variable is initialised with the value of the "fname" attribute

* A RandomAccessFile is opened using the value stored in the GlobalFileName variable

*/

 

// Start the Event Handler

public void startElement(String uri, String local, String qname, Attributes atts) {

try {

// Logic introduced here to store the name of the Configuration File Name and Path

// and open it when the first configuration variable (“number” = 1) to be written is

// encountered

……

……

//Logic introduced here to capture the name of the element for later processing

ElementName = new String(local);

}catch (FileNotFoundException e) {

……

}

}

/** Custom Implementation of the characters method provided by DefaultHandler

* The Configuration Files are populated with the configuration variables indicated

* by the content of the "vname" nodes and their corresponding values indicated by

* the values of the "vvalue" nodes

*/

 

// Character Scanner

public void characters(char ch[], int start, int length) {

try {

String str = new String(ch, start, length);

//Logic introduced to write the configuration information to the Configuration file opened in “StartElement”

……

}

}catch (IOException e) {

System.err.print(e);

}

}

 

/** This method provides a command line entry to the BasicSAX program

* @param args The URI of the XML file to be parsed

*/

 

// Main Method

public static void main (String[ ] args) {

 

BasicSAX basicSAX = new BasicSAX (args[0] );

}

}

Listing 4. Outline of the BasicSAX program logic to parse configuration.xml based the SAX interface.

The bulk of the Configuration Variable processing logic in BasicSAX.java is contained in the overridden "characters" event handler method wherein the node values corresponding to the "vname" and "vvalue" elements are written out to the appropriate configuration file.

Data Binding

Parsing XML documents at the level of the SAX or DOM interface rapidly tends to become a tedious chore. Using SAX or DOM parsers ,there is a level of indirection, which makes the code relatively complex. For example, it would be preferable to say Variable.getNumber() rather than saying something like Node.getAttributes().getNamedItem("number").getNodeValue(), which is usually the case in DOM. This is achieved by using Data Binding. XML Data Binding is the binding of XML documents to objects designed especially for the data in those documents. This allows applications (usually data-centric) to manipulate data that has been serialized as XML in a way that is more natural than using DOM or SAX. The Data Binding Utility we use is JAXB (Java Architecture for XML Binding), which provides a schema compiler and a run-time framework, which supports a two-way mapping between XML documents and Java Objects. We define a Binding Schema configuration.xjs (Listing 5.)using the configuration.dtd and compile this schema to generate schema classes. These classes form the basis of ConfigurationApp.java (Outline in Listing 6.), which is an application that does what BasicSAX/BasicDOM achieved albeit in a much simpler manner using Data Binding techniques.

<?xml version="1.0" encoding="ISO-8859-1" ?>

 

<xml-java-binding-schema version="1.0-ea">

<element name="productlist" type="class" root="true">

<content>

<element-ref name="product"/>

</content>

</element>

<element name="product" type="class">

<content>

<element-ref name="configuration"/>

</content>

<attribute name="pname"/>

</element>

<element name="configuration" type="class">

<content>

<element-ref name="configfile"/>

</content>

</element>

<element name="configfile" type="class">

<content>

<element-ref name="cfgvariables"/>

</content>

<attribute name="fname"/>

</element>

<element name="cfgvariables" type="class">

<content>

<element-ref name="variable"/>

</content>

</element>

<element name="variable" type="class">

<content>

<element-ref name="vname"/>

<element-ref name="vvalue"/>

</content>

<attribute name="number"/>

</element>

<element name="vname" type="value"/>

<element name="vvalue" type="value"/>

</xml-java-binding-schema>

Listing 5. The Binding Schema(configuration.xjs) used by the JAXB Schema compiler based on configuration.dtd

By running the schema compiler supplied with JAXB on the above binding schema (configuration.xjs) and the DTD it is derived from (configuration.dtd) we get the source code for Java objects corresponding to the elements defined in the DTD viz. Productlist.java, Product.java, Configfile.java, Configuration.java, Cfgvariables.java and Variable.java. On compiling the source code we get the classes corresponding to these objects. A complete listing of the source code for these objects can be found in the in the XMLMeta.zip file in the Resources Section.

public class ConfigurationApp {

 

//Global variable(s)

static RandomAccessFile File1;

public static Productlist firstOne = new Productlist();

public static Productlist secondOne = new Productlist();

/** This method builds the content trees corresponding to each of the Productlist class

* instances by unmarshalling the XML document

*/

public static void buildTrees() throws Exception {

 

File first = new File("configuration.xml");

FileInputStream fln = new FileInputStream(first);

 

try {

//Content Tree corresponding to firstOne built by unmarshalling the XML document

firstOne = Productlist.unmarshal(fln);

} finally {

fln.close();

}

}

 

/** This method accesses and modifies the content trees as desired */

 

public static void accessContent() throws Exception {

 

List firstProductList = firstOne.getProduct();

for (ListIterator i = firstProductList.listIterator(); i.hasNext(); ) {

Product product = (Product)i.next();

//Logic to drill down to the “vname” and “vvalue” elements

// and write the configuration variable information stored in them to

// to the Configuration File opened

……

……

}

}

 

/** This method ensures the content tree (after modification) is valid with

* respect to the DTD

*/

 

public static void validateTrees() throws Exception {

firstOne.validate();

}

 

/** The content tree is marshalled to a new XML document */

 

public static void marshalTrees() throws Exception {

……

……

}

 

public static void main(String args[ ] ) throws Exception {

 

buildTrees();

accessContent();

validateTrees();

marshalTrees();

 

}

}

 

Listing 6. Outline of the ConfigurationApp program logic based on JAXB.

The Java objects obtained by running the Schema Compiler form the basis for the ConfigurationApp program. The ConfigurationApp program contains the methods to

  • · Unmarshal the XML document into a content tree and instantiate the classes to build a content tree (if only the DTD is available) buildTrees()
  • · Access the content of the content Trees accessContent()
  • · Validate the content tree against the DTD validateTrees()
  • · Marshal the content trees to a new XML document marshalTrees()

The accessContent() method contains the core configuration file management logic wherein the content tree is accessed (and modified as desired) and the information is used to populate the relevant Configuration files with the appropriate configuration variable names and values.

Using our approach so far, the Integration Engineer no longer has to modify several configuration files on different platforms and/or client Machines. Instead he has to simply modify a single XML file, which supplies the different configuration variables, and their respective Files along with their Locations in the File System. The Application logic then calls upon the relevant parser or Data Binding Logic, which populates the appropriate files, with the relevant configuration variables. However, in the event that changes need to be made to the System (say a new product needs to be added or a Product name is changed) ,the above approach places the onus of creating and modifying the XML file to reflect these changes, on the Integration Engineer or the client. In a relatively simple example such as ours, it is not too difficult a task but in more complex Real Time systems, which need Application configuration more rapidly, and/or on a larger scale it would be preferable to achieve the same programmatically. We can use Data Binding to replace the tedious chore of manually building XML documents tag by tag as illustrated by ExtConfigurationApp.java (Outline in Listing 7). ExtConfigurationApp.java modifies the configuration.xml file by changing the name of the "DataWarehouse" product to "NewDataWarehouse" and adds a new product "TrialProduct" to the list of products, which are to be integrated automatically. The modified XML file new_configuration.xml is then used as the input for the configuration logic.

public class ExtConfigurationApp {

 

//Global Variable(s)

static RandomAccessFile File1;

public static Productlist firstOne = new Productlist();

public static Productlist secondOne = new Productlist();

/** This method builds the content trees corresponding to each of the Productlist class

* instances by unmarshalling the XML document for the first instance "firstOne"

* and Instantiation in the case of the second instance "secondOne"

*/

public static void buildTrees() throws Exception {

 

File first = new File("configuration.xml");

FileInputStream fln = new FileInputStream(first);

 

try {

//Content Tree corresponding to firstOne built by unmarshalling the XML document

firstOne = Productlist.unmarshal(fln);

//Content Tree corresponding to secondOne built by Instantiation

List secondProductList = secondOne.getProduct();

Product newProduct = new Product();

newProduct.setPname("TrialProduct");

secondProductList.add(newProduct);

……

} finally {

fln.close();

}

}

 

/** Append content trees

* The second content tree created by Initialization is appended to the first one.

*/

public static void appendTrees() {

List firstProductList = firstOne.getProduct();

List secondProductList = secondOne.getProduct();

firstProductList.addAll(secondProductList);

}

 

/** This method accesses and modifies the content trees as desired

* It also populates the Configuration files with the relevant Configuration variables

*/

public static void accessContent() throws Exception {

 

List firstProductList = firstOne.getProduct();

for (ListIterator i = firstProductList.listIterator(); i.hasNext(); ) {

Product product = (Product)i.next();

// Logic to rename the “DataWarehouse” Product to “NewDataWarehouse”

……

}

for (ListIterator i = firstProductList.listIterator(); i.hasNext(); ) {

Product product = (Product)i.next();

//Logic to drill down to the “vname” and “vvalue” elements

// and write the configuration variable information stored in them to

// to the Configuration File opened

……

 

}

}

 

/** This method ensures the content trees (after modification) are valid with

* respect to the DTD

*/

public static void validateTrees() throws Exception {

firstOne.validate();

secondOne.validate();

}

 

/** The content trees are marshalled to new XML documents */

public static void marshalTrees() throws Exception {

……

}

 

public static void main(String args[ ] ) throws Exception {

 

buildTrees();

appendTrees();

accessContent();

validateTrees();

marshalTrees();

 

}

}

 


Listing 7. Outline of the ExtConfigurationApp program logic (extension of the ConfigurationApp program)

While the overall structure of ExtConfigurationApp.java is very similar to ConfigurationApp.java(Listing 6.), it contains an additional appendTrees() method, which is called before the accessContent() method to incorporate the additional Product "TrialProduct" which needs to be integrated into the existing system. The accessContent() method also contains additional logic to change the "DataWarehouse" Product Name to "NewDataWarehouse".

Pros and Cons of the XML Approach

This article has shown how configuration variable information can be captured in an XML file and how XML parsers based on the DOM and SAX interface and Data Binding can be used to integrate different Applications. Using this approach any changes in the setup configuration would automatically get picked up by the relevant configuration files.

The primary benefits of the XML Approach are:

  • It also allows for a greater decoupling of the application logic from the configuration variable aspects enabling rapid application deployment in the face of ongoing development. This would be of greater importance within development teams where you have a team of System Engineers testing a product while development is still in progress.
  • The human readability of XML documents makes manual intervention possible and relatively easy, if the need arises.
  • Decoupling of Configuration Variable Metadata from configuration variable information (the actual configuration data) is an added benefit, especially in more complex Systems.
  • Using XML based technologies like Data Binding, SOAP etc it is possible to convert and transmit the data in XML documents into objects, which can then form the basis for more complex Configuration Servers facilitating more complex configuration issues like, real time configuration variable access over networks in more complex systems which is becoming increasingly important in a 24x7 world.
  • With the increasing acceptance of XML as the de-facto standard for inter-application data transfer, the number of software tools/utilities to parse, convert, serialize and transform XML documents has grown manifold making it a preferred medium for data transfer. This is especially useful in applications requiring remote configuration or setup in real time over a network.

Limitations

  • The above approach may not be necessary and indeed be counter productive in simple Application Integration Systems. Most XML parser code is bulky and DOM parsers can be slow and memory intensive and for Systems requiring little or no configuration the above approach would be overkill.

Conclusion


With an ever-increasing number of software applications and legacy systems, it is impractical if not impossible to reengineer all of them to facilitate System Integration and Data Transfer. XML facilitates the decoupling of Application Logic from Integration Issues that might arise from such complex system integration needs. Using XML parsers and Data Binding Utilities, we have shown how it is possible for a client to configure a system with many different Applications, without requiring an in-depth knowledge of the system and its workings on his/her part. While this article is not intended to be exhaustive, it strives to show how a judicious use of XML and Java can help ease the burden on the Application Systems Integration Engineer.

Resources


Manoj Sharma is a Software Architect with more than six years professional experience in the IT Industry in various development and consulting roles. He is also a regular contributor to Industry Magazines and Trade Journals and can be reached at sharma.manoj@rogers.com .