01 JAX-WS Handler

When we develop several web service endpoints and web services consumer or clients, once in a while we need to address some cross-cutting concerns or nonfunctional requirements which have to be applied across Web Services clients or across the web services endpoints. This requirements might not have anything to do with the business logic but they need us to manipulate the SOAP message.

  • It could be SOAP headers, the SOAP body or it could be completely different requirement which your application needs, but it is a non-functional requirements which should be applied across WS endpoints. This is where JAX_WS comes into picture.

These handlers are classes that we develop by implementing certain interfaces in JAX-WS API. Web Services stacks like APACHE CXF will call into these handlers when the client request is sent from the client, when the request comes into the endpoint and the response goes back from the endpoint and also when the response comes back on to the client.

This handlers are very similar to servlet filters, if you are aware of servlet filters, except for these handlers can be applied both on the client and server side.

Whatever logic we write in the methods in the handlers will be called by webservices stacks like CXF.

Why and When to use Handlers?

Handlers can be used to implement custom authentication mechanism.

Let’s say you don’t want to use the username token profile or whatever is available in WS Standard and you want to include your own SOAP headers, you can create handlers both on the provider side and the client side of your application and you can manipulate the SOAP headers inside the handlers.

All SOAP message information will be available to you when you create a handler.

The 2nd usage is Caching. Instead of our web service doing a particular service every time, we can create a handler that will cache the responses and it can check the request to see if its the same request which came in earlier and then it can send back the response from the cache instead of calling into the web services endpoint and executing then entire business logic and database operations.

Third usage is to decide which web service to send the request into based on the soap header version it comes into.

To summarize, from this lecture you have learnt that JAX-WS handlers give you a custom way to manipulate the soap message or to address cross-cutting concerns like security caching which your application needs or the various endpoints in our application needs.

Some examples for JAX-WS handlers are to handle custom authentication, Caching, Versioning and so on. Anything that has to do with the SOAP message can be done using the Händler framework.

Two Types of JAX-WS Handlers

  1. SOAP Handlers

    • SOAP Handlers have access to the entire message. They have access to the protocol information like HTTP Headers, SOAP Headers and the entire SOAP body.

  2. Logical Handlers

    • We implement logical handlers when we want to access just the payload information, that is whatever goes in the SOAP body.

    • We implement a SOAP handler by implementing the SOAPHandler Interface. It is a generic interface.

    • Usually we use SOAPMessageContext which wraps the entire SOAP information. It has lifecycle methods like handleMessage, handleFault, getHeaders and close in action.

    • handleMessage and getHeaders are called both on the way in as well as way out on the client side as well as on provider side.

    • handleFault is only called when there is a SOAP Fault and the close method is called on the way out at the end of the entire flow.

    • close method is called before the response goes back. We will do any cleanup like code, resources, or database connections.

Question 1:

Which JAX-WS handlers should be used to access the SOAP headers? → SOAP Handler

  • logical handlers

  • soap handler

  • cxf handler

  • jee handler


Question 2:

The logical handlers can be used to access which part of the SOAP message? → payload

  • payload

  • headers

  • entire message

  • none of the above

Step to create a project

  1. Design the handler chain

  2. Create the handlers

  3. Configure the handlers

  4. Run and Test

Project Step

  1. Design the handler chain

    package com.soaptest.handlers;
    
    import java.util.Set;
    
    import javax.xml.namespace.QName;
    import javax.xml.ws.handler.MessageContext;
    import javax.xml.ws.handler.soap.SOAPHandler;
    import javax.xml.ws.handler.soap.SOAPMessageContext;
    
    public class SiteHandler implements SOAPHandler<SOAPMessageContext> {
    
    	@Override
    	public boolean handleMessage(SOAPMessageContext context) {
    		// TODO Auto-generated method stub
    		return false;
    	}
    
    	@Override
    	public boolean handleFault(SOAPMessageContext context) {
    		// TODO Auto-generated method stub
    		return false;
    	}
    
    	@Override
    	public void close(MessageContext context) {
    		// TODO Auto-generated method stub
    		
    	}
    
    	@Override
    	public Set<QName> getHeaders() {
    		// TODO Auto-generated method stub
    		return null;
    	}
    
    }
    

2.Extract the header

package com.soaptest.handlers;

import java.util.Iterator;
import java.util.Set;

import javax.xml.namespace.QName;
import javax.xml.soap.Node;
import javax.xml.soap.SOAPEnvelope;
import javax.xml.soap.SOAPException;
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 org.springframework.web.servlet.tags.EvalTag;

public class SiteHandler implements SOAPHandler<SOAPMessageContext> {

	@Override
	public boolean handleMessage(SOAPMessageContext context) {
		System.out.println("start handleMessage() ");
		
		Boolean isResponse = (Boolean) context.get(MessageContext.MESSAGE_OUTBOUND_PROPERTY);
		if (isResponse) {
			SOAPMessage soapMessage = context.getMessage();
			try {
				// Get Envelope
				SOAPEnvelope envelope = soapMessage.getSOAPPart().getEnvelope();
				
				// Get Headers
				SOAPHeader header = envelope.getHeader();
				// Get Child elements
				Iterator<Node> childElements = header.getChildElements();
				
				while(childElements.hasNext()) {
					Node eachSoapHeaderNode = (Node) childElements.next();
					
					//Name of soap header
					String name = eachSoapHeaderNode.getLocalName();
					if( name != null && name.equals("Sitename")) {
						System.out.println("Site name is: "+eachSoapHeaderNode.getValue());
					}
				}
				
			} catch (SOAPException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			}
		} else {
			System.out.println("Response is on the way");
		}
		
		System.out.println("End handleMessage() ");
		return true;
	}

	@Override
	public boolean handleFault(SOAPMessageContext context) {
		System.out.println("start handleFault() ");
		
		System.out.println("end handleFault() ");
		return false;
	}

	@Override
	public void close(MessageContext context) {
		System.out.println("start close() ");
		
		System.out.println("end close() ");
	}

	@Override
	public Set<QName> getHeaders() {
		System.out.println("start close() ");
		
		System.out.println("end close() ");
		return null;
	}

}

  1. Configure the handler

    @Configuration
    public class WebServiceConfig {
    
    	@Autowired
    	private Bus bus;
    
    	@Bean
    	public Endpoint endpoint() {
    		//Endpoint endpoint = new EndpointImpl(bus, new HelloController());
    		//endpoint.publish("/hello");
    		
    		Endpoint endpoint = new EndpointImpl(bus, new CustomerOrderWsImpl());
    		endpoint.publish("/customerordersservice");
    		
    		//Add SOAPBinding
    		SOAPBinding binding = (SOAPBinding) endpoint.getBinding();
    		ArrayList<Handler> handlerchain = new ArrayList<>();
    		handlerchain.add(new SiteHandler());
    		binding.setHandlerChain(handlerchain);
    		
    		return endpoint;
    
    	}
    
    }