I've searched on this and found a few near misses. I've created a java client to consume a web service using JAX-WS. Is there a way when using JAX to set the HTTP_USER_AGENT value? I would like to have my web service log when specific clients (mine) access it so I wanted a customized value.
I've seen options where you set it in the system properties but this doesn't seem to work. The generated JAX classes don't seem to have a direct reference to the connection object so I don't see how I can manipulate those classes.
Any help would be great. Thanks ST
The solution to this kind of problem in JAX-WS is to implement a SoapMessage Handler (Interface: SOAPHandler< SOAPMessageContext >). Within that handler you insert your HTTP header into maybe already existing headers, then you give control to the next handler in the handler chain.
The concept of this handler chain is kind of nice, you can have small classes for a very specific purpose (Security, Logging etc.).
In your client you configure the handler chain prior to sending any request:
// HandlerChain installieren
Binding binding = ((BindingProvider) port).getBinding();
List hchain = binding.getHandlerChain();
if (hchain == null) {
hchain = new ArrayList();
}
hchain.add(new HTTPUserAgentHandler());
binding.setHandlerChain(hchain);
And here is the code for the HTTPUserAgentHandler:
public class HTTPUserAgentHandler implements SOAPHandler<SOAPMessageContext> {
@Override
public boolean handleMessage(SOAPMessageContext context) {
boolean request = ((Boolean) context.get(SOAPMessageContext.MESSAGE_OUTBOUND_PROPERTY)).booleanValue();
if (request) {
@SuppressWarnings("unchecked")
Map<String, List<String>> headers = (Map<String, List<String>>) context
.get(MessageContext.HTTP_REQUEST_HEADERS);
if (null == headers) {
headers = new HashMap<String, List<String>>();
}
headers.put("HTTP_USER_AGENT", Collections.singletonList("user_agent"));
context.put(MessageContext.HTTP_REQUEST_HEADERS, headers);
}
return true;
}
@Override
public boolean handleFault(SOAPMessageContext context) {
return true;
}
@Override
public void close(MessageContext context) {}
@Override
public Set<QName> getHeaders() {
return null;
}
}
Let me question the idea of having HTTP header first.
A more correct (WS-centric) approach is to set SOAP Header, not HTTP header. Consider this: SOAP messages can be delivered not only by HTTP, but by JMS, SMTP or custom transports. By requiring to have user-agent HTTP Header, you unnecessary tie you code to only one transport, albeit currently prevailing.
This is the reason BTW why JAX-WS have no notion of HTTP headers except in handlers.
And (of course) StackOverlow knows how to create SOAP headers.
not sure if this is the best/most direct way to do it, but i think you could add a custom javax.xml.ws.handler.Handler to the handler chain in the dispatch javax.xml.ws.Binding. in the Handler, you should be able to set a custom map of extra http headers on the outgoing MessageContext using the MessageContext.HTTP_REQUEST_HEADERS property.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With