Sun Java Solaris Communities My SDN Account Join SDN
 
Article

The Java Web Services Developer Pack, Part 2

 
 

What's This About? | XML Technologies for RPC Calls and Messaging | JAX-RPC | Build and Run the Sample Application

Web Services Developer Pack

JAXM

JAXM is a Java API for SOAP-based XML (document-oriented) messaging.

JAXM is a Java API for XML-based messaging. In XML-based messaging, a client sends an XML document to the server for processing. What's important in this context is that both the client and server recognize the format and meaning of the document. For example, the document could be something that both the client and server recognize as a purchase order. The server processes the purchase order, and could return a response (perhaps confirming that the purchase order was received). JAXM is focused on business-to-business messaging. In other words, it's designed for the exchange of documents, such as purchase orders, that are typically used in business operations.

If you read the section on JAX-RPC, you know that a JAX-RPC client calls a specific method on the server. In contrast to a JAX-RPC client, a messaging client does not call a specific method -- in the purchase order example, the messaging client does not call a specific purchase order method. In fact, the client might not know what program on the server actually processes the request. Instead, the client relies on the server to invoke the appropriate application to process the request because the server understands the document it receives. Similarly, what the server returns is not a method response, but rather a response generated by the processing application.

JAXM works in conformance with SOAP, specifically the SOAP 1.1 specification and the SOAP 1.1 with Attachments specification. What this means is that in a JAXM scenario, documents and responses are SOAP messages or SOAP messages with attachments. What it also means is that JAXM implementations must support the SOAP 1.1 and SOAP 1.1 with Attachments specifications. However a JAXM provider can also support messaging protocols (usually industry-based) that are built on top of SOAP 1.1 and SOAP 1.1 with Attachments, for example, the ebXML Message Service Specification V1.0.

Like JAX-RPC, JAXM is designed to hide the complexity of SOAP. When you use JAXM, you don't explicitly code a SOAP request. Instead you code the request in the Java programming language, using a Java API. JAXM converts the request to a SOAP message (or SOAP message with attachments) and then transports it to the server. The server converts the SOAP message (with possible attachments) and then processes it. Then the sequence is reversed. The server converts the response to a SOAP message (possibly with attachments) and transports it back to the client.

In order to understand and use JAXM, it's important to understand some basic concepts. These concepts include:

After you're familiar with these concepts, see the JAXM Example.

Clients and Providers

A JAXM client is necessary for messaging, a JAXM provider is optional.

There are two roles that can take part in JAXM messaging: clients and providers. A JAXM client is necessary for messaging, a JAXM provider is optional. A JAXM client is an application that sends messages using the JAXM API. If a provider isn't used, the client sends the message to a recipient (typically a service) on a server, identified by a URL.

Messaging without a Provider

A JAXM provider (also called a messaging provider) is an intermediate service that acts on behalf of a client. If a JAXM provider is used, the client sends the message to the provider, which then transmits and routes the message to the service. To do this, a JAXM provider implements and supports the JAXM API.

Messaging with a Provider

A client or client-provider pair can also receive messages, in other words, it can be a target service of a message. For example, suppose three businesses use JAXM to exchange purchase orders. One business, Business 1, sends purchase orders to a service provided by a second business, Business 2, which in turn, sends the purchase order to a service provided by a third business, Business 3. Business 2's service acts as a service when it receives the purchase order from Business 1, and acts as a client when it sends the purchase order to Business 3. If a JAXM provider is used in this scenario, Business 1's JAXM client sends the purchase order to its JAXM provider, which transmits the purchase order to Business 2's JAXM provider. Business 2's JAXM provider sends the purchase order to its service. The service then uses Business 2's JAXM provider to transmit the purchase order to Business 3.

A Client-Provider Pair Can Send and Receive Messages

If you use a provider, you must deploy the client in a J2EE Web container or in a J2EE Enterprise JavaBeans container. If you don't use a provider you can deploy a standalone client.

The choice of whether or not to use a provider has implications for deployment, level of service, and routing:

  • Where you deploy a client. If you use a provider, you must deploy the client in a J2EE Web container or in a J2EE Enterprise JavaBeans (EJB) container. If you don't use a provider you don't have to deploy the client in a J2EE container. You could deploy it, for example, as an application on the J2SE platform. A JAXM client that isn't deployed in a J2EE container is called a standalone client. A standalone client can act only as a client -- it can't also act as a service.
  • The level of service provided to messages. As mentioned earlier, JAXM supports additional messaging protocols that are built on top of SOAP 1.1 and SOAP 1.1 with Attachments. For example, JAXM supports the ebXML Message Service Specification V1.0. In JAXM terminology, these additonally-supported protocols are called profiles, and the support is provided by a JAXM provider (but not a JAXM client). A JAXM provider can support one or more profiles (or no profiles). In supporting a profile, the JAXM provider makes available the additional levels of service offered by the associated protocol. Note that a JAXM client can only take advantage of one profile at a time when it sends a message to a JAXM provider -- even if the provider supports more than one profile. In fact, the client and provider must agree on the profile before the client sends the message.
  • Additional routing. If a JAXM provider isn't used, a JAXM client sends a message directly to a service. If a JAXM provider is used, the message is routed through the provider to the service. However a JAXM provider allows for even more intricate routing. For example, a message can be routed to a number of intermediate destinations (for perhaps some intermediate level of processing) before routing to a final destination.

Message Exchanges

JAXM supports asynchronous (that is, one-way) and synchronous (that is, two-way) exchanges between a sender and a receiver.

JAXM supports various types of exchanges between a JAXM client and a service, or between an JAXM client-JAXM provider pair that sends a message (the JAXM specification calls a client-provider pair that takes this role a sender) and a JAXM client-JAXM provider pair that receives a message (the JAXM specification calls a client-provider pair that takes this role a receiver). First, it supports two categories of exchanges: asynchronous and synchronous.

An asynchronous exchange is a one-way exchange between a sender and receiver. (Notice that client and service is not mentioned here. If a JAXM provider is not used, a JAXM client can only have a synchronous exchange with a service.) In an asynchronous exchange, the sender sends a message to the receiver without waiting for a response. The sender can then continue processing. When the receiver receives the message, it must process it.

An Asynchronous Message Exchange

A synchronous exchange is a two-way exchange (also called a request-response exchange) between a client and a service or a sender and receiver. In a synchronous exchange, the client or sender sends a message to the receiver and then waits for a response. In other words the client or sender is blocked, it can't continue processing until the service or receiver replies.

A Synchronous Message Exchange

