使用处理链处理WEB服务中的请求/响应消息

日期: 2008-03-23 来源:TechTarget中国

  为什么使用处理链?


  一个处理程序可以在客户端或服务器端用来创建一个SOAP的请求消息和响应消息。例如一个使用消息处理程序的简单例子,在SOAP消息中的实体部分对数据进行加密和解密,客户端在他向WEB服务发送SOAP请求消息前必须使用消息处理程序对消息进行加密,WEB服务收到请求后,在它将数据发送到后台实现WEB服务之前,必须使用消息处理程序对从客户端发送过来的消息进行解密。与请求消息的传输方向相反,SOAP响应消息也要执行相同的步骤。


  另外一个例子,在SOAP消息的头部分访问信息进行处理。SOAP头经常用来存储WEB服务详细说明信息并且使用消息处理程序来操作它。例如将用户名和密码可以放在SOAP消息的头部分中来发送到验证处理程序。


  SOAP消息处理可以用来提高WEB服务的使用效率。这种方法的实现可以通过使用队列缓冲SOAP响应的次序。处理程序可以使SOAP的请求信息生效并且将消息交互纪录下来。
 
  处理链:


  处理链就是将每一个消息处理装配成一个链表形式进行处理。在WEB服务中实现可能需要调用多个处理类,用来提供处理请求/响应前面或后面的服务。JAX-RPC运行环境中可以在链表中调用多个处理类。这种处理消息的概念称为处理链。


  处理链模型:


  一个消息处理类功能主要在客户服务器端通信中,尽可能的为终端服务和可以设置用来截取SOAP消息并且在以下几种情况下对消息执行


  各种操作:


  1)在客户端,在SOAP请求被建立后并且在发送到WEB服务之前
  2)在WEB服务端,在SOAP消息请求被WEB服务程序处理之前
  3)在WEB服务端,在WEB服务发送SOAP消息响应之前
  4)在客户端,在JAX-RPC运行时处理从WEB服务中收到的SOAP响应之前



  (图1)


  图一描述了使用后台组件进行处理链操作。当客户端调用WEB服务时,SOAP请求到达处理链中的处理请求部分,一旦处理通过,处理程序将消息传送到WEB服务中并且执行。处理响应程序被WEB服务调用并且将SOAP响应发送到客户端。



  图2使用后台组件的处理链模型


  举例:


  这个例子我们采用的服务为WEBLOGIC8.X,这里我们通过后台组件提供查询服务的验证处理程序来详细说明。这里面的验证内容主要是帐号和个人识别码,它们被放在SOAP请求消息的头部分中,消息处理程序将重新获得帐号和个人识别码并验证,如果验证通过,一旦通过验证,后台组件将会调用余额查询来获得此帐号的余额。


  以下就是写一个处理程序的步骤:


  1)处理程序必须实现javax.xml.rpc.handler.Handler 接口或继承Weblogic中的GenericHandler 类。
  2)javax.xml.rpc.handler.Handler 接口包含了以下这些方法用来实现
  init ()
  destroy()
  getHeaders()
  handleRequest()
  handleResponse()
  handleFault()


  如果使用weblogic.webservice.GenericHandler 类,只需要重写必须的方法,在这个例子中验证处理程序重写了handleRequest() 和handleResponse() 方法。如果handleRequest()方法返回true,将会调用处理链中的下一个处理程序,如果这个处理程序是处理链中最后一个元素,将会调用后台的WEB服务程序。如果  handleRequest()方法返回false,对应的handleResponse()方法将会被调用。验证处理程序中handleRequest() 将从SOAP的头部分中重新获得帐号和个人识别码,并且验证后要返回true 或false结果。


  AuthenticationHandler.java


  import java.util.Map;
  import java.util.Iterator;


  import javax.xml.rpc.JAXRPCException;
  import javax.xml.rpc.handler.soap.SOAPMessageContext;
  import javax.xml.rpc.handler.HandlerInfo;
  import javax.xml.rpc.handler.MessageContext;
  import javax.xml.namespace.QName;
  import javax.xml.soap.*;


  import weblogic.webservice.GenericHandler;


  public class AuthenticationHandler extends GenericHandler
  {


     private int me = System.identityHashCode(this);


     private HandlerInfo handlerInfo = null;
     String accountNo                = null;
     String pin                      = null;


     public void init(HandlerInfo handlerInfo)
     {
        this.handlerInfo = handlerInfo;
     }
     public boolean handleRequest(MessageContext messageContext)
     {
        System.err.println(“** handleRequest called in: “+me);
        try
        {
           SOAPMessageContext sctx = (SOAPMessageContext)messageContext;
           SOAPMessage message     = sctx.getMessage();
           SOAPPart sp             = message.getSOAPPart();
           SOAPEnvelope senv       = sp.getEnvelope();
           SOAPHeader sh           = senv.getHeader();


         Iterator iter =  sh.getChildElements();
         if(iter.hasNext())
         {
            iter.next();                 //skip text
            Object obj = iter.next();    //account details
            SOAPElement elt = (SOAPElement)obj;
            iter = elt.getChildElements();
            iter.next();                 //skip text node
            obj = iter.next();
            elt = (SOAPElement)obj;
            accountNo = elt.getValue();
            iter.next();                 //skip text node
            obj = iter.next();
            elt = (SOAPElement)obj;
            pin = elt.getValue();
         }
        }
        catch (Exception e)
       {
         e.printStackTrace();
         throw new JAXRPCException(e);
       }
        if(accountNo.equals(“12345”) && pin.equals(“6789”))
         return true;
       else
         return false;
     }
     public boolean handleResponse(MessageContext messageContext)
     {
      System.out.println(“Inside HandleResponse”);
      return true;


     }
     public QName[] getHeaders()
     {
      return handlerInfo.getHeaders();
     }
  }


  以下就是余额查询的代码,是一个非常简单的服务返回给出已知帐号的余额。


  BalanceEnquiryService.java
  public class BalanceEnquiryService
  {
     public float getBalance(String accountNo)
     {
      if(accountNo.equals(“12345”))
         return 5000f;
      else
         return 100f;
     }
  }


  WEB服务中的web-service.xml 必须要修改为包含处理链的描述,下面几个部分需要在web-service.xml 中修改的:


  1)在<web-services> 的根元素中创建一个<handler-chains> 子元素,在这个子元素中包含了WEB服务中一系列处理链程序的定义。
  2)创建<handler-chains>的子元素<handler-chain> ,在这个子元素中,显示了所有处理链中的处理程序。对于每一个处理程序,使用类名必须指定 java类的全限定名以便实现处理程序。使用<init-params>元素来指定处理程序的初始化参数。


  <handler-chains>
     <handler-chain name=”myChain”>
      <handler class-name=”myHandlers.handlerOne” />
      <handler class-name=”myHandlers.handlerTwo” />
      <handler class-name=”myHandlers.handlerThree” />
     </handler-chain>
  </handler-chains>


  3.使用<operations>(它本身是<web-service> 的子元素)的子元素<operation>元素,来详细说明处理链是WEB服务中的一个操作。
注意:处理链只是自执行的,没有后台组件参与执行,在这中情况下,只要使用处理链属性中的<operation>元素并且并不需要指定组件或方法的属性,就像下面所选其中的一部分:


  <web-service>
     <operations>
        <operation name=”chainService”
                 handler-chain=”myChain” />
     </operations>
  </web-service>


  这里有一个完整的WEB.xml的例子:


  web-service.xml
  <web-services http://www.w3.org/2001/XMLSchema”>http://www.w3.org/2001/XMLSchema“>
     <handler-chains>
        <handler-chain name=”AuthenticationHandlerChain”>
         <handler class-name=”AuthenticationHandler” />
        </handler-chain>
     </handler-chains>
     <web-service name=”BalanceEnquiryService”
                uri=”/BalanceEnquiryService”
                targetNamespace=”http://www.bea.com“>
        <components>
         <java-class name=”jccomp0″
                     class-name=”BalanceEnquiryService”>
         </java-class>
        </components>
        <operations>
           <operation method=”getBalance”
                    handler-chain=”AuthenticationHandlerChain”
                    component=”jccomp0″>
            <params>
               <param name=”param0″ class-name=”java.lang.String”
                                    style=”in” type=”xsd:string” />
               <return-param name=”result”
                             class-name=”java.lang.Float”
                                           type=”xsd:float” />
             </params>
          </operation>
       </operations>
    </web-service>
  </web-services>


  这里面处理链的名字叫做AuthenticationHandlerChain,这里面包含了一个AuthenticationHandler处理程序,注意,在操作中包含了操作属性handler-chain=”AuthenticationHandlerChain”.


  这里给出了ant脚本build.xml用来打包EAR,注意在打包之前必须有Web.xml 和 application.xml


  build.xml
  <project name=”webservices-handler” default=”all” basedir=”.”>
  <!–  set global properties for this build  –>
  <property environment=”env” />
  <property name=”compiler” value=”modern” />
  <property name=”debug” value=”yes” />
  <property name=”deprecation” value=”yes” />
  <property name=”build.compiler” value=”${compiler}” />
  <property name=”source” value=”.” />
  <property name=”build” value=”${source}/build” />
  <property name=”war_file” value=”BalanceEnquiry.war” />
  <property name=”ear_file” value=”BalanceEnquiry.ear” />
  <property name=”namespace” value=”http://www.bea.com” />
  <property name=”client.classes.dir” value=”{source}/clientclasses” />
  <target name=”all” depends=”clean, war, ear” />
  <target name=”clean”>
  <delete dir=”${build}” />
  <delete file=”${source}/${ear_file}” />
  <delete file=”${war_file}” />
  </target>
  <target name=”war”>
  <delete dir=”${build}” />
  <mkdir dir=”${build}” />
  <mkdir dir=”${build}/WEB-INF” />
  <mkdir dir=”${build}/WEB-INF/classes” />
  <javac srcdir=”${source}” includes=”AuthenticationHandler.java,
                          BalanceEnquiryService.java”
                          destdir=”${build}/WEB-INF/classes” />
  <copy todir=”${build}/WEB-INF”>
  <fileset dir=”${source}”>
  <include name=”web-services.xml” />
  <include name=”web.xml” />
  </fileset>
  </copy>
  <jar jarfile=”${war_file}” basedir=”${build}” />
  </target>
  <target name=”ear” depends=”war”>
  <delete dir=”${build}” />
  <mkdir dir=”${build}” />
  <mkdir dir=”${build}/META-INF” />
  <copy todir=”${build}”>
  <fileset dir=”${source}”>
  <include name=”${war_file}” />
  </fileset>
  </copy>
  <copy todir=”${build}/META-INF”>
  <fileset dir=”${source}”>
  <include name=”application.xml” />
  </fileset>
  </copy>
  <jar jarfile=”${source}/${ear_file}” basedir=”${build}” />
  </target>
  </project>


  ant脚本在创建WAR文件的同时也进行EAR打包,在WEBLOGIC服务器上部署打包好的EAR文件,下面是客户端调用余额查询的程序:


  Client.java
  import org.apache.axis.client.Call;
  import org.apache.axis.client.ServiceFactory;
  import org.apache.axis.client.Service;
  import org.apache.axis.MessageContext;
  import org.apache.axis.attachments.Attachments;
  import org.apache.axis.message.SOAPEnvelope;


  import javax.xml.namespace.QName;
  import javax.xml.soap.SOAPBody;
  import javax.xml.soap.SOAPBodyElement;
  import javax.xml.soap.SOAPConnection;
  import javax.xml.soap.SOAPConnectionFactory;
  import javax.xml.soap.SOAPElement;
  import javax.xml.soap.SOAPHeader;
  import javax.xml.soap.SOAPHeaderElement;
  import javax.xml.soap.SOAPMessage;
  import javax.xml.soap.SOAPPart;
  import javax.xml.namespace.QName;
  import javax.xml.rpc.ParameterMode;
  import javax.xml.soap.AttachmentPart;
  import javax.xml.soap.MessageFactory;
  import javax.xml.soap.Name;
  import javax.xml.rpc.ParameterMode;


  import java.net.URL;
  import java.util.Iterator;


  public class Client
  {
     private static String TARGET_NAMESPACE = “http://www.bea.com“;
     private static QName xsdFloat = new
                  QName(“http://www.w3.org/2001/XMLSchema“, “float”);
     public static org.apache.axis.message.SOAPEnvelope env = null;
     public static SOAPMessage message = null;
     public static void main(String[] argv) throws Exception
     {
      Client client = new Client();
      env = client.constructSOAPEnvelope();
      client.constructHeader(env);
      client.constructBody(env);
      System.setProperty( “javax.xml.rpc.ServiceFactory”,
                          “org.apache.axis.client.ServiceFactory” );


      String url =
     “http://localhost:7001/BalanceEnquiry/BalanceEnquiryService”;
     ServiceFactory factory =
         (org.apache.axis.client.ServiceFactory)ServiceFactory.
              newInstance();
      QName serviceName   = new QName(TARGET_NAMESPACE,
         “BalanceEnquiryService”);


      Service service =
         (org.apache.axis.client.Service)factory.
          createService(serviceName);
      Call call = (org.apache.axis.client.Call)service.createCall();
      call.setTargetEndpointAddress(url);
      SOAPEnvelope result = call.invoke(env);
      System.out.println(result);
    }
     public SOAPEnvelope constructSOAPEnvelope() throws Exception
    {
      org.apache.axis.message.SOAPEnvelope env = new
         org.apache.axis.message.SOAPEnvelope();
      return env;
    }
     public void constructHeader(SOAPEnvelope envelope) throws Exception
    {
      SOAPHeader header = envelope.getHeader();
      Name headerElementName =
         envelope.createName(“AccountDetails”,””,
                             “http://schemas.xmlsoap.org/soap/
                                     envelope/”);
      SOAPHeaderElement headerElement =
         header.addHeaderElement(headerElementName);
      headerElement.setMustUnderstand(false);
      headerElement.addNamespaceDeclaration(“soap”,
         “http://schemas.xmlsoap.org/soap/envelope/“);
      SOAPElement accNo = headerElement.addChildElement(“accountNo”);
      accNo.addTextNode(“12345”);
      SOAPElement pinNo = headerElement.addChildElement(“pin”);
      pinNo.addTextNode(“6789”);
   }


     public void constructBody(SOAPEnvelope envelope) throws Exception
    {
      SOAPBody body = envelope.getBody();
      Name bodyRootElementName =
         envelope.createName(“getBalance”,””,
                             “http://schemas.xmlsoap.org/soap/
                                     encoding/”);
      SOAPBodyElement bodyRootElement =
         body.addBodyElement(bodyRootElementName);
      SOAPElement bodyElement =
         bodyRootElement.addChildElement(“param0”);
      bodyElement.addAttribute(envelope.createName(“xsi:type”),
                                                   “xsd:string”);
       bodyElement.addTextNode(“12”);
    }
  }


  如果在客户端也有一个处理程序,以下部分要发生变化:


  (1)导入import javax.xml.rpc.handler.HandlerInfo;
  import javax.xml.rpc.handler.HandlerRegistry;两个类。


  (2)在call().invoke前面加:
  QName portName = new QName( “http://bea.com/“,
                            “HelloWorldServicePort”);
  HandlerRegistry registry = service.getHandlerRegistry();
  List handlerList = new ArrayList();
  handlerList.add( new HandlerInfo( ClientHandler.class, null,null ) );
  registry.setHandlerChain( portName, handlerList );


  结论:


  我们希望能让大家更多的了解关于处理链机制并且应用到WEB服务中。

我们一直都在努力坚持原创.......请不要一声不吭,就悄悄拿走。

我原创,你原创,我们的内容世界才会更加精彩!

【所有原创内容版权均属TechTarget,欢迎大家转发分享。但未经授权,严禁任何媒体(平面媒体、网络媒体、自媒体等)以及微信公众号复制、转载、摘编或以其他方式进行使用。】

微信公众号

TechTarget微信公众号二维码

TechTarget

官方微博

TechTarget中国官方微博二维码

TechTarget中国

相关推荐