JAX-WS - SOAP Handlers

What is SOAP Handlers ?

SOAP Handlers are interceptor to do additional processing of incoming and outgoing message at Client as well as Server level. For example, to check properties in handler, to audit req/response or to do any filtering.

SOAP message contains three parts as below:-
  1. SOAP Header [Optional]
  2. SOAP Body
  3. Attachments [Optional]
JAX-WS 2.0 defines 2 types of Handlers - Logical and Message Handler.
  • Logical Handlers operates on message context properties and message payload only. Logical handlers are handlers that implements - javax.xml.ws.handler.LogicalHandler
  • Message Handlers operates all parts of SOAP, i.e. SOAP Header, Body and attachments. it implements - javax.xml.ws.handler.soap.SOAPHandler
There are three methods of handlers as follows:-
  1. handleMessage() - This method is called for both incoming and outgoing message for any additional processing
  2. handleFault() - This handles any fault generated by service implementation or exception generated from above method
  3. close() - called at last to do clean up resources.
Flow of SOAP Handler invocations: 

Senders
  -> Logical Handler
     -> Message Handler
        -> Transport [HTTP?]
           -> Message Handler
               -> Logical handler 

                   -> Receiver

Example:
Let us explore small web service example - echoservice, there are 2 handlers - one is checking for soap header parameter and second one is logging request / response console.
EchoServiceInterface.java  
 package soap.handler;  
   
 import javax.jws.WebParam;  
 import javax.jws.WebService;  
 import javax.jws.soap.SOAPBinding;  
 import javax.jws.soap.SOAPBinding.Style;  
   
 @WebService  
 @SOAPBinding(style = Style.DOCUMENT)  
 public interface EchoServiceInterface {  
   
      String getMessage(@WebParam(name = "message") String message);  
 }  
   
EchoServiceImpl.java
 package soap.handler;  
   
 import javax.jws.HandlerChain;  
 import javax.jws.WebService;  
   
 @WebService(endpointInterface = "soap.handler.EchoServiceInterface")  
 @HandlerChain(file = "handlers.xml")  
 public class EchoServiceImpl implements EchoServiceInterface {  
   
      @Override  
      public String getMessage(String message) {  
           return message;  
      }  
   
 }  
   
EchoServiceExecutor.java
 package soap.handler;  
   
 import javax.xml.ws.Endpoint;  
   
 public class EchoServiceExecutor {  
   
      public static void main(String[] args) {  
           Endpoint.publish("http://localhost:8888/echo-service", new EchoServiceImpl());  
      }  
   
 }  
ClientValidator.java  - Message Handler
 package soap.handler;  
   
 import java.util.Iterator;  
 import java.util.Set;  
   
 import javax.xml.namespace.QName;  
 import javax.xml.soap.Node;  
 import javax.xml.soap.SOAPBody;  
 import javax.xml.soap.SOAPConstants;  
 import javax.xml.soap.SOAPEnvelope;  
 import javax.xml.soap.SOAPException;  
 import javax.xml.soap.SOAPFault;  
 import javax.xml.soap.SOAPHeader;  
 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 javax.xml.ws.soap.SOAPFaultException;  
   
 public class ClientValidator implements SOAPHandler<SOAPMessageContext> {  
   
      private String SERVICE_CONSUMER = "serviceconsumer";  
   
      @Override  
      public boolean handleMessage(SOAPMessageContext context) {  
             
   
           Boolean outboundProperty = (Boolean) context.get(MessageContext.MESSAGE_OUTBOUND_PROPERTY);  
   
           // incoming request  
           if (!outboundProperty) {  
                System.out.println("Client Request...");  
                checkMessage(context);  
           }else{  
                System.out.println("Client Response...");  
           }  
           return true;  
      }  
   
      // Check ConsumerApplication  
      private boolean checkMessage(SOAPMessageContext context) {  
           try {  
                SOAPMessage soapMessage = context.getMessage();  
                SOAPEnvelope soapEnvelope = soapMessage.getSOAPPart().getEnvelope();  
                SOAPHeader soapHeader = soapEnvelope.getHeader();  
   
                Iterator<?> headers = soapHeader.extractHeaderElements(SOAPConstants.URI_SOAP_ACTOR_NEXT);  
   
                if (headers != null && headers.hasNext()) {  
                     Node node = (Node) headers.next();  
   
                     if (node != null) {  
                          if (!SERVICE_CONSUMER.equals(node.getNodeName())) {  
                               System.out.println("Missing ServiceConsumer Header");  
                               SOAPBody soapBody = soapMessage.getSOAPPart().getEnvelope().getBody();  
                               SOAPFault soapFault = soapBody.addFault();  
                               soapFault.setFaultString("Invalid Service Consumer..!!");  
                                 
                               throw new SOAPFaultException(soapFault);  
                          }  
                     }  
                }  
   
           } catch (SOAPException e) {  
                System.err.println(e);  
           }  
           return true;  
   
      }  
   
      @Override  
      public boolean handleFault(SOAPMessageContext context) {  
           return false;  
      }  
   
      @Override  
      public void close(MessageContext context) {  
   
      }  
   
      @Override  
      public Set<QName> getHeaders() {  
           return null;  
      }  
   
 }  
