IBM®
跳转到主要内容
    中国 [选择]    使用条款
 
 
Select a scope: Search for:    
    首页    产品    服务与解决方案     支持与下载    个性化服务    
跳转到主要内容

developerWorks 中国  >  SOA and Web services  >

Web 服务编程技巧与窍门: 使用 WS-I 的 wsi:swaRef XML 类型的附件

developerWorks
文档选项

未显示需要 JavaScript 的文档选项


级别: 中级

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 的接口,会在其中看到两个操作,即 sendImagesendOctet。每个操作都有一个 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。




对本文的评价










回页首


IBM 公司保留在 developerWorks 网站上发表的内容的著作权。未经IBM公司或原始作者的书面明确许可,请勿转载。如果您希望转载,请通过 提交转载请求表单 联系我们的编辑团队。
    关于 IBM 隐私条约 联系 IBM 使用条款