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/"/>
  logo
 
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值