LoggingHandler.java - Logical handler
 package soap.handler;  
   
 import javax.xml.transform.Source;  
 import javax.xml.ws.LogicalMessage;  
 import javax.xml.ws.handler.LogicalHandler;  
 import javax.xml.ws.handler.LogicalMessageContext;  
 import javax.xml.ws.handler.MessageContext;  
   
 public class LoggingHandler implements LogicalHandler<LogicalMessageContext> {  
   
      @Override  
      public boolean handleMessage(LogicalMessageContext context) {  
   
           Boolean outboundProperty = (Boolean) context.get(MessageContext.MESSAGE_OUTBOUND_PROPERTY);  
   
           if (outboundProperty.booleanValue()) {  
                System.out.println("Response:-");  
           } else {  
                System.out.println("Request:-");  
           }  
   
           LogicalMessage message = context.getMessage();  
   
           try {  
                Source src = message.getPayload();  
                Utility.print(src);  
           } catch (Exception e) {  
                System.err.println(e);  
           }  
   
           return true;  
      }  
   
      @Override  
      public boolean handleFault(LogicalMessageContext context) {  
           return false;  
      }  
   
      @Override  
      public void close(MessageContext context) {  
   
      }  
   
 }  
handlers.xml
 <?xml version="1.0" encoding="UTF-8" standalone="yes"?>  
 <javaee:handler-chains xmlns:javaee="http://java.sun.com/xml/ns/javaee"  
      xmlns:xsd="http://www.w3.org/2001/XMLSchema">  
      <javaee:handler-chain>  
           <javaee:handler>  
                <javaee:handler-class>soap.handler.ClientValidator  
                </javaee:handler-class>  
           </javaee:handler>  
           <javaee:handler>  
                <javaee:handler-class>soap.handler.LoggingHandler  
                </javaee:handler-class>  
           </javaee:handler>  
      </javaee:handler-chain>  
 </javaee:handler-chains>  
soap-ui Request / Response
 <soapenv:Envelope   
 xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/" xmlns:han="http://handler.soap/">  
   <soapenv:Header>   
        <serviceconsumer soapenv:actor="http://schemas.xmlsoap.org/soap/actor/next">Application</serviceconsumer>  
   </soapenv:Header>  
   <soapenv:Body>  
    <han:getMessage>  
      <message>Demo Application</message>  
    </han:getMessage>  
   </soapenv:Body>  
 </soapenv:Envelope>  

 <S:Envelope xmlns:S="http://schemas.xmlsoap.org/soap/envelope/">  
   <S:Body>  
    <ns2:getMessageResponse xmlns:ns2="http://handler.soap/">  
      <return>Demo Application</return>  
    </ns2:getMessageResponse>  
   </S:Body>  
 </S:Envelope>  
Console Output
 Client Request...  
 Request:-  
 <?xml version="1.0" encoding="UTF-8"?><han:getMessage xmlns:han="http://handler.soap/" xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/">  
      <message>Demo Application</message>  
    </han:getMessage>  
 Response:-  
 <?xml version="1.0" encoding="UTF-8"?><ns2:getMessageResponse xmlns:ns2="http://handler.soap/"><return>Demo Application</return></ns2:getMessageResponse>  
 Client Response...  
   

Download Example

Comments

Popular posts from this blog

Create BeanShell Script to Make Database call

Connection Pooling