JAX – WS – 14 – SOAPHandler Server Side

Merhaba arkadaslar
Bu bolumde SOAPHandler’i inceleyecegiz.

SOAP message’lari HTTP mesajlarina benzerlik gostermektedir.
SOAP ve HTTP mesajlari header ve body bilgisine sahiptir. SOAP mesajlarinda header bilgisi opsiyoneldir.
HTTP 1.1 icin en az 1 tane header bilgisi (key/value) zorunludur.

SOAP mesaj yapisi, tek yonlu iletisim (one-way transmission) mimarisi uzerine kurulmustur.

SOAP message architecture(mimari) , sender ve receiver dan olusur fakat buna ek olarak
intermediary dugumleri de bu mimaride yer almaktadir.

A SOAP message has a sender and targets a receiver, but the SOAP messaging architecture 
allows for intermediaries, which are nonterminal recipients along the route 
from the sender to the ultimate receiver.

Bir uygulamada, sender security credential bilgilerini SOAP header message’larina ekleyebilir.
Bir intermediary node/dugum de bu bilgileri verify edebilir, verification basarili oldugunda ,
bir verification block bilgisini SOAP mesajin header alanina ekleyebilir ve sonraki dugume gonderebilir.
Ya da verification fail/basarisiz oldugunda bir SOAP fault firlatabilir ve mesaji terminate edebilir.

Intermediary ‘er bir nevi filter/interceptor gibi gorev yapmaktadirlar.

SOAP handler is a SOAP message interceptor, which is able to intercept incoming or 
outgoing SOAP message and manipulate its values.

SOAPHandler
LogicalHandler

Simple JAX-WS

Oncelikle , yeni bir proje olusturalim ve onceki bolumlerde kullandigimiz basit bir web service’i uyguluyalim.
(Ornek projeyi bolum sonunda belirttigim , Github hesabim uzerinden ulasabilirsiniz
proje adi : injavawetrust.jaxws.soaphandler.service)

MessageWriter.java

package ws.service;

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

@WebService
@SOAPBinding(style = Style.RPC)
public interface MessageWriter {

	@WebMethod
	public String getWelcomeMessage(@WebParam(name = "name") String name, @WebParam(name = "surname") String surname);
	
}

MessageWriterImpl.java

package ws.service;

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

@WebService(endpointInterface = "ws.service.MessageWriter")
public class MessageWriterImpl implements MessageWriter {

	@Override
	public String getWelcomeMessage(String name, String surname) {
		return "Welcome , " + name + " " + surname + ". This message is sent by MessageWriterImpl#getWelcomeMessage.";
	}

}

WebServicePublisher.java

package ws.publisher;

import javax.xml.ws.Endpoint;

import ws.service.MessageWriterImpl;

public class WebServicePublisher {

	private static String WEB_SERVICE_URL = "http://localhost:8888/injavawetrust/hello.jaxws";

	public static void main(String[] args) {
		Endpoint.publish(WEB_SERVICE_URL, new MessageWriterImpl());
		System.out.println("Web Service is started.");
	}
}

SOAPHandler implementation

Onceki orneklerimizde buraya kadar olan kodlari uygulamistik. Simdi de SOAPHandler interface’ini implements edelim.
handleMethod metodunu inceleyecek olursak

SOAPMessageContext objesi uzerinden , MessageContext.MESSAGE_OUTBOUND_PROPERTY boolean degerini aliyoruz.
bu deger false oldugunda client’tan gelen istek mesaji anlamina gelmektedir.

  • SOAPMessage
  • SOAPEnvelope
  • SOAPHeader objelerini olusturuyoruz.

Eger token gonderilmemisse exception firlatiyoruz.( No SOAP header)

Sonrasinda extractHeaderElements metodun kullaniyoruz metoda SOAPConstants.URI_SOAP_ACTOR_NEXT  degerini veriyoruz.

Node objesi uzerinden getValue metodunu cagiriyoruz , gonderilen token degeri gecerliyse (token12345) basarili sekilde devam etmekte, aksi durumda exception firlatilmaktadir. (else block)

