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