Home > Chapters & Articles > XML > Learning About JMS Messages

Learning About JMS Messages

Chapter Description

Need step-by-step guidance through WebSphere JMS development? In this sample book chapter, you'll examine JMS messaging concepts and considerations. Learn how message content is defined, as well as the three popular physical formats used to structure message content, and discover the structure of the JMS message.

All too often when people think about messaging, their minds immediately focus on the mechanics of the process and the entity for which the process is being implemented—the message—is all too easily forgotten. The message is the unit of exchange and without first defining the message, we have nothing with which to communicate. Thus, before we explore the use of the JMS API, we examine in detail the JMS message. We review the process of message definition and learn what factors influence the nature of the message content. We detail the structure of JMS messages, discuss key attributes, and consider when a given message type should be used. We also answer questions regarding how the JMS client uses the JMS message interface. For instance: How do I select a specific message of interest or populate it with content?

Message Definition

Message definition is probably the most crucial and potentially the most challenging of all activities associated with enterprise messaging. It defines the process of determining message content (what makes up a message) and structure (how message content is organized), without which applications do not have the basis to communicate. The varied nature and number of applications that interact using the enterprise messaging infrastructure implies that the number and form of message definitions can vary widely. This typically suggests a requirement for transformation services that transform messages between different formats. Such services are often provided by messaging providers as part of the delivery service.

In approaching the problem of message definition proliferation, some encourage the use of a common message model or canonical form that all messages exchanged are based on. Of course, the main challenge is defining a suitable canonical form that addresses the needs of all the enterprise applications. Irrespective of the approach to message definition adopted, the problem still remains to define for any given message the message content and its physical format or layout. Together, the message content and physical format define the data block that will be contained within the body of the JMS message.

The message content problem is typically bounded by the actual functions of the applications that will be producing or consuming the message. For instance, for an application that is responsible for submitting an order, it's safe to assume that the message content representing the order will contain data consistent with how an order is defined in that enterprise. The content should address the needs of the application that will process the order as well as take into account the data the submitting application has available. Expected content could comprise an order identifier, customer details, and a list of ordered items.

Defining message content can thus be viewed as an exercise in understanding and interpreting the business context. In addition, the potential interactions between the communicating applications must be considered. For example, when the order is submitted, how is the status of the order communicated? We could adopt the approach that our order message contains a status field, which is populated by the order fulfillment application. In this case we use a single message type for submitting an order as well as for receiving or querying its status. Alternately, we could design an order status message that is returned when the order is submitted and also used when the status of the order is requested. Note that in both cases we would also have to define the dependencies among the data. For instance, in the case where I use the same message type for different purposes, what fields are mandatory or optional based on my usage?

Sometimes the message content is predefined by the application that ultimately produces or consumes the message. This is often the case when enabling existing off-the-shelf or custom applications to communicate via messaging. As an example, the message content of a message designed to move data to or from a database table could be expected to bear a close relationship with the columns and rows defined for the database table.

The physical format of a message refers to the actual representation of the message content. It specifies how the data is structured and laid out and defines the relationship between discrete items of data, usually called fields or elements. The physical format enables the sending or receiving application to make sense of the data contained within the message.

As an illustration of the problem, consider the data block:

JOHN DOE 33

Is this a single data field? Or is it three fields, each separated by a space? What is the nature of the data? Is it a string? Is 33 an integer? The ways in which this data block could be interpreted are endless, and the physical format enables the data to be interpreted as intended.

To further our discussion of physical formats, we examine three physical formats commonly used to define messages: XML, tagged/delimited, and record-oriented.

XML