package 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 TokenHandler implements SOAPHandler<SOAPMessageContext> {

	private final String validTokenValue = "token12345";

	@Override
	public boolean handleMessage(SOAPMessageContext context) {

		// Standard property: message direction, true for outbound messages,
		// false for inbound.
		Boolean outbound = (Boolean) context.get(MessageContext.MESSAGE_OUTBOUND_PROPERTY);

		// if this is an incoming message from the client
		if (!outbound) {
			System.out.println("TokenHandler#handleMessage working...");
			try {
				// Get the SOAPMessage , SOAPEnvelope and SOAPHeader
				SOAPMessage soapMsg = context.getMessage();
				SOAPEnvelope soapEnv = soapMsg.getSOAPPart().getEnvelope();
				SOAPHeader soapHeader = soapEnv.getHeader();

				Iterator<?> headerIterator = soapHeader.extractHeaderElements(SOAPConstants.URI_SOAP_ACTOR_NEXT);

				if (headerIterator == null || !headerIterator.hasNext()) {
					generateSOAPErrorMessage(soapMsg, "No SOAP header.");

				}

				Node propertyNode = (Node) headerIterator.next();

				String tokenValueFromClient = null;

				if (propertyNode != null) {
					tokenValueFromClient = propertyNode.getValue();

				}
				System.out.println(tokenValueFromClient);
				if (validTokenValue.equals(tokenValueFromClient)) {
					System.out.println("Valid Token");
					soapMsg.writeTo(System.out);
				} else {
					generateSOAPErrorMessage(soapMsg, "Invalid Token.");
				}

			} catch (SOAPException | SOAPFaultException | IOException e) {
				e.printStackTrace();
				//return false if someting wrong
				return false;
			}

		}

		return true;
	}

	@Override
	public boolean handleFault(SOAPMessageContext context) {
		return false;
	}

	@Override
	public void close(MessageContext context) {
	}

	@Override
	public Set<QName> getHeaders() {
		return null;
	}

	private void generateSOAPErrorMessage(SOAPMessage msg, String reason) throws SOAPException {
		SOAPBody soapBody = msg.getSOAPPart().getEnvelope().getBody();
		SOAPFault soapFault = soapBody.addFault();
		soapFault.setFaultString(reason);
		throw new SOAPFaultException(soapFault);
	}
}

XML Configuration

Simdi de XML configuration dosyamizi ekleyelim.
javaee:handler-class, ws.handler.TokenHandler sinifini ekleyelim.
handler-server-config.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>ws.handler.TokenHandler</javaee:handler-class>
		</javaee:handler>
	</javaee:handler-chain>
</javaee:handler-chains>

@HandlerChain

Bir sonraki adim olarak @HandlerChain annotation’ini MessageWriterImpl sinifina ekleyelim.
Bu dosya ws.config package icerisinde yer aldigi icin file path bilgisini ilgili sekilde verdim.

@WebService(endpointInterface = "ws.service.MessageWriter")
@HandlerChain(file="ws/config/handler-server-config.xml")
public class MessageWriterImpl implements MessageWriter {
...
}

Run Application

Uygulamamizi publish edelim ve SOAP UI yardimiyla testlerimizi yapalim.

Header bilgisi eklemeden sadece name , surname alanlarini ekleyip gonderdigimizde No SOAP header faultstring degeri dondugunu gorebiliriz.

Request 1

<soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/" xmlns:ser="http://service.ws/">
   <soapenv:Header/>
   <soapenv:Body>
      <ser:getWelcomeMessage>
         <name>Levent</name>
         <surname>Erguder</surname>
      </ser:getWelcomeMessage>
   </soapenv:Body>
</soapenv:Envelope>

Resonse 1

<S:Envelope xmlns:S="http://schemas.xmlsoap.org/soap/envelope/">
   <S:Body>
      <S:Fault xmlns:ns4="http://www.w3.org/2003/05/soap-envelope">
         <faultcode>S:Server</faultcode>
         <faultstring>No SOAP header.</faultstring>
      </S:Fault>
   </S:Body>
</S:Envelope>

Eclipse Console’da