In addition, JAXM supports a number of request types within these categories:

  • Asynchronous inquiry. In this exchange, a sender uses JAXM to ask a receiver for information. Because it's an asynchronous request, the sender can continue processing -- it's not blocked. The receiver reads and processes the request and returns a reply message. Sending the reply message is a totally separate operation and can happen long after the request is sent.
  • Asynchronous update with acknowledgment. In this exchange, a sender uses JAXM to ask a receiver to update information. Again, because this is an asynchronous request, the sender can continue processing -- it's not blocked. The receiver reads and processes the request. When it successfully completes the processing, the receiver sends the client an acknowledgment that it made the update.
  • Synchronous update. Unlike an asynchronous update, a synchronous update forces the client or sender to wait for an acknowledgment. The acknowledgment, which is correlated to the request, indicates that the update was successfully made. The acknowledgment unblocks the client or sender.
  • Synchronous inquiry. This exchange is a variation of the synchronous update exchange. The one difference is that in this exchange the service or receiver returns a reply message (rather than acknowledgment message). The reply message has no correlation to the request. It's only purpose is to unblock the client or sender.
  • Fire and forget. This exchange does not involve an acknowledgment or reply. The sender makes the request and continues processing.

Profiles

A JAXM provider can offer messaging functionality that extends what's offered in support of the SOAP 1.1 and SOAP 1.1 with Attachments specifications. For example, a JAXM provider might support a specification such as the ebXML Message Service Specification, ebXML Transport, Routing & Packaging Version 1.0, which adds transport, routing, and packaging features beyond the basic messaging features specified in the SOAP 1.1 and SOAP 1.1 with Attachments specifications. In this case, the specification documents specifics regarding the content of the SOAP header and the content of other SOAP elements that is not covered in the basic SOAP model. It's important to note that although this ebXML specification extends the SOAP specifications, it is also based on the SOAP specifications. In fact, any additional functionality that a JAXM provider offers must be based on the SOAP specifications. In JAXM, the extended functions that a JAXM provider offers are represented by a profile. In other words, a JAXM provider that supports the ebXML Transport, Routing & Packaging Version 1.0 specification, supports a profile for that specification. Support for a profile is required for asynchronous messaging.

A JAXM provider can support multiple profiles. Each profile can represent a particular set of extensions to basic SOAP messaging that are agreed on by a particular industry or standards body. Typically, these extensions cover security and quality-of-service features not covered in the SOAP 1.1 and SOAP 1.1 with Attachments specifications. However, a profile does not have to be industry-based or standards body-based. It can be application-specific.

Profiles play a part in creating a message for exchange with a JAXM provider. Before a JAXM client creates a message, it needs to identify a profile for the exchange. This makes the extended functions associated with the profile available to the exchange. JAXM provides a mechanism that a client can use to determine which profiles a provider supports. After determining what profiles are supported, the client then specifies one of the supported profiles when it creates a message for transmission to the provider.

Connection and Message Objects

In JAXM, SOAP messages are sent between a client (or sender) and a service (or receiver) over a connection. A connection is either point-to-point, that is, directly from a client to a destination such as a URL or a service, or client-to-JAXM provider. A point-to-point connection is represented by a SOAPConnection object. A connection to a JAXM provider is represented by a ProviderConnection object. In other words, you use a SOAPConnection object in a synchronous, request-response exchange between standalone JAXM client and a service. You use a ProviderConnection object in an asynchronous exchange between a sender and receiver.

A SOAP message is represented by a SOAPMessage object. The object models the structure of a SOAP message with attachments. The SOAPMessage object is a container that holds other objects that model the parts of a SOAP message with attachments, that is, the root body part and attachment parts (if there are attachments in the message). In particular, a SOAPMessage object contains the following object hierarchy:

  • SOAPPart
    • SOAPEnvelope
      • SOAPHeader
      • SOAPBody
  • AttachmentPart
    • MimeHeaders
      • MimeHeader

JAXM Packages

The JAXM 1.1 API consists of a single package, javax.xml.messaging. However the JAXM 1.1 specification also depends on another package, javax.xml.soap, that is defined by the SOAP with Attachments API for Java (SAAJ) 1.1 specification. Originally, both packages were part of JAXM API, however the javax.xml.soap package was decoupled from the JAXM API so that other specifications, such as JAX-RPC 1.0, could depend on this package without having to depend on the rest of the JAXM specification.

javax.xml.soap. This package provides the basic building blocks for creating a SOAP message, and for sending it synchronously, that is, in a request-response exchange. For example, if you use a standalone JAXM client to request a synchronous update, you use the javax.xml.soap package. Some of the important classes in the package are:

SOAPConnectionFactory This is an abstract base class for factory classes that create a synchronous, point-to-point connection. Two important methods in the class are newInstance, which is used to create an instance of a default SOAPConnectionFactory object, and createConnection, which creates a SOAPConnection object.
MessageFactory This is an abstract base class for factory classes that create a SOAPMessage object. Two important methods in the class are newInstance, which is used to create an instance of a default MessageFactory object, and createMessage, which creates a SOAPMessage object.
SOAPPart This is a container class for the SOAPEnvelope object. An important method in the class is getEnvelope, which is used to get the SOAPEnvelope object contained in the SOAPPart object.
SOAPEnvelope This is a container class for the SOAPHeader and SOAPBody objects. Some of the important methods in the class are getHeader, which is used to get the SOAPHeader object, getBody, which is used to get the SOAPBody object, and createName, which is used to create a Name object needed for qualifying and localizing names in the SOAP message.
SOAPHeader This class represents a SOAP Header element, in other words, it adds information beyond what is in the body of the SOAP message. For example, it can indicate additional processing that needs to be done at an intermediate node along the path to the final destination. A SOAPEnvelope object contains an empty SOAPHeader object by default. However, a SOAPHeader object is optional. If the SOAPHeader object is not needed, the method detachNode can be used to remove the object.
SOAPBody This class represents a SOAP Body element. The class can contain SOAPBodyElement objects that model the content of the body of a SOAP message. An important method in the class is addBodyElement, which is used to create a SOAPBodyElement object, and add it to a SOAPBody object
SOAPBodyElement This class represents content within a SoapBody object. The set of SOAPBodyElement objects added to a SoapBody object models the full content in the body of a SOAP message. An important method in the class is addChildElement, which adds a child element to a SOAPBody object
AttachmentPart This class represents an attachment to a SoapMessage object. The content of the attachment can be XML or some other content type such as an image. A SoapMessage object can contain multiple AttachmentPart objects. Each AttachmentPart object contains the content of the attachment, and MIME headers that identify the type of content. Two important methods in the class are addMIMEHeader, which adds a MIME header to an AttachmentPart object, and setContent, which sets the content of the AttachmentPart object.

javax.xml.messaging. This package provides the API for using a JAXM provider to send and receive SOAP messages. The API is also used by a recipient to process a SOAP message and return a reply -- even if a JAXM provider is not used in the exchange with a client. When you send a SOAP message using a JAXM provider, you still need to create the SOAP message, so you need to use the javax.xml.soap package in addition to the javax.xml.messaging package. For example, if you use a JAXM provider to make an asynchronous inquiry, you need the javax.xml.soap package to create the SOAP message and the javax.xml.messaging package to use the JAXM provider. Some of the important classes and interfaces in the package are:

