JAXWS Handler Chain Intercept incoming outgoing messages
In this tutorial we create a basic JAX-WS web service with a handler chain. SOAP Handlers are similar to Servlet Filters or EJB/CDI Interceptor. They can intercept and alter incomming and outgoing SOAP messages. JAX-WS defines a Handler interface with subinterfaces LogicalHandler
and SOAPHandler
. The SOAPHandler
has access to the full SOAP Message, including the headers. The LogicalHandler
only has access to the Payload of the message.
Project Structure
src
|--main
| +--java
| +--com
| +--memorynotfound
| +--handlers
| |--LoggingHandler.java
| +--ws
| |--GreetingService.java
| |--GreetingServiceImpl.java
| +--resources
| +--com
| +--memorynotfound
| +--ws
| |--handlers.xml
| +--webapp
| +--WEB-INF
| |--sun-jaxw.xml
| |--web.xml
pom.xml
SOAP Handler
To create a Handler we need to implement the javax.xml.ws.handler.Handler
interface or any of its subinterfaces.
- SOAPHandler: SOAP handlers can access the entire SOAP message, including the message headers and body.
- LogicalHandler: Logical handlers can access the payload of the message only, and cannot change any protocol-specific information (like headers) in a message.
package com.memorynotfound.handlers;
import javax.xml.namespace.QName;
import javax.xml.soap.SOAPBody;
import javax.xml.soap.SOAPException;
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 java.util.HashSet;
import java.util.Set;
public class LoggingHandler implements SOAPHandler<SOAPMessageContext> {
@Override
public Set<QName> getHeaders() {
return new HashSet<QName>();
}
@Override
public boolean handleMessage(SOAPMessageContext context) {
Boolean isOutBound = (Boolean) context.get(MessageContext.MESSAGE_OUTBOUND_PROPERTY);
try {
if (isOutBound){
System.out.println("Intercepting outbound message:");
} else {
System.out.println("Intercepting inbound message:");
}
context.getMessage().writeTo(System.out);
System.out.println();
} catch (SOAPException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
return true;
}
@Override
public boolean handleFault(SOAPMessageContext context) {
return false;
}
@Override
public void close(MessageContext context) {
System.out.println("Do some cleanup handling .. ");
}
}
SOAP Handler chain xml file
handlers.xml
file needs to be in the same package as your web service on the classpath. This means for every service you need to add a handler chain this file must exist.<?xml version="1.0" encoding="UTF-8"?>
<handler-chains xmlns="http://java.sun.com/xml/ns/javaee">
<handler-chain>
<handler>
<handler-name>LoggingHandler</handler-name>
<handler-class>com.memorynotfound.handlers.LoggingHandler</handler-class>
</handler>
</handler-chain>
</handler-chains>
Attaching the Handler to our Web Service
To register a SOAP Handler with our Web Service we need to specify a @HandlerChain()
annotation in our class. As said before, the handlers.xml
file must be in the same package on your classpath as the web service. For our example this means that the file must exist in com.memorynotfound.ws
in the resources folder.
package com.memorynotfound.ws;
import javax.jws.HandlerChain;
import javax.jws.WebService;
import javax.jws.soap.SOAPBinding;
@WebService
@HandlerChain(file = "handlers.xml")
@SOAPBinding(style = SOAPBinding.Style.RPC)
public class GreetingServiceImpl implements GreetingService {
public String printMessage() {
return "Hello, World!";
}
}