Skip to main content

Building an XML-based message server

An illustrative example of an XML-based message server

George Franciscus is a technical and management consultant based in Toronto, who works with Java, XML, WebSphere, and Lotus Domino on multitier projects. George is a Sun Certified Java Programmer, IBM Certified Developer - XML and Related Technologies, R5 R4 Principle Domino Developer, R5 R4 Principle Domino Administrator, and Microsoft Certifed Professional. You can contact George at george.franciscus@nexcel.ca.

Summary:  This article shows how to code a lightweight, transport-protocol-agnostic, XML-based message server that not only allows clients to place and pick up messages on queues, but also transform messages using XSL. Written in the Java language, eight code listings take you from opening a client connection to invoking XSL transformations on messages.

Date:  01 Nov 2001
Level:  Introductory
Activity:  1418 views

Messaging has become a popular strategy to solve business problems concerning communication between homogeneous and heterogeneous hosts. Let's take the classic supplier-purchaser relationship. A purchaser wants to place an electronic order with a supplier anytime, day or night. However, the supplier's computer may not have around-the-clock support or share a compatible platform. Messaging is an excellent solution to the problem.

Using messaging, the purchaser sends the supplier a message containing order information. Since the supplier may not be online when the purchaser sends the message, the message is sent to a repository that stores the message until the supplier is ready to ask for it. Upon picking up and processing the order, the supplier sends a confirmation message to the purchaser by depositing a message in the repository. The purchaser checks the repository from time to time to get a confirmation message from the supplier. The software that manages this repository is the message server. If you are thinking that this sounds an awful lot like a message broker such as IBM's MQSeries, you're right. The topic of this article is to build a simplistic XML-based message server that mimics some of the functionality found in MQSeries.

The postmaster analogy

Many technology concepts find their roots in everyday occurrences, and messaging is no exception. A simple post office example does a fine job of illustrating the processes that occur in a message server. Consider the following scenario. You want to send a message to someone. You jot down your message on a piece of paper and stuff it in an addressed envelope. You then send your letter, which now consists of the addressed envelope and the message inside, to the post office. After your letter makes its way through the door of the post office, the postmaster will look at the address information of the envelope and place it in the appropriate slot. The letter will sit there until someone picks it up. The receiver of the letter will walk up to the post office and ask the postmaster for a letter in the desired slot.

Let's review roles and responsibilities. The post office is responsible for receiving a request and delegating the management of the letter to the postmaster. In our project, the post office is the message server and the postmaster is the queue manager. The slot that holds the letter is the queue. The letter consists of the envelope and the message. In our circumstance the envelope can be considered equivalent to the message header, while the address is the queue name. The content of the letter is called the payload. A container, another concept I'll introduce, is simply a convenient way to grab all the queues at once.


Application architecture

Let's put the analogy aside and have a look at Figure 1, which illustrates the architecture of the message server. The MessageServer detects a socket connection from the client. It then delegates the reading of the socket and the placement of the message into the appropriate queue to the QueueManager. To free up the receiving port, the Java network API reassigns the port to an available port. The MessageServer object creates a QueueManager thread, passing it the client's socket object and the container. Now the QueueManager is in charge.


Figure 1. Message server architecture
Message server architecture

The QueueManager reads from the socket to obtain the complete message from the client. It then builds a message object using the byte stream passed by the client. From this point forward, all manipulation of the message is done through the Message object. The QueueManager inspects the object to discover the messageId, queueName, and the command. The command specified by the client tells the QueueManager what to do next. A PUT command instructs the QueueManager to place the message on the queue using the queueName specified by the client. The client-defined message ID will serve as the key for subsequent message retrievals. A GET command is used by the client to request message retrieval. A DEL command removes all messages from the queue.

The message is composed of two parts, a header and a body. The header section contains metadata for the entire message. These header fields are statusCode, command, queueName, messageId, and processingRule. The body section contains just one field, payload.


The power of XML

In message servers that are not XML based, there is no practical limitation to the message size. However, the client and the server must agree on the size of the header section and the size of the fields it contains. XML can eliminate this inflexibility. When the message is built as XML, an XML parser can be used to extract the content of message fields without regard to the size of the content. Therefore, there are no programming changes required if the message ID must be lengthened to ensure uniqueness. It also means that new fields can easily be added to the header without impacting messages already stored in the queue.

