Nikos Maravitsas

About Nikos Maravitsas

Nikos has graduated from the Department of Informatics and Telecommunications of The National and Kapodistrian University of Athens. Currently, his main interests are system’s security, parallel systems, artificial intelligence, operating systems, system programming, telecommunications, web applications, human – machine interaction and mobile development.

JAX-WS SOAP Handler Example

In this example we are going to see how to Use SOAP Handler to intercept SOAP messages form the client – server communication. A SOAP handler can also change the SOAP messages from/to client/server. In this example we are going to create a Handler in the Client Side that will add a header to the SOAP message containing his IP address. At the other end, there is a Handler in the Server Side that will exctract the IP address of the client and decide whether to serve him or not. For example you can have a list of your trusted IP addresses (or any kind of filter for that mater), and only serve SOAP messages containing these trusted IP addresses at their headers.

For invalid SOAP messages, an Exception will be thrown and a SOAP Fault message will be attached to the SOAP envelope.

Service Endpoint

In the Web Server Endpoint there will be a SOAPHandler that will extract the special header from the SOAP message, will read the ip address that the client put it that header, and decide whether to serve him or not.

But let’s see the Endpoint Creation step by step :

In order to create our Web Service Endpoint:

  • First you have to create a Web Service Endpoint Interface. This interface will contain the declerations of all the methods you want to include in the Web Service.
  • Then you have to create a class that actually implements the above interface, which will be your Endpoint implementation.
  • Next we are going to create an IpValidator class that will implement SOAPHandler<SOAPMessageContext>.
  • We will create an XML file (handlers.xml) that will define the IpValidator class as a SOAP handler. This file can also chain other handlers. The SOAP message will be handled by all of those handlers, one by one. Then, we are going to add a @HandlerChain annotation to the  Server Endpoint Implementation class, to state to the web service to use a specific SOAP handler (obviously the one that we’ve created)
  • Finally you create your Endpoint publisher which actually deploys the web service and creates and publishes the endpoint for the specified implementor object at a given address. The necessary server infrastructure will be created and configured by the JAX-WS implementation. You have to run the publisher to make your Web Service available to clients.

Web Service Endpoint Interface

WebServiceInterface.java:

package com.javacodegeeks.enterprise.ws;

import javax.jws.WebMethod;
import javax.jws.WebService;
import javax.jws.soap.SOAPBinding;
import javax.jws.soap.SOAPBinding.Style;

@WebService
@SOAPBinding(style = Style.DOCUMENT)
public interface WebServiceInterface {

	@WebMethod
	String printMessage();

}

Web Service Endpoint Implementation

WebServiceImpl.java:

package com.javacodegeeks.enterprise.ws;

import javax.jws.HandlerChain;
import javax.jws.WebService;

@WebService(endpointInterface = "com.javacodegeeks.enterprise.ws.WebServiceInterface")
public class WebServiceImpl implements WebServiceInterface{

	@Override
	public String printMessage() {
		return "Hello from Java Code Geeks Server";
	}

}

SOAP Handler

IpValidator .java:

package com.javacodegeeks.enterprise.ws.handler;

import java.io.IOException;
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 IpValidator implements SOAPHandler {

	private final String VALID_ADDRESS = "192.168.1.100";

	@Override
	public boolean handleMessage(SOAPMessageContext context) {

		System.out.println("Server::handleMessage() : ");

		Boolean isRequest = (Boolean) context.get(MessageContext.MESSAGE_OUTBOUND_PROPERTY);

		// inbound message from client
		if (!isRequest) {

			try {

				SOAPMessage soapMsg = context.getMessage();
				SOAPEnvelope soapEnv = soapMsg.getSOAPPart().getEnvelope();
				SOAPHeader soapHeader = soapEnv.getHeader();

				// if no header, add one
				if (soapHeader == null) {
					soapHeader = soapEnv.addHeader();
					attacheErrorMessage(soapMsg, "No SOAP header");
				}

				// Get client mac address from SOAP header
				Iterator<?> it = soapHeader.extractHeaderElements(SOAPConstants.URI_SOAP_ACTOR_NEXT);

				// if no header block for next actor found? throw exception
				if (it == null || !it.hasNext()) {
					attacheErrorMessage(soapMsg,"No header");
				}

				// if no ip address found? throw exception
				Node ipNode = (Node) it.next();
				String ipAddress = (ipNode == null) ? null : ipNode.getValue();

				if (ipAddress == null) {
					attacheErrorMessage(soapMsg,"No IP address in header");
				}

                                // at last, check if the ip address is trusted
				if (!ipAddress.equals(VALID_ADDRESS)) {
					attacheErrorMessage(soapMsg, "Untrusted IP address");
				}

			        // print soap message
                                // you can log it as well
				soapMsg.writeTo(System.out);

			} catch (SOAPException e) {
				System.err.println(e);
			} catch (IOException e) {
				System.err.println(e);
			}

		}

		return true;
	}

	@Override
	public boolean handleFault(SOAPMessageContext context) {

		System.out.println("Server::handleFault() : ");

		return true;
	}

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

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

	private void attacheErrorMessage(SOAPMessage errorMessage, String cause) {
		try {
			SOAPBody soapBody = errorMessage.getSOAPPart().getEnvelope().getBody();
			SOAPFault soapFault = soapBody.addFault();
			soapFault.setFaultString(cause);
			throw new SOAPFaultException(soapFault);
		} catch (SOAPException e) {
		}
	}

}

