The SOAP-RP profile is an implementation of the SOAP WS-Routing specification (formerly known as the SOAP Routing Protocol), which can be downloaded from http://msdn.microsoft.com/ws/2001/10/Routing. Although a full discussion of the specification is outside the scope of this book, this section contains a brief overview and a description of the API that JAXM provides to allow the construction of messages that conform to the specification.
SOAP-RP defines a SOAP header and a set of rules to be followed that enable a SOAP message to be routed from a sender, through zero or more intermediate systems to its final destination. The SOAP-RP header, which is called path, contains child elements from the set listed in Table 4-4.
Element |
Description |
---|---|
Contains the URI of the ultimate destination of the message. This element is added by the sender and cannot be changed as the message passes through intermediate systems. |
|
Contains a URI that identifies the sender of the message. |
|
If present, this tag contains zero or more URIs that define a list of intermediate systems that must be visited before the message is delivered to its final recipient. All of the systems in this list must be visited in the order in which they appear. If this is not possible, the message is discarded and a fault is returned (see the fault element). Each URI is enclosed in a child element called via. As each intermediate system is traversed, it removes its own via entry, which must be at the front of the list. Intermediate systems can add new via entries to the path as necessary, before forwarding. |
|
If present, this tag allows a reverse path to be created as the message traverses the route from sender to receiver. Each intermediate system that handles the message typically inserts its own URI as the first child of this element, in the form of a via tag, although it may insert the URI of some other system if that system would be a more appropriate hop in the return path. The final recipient of a SOAP message that contains a reverse path usually extracts it and stores it as the fwd element of the message that it sends in reply. The rev tag is inserted by the initial sender. If it is not present, it cannot be added by an intermediate system, and therefore a reverse path cannot be constructed. |
|
Contains a URI that defines the intent of the message. Its meaning is private to the application and therefore there is no well-known set of permitted action values. This element must be set by the sender and cannot be modified by intermediate systems. |
|
Contains a URI that uniquely identifies the message in which it is contained. The identifier is used to link a reply or a fault to the original message that caused it to be sent. |
|
Contains the value of the id element for the message to which it is related. This element is used when returning a fault, or in an application-level reply to a message sent earlier. |
|
Used to report an error condition detected when trying to route or handle a SOAP-RP message. fault must be used in conjunction with relatesTo to indicate the message to which the fault applies. The reason for a fault is described by two child elements that must always be present. The code element contains a numeric code defined by the WS-Routing specification and is intended for application use. The reason element contains a textual description intended for logging or display. Depending on the fault code, other child elements may be present. Refer to the WS-Routing specification for details. |
The path element and all of its child elements are defined in the namespace associated with the URI http://schemas.xmlsoap.org/rp.
In outline, here is how the SOAP-RP path header is used when routing a message:
The message originator constructs a path containing an id element to uniquely identify the message and an action element that specifies what the receiver should do with the message. It may also include a to element, a fwd element, a from element, and a rev element. If it is present, the to element indicates the URI of the intended recipient. The fwd element may contain an ordered set of URIs that determine the route to be taken to reach the recipient. If the header does not contain a to element, then the last entry in the fwd element must be the URI of the target system. A rev element is included only if a reverse path is to be created and would normally be empty.
The message originator sends the message to the first intermediary system.
The intermediate system looks for a via element in the fwd element of the path header of the received message. If such an element exists, it must contain the intermediate system's own URI; if it does not, a fault is generated and returned to the sender. Assuming that the via entry is valid, it is removed.
If the header contains a fwd entry, the intermediate system may introduce additional via entries in the message path if appropriate. This allows routing to proceed even if the message sender does not know the complete route to the destination when sending the message.
If the path header contains a rev element, the intermediate system may add a URI as its first child element to indicate a node on the reverse path for the message.
The intermediate system uses the first via entry of the fwd element as the URI for the next hop of the path. If there are no remaining via entries, the URI in the to element is used instead. If there is no to element, a fault is generated and returned to the sender.
When the message reaches its intended recipient, it should validate that its own URI is either in the to element or in the only remaining via entry of the fwd element. Failing this, a fault should be generated.
Should the receiver need to send a message back to the originator, it again includes a path header with id and action elements, together with a relatesTo element whose value is the URI from the id element of the original message. The to, fwd, from, and rev elements may also be included and are used as just described. If the original message contains a rev element, then its content may be used to create the fwd element of this message, but this is not mandatory.
For a definitive description of the message routing process, refer to the WS-Routing specification.
In order to create SOAP-RP messages, you need a MessageFactory that implements the SOAP-RP profile. As described earlier, once you have a ProviderConnection for a provider that supports this profile, you can obtain a suitable factory using the createMessageFactory( ) method:
// Get a message factory for the SOAP-RP profile MessageFactory msgFactory = conn.createMessageFactory("soaprp");
To arrange for the correct factory to be used when receiving SOAP-RP messages in the onMessage( ) method of JAXMServlet, you must override its init( ) method to install the same MessageFactory, as shown in Example 4-4.
All SOAP messages created using this factory are of type com.sun.xml.messaging.soaprp.SOAPRPMessageImpl. They have a minimal path header populated only with empty fwd and rev elements.[7] To include other elements or to add entries to the forward and reverse paths, you need to use convenience methods provided by the SOAPRPMessageImpl class, definitions of which you will find in the reference section of this book. A typical SOAP-RP message header is shown in Example 4-7, earlier in this chapter. The following sections cover some of the more important aspects of this API.
[7] In fact, this is not a good default. Ideally, fwd and rev elements are added only when specifically requested, since the absence of the rev element has a specific meaning. With the current implementation, it is not possible to create a path header without a rev element. This may change in the future, of course.
The SOAP-RP specification requires that each message has a unique identifier that can be used to correlate it with either a fault or a reply. Fortunately, you don't have to generate these identifiers for yourself, since one is automatically created each time the factory returns a new SOAP-RP message. The getSOAPRPMessageId( ) method can be used to retrieve the identifier for a message. The most likely reason for calling this method is to use its return value to set the value of the relatesTo element when building a fault or reply message:
reply.setRelatesTo(request.getSOAPRPMessageId( ));
The API includes a method called newMessageId( ) that lets you set a new identifier for a message, but it is unlikely that you will need to use this because it is called for you when a SOAP-RP message is created.
The forward and reverse message paths are held as Vectors containing Endpoint objects. You can retrieve the complete path and modify it directly using the getSOAPRPFwdMessagePath( ) and getSOAPRPRevMessagePath( ) methods. There are also slightly more abstract methods that let you update a path without having to fetch a complete copy of it:
public void updateFwdMessagePath(Endpoint uri, int position); public void updateRevMessagePath(Endpoint uri);
The updateFwdMessagePath( ) method requires both the URI to be added and the position in the path at which it is to be inserted, where the value 0 indicates that the entry should be added at the front of the list. The updateRevMessagePath( ) method does not require a position index, since new elements in the reverse path are always added at the start of the list.
If you need to create a reply or generate a fault for a message, you might want to use the reverse path from the message as the forward path for the reply or the fault. To do this, use the getSOAPRPRevMessagePath( ) and updateFwdMessagePath( ) methods together:
Vector revPath = soapMsg.getSOAPRPRevMessagePath( ); int count = revPath.size( ); for (int i = 0; i < count; i++) { replyMsg.updateFwdMessagePath((Endpoint)revPath.get(i), i); }
|
Fault information is included using the fault element, which is a direct child of the path header. Unfortunately, the reference implementation does not provide any API for accessing this information or creating it if it is not already present. Therefore, if you want to add fault information to a new message or extract it from a message that you have received, you must do so by directly accessing the path header, and using the usual SAAJ APIs to add or locate the fault element. Here's how you might locate the path header for a message:
final String SOAPRP_URI = "http://schemas.xmlsoap.org/rp";
message.addHeaders( );
SOAPHeader header = message.getSOAPPart().getEnvelope( ).getHeader( );
Iterator iter = header.getChildElements( );
while (iter.hasNext( )) {
SOAPElement elem = (SOAPElement)iter.next( );
Name name = elem.getElementName( );
// Compare both the local name and the namespace URI
if (name.getLocalName( ).equalsIgnoreCase("path") &&
name.getURI( ).equals(SOAPRP_URI)) {
// "elem" is the path header element.
}
}
When adding fault information to a newly created message, you should call the addHeaders( ) method as shown in this code extract before searching for the path element, since the header is not actually created until this method is invoked. This is not necessary in the case of a message received in the onMessage( ) method of a servlet, since the headers are created automatically as part of the process of converting the received XML to a SOAPMessage.