级别: 中级 Russell Butek (butek@us.ibm.com), SOA 和 Web 服务顾问, IBM
2006 年 9 月 21 日 本文介绍如何使用 Web 服务互操作性组织 (Web Services Interoperability Organization) 定义的 XML 附件类型:wsi:swaRef。
引言
IBM developerWorks 发布了多篇介绍各种发送 Web 服务附件的方法的文章(相关链接请参阅参考资料)。本文介绍了另一种机制,即 Web 服务互操作性 (WS-I) 组织的带附件的 SOAP参考类型:wsi:swaRef。
为什么使用 wsi:swaRef?
因为没有针对附件的 XML 类型,因此 WS-I 创建了一个这样的 XML 类型。WSDL 规范包含一个附件定义,但是由于各种原因,该定义存在以下不足:
- 附件在接口中不可见
- 只有消息部分才能包含附件
- 附件与 document/literal 包装的内容不能很好地融合
附件在接口中不可见
附件是在 SOAP 中定义的,而 WSDL 规范将 SOAP 附件映射到 WSDL 绑定。这就意味着 WSDL 文档的接口 部分(portType、messages 和 types)并不能识别附件。
以清单 1 中所示的代码为例。其中的代码摘自“Web 服务编程技巧和诀窍: 使用 JAX-RPC 来传递 SOAP 附件
”一文(请参阅参考资料)。如果您暂时忽略绑定,而只看 WSDL 的接口,会在其中看到两个操作,即 sendImage 和 sendOctet。每个操作都有一个 hexBinary 输入。JAX-RPC 将 hexBinary 映射到一个 Java byte[]。仅通过该信息就可以合理地猜到,此 WSDL 接口将映射到一个包含两个方法的 Java 接口,其中每个方法都有一个 byte[] 参数。猜的没错,的确如此,但 MIME 类型例外。对于 MIME 类型,必须检查绑定,才能确定真实的参数类型。您将在绑定中看到操作的输入实际上是 MIME 内容类型——图像/jpeg 和应用程序/八进制流——而不是 hexBinary。JAX-RPC 会将其分别映射到 java.awt.Image 和 javax.activation.DataHandler。
对于附件,仅根据 WSDL 接口并不足以确定 Java 接口。这非常不方便。接口与实现之间的界线因此变得模糊了。
清单 1. 带附件的 WSDL——WS-I 的 wsi:swaRef 出现之前
<definitions
xmlns="http://schemas.xmlsoap.org/wsdl/"
xmlns:xsd="http://www.w3.org/2001/XMLSchema"
xmlns:soap="http://schemas.xmlsoap.org/wsdl/soap/"
xmlns:mime="http://schemas.xmlsoap.org/wsdl/mime/"
targetNamespace="urn:attachment.tip"
xmlns:tns="urn:attachment.tip">
<message name="empty"/>
<message name="imageMsg">
<part name="image" type="xsd:hexBinary"/>
</message>
<message name="octetMsg">
<part name="octet" type="xsd:hexBinary"/>
</message>
<portType name="AttachmentTip">
<operation name="sendImage">
<input message="tns:imageMsg"/>
<output message="tns:empty"/>
</operation>
<operation name="sendOctet">
<input message="tns:octetMsg"/>
<output message="tns:empty"/>
</operation>
</portType>
<binding name="AttachmentBinding" type="tns:AttachmentTip">
<soap:binding style="rpc"
transport="http://schemas.xmlsoap.org/soap/http"/>
<operation name="sendImage">
<soap:operation soapAction=""/>
<input>
<mime:multipartRelated>
<mime:part>
<soap:body use="literal"/>
</mime:part>
<mime:part>
<mime:content part="image" type="image/jpeg"/>
</mime:part>
</mime:multipartRelated>
</input>
<output>
<soap:body use="literal"/>
</output>
</operation>
<operation name="sendOctet">
<soap:operation soapAction=""/>
<input>
<mime:multipartRelated>
<mime:part>
<soap:body use="literal"/>
</mime:part>
<mime:part>
<mime:content part="octet" type="application/octet-stream"/>
</mime:part>
</mime:multipartRelated>
</input>
<output>
<soap:body use="literal"/>
</output>
</operation>
</binding>
<service name="AttachmentService">
<port name="AttachmentTip" binding="tns:AttachmentBinding">
<soap:address
location="http://localhost:9080/attachment/services/AttachmentTip"/>
</port>
</service>
</definitions> |
只有消息部分才能包含附件
请注意,在清单 1 中,绑定将一个 MIME 类型与一个消息部分进行了关联。这意味着所有附件必须是部分;例如,您不能将附件定义为 complexType 元素。这样的方法限制性很强,使附件的可用性降到了最低。
附件与 document/literal 包装模式
第三个问题是附件不符合行业当前对 WSDL 的 document/literal 包装模式的习惯用法。参考资料部分中的“我应该采用哪一种 WSDL 样式?”一文对此包装模式进行了介绍。有些人认为附件完全不适合 document/literal 包装模式。我并不这样认为,但是无论我怎样想,目前尚没有任何规范尝试过让附件适应 document/literal 包装模式。
问题在于,在 document/literal 包装模式中,一条消息中只有一个部分,而部分必须引用一个 wrapper 元素。附件部分如何适应这个模型呢?它并不能适应。只有放宽对消息中可包含内容的规定,它才能够 适应,但是目前没有任何人尝试过正式地放宽此规定。
WS-I 的解决方案
WS-I 通过创建 XML 附件类型解决了所有这些问题。wsi:swaRef 在 WSDL“接口”中可见。wsi:swaRef 的位置并不局限于消息部分中,也可以为 complexType 元素。作为 XML 类型,wsi:swaRef 能很好地适应 document/literal 包装模式(此模式要求参数是 complexType 元素)。清单 2 是清单 1 的修改版本,其中使用 wsi:swaRefs 代替了标准的附件。请注意,我们还将清单 2 的 WSDL 转换为 document/literal 包装的 WSDL 了。
清单 2. 使用 WS-I 的 wsi:swaRef 附件类型的 WSDL
<definitions
xmlns="http://schemas.xmlsoap.org/wsdl/"
xmlns:soap="http://schemas.xmlsoap.org/wsdl/soap/"
targetNamespace="urn:attachment.tip"
xmlns:tns="urn:attachment.tip">
<types>
<schema
targetNamespace="urn:attachment.tip"
xmlns:tns="urn:attachment.tip"
xmlns="http://www.w3.org/2001/XMLSchema"
xmlns:wsi="http://ws-i.org/profiles/basic/1.1/xsd">
<import
namespace="http://ws-i.org/profiles/basic/1.1/xsd"
schemaLocation="http://ws-i.org/profiles/basic/1.1/xsd"/>
<element name="sendImage">
<complexType>
<sequence>
<element name="image" type="wsi:swaRef"/>
</sequence>
</complexType>
</element>
<element name="sendImageResponse">
<complexType>
<sequence/>
</complexType>
</element>
<element name="sendOctet">
<complexType>
<sequence>
<element name="octet" type="wsi:swaRef"/>
</sequence>
</complexType>
</element>
<element name="sendOctetResponse">
<complexType>
<sequence/>
</complexType>
</element>
</schema>
</types>
<message name="imageMsg">
<part name="parameters" element="tns:sendImage"/>
</message>
<message name="imageResponseMsg">
<part name="return" element="tns:sendImageResponse"/>
</message>
<message name="octetMsg">
<part name="parameters" element="tns:sendOctet"/>
</message>
<message name="octetResponseMsg">
<part name="return" element="tns:sendOctetResponse"/>
</message>
<portType name="AttachmentTip">
<operation name="sendImage">
<input message="tns:imageMsg"/>
<output message="tns:imageResponseMsg"/>
</operation>
<operation name="sendOctet">
<input message="tns:octetMsg"/>
<output message="tns:octetResponseMsg"/>
</operation>
</portType>
<binding name="AttachmentBinding" type="tns:AttachmentTip">
<soap:binding style="document"
transport="http://schemas.xmlsoap.org/soap/http"/>
<operation name="sendImage">
<soap:operation soapAction=""/>
<input>
<soap:body use="literal"/>
</input>
<output>
<soap:body use="literal"/>
</output>
</operation>
<operation name="sendOctet">
<soap:operation soapAction=""/>
<input>
<soap:body use="literal"/>
</input>
<output>
<soap:body use="literal"/>
</output>
</operation>
</binding>
<service name="AttachmentService">
<port name="AttachmentTip" binding="tns:AttachmentBinding">
<soap:address
location="http://localhost:9080/attachment/services/AttachmentTip"/>
</port>
</service>
</definitions> |
从清单 2 可以看到,定义 wsi:swaRef 非常简单。其行为方式与其他基本 XML 类型相似。但在我看来,它过于简单了。与标准附件不同的是,并不知道附件的 MIME 类型。您只知道有一个附件。如果 WS-I 定义 wsi:swaRef 具有特定属性(例如,提供 MIME 类型的属性),将会更有用;但是 WS-I 并不负责定义规范,而只是对相关内容进行阐明,因此在并不定义任何新内容时,会尽可能使其保持最小。
wsi:swaRef 与 SOAP
清单 2 显示了 WSDL 定义中的 wsi:swaRef。清单 3 显示了一个 SOAP 请求消息示例。它是清单2 中定义的服务的sendImage 操作的消息。在突出显示的部分,可以看到 image 的 wsi:swaRef 参数如何与实际图像数据的内容 ID 相关联。尽管与标准的带附件的 SOAP 消息不完全相同,但概念是相似的。参考资料部分中的“技巧: 向 Web 服务传递文件”一文提供了一个带附件的 SOAP 消息示例。
清单 3. 带 wsi:swaRef 数据的 SOAP 消息
------=_Part_0_1245231543.1147796620031
Content-Type: text/xml; charset=UTF-8
Content-Transfer-Encoding: binary
Content-Id: <89884062647.1147796620016.IBM.WEBSERVICES@ISSW>
<soapenv:Envelope
xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/"
xmlns:soapenc="http://schemas.xmlsoap.org/soap/encoding/"
xmlns:xsd="http://www.w3.org/2001/XMLSchema"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
<soapenv:Header/>
<soapenv:Body>
<p985:sendImage xmlns:p985="urn:attachment.tip">
<image>cid:image=881207433652.1147796619984.IBM.WEBSERVICES@ISSW</image>
</p985:sendImage>
</soapenv:Body>
</soapenv:Envelope>
------=_Part_0_1245231543.1147796620031
Content-Type: image/jpeg
Content-Transfer-Encoding: binary
Content-Id: <image=881207433652.1147796619984.IBM.WEBSERVICES@ISSW>
... binary image data ...
|
wsi:swaRef 与 Java
您已经了解了 wsi:swaRef 的声明,而且还看到了 SOAP 消息中的 wsi:swaRef 实例。最后要考虑的是 wsi:swaRef 如何映射到编程语言。由于我是一个 Java 迷,因此将在此讨论 Java 映射。
JAX-RPC 1.1 版最终确定之后,WS-I才定义了 wsi:swaRef,因此 JAX-RPC 没有为我们提供映射。不过,它还是给了我们一点提示。它规定,未知的 MIME 类型将映射到 javax.activation.DataHandler。由于 wsi:swaRef 的确是一个未知的 MIME 类型,因此它也会映射到 javax.activation.DataHandler,这似乎是理所当然的。如果我们注意一下新动向,就会发现新的JAX-B 2.0 规范事实上已经采纳了这种映射方式。因此,完全可以假定任何支持 wsi:swaRef 的实现都会将其映射到 javax.activation.DataHandler。清单 4 显示了清单 2 中的 WSDL 的 Java 接口。
清单 4. wsi:swaRef 的 Java 映射
public interface AttachmentTip extends java.rmi.Remote {
public void sendImage(javax.activation.DataHandler image)
throws java.rmi.RemoteException;
public void sendOctet(javax.activation.DataHandler octet)
throws java.rmi.RemoteException;
} |
结束语
WSDL 的附件定义存在一些问题,因此 WS-I 组织创建了新的附件类型 wsi:swaRef。此类型将采用与标准的 WSDL 附件类似的方式映射到 SOAP 消息中;此类型还将作为未知 MIME 类型映射到 Java 中,即 javax.activation.DataHandler。
参考资料 学习
获得产品和技术
讨论
关于作者  | |  | Russell Butek 是 IBM 的一名 SOA 和 Web 服务顾问。他曾是 IBM WebSphere Web 服务引擎的开发人员之一。他也是 JAX-RPC Java Specification Request (JSR) 专家组的成员。他参与了 Apache 的 AXIS SOAP 引擎的实现,并推动 AXIS 1.0 遵守 JAX-RPC 1.0。 |
对本文的评价
|