TokenHandler#handleMessage working...
javax.xml.ws.soap.SOAPFaultException: No SOAP header.
	at ws.handler.TokenHandler.generateSOAPErrorMessage(TokenHandler.java:90)
	at ws.handler.TokenHandler.handleMessage(TokenHandler.java:43)
	at ws.handler.TokenHandler.handleMessage(TokenHandler.java:1)
	at com.sun.xml.internal.ws.handler.HandlerProcessor.callHandleMessage(HandlerProcessor.java:282)
	at com.sun.xml.internal.ws.handler.HandlerProcessor.callHandlersRequest(HandlerProcessor.java:125)
	at com.sun.xml.internal.ws.handler.ServerSOAPHandlerTube.callHandlersOnRequest(ServerSOAPHandlerTube.java:123)
....

Ornek token degerini ekleyebiliriz , herhangi bir isim verebiliriz.
Gecersiz bir token verdigimizde Invalid Token mesaji donecektir.

Request 2

<soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/" xmlns:ser="http://service.ws/">
   <soapenv:Header>
   	<MYTOKEN xmlns="http://service.ws.injavawetrust/" soapenv:actor="http://schemas.xmlsoap.org/soap/actor/next">token12345NotValid</MYTOKEN>
   </soapenv:Header>
   <soapenv:Body>
      <ser:getWelcomeMessage>
         <name>Levent</name>
         <surname>Erguder</surname>
      </ser:getWelcomeMessage>
   </soapenv:Body>
</soapenv:Envelope>

Response 2

<soapenv:Envelope xmlns:SOAP-ENV="http://schemas.xmlsoap.org/soap/envelope/" xmlns:ser="http://service.ws/" xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/">
   <soapenv:Header/>
   <soapenv:Body>
      <ser:getWelcomeMessage>
         <name>Levent</name>
         <surname>Erguder</surname>
      </ser:getWelcomeMessage>
      <soapenv:Fault>
         <faultcode>SOAP-ENV:Server</faultcode>
         <faultstring>Invalid Token.</faultstring>
      </soapenv:Fault>
   </soapenv:Body>
</soapenv:Envelope>

Eclipse Console’da

TokenHandler#handleMessage working...
token12345NotValid
javax.xml.ws.soap.SOAPFaultException: Invalid Token.
	at ws.handler.TokenHandler.generateSOAPErrorMessage(TokenHandler.java:91)
	at ws.handler.TokenHandler.handleMessage(TokenHandler.java:60)
	at ws.handler.TokenHandler.handleMessage(TokenHandler.java:1)
	at com.sun.xml.internal.ws.handler.HandlerProcessor.callHandleMessage(HandlerProcessor.java:282)
	at com.sun.xml.internal.ws.handler.HandlerProcessor.callHandlersRequest(HandlerProcessor.java:125)
	at com.sun.xml.internal.ws.handler.ServerSOAPHandlerTube.callHandlersOnRequest(ServerSOAPHandlerTube.java:123)
	at com.sun.xml.internal.ws.handler.HandlerTube.processRequest(HandlerTube.java:112)

Son olarak gecerli token degerini gonderdigimizde basarili sonucu elde ederiz.

<S:Envelope xmlns:S="http://schemas.xmlsoap.org/soap/envelope/">
   <S:Body>
      <ns2:getWelcomeMessageResponse xmlns:ns2="http://service.ws/">
         <return>Welcome , Levent Erguder. This message is sent by MessageWriterImpl#getWelcomeMessage.</return>
      </ns2:getWelcomeMessageResponse>
   </S:Body>
</S:Envelope>
<S:Envelope xmlns:S="http://schemas.xmlsoap.org/soap/envelope/">
   <S:Body>
      <ns2:getWelcomeMessageResponse xmlns:ns2="http://service.ws/">
         <return>Welcome , Levent Erguder. This message is sent by MessageWriterImpl#getWelcomeMessage.</return>
      </ns2:getWelcomeMessageResponse>
   </S:Body>
</S:Envelope>

Github kaynak kodlar / source folder
injavawetrust.jaxws.soaphandler.service

Print Friendly, PDF & Email

Leave a Reply

Your email address will not be published. Required fields are marked *