Advertisement: Support JavaWorld, click here!

September 1999


Mail this Article
Printer-Friendly Version


More search options...
Search jCentral

Topical index
Net News Central
Developer Tools Guide
Book Catalog
Writers Guidelines
Privacy Policy


XML-Java Tutorial

Adaptive Java applications -- XML makes it possible

Create an adaptive, dynamic, and extensible messaging system using Java, XML, and the DOM

The powerful triangle of Java, XML, and the DOM (Document Object Model) provides the key for creating adaptive systems -- systems in which data is separate from behavior -- in Java, based on Internet standards. In this article, Gad builds upon more than a year's worth of design experience using these new technologies and produces a novel approach for designing a messaging system. (1,700 words)
By Gad Barnea

In the history of programming languages there has been a discernable movement towards the componentization and modularization of program behavior. The advent of object-oriented programming has allowed applications to make use of components and to define the relationships between them.

However, object-oriented applications still view and deal with data as an intrinsic part of the component (object). This can be harmful for all but the simplest applications. For example, if an object is coded to expect a certain data flavor, say account_number, recalibrating that object to expect a different flavor can be tedious work.

It would be convenient to be able to set an object's state at runtime so that it deals only with the behavioral aspects of the application (performing some mathematical operations on the data, for example). However, in such a situation, the notion of type-safety could be compromised -- if everything can legally be passed to the object's state, runtime type checking becomes pointless.

With the introduction of XML and its subsequent adoption by the major players of the software industry, data can lead its own life. An XML document is, in many ways, a database, a fact that can be exploited to build adaptive systems. In an adaptive system, careful design thought is given to isolating objects from one another and isolating data from the behavior (for example, the operations and methods) defined in the object.

To demonstrate how this works, we will design a simple messaging system that hides the communicating objects from one another and holds the data manipulated by the objects in a parallel universe -- as XML.

