Logging JAX-WS SOAP messages in Spring
Whenever you’re using JAX-WS within Spring you’ll probably want to log the incoming and outgoing SOAP messages – if only for debugging during development. So the first thing to do is increase the log levels, right? Unfortunately this will have no effect. What you will have to do is to make use of the javax.xml.ws.handler.HandlerResolver
interface. So how do we do this?
First of all, you’ll want to create a class that implements the HandlerResolver
interface. This is a very basic class that will be used to get control over the handler chain. It could look something like the following:
A DefaultHandlerResolver
package it.jdev.example.ws; import java.util.List; import javax.xml.ws.handler.Handler; import javax.xml.ws.handler.HandlerResolver; import javax.xml.ws.handler.PortInfo; public class DefaultHandlerResolver implements HandlerResolver { private List<Handler> handlerList; @Override public List<Handler> getHandlerChain(final PortInfo portInfo) { return handlerList; } public void setHandlerList(final List<Handler> handlerList) { this.handlerList = handlerList; } }
We then have to implement the class that will do the actual logging. This class will have to implement the SOAPHandler<SOAPMessageContext>
interface. A very simple implementation that only logs the message using SLF4J:
The LoggingHandler
package it.jdev.example.ws; import java.io.ByteArrayOutputStream; import java.lang.invoke.MethodHandles; import java.util.Set; import javax.xml.namespace.QName; import javax.xml.soap.SOAPMessage; import javax.xml.ws.handler.MessageContext; import javax.xml.ws.handler.soap.SOAPHandler; import javax.xml.ws.handler.soap.SOAPMessageContext; import org.slf4j.Logger; import org.slf4j.LoggerFactory; public class LoggingHandler implements SOAPHandler<SOAPMessageContext> { private static final Logger LOGGER = LoggerFactory.getLogger(MethodHandles.lookup().lookupClass()); @Override public boolean handleMessage(final SOAPMessageContext context) { final SOAPMessage msg = context.getMessage(); final boolean request = ((Boolean) context.get(SOAPMessageContext.MESSAGE_OUTBOUND_PROPERTY)).booleanValue(); if (request) { // This is a request message. logMessage(msg); } else { // This is the response message logMessage(msg); } return true; } @Override public boolean handleFault(final SOAPMessageContext context) { logMessage(context.getMessage()); } private void logMessage(final SOAPMessage msg) { try { // Write the message to the output stream final ByteArrayOutputStream baos = new ByteArrayOutputStream(); msg.writeTo(baos); LOGGER.info(baos.toString()); baos.close(); } catch (final Exception e) { LOGGER.error("Caught exception: " + e.getMessage(), e); } } @Override public void close(final MessageContext context) { // Not required for logging } @Override public Set<QName> getHeaders() { // Not required for logging return null; } }
Finally, we’ll have to wire things together in Spring. Using xml configuration, all you have to do is add a new bean definition:
Configuring Spring to use the SOAP message logger
<bean id="handlerResolver" class="it.jdev.example.ws.DefaultHandlerResolver"> <property name="handlerList"> <list> <bean class="it.jdev.example.ws.LoggingHandler" /> </list> </property> </bean>
And that’s all there is to it. Your application should now log all JAX-WS SOAP messages.
Reference: | Logging JAX-WS SOAP messages in Spring from our JCG partner Wim van Haaren at the JDev blog. |
Nice article, but this piece of code does not make sense
if (request) { // This is a request message.
logMessage(msg);
} else { // This is the response message
logMessage(msg);
}
The handleMessage() method handles both request and response messages. The example illustrates a way to differentiate between request and response in case you’ll want to handle them differently. If both outbound and inbound messages are handled in exactly the same way – as in this example – there indeed is no need to differentiate. In that case the method in the example could be shortened to
public boolean handleMessage(final SOAPMessageContext context) {
final SOAPMessage msg = context.getMessage();
logMessage(msg);
return true;
}
@Override
public boolean handleFault(final SOAPMessageContext context) {
logMessage(context.getMessage());
}
Should it return true or false ?
From the javax.xml.ws.handler.Handler javadoc:
Returns:
An indication of whether handler fault processing should continue for the current message
Return true to continue processing.
Return false to block processing.
Its not working for me, its not invoked my soaphandler class , I am using jaxws-spring api, and added this bean wire in applicationContext.xml , added here because my webservice is configured here. Please help why this in not invoked