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

developerWorks 中国  >  SOA and Web services  >

Web Services 提示与技巧: 设计可重用的 WSDL 错误定义

developerWorks
文档选项

Get Adobe® Reader®

未显示需要 JavaScript 的文档选项

讨论

英文原文

英文原文


级别: 中级

Russell Butek (butek@us.ibm.com), SOA 和 Web 服务顾问, IBM 

2008 年 3 月 27 日

我们都赞同定义 Web 服务描述语言 (WSDL) 错误定义是较好的做法(如果您不同意,则不需要阅读本文)。存在许多定义 WSDL 错误的方法,但是只有有限的内容提到了重用。本文向您介绍可重用的 WSDL 错误定义模板、展示如何重用该模板,同时指出了一些应该注意的事项。

可重用的错误定义模板

在详细介绍如何重用错误定义之前,让我们先看一个可重用错误定义的示例。清单 1 显示了 XML 模式,清单 2 显示了 WSDL。


清单 1. 用于可重用错误定义的模板模式
                
<xsd:schema 
    targetNamespace="urn:SchemaTemplates"
    xmlns:xsd="http://www.w3.org/2001/XMLSchema">
  <xsd:complexType name="Fault">
                    <xsd:sequence>
                      <xsd:element minOccurs="0" name="reason" type="xsd:string"/>
                    </xsd:sequence>
                  </xsd:complexType>
</xsd:schema>


清单 2. 可重用错误定义的模板 WSDL
                
<wsdl:definitions 
    targetNamespace="urn:WSDLTemplates"
    xmlns:tns="urn:WSDLTemplates"
    xmlns:wsdl="http://schemas.xmlsoap.org/wsdl/"
    xmlns:soap="http://schemas.xmlsoap.org/wsdl/soap/">
  <wsdl:types>
    <xsd:schema 
        targetNamespace="urn:WSDLTemplates" 
        xmlns:tns="urn:WSDLTemplates"
        xmlns:t="urn:SchemaTemplates"
        xmlns:xsd="http://www.w3.org/2001/XMLSchema">
      <xsd:import namespace="urn:SchemaTemplates" schemaLocation="Fault.xsd"/>
      <xsd:element name="op1" type="tns:op1"/>
      <xsd:complexType name="op1">
        <xsd:sequence>
          <xsd:element name="input" type="xsd:string"/>
        </xsd:sequence>
      </xsd:complexType>
      <xsd:element name="op1Response" type="tns:op1Response"/>
      <xsd:complexType name="op1Response">
        <xsd:sequence>
          <xsd:element name="output" type="xsd:string"/>
        </xsd:sequence>
      </xsd:complexType>
      <xsd:element name="fault" type="t:Fault"/>
    </xsd:schema>
  </wsdl:types>
  <wsdl:message name="op1RequestMsg">
    <wsdl:part name="op1Parameters" element="tns:op1"/>
  </wsdl:message>
  <wsdl:message name="op1ResponseMsg">
    <wsdl:part name="op1Result" element="tns:op1Response"/>
  </wsdl:message>
  <wsdl:message name="faultMsg">
                    <wsdl:part name="fault" element="tns:fault"/>
                  </wsdl:message>
  <wsdl:portType name="Interface">
    <wsdl:operation name="op1">
      <wsdl:input name="op1Request" message="tns:op1RequestMsg"/>
      <wsdl:output name="op1Response" message="tns:op1ResponseMsg"/>
      <wsdl:fault name="fault" message="tns:faultMsg"/>
    </wsdl:operation>
  </wsdl:portType>
  <wsdl:binding name="Binding" type="tns:Interface">
    <soap:binding 
        style="document" 
        transport="http://schemas.xmlsoap.org/soap/http"/>
    <wsdl:operation name="op1">
      <soap:operation soapAction=""/>
      <wsdl:input name="op1Request">
        <soap:body use="literal"/>
      </wsdl:input>
      <wsdl:output name="op1Response">
        <soap:body use="literal"/>
      </wsdl:output>
      <wsdl:fault name="fault">
                        <soap:fault use="literal" name="fault"/>
                      </wsdl:fault>
    </wsdl:operation>
  </wsdl:binding>
  <wsdl:service name="Service">
    <wsdl:port name="Port" binding="tns:Binding">
      <soap:address location="http://www.example.org/"/>
    </wsdl:port>
  </wsdl:service>
