ONJava.com    
 Published on ONJava.com (http://www.onjava.com/)
 See this if you're having trouble printing code examples


Hangin' with the JAX Pack, Part 2: JAXM

by Al Saganich
11/28/2001

This is the second of a three-part series on the "JAX Pack," Sun's Java APIs for XML. In the first article, I introduced the Java API for XML Processessing (JAXP) and the Java API for XML Binding (JAXB). These two mechanisms provide the underlying framework to access XML data and encapsulate that XML data within Java objects. Let's move on and examine the Java API for XML Messaging (JAXM) and see how it provides underlying support for accessing various messaging formats.

JAXM

JAXM (JSR67) is currently at version 0.93 (public review) with early access reference implementation version 2. JAXM is expected to be an optional part of J2SE and a standard part of J2EE.

JAXP and JAXB help us access XML data, but how does XML actually get between two cooperating applications? JAXM provides a specialized API for just this purpose. Effectively, JAXM is a specification for a Service Provicer Interface (SPI) to access standard XML messaging protocols, such as SOAP. JAXM allows for the transfer of complete business-level documents between two separate Web services. What JAXM does not do is attempt to define messaging standards of the so-called vertical markets; instead, it allows direct access to the various fields without regard to payload type. JAXM looks to provide an infrastructure for supporting whatever standard emerges, whether it be SOAP, ebXML or something else.

As I discussed in my article on Java and Web services, Simple Object Access Protocol (SOAP) actually describes the underlying format of messages transfered between applications. It's a reasonable enough task to write a SOAP- based servlet that uses JAXP to access the various parts of a message and work with it. This begs the question, why do we need JAXM at all? The problem with what I've proposed is the level of complexity and understanding that a developer requires to actually process and manipulate a SOAP message.

As much as I hate to admit it, I programmed long ago using raw Unix socket calls. At first it was really cool, but as we developed FTP and SMTP clients, the coding became tedious and error-prone. We went through a similar growth period as people developed the first Web sites. We are now seeing those same issues with Web services. JAXM is designed to be a lightweight API that abstracts away the underlying messaging infrastructure. In theory, we should be able to develop JAXMServlets, extending HttpServlets, which allow us to access SOAP (or whatever protocol follows SOAP) messages quickly and easily. Figure 1 below shows just such a conceptual picture.

Diagram.
Figure 1. SOAP- and JAXM-Based applications.

Before we move on, a word of caution. JAXM is in reality a fairly low-level or SPI-level interface. Effectively, JAXM is an optional J2EE package supporting the sending and receiving of XML messages using a pure Java API. JAXM allows developers to focus on the processing aspects of their applications rather than on issues associated with composing and decomposing XML messages using SOAP, ebXML, or something else.

JAXM version 1.0 is targeted at providing support for:

JAXM applications fall into two major catagories: synchronous and asynchronous, each taking advantage of various capabilities, as shown above. JAXM, in fact, supports five major catagories of client-client interactions.

Asynchronous
A client sends a message that must be processed, to which a reply must ultimately be generated. The reply could take days to generate; the client is free to do other things while waiting for reply.
Asynchronous with acknowledgement
A client sends a message that must be acknowledged with a specific message. The acknowledgement format and correlation between messages is not specified by JAXM. The client is free to do other things while awaiting the "ack."
Synchronous
A client sends a message and waits for a reply. The reply is informational only, and not required. The client does nothing else while waiting.
Synchronous with acknowledgement
A client sends a message and waits for the acknowledgement.
Fire and forget
A client sends a message and goes on. No "ack" or response expected.

A fair amount of SOAP knowledge is implied in processing a SOAP message. Developers with absolutely no SOAP knowledge are advised to poke around in the SOAP areas of W3C. For those who simply need a SOAP refresher, Figure 2 shows the JAXM SOAP packaging conceptual model.

Diagram.
Figure 2. JAXM SOAP Packaging conceptual model.

JAXM is, for the most part, concentrated on accessing the various parts of a SOAP 1.1 packet today, although provisions exist for other messaging styles. JAXM base applications come in one of two flavors: message consumers or message producers. Rather than go into any more detail, lets look at a JAXM message consumer example.

Message Consumers and JAXMServlet

Related Reading

Java and XML, 2nd Ed.Java and XML, 2nd Ed.
By Brett McLaughlin
Table of Contents
Index
Sample Chapter
Full Description
Read Online -- Safari

The first, and perhaps simplest, method for taking advantage of JAXM functionality is by developing a servlet that extends the JAXMServlet interface and consumes XML messages packaged via SOAP 1.1. JAXMServlets look surprisingly like message-driven Enterprise Java Beans, in that they have a single onMessage(Message msg) method that needs to be implemented. The reality, however, is that they are traditional servlets and that the onMessage method gets called whenever a servlet POST or GET action occurs. When onMessage() is called we can then decompose the underlying SOAP message, as required by the application. Let's look at a complete example, adapted from public draft 1, that takes a SOAP trade message and dumps it to System.out.


Listing 1: SOAPListener.java

00 /*
01 * adapted from a sun example
02 */
03 import javax.xml.messaging.*;
04 import javax.xml.soap.*;
05 import javax.xml.parsers.*;
06 import javax.xml.transform.*;
07 import javax.activation.DataHandler;
08 import java.io.*;
09 import org.w3c.dom.*;
10 import org.xml.sax.SAXException;
11 public class SOAPListener extends JAXMServlet implements AsyncListener {
12 // implement the required onMessage method
13  public void onMessage(Message message) {
14    try {
15      //Get the soap part of the message (ignore attachments)
16      SOAPPart soapPart = message.getSOAPPart( );
17
18      // tunnel in and get the envelope
19
20      SOAPEnvelope soapEnvelope = soapPart.getSOAPEnvelope( );
21
22      // from the envelope get the DOM tree representing the content.
23      DOMSource domSrc = (DOMSource) soapEnvelope.getContentAs(DOMSource.FEATURE );
24
25      //Now use the dom tree to traverse the info.
26      //get some of the fields from it.
27      Document doc = (Document) domSrc.getNode();
28      Element root = doc.getDocumentElement();
29      NodeList list = root.getElementsByTagName("GetLastTradePriceDetailed" );
30      Element element;
31      Element childElement;
32      for(int i = ; i < list.getLength(); i++){
33        if (!(list.item(i) instanceof Element )) continue;
34        element = (Element list.item(i) );
35        NodeList list2 = element.getChildNodes();
36        for(int j = ; j < list2.getLength( ; j++ {
37          if(!(list2.item(j instanceof Element) continue;
38          childElement = (Element list2.item(j ;
39          System.out.println(childElement.getTagName() ;
40          System.out.println("\t" ;
41          System.out.println( ((Text) childElement.getFirstChild()).getData()) ;
42          System.out.println("\n" );
43        }
44      }
45    } // end try
46    catch(Exception jxe ) {
47      jxe.printStackTrace();
48    }
49  } // end onMessage
50 } // end SOAPListener


Breaking the example down, we see that lines 3-10 simply import the required packages to support JAXM (see the JAXM specification for details). On line 11 we've defined an AsyncListener listener. Note that SynchListeners are expected to return a SOAPmessage object. Servlets must implement either the AsyncListener or SyncListener, depending on what behavior you want. Line 13 shows the first real line of code, the definition of the onMessage() method with its single message argument, defined in the javax.xml.messaging package. It's interesting to note that the specification provides classes and methods that closely parallel the SOAP 1.1 specification. Specifically, messages contain a SOAP part, which contains a SOAP Envelope, containing a SOAP Header and Body, etc.

Lines 16 and 20, respectively, show how we obtain the object representing the SOAP envelope, as shown in figure 3. The various SOAP message class information is detailed in the javax.xml.soap package. Note that we could have just as easily obtained the attachment part of the message by writing:

AttachmentPart attachmentPart = message.getAttachmentPart( );

A word of caution: the EA2 version of the JAXM contains documentation for the JAXM packages that is unfortunately sketchy. I have tried to be as accurate as possible, but some of the information on JAXM was obtained by decompiling and examining source!

Once we have the SOAPEnvelope we can obtain the data representing the encapsulated XML using the getContentAs() method. GetContentAs returns any of a number of javax.xml.transform.Source types, of which we chose DOMSource.FEATURE, but could have chosen SAXSource.FEATURE or STREAMSource.FEATURE, depending on how we wanted to process the result.

Since we choose to process the content as a DOM Tree, we use the DOMSource object to get the DOM Document representing the XML content; then we can then use the various DOM APIs to process the data.

The steps we went through to develop our JAXM Servlet were:

  1. Import the required packages.
  2. Implement either AsynchListener or SyncListener.
  3. Implement the onMessage method (other parts may be available in the future).
  4. Obtain the SOAP part of the message.
  5. Obtain the SOAP Envelope or attachment.
  6. Tunnel down into the appropriate Envelope or attachment field as required.
  7. Optionally, for SyncListeners, return an appropriate SOAPMessage.

Before we close our discussion of JAXM, let's spend a few moments looking at message producers as well.

Producing Messages

Building a message consumer is a much more straightforward process than building a message producer. However, the concepts as a whole are simple. Sending a SOAP 1.1 message with JAXM is a three-step process:

  1. Create a message.
  2. Populate the message with appropriate content.
  3. Send the message.

There are a number of ways to achieve these three steps using either direct connections or a messaging provider. Let's look more closely at how to develop message producers.

Create a Connection

The first step in developing a messaging producer is to create a connection. When developing applications to produce SOAP 1.1 messages, we would normally build a message and send it over some connection. JAXM, however, defines the concept of a messaging provider. Those readers familar with JMS will be quite at home with messaging providers. A messaging provider is a sort of intermediary that collects, caches, and ultimately sends messages on behalf of an application. We can create one connection in one of two ways; using a messaging provider or not.

Creating a direct connection, without a messaging producer, is done using a SOAPConnection object that has a static newInstance() method for creating connection instances. SOAP Connections are created as shown below:

java.xml.soap.SOAPConnection connection = SOAPConnection.newInstance();

Creating a connection using a messaging provider is a somewhat more difficult process. Like JMS connections, using a messaging provider requires you request the connection from the messaging provider:

private static final String providerURI = "http://java.sun.com/xml/jaxm/provider";
Context ctx = new InitialContext();
ProviderConnectionFactory cf = (ProviderConnectionFactory)ctx.lookup( providerURI);
SOAPConnection connection = connectionFactory.createConnection();

The code above assumes that the connection factory was registered in JNDI (again, much like JMS) and fully implements the ProviderConnectionFactory interface.

Obtain a Message From a Message Factory

Once we have a connection, we need a message to send. Again, much like JMS, we use a factory object to create the message.

Using a direct connection, we can use a simple MessageFactory object to generate an instance of a SOAPMessage as shown below:

MessageFactory mf = MessageFactory.newInstance();
SOAPMessage mg = mf.createMessage();

If we were using a messaging provider we would need to obtain a MessageFactory from the connection, as the messages might use common profiles and are bound to the provider behind the scenes. A code snippet for obtaining messages from a messaging provider-based connection is shown below.

MessageFactory mf = connection.createMessageFactory(); // Create messgages from the message factory.
SOAPMessage message = mf.createMessage( );

Populating a Message

Once we have a message, we populate it the same way for both connection types. For example:

//Get the SOAP part of the message. We could have gotten the attachment part as well.
SOAPPart sp = message.getSOAPPart( );

// Get the soap envelope
SOAPEnvelope se = sp.getSOAPEnvelope( );

// populate the soap envelope using a DOMSource object
DOMSource domsrc = null;
try {
  DocumentBuilderFactory dbf =DocumentBuilderFactory.newInstance( );
DocumentBuilder db = dbf.newDocumentBuilder( ;
Document doc = db.parse("file:///somefiles.xml" );
  domsrc = new DOMSource(doc);
} catch(Exception e ) {
System.err.println("Error in creating DOMSource" +
  e.getMessage( );
}
// add the DOMSource object to the soap envelop
se.setContent(domsrc);

Obviously, you will need to adhere to the SOAP rules, perhaps adding SOAP Header elements with appropriate content. See the SOAP specification for complete details on how to comply with the SOAP specification.

Sending a Message

We then send a message and close the connection as shown below:

private static final String endpointURL ="http://somewebservice:7001";
URLEndPoiunt ep = new URLEndPoint(endpointURL);
SOAPMessage reply = connection.send (message,ep);
connection.close();

Alternatively, if we were sending many messages to the same end point, we might set the default message end point as follows:

private static final String endpointURL ="http://somewebservice:7001";
message.setTo(new URLEndPoint(endpointURL);
connection.send(message);

We could then update the message content as required, keep sending the same message, and later close the connection as required.

A complete message provider example is shown below. Note that this example is for illustration purposes and may not conform to the SOAP specification.


Listing 2: SOAPProducer.java

import javax.xml.messaging.*;
import javax.xml.soap.*;
import javax.xml.transform.dom.DOMSource;
import javax.xml.parsers.*;
import javax.servlet.http.*;
import java.io.IOException;
import org.w3c.dom.Document;

public class SOAPServlet extends HttpServlet {
  private static final String providerURI =
        "http://java.sun.com/xml/jaxm/provider";

  private ProviderConnectionFactory connectionFactory;

  public void init(ServletConfig servletConfig) throws ServletException {
     Context ctx = new InitialContext();
     connectionFactory = (ProviderConnectionFactory)ctx.lookup( providerURI);
     }

  public void doGet(HttpServletRequest request,HttpServletResponse response )
    throws ServletException, IOException
  {
    try {
      // A request comes in to send a message. So we create a connection from the factory.
      // factories are used when we have an intermediate which caches and send messages on our behalf
      // much like JMS.
      SOAPConnection connection = connectionFactory.createConnection();

      // Create a message factory from the Connection to produce messages.
      MessageFactory mf = connection.createMessageFactory();
      // Create messgages from the message factory.
      Message message = mf.createMessage( );


      // Get the SOAPPart from the message.
      // Note the infrastructure takes care of creating the SOAPPart.
      // The user needs to get the SOAPPart and get the SOAPEnvelope and populate it appropriately.
      SOAPPart soapPart = message.getSOAPPart( );
      // Get the SOAPEnvelope from the header container obtained above.
      SOAPEnvelope soapEnvelope = soapPart.getSOAPEnvelope( );

      // Create a SOAPHeader from the SOAPEnvelope
      SOAPHeader soapHeader = soapEnvelope.createSOAPHeader() ;

      // Create a SOAPHeaderElement that will be appended to the SOAPHeader.
      SOAPHeaderElement she = soapHeader.createSOAPHeaderElement( );
      she.setName("from", "http://foo.bar/", "m" );
      she.addContent("foo@bar.com" ;
      soapHeader.addContent(she);
      soapEnvelope.setSOAPHeader(soapHeader);

      // Add a DOMSource object as the actual message content

      DOMSource domsrc = null;
      try {
        DocumentBuilderFactory dbf =
        DocumentBuilderFactory.newInstance( );
        DocumentBuilder db = dbf.newDocumentBuilder( ;
        Document doc = db.parse("file:///foo.bar/soap.xml" );
        domsrc = new DOMSource(doc);
      } catch(Exception e ) {
        System.err.println("Error in creating DOMSource" +
        e.getMessage( );
      }

      soapEnvelope.setContent(domsrc);

      soapEnvelope.setSOAPBody(soapBody );
      URLEndpoint ep = new URLEndpoint("http://foo.bar/Service" );
      connection.send(message, endPoint );
      response.setStatus(HttpServletResponse.SC_OK );

    } catch(Exception jxe {
      jxe.printStackTrace();
    }
  } // end doGet
}

Conclusion

The JAX Pack APIs add an exciting element to Web services development in a J2EE environment. In this article, we saw how to process XML messages using JAXM -- an admittedly low-level API, but all in all, a very powerful set of tools for writing robust Web services. In part three of this series we will look at the remaining JAXPack APIs -- JAXR and JAX-RPC.

Al Saganich is BEA Systems' senior developer and engineer for enterprise Java technologies, focused on Java integration and application with XML and Web services.


Return to ONJava.com.

Copyright © 2009 O'Reilly Media, Inc.