(To download the complete source code for this article's messaging system, see Resources.)

Adaptive systems
You can classify an adaptive system by the degree of independence its code has from data and by its resilience to change. The greater the independence and resilience, the more adaptive the system is said to be. It has long been an acknowledged shortcoming of conventional object-oriented programming that data is too tightly hard-coded into the design and implementation of objects. As a result, adaptivity is a necessary next step in software engineering.

Indeed, applications need to be able to communicate with and adapt to one another -- transparently. Moreover, compound applications (especially distributed ones) need to be designed to anticipate change -- change in their components and in the way these components interface with other applications.

On the other hand, object interrelationships should also be transparent. Objects need to rely as little as possible on one another's existence to perform their tasks. Different approaches have been proposed over the past decade to come up with an alternative to conventional object-oriented practices. Arguably, the most prominent alternative is the Demeter method, which defines strategies for an object-graph traversal (see Resources for more on the Demeter method). However, although the Demeter method defines rules for building adaptive object-oriented applications, it does not specifically concentrate on the independence of data from behavior.

In the following sections, we will examine how this independence can be achieved by employing the regular tools of the Java programming language.

An adaptive messaging system
When designing adaptive, mission-critical, server-side applications, it's important to design the application such that the logical messaging in the system is as extensible and dynamic as possible. This is important for the following reasons:

  • Separation of data from behavior: We should not hard-code the data handled by the system in any way to the application itself. Rather, the system should process data with a common behavior pattern capable of handling many data types.

  • Scalability: Scaling a server-side application requires high flexibility in the way different components handle messaging.

  • Adaptivity: The application should be able to adapt to the changing and typically heterogeneous landscape into which it will eventually be integrated.

  • Maintainability: The maintenance of the application and failure reporting can be made much simpler through an adaptive design.

The messaging system we're about to develop -- with XML and the DOM's help -- successfully addresses each of these concerns. Although simple in design, our system provides a good example for large-scale, mission-critical applications in which the four points above are major design concerns.

One final note before we begin: keep in mind that this article's example application uses IBM's XML4J XML platform. See Resources for more information.

Understanding XML and the DOM
As I mentioned earlier, you can view an XML file as a hierarchical database. Indeed, it holds data in a tree-like fashion and allows various data lookup operations to be performed. Querying XML is beyond the scope of this article, but the W3C is working on XQL (XML Query Language) and other approaches to make our system even more dynamic in nature. (See Resources for more on the W3C.)

If XML is our database, then the DOM (Document Object Model) is our object model. In effect, you can view the DOM as a tree-like data structure that fully represents an XML document.

Be aware that this is not a declared goal for the DOM. The DOM was conceived as a set of interfaces that define logical relationships between elements of an XML document -- not as any specific data structure.

The DOM defines Elements, Nodes, Attributes, and Entities, among other objects. It makes the XML document programmatically accessible not only as text, but also as an object graph -- a hierarchy of objects. For example, examine the following document (used in our example):

(You can find the complete XML file used in the example below by clicking Messaging_config.xml with Microsoft's IE 5.0 browser.)

        <CONFIGURE publisher="Customer"/>
     <EVENT type="deposit">

The <DATA> tag represents the Document element for the object's DOM (that is, the container element).

The above XML document translates into the following DOM structure:

Figure 1. DOM structure

In Figure 1, the rectangular boxes are all objects of type Node (and more specifically of type Element); the actual data (for example, checking) is a value of an Attribute node.

Message objects
Our messaging system will make use of three classes: MessageHub, MessageParticipant, and Swithboard.

The flow will typically be as follows:

  1. The MessageHub configures and initializes the MessageParticipants.

  2. A MessageParticipant sends a MessageObject to the Switchboard. In effect, the MessageParticipant does not know where it sends the actual message -- it wraps the DOM content for the message in the MessageObject, which is sent on its way.

  3. The Switchboard processes the MessageObject it receives and extracts the DOM Element that represents the actual message. The Switchboard then finds other MessageParticipants that are registered as expecting the data flavors held in this message.

  4. To each MessageParticipant so registered, the Switchboard passes the message (again, as a DOM Element) for processing.

  5. The MessageParticipant compares the DOM Element against its Master Document. The Master Document is, in effect, a container for the object's state (at least as it pertains to messaging). It holds the expected values and, optionally, gets updated with the new state.

Schematically, our system would look like this:

Figure 2. Messaging system

Let's examine the classes MessageHub, MessageParticipant, and Switchboard in more detail.

Class MessageHub
Our messaging system will need a central object -- a MessageHub -- to set up the various MessageParticipants and configure them for messaging.

Let's take a look at class MessageHub:

public class MessageHub {

   public void init(String xmlFileName);

   public void configureMessageParticipants();

   public void configureMessages();

   public void matchMessageParticipants2Documents(String hashName, Hashtable h);

   public void processMessages();

   public Vector getTypes();

   public Vector getMessageParticipants();

   public Hashtable getPublishers();

The init method reads the actual XML file (Messaging_config.xml) and constructs the MessageParticipants. It then sets the <MASTER_DOCUMENT> element (a DOM Element) for each MessageParticipant.

The data contained in the <MASTER_DOCUMENT> element configures the MessageParticipant's internal state. In our example, the <MASTER_DOCUMENT> holds data for the object's runtime name (the name by which it is known to the system) and the data types to which it subscribes:

    <RUNTIME_NAME>Account Manager</RUNTIME_NAME>

Finally, MessageHub gives each MessageParticipant a set of XML elements to be used as messages (or message templates). These are contained in the <MESSAGE> element.

    <CONFIGURE publisher="Customer"/>
    <EVENT type="withdrawal">

Every <MESSAGE> DOM Element has one (or more) <CONFIGURE> DOM elements that designate the publishers. Publishers are MessageParticipants and are known to the system through their runtime names. The <CONFIGURE> DOM Elements define which publishers are allowed to use this type of message. In the example above, only the MessageParticipant whose runtime name is Customer can issue a withdrawal event. When an event is sent, it is always sent to the Switchboard object.

After initialization, the MessageParticipants are ready to start dealing with messages.

Class MessageParticipant
As outlined above, our messaging system will need MessageParticipant objects that (surprisingly enough) participate in system-wide messaging (that is, communicate). It is important that MessageParticipants:

  • Have no knowledge of one another
  • Are able to accept and to send messages
  • Are able to process the data they receive

The first point is important because the objects participating in messaging can (and often will) change over time. We will use a Switchboard object to keep a centralized reference repository -- a registry -- of the different MessageParticipants and the data flavors in which they are interested.

Now let's look at the MessageParticipant interface:

public interface MessageParticipant {

   public void propagateToSwitchboard(Vector subscriptions);

   public void configureForMessage(Message message);

   public void processMessage(Message message);

   public void processMasterDocument(Element doc);

   public void loadMessage(int idx);

   public void send(Message message);

   public String getRuntimeName();

The MessageParticipant interface also defines a set of constants for attribute or general-element names, such as:

   public final static String RUNTIME_NAME_ELEMENT = "RUNTIME_NAME";
   public final static String CONFIGURE_ELEMENT = "CONFIGURE";

This allows us to easily maintain the evolution of the XML data structures in one central location.

Class Switchboard
The Switchboard is where messages find their destination. A MessageParticipant registers at the Switchboard and propagates the set of values found in its Master Document's <SUBSCRIBE> element to the Switchboard. The Switchboard's registry (a hashtable) outlines the connections between those values and the MessageParticipants associated with them.

public class Switchboard {
   public static void broadcast(Message msg) throws BroadcastException;
   public static void update(MessageParticipant part, Vector subscriptions);

The update() method updates the Switchboard's internal registry. The broadcast() method identifies the correct MessageParticipants that have subscribed to the XML code contained in the message, and passes the message on to them.

We now have a fully operational miniature messaging system that achieves maximum flexibility through the separation of data from behavior. This application can be used as a basis for many others. We've seen how a simple and adaptive messaging system can be created using XML, DOM, and Java. This combination promises to minimize the extent to which object-oriented programs rely on hard-coded data. The implications for this approach are important for designers of mission-critical, enterprise-scale systems.

About the author
Gad Barnea is CTO and founder of Manna Inc. At Manna, he designed the FrontMind product -- a high-end, mission-critical server for Internet relationship management that permits commercial sites to conduct online learning relationships with their customers through intelligent business rules. Gad has been building and designing high-end distributed systems for more than eight years. He is also a composer of contemporary classical music and has studied philosophy at the Sorbonne.

Tell us what you
thought of this story

-Very worth reading
-Worth reading
-Not worth reading

-Too long
-Just right
-Too short

-Too technical
-Just right
-Not technical enough



Company Name:


Home | Mail this Story | Printer-Friendly Version | Resources and Related Links

Advertisement: Support JavaWorld, click here!


Technical difficulties:
Last modified: Monday, November 01, 1999