</wsdl:definitions>





回页首


重用级别

如果您定义的 WSDL 符合此模式,则可以获得可重用的错误定义。但是可重用性具有许多级别。您没有必要遵守此处介绍的全部可重用性。让我们看一下这些级别。

WSDL 内重用(Intra-WSDL)

WSDL 内重用 是本地级别的重用:即 WSDL 文件中的重用。要实现 WSDL 内重用,请避免不必要的关联;特别是,避免将操作名称放入错误名称中。这听起来非常容易,但是一些工具可创建此类错误名称。例如,可能将消息名称生成为 op1_faultMsg。使用工具和图形编辑器可以非常容易地完成许多繁锁的工作,但是它们生成的内容有时可能不是您需要的。如果错误定义包含操作名称,那么在创建新的操作(例如 op2),并需要重用 op1 的错误时,在 op2 中引用 op1_faultMsg 看起来就有些奇怪了。您可以创建名为 op2_faultMsg 的另一个 WSDL 消息,它可引用 op1_faultMsg 引用的同一模式元素,但这是不必要的额外开销。如果将错误的消息名称与操作名称分离,则可以重用该消息,并且看起来也不感到陌生(请参见清单 3)。


清单 3. 将 op2 添加到 WSDL
                
  .
  .
  .
    <wsdl:operation name="op2">
      <wsdl:input name="op2Request" message="tns:op2RequestMsg"/>
      <wsdl:output name="op2Response" message="tns:op2ResponseMsg"/>
      <wsdl:fault name="fault" message="tns:faultMsg"/>
    </wsdl:operation>
  .
  .
  .

WSDL 间重用

WSDL 间重用 是 WSDL 之间的重用,其中多个 WSDL 可以使用同一错误定义。这里需要避免两种情况:

  • 显然,在 WSDL 的类型部分中不能定义您的错误定义。在 WSDL 类型部分中直接定义的任何内容仅对该 WSDL 可视。其他 WSDL 不可重用这些内容。
  • 第二种情况比较难,需要考虑到编程语言的映射。请看一下错误类型。因为 fault 包含单一字符串字段,您可能更愿意采用简单的路由,并将字符串直接放入错误元素中,而不是通过 t:Fault 获得该字符串。某些工具可创建此类错误(请参见清单 4)。

清单 4. 简单的错误定义
                  .
  .
  .
  <xsd:schema ...>
  .
  .
  .
    <xsd:element name="fault" type="xsd:string"/>
  </xsd:schema>
  .
  .
  .
  <wsdl:message name="faultMsg">
    <wsdl:part name="fault" element="tns:fault"/>
  </wsdl:message>
  .
  .
  .

当重用模式元素和模式类型时,请考虑 WSDL 要映射的编程语言。语言映射(如 Java™ API for XML-based RPC (JAX-RPC))以直接的方式将模式类型映射到语言构造。但是如何映射元素并不总是显而易见的。对于 JAX-RPC,错误定义可映射为一个异常类。如果使用类型定义错误,则从该错误的类型名称和命名空间映射该异常的名称和包。如果仅将错误定义为一个元素,则从消息名称映射异常的名称,从消息的命名空间映射数据包(请参见清单 5)。因此,错误定义仅在消息的封闭命名空间中可重用,没有普遍的可重用性。您可以定义重用现有错误元素的另一个错误消息,但是 JAX-RPC 仍将其映射为另一个异常;它不重用现有异常。


