Reading an XML Configuration File
To allow our XML-RPC classes to use our configuration file, we must create a helper class that parses the information and then makes it available to the server and clients. Although we could build this behavior into methods within the XML-RPC classes (similar to how the getHandlers( ) method was used in our LightweightServer class), using a separate class allows this class to be shared by both the clients and server, reducing duplication of code. We have already determined the information that needs to be obtained and can begin by writing a skeleton class with accessor methods for that data. The actual contents of the member variables we use will be populated by the parsing behavior we write in a moment.
Getting the Configuration Information
We could add code directly to the com.oreilly.xml.LightweightXmlRpcServer class to parse a configuration file; we could then add similar code to our XML-RPC clients that performed the same task. However, this results in a lot of duplicate code. Instead, another com.oreilly.xml utility class is introduced here: XmlRpcConfiguration. The beginnings of this class are shown in Example A; a constructor takes in either a filename or an InputStream to read XML configuration data from. Simple accessor methods are also provided to access the configuration data once it has been loaded. By isolating the input and output of the class from specific XML constructs, we can change the parsing mechanism (which we look at next) without changing our XML-RPC server and client code; this is a much more object-oriented approach than embedding XML parsing code within our server and client code.
Example A. The XmlRpcConfiguration Class to Read XML Configuration Data
package com.oreilly.xml;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.InputStream;
import java.io.IOException;
import java.util.Hashtable;
/**
*
XmlRpcConfiguration
is a utility class* that will load configuration information for XML-RPC servers
* and clients to use.
*
* @author
*
This email address is being protected from spambots. You need JavaScript enabled to view it. * @version 1.0
*/
public class XmlRpcConfiguration {
/** The stream to read the XML configuration from */
private InputStream in;
/** Port number server runs on */
private int portNumber;
/** Hostname server runs on */
private String hostname;
/** SAX Driver Class to load */
private String driverClass;
/** Handlers to register in XML-RPC server */
private Hashtable handlers;
/**
*
* This will set a filename to read configuration
* information from.
*
*
* @param filename
String
name of* XML configuration file.
*/
public XmlRpcConfiguration(String filename)
throws IOException {
this(new FileInputStream(filename));
}
/**
*
* This will set a filename to read configuration
* information from.
*
*
* @param in
InputStream
to read* configuration information from.
*/
public XmlRpcConfiguration(InputStream in)
throws IOException {
this.in = in;
portNumber = 0;
hostname = "";
handlers = new Hashtable( );
// Parse the XML configuration information
}
/**
*
* This returns the port number the server listens on.
*
*
* @return
int
number of server port.*/
public int getPortNumber( ) {
return portNumber;
}
/**
*
* This returns the hostname the server listens on.
*
*
* @return
String
hostname of server.*/
public String getHostname( ) {
return hostname;
}
/**
*
* This returns the SAX driver class to load.
*
*
* @return
String
- name of SAX driver class.*/
public String getDriverClass( ) {
return driverClass;
}
/**
*
* This returns the handlers the server should register.
*
*
* @return
Hashtable
of handlers.*/
public Hashtable getHandlers( ) {
return handlers;
}
}
With this skeleton in place, we can add JDOM parsing behavior to load the member variables with configuration data. To ensure that this information is ready when needed, we call the parsing method in the class constructor. The intent of providing these basic accessor methods is to hide the details of how the configuration information is obtained from the classes and applications that usethe information. Changes to JDOM version, or even to using an entirely different method ofaccessing the XML data, affect only this class; changes do not have to be made to the XML-RPC clients and server. This provides a highly maintainable method of getting configuration information.
Loading the Configuration Information
With our class skeleton created, we can begin outlining the details of the parsing behavior we need. In this situation, we have a simple task because we know the structure of the XML document coming in (thanks to our DTD and its constraints). Thus we can directly access the elements in the document for which we need to obtain values. The best way to think about this is as a hierarchical
tree structure; we can then "walk" the tree and obtain values for the elements we need information from. Figure B shows our XML configuration file represented in this fashion With this model in mind, it is simple to use the getChildren( ) and getChild( ) methods that JDOM provides to navigate to each of the XML elements we want to obtain data from; we can then invoke getContent( ) on the resultant elements and use those values in our application. We need to import the needed JDOM classes (and the Java support classes), create a new method to parse our configuration, and then invoke that method from the XmlRpcConfiguration constructor.
The Real World
As we continue through our topical discussions, the line between a realistic use of XML and our examples is becoming thinner. Our XML-RPC server in this article is close to being ready for production use; it has a flexible configuration file format, it registers handlers dynamically, and
maintains a lightweight structure for handling XML-RPC requests. However, the use of XML for pure data, as discussed in this article, is as new an idea as most of our other XML topics. As with RMI versus RPC, it is possible to overuse the technology. In this section, we compare XML as a data storage medium with other more traditional formats, discussing when one format is preferable over the other, as well as comparing JDOM with other solutions for accessing our underlying XML data.
XML Versus Directory Services and LDAP
Another fairly recent upstart in the technology and data space is the Lightweight Directory Access Protocol (LDAP) and directory services. From the first steps in research at Berkeley and Michigan to Netscape's now widespread Directory Server (http://www.netscape.com), LDAP has become a hot topic in its own right. With the rise of XML, there has been a fair bit of confusion as to when directory services are appropriate to use instead of XML. While directory services are well recognized as useful for company directories and integration of company-wide mail, addressing, and calendaring services, using the LDAP protocol has become popular for configuration information. Storing information about application configuration as well as about how to respond to key application events (such as authentication) is commonly handled with a directory server. This provides faster search and retrieval than a database, and the hierarchical format of most directory servers lends itself well to configuration information. With this article on XML for storing the same type of data, the question of when to use LDAP and when to use XML is particularly pertinent.
The surprising answer to this query is that the question itself is not valid! There is really not a comparison between LDAP and XML, as the two serve orthogonal purposes. Where LDAP and directory services are about making technology or components available by some specific name,
XML is about the storage and transmission of the data involved with those components. In fact, a more appropriate question is "When will LDAP and XML integrate?" The answer lies in the same technologies for XML data binding that we mentioned in regards to databases; the Castor project actually has a complete XML-to-LDAP binding. Additionally, directory services are moving towards a uniform data storage medium; XML certainly could be this medium. As the hierarchical structures of LDAP and XML are close matches, don't be surprised to see a marriage between LDAP services and XML storage.