You have now seen and deployed all of the code for both the sender and receiver parts of the JAXM message echo example. If, however, you were to start your web browser and point it at http://localhost:8080/SOAPRPSender/request, which is the URL that causes the sender servlet to transmit a message, you would find that after about 30 seconds, the sender would give up waiting for a reply from the receiver and an error page would be displayed by the browser. Although all of the code is in place, the proper JAXM configuration has not been set up to allow the providers to exchange messages. In this section, we look at how to configure the JAXM reference implementation.
A message traveling from the sending servlet to the receiver has to make three hops:
From the sender to the local provider
From the local provider to the remote provider
From the remote provider to the receiving servlet
We saw earlier that a JAXM client logically connects to its local
provider using the
createConnection( ) method, but we
didn’t see how the provider itself is located. This
information is held in a file called
which must be located in the
CLASSPATH of the JAXM
client. Since both the sender and the receiver servlets in this
example are deployed as web applications, their
client.xml files should be placed in the
WEB-INF/classes directory of their WAR files, as
shown in the following listing of the files that make up the web
archive for the
META-INF/MANIFEST.MF WEB-INF/classes/ora/jwsnut/chapter4/soaprpsender/SOAPRPSenderServlet.class WEB-INF/classes/client.xml WEB-INF/web.xml
A full description of the
client.xml file will
be found in Chapter 8. The content of the
client.xml file used by the
SOAPRPSender servlet is shown in Example 4-6, in which the line numbers on the left have
been added for ease of reference only.
Example 4-6. The client.xml file for the sending servlet
1 <?xml version="1.0" encoding="ISO-8859-1"?> 2 3 <!DOCTYPE ClientConfig 4 PUBLIC "-//Sun Microsystems, Inc.//DTD JAXM Client//EN" 5 "http://java.sun.com/xml/dtds/jaxm_client_1_0.dtd"> 6 <ClientConfig> 7 <Endpoint> 8
urn:SOAPRPSender9 </Endpoint> 10 <CallbackURL> 11
http://localhost:8080/SOAPRPSender/message12 </CallbackURL> 13 14 <Provider> 15
<URL>http://localhost:8081/jaxm-provider/sender</URL>17 </Provider> 18 </ClientConfig>
The lines shown in bold relate to the configuration of the sending
servlet; the other lines are fixed content that are the same in all
client.xml files. The
Provider element at the end of the file is used
when the client connects to the messaging provider. The two child
elements are used as follows:
The URI value identifies the provider in use. For the JAXM reference
implementation, you must use the value http://java.sun.com/xml/jaxm/provider. The
JAXM code that implements the
interface and the provider itself communicate by adding private
header entries to the messages sent by JAXM clients. This URI is used
as the namespace for the XML elements in these header entries; it is
also used to set their actor attribute. When the provider receives a
message from a JAXM client, it removes and actions all headers for
which the actor attribute has this fixed value.
The URL is where messages from the JAXM client to the provider are
actually sent. For the reference implementation in the JWSDP, the
provider is a Tomcat service called
accessible at port 8081. The provider is not required to be on the
same host as the JAXM client. If the provider is not co-located with
the client, then the name of the provider’s host
should be used instead of
Figure 4-5 shows how the URL field of the
Provider element is used to locate the JAXM
client’s local provider.
When a provider receives a message for delivery to a client, it needs
to be able to match the destination address of the message to the
client that provides service at that address. As we saw earlier, the
destination address that is placed in a SOAP-RP header is a URI that
identifies the target of the message — it need not be a URL.
Therefore, the provider maintains a list of mappings from the
Endpoint URI to the URL of the client that should
receive messages destined for that URI. In the
client.xml file, the
element declares the URI that corresponds to the client, and the
CallbackURL element specifies the URL to which
messages for that URI should be delivered. In terms of the example
that we are using in this chapter, the sending servlet advertises its
URI as urn:SOAPRPSender. Since
the sending servlet expects to receive messages on the URL
this is the URL to which the sending servlet’s URI
should be mapped. Hence,
entries in the
client.xml file for the sending
servlet would be:
<Endpoint> urn:SOAPRPSender </Endpoint> <CallbackURL> http://localhost:8080/SOAPRPSender/message </CallbackURL>
In the case of the receiving servlet (which as a JAXM client also
requires its own
client.xml file), these entries
would look like this:
<Endpoint> urn:SOAPRPEcho </Endpoint> <CallbackURL> http://localhost:8080/SOAPRPEcho/message </CallbackURL>
The receiving servlet also needs a
element containing the URL of its local provider that, if you deploy
both the sending and receiving servlets on the same host, is the same
provider used by the sending servlet and therefore requires the same
client.xml file solves the problem of how to
route messages between clients and a provider, but there remains the
issue of how the providers route messages among themselves. In the
case of the example used in this chapter, the provider needs to
deliver messages addressed to the URIs urn:SOAPRPEcho and urn:SOAPRPSender, by passing them to
whichever provider the clients owning these endpoints are
connected. In order to make this possible, providers
are configured with URI-to-URL mappings that are similar to those
created by the
CallbackURL elements used in the
client.xml file. Each provider must be
configured with a mapping for each remote URI to which messages from
its local clients might be addressed, specifying the URL of the
provider to which messages carrying that URI as a destination address
must be delivered (and not the URL of the receiving client).
In the reference implementation, these mappings are stored in a file
, which resides in the
/WEB_INF directory of the
jaxm-provider service, details of which
you’ll find in Chapter 8.
Fortunately, you don’t need to deal with this file
directly — instead, you can view and change the mappings using
the JAXM provider administration service, which can be accessed using
a web browser.
The provider administration tool is a web
application that provides a user interface that lets you configure
the JAXM provider without having to manually edit its
provider.xml file. Once you understand the
content of this file (details of which are provided in Chapter 8), you’ll find it very easy to
use the administration tool, so we’re not going to
describe it in great detail. Here, we need to use it to add endpoint
mappings for the URIs urn:SOAPRPEcho and urn:SOAPRPSender. Assuming that this service
is running on the same host as your browser, the URL that you need to
use to access it is http://localhost:8081/jaxm-provideradmin.
When you attempt to connect to this service, you are
prompted to supply a username and password. When you installed the
JWSDP, you were prompted to supply a username and a password, and you
should use the same username and password to access the configuration
service. If you can’t remember them, you can find
them in the
tomcat-users.xml file, which is held
conf directory of the web server. Here is
what this file typically looks like, with the important lines
highlighted in bold:
<?xml version='1.0'?> <tomcat-users> <role rolename="admin"/> <role rolename="manager"/> <role rolename="provider"/> <user username="JWSUserName" password="JWSPassword" roles="admin,manager,provider"/> </tomcat-users>
In this case, supply the username
JWSPassword. These values can also be
found in the
jwsnutExamples.properties file in
your home directory, assuming you created it as described in Chapter 1.
Once you reach the configuration service’s home
page, expand the tree view that you’ll see on the
left, and select the entry for
http below the
SOAPRP profile. You should see a screen like that
shown in Figure 4-6.
This screen contains, among other things, the endpoint mappings for messages being sent by the provider for the SOAP-RP profile using HTTP as the underlying communications protocol. The URL associated with the URI urn:SOAPRPEcho needs to be the one required to access the provider to which the receiving servlet is attached, whereas the URL for the URI urn:SOAPRPSender should be that of the provider for the sending servlet. A provider has three available URLs; for the case of the JWSDP reference implementation running in the Tomcat web server, these URLs are listed in Table 4-2, where it is assumed that the provider and the clients are all running on the same machine.
Table 4-2. URLs for the JAXM provider in the reference implementation
Address to which JAXM clients send outgoing messages. This URL is
configured in the client’s
Address to which messages using the SOAP-RP profile should be sent.
Address to which messages using the ebXML profile should be sent.
If the target provider is on a different machine, substitute the
hostname of that machine for
localhost in these
Since the messages in the example used in this chapter use the SOAP-RP profile, both of the JAXM client URIs should be mapped to the URL for the SOAP-RP receiving URL of the target provider, which will be http://localhost:8081/jaxm-provider/receiver/soaprp. To add these mappings, select “Create New Endpoint Mapping” from the combo box at the top right of the screen. You are presented with a form that allows you to enter a URI along with its corresponding URL, as shown in Figure 4-7, where the mapping for urn:SOAPRPEcho has been entered.
The mappings that you need to enter are shown in Table 4-3.
Table 4-3. URI mappings for the JAXM SOAP-RP profile example
Once both mappings are set up, they should appear on the main screen as shown in Figure 4-8. Select “Save to Profile” to save these mappings.
At this point, the provider is properly configured to forward messages to either URI. Of course, if the clients are on separate machines and use different providers, it is then necessary to configure each provider separately:
The provider local to the sending servlet is configured with a mapping for the URI urn:SOAPRPEcho — that is, the URI to which it sends. The URL for this mapping refers to the other provider.
The provider local to the receiving servlet similarly requires a mapping for the URI urn:SOAPRPSender.
You can now finally run the example that we have been using throughout this chapter. To do so, simply enter the URL http://localhost:8080/SOAPRPSender/request into your browser. After a short delay, you should see the SOAP message that was sent by the sending servlet and returned by the receiver, an example of which is shown in Example 4-7. This message has been reformatted for the sake of readability.
Example 4-7. A SOAP-RP message sent via a messaging provider
<?xml version="1.0" encoding="UTF-8"?> <soap-env:Envelope xmlns:soap-env="http://schemas.xmlsoap.org/soap/envelope/"> <soap-env:Header> <m:path xmlns:m="http://schemas.xmlsoap.org/rp"> <m:from>urn:SOAPRPEcho</m:from> <m:to>urn:SOAPRPSender</m:to> <m:id>9a85b633-2c8f-4d2e-84a5-ff6b21c05f61</m:id> <m:relatesTo>3166c06a-e38c-466e-b43e-d55a37f3d3fc</m:relatesTo> <m:fwd/> <m:rev/> </m:path> </soap-env:Header> <soap-env:Body> <tns:Sent xmlns:tns="urn:SOAPRPSender">This is the content</tns:Sent> </soap-env:Body> <tns:Date xmlns:tns="urn:SOAPRPEcho">Thu Aug 08 15:58:53 BST 2002</tns:Date> </soap-env:Envelope>
The elements in the message header are defined by the SOAP-RP
protocol, further information on which can be found later in this
chapter. Note the
elements, which contain the URIs for the sending and receiving
servlets, and the
Date element, which follows the
SOAP body and contains the date and time at which the message was
processed by the receiver.
As a summary of how messaging providers use the JAXM configuration information, the following is a step-by-step account of the way in which a SOAP-RP message is sent from a JAXM client to its destination. The return path would obviously be identical, but with the addresses reversed.
The receiving servlet initializes. As it does so, it uses the
ProviderConnectionFactory and the
ProviderConnection interface to establish a
connection to its local provider, as well as calls the
getMetaData( ) method. In order to contact the provider to obtain the
metadata, the JAXM code in the client accesses the receiving
client.xml file to
locate the provider’s URL from the
Provider element — in this case, http://localhost:8081/jaxm-provider/sender.
It also passes to the provider the information in the
elements so that the provider knows that messages intended for the
URI urn:SOAPRPEcho should be
delivered to the URL http://localhost:8080/SOAPRPEcho/message.
The sending servlet uses the
ProviderConnectionFactory and the
ProviderConnection interface to establish a
connection to its local provider. It also obtains a
MessageFactory for the
profile and constructs a message, setting the
address to urn:SOAPRPSender and
to address to urn:SOAPRPEcho.
The client uses the
send( ) method to transmit the message. The JAXM
code in the client accesses the sending servlet’s
client.xml file and uses the URI and URL in the
Provider element to find the URL of the provider
— in this case, http://localhost:8081/jaxm-provider/sender.
Also, if it has not already done so, it passes to the provider the
information in the
CallbackURL elements so that it can map the
sending servlet’s URI (urn:SOAPRPSender) to its message callback URL
The message is then delivered to the provider at the URL http://localhost:8081/jaxm-provider/sender.
When the provider receives the message, it stores it in its outgoing
message queue. There is a separate set of message queues for each
profile that the provider supports, which the reference
implementation keeps in a directory hierarchy in temporary storage
provided by its host container. If you are running the JWSDP in the
Tomcat web server, you’ll find the messages that the
provider sends and receives held below the directory
Engine\jwsdp-services\jaxm-provider, relative to the JWSDP
When the message is to be transmitted from the outgoing message
queue, the provider extracts its destination address. In order to do
this, the provider needs to understand where it will find this
address, which is profile-dependent. The provider can do this because
that represents a SOAP-RP message is derived from
(which has abstract methods that extract to
from addresses from the message).
SOAPRPMessageImpl implements these methods so that
they extract the correct parts of the SOAP-RP header. The message
class for the ebXML profile similarly implements them to extract the
Party object from the message (see Section 4.6 later in this chapter, for
further information on this). The fact that the provider has to be
able to get the destination address from within a SOAP message
explains why nonprofiled messages that do not contain a destination
address (i.e., SAAJ messages created using the default
MessageFactory) cannot be sent using a provider.
The provider uses the destination address to check its URI-to-URL mapping, set up using the JAXM provider administration tool, to find the URL of the provider to which the message should be sent. In this case, the destination address is urn:SOAPRPEcho, which maps to the URL http://localhost:8081/jaxm-provider/receiver/soaprp. This happens to be a URL belonging to the same provider, of course, but this does not matter. The local provider delivers the message to its peer using an HTTP POST request to this URL. If delivery fails, the provider retries on the assumption that the remote provider is not yet started or there is a problem with network connectivity.
When the peer provider receives the incoming SOAP-RP message, it
stores it in its received message queue. Subsequently, an attempt is
made to deliver this message to the correct JAXM client. Delivery is
performed by extracting the destination address from the message, in
the same way as the sending provider did when transmitting the
message, and using it to access the
mapping table built from the
client.xml files of
the clients connected to the provider (see Figure 4-5). Here, the destination address urn:SOAPRPEcho has been registered by the
receiving servlet and mapped to its delivery URL http://localhost:8080/SOAPRPEcho/message (see
Step 1). The provider delivers the message using an HTTP POST request
to that URL. If delivery fails, or if there is no entry for the
destination URI in the provider’s mapping table, the
provider will retry delivery later, on the assumption that the client
has not yet been started but will register later.
The final point to mention in our
discussion of JAXM configuration discusses the reason for including
load-on-startup element in the
web.xml file of the receiving servlet in our
example so that it is loaded when the web container initializes. As
we said earlier in Section 4.4.1, a provider uses the
Endpoint elements from the
client.xml files of the JAXM clients that are
connected to it to determine where to route the messages it receives.
A provider cannot directly read these files — instead, they are
read and a representation of their content is passed (in a private
SOAP message header) when a client connects to the
provider. The sending servlet, which is not marked
to be loaded at startup, initializes and connects to the provider
when the request from the browser sent to the URL http://localhost:8080/SOAPRPSender/request is
received by the web container; therefore, it is registered with the
provider before a message addressed to it needs to be dispatched.
However, since the receiving servlet’s URL is only
referenced when the provider tries to deliver a message to it based
on an entry in the provider’s client URI-to-URL
mapping table, if the receiving servlet were not marked to be loaded
at startup, it would not have initialized and connected to the
provider, and therefore its URL would not be registered in this
 In general, when there are two JAXM clients on separate machines, there are two providers involved. However, if both the sender and receiver are deployed on the same machine, the likelihood is that they will use the same provider (although you could arrange to run two providers on the same machine). Even though this is the case, the configuration still has to be created in the same way as if there were two providers. The description here is consistent with that.
 Exactly when this happens is, of course,
implementation-dependent. At the time of this writing, the reference
implementation does this the first time the client requests
ProviderMetaData, or when the
method is called for the first time. The fact that this is left so
late also explains why a client that simply listens passively for
messages, such as the receiving servlet in the example in this
chapter, must call
getMetaData( ) as shown in
Example 4-4, even though it doesn’t
make use of the
ProviderMetaData. The purpose of
the call is simply to register the receiver’s
Endpoint with the provider so that it can receive