清单 5. 清单 4 中 WSDL 的 Java 签名
                
public String op1(String input) throws RemoteException, WSDLTemplates.FaultMsg;

对象重用

重用的最后一个级别更抽象一些。按以往方法定义一个错误,它不仅是一种错误,而且是一种数据类型。当错误数据必须位于 SOAP 错误的外部时,这特别有用,。例如,如果您在处理批操作时。在简单的操作中,您将有一组输入和一组输出。此操作的批量版本将包含输入集的数组和输出集的数组。如果操作的非批量版本也可以抛出错误,则应通过一种方法将错误数据插入输出数组。在定义与本文中类似的错误时,此操作非常容易。清单 6清单 7 显示了一个批量示例。它从清单 1清单 2 中 XML Schema Definition (XSD) 和 WSDL 的基础上构建,并添加一个称为 batchOp1 的 op1 批量版本以及它的其他数据类型。


清单 6. 用于批量操作错误的 XSD
                
<xsd:schema 
    targetNamespace="urn:SchemaTemplates"
    xmlns:tns="urn:SchemaTemplates"
    xmlns:xsd="http://www.w3.org/2001/XMLSchema">
  <xsd:complexType name="Fault">
    <xsd:sequence>
      <xsd:element minOccurs="0" name="reason" type="xsd:string"/>
    </xsd:sequence>
  </xsd:complexType>
<xsd:complexType name="Response" abstract="true"/>
                <xsd:complexType name="NormalResponse">
                 <xsd:complexContent>
                  <xsd:extension base="tns:Response">
                   <xsd:sequence>
                    <xsd:element name="response" type="xsd:string"/>
                   </xsd:sequence>
                  </xsd:extension>
                 </xsd:complexContent>
                </xsd:complexType>
                <xsd:complexType name="FaultResponse">
                 <xsd:complexContent>
                  <xsd:extension base="tns:Response">
                   <xsd:sequence>
                    <xsd:element name="fault" type="tns:Fault"/>
                   </xsd:sequence>
                  </xsd:extension>
                 </xsd:complexContent>
                </xsd:complexType>
</xsd:schema>


清单 7. 用于批量操作错误的 WSDL
                
