i.Filter Calls to Operations of WS ?
ii.Write Logs
*Types of Handler?
i. Handlers related to the transport protocol (eg SOAP)
=>Use SOAPHandler interface : access to the entire message including the SOAP
headers
ii.Handlers related content transferred (logical Handlers)
=>Use SOAPLogic interface : independence of the transport protocol and access the content of the message
*Methods of Handler Interface defined by JAX-WS?
i. Boolean handleMessage (C context)
* Invoked when messages incoming and outgoing. If false is returned the process is stopped
ii. Boolean handleFault (C context)
* Invoked when messages error (fault))
=> C is a geniric Type which inherit from MessageContext which is a Map
*Properties of MessageContext(as it's a Map) :
1.MESSAGE_OUTBOUND_PROPERTY : to determine if it is incoming or outgoing messages
2.HTTP_REQUEST_HEADERS:to retrive HTTP Header of Request .
3.WSDL_OPERATION :name of WSDL operation .
4.WSDL_SERVICE : name of WSDL Service .
a.SOAP handler in server side:
* Step1 :
Develop Java class that implements either the interface SOAPHandler or LogicalHandler
*Step 2 :
Define a mapping file (handlers.xml) .
=>to specify the classes that implement the handlers
<?xml
version="1.0"
encoding="UTF-8"?>
<handler-chains
xmlns="http://java.sun.com/xml/ns/javaee">
<handler-chain>
<handler>
<handler-name>Name_Of_HANDLER</handler-name>
<handler-class>CLASSE_OF_HANDLER</handler-class>
</handler>
</handler-chain>
</handler-chains>
* Step3 :
annoted POJO Class with @HandlerChain
a.1.Example :retrieve the mac address in SOAP header block from every incoming SOAP message.
1. Web Service
A simple web service , with a getServerName()
method to return a string.
File : ServerInfo.java
package slm.abdennour.ws;
import javax.jws.WebMethod;
import javax.jws.WebService;
import javax.jws.HandlerChain;
@WebService
public
class ServerInfo {
@WebMethod
public String getServerName(){
return "Abdennour Engine Server";
}
}
Generate necessary Java files for the web service deployment.
toumi@toumi-laptop:~/workspaceEclipseAll/soaHelios/handlerSOAPServer/build/classes$wsgen -keep -verbose -cp . slm.abdennour.ws.ServerInfo
Two files are generated :
- slm\abdennour\ws\jaxws\GetServerName.java
- slm\abdennour\ws\jaxws\GetServerNameResponse.java
File : GetServerName.java
package slm.abdennour.ws.jaxws;
import javax.xml.bind.annotation.XmlAccessType;
import javax.xml.bind.annotation.XmlAccessorType;
import javax.xml.bind.annotation.XmlRootElement;
import javax.xml.bind.annotation.XmlType;
@XmlRootElement(name = "getServerName", namespace = "http://ws.abdennour.slm/")
@XmlAccessorType(XmlAccessType.FIELD)
@XmlType(name = "getServerName", namespace = "http://ws.abdennour.slm/")
public class GetServerName {
}
File : GetServerNameResponse.java
package slm.abdennour.ws.jaxws;
import javax.xml.bind.annotation.XmlAccessType;
import javax.xml.bind.annotation.XmlAccessorType;
import javax.xml.bind.annotation.XmlElement;
import javax.xml.bind.annotation.XmlRootElement;
import javax.xml.bind.annotation.XmlType;
@XmlRootElement(name = "getServerNameResponse", namespace = "http://ws.abdennour.slm/")
@XmlAccessorType(XmlAccessType.FIELD)
@XmlType(name = "getServerNameResponse", namespace = "http://ws.abdennour.slm/")public class GetServerNameResponse {
@XmlElement(name = "return", namespace = "")
private String _return;
/**
*
* @return
* returns String
*/
public String getReturn() {
return this._return;
}
/**
*
* @param _return
* the value for the _return property
*/
public void setReturn(String _return) {
this._return = _return;
}
}
2. SOAP Handler
Create a SOAP handler to retrieve the value in SOAP header block, for every incoming SOAP message. See comments for the code explanation.
File MacAddressValidatorHandler.java
package slm.abdennour.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 MacAddressValidatorHandler implements SOAPHandler<SOAPMessageContext>{
@Override
public boolean handleMessage(SOAPMessageContext context) {
System.out.println("Server : handleMessage()......");
Boolean isRequest = (Boolean) context.get(MessageContext.MESSAGE_OUTBOUND_PROPERTY);
//for response message only, true for outbound messages, false for inbound
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();
//throw exception
generateSOAPErrMessage(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()){
generateSOAPErrMessage(soapMsg, "No header block for next actor.");
}
//if no mac address found? throw exception
Node macNode = (Node) it.next();
String macValue = (macNode == null) ? null : macNode.getValue();
if (macValue == null){
generateSOAPErrMessage(soapMsg, "No mac address in header block.");
}
//if mac address is not match, throw exception
if(!macValue.equals("90-4C-E5-44-B9-8F")){
generateSOAPErrMessage(soapMsg, "Invalid mac address, access is denied.");
}
//tracking
soapMsg.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("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 generateSOAPErrMessage(SOAPMessage msg, String reason) {
try {
SOAPBody soapBody = msg.getSOAPPart().getEnvelope().getBody();
SOAPFault soapFault = soapBody.addFault();
soapFault.setFaultString(reason);
throw new SOAPFaultException(soapFault);
}
catch(SOAPException e) { }
}
}
3. SOAP Handler XML file
Create a SOAP handler XML file, and puts your SOAP handler declaration.
File : handler-chain.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>slm.abdennour.handler.MacAddressValidatorHandler</javaee:handler-class>
</javaee:handler>
</javaee:handler-chain>
</javaee:handler-chains>
4. Attach SOAP Handler –> Web Service
To attach above SOAP handler to web service ServerInfo.java
, just annotate with @HandlerChain and specify the SOAP handler file name inside.
File : ServerInfo.java
package slm.abdennour.ws;
import javax.jws.HandlerChain;
import javax.jws.WebMethod;
import javax.jws.WebService;
@WebService
@HandlerChain(file="handler-chain.xml")
public class ServerInfo{
@WebMethod
public String getServerName() {
return "Abdennour Engine Server";
}
}
5. Web Service Publisher
A simple web service publisher for testing.
package slm.abdennour.endpoint;
import javax.xml.ws.Endpoint;
import slm.abdennour.ws.ServerInfo;
//Endpoint publisher
public class WsPublisher{
public static void main(String[] args) {
Endpoint.publish("http://localhost:8888/ws/server", new ServerInfo());
System.out.println("Service is published!");
}
}
Send Request SOAP With SoapUI
b.SOAP handler in Client side:
develop a web service client to access the published service in previous Example(side Server)
, and
attach a handler to inject client’s MAC address into header block, for every outgoing SOAP message that’s send by client side.
1. Web Service Client
Uses wsimport command to parse the published service WSDL file (http://localhost:8888/ws/server?wsdl) and generate all required files to access the service.
C:\>wsimport -keep -verbose http://localhost:8888/ws/server?wsdl
parsing WSDL...
generating code...
slm\abdennour\ws\GetServerName.javaslm\abdennour\ws\GetServerNameResponse.javaslm\abdennour\ws\ObjectFactory.javaslm\abdennour\ws\ServerInfo.javaslm\abdennour\ws\ServerInfoService.javaslm\abdennour\ws\package-info.java
Six files are generated automatically, you may only need to concern on the ServerInfoService.java
.
File : ServerInfoService.java
@WebServiceClient(name = "ServerInfoService",
targetNamespace = "http://ws.abdennour.slm/", wsdlLocation = "http://localhost:8888/ws/server?wsdl")
public class ServerInfoService extends Service
{
//......
}
A client to access the published service.
File : WsClient.java
package slm.abdennour.client;
import slm.abdennour.ws.ServerInfo;
import slm.abdennour.ws.ServerInfoService;
public class WsClient{
public static void main(String[] args) throws Exception {
ServerInfoService sis = new ServerInfoService();
ServerInfo si = sis.getServerInfoPort();
System.out.println(si.getServerName());
}
}
2. SOAP Handler
Create a SOAP handler to inject client’s MAC address into the SOAP header block, for every outgoing SOAP message :
File : MacAddressInjectHandler.java
package slm.abdennour.handler;
import java.io.IOException;
import java.net.InetAddress;
import java.net.NetworkInterface;
import java.net.SocketException;
import java.net.UnknownHostException;
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 MacAddressInjectHandler implements SOAPHandler<SOAPMessageContext>{
@Override
public boolean handleMessage(SOAPMessageContext context) {
System.out.println("Client : handleMessage()......");
Boolean isRequest = (Boolean) context.get(MessageContext.MESSAGE_OUTBOUND_PROPERTY);
//if this is a request, true for outbound messages, false for inbound
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();
}
//get mac address
String mac = getMACAddress();
//add a soap header, name as "mac address"
QName qname = new QName("http://ws.abdennour.slm/", "macAddress"); SOAPHeaderElement soapHeaderElement = soapHeader.addHeaderElement(qname);
soapHeaderElement.setActor(SOAPConstants.URI_SOAP_ACTOR_NEXT);
soapHeaderElement.addTextNode(mac);
soapMsg.saveChanges();
//tracking
soapMsg.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<QName> getHeaders() {
System.out.println("Client : getHeaders()......");
return null;
}
//return current client mac address
private String getMACAddress(){
InetAddress ip;
StringBuilder sb = new StringBuilder();
try {
ip = InetAddress.getLocalHost();
System.out.println("Current IP address : " + ip.getHostAddress());
NetworkInterface network = NetworkInterface.getByInetAddress(ip);
byte[] mac = network.getHardwareAddress();
System.out.print("Current MAC address : ");
for (int i = 0; i < mac.length; i++) {
sb.append(String.format("%02X%s", mac[i], (i < mac.length - 1) ? "-" : ""));
}
System.out.println(sb.toString());
} catch (UnknownHostException e) {
e.printStackTrace();
} catch (SocketException e){
e.printStackTrace();
}
return sb.toString();
}
}
3. SOAP Handler XML file
Create a SOAP handler XML file, and puts your SOAP handler declaration.
File : handler-chain.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.abdennour.handler.MacAddressInjectHandler</javaee:handler-class> </javaee:handler>
</javaee:handler-chain>
</javaee:handler-chains>
4. Attach SOAP Handler –> Web Service Client
To attach above SOAP handler to web service client, edit the ServerInfoService.java
file (generated via wsimport), and annotate with @HandlerChain and specify the SOAP handler file name inside.
File : ServerInfoService.java
@WebServiceClient(name = "ServerInfoService",
targetNamespace = "http://ws.abdennour.slm/",
wsdlLocation = "http://localhost:8888/ws/server?wsdl")
@HandlerChain(file="handler-chain.xml")
public class ServerInfoService extends Service
{
//......
}
No comments:
Post a Comment