|
What's This About? |
XML Technologies for
RPC Calls and Messaging |
JAX-RPC |
Build and Run
the Sample Application
Web Services Developer Pack
Part 2: RPC Calls, Messaging, and the JAX-RPC and JAXM API
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.
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.
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.
|
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.
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.
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:
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.
|
|
|
|
3. Providers that offer books meeting the search criteria respond with information about those books.
|
4. The employee selects one of the books.
|
|
|
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:
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:
- Sends the message using the send method of the
ProviderConnection object:
pc.send(ebxmlMsg);
[<<BACK]
[TOP]
[NEXT>>]
|
|