SOAP Handler XML File

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>com.javacodegeeks.enterprise.ws.handler.IpValidator</javaee:handler-class>
		</javaee:handler>
	</javaee:handler-chain>
</javaee:handler-chains>

Add @HandlerChain annotation to SEI

WebServiceImpl.java:

package com.javacodegeeks.enterprise.ws;

import javax.jws.HandlerChain;
import javax.jws.WebService;

@WebService(endpointInterface = "com.javacodegeeks.enterprise.ws.WebServiceInterface")
@HandlerChain(file="./handler/handlers.xml")
public class WebServiceImpl implements WebServiceInterface{

	@Override
	public String printMessage() {
		return "Hello from Java Code Geeks Server";
	}

}

Web Service Endpoint Publisher

WebServicePublisher.java:

package com.javacodegeeks.enterprise.ws;

import javax.xml.ws.Endpoint;
import com.javacodegeeks.enterprise.ws.WebServiceImpl;

public class WebServicePublisher{

	public static void main(String[] args) {
	   Endpoint.publish("http://localhost:8888/webservice/validator", new WebServiceImpl());
    }

}

Now when you run the publisher the Web Service will be available to the clients, deployed in the URL:

http://localhost:8888/webservice/validator

Ok, that’s it for the Server Side. Let’s see the project structure od the Eclipse project to get a clear view of all the files and their location:

package-explorer

Client Side

In the Client Side there will be a SOAP Handler to attach a new Header to every outgoing SOAP message. But first, we are going to use wsimport tool to create all necessary file for the Client Side program (see JAX-WS Hello World Example – RPC Style).

So, this is the command that I issued :

wsimport -keep http://localhost:8888/webservice/validator?wsdl -d F:\nikos7\Desktop
  • -keep : is an options that lets you keep the generated files
  • -d : you can sepcify the folder where the generated files will be stored

This command will create six java source files. In our case we are only going to manipulate WebServiceImplService.java

This is how that file looks like:

WebServiceImplService.java:

package com.javacodegeeks.enterprise.ws;

import java.net.MalformedURLException;
import java.net.URL;
import javax.xml.namespace.QName;
import javax.xml.ws.Service;
import javax.xml.ws.WebEndpoint;
import javax.xml.ws.WebServiceClient;
import javax.xml.ws.WebServiceException;
import javax.xml.ws.WebServiceFeature;
import javax.jws.HandlerChain;

/**
 * This class was generated by the JAX-WS RI. JAX-WS RI 2.2.4-b01 Generated
 * source version: 2.2
 * 
 */
@WebServiceClient(name = "WebServiceImplService", targetNamespace = "http://ws.enterprise.javacodegeeks.com/", wsdlLocation = "http://localhost:8888/webservice/validator?wsdl")
public class WebServiceImplService extends Service {

...

}

We are going to create the SOAP Handler and the SOAP Handler XML file and then add a @HandlerChain annotation to the above file

SOAP Handler

IpInjector.java:

package com.javacodegeeks.enterprise.ws.handler;

import java.io.IOException;
import java.net.InetAddress;
import java.util.Set;

import javax.xml.namespace.QName;
import javax.xml.soap.SOAPConstants;
import javax.xml.soap.SOAPEnvelope;
import javax.xml.soap.SOAPException;
import javax.xml.soap.SOAPHeader;
import javax.xml.soap.SOAPHeaderElement;
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;