ProviderConnectionFactory This is an abstract base class for factory classes that create a connection to a JAXM provider. Two important methods in the class are newInstance, which is used to create an instance of a default ProviderConnectionFactory object, and createConnection, which creates a ProviderConnection object.
ProviderConnection This class represents an active connection to a JAXM provider. Two important methods in the class are getMetaData, which is used to get a ProviderMetaData object that contains information about a JAXM provider, and createMessageFactory, which creates a MessageFactory object for sending SOAPMessage objects for a specified provider profile.
ProviderMetaData This class contains information about a JAXM provider. An important method in the interface is getSupportedProfiles, which is used to retrieve a list of the profiles supported by the provider.
ReqRespListener This is an interface that is implemented by a recipient in a synchronous message exchange with a client. The interface defines one method, onMessage, that is used to pass a SOAP message to the ReqRespListener implementation, and to return a response.
OnewayListener This is an interface that is implemented by a recipient in an asynchronous message exchange with a client. The interface defines one method, onMessage, that is used to pass a SOAP message to the OnewayListener implementation, and to return a response.

Let's see how these classes are used to exchange messages. First let's look at how the classes are used by a JAXM client that doesn't use a JAXM provider, then let's look at how the classes are used by a JAXM client that does use a JAXM provider.

Exchanging Messages Without a JAXM Provider

A standalone JAXM client, that is one that doesn't use a JAXM provider, can only exchange messages synchronously in a request-response exchange with a recipient such as a service. Here are the steps in this kind of exchange.

The JAXM client:

The service then processes the message and returns a reply.

The client then processes the reply.

Get a Connection

A standalone JAXM client gets a connection by creating a SOAPConnection object. This object represents a connection between the client and the service. The client uses the newInstance method of the static SOAPConnectionFactory class to create an instance of the class. (The SAAJ API provides a default implementation of this class.) The client then uses the createConnection method of that instance to create a SOAPConnection object.

import javax.xml.soap.*;

SOAPConnection conn;
SOAPConnectionFactory scf = 
                   SOAPConnectionFactory.newInstance();
conn = scf.createConnection();

Create a Message

A standalone JAXM client creates a message by creating a SOAPMessage object. The client uses the newInstance method of the static MessageFactory class to create an instance of the class. (The SAAJ API provides a default implementation of this class.) The client then uses the createMessage method of that instance to create the SOAPMessage object.

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

Add Content to the Message

A SOAPMessage object represents all the elements of a SOAP message, but the elements initially have no content. To add content to the SOAP message, a JAXM client needs to access the appropriate element in the message (that is, the body and optionally the header), and then add content to that element. To access the header and body elements, the client first uses the getSOAPPART method of the SOAPMessage class to get a SOAPPart object. The SOAPPart object contains a hierarchy of objects that represents the envelope, header, and body of the message. After getting the SOAPPart object, the client successively gets the objects in hierarchy using the appropriate get methods (getEnvelope, getHeader, getBody).

SOAPPart sp = msg.getSOAPPart() ;
SOAPEnvelope envelope = sp.getEnvelope();
SOAPHeader hdr = envelope.getHeader();
SOAPBody bdy = envelope.getBody();

To add content to the header, a client:

  • Uses the createName method of the SOAPEnvelope object to name a SOAPHeaderElement object
  • Uses the addHeaderElement method of the SOAPHeader object to add the SOAPHeaderElement object to the SOAPHeader object
  • Uses the appropriate add method of the SOAPHeaderElement object to add content to the header element

For example, the following code adds a SOAPHeaderElement object named OnlineBooks to a SOAPHeader object, and adds text to the SOAPHeaderElement object. The text is "Online Book Orders":

hdr.addHeaderElement( envelope.createName(
                  "OnlineBooks", "ob",
  "http://www.bookprovider.com" )).addTextNode(
                                 "Online Book Orders");

To add content to the body of the message, a client adds one or more child elements to the body, and then adds content to each child element. To do this, the client:

  • Uses the addBodyElement method of the SOAPBody object to create a SOAPBodyElement object
  • Uses the createName method of the SOAPEnvelope object to name the SOAPBodyElement object
  • Uses the createName method of the SOAPEnvelope object to name a SOAPElement object that represents a child element
  • Uses the addChildElement method of the SOAPBodyElement object to add the child element to the SOAPBodyElement object
  • Uses the appropriate add method of the SOAPBodyElement object to add content to the child element

For example, the following code creates a SOAPBodyElement object named GetBookDetails, adds two child elements to it named searchCriteria and searchValue, and adds text to each child element. The text for the searchCriteria child element is "author", and the text for the searchValue child element is "Hemmingway":

SOAPBodyElement sbe = bdy.addBodyElement
  (envelope.createName("GetBookDetails", "bp",
                  "http://www.bookprovider.com"));
sbe.addChildElement( envelope.createName(
                           "searchCriteria", "bp",
  "http://www.bookprovider.com" )).addTextNode("author");	
sbe.addChildElement( envelope.createName(
                  "searchValue", "bp",
  "http://www.bookprovider.com" )).addTextNode("Hemmingway");

The name specified for header and body elements must be a local name. The SOAPEnvelope class provides a method, createName, to create the name. Specifically, the method creates a Name object that is initialized with the local name. The SAAJ API provides two signatures for the createName method. In one signature, the method is specified with a single parameter: a string that specifies a local name. In the other signature, the method is specified with three parameters: a string that specifies a local name, a string that specifies a prefix for the namespace to be used for the name, and a URI for the namespace (this is the signature that is shown in the previous examples).

Add Attachments (If Any)

Suppose a JAXM client wants to send an image as part of the message? The SOAP part of a message (as represented by the SOAPPart object) can only contain XML content. To include non-XML content such as an image, the client needs to provide it as an attachment (however, an attachment can also contain XML content). To add an attachment to a message, the client:

  • Uses the createAttachmentPart method of the SOAPMessage object to create an AttachmentPart object that represents an attachment (a SOAP message can have multiple attachments, each requires its own AttachmentPart object)
  • Uses the setContent method of the AttachmentPart object to set the content of the attachment (this also sets the Content-Type header for the attachment)
  • Optionally, adds additional headers for the attachment using appropriate methods in the AttachmentPart object
  • Uses the addAttachmentPart method of the SOAPMessage object to add the SOAPAttachment object to the SOAPMessage object

For example, the following code adds an attachment whose content is a JPEG image:

AttachmentPart ap = msg.createAttachmentPart();
byte[] jpegData = "..."
ap.setContent(new ByteArrayInputStream(jpegData), "image/jpeg")
msg.addAttachmentPart(ap);

Notice that the addAttachmentPart method is specified with two parameters. The first parameter is an object that contains the content for the attachment. The second parameter is a string that specifies the Content-Type header for the attachment.

