I was writing a WSDL-first SOAP 1.1 service (server) using Apache CXF.
I needed to directly access the XML DOM of the SOAP Header and Body, so I did not want to use
the standard JAXB data binding. My solution was to implement
a Provider using message mode. However,
retrieving the SOAPAction inside the Provider’s invoke(SOAPMessage msg)
method
was not intuitive to me.
The WSDL for this service was produced by a standards body, so I tried to avoid modify it.
Each operation in the WSDL specified a soapAction
, therefore I
assumed I needed the value of the SOAPAction
HTTP header to process the
message.
After further digging into the SOAP 1.1 Specification,
it looks like the SOAPAction
is more or less optional. The HTTP header is required, but it is not required to have a value.
Therefore, I suspect to make my service as robust as possible, I may not require the header
and instead look at the name of the first element in the SOAP Body to determine the operation.
In any case, to get the value of the SOAPAction
header, here is what I did.
import javax.annotation.Resource;
import javax.jws.WebService;
import javax.xml.soap.SOAPMessage;
import javax.xml.ws.Provider;
import javax.xml.ws.Service;
import javax.xml.ws.ServiceMode;
import javax.xml.ws.WebServiceContext;
import org.apache.cxf.binding.soap.SoapBindingConstants;
@WebService(/* details specified here */)
@ServiceMode(value=Service.Mode.MESSAGE)
public class MyServer implements Provider<SOAPMessage> {
private WebServiceContext m_webServiceContext;
@Resource
public void setWebServiceContext(WebServiceContext context) {
m_webServiceContext = context;
}
public SOAPMessage invoke(SOAPMessage request) {
final String soapAction = (String) m_webServiceContext
.getMessageContext()
.get(SoapBindingConstants.SOAP_ACTION);
}
}
The annotation @Resource
causes the method setWebServiceContext
to
be called when the service starts. WebServiceContext
contains values stored in ThreadLocal fields which allow you to get context about the message being processed
inside invoke()
.
I found this use of “context” very unintuitive. I would expect that injected dependency to
provide context for the entire Provider, not a specific method invocation. Any context specific to the
method invocation I would expect
to arrive as an argument to the invoke()
method. It appears this is the way JAX-WS was designed.
Note that the context contains many other properties that may be useful in your coding and debugging.
Hopefully this saved you hours of head scratching.