public class IpInjector implements SOAPHandler {
	@Override
	public boolean handleMessage(SOAPMessageContext context) {

		System.out.println("Client::handleMessage()");

		Boolean isRequest = (Boolean) context.get(MessageContext.MESSAGE_OUTBOUND_PROPERTY);

		// outbound message to server
		if (isRequest) {

			try {
				SOAPMessage soapMessagg = context.getMessage();
				SOAPEnvelope soapEnvelope = soapMessagg.getSOAPPart().getEnvelope();
				SOAPHeader soapHeader = soapEnvelope.getHeader();

				// add a header to the SOAP message
				if (soapHeader == null) {
					soapHeader = soapEnvelope.addHeader();
				}

				// find out client's ip address
				InetAddress inAdd = InetAddress.getLocalHost();
				String ip = inAdd.getHostAddress();

				System.out.println("Client's ip address :"+ip);

				// add a soap header, name as "ipAddress"
				QName qname = new QName("http://ws.enterprise.javacodegeeks.com/", "ipAddress");
				SOAPHeaderElement soapHeaderElement = soapHeader.addHeaderElement(qname);

				soapHeaderElement.setActor(SOAPConstants.URI_SOAP_ACTOR_NEXT);
				soapHeaderElement.addTextNode(ip);
				soapMessagg.saveChanges();

				// print the message, or log it...
				soapMessagg.writeTo(System.out);

			} catch (SOAPException e) {
				System.err.println(e);
			} catch (IOException e) {
				System.err.println(e);
			}

		}

		// continue other handler chain
		return true;
	}

	@Override
	public boolean handleFault(SOAPMessageContext context) {
		System.out.println("Client::handleFault() : ");
		return true;
	}

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

	@Override
	public Set getHeaders() {
		System.out.println("Client::getHeaders() : ");
		return null;
	}

}

This Handler basically adds a new Header element to the SOAP envelope with a simple String in it, the IP address of the Client. It will also add an Actor to the Header. A SOAP message may travel from a sender to a receiver by passing different endpoints along the message path. However, not all parts of a SOAP message may be intended for the ultimate endpoint, instead, it may be intended for one or more of the endpoints on the message path. The SOAP actor attribute is used to address the Header element to a specific endpoint.

The SOAP actor global attribute can be used to indicate the recipient of a header element. The value of the SOAP actor attribute is a URI. The special URI “http://schemas.xmlsoap.org/soap/actor/next” as the value of actor attribute indicates that the next SOAP node in the message path must process the header element.

SOAP 1.1 defines only one single role named http://schemas.xmlsoap.org/soap/actor/next (URI_SOAP_ACTOR_NEXT, for short). Every SOAP node is required to assume the next role. Thus, when a SOAP message arrives at any SOAP node, the node must process all headers marked with the next role. In addition to next, SOAP 1.2 defines a few more roles and applications are allowed to define custom roles as well.

The absence of the SOAP actor attributes, in the header block, indicates that the recipient is the ultimate destination of the SOAP message. This attribute must appear in the SOAP message instance in order to be effective.

SOAP Handler XML File

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>com.javacodegeeks.enterprise.ws.handler.IpValidator</javaee:handler-class>
		</javaee:handler>
	</javaee:handler-chain>
</javaee:handler-chains>

Add @HandlerChain annotation to WebServiceImplService

WebServiceImplService .java:

package com.javacodegeeks.enterprise.ws;

import java.net.MalformedURLException;
import java.net.URL;
import javax.xml.namespace.QName;
import javax.xml.ws.Service;
import javax.xml.ws.WebEndpoint;
import javax.xml.ws.WebServiceClient;
import javax.xml.ws.WebServiceException;
import javax.xml.ws.WebServiceFeature;
import javax.jws.HandlerChain;

/**
 * This class was generated by the JAX-WS RI. JAX-WS RI 2.2.4-b01 Generated
 * source version: 2.2
 * 
 */
@WebServiceClient(name = "WebServiceImplService", targetNamespace = "http://ws.enterprise.javacodegeeks.com/", wsdlLocation = "http://localhost:8888/webservice/validator?wsdl")
@HandlerChain(file="./handler/handlers.xml")
public class WebServiceImplService extends Service {

...

}

WSClient.java

package com.javacodegeeks.enterprise.ws;

import com.javacodegeeks.enterprise.ws.WebServiceImplService;