XML (Extensible Markup Language) is probably the most commonly used physical format in Java applications. It is a standards-based markup language (http://www.w3.org/XML/) that allows data to be described independent of the language the application is written in or the operating system on which the application runs. The inherent portability of XML data is a major factor in its popularity in the Java world, which is understandable given that Java itself is aimed at developing portable applications that can run on any operating system. XML is also widely used by non-Java applications and is definitely experiencing a boom in its usage. Indeed, it may not be inappropriate to suggest that XML could be considered the physical format of choice, or at the very least the first port of call, for representing data in today's business applications.

XML is a markup language: it uses tags to identify pieces of data. XML, like its sibling HTML, owes its existence to Standard Generalized Markup Language (SGML), which was defined in 1986 by the International Standards Organization in the standard ISO 8879. SGML had its roots in document representation and was designed to provide a basis for describing the various elements associated with a document, including text, formatting, linking, and embedding. It introduced the concept of providing start and end tags to identify a piece of textual data. Hence, a first name of John would be described <firstName>John</firstName>, with the addition of the forward slash (/) identifying the end tag. The use of start and end tags meant that data could be nested and described in a hierarchical form. For instance, the attributes of a given individual could be described as:

<person>
     <firstName>John</firstName>
     <lastName>Doe</lastName>
     <age>33</age>
</person>

In essence, SGML provided a way to identify, name, and describe the relationship between pieces of data so they could be managed and manipulated. That said, the SGML standard was by no means simple, as it provided a generalized framework and was consequently extensive in scope and detail. A key characteristic of SGML is that it is a metalanguage, which means that it defines how any given markup language can be specified. HTML was first introduced in 1990 as a markup language for describing data that is rendered in browsers as Web pages. HTML defined a strict set of tags and associated syntax to be used and provided the impetus for the explosion of the Internet, as any browser that could process HTML could display the resulting data. XML, introduced in 1996, was aimed at providing a simpler and lightweight generalized markup language for use on the Web. It differed from HTML in one key aspect: it did not define a tag set. This meant that XML was highly extensible and flexible, as tags could be defined to suit any given purpose. In addition, as long as the XML document was well formed (e.g., matching start and end tags), the data could be processed by any application that could handle XML. Of course with such flexibility there was the question of whether the tags would be understood by the processing application, and a number of specifications, which we will examine later, such as DTD and Schemas, evolved to enable the meaning of an XML document to be shared among applications.

XML describes data in a textual form that is typically human readable, it is used in a variety of applications ranging from presentation of information and storage of configuration options, to communication of data—a use we are obviously interested in. Being a meta-language in its own right, XML has formed the basis of other language specifications that define an explicit tag set and associated syntax for their use. Examples include SOAP, a standards-based format for describing messages sent using Web services, and WSDL, a format for describing Web services.

Anatomy of an XML Document

Figure 3-1 shows an XML document (a block of data rendered in XML) with key attributes of the document highlighted.

03fig01.gifFigure 3-1. Anatomy of an XML Document

An XML document typically commences with an optional XML declaration that in the least identifies the version of XML in the document and additionally the character encoding. If the XML declaration is omitted, the version is assumed to be 1.0, and heuristics are applied by the processing application to guess the encoding. The XML declaration is known as a processing instruction (PI) and is characterized by the syntax <?PITarget instructions?>. PITarget represents a keyword meaningful to the processing XML parser or application. In our example we specify a target "XML", which refers to the XML standard set of PIs that a parser should recognize; the specific instructions identify version and character encoding. Application-specific PIs may be defined and included in the document.

The XML data is bound by a root tag <customer> … </customer>. The root tag encapsulates all other tags associated with the data block and marks the start and end of the XML data. As would be expected with most hierarchical structures, there can be only one root tag. An element is generally defined by a start tag, end tag, and some value. The element itself may contain nested elements and may indeed be empty; that is, they may have no value or nested element assigned. In the case of an empty element, a special shorthand may be used specifying a start tag ending in a forward slash, for example, <value/>. Elements may optionally contain attributes, which are name-value pairs that provide an alternative way of structuring data. For example, element contact has associated with it three attributes: type, status, and usage.

The question that always arises is: When do I represent data as an element or as an attribute, given that either approach can be easily adopted? For instance,

<contact type="email" status="active" usage="unrestricted">
....
</contact>

can just as easily be represented by

<contact>
<type>email</type>
<status>active</status>
<usage>unrestricted</usage>
...
</contact>

The simple answer is that it depends. It basically comes down to what constitutes a logical arrangement, what makes contextual sense, personal preference, and style.

In reviewing the XML example (Figure 3-1), you may have noted some simple syntactical rules. Element names must begin with a letter or underscore and may not contain embedded spaces. All start tags must have a corresponding end tag, and the order of nesting must be maintained. An XML document that conforms to these rules is said to be well formed; however, that a document is well formed does not mean that it is correct or valid from the perspective of the application that is processing it. As an example, assume I wish to send an XML-based message to a shipping application. The shipping application requires that a postal code (ZIP Code) be specified and the sending application sends the following:

<address>
      <street>One Circle Park</street>
      <street>Apartment 301</street>
      <city>Grand Rapids</city>
      <state>MI</state>
      <zipCode/>
   </address>

The XML document in itself is well formed, obeying all the syntactical rules; however, from the perspective of the shipping application, the XML document is not valid because it does not contain a required value: zipCode is empty. When viewed from the perspective of validity, you may have already begun to ask other questions, such as how the shipping application knows that the element zipCode is contained in the element address, or how the sending application can be notified that in preparing the XML document, zipCode is a mandatory element that must be populated. In other words, is there a blueprint or metadata that describes the structures and relationships in the XML document? This need is addressed by DTDs and XML Schema.

DTDs and Schemas

DTDs (Document Type Definitions) and XML Schemas define what an XML document should look like. They define the ordering of elements, mandatory and optional elements, allowable values, and a host of other characteristics that make it possible for an application to successfully interpret an XML document. While they are not required to successfully parse or construct an XML document, they define a reusable template for the XML document that can be shared among applications, and they provide a definition against which the document can be validated.

Initially, a DTD was the only means of describing an XML document, but as usage evolved, a number of restrictions became apparent:

  • DTDs are not expressed in XML; they are simple text documents and are consequently not as easy as XML to process or manipulate.

  • DTDs do not allow the value of an element to be typed as anything other than a String. While it was accepted that an XML document represented all data in textual form and was in itself one large String, users wanted the capability to say that the value of a given element was not actually a String, but an integer, for example, and should be treated as such by the processing application.

  • DTDs do not provide a mechanism to define the scope of a tag to protect against name collision. For example, does the element type mean the same thing when defined as part of the element account and the element phoneNumber? Are the allowed values in both cases the same? And how do we address the ambiguity?

XML Schemas were introduced to address these and other limitations, and are the preferred option over DTDs. XML Schemas are written in XML. They allow elements to be typed and are closely associated with the concept of XML namespaces, which provide a solution to name collision. The concepts associated with XML Schemas, particularly XML namespaces, are nontrivial, and a detailed review is outside the scope of this book. However, a number of excellent references are suggested in the resource list in Appendix D. For our purposes, it suffices to say that armed with a DTD or Schema, our application can validate that the message content is appropriately formatted and populated before sending or on receipt. It is useful to note that from a performance viewpoint, the overhead associated with validating an XML document can be significant. It is thus not unusual for validation to be done as part of development and testing, and disabled when the applications move into production, as thorough testing should have confirmed the correctness of the exchanged XML.

Processing XML Documents

Generally, an XML-aware application is concerned with constructing XML documents from various data structures and/or parsing XML documents into data structures that can be accessed and manipulated. From the JMS client's perspective, the XML document will be inserted into or retrieved from the message body of a JMS message. Given the textual nature of the XML document, it is fair to assume that it would be contained in a JMS TextMessage or BytesMessage.

A number of APIs have been developed in Java that enable an application to process an XML document. In all cases the use of the API is associated with a supporting XML parser that implements support for the API. The XML parser is responsible for actually parsing the XML document and optionally validating it against a Schema or DTD. A good example of an XML parser is the open source Apache Xerces2 Java Parser (http://xml.apache.org/xerces2-j/index.html), which supports the full range of APIs. It is particularly popular among developers and is repackaged by a number of vendors, including IBM. Currently, Java developers have a choice of four APIs to use for XML processing: SAX, DOM, JAXP, and JDOM.

SAX

SAX (Simple API for XML; http://www.saxproject.org/) focuses on the parsing of XML documents only. It does not provide for the building of an XML document from scratch or the modification of an existing document. It offers an event-driven interface that enables the application to register content handlers that are called with parsing events as they occur. The parsing events are triggered as the document is parsed by the parser, and the content handler implements methods (callbacks) that are called based upon the nature of the event. Examples include startDocument(), endDocument(), startElement(), endElement(), and characters(). In all cases the callback methods are passed arguments, which are processed by the application. The characters() method receives the actual data associated with a given element.

Under SAX, the parser handles the document sequentially, triggering events as it progresses. Once an event has been triggered, it cannot be retrieved, and SAX does not store processed values. This offers a performance advantage, as large documents can be easily handled without constraining available memory. The downside is that SAX provides no means of accessing data randomly or at a specified location. It also provides no in-memory model of the document that can be accessed by the application.

DOM

The DOM (Document Object Model) API is aimed at providing an in-memory model of the XML document defined as a tree. A document object is provided by the API, which contains the parse tree and methods that enable the tree to be traversed. The API also allows a document object and thus a tree to be built from scratch, providing methods to create elements, attributes, and other XML constructs. Unfortunately, the API does not provide a means to easily render a built tree in XML, and custom string-generation methods are required if DOM is to be used this way. Such utilities may be provided by the parser vendor; for example, Xerces provides an XMLSerializer class for this purpose.

The greatest concern when using DOM is the resource constraints that can occur when parsing large documents, as in all cases the entire document must be read into memory before it can be accessed. It is instructive to note that DOM actually uses SAX to parse the document as it builds the tree.

DOM was not designed specifically for Java, but is rather a general specification (see http://www.w3.org/DOM/) that can be implemented in any programming language. This has resulted in what some developer's have described as an API that is foreign to Java programmers. While this is of course a matter of opinion, the API does offer certain idiosyncrasies such as treating everything, even data, as a node on the tree (one would expect data to be associated with a node and not be a node itself), which can make the API feel unwieldy.

JAXP

JAXP (Java API for XML Parsing) was introduced by Sun to attempt to provide some standardized abstraction to the use of SAX and DOM with different parsers. One of the drawbacks of SAX and DOM is that they both require that the XML parser is explicitly specified, which of course means that code would need to be modified if a different parser is used. While one could work around this limitation using property files, JAXP (http://java.sun.com/xml/jaxp/) provides a standard pluggability layer that allows applications to be written independent of the XML parser used. It allows the XML parser to be specified using Java system properties, and provides factory classes that enable a SAX or DOM parser to be invoked. It does not change the SAX or DOM APIs, but simply adds some convenience constructs that abstract the vendor specific parser.

JDOM

The JDOM API is an open source effort (http://www.jdom.org/) that addresses the limitations of SAX and DOM. Despite the name similarity, JDOM is not based on DOM, though it adopts a document object model. It was designed and optimized specifically for Java and harnesses the power of the Java language to provide a simple API with credible performance characteristics. It is not dependent on an XML parser implementing support for JDOM, as it uses SAX (or DOM) to invoke the parser; thus it can be used with existing parsers. As it is based on a document object model, it allows the parse tree to be constructed from scratch, and unlike DOM, it provides utility classes that can render the tree in a number of forms, including XML.

While not intended to be a full-fledged tutorial on using JDOM, to round out our discussion on XML, the code snippet below illustrates the use of JDOM to construct and insert a simple XML document into a JMS message. It also shows how to parse an XML document retrieved from a JMS message.

//JDOM imports
import org.jdom.*; //XML Processing API
import org.jdom.input.SAXBuilder; //Parser
import org.jdom.output.XMLOutputter;//XML generator

/*Sender*/
//build XML document from data
String firstName = "JOHN";
String lastName = "DOE";
int age = 33;

//create document object
Document doc = new Document(new Element("person"));
//retrieve root element and build tree
Element root = doc.getRootElement();
root.addContent(new Element("firstName").setText(firstName));
root.addContent(new Element("lastName").setText(lastName));
root.addContent(new Element("age").setText(Integer.toString(age)));
   //output tree as XML stream ready for transmission
   XMLOutputter fmt = new XMLOutputter();
   //XMLOutputter output method works with java.io.OutputStream
   //though an outputString method is provided, its use is not recommended by jdom
   ByteArrayOutputStream out = new ByteArrayOutputStream();
   fmt.output(doc, out);
   
   //create TextMessage
   TextMessage tOutMsg = session.createTextMessage();
   tOutMsg.setText(new String(out.toByteArray()));
   
   /*Receiver*/
   //Unpack TextMessage
   String message = tInMsg.getText();
   
   //parse message content to generate document
   ByteArrayInputStream in = new ByteArrayInputStream(message.getBytes());
   //create parser using default (Xerces) and no validation
   SAXBuilder parser = new SAXBuilder(false);
   Document doc = parser.build(in);
   Element root = doc.getRootElement();
   String firstName = root.getChildText("firstName");
   String lastName = root.getChildText("lastName");
   int age = Integer.parseInt(root.getChildText("age"));
   

Note that for the construction and parsing of the message, JDOM favors java.io.InputStream, and I used the ByteArrayInputStream and ByteArrayOutputStream. My reason for not simply using a BytesMessage (which would be a natural fit) is specifically related to the fact that with the BytesMessage, the receiver does not know the size of the incoming message, which hampers its ability to extract the contents (a problem fixed in JMS 1.1). This is discussed in detail in the section "Using the JMS Message Interface," later in this chapter.

Tagged/Delimited

A tagged/delimited physical format uses tags, delimiters, or both to define the structure of a block of data, which is usually rendered as text. If we revisit our sample message data, JOHN DOE 33, we could define this as three fields delimited by a space. Alternately, JOHN;DOE;33 would be three fields delimited by a semicolon. Tagged/delimited physical formats have been in use for years and are found in many industrial-strength applications. For instance, the SWIFT message format, which is used to move money electronically between banks, is tagged/delimited. Automated commerce transactions between businesses often rely upon the exchange of messages that conform to the Electronic Data Interchange (EDI) format, which is also traditionally a tagged/delimited format. Indeed, in the strictest sense XML can be thought of as a formalized tagged/delimited format.

Using a tagged/delimited format simply comes down to deciding if your fields need to be tagged and how the fields are delimited. A number of approaches can be adopted to define the structure of the data:

Variable-Length Delimited

With a variable-length delimited approach, the data fields are separated from each other by a delimiter. The delimiter is a constant that marks the end of a field. Punctuation constructs such as commas (,), full stops (.), semicolons (;), and colons (:) are commonly used. This approach proves particularly useful when the length of a data field varies from message to message (hence the term variable-length). For example, the length of a person's name varies widely. Defining a fixed length for the data field that will contain a name requires you to define an allowable maximum. This runs the risk of someday proving inadequate or alternately proves inefficient because the full length is never used and thus a great portion of the message is essentially redundant space.

It is not uncommon to have data that contains a combination of fixed-length and variable-length fields. You can choose to simply delimit all fields using a delimiter, or you can choose to delimit fixed fields based on their length and variable fields with a delimiter. For example, in

1050JOHN;DOE;33

1050 is a value with a fixed length of four characters. The other fields are variable and delimited with a semicolon.

Tagged Delimited

As the name suggests, tagged delimited uses a tag to identify data fields. The tag generally precedes the data field and is itself separated from the data field either by a known tag length or by a specified tag data separator, which is essentially a delimiter that specifies the end of the tag. The data field is separated from the next tag by a specified delimiter. For example, in

DATA:0001;DATA:0002;DATA:0003

DATA is the tag for each field, a colon is the tag data separator, and a semicolon delimits the data field from the next tag. A variation on this is tagged fixed length, in which the data fields are delimited by their known length.

It is certainly possible for techniques to be combined when defining data formats, and varied and complicated variations can occur. For example, if a field is delimited by its length, the data structure may be designed such that the length of the field is carried as part of the message, as shown:

X:4;0001Y:6;000123

where X is a tag separated from the following data field by a colon. The data field containing the value 4 is delimited by a semicolon from a fixed data field whose length is the value contained in the preceding field: 4. The data structure then repeats the same pattern with a tag, Y, and a data field whose length is 6.

Processing Tagged/Delimited Formats

The tagged/delimited physical format offers considerable flexibility in defining the way data is structured. Consider the sample SWIFT message shown:

{1:F01IBMADEF0AXXX0000000000}{2:I100IBMADEF0AXXXN}{3:{108:abc}}{4:
:20:X
:32A:940930USD1,
:50:X
:52A:CHASUS33
:53A:CHASUS33
:54A:CHASUS33
:56A:CHASUS33
:57A:CHASUS33
:59:X
:70:X
:71A:OUR
:72:/A/
-}

The message is defined by blocks of data grouped together. Each block is identified by a tag (1, 2, …) which is separated from its data fields by a colon. Blocks are delimited by curly braces (}{). Notice that in the block tagged with a 4 (known as the SWIFT message body; the others are headers), each data field is further tagged with a colon as separator, and the data is delimited with a carriage-return linefeed.

Clearly, the parsing or construction of such a message format is nontrivial; however, it illustrates an important point: if you decide to define a tagged/delimited format, you must typically design code to successfully parse and construct messages in that format. As an example, the following code snippet illustrates how our sample variable-length delimited message JOHN;DOE;33 might be parsed:

//parse received message
String message = tInMsg.getText();
//initialize variables
String firstName = "";
String lastName = "";
int age = 0;

//use java.util.StringTokenizer to parse string
StringTokenizer st = new StringTokenizer(message, ";");
while (st.hasMoreTokens()) {
     firstName = st.nextToken();
     lastName = st.nextToken();
     age = Integer.parseInt(st.nextToken());
}

It is useful to note that in the case of well-known, complicated formats such as SWIFT and EDI, vendor-supplied tools are generally available to assist in the processing of such data.

Why, you may ask, would I want to create a tagged/delimited format when I can use XML with all its associated tools? Performance considerations and optimizing message size are influencing factors. XML by design is a verbose format, and as previously discussed, processing XML documents can attract significant overhead. In contrast, representing the data using a tagged/delimited format such as variable-length delimited results in much less data that needs to be transmitted and, with careful choices, a structure that is not that hard to parse or construct. However, this is usually at the expense of readability and maintainability. Thus, in choosing a physical format, thought should be given to the use of the message and the impact the choice of physical format will have on development effort, performance, maintainability, ease of change, and ease of data sharing (remember that the physical format definition will need to be shared with at least one other application).

Record-Oriented

The record-oriented physical format is a fixed length–based format; that is, data is described based on the length of associated typed fields. For example, JOHNDOE33 is described as two strings of length 4 and 3 and an integer. Record-oriented formats were first introduced by mainframe-based applications as a means of formatting data that was to be exchanged between programs. Such applications were often written in COBOL, and COBOL copybooks defined the structure of data in terms of the number of bytes representing each field. For applications written in C, the struct provided a useful construct for representing record-oriented data. In Java, record-oriented formats are often rendered in byte arrays, and the JMS BytesMessage object provides useful methods for rendering record-oriented physical formats, as we see later in this chapter.

While a record-oriented format can form the most concise description of a data block, this is done at the expense of readability and ease of sharing. For example, it is not as straightforward to share the definition of a record-oriented format between two applications that are written in different languages as it is to share an XML Schema. As discussed earlier, if fields may vary in length, then a maximum allowable length must be defined, with the attendant risks. Consideration also must be given to padding characters (often null or whitespace), which must be inserted when the actual data is less than the maximum length. The question of justification—Is data inserted from the beginning or end of the field so that blank space is either after or before the data?—also needs to be considered.

As with XML and tagged/delimited formats, record-oriented formats can be used to render quite complex data structures, and I would not want to convey the impression that they are obsolete, as they are widely used by today's enterprise applications. However, it is fair to say that new Java applications being developed today will most likely use XML rather than a record-oriented format for reasons discussed earlier. In the instance where the JMS application is sending or receiving a message from a non-JMS application that uses a record-oriented format, we may find ourselves handling record-oriented formats directly. However, recall that a messaging provider may offer value-added transformation services, which transform messages into physical formats appropriate for the recipient. If such services are available and are used, then the physical formats adopted by different applications do not need to be constrained. A given application simply speaks in a format that best suits its purposes.

2. JMS Message Structure | Next Section

Search Related Safari Books

Safari Books