Having created a java web service client using wsimport on a wsdl, I need to set the Authorization header for each soap message embedded in an http request. Having generated
For the sake of completeness and to help others in similar situations, I'd like to illustrate the IMHO cleanest solution using the JAX-WS-handler-chain:
1) Sub-class your service-class (not the port-class) in a different (non-generated) package. Because the service-class (and its entire package) was likely generated from a WSDL, your changes to the sub-class are not lost, when you update your service-class after a WSDL change.
2) Annotate your service-sub-class like this (import javax.jws.HandlerChain
):
@HandlerChain(file="HandlerChain.xml")
public class MyService extends GeneratedService {
3) Create a file called HandlerChain.xml
in the same package as your service-sub-class, i.e. next to MyService
with the following content:
co.codewizards.example.HttpHeaderExtensionSOAPHandler
co.codewizards.example.HttpHeaderExtensionSOAPHandler
You may add multiple
elements, btw.
And make sure that this file really ends up in your JAR! For example, when using Maven, you have to place it either in ${project}/src/main/resources/
(instead of ${project}/src/main/java/
) or you have to change your build-configuration to include resources from the java
-folder! I recommend the latter, because it's cumbersome to have a parallel package-structure in the resources
-folder, which is often forgotten during refactorings.
4) Implement your HttpHeaderExtensionSOAPHandler
-- similar to this:
import static com.google.common.base.Preconditions.*;
import java.util.*;
import javax.xml.namespace.QName;
import javax.xml.ws.handler.MessageContext;
import javax.xml.ws.handler.soap.SOAPHandler;
import javax.xml.ws.handler.soap.SOAPMessageContext;
import co.codewizards.webservice.WebserviceContext;
public class HttpHeaderExtensionSOAPHandler implements SOAPHandler {
@Override
public boolean handleMessage(SOAPMessageContext context) {
checkNotNull(context, "context");
Boolean outboundProperty = (Boolean) context.get(MessageContext.MESSAGE_OUTBOUND_PROPERTY);
checkNotNull(outboundProperty, "outboundProperty");
if (outboundProperty.booleanValue()) {
WebserviceContext, ?> webserviceContext = WebserviceContext.getThreadWebserviceContextOrFail();
String something = (String) webserviceContext.___(); // my API method ;-)
@SuppressWarnings("unchecked")
Map> requestHeaders = (Map>) context.get(MessageContext.HTTP_REQUEST_HEADERS);
if (requestHeaders == null) {
requestHeaders = new HashMap>();
context.put(MessageContext.HTTP_REQUEST_HEADERS, requestHeaders);
}
requestHeaders.put(MyService.MY_CONSTANT, Collections.singletonList(something));
}
return true;
}
@Override
public boolean handleFault(SOAPMessageContext context) { return true; }
@Override
public void close(MessageContext context) { }
@Override
public Set getHeaders() { return Collections.emptySet(); }
}
In my example above (and in my productive code) I obtain the data to be passed into the HTTP request headers from a ThreadLocale
, i.e. my current thread's context. Since this WebserviceContext
is my custom class, you'll need to implement your own way to access your data.