WELCOME Abdennour : Software engineer

May 17, 2012

4.Develop Web services extended With JAX-Ws :Part2



1.JAX-WS Generalities 
2.Server Developpement
        a.Bottom -> up
                 Full Example with Eclipse Helios from scratch:
        c.Top ->Down
                 Example With Eclipse (Apache Tomcat+Axis) : 
3. Client Developpement : 
4.Annotations:
5.wsimport vs  wsgen:
6.Handler:
      a.Generalities
                  What's Handler in JAX-WS
        b.Part 1 : SOAP handler in server side
                 how to create a SOAP handler and attach it in server side, to retrieve the mac address in SOAP header block from every incoming SOAP message. And do validation to allow only computer with MAC address “90-4C-E5-44-B9-8F” to access this published service.
        c.Part 2 :  SOAP handler in client side
                
develop a web service client to access the published service in previous article, and attach a handler to inject client’s MAC address into header block





7.Java6 &EJB(seet part3)
8.Jax-Ws "in action" :ebay  Web Service .(seet part3) 
9. with NetBeans : (seet part3)



6.Handler
 : 
  Generalities Handler's : 


 -
The "handlers" are interceptors for achieving treatment when receiving and sending messages

  => 
When receiving, they are triggered(
déclenché) before calling an operation.

  =>When sending, they are triggered after calling an operation.



*When Use Handler? 
    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 :
  1. slm\abdennour\ws\jaxws\GetServerName.java
  2. 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