public class WSClient {
	public static void main(String[] args) {

	WebServiceImplService webService = new WebServiceImplService();
	WebServiceInterface serviceInterface = webService.getWebServiceImplPort();

	System.out.println(serviceInterface.printMessage());
 }
}

Let’s see the Eclipse project structure:

package-explorer-client

Test the Application

Now let’s see what happens if we run the above program.

Output for a valid IP address

Client : getHeaders()......
Client : handleMessage()......
Clients ip address :192.168.1.100
<S:Envelope xmlns:S="http://schemas.xmlsoap.org/soap/envelope/">
	<S:Header>
		<ipAddress xmlns="http://ws.enterprise.javacodegeeks.com/"
			xmlns:SOAP-ENV="http://schemas.xmlsoap.org/soap/envelope/"
			SOAP-ENV:actor="http://schemas.xmlsoap.org/soap/actor/next">192.168.1.100</ipAddress>
	</S:Header>
	<S:Body>
		<ns2:printMessage xmlns:ns2="http://ws.enterprise.javacodegeeks.com/" />
	</S:Body>
</S:Envelope>
Client : handleMessage()......
Client : close()......
Hello from Java Code Geeks Server

Output for a valid IP address

Client::getHeaders() : 
Client::handleMessage()
Client's ip address :192.168.1.100
<S:Envelope xmlns:S="http://schemas.xmlsoap.org/soap/envelope/">
	<S:Header>
		<ipAddress xmlns="http://ws.enterprise.javacodegeeks.com/"
			xmlns:SOAP-ENV="http://schemas.xmlsoap.org/soap/envelope/"
			SOAP-ENV:actor="http://schemas.xmlsoap.org/soap/actor/next">12.12.12.12</ipAddress>
	</S:Header>
	<S:Body>
		<ns2:printMessage xmlns:ns2="http://ws.enterprise.javacodegeeks.com/" />
	</S:Body>
</S:Envelope>
Client::handleFault() : 
Client::close() : 
Exception in thread "main" javax.xml.ws.soap.SOAPFaultException: Invalid mac address, access is denied.
	at com.sun.xml.internal.ws.fault.SOAP11Fault.getProtocolException(Unknown Source)
	at com.sun.xml.internal.ws.fault.SOAPFaultBuilder.createException(Unknown Source)
	at com.sun.xml.internal.ws.client.sei.SyncMethodHandler.invoke(Unknown Source)
	at com.sun.xml.internal.ws.client.sei.SyncMethodHandler.invoke(Unknown Source)
	at com.sun.xml.internal.ws.client.sei.SEIStub.invoke(Unknown Source)
	at com.sun.proxy.$Proxy30.printMessage(Unknown Source)
	at com.javacodegeeks.enterprise.ws.WSClient.main(WSClient.java:11)

This was an example on JAX-WS SOAP Handler. Download the Eclipse Projects of this Example : JAX-WS SOAP HANDLER.zip

Related Whitepaper:

Java Essential Training

Author David Gassner explores Java SE (Standard Edition), the language used to build mobile apps for Android devices, enterprise server applications, and more!

The course demonstrates how to install both Java and the Eclipse IDE and dives into the particulars of programming. The course also explains the fundamentals of Java, from creating simple variables, assigning values, and declaring methods to working with strings, arrays, and subclasses; reading and writing to text files; and implementing object oriented programming concepts. Exercise files are included with the course.

Get it Now!  

Examples Java Code Geeks and all content copyright © 2010-2014, Exelixis Media Ltd | Terms of Use
All trademarks and registered trademarks appearing on Examples Java Code Geeks are the property of their respective owners.
Java is a trademark or registered trademark of Oracle Corporation in the United States and other countries.
Examples Java Code Geeks is not connected to Oracle Corporation and is not sponsored by Oracle Corporation.

Sign up for our Newsletter

15,153 insiders are already enjoying weekly updates and complimentary whitepapers! Join them now to gain exclusive access to the latest news in the Java world, as well as insights about Android, Scala, Groovy and other related technologies.

As an extra bonus, by joining you will get our brand new e-books, published by Java Code Geeks and their JCG partners for your reading pleasure! Enter your info and stay on top of things,

  • Fresh trends
  • Cases and examples
  • Research and insights
  • Two complimentary e-books
Get tutored by the Geeks! JCG Academy is a fact... Join Now
Hello. Add your message here.