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:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 |
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:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 |
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:
1 2 3 4 5 6 7 |
<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.
One Reply to “Logging JAX-WS SOAP messages in Spring”
Comments are closed.