本部分是
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/"/>