Summary:
This article tries to address the following questions
- How to define SOAP headers in a WSDL?
- How to deal with SOAP headers when following the top-down and bottom-up development approaches?
- How to make the SOAP headers available to the implementation when the headers are defined using explicit or implicit styles using a top-down or a bottom-up approach?
Development Environment: WebSphere Integration Developer (WID) 6.2
Defining SOAP headers in WSDL (Implicit and Explicit Styles):
“An implicit SOAP header is a SOAP header that fits one of the following descriptions:
- A message part that is declared as a SOAP header in the binding in the Web Services Description Language (WSDL) file, but the message definition is not referenced by a portType element within a WSDL file.
- An element that is not contained in the WSDL file.” – [4]
The author of the wonderful article named “Implement implicit and explicit SOAP headers” has described both styles in great detail.
Two cases when using SOAP headers:
- The data in the SOAP header is either used or populated in the implementation of the operation.
- The data in the SOAP header is neither used nor populated in the implementation of the operation.
In particular, the rest of this article focuses on case 1 with both Implicit and Explicit styles.
Development Approach (Top-Down and Bottom-Up):
In a Top-Down development approach of a web service, the WSDL is first defined from which the java artifacts that are necessary to implement the service are generated.
For a top-down approach, you could use
- WSDL2Java command in case of JAX-RPC
- wsimport command in case of JAX-WS
In a Bottom-Up approach of a web service, the WSDL is generated from the java artifacts that are associated with the implementation of a particular service.
For a bottom-up approach, you could use
- Java2WSDL command in case of JAX-RPC
- wsgen command in case of JAX-WS
Combining the two options of the development approach with the two options of SOAP header definition styles, we end up with 4 combinations.
- Top-Down – Explicit
- Top-Down – Implicit
- Bottom-Up – Explicit
- Bottom-Up – Implicit
JAX-RPC
Top-Down – Explicit
If you have defined your SOAP header using the explicit style in the WSDL, JAX-RPC maps the explicit headers to the Service Endpoint Interface (SEI) of the web service. Both request and response headers if any will be available for the implementation code.
With an explicit header definition style, after the java artifacts are generated, the SEI looks like the following for one operation named “returnInput” that has both request and response headers defined
public interface TestTopDownHeaders extends java.rmi.Remote {
public void returnInput(com.test.TestInput parameters, com.test.BaseRequest_Type
request_header, com.test.holders.TestOutputHolder parameters2,
com.test.holders.BaseResponse_TypeHolder response_header) throws
java.rmi.RemoteException;
}
Note that the headers are passed in as parameters.
Top-Down – Implicit
JAX-RPC does not provide any mapping for the implicit header definitions.
One could use JAX-RPC handlers to access the headers for cases where the implementation of the service does not deal with the header information.
For cases where the SOAP header is either used or populated in the implementation of the operation, you could use one of the two options
- Use the ServiceLifecycle interface as described in [2] in the references section.
- Use JAX-RPC handler and use ThreadLocal class to store/retrieve the header information. On the Server side, when the request comes in, the handler basically populates the values in the request header that the implementation needs on the thread-local variable. The information stored is available to the operation implementation. For the response headers, the operation implementation can pass the information along to the handler in a similar fashion. This is not an elegant approach but sure works!
Bottom-Up – Explicit
For the Bottom-Up – Explicit header approach, a lot of manual changes need to be made. This is particularly for cases where the operation implementation needs to have access to SOAP headers.
Here is what I have done.
- Create holder classes
- Modify the SEI to pass headers as parameters mimicking the generated classes in the top-down approach.
- Generate the WSDL
- Modify the WSDL
- Modify the mapping xml
Seems to work fine, but I would not recommend this approach since there is a lot of manual work involved.
Bottom-Up – Implicit
Some amount of manual changes to the WSDL is required (adding the SOAP header to the bindings sections). Also, in-order to generate the mappings for the header objects, they will have to be added to the interface and then removed at a later point, not to mention the changes to the mappings xml file.
One of the two approaches described in Top-Down – Implicit can be used to make the SOAP header information available to the implementation of the operation.
JAX-WS (2.1)
Using annotations in JAX-WS, you can mark a parameter as a header.
Eg:
@WebParam(name = "RequestHeader", targetNamespace = "http://www.test.com", header = true, partName = "request_header")
If you are looking for JAX-WS annotations reference, please use [5] in the references section.
Top-Down – Explicit
JAX-WS supports explicit headers and provides the header objects as parameters to the operation. It generates the annotations, marking the SOAP header parameters as headers.
Top-Down – Implicit
JAX-WS has no support for implicit headers but after generating the java artifacts. For cases where the implementation deals with the headers
- Simply add header parameters with annotations to the interface/implementation classes and the mapping is taken care of. Don’t forget to use the Holder class for OUT and IN/OUT parameters.
- The other approach would be to use JAX-WS handlers and MessageContext object to make the headers accessible to the implementation. Please refer [3] to see how you can work with JAX-WS handlers to do the same.
Bottom-Up – Explicit
JAX-WS supports explicit headers even in the bottom-up approach. Add the annotations marking the header parameters as headers.
E.g.:
@WebService(name = "TestBottomupHeaders", targetNamespace = "http://www.test.com")
@SOAPBinding(parameterStyle = SOAPBinding.ParameterStyle.BARE)
public interface TestBottomupHeadersIntf extends java.rmi.Remote{
@WebMethod(action = "returnInput")
public void returnInput(
@WebParam(name = "TestInput", targetNamespace =
"http://www.test.com", partName = "input") TestInput input,
@WebParam(name = "BaseRequest", targetNamespace = "http://www.test.com",
header = true, partName = "request_header") BaseRequest_Type requestHeader,
@WebParam(name = "TestOutput", targetNamespace = "http://www.test.com", mode
= WebParam.Mode.OUT, partName = "output") Holder<TestOutput> output,
@WebParam(name = "BaseResponse", targetNamespace = "http://www.test.com",
header = true, mode = WebParam.Mode.OUT, partName = "response_header")
Holder<BaseResponse_Type> responseHeader);
}
NOTE: For OUT and IN/OUT parameters, you must use the Holder class as shown above.
Bottom-Up – Implicit
Two approaches here:
1.
- Define the POJO interface passing the headers as parameters and with annotations marking header=”true” where appropriate
- Generate the WSDL
- Change the WSDL manually to have implicit headers definitions rather than explicit.
2. Use JAX-WS handlers to make the headers available to the implementation. Please refer [3] to see how you can work with JAX-WS handlers and MessageContext to do the same.
References:
[1] Implement implicit and explicit SOAP headers
[2] Web services programming tips and tricks: Using SOAP headers with JAX-RPC
[3] Get a handle on the JAX-WS API's handler framework
[4] IBM WebSphere Application V 7.0 Information Center
[5] JAX-WS annotations reference
Hi Sagar, great post. Thanks for the info here. We leveraged the top-down explicit approach to generate the associated code using Axis1.4. One thing we noticed, however, was that Axis1.4 (and this did not happen with Axis2) generates the header in the dynamically generated wsdl file with a 1 appended to it if the header is used in more than 1 message. Likewise a 2 is appended if the header is used again in a subsequent message. There appears to be no way to prevent this from happening however. Rather annoying as it confuses the caller into thinking they have to send packets with the 1 and 2, etc appended to the header name.
ReplyDeleteThanks Biztrav for sharing your experience with Axis 1.4 and for your feedback!
ReplyDelete