This message server supports an XML payload. An XML format can easily support payload transformations by allowing the client to request XSL transformations. Clients can now request a subset of the payload to minimize download times, or perhaps retrieve the data sorted. The server can expand its collection of transformation rules by adding additional XSL programs. In our server, the client is required to provide the XSL file name. Adding a new transformation rule is as easy as dropping an XSL program into a directory.

A typical message might look something like Listing 1.

<message>
   <header>
      <status>OK</status>
      <command>GET</command>
      <queueName>inbound</queueName>
      <processingRule>sortinvoice</processingRule>
      <messageId>0000001</messageId>
   </header>
   <payload>
      <orders>
         <order>
            <itemNumber>83726</itemNumber>
            <quantity>2</quantity>
            <price>10.00</price>
         </order>
         <order>
            <itemNumber>83432</itemNumber>
            <quantity>2</quantity>
            <price>10.00</price>
         </order>
      </orders>
   </payload>
</message>


This XSL style sheet will sort the order XML by item number, as shown in Listing 2.


Message server features

Message servers are capable of much more. Unfortunately, we must keep this implementation bare boned. But here is an overview of the type of things message servers can do. The can support:

  • Persistence: Message servers typically support persistence by writing messages to disk in the event of a server crash.
  • Intelligent message routing: This feature provides the message server with decision capability regarding which queue is used to store the message. It can even forward messages to another message server.
  • Synchronous and asynchronous communication: Clients that choose to use synchronous communication will wait for a response. Synchronous communication is appropriate when another client immediately picks up the message and responds by placing a response message on a queue. Asynchronous communication allows clients to pick up the response whenever the time is right.

Under the hood

Let's have a look at the nuts and bolts. I will take you through the code for the key pieces of the server. If you want to try it out or extend the functionality, you can download the code (see Downloads). The download contains the server, a client, and an example that invokes the client.

Let's look at the message server itself, in Listing 3. Before it can listen for clients, it must do a bit of housekeeping. The server reads an XML configuration file into the Config object to obtain the port number, queue names, and a logging switch. The Config object reads config.xml into a DOM object and provides getters to obtain configuration values. The queues are simply hashtables. The Container, which is also a hashtable, and the queues are placed as objects in the container hashtable. All housekeeping is done in the MessageServer constructor. The last housekeeping job is to bind to a server socket on the desired port number.

Now the server is ready to listen for a client connection. The MessageServer run() method, shown in Listing 4, establishes an infinite loop to wait for a client connection. When a client connection is detected, the server starts a QueueManager thread which pasess in the queueContainer, the clientSocket, and the loggingSw. Behind the scenes, the Java network API reassigns the socket to a free socket. The server port is freed up to listen for another connection, which would launch another QueueManager thread to service the new client.

The job of dealing with the message is delegated to the QueueManager. Let's have a look at the QueueManager class. The QueueManager's constructor has the simple task of opening an input and output stream to the client. The real work happens in the run() method, shown in Listing 5. The new thread reads the message from the socket and uses the resulting String to build a Message object. The thread searches the Container for the queue. If the Queue is found in the Container, the thread will either place the Message object on the queue (PUT), retrieve and remove the Message object from the queue (GET), or purge the queue (DEL), depending on the command sent by the client. The QueueManager always returns an acknowledgement to the client in the form of a message.

readSocket(), shown in Listing 6, is one interesting method to look at. We want to use the same socket connection to both read the inbound message and send back the acknowledgement. Therefore we need to be able to indicate that we've read the entire inbound message and that we're not just waiting for the client to send the rest of the inbound message. How do we know when the client is finished sending the message? We take the same approach as the HTTP protocol. The client sends the length of the message, followed by a carriage return and then the message. The socket is read byte by byte until the length has been reached. HTTP takes the same sort of approach with the Content-Length HTTP header on POST requests.

At this point we have a server that detects client connections, and a QueueManager that stores and returns messages. The message is nicely encapsulated in the Message object. Let's peek in the Message class to see what it's all about.

The Message class implements two constructors, as shown in Listing 7. The single String arg constructor builds an XML DOM object using the string as input. The no-arg constructor builds a DOM object with no values contained in the tags. Each XML tag has a getter and setter that serves to abstract the XML implementation of the Message object.

Two approaches were considered for the retrieval of tag values from the DOM object. One approach is dependent on a static definition of the XML structure of the DOM object. The other is designed to adapt to a flexible definition. For brevity's sake, the former approach is implemented in Listing 8. (For an excellent presentation on this topic, see "Lowering the bar of the DOM API" in Resources).


Transformations

The client can request a message transformation by stipulating a processing rule on the GET request. QueueManager, shown in Listing 9, inspects the processing rule to determine which rule to apply against the message being retrieved from the queue. QueueManager appends ".xsl" to the processing rule to retrieve the XSL style sheet from the file system. Then, it is a simple matter of invoking the XSLT processor, as shown in Listing 10.


Conclusion

This message server is lightweight and it satisfies the requirement of running on any old box you have laying around the office. It can do this because it doesn't need to implement the server on top of a transport protocol such as HTTP or SMTP. You don't need a Web server or servlet engine. All you need is a JVM and an XML parser that supports XSL.

We needed to implement a simple transport protocol to address issues that are usually addressed with HTTP or some other transport protocol. The client needed to know what to send and what it would receive. If we wanted to augment the set of commands, we would need to make some code changes. (These changes could be minimized by using the Java Reflection API to discover methods that implement commands).

Fortunately, SOAP (Simple Object Application Protocol) presents us with an alternative. If we are willing to implement on a transport protocol such as HTTP or SMTP we can make our lives a whole lot easier. The payback is that we are now able to use a popular XML-based protocol that enables us to easily extend the set of commands without using the Java Reflection API. SOAP deals with the format for the messaging infrastructure and HTTP deals with the transport needs. With message formatting and transport needs dealt with, the only thing we have to worry about is the payload. The whole application requires just a fraction of the code presented in this article.



Download

DescriptionNameSizeDownload method
Code for the message server in this articlex-msgsrvr.zip25 KB HTTP

Information about download methods


Resources

About the author

George Franciscus is a technical and management consultant based in Toronto, who works with Java, XML, WebSphere, and Lotus Domino on multitier projects. George is a Sun Certified Java Programmer, IBM Certified Developer - XML and Related Technologies, R5 R4 Principle Domino Developer, R5 R4 Principle Domino Administrator, and Microsoft Certifed Professional. You can contact George at george.franciscus@nexcel.ca.

Comments (Undergoing maintenance)



Trademarks  |  My developerWorks terms and conditions

Help: Update or add to My dW interests

What's this?

This little timesaver lets you update your My developerWorks profile with just one click! The general subject of this content (AIX and UNIX, Information Management, Lotus, Rational, Tivoli, WebSphere, Java, Linux, Open source, SOA and Web services, Web development, or XML) will be added to the interests section of your profile, if it's not there already. You only need to be logged in to My developerWorks.

And what's the point of adding your interests to your profile? That's how you find other users with the same interests as yours, and see what they're reading and contributing to the community. Your interests also help us recommend relevant developerWorks content to you.

View your My developerWorks profile

Return from help

Help: Remove from My dW interests

What's this?

Removing this interest does not alter your profile, but rather removes this piece of content from a list of all content for which you've indicated interest. In a future enhancement to My developerWorks, you'll be able to see a record of that content.

View your My developerWorks profile

Return from help

static.content.url=http://www.ibm.com/developerworks/js/artrating/
SITE_ID=1
Zone=XML
ArticleID=12048
ArticleTitle=Building an XML-based message server
publish-date=11012001
author1-email=george.franciscus@nexcel.ca
author1-email-cc=

My developerWorks community

Tags

Help
Use the search field to find all types of content in My developerWorks with that tag.

Use the slider bar to see more or fewer tags.

Popular tags shows the top tags for this particular content zone (for example, Java technology, Linux, WebSphere).

My tags shows your tags for this particular content zone (for example, Java technology, Linux, WebSphere).

Use the search field to find all types of content in My developerWorks with that tag. Popular tags shows the top tags for this particular content zone (for example, Java technology, Linux, WebSphere). My tags shows your tags for this particular content zone (for example, Java technology, Linux, WebSphere).

Rate a product. Write a review.

Special offers