After years of building, extending, and maintaining large, distributed applications, programmers are learning to appreciate the benefits of platform-neutral behavior and platform-neutral data.
The Java programming language has stepped forward to fill the need for platform-neutral behavior (although scripting languages such as TCL still enjoy a moment or two in the spotlight). XML (Extensible Markup Language) is proving to be the backbone of open, platform-neutral data solutions.
This article demonstrates how XML fulfills the promise of platform-neutral data when used with the Java Message Service (JMS).
Messaging pulls it all together
JMS defines a generic Java language interface to a message service. It supports most common messaging models (both publish/subscribe and point-to-point).
At first it might seem strange to mention platform-neutral data in the same paragraph as Java technology. After all, why do we need platform-neutral data when we're using JMS, which is a Java-based (and therefore platform-neutral) technology?
The answer springs from the environment in which messaging is often used. One of messaging's great strengths is in the realm of application integration. More often than not, the applications being integrated aren't all Java applications.
JMS is ideal in this situation because it is an interface specification -- not an implementation. It is meant to be layered on top of an existing technology which might already be in place. (Of course, all-Java implementations can also take advantage of this JMS and XML solution.)
Figure 1. JMS layered on top of a proprietary message service

Figure 1 illustrates such an environment. Non-Java applications communicate with the proprietary message service directly. Java applications communicate via JMS. Everything is seamless, right?
Well, not quite. There's still the question of data.
Platform-neutral data saves the day
Consider JMS's five message types. JMS supplies three structured or semi-structured message types (MapMessage, ObjectMessage, and StreamMessage) and two unstructured or free-form message types (TextMessage and BytesMessage).
The structured message formats represent only a handful of the many ways to structure data (only a map, a serialized object, and a stream of data elements are directly represented). More importantly, they raise the question of interoperation with non-Java applications. How is the translation or mapping accomplished, especially when the translation involves serialized classes?
The unstructured message formats are more likely to interoperate well, but only because they impose very little structure on the messages. This small fact, however, places the burden of parsing and validation upon each recipient.
XML eases this burden. It provides a clean, standardized path to rich, functional data structures, and backs it up with a growing number of tools for doing the dirty work of parsing and validation.
With XML in the loop, everything is seamless.
The following two pieces of code demonstrate how to transfer an XML message. Since XML is basically text, it is transferred in the body of a TextMessage instance. Both examples assume the existence of an XMLValidator class. This class is a thin wrapper around one of the many Java-based XML parsing and validation tools available.
The sending side is pretty straightforward. The code in Listing 1 demonstrates how to locate a Queue and QueueConnectionFactory, create a connection and a session, stuff the XML into a TextMessage, and send the message to the queue.
Listing 1. Example of sending an XML message
public
static
void
send(
String stringQueue,
String stringQueueConnectionFactory,
XMLValidator xmlvalidator,
String stringXML)
throws
NamingException,
JMSException,
XMLValidationException {
// Look up the Queue and the QueueConnection Factory
// in a JNDI naming and directory service, or create
// them directly.
Context context = new InitialContext();
Queue queue = null;
queue = (Queue)context.lookup(stringQueue);
QueueConnectionFactory queueconnectionfactory = null;
queueconnectionfactory =
(QueueConnectionFactory)context.lookup(stringQueueConnectionFactory);
QueueConnection queueconnection = null;
queueconnection = queueconnectionfactory.createQueueConnection();
QueueSession queuesession = null;
queuesession =
queueconnection.createQueueSession(false, Session.AUTO_ACKNOWLEDGE);
// Create the QueueSender.
QueueSender queuesender = null;
queuesender = queuesession.createSender(queue);
// Create a TextMessage from the XML. If the XML is
// created from user input, it will be necessary to
// validate the XML. Send it.
xmlvalidator.validate(stringXML);
TextMessage textmessage;
textmessage = queuesession.createTextMessage();
textmessage.setText(stringXML);
queuesender.send(textmessage);
}
|
On the receiving end there is more work to do (see Listing 2). After receiving the TextMessage, the code extracts the XML and validates it. The process of validation checks the XML against a Document Type Definition (DTD), which may be part of the XML or external to it.
If the DTD is stored externally, you face the interesting possibility of creating and maintaining an enterprise-wide DTD repository. The repository rigorously defines the structure of the messages that participating enterprise applications can exchange.
The TextMessage is now the conduit of very structured, well-defined messages, understood by Java and non-Java applications alike.
Listing 2. Example of receiving an XML message
public
static
String
receive(
String stringQueue,
String stringQueueConnectionFactory,
XMLValidator xmlvalidator)
throws
NamingException,
JMSException,
XMLValidationException {
// Look up the Queue and the QueueConnection Factory
// in a JNDI naming and directory service, or create
// them directly.
Context context = new InitialContext();
Queue queue = null;
queue = (Queue)context.lookup(stringQueue);
QueueConnectionFactory queueconnectionfactory = null;
queueconnectionfactory =
(QueueConnectionFactory)context.lookup(stringQueueConnectionFactory);
QueueConnection queueconnection = null;
queueconnection = queueconnectionfactory.createQueueConnection();
QueueSession queuesession = null;
queuesession =
queueconnection.createQueueSession(false, Session.AUTO_ACKNOWLEDGE);
// Create the QueueReceiver.
QueueReceiver queuereceiver = null;
queuereceiver = queuesession.createReceiver(queue);
// Retrieve a TextMessage. Get the XML. Validate
// the XML before returning it. It is also possible to
// transform the XML into a DOM tree or other representation
// during the validation and to return that.
TextMessage textmessage;
textmessage = (TextMessage)queuereceiver.receive();
String stringXML = textmessage.getText();
xmlvalidator.validate(stringXML);
return stringXML;
}
|
There seems to be a general feeling that Message-oriented Middleware (of which JMS is a part) and XML belong together. I hope I've added some strength to the claim. It's really not that surprising. XML documents are natural messages -- they're structured and yet very flexible. In addition, MOM excels at integrating heterogeneous applications, as does XML.
- Learn about the Java Message Service API.
- Find answers to your questions in the list of JMS frequently asked questions.
- Access the W3C XML Specification.
Todd Sundsted has been writing programs since computers became available in convenient desktop models. Though originally interested in building distributed applications in C++, Todd moved on to the Java programming language when it became the obvious choice for that sort of thing. In addition to writing, Todd works as a Java Architect with ComFrame Software Corporation. Todd can be reached at tsundsted@comframe.com.