<wsdl:definitions 
    targetNamespace="urn:WSDLTemplates"
    xmlns:tns="urn:WSDLTemplates"
    xmlns:wsdl="http://schemas.xmlsoap.org/wsdl/"
    xmlns:soap="http://schemas.xmlsoap.org/wsdl/soap/">
  <wsdl:types>
    <xsd:schema 
        targetNamespace="urn:WSDLTemplates" 
        xmlns:tns="urn:WSDLTemplates"
        xmlns:t="urn:SchemaTemplates"
        xmlns:xsd="http://www.w3.org/2001/XMLSchema">
      <xsd:import namespace="urn:SchemaTemplates" schemaLocation="Fault.xsd"/>
      <xsd:element name="op1" type="tns:op1"/>
      <xsd:complexType name="op1">
        <xsd:sequence>
          <xsd:element name="input" type="xsd:string"/>
        </xsd:sequence>
      </xsd:complexType>
      <xsd:element name="op1Response" type="tns:op1Response"/>
      <xsd:complexType name="op1Response">
        <xsd:sequence>
          <xsd:element name="output" type="xsd:string"/>
        </xsd:sequence>
      </xsd:complexType>
      <xsd:element name="batchOp1" type="tns:batchOp1"/>
                <xsd:complexType name="batchOp1">
                  <xsd:sequence>
                    <xsd:element name="input" type="xsd:string" 
                  maxOccurs="unbounded"/>
                  </xsd:sequence>
                </xsd:complexType>
                <xsd:element name="batchOp1Response" 
               type="tns:batchOp1Response"/>
                <xsd:complexType name="batchOp1Response">
                  <xsd:sequence>
                    <xsd:element name="output" type="t:Response" 
                   maxOccurs="unbounded"/>
                  </xsd:sequence>
                </xsd:complexType>
      <xsd:element name="fault" type="t:Fault"/>
    </xsd:schema>
  </wsdl:types>
  <wsdl:message name="op1RequestMsg">
    <wsdl:part name="op1Parameters" element="tns:op1"/>
  </wsdl:message>
  <wsdl:message name="op1ResponseMsg">
    <wsdl:part name="op1Result" element="tns:op1Response"/>
  </wsdl:message>
  <wsdl:message name="faultMsg">
    <wsdl:part name="fault" element="tns:fault"/>
  </wsdl:message>
  <wsdl:message name="batchOp1RequestMsg">
                    <wsdl:part name="batchOp1Parameters" 
                   element="tns:batchOp1"/>
                  </wsdl:message>
                  <wsdl:message name="batchOp1ResponseMsg">
                    <wsdl:part name="batchOp1Result" 
                   element="tns:batchOp1Response"/>
                  </wsdl:message>
  <wsdl:portType name="Interface">
    <wsdl:operation name="op1">
      <wsdl:input name="op1Request" message="tns:op1RequestMsg"/>
      <wsdl:output name="op1Response" message="tns:op1ResponseMsg"/>
      <wsdl:fault name="fault" message="tns:faultMsg"/>
    </wsdl:operation>
    <wsdl:operation name="batchOp1">
                      <wsdl:input name="batchOp1Request" 
                     message="tns:batchOp1RequestMsg"/>
                      <wsdl:output name="batchOp1Response" 
                     message="tns:batchOp1ResponseMsg"/>
                    </wsdl:operation>
  </wsdl:portType>
  <wsdl:binding name="Binding" type="tns:Interface">
    <soap:binding 
        style="document" 
        transport="http://schemas.xmlsoap.org/soap/http"/>
    <wsdl:operation name="op1">
      <soap:operation soapAction=""/>
      <wsdl:input name="op1Request">
        <soap:body use="literal"/>
      </wsdl:input>
      <wsdl:output name="op1Response">
        <soap:body use="literal"/>
      </wsdl:output>
      <wsdl:fault name="fault">
        <soap:fault use="literal" name="fault"/>
      </wsdl:fault>
    </wsdl:operation>
    <wsdl:operation name="batchOp1">
                      <soap:operation soapAction=""/>
                      <wsdl:input name="batchOp1Request">
                        <soap:body use="literal"/>
                      </wsdl:input>
                      <wsdl:output name="batchOp1Response">
                        <soap:body use="literal"/>
                      </wsdl:output>
                    </wsdl:operation>
  </wsdl:binding>
  <wsdl:service name="Service">
    <wsdl:port name="Port" binding="tns:Binding">
      <soap:address location="http://www.example.org/"/>
    </wsdl:port>
  </wsdl:service>
</wsdl:definitions>

batchOp1 返回 Response 的数组。Response 是一种抽象类型,因此,您必须使用具体的扩展填充该数组。Response 数组元素可以包含 NormalResponse 对象或 FaultResponse 对象。

批量模型的实际扩展
在实际示例中,您可能有多个错误。要容纳这些错误,可以为错误构建层次结构,然后将所有错误的基类插入 FaultResponse 类型。

总结

尽可能扩展 WSDL 错误定义非常有用。希望您已了解了本文中介绍的操作方式。



参考资料

学习

获得产品和技术
  • 使用 IBM 试用软件开发您的下一个项目,可下载或索取 DVD 光盘。


讨论


关于作者

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 和 IBM 徽标是 IBM 在美国和/或其他国家/地区的注册商标。 Java 和所有基于 Java 的商标都是 Sun Microsystems, Inc. 在美国和/或其他国家/地区的商标。 其他公司、产品或服务的名称可能是其他公司的商标或服务标志。

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