There's another way to add an attachment. In this alternate approach, a JAXM client uses a URL object that is part of the java.net package, and a DataHandler object that is part of the JavaBeans Activation Framework. Specifically, the client:

  • Creates a URL object that represents a URL that provides the content for the attachment
  • Creates a DataHandler object that references the URL object
  • Uses the createAttachmentPart method of the SOAPMessage object to create an AttachmentPart object -- this method specifies the DataHandler object as a parameter
  • Optionally, adds additional headers for the attachment using appropriate methods in the AttachmentPart object
  • Uses the addAttachmentPart method of the SOAPMessage object to add the SOAPAttachment object to the SOAPMessage object

For example, the following code uses a URL object and a Datahandler object to add an attachment that is a JPEG image:

import java.net.*;
import javax.activation.*;

URL url = new URL("http://mysite.com/mybooks.jpg");         
AttachmentPart ap = 
       msg.createAttachmentPart(new DataHandler(url));
ap.setContentType("image/jpeg");
msg.addAttachmentPart(ap);

Send the Message (and Wait)

A standalone JAXM client uses the call method of the SOAPConnection object to send a message. The call method is specified with two parameters: a SOAPMessage object that represents the SOAP message, and an object that represents the destination of the message (this is typically a URL).

For example, the following code sends the SOAP message represented by the message object to a URL destination ("http://www.bookstogo.com/bookordering"):

java.net.URL urlendpoint = new URL(
    "http://www.bookstogo.com/bookordering";
SOAPMessage reply = conn.call(message, urlEndpoint)

Notice that the call method returns a reply that is represented by a SOAPMessage object. Because this is a synchronous exchange, the client waits until it receives the reply. In other words, the reply unblocks the client.

Process the Message

After a standalone JAXM client sends a message to a service, the service processes the message. To process the message in a synchronous exchange, a service must implement the ReqRespListener interface in the javax.xml.messaging package. For example, suppose that the service is implemented as a servlet. The following statement declares that the servlet implements the ReqRespListener interface:

import javax.xml.messaging.*;

public class FunBooks extends JAXMServlet implements ReqRespListener

Notice the JAXMServlet specification. This is a superclass for servlets that receive JAXM messages.

The ReqRespListener interface declares one method, onMessage, that is used to describe how to process a request. The method takes a SOAPMessage object as a parameter. When the method is called, it passes the SOAPMessage object to the ReqRespListener implementation, and returns a response. The implementation of the onMessage method describes how the service processes a request. The service first gets the pertinent elements of the message, that is, the envelope, body, and child elements. To do that, the service takes actions that are similar to what the standalone client does to build the message. Specifically, the service uses the getSOAPPart method of the SOAPMessage class to get the SOAPPart object. The service then uses appropriate get methods to get the envelope, header, body, and child elements (getEnvelope, getHeader, getBody, getChildElements):

public SOAPMessage onMessage(SOAPMessage message) {

SOAPEnvelope menv = message.getSOAPPart().getEnvelope();
SOAPBody sb = menv.getBody();
Iterator sbes = sb.getChildElements(menv.createName
   ("GetBookDetails","bp",
   "http://www.bookprovider.com"));

The getChildElements method returns an Iterator object that represents all the child elements associated with the Name object that is specified as a parameter. In this example, the Name object is GetBookDetails. The service then iterates over the Iterator object to access each child element, and uses the getValue method to get the content of each child element. For example, the following code accesses the child elements in the body of a SOAP message, and gets the content in each child element:

while ( sbes.hasNext() ) {
   SOAPBodyElement sbe = (SOAPBodyElement)sbes.next();

   Iterator scIterator =sbe.getChildElements(
      menv.createName("searchCriteria", "bp",
                      "http://www.bookprovider.com" ));
      if ( scIterator.hasNext() ) {
		 
         SOAPElement child = 
                        (SOAPElement)scIterator.next();
            searchCriteria=child.getValue();
         } else {
            System.err.println("ERROR"+
                                " Returning null" );
            return null;
         }

The service continues processing based on the content of the message. For example, suppose the service is an online book ordering service, and the content in the child elements of the SOAP message sent to the service represent a search criterion (such as author), and a search value (such as Hemmingway). After getting the content of the child elements, the service might search a list to find books that meet the search criteria. If it finds a match, the service might then extract additional information from the list about those books. (The logic for doing the search is not shown here.)

The service then builds the reply message. To do that, it creates a SOAPMessage object to represent the reply message, and accesses the appropriate elements of the reply message (the envelope, body, and optionally the header). It then adds content to the reply message by adding one or more child elements to the body, and then adding content to each child element. The service can also add content to the header by adding a header element, and adding content to the header element. For example, the following code builds a reply message that contains the title of a book. The code also adds text to the header that identifies the organization providing the book:

SOAPMessage msg = fac.createMessage();
SOAPEnvelope env = msg.getSOAPPart().getEnvelope();
SOAPHeader header = env.getHeader();
header.addHeaderElement( env.createName(
   "organization", "bp",
   "http://www.bookprovider.com" ) ).
   addTextNode("Fun Books" );

env.getBody() .addChildElement(
   env.createName("Response"))
   addTextNode("Reply: "+bookTitle);

Process the Reply

To process the reply from a service, a JAXM client needs to first get the pertinent elements of the reply message, that is, the envelope, body, and child elements. The client gets the elements in the same way as the service gets the pertinent elements in a SOAP message. The client uses the getSOAPPart method of the SOAPMessage class to get the SOAPPart object, and uses appropriate get methods to get the envelope, header, body, and child elements (getEnvelope, getHeader, getBody, getChildElements):

SOAPEnvelope envelope = 
                     reply.getSOAPPart().getEnvelope();
SOAPHeader header = envelope.getHeader();
SOAPBody sb = env.getBody();

The client then uses the Iterator object returned by the getChildElements method to access each child element, and uses the getValue method to get the content of each child element. For example, the following code accesses the child elements in the body of a SOAP message, and gets the content in each child element:

Iterator bpIterator = sb.getChildElements(
   envelope.createName(localname, "bp", 
                         "http://www.bookprovider.com"));
   if ( bpIterator.hasNext() ) {                                        
      SOAPBodyElement sbe = (SOAPBodyElement)bpIterator.next();
      String bookTitle = bodyElement.getValue();
      System.out.print("Book Title: "+bookTitle); 
   } else {
            System.err.println("ERROR"+
                                " Returning null" );
            return null;
          }

Exchanging Messages With a JAXM Provider

A JAXM client that uses a JAXM provider can exchange messages asynchronously as well as synchronously with a recipient such as a service, or with a service/provider pair (that is, a reciever). Here are the steps in this kind of exchange.

Just like a standalone client, a JAXM client that uses a JAXM provider:

However instead of getting a synchronous, point-to-point, connection with the service or receiver, the JAXM client gets a connection to a JAXM provider. The client uses that connection to send a message to the provider, which then transmits and routes the message to the service, or to the receiver (which then forwards the message to its paired service). The receiving service then processes the message.

If the client exchanges the message asynchronously, it can continue processing after it sends the message (it does not have to wait for a reply). If the client exchanges the message synchronously, the client waits for the reply. The service then returns the reply to the JAXM provider (in the asynchronous case, this can be long after the request was sent by the client). If the service is part of a provider/service pair, it returns the reply to its paired JAXM provider, which then transmits it to the JAXM provider paired with the client. The provider forwards the reply to the client. The client then processes the reply.

Get a Connection With a JAXM Provider

A JAXM client gets a connection with a JAXM provider by creating a ProviderConnection object. There are two ways to do this. One way is similar to the way a standalone client gets a connection: that is, it uses the newInstance method of a static connection factory class to create an instance of the class. The connection factory class for connection to a JAXM provider is ProviderConnectionFactory. The instance of the ProviderConnectionFactory class connects to a default provider implementation. The client then uses the createConnection method of that instance to create a ProviderConnection object.

import javax.xml.messaging.*;

ProviderConnection pc;
ProviderConnectionFactory pcf = 
               ProviderConnectionFactory.newInstance();
pc = pcf.createConnection();

The second way to get a connection depends on the JAXM provider being registered with a naming service based on the Java Naming and Directory Interface (JNDI). Registering the provider associates it with a logical name. To get the connection to the registered provider, the JAXM client uses JNDI's lookup method, passing it the logical name of the provider. The method returns a ProviderConnectionFactory object. The client then uses the createConnection method of the returned ProviderConnectionFactory instance to create a ProviderConnection object. Here, for example, a JAXM client gets a connection to a JAXM provider whose logical name is bookprovider:

import javax.xml.messaging.*;
import javax.naming.*;

Context ctx = new InitialContext(); 
ProviderConnectionFactory pcf =
 (ProviderConnectionFactory)ctx.lookup("bookprovider");
ProviderConnection pc = pcf.createConnection();

For this approach to work, the logical name of the provider must be specified to the container when it's deployed. Remember, if you use a provider, you must deploy the client in a J2EE Web container or in a J2EE Enterprise JavaBeans container.

Create a Message

As is the case for a standalone client, a JAXM client that uses a provider creates a message by producing a MessageFactory instance and then using it to generate a a SOAPMessage object. However the client in the provider case uses the createMessageFactory method of the ProviderConnection object to produce the MessageFactory instance.

Before a JAXM client creates a message, it needs to identify a profile. It does this when it creates a MessageFactory instance. Information about a provider, such as its name and the profiles the provider supports, is contained in a ProviderMetaData object. A JAXM client uses the getMetaData method of the ProviderConnection object to create a ProviderMetaData object for a specific connection to a provider. The client then uses the getSupportedProfiles method of the ProviderMetaData object to identify the profiles supported by the provider. For example, the following code identifies the profiles supported by a JAXM provider associated with the ProviderConnection object, pc:

ProviderMetaData metaData = pc.getMetaData();
metaData.getSupportedProfiles();

The client then creates a MessageFactory instance, and specifies a String argument for a specific profile. For example, here a client determines whether the connected-to provider supports the ebXML Message Service Profile, and then identifies that profile in creating a MessageFactory object:

String profile = null;

for(int i=0; i < supportedProfiles.length; i++) {
   if(supportedProfiles[i].equals("ebxml")) {
      profile = supportedProfiles[i];
      break;
    
   } 
}
MessageFactory mf = pc.createMessageFactory(profile);

After creating a MessageFactory instance, the client uses the createMessage method of that instance to create the SOAPMessage object. Because the MessageFactory is initialized with a profile, the SOAPMessage object it generates needs to be cast to an implementation of that profile. The Java WSDP includes a basic ebXML profile implementation, EbXMLMessageImpl. The following code creates a MessageFactory instance, using the basic ebXML profile implementation:

EbXMLMessageImpl ebxmlMsg = 
                  (EbXMLMessageImpl)mf.createMessage();

Add Content to the Message

A client that uses a JAXM provider adds content to a SOAPMessage object in the same way as a standalone client. However, because the JAXM provider must support a profile, the client can use methods in the profile implementation to add content to a header. The client can use these methods instead of, or in addition to, methods provided in the javax.xml.soap package for adding header content. For example, the basic ebXML profile implementation, EbXMLMessageImpl, provides the method setSender to identify the location of the client, and setReceiver to identify the endpoint address of the recipient in a message exchange. The methods create Party objects that hold the address information -- the information is also added to the message header. A client that uses a JAXM provider that supports the EbXMLMessageImpl profile implementation can specify the setSender and setReceiver methods as follows:

ebxmlMsg.setSender(new Party(
         "http://www.employeeportal.com/bookordering"));
ebxmlMsg.setReceiver(new Party("http://www.funbooks.com"));

Note that because the endpoint address is provided in the header, it does not need to be specified when the message is sent (see Send the Message).

The client then gets the SOAPPart object and the objects within, and adds its content:

SOAPPart sp = ebxmlMsg.getSOAPPart() ;
SOAPEnvelope envelope = sp.getEnvelope();
SOAPHeader hdr = envelope.getHeader();
SOAPBody bdy = envelope.getBody();
SOAPBodyElement sbe = bdy.addBodyElement
   (envelope.createName("SendBookDetails", "bp",
                        "http://bookprovider.com"));
sbe.addTextNode("BuyISBN"+"**"+ isbn);    

Add Attachments (If Any)

Attachments are added in the same way as for a standalone client.

Send the Message

A client that uses a JAXM provider sends a message using the send method of the ProviderConnection object. Unlike the call method that is used to send messages from a standalone client, the send method is specified with only one argument: the SOAPMessage object. The call method requires a second argument that specifies the endpoint address of the recipient. However, for a client that uses a JAXM provider, the endpoint address is in the header of the SOAPMessage object, so the address does not need to be specified in the send request:

pc.send(ebxmlMsg)

Process the Message

A client that uses a JAXM provider can exchange messages synchronously or asynchronously. if the client sends the message synchronously, the receiving service processes it in the same way as though the client was standalone. In particular, the service must implement the ReqRespListener interface, and define within the onMessage method actions that get the SOAPPart object and the envelope, header, body, and child elements within the object. The service can then process the content and build a reply.

If the client uses a JAXM provider to exchange messages asynchronously, the service needs to implement the OnewayListener interface in the javax.xml.messaging package. For example, suppose that the recipient is a service that is implemented as a servlet. The following statement declares that the servlet implements the OnewayListener interface:

import javax.xml.messaging.*;

public class PurchaseConfirmer extends JAXMServlet implements OnewayListener

Notice the JAXMServlet specification. This is a superclass for servlets that receive JAXM messages.

The OnewayListener interface declares one method, onMessage, that is used to describe how to process an asynchronous request. The method takes a SOAPMessage object as a parameter. When the method is called, it passes the SOAPMessage object to the OnewayListener implementation. Unlike the case for a synchronous message request, the recipient of an asynchronous request does not have to send an immediate response. The time interval between the request and the response can, in fact, be very long. The implementation of the onMessage method describes how the recipient processes the asynchronous request. Here, for example, the implementation of the onMessage method displays a number of messages. It also uses various methods in the basic ebXML profile implementation, EbXMLMessageImpl, to process the SOAPMessage object:

public void onMessage(SOAPMessage message) {
System.out.println(
  "Asynchronous On message call in receiving servlet");
    
System.out.println("Here's the message: ");
message.saveChanges();
message.writeTo(System.out);

System.out.println(
         "Sending an asynchronous message to origin ");

EbXMLMessageImpl ebxmlMsg = (EbXMLMessageImpl)message;
Party from = ebxmlMsg.getSender();
Party to = ebxmlMsg.getReceiver();

ebxmlMsg.setReceiver(from);
ebxmlMsg.setSender(to);
ebxmlMsg.saveChanges();

Notice the saveChanges method. This method is used to save changes made to the SOAPmessage object.

After the service processes the message, it sends the reply using the send method of the ProviderConnection object:

pc.send(ebxmlMsg); 
ebxmlMsg.writeTo(System.out);
System.out.println(
             "***Sent message from ReceivingServlet");         

Process the Reply

The way that a client that uses a JAXM provider processes a reply from the service is the same as the way that the service processes a message from the client. If the client uses a JAXM provider to exchange messages synchronously, the client must implement the ReqRespListener interface, and define within the onMessage method how to handle the reply.

If the client uses a JAXM provider to exchange messages asynchronously, the client needs to implement the OnewayListener interface, and define within the onMessage method how to handle the reply. For example, suppose a client is implemented as a servlet. The following statement declares that the servlet implements the OnewayListener interface:

public class BookPurchaser extends 
     JAXMServlet implements OnewayListener {

Here is the definition of the onMessage method in the client. The definition describes the actions taken by the client to process a reply from the service. In this example, the client displays changes made by the service to the message initially sent by the client. The client uses the saveChanges method in the basic ebXML profile implementation to get the changes.

public void onMessage(SOAPMessage message) {
 System.out.println(
 "Sender received asynchronous reply from receiver");
    try {
        System.out.println("Here's the message: ");
        message.saveChanges();
        message.writeTo(System.out);
    } catch(Exception e) {
        e.printStackTrace();
    }
}

A JAXM Example

This section presents an example of JAXM in use. The example is based on a sample application that uses JAXM (as well as JAX-RPC) to access Web services. For instructions on building and running the sample application, see Build and Run the Sample Application.




Part 1 of this series presented an example that illustrated how a fictitious company named BooksToGo uses JAXR to register a Web service, and how another fictitious company, BoomingBusiness.com, uses JAXR to discover the service. Recall that BoomingBusiness.com provides a Web site to its employees. The Web site is a portal to a variety of employee services. One of the services that BoomingBusiness.com plans to make available through its Web site is an online service for ordering books. BooksToGo is a provider of that service. BooksToGo has recently changed its name to FunBooks.

BoomingBusiness.com's IT staff decides to take a messaging approach for the book order service. When an employee requests the online book ordering service from the employee portal, an underlying program will dynamically search a business registry for online book service providers. JAXM will then be used to exchange messages between employees submitting book order requests, and the registered book service providers.

In addition to FunBooks, Aerns and Cable is a company that provides online book services. Both FunBooks and Aerns and Cable want to make their services available to clients. Both companies choose to make their online book services available through JAXM. Let's examine what FunBooks and Aerns and Cable do to make their online book services available to clients through JAXM. Then let's examine what BoomingBusiness.com does to access the online book services through JAXM.

FunBooks and Aerns and Cable Register Their Online Book Services

FunBooks and Aerns and Cable use the JAXR API in the Java WSDP package to register their online book services. They choose to register the services in a UDDI registry. (In the sample application, the UDDI registry used is the Java WSDP Registry Server v1.0_01 provided in the Java WSDP v1.0.) For a description of the steps involved in registering a Web service, see the JAXR example in Part 1 of this series.

Each provider publishes information about its online book service. For example, Aerns and Cable publishes the following information:

Business Name Aerns and Cable
Contact Information Primary Contact: Bhakti Mehta

Phone number: (877)1111111

Email Address: bhakti.mehta@ae.com
Classification Scheme (classification, code) NAICS (Book Stores, 451211)
Service Online Book Ordering
Service Binding Description: JAXM-FCS (SOAP/HTTP) based binding

Access Point: http://localhost:8080/ancbooks/bookordering

Notice the classification code, 451211. This is the North American Industry Classification System (NAICS) code for book stores. To find the online book service providers, BooomingBusiness.com's application program will query a registry for entries that have the book stores code in their classification.

Notice too the binding information: JAXM-FCS (SOAP/HTTP) based binding. This identifies the service as accessible through JAXM. In looking for online book service providers, BooomingBusiness.com's application program will look for entries that meet this criteria. The access point identifies the URL for the service endpoint. JAXM clients will specify this URL to contact the service. In this example, the URL is a localhost URL, so that the service endpoint is actually on your machine. In a real Web service deployment, the service endpoint would probably be on a different machine.

The sample application includes a class that registers the online book order services. To see the source code for the class, look here.

FunBooks and Aerns and Cable Deploy Their Online Book Services

Both online book service providers want to deploy their services in a J2EE-compliant container. (In the sample application, the container is Tomcat.) They also decide to implement the service endpoints for their services as servlets. To deploy Web server-based components such as servlets in a J2EE-compliant container, each service provider needs to create a WAR file. The service providers create their respective WAR files using J2EE tools.

To illustrate what the services look like, here is the source code for a servlet in FunBook's online book service that exchanges messages synchronously with a JAXM client. For example, when a BoomingBusiness.com employee initiates a book search by submitting search criteria in the online book order form, the "book client" in BoomingBusiness.com's employee portal sends a SOAP message synchronously to various service endpoints. When the endpoint for FunBook's online book service receives the message, this servlet processes it. Notice how the servlet:

  • Gets the request
  • Extracts the query criteria and query value from the request
  • Checks the inventory for the books matching the criteria
  • Sends the response as a SOAP attachment
  • Sends any promotion information as another attachment

These actions are further described in the Process the Message section under Exchanging Messages Without a JAXM Provider.

Here is the source code for a servlet in FunBook's online book service that exchanges messages asynchronously with a JAXM client. For example, when a BoomingBusiness.com employee selects a book from the results page, the book purchaser in BoomingBusiness.com's employee portal sends a SOAP message asynchronously to a JAXM provider, which then routes the message to the target endpoint. When the endpoint for FunBook's online book service receives the message, this servlet processes it and sends a confirmation message back to the sender. Notice how the servlet:

  • Implements the OnewayListener interface
  • Defines the onMessage method
  • Sends the asynchronous reply

These actions are further described in the Process the Message section under Exchanging Messages With a JAXM Provider.

BoomingBusiness.com Creates the Client

BoomingBusiness.com envisions the following flow of events for its online book ordering service. After an employee clicks a "Online Book Ordering Service" link in the employee portal:

Click to enlarge each image

1. The employee portal displays an online book ordering form. 2. The employee specifies search criteria such as the name of a book or an author.
Book ordering form Searching for books
3. Providers that offer books meeting the search criteria respond with information about those books. 4. The employee selects one of the books.
Book list Book selection




The provider of the selected book then sends a note to confirm the transaction.

Here's what BoomingBusiness.com's IT staff plans to implement in support of this interaction:

Let's look at some of these components in more detail.

Book Query JSP: Here is the source code for the book query JSP. The JSP displays the online book ordering form. After the employee enters search criteria in the form, the subsequent action is to invoke the process book query JSP:

<FORM method=post action=processBookQuery.jsp>
...

<font size=+2>Select Criteria and enter information: </font> 
...
<TR valign=center><TH align=left>Search Criteria</TH> 
...
<TH align=left>Search Value</TH> </TR>
<tr valign=center>
<td align=left> ISBN ...
</td>
...

Process Book Query JSP: Here is the source code for the process book query JSP. Notice the use of the book info handler JavaBean. The JSP invokes the validate method in the book info handler JavaBean to validate that a search criteria was selected in the online book order form. The JSP then invokes the executeTest method in the book info handler JavaBean to identify which search criteria was selected, and to initiate the search.

<jsp:useBean id="bookInfoHandler" 
  class="com.sun.eportal.bookordering.BookQueryBean" 
  scope="request"/>
...
<%
    if(bookInfoHandler.validate()) {
       ...
      bookInfoHandler.executeTest(); 

The process book query JSP then invokes the process result JSP to display the search results:

<jsp:forward page="result.jsp?searchCriteria='
    %= searchCriteria %>'&searchValue='
    %= searchValue %>'"  />

Process Result JSP: Here is the source code for the process result JSP. The JSP displays the results page. After the employee selects a book in the results page, the subsequent action is to invoke the book purchaser servlet:

...
<form method=get action=bookpurchaser>
...
<h1 align=center>...Results of your query ...
<jsp:useBean id="bookInfoHandler" 
    class="com.sun.eportal.bookordering.BookQueryBean" 
    scope ="request" />
...
<table border=0>
...
...	
   <TH ...>
...
     <P> Book Supplier</P>
   </TH>
   <TH ...>
     <P>ISBN</P>
   </TH>
...

Notice that the JSP page gets the data returned in the search by the book info handler JavaBean:


<%
  for (int i = 0;i
...
<tr valign=center  bgcolor=666699>
 <td align = left><INPUT TYPE="RADIO" NAME=< ...
  <td align=center> ...<%=bookInfo.getBookProviderName() %> ... 
  <td align=center> ...<%=bookInfo.getBookISBN()%></font> ...
...

Book Info Handler JavaBean: Here is the source code for book info handler JavaBean. Notice the validate method. This is the method that the process book query JSP uses to validate that search criteria was selected. Also notice the execute test method. This method identifies which search criteria was selected, and then invokes the sendQuery method, passing it the search criteria and search value. The sendQuery method creates a book lister object to search for books that meet the submitted search criteria and value.

public boolean validate() {
    boolean allOk=true;
    if (criteria.equals("")) {
        errors.put("criteria","Please choose a criteria ");
        criteria="";
        allOk=false;
        System.out.println("criteria ERROR");
    }
    System.out.println("Validate returnin -> " + allOk +criteria);
            return allOk;
}

public void executeTest(){

    if (criteria.equals("ISBN")){
        sendQuery("isbn",bookISBN);
    }else if (criteria.equals("bookName")){
        sendQuery("name",bookName);
    }else if (criteria.equals("bookAuthor")){
        sendQuery("author1",bookAuthor1);
    }

}

public void sendQuery(String queryType, String queryVal) {
    try {
       BookLister bookLister = new BookLister (  );
       data = bookLister.populateAvailableBooks(
                   queryType, queryVal) ;

Book Lister Class: Here is the source code for the book lister class. Notice the populateAvailableBooks method. This is the method that the book info handler JavaBean uses to search for appropriate providers. The populateAvailableFunds method uses a query method in a client query object to search a Web services registry for providers classified as book stores. The parameters passed to the query method comprise the NAICS classification scheme for book stores.

public Vector populateAvailableBooks ( String queryType,
                      String queryValue ) {
    bookVector = new Vector();
    try {
    String cScheme="ntis-gov:naics";
    String keyName="Book Stores";
    String keyValue="451211";
    String serviceName="Online Book Ordering";

   ...

    ClientQuery clientQuery = new ClientQuery( );
    Vector serviceProviderInfoVector = clientQuery.query( 
               cScheme, keyName, keyValue);
  
    ... 

After the the query returns information from the registry, the book lister examines the binding information exposed by the candidate providers. If the binding is JAXM, the book lister adds the provider's service endpoint to a vector:

if ( spi.getCommunicationType().equals("JAXM") ) {
    jaxmEndpointVector.addElement( spi.getEndpoint() );
}

The book lister then uses the constructMessage method in the book client class to construct a SOAP message for the online book request, and the getAvailableBooks method to send the SOAP message synchronously to each endpoint:

BookClient bookClient = new BookClient();
    bookClient.constructMessage ( queryType, queryValue );
...    

    bookVector = bookClient.getAllAvailableBooks (
                            jaxmEndpointVector  );

Client Query Class: Here is the source code for the client query class. The class uses JAXR to search a Web services registry. Notice how the query method in the class searches the registry for organizations that meet the supplied classification scheme, and retrieves information about service providers that meet the classification criteria:

ClassificationScheme classificationScheme = 
  queryManager.findClassificationSchemeByName(
                             findQualifiers,  cName );
Classification classification = 
  lifeCycleManager.createClassification( 
  classificationScheme, keyName, keyValue );
  
...

BulkResponse response =
  queryManager.findOrganizations(findQualifiers,
             null, classifications, null, null, null);
Collection orgs = response.getCollection();  

For more information about using JAXR to search a Web services registry, see Part 1 of the series.

Book Client Class: Here is the source code for the book client class. The class uses JAXM to send a SOAP message synchronously to a URI endpoint. The book lister class uses the constructMessage method in the book client class to construct a SOAP message for the online book request. Here is the source code for the constructMessage method:

public void constructMessage(String queryType, String queryValue){
    try {
        MessageFactory mf = MessageFactory.newInstance();
        SOAPMessage msg = mf.createMessage();
        SOAPPart sp = msg.getSOAPPart() ;
        SOAPEnvelope envelope = sp.getEnvelope();

        SOAPHeader hdr = envelope.getHeader();
        SOAPBody bdy = envelope.getBody();

        SOAPBodyElement sbe = bdy.addBodyElement
         (envelope.createName("GetBookDetails", "bp",
                         "http://www.bookprovider.com"));

        sbe.addChildElement( envelope.createName("searchCriteria", "bp",
             "http://www.bookprovider.com" )).addTextNode(queryType);	

        sbe.addChildElement( envelope.createName("searchValue", "bp",
            "http://www.bookprovider.com" )).addTextNode(queryValue);	
        message=msg;
    } catch ( Exception e ) {
      e.printStackTrace();
    }
  
}

Notice how the constructMessage method uses the MessageFactory class to create a SOAPMessage object for the message, and how it adds content (in this case, the search criteria and search value) to the body of the message. These actions are further explained in Create a Message and Add Content to the Message.

After constructing the SOAP message, the book lister class calls the the getAvailableBooks method in the book client class to send the SOAP message synchronously. The method is called for each endpoint associated with a registered online book provider (and that exposes a JAXM binding). Each call to the method for a specific endpoint sends the SOAP message synchronously to that endpoint. Because the exchange is synchronous, the getAvailableBooks method waits after sending the message. Here is part of the source code for the getAvailableBooks method:

public Vector getAvailableBooks (String endPoint){
    try {
        Vector retVector = new Vector();
        URLEndpoint urlEndpoint = 
                               new URLEndpoint(endPoint);
        ...

        SOAPConnection conn;
        SOAPConnectionFactory scf = 
                     SOAPConnectionFactory.newInstance();
        conn = scf.createConnection();

        SOAPMessage reply = 
                         conn.call(message, urlEndpoint);

Notice how the getAvailableBooks method gets a connection by creating a SOAPConnection object. It then uses the call method of the connection to send the message. The two parameters in the call are objects that represent the message and the target endpoint. These actions are further explained in Get a Connection and Send the Message (and Wait).

Each service at a target endpoint processes the SOAP message it receives and returns a reply. For example, after receiving the message, the FunBooks Online Book Service processes the message and returns a reply. Here is the source code for FunBook's online book service.

Because it sent a message synchronously, the getAvailableBooks method is blocked until it receives a reply. After the method receives a reply it continues processing. Specifically, it gets the pertinent elements of the reply message, that is, the envelope, body, and child elements. It then uses an Iterator object to access each child element. This is further explained in Process the Reply.

    ...
    SOAPEnvelope envelope = 
                     reply.getSOAPPart().getEnvelope();
    SOAPHeader header = envelope.getHeader();

    orgName = extract( envelope, header, "organization"); 

    ... 
    int attachmentCount = reply.countAttachments();
    ...

    Iterator attachmentIterator = reply.getAttachments();
    while ( attachmentIterator.hasNext() ) {
         ...
         ap = (AttachmentPart)attachmentIterator.next();
         System.out.println(
                           "ContentType is" + ap.getContentType());
         ...

The book client expects the reply to contain two attachments: one, in content type text/xml, that contains book information, and the other, in content type text/html, that contains promotional information. It saves the promotional information attachment in a file, and transforms the book information to XML. It does the transform using the Java API for XML Parsing (JAXP) packages, javax.xml.transform and javax.xml.transform.stream. JAXP v1.2_01 is part of Java WSDP 1.0_01.

     if ( ap.getContentType().equals("text/html") ) {
            String is = (String)ap.getContent();
            FileOutputStream fos = new FileOutputStream (
            "../webapps/ROOT/" +getFileName(endPoint)+
            ".html");

            fos.write(is.getBytes());
            System.out.println("Attachment is saved "+
                 getFileName(endPoint)+".html");

            fos.flush();
            fos.close();
       } else {

             javax.xml.transform.stream.StreamSource 
                 bookSource = (StreamSource)ap.getContent ();
             ...   
             TransformerFactory tfactory = TransformerFactory
                                     .newInstance();
             Transformer transformer = 
                                     tfactory.newTransformer();
             transformer.setOutputProperty(OutputKeys.INDENT,
                  "yes");
             transformer.setOutputProperty(OutputKeys.METHOD,
                  "xml");
             ...

             file = getFileName(endPoint);
             String fileName = "../webapps/ROOT/"+file+".xml";
             FileOutputStream fos = new FileOutputStream
                  (fileName) ;
             transformer.transform(bookSource, 
                   new StreamResult(fos));
             fos.close();
             ...

Book Purchaser Servlet: Here is the source code for the book purchaser servlet. The servlet is invoked when a user selects one of the books in the results page. The servlet uses JAXM to send a SOAP message asynchronously to a JAXM provider, which then routes the message to the target endpoint. Notice how the servlet:

  • Gets a connection with a JAXM provider by creating a ProviderConnection object:

        pcf = ProviderConnectionFactory.newInstance();
        pc = pcf.createConnection();
    

    This is further described in Get a Connection With a JAXM Provider.

  • Identifies a profile for the exchange:

        ProviderMetaData metaData = pc.getMetaData()
        String[] supportedProfiles = 
                           metaData.getSupportedProfiles();
        String profile = null;
    
        for(int i=0; i < supportedProfiles.length; i++) {
        if(supportedProfiles[i].equals("ebxml") {
        profile = supportedProfiles[i];
    

    This is further described in Create a Message.

  • Creates a message from a MessageFactory instance that is initialized with the profile -- the MessageFactory instance uses the basic ebXML profile implementation provided in the Java WSDP:

        mf = pc.createMessageFactory(profile);
    ...
        EbXMLMessageImpl ebxmlMsg = 
              (EbXMLMessageImpl)mf.createMessage();
    

    This is further described in Create a Message.

  • Adds content to the message. In this case the content is the ISBN number of the selected book. Notice the use of the ebXML profile implementation method setSender and setReceiver to identify the location of the client, and to identify the endpoint address of the recipient, respectively:

        ebxmlMsg.setSender(new Party(from));
        ebxmlMsg.setReceiver(new Party(endPoint));
    
        SOAPPart sp = ebxmlMsg.getSOAPPart() ;
        SOAPEnvelope envelope = sp.getEnvelope();
    
        SOAPHeader hdr = envelope.getHeader();
        SOAPBody bdy = envelope.getBody();
    
        SOAPBodyElement sbe = bdy.addBodyElement
              (envelope.createName("SendBookDetails", "bp",
                         "http://bookprovider.com"));
    
        sbe.addTextNode("BuyISBN"+"**"+ isbn);
    
    

    This is further described in Add Content to the Message.

  • Sends the message using the send method of the ProviderConnection object:

        pc.send(ebxmlMsg);
    



[<<BACK] [TOP] [NEXT>>]