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");
}
}
MessageService的WSDD文件內容如下:
<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實現之間的一個存在的挑戰。如果期望服務在其他的平臺和實現上也可以使用,需要理解這個概念。Axis中Java類型到WSDL/XSD/SOAP的映射由JAX-RPC規範確定。相關內容請參考JAX-RPC規範。
WSDL到Java的標準映射
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,這樣的話,原始數據類型可以使用它們的包裝類代替,例如Byte、Double、Boolean。
SOAP編碼數據類型
和XSD數據類型相對應的是SOAP ‘Section 5’數據類型,這些數據類型都是nillable的,所以總是可以和包裝類映射。這些類型之所以存在是因爲他們都支持ID和HREF屬性,所以也用於當一個RPC編碼的context來支持multi-ref序列化。
7.異常
一般來說,Axis將java.rmi.RemoteException映射成爲SOAP Fault。這部分內容在筆者介紹的Axis2的文章中有比較詳細的介紹,請參考。
8.Axis可以/不可以通過SOAP發送的內容
Java的集合框架元素,例如Hashtable,具有序列器,但是和其它的SOAP實現沒有正式的交互操作能力,並且在SOAP規範中沒有對應的複雜對象。最可靠的發送集合對象的辦法就是使用數組。
沒有預先註冊的對象:不能發送任意的Java對象,並且期望它們可以被在服務器端被理解。在使用RMI的時候,可以發送和接受實現了Serializable接口的Java對象,那是由於雙發都是使用Java。Axis值可以發送那麼被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。主要它包含兩個重要的屬性,qname和languageSpecificType。所以在上例中,將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/BeanDeserializer、ArraySerializer/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/"/>
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.