Like any good messaging protocol, SOAP defines the concept of a message header. It is an optional part of any SOAP message. If it exists, the header contains information about the message, or about the context in which the message is sent, or basically whatever the creator of the message thought was a good idea to put there instead of the actual body of the message. Obviously, both the sender and the receiver of the message need to agree on its format.
I could spend this entire article on the discussion about what kind of data is appropriate to be put into the header instead of the body. The most commonly used example is security information and, in fact, there is a specification (WS-Security) describing how to store userid and password information or other authentication credentials in the SOAP header.
However, in this article, I will focus on the programming side of things and show you how to deal with SOAP header fields, both from a client and server side perspective. To keep the example as simple as possible, I will use the good old "Stockquote" example, that is, a Web service returning a stock quote.
As mentioned above, if two applications exchange SOAP messages with headers, they have to agree on the data format of these headers. Naturally, the description of this format goes into the WSDL definition for the Web service. One decision you have to make is whether the data that is stored in the SOAP header is part of your functional, or business interface. In other words, is the header information part of your port type (that is, included in the input or output message of an operation), or is it not? We will assume here for now that it is. This means that it is not only defined in the SOAP binding, but also part of the port type, namely in the <getLastSellPriceRequest> message.
WSDL allows you to define SOAP header fields for input and/or output messages separately. For this example, we will assume that you want to pass along a timestamp field with the request message, to allow measuring response times of the service, for example. Again, the focus here is not on what you send in the header and why, but how it is done.
Listing 1 shows an extract of the WSDL definition file (you can find a download link for the complete example in the Resources section).
Listing 1. Example WSDL definition with SOAP header field
<?xml version="1.0" encoding="UTF-8"?>
<wsdl:definitions targetNamespace="http://soapheader.ibm.com" ...>
<wsdl:types>
<schema ...>
<element name="getLastSellPrice">
<complexType>
<sequence>
<element name="ticker" nillable="true" type="xsd:string" />
</sequence>
</complexType>
</element>
<element name="getLastSellPriceResponse">
<complexType>
<sequence>
<element name="getLastSellPriceReturn" type="xsd:float" />
</sequence>
</complexType>
</element>
<element name="quote_timestamp" type="xsd:dateTime" />
</schema>
</wsdl:types>
<wsdl:message name="getLastSellPriceRequest">
<wsdl:part name="parameters"
element="intf:getLastSellPrice"/>
<wsdl:part name="request_header"
element="intf:quote_timestamp"/>
</wsdl:message>
<wsdl:message name="getLastSellPriceResponse">
<wsdl:part name="parameters"
element="intf:getLastSellPriceResponse"/>
</wsdl:message>
<wsdl:portType name="StockService">
<wsdl:operation name="getLastSellPrice">
<wsdl:input name="getLastSellPriceRequest"
message="intf:getLastSellPriceRequest"/>
<wsdl:output name="getLastSellPriceResponse"
message="intf:getLastSellPriceResponse"/>
</wsdl:operation>
</wsdl:portType>
<wsdl:binding name="StockServiceSoapBinding"
type="intf:StockService">
<wsdlsoap:binding style="document"
transport="http://schemas.xmlsoap.org/soap/http"/>
<wsdl:operation name="getLastSellPrice">
<wsdlsoap:operation soapAction=""/>
<wsdl:input name="getLastSellPriceRequest">
<wsdlsoap:header message="intf:getLastSellPriceRequest"
part="request_header" use="literal"/>
<wsdlsoap:body use="literal" parts="parameters"/>
</wsdl:input>
<wsdl:output name="getLastSellPriceResponse">
<wsdlsoap:body use="literal"/>
</wsdl:output>
</wsdl:operation>
</wsdl:binding>
<wsdl:service name="StockServiceService">
...
</wsdl:service>
</wsdl:definitions>
|
The most interesting part of this WSDL definition is highlighted in bold. The SOAP bindings, in the <input> element, contain both a <header> and a <body> element, defining which message parts are transferred in the header and which in the body. In this case, the timestamp goes into the header.
Now you want to provide an implementation of the service described above. I choose JAX-RPC as the server side model, so that you have a standardized Java application hosting the service. There are several options in mapping the header information, so let's look at each of them in a bit more detail.
The JAX-RPC specification describes the concept of message handlers. A server side message handler can intercept a request message before it reaches the Web service, or it can intercept a response message before it is sent back to the requestor. More than one message handler can be invoked for a service, leading to a so called "handler chain". Which handlers are invoked for a service is configurable, but can also be set programmatically. I will cover a much more detailed explanation and examples for JAX-RPC handlers in a separate article in the future.
A SOAP header often contains "out-of-band" information. This is information that is not directly part of the business functionality of a service, and thus should not be passed into the service implementation. A JAX-RPC message handler can extract SOAP header fields from an incoming message, or add new headers to an outgoing message, without the actual service implementation even knowing about it.
Listing 2 shows an example message handler retrieving and removing SOAP header fields from an incoming message (again, you can find a link to the complete source in the Resources section).
Listing 2. JAX-RPC message handler example
public class SOAPHeaderHandler extends javax.xml.rpc.handler.GenericHandler {
...
public boolean handleRequest(MessageContext arg) {
if (arg instanceof SOAPMessageContext) {
SOAPMessageContext context = (SOAPMessageContext)arg;
try {
SOAPHeader header =
context.getMessage().getSOAPPart().getEnvelope().getHeader();
Iterator headers =
header.extractHeaderElements
("http://schemas.xmlsoap.org/soap/actor/next");
while (headers.hasNext()) {
SOAPHeaderElement he =
(SOAPHeaderElement)headers.next();
// process the retrieved header element here
}
} catch (SOAPException x) {
// insert error handling here
}
}
return true;
}
}
|
Parameter on the Service Endpoint Interface (SEI)
Another option for dealing with a SOAP header field is to simply add it to the Service Endpoint Interface (SEI) of the Web service. This allows you to process the SOAP header directly in the service implementation.
Exactly how the header information in the WSDL definition is mapped into a parameter on the SEI depends on your JAX-RPC implementation, because the specification does not define how this is done. For example, your SEI for the WSDL example above may look like Listing 3 (generated by WebSphere Studio Application Developer 5.1).
Listing 3. Service Endpoint Interface example
public interface StockService_SEI extends java.rmi.Remote {
public float getLastSellPrice(
String ticker,
java.util.Calendar request_Header)
throws java.rmi.RemoteException;
}
|
Most likely, your JAX-RPC implementation will generate header information as part of the SEI if the header is defined as a message part in the port type. In the example shown in Listing 1 above, the "request_header" part is included in the <getLastSellPriceRequest> message and hence is mapped to a parameter on the SEI.
The ServiceLifecycle interface
This option also provides header information to the service implementation class. However, it does not show up on the endpoint interface, but must be explicitly retrieved from the message. You can view this as a mix of the two earlier methods: the content of the SOAP header is retrieved from the passed MessageContext not in a message handler, but in the service implementation class.
To get access to the SOAP message, your service implementation class must implement the javax.xml.rpc.server.ServiceLifecycle interface. It contains a method called init(), which is used by the JAX-RPC engine to pass a context object into the service implementation instance. In the actual service method, you can use code that is similar to that described earlier for the message handler to retrieve the content of the header. Listing 4 shows what that looks like for our example.
Listing 4. The ServiceLifecycle interface
public class StockService implements
StockService_SEI, javax.xml.rpc.server.ServiceLifecycle
{
ServletEndpointContext ctx;
public float getLastSellPrice(String ticker, java.util.Calendar request_Header) {
float f = 0.0f;
if (ctx != null) {
ServletContext servletContext = ctx.getServletContext();
SOAPMessageContext mc =
(SOAPMessageContext)ctx.getMessageContext();
// process SOAP header as shown in the message handler
}
// further processing...
return f;
}
public void init(Object arg0) throws ServiceException {
if (javax.xml.rpc.server.ServletEndpointContext.class.isInstance(arg0))
ctx = (ServletEndpointContext) arg0;
}
|
Processing of SOAP handlers on the client side is not much different from what I have discussed above for the server side. You can directly use the first two options.
JAX-RPC defines the concept of message handlers for clients just like for servers, and they are normally defined in the client Web service deployment descriptor.
The other option is to add the SOAP header fields as parameters on the client side stub, so that they can directly be passed as part of the invocation. Respectively, they can also be returned as a result of the invocation, if the header fields are defined for the output message.
SOAP header fields can be created and processed by JAX-RPC applications in a variety of ways. They can be part of the business interface of a service, or be "hidden" and processed by message handlers. In either case, the service contract, that is, the WSDL definition, must define any SOAP header fields that are used. Specific JAX-RPC engines will support all or a subset of the options described above.
| Name | Size | Download method |
|---|---|---|
| ws-tipjaxcode.zip | HTTP |
Information about download methods
- Find the SOAP specification describing how SOAP headers are represented at the W3C SOAP 1.1 Web site.
- Check out the Web Services Security (WS-Security) Specification.
- The W3C WSDL 1.1 Web site contains the WSDL specification with a description of how to add headers to the SOAP binding.
- Download the source code used in this article. (zip file)
- "Developer's Introduction to JAX-RPC, Part 1" and "Developer's Introduction to JAX-RPC, Part 2" (developerWorks, January 2003) provide a great introduction to the JAX-RPC standard.
- The WebSphere SDK for Web Services (WSDK) provides you with an easy entry into Web services programming.
Andre Tost works as a Solution Architect in the WebSphere Business Development group, where he helps IBM's Strategic Alliance partners integrate their applications with WebSphere. His special focus is on Web services technology throughout the WebSphere product family. Before his current assignment, he spent ten years in various development and architecture roles in IBM software development, most recently for the WebSphere Business Components product. Originally from Germany, he now lives and works in Rochester, Minnesota. In his spare time, he likes to spend time with his family and play and watch soccer whenever possible. You can contact Andre at atost at us.ibm.com.




