Apache Axis用戶指南(2)

本部分是apache axis用戶指南的第二部分。
5.服務Styles---RPC,Document,Wrapped和消息
Axis支持四種樣式的服務。
RPC服務使用SOAP RPC慣例和SOAP section 5的編碼。Document服務部使用任何編碼方式(所以,不會看到多飲用的對象序列化或者SOAP-style數組),但是使用XML<-->Java數據綁定。Wrapped服務和document服務相似,但是Wrapped服務不是將整個SOAPbody綁定到一個大的結構,而是將它分成很多個體參數。Message服務接受和返回任意SOAP Envelope中的XML,並不進行類型映射和數據綁定。
如果只想使用原始的XML作爲SOAP Envelope的輸入和輸出,那麼就是用message服務。
RFC服務
RFC服務是Axis的默認服務。它們在部署描述符中的定義爲<service....provider=”java:RPC”>或者<service....style=”RPC”>RPC服務遵循SOAP RPC和編碼規則,這意味着RPC服務的XML就像上面的echoString例子一樣,每個RPC調用都作爲操作名,包含的內部元素對應操作的參數。Axis會將XML反序列化成Java對象來適應服務,然後再將返回的Java對象進行序列化成XML返回。由於RPC服務默認使用soap section 5比阿瑪規則,對象會通過multi-ref序列化,允許對對象圖表進行編碼。
Document/Wrapped服務
這兩種服務很類似,都不對數據進行SOAP編碼,而只是簡單的XML Schema。在這兩種情況中,Axis仍然對java表示與XML進行綁定,所以只需要處理Java對象,而不是直接處理XML結構。
下面是一個關於購買順序的SOAP消息,用來說明兩者的區別:
<soap:Envelope xmlns="http://xml.apache.org/axis/wsdd/"
            xmlns:java="http://xml.apache.org/axis/wsdd/providers/java">
 <soap:Body>
    <myNS:PurchaseOrder xmlns:myNS="http://commerce.com/PO">
      <item>SK001</item>
     <quantity>1</quantity>
      <description>Sushi Knife</description>
    </myNS:PurchaseOrder>
 </soap:Body>
</soap:Envelope>
PurchaseOrder元素的Schema如下:
<schema targetNamespace="http://commerce.com/PO">
 <complexType name="POType">
    <sequence>
      <element name="item" type="xsd:string"/>
      <element name="quantity" type="xsd:int"/>
      <element name="description" type="xsd:string"/>
    </sequence>
 </complexType>
 <element name="PurchaseOrder" type="POType"/>
</deployment>
對於Document樣式的服務,將會映射到一個如下的方法:
public void method(PurchaseOrder po)
也就是說,整個<PurchaseOrder>元素作爲方法的一個單獨的bean對象參數,這個Bean類應該有三個成員屬性。而對於wrapped樣式的服務來說,將會映射到如下的方法:
public void purchaseOrder(String item,int quality,String description)
注意在這種情況的大小寫,<PurchaseOrder>元素是一個”wrapper”,只處理正確的操作。方法的參數就是unwrap外層元素後的每一個內層元素。
document或者wrapped樣式的定義是在WSDD中定義的:
<service ... style="document"> for document style
<service ... style="wrapped"> for wrapped style
當使用WSDL文檔創建Web Service的時候,就不需要擔心到底是哪種服務了。
Message服務
最後是Message樣式的服務,當需要使Axis無效,將代碼作爲實際的XML查看而不是java對象的時候,就使用這種服務。
下面是四的message-style服務的方法的合法信號
public Element [] method(Element [] bodies);
public SOAPBodyElement [] method (SOAPBodyElement [] bodies);
public Document method(Document body);
public void method(SOAPEnvelope req, SOAPEnvelope resp);
前兩個將方法的數組傳給方法DOM元素或者SOAPBody元素的數組-----這個數組包含<soap:body>中的每一個XML元素。
第三個方法傳遞一個DOM文檔,這個文檔表示<soap:body>,並期望同樣的返回。
最後一個傳遞兩個SOAPEnvelope對象來表示請求和響應消息,這意味着可以在服務方法中查看或者修改headers
Message樣例
Axis的例子中,samples/message/MessageService.java就是一個Message服務的例子,服務的類是MessageService,包含一個公開方法,echoElement,符合上述中的第一個方法:
public Element[] echoElements(Element[] elems)
MsgProvider是一個handler,它調用echoElement()方法,傳遞一個org.w3c.dom.Element的數組作爲參數,作爲輸入信息的SOAPbody的直接子元素。一般來說,這個數組會包含一個單獨的Element(可能是一個XML文檔的根元素),但是SOAP Body可以處理任意多個子元素。這個方法返回一個Element[]數組作爲響應消息的SOAP Body
package samples.message ;
 
import org.w3c.dom.Element;
import javax.xml.soap.SOAPEnvelope;
import javax.xml.soap.Name;
import javax.xml.soap.SOAPBody;
import javax.xml.soap.SOAPBodyElement;
import javax.xml.soap.SOAPHeader;
import javax.xml.soap.SOAPElement;
 
/**
 * Simple message-style service sample.
 */
public class MessageService {
    /**
     * Service method, which simply echoes back any XML it receives.
     *
     * @param elems an array of DOM Elements, one for each SOAP body element
     * @return an array of DOM Elements to be sent in the response body
     */
    public Element[] echoElements(Element [] elems) {
        return elems;
    }
 
    public void process(SOAPEnvelope req, SOAPEnvelope resp) throws javax.xml.soap.SOAPException {
    SOAPBody body = resp.getBody();
    Name ns0 = resp.createName("TestNS0", "ns0", "http://example.com");
    Name ns1 = resp.createName("TestNS1", "ns1", "http://example.com");
    SOAPElement bodyElmnt = body.addBodyElement(ns0);
    SOAPElement el = bodyElmnt.addChildElement(ns1);
    el.addTextNode("TEST RESPONSE");
    }
}
MessageServiceWSDD文件內容如下:
<deployment name="test" xmlns="http://xml.apache.org/axis/wsdd/"
      xmlns:java="http://xml.apache.org/axis/wsdd/providers/java"
      xmlns:xsi="http://www.w3.org/2000/10/XMLSchema-instance">
         <service name="MessageService" style="message">
    <parameter name="className" value="samples.message.MessageService"/>
    <parameter name="allowedMethods" value="echoElements"/>
 </service>
</deployment>
注意這裏使用的是style=”message”,而不是使用provider=”java:RPC”message style告訴Axis本服務是由org.apache.axis.providers.java.MsgProvider來處理的,而不是org.apache.axis.providers.java.RPCProvider
6.XML<---->Java數據映射
Java類型映射到SOAP/XML
互操作,或者叫interop,是各種SOAP實現之間的一個存在的挑戰。如果期望服務在其他的平臺和實現上也可以使用,需要理解這個概念。AxisJava類型到WSDL/XSD/SOAP的映射由JAX-RPC規範確定。相關內容請參考JAX-RPC規範。
WSDLJava的標準映射
xsd:base64Binary          byte[]
xsd:boolean                     boolean
xsd:byte                             byte
xsd:dateTime                  java.util.Calendar
xsd:decimal                      java.math.BigDecimal
xsd:double                        double
xsd:float                             float
xsd:hexBinary                  byte[]
xsd:int                                  int
xsd:integer                         java.math.BigInteger
xsd:long                             long
xsd:QName                      javax.xml.namespace.QName
xsd:short                            short
xsd:string                            java.lang.String
如果在WSDL中聲明瞭一個對象是nillable的,則調用者可以選擇返回值爲0,這樣的話,原始數據類型可以使用它們的包裝類代替,例如ByteDoubleBoolean
SOAP編碼數據類型
XSD數據類型相對應的是SOAP ‘Section 5’數據類型,這些數據類型都是nillable的,所以總是可以和包裝類映射。這些類型之所以存在是因爲他們都支持IDHREF屬性,所以也用於當一個RPC編碼的context來支持multi-ref序列化。
7.異常
一般來說,Axisjava.rmi.RemoteException映射成爲SOAP Fault。這部分內容在筆者介紹的Axis2的文章中有比較詳細的介紹,請參考。
8.Axis可以/不可以通過SOAP發送的內容
Java的集合框架元素,例如Hashtable,具有序列器,但是和其它的SOAP實現沒有正式的交互操作能力,並且在SOAP規範中沒有對應的複雜對象。最可靠的發送集合對象的辦法就是使用數組。
沒有預先註冊的對象:不能發送任意的Java對象,並且期望它們可以被在服務器端被理解。在使用RMI的時候,可以發送和接受實現了Serializable接口的Java對象,那是由於雙發都是使用JavaAxis值可以發送那麼被Axis序列器註冊的對象。文本後面會介紹如何使用BeanSerializer來序列化任何符合JavaBean規範的類。
遠程引用:遠程引用(Remote Reference)既不是SOAP規範的一部分,也不是JAX-RPC的一部分,所以不能返回對象的引用,然後期望調用者可以使用它作爲SOAP調用的參數或者其他調用的參數。此時應該使用其他的方案,例如將他們存儲在HashMap中,使用數字或者字符串鍵值來進行標識,這樣就可以傳遞鍵值。
9.編碼Beans---BeanSerializer
Axis具有序列化和反序列化的能力,不需要編寫代碼,任何Java類,主要它遵守標準JavaBean的模式,那麼就只需要告訴Axis Java類與XML Schema類型之間的映射,配置方式如下:
<beanMapping qname=”ns:local” xmlns:ns=”someNamespace”
                   languageSecificType=”java:my.java.thingy”/>
<beanMapping>標籤將一個Java類映射到一個XML QName。主要它包含兩個重要的屬性,qnamelanguageSpecificType。所以在上例中,將my.java.thingy類映射到XML QName:[someNamespace]:[local]
下面看一個例子:BeanService.java
package samples.userguide.example5;
 
public class BeanService
{
    public String processOrder(Order order)
    {
        String sep = System.getProperty("line.separator");
        String response = "Hi, " + order.getCustomerName() + "!" + sep;
        response += sep + "You seem to have ordered the following:" + sep;
        String [] items = order.getItemCodes();
        int [] quantities = order.getQuantities();
        for (int i = 0; i < items.length; i++) {
            response += sep + quantities[i] + " of item : " + items[i];
        }
        response += sep + sep +
                    "If this had been a real order processing system, "+
                    "we'd probably have charged you about now.";
        return response;
    }
}
上面的代碼中,Order類是一個JavaBean類。由於Order類不是一個基本類型,這樣Axis就不能識別它,所以一個錯誤的wsdd是下面這樣的:
<deployment xmlns="http://xml.apache.org/axis/wsdd/" xmlns:java="http://xml.apache.org/axis/wsdd/providers/java">
    <service name="OrderProcessor" provider="java:RPC">
        <parameter name="className" value="samples.userguide.example5.BeanService"/>
        <parameter name="allowedMethods" value="processOrder"/>
    </service>
</deployment>
而正確的wsdd文件應該爲下面的文件:
<deployment xmlns="http://xml.apache.org/axis/wsdd/" xmlns:java="http://xml.apache.org/axis/wsdd/providers/java">
    <service name="OrderProcessor" provider="java:RPC">
        <parameter name="className" value="samples.userguide.example5.BeanService"/>
        <parameter name="allowedMethods" value="processOrder"/>
        <beanMapping qname="myNS:Order" xmlns:myNS="urn:BeanService" languageSpecificType="java:samples.userguide.example5.Order"/>
    </service>
</deployment>
運行的結果如下:
此時在Client類中需要添加如下的代碼:
QName    qn      = new QName( "urn:BeanService", "Order" );
call.registerTypeMapping(Order.class, qn,new org.apache.axis.encoding.ser.BeanSerializerFactory(Order.class, qn), new org.apache.axis.encoding.ser.BeanDeserializerFactory(Order.class, qn));
Axis允許用戶編寫自定義的序列器和反序列器,並提供了實現序列器和反序列器的工具。現在只需要查看DataSer/DataDeser類、BeanSerializer/BeanDeserializerArraySerializer/ArrayDeserializer以及org.apache.axis.encoding.ser包中的其他類。
部署自定義的映射----<typeMapping>標籤
在建立了自定義的序列器和反序列器後,需要告訴Axis這些序列器的應用範圍,通過在WSDD中使用它:
<typeMapping qname="ns:local" xmlns:ns="someNamespace"
             languageSpecificType="java:my.java.thingy"
             serializer="my.java.Serializer"獲取序列器的序列器工廠類
             deserializer="my.java.DeserializerFactory" 、、
             encodingStyle="http://schemas.xmlsoap.org/soap/encoding/"/>
實際上<beanMapping><typeMapping>的一個簡化,其中serializer=”org.apache.axis.encoding.ser.BeanSerializerFactory”,deserializer=”org.apache.axis.encoding.ser.BeanDeserializerFactory”,encodingStyle=”http://schemas.xmlsoa.org/soap/encoding”
<arrayMapping qname="ns:ArrayOfthingy" xmlns:ns="someNamespaceURI"
             languageSpecificType="java:my.java.array.thingy[]"
                             innerType="ns2:thingy" xmlns:ns2="anotherNamespaceURI" 數組的元素類型
             encodingStyle="http://schemas.xmlsoap.org/soap/encoding/"/>
 logo
 
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章