Skip to main content

skip to main content

developerWorks  >  SOA and Web services | Information Management  >

Web services hints and tips: Design reusable WSDL faults

developerWorks
Document options
PDF format - Fits a4 and Letter

PDF - Fits a4 and Letter
35KB

Get Adobe® Reader®

Document options requiring JavaScript are not displayed

Discuss


Rate this page

Help us improve this content


Level: Intermediate

Russell Butek (butek@us.ibm.com), IT Specialist, IBM 

28 Feb 2008

We all agree that defining Web Services Description Language (WSDL) faults is good (if you disagree, then you're probably not reading this article). There are a number of ways to define WSDL faults, but only a limited subset provides for reuse. This article presents you with a template for reusable WSDL faults, shows you how the template is reusable, and identifies some things you should avoid.

Reusable fault definition template

Before jumping into details of what makes a fault reusable, take a look at an example of a reusable fault. Listing 1 shows the XML schema, and Listing 2 shows the WSDL.


Listing 1. Template schema for a reusable fault
                
<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>


Listing 2. Template WSDL for a reusable fault
                
<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>



Back to top


Levels of reuse

If you define your WSDL following this pattern, you have reusable faults. But reusability comes at a number of levels. You don't necessarily have to adhere to the full reusability shown here. Let's look at those levels.

Intra-WSDL reuse

Intra-WSDL reuse is a local level of reuse: reuse within the WSDL file. To achieve intra-WSDL reuse, avoid unnecessary associations; in particular, avoid putting operation names into fault names. This may sound like an obvious practice, but some tools create such fault names. For example, the message name might be generated as op1_faultMsg. Tools and graphical editors make life easier by doing a lot of the grunt work for you, but sometimes what they generate may not be precisely what you want. If your fault contains the operation name, when you create a new operation—for example, op2—and you want to reuse op1's fault, it looks rather odd in op2 to refer to op1_faultMsg. You can create another WSDL message named op2_faultMsg, which refers to the same schema element that op1_faultMsg refers to, but that's extra overhead that you don't need. If you disassociate the fault message name from the operation name, you can reuse that message without it looking strange (see Listing 3).


Listing 3. Add op2 to the 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>
  .
  .
  .

Inter-WSDL reuse

Inter-WSDL reuse is reuse between WSDLs where multiple WSDLs can use the same fault. There are two things to avoid here:

  • Obviously, don't define your fault in a WSDL's types section. Anything that you define directly within a WSDL types section is only visible to that WSDL. It's not reusable by other WSDLs.
  • The second is more obscure and requires you to think about mapping to programming languages. Take a look at your fault type. Because fault contains a single string field, you might prefer to go the simple route and put the string directly in the fault element rather than to go through t:Fault to get to the string. Some tools create this sort of fault (see Listing 4).

Listing 4. A fault that's too simple
                  .
  .
  .
  <xsd:schema ...>
  .
  .
  .
    <xsd:element name="fault" type="xsd:string"/>
  </xsd:schema>
  .
  .
  .
  <wsdl:message name="faultMsg">
    <wsdl:part name="fault" element="tns:fault"/>
  </wsdl:message>
  .
  .
  .

While you can reuse schema elements and schema types, consider the programming language that the WSDL will map to. Language mappings, such as Java™ API for XML-based RPC (JAX-RPC), map schema types in a straightforward manner to language constructs. But it's not always obvious how elements are mapped. In the case of JAX-RPC, a fault maps to an exception class. If the fault is defined with a type, the name and package of the exception is mapped from the fault's type name and namespace. If the fault is defined simply as an element, then the name of the exception is mapped from the message name, and the package is mapped from the message's namespace (see Listing 5). As such, the fault is only reusable within the message's enclosing namespace, not universally reusable. You can define another fault message that reuses your existing fault element, but JAX-RPC maps it to yet another exception; it doesn't reuse the existing exception.


Listing 5. Java signature from Listing 4's WSDL
                
public String op1(String input) throws RemoteException, WSDLTemplates.FaultMsg;

Object reuse

The final level of reuse is a bit more abstract. Defining a fault as you have, it's not simply a fault, it's also a data type. This is particularly useful when fault data might be necessary outside of a SOAP fault, for instance, if you're dealing with batch operations. In a simple operation, you have a set of inputs and a set of outputs. A batch version of this operation would contain an array of the set of inputs and an array of the set of outputs. If your nonbatch version of the operation can also throw a fault, then you should have a way to plug the fault data into the output array. When you define the fault like in this article, that's easy. Listing 6 and Listing 7 show a batch example. It builds on the XML Schema Definition (XSD) and WSDL from Listing 1 and Listing 2, adding a batch version of op1 called batchOp1 and its additional data types.


Listing 6. XSD for batch operation with faults
                
<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>


Listing 7. WSDL for batch operation with faults
                
<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 returns an array of Response. Response is an abstract type, so you have to fill the array with concrete extensions. The Response array elements may contain either NormalResponse objects or FaultResponse objects.

Real-world extension of this batch model
In a real-world example, you'd probably have multiple faults. To accommodate them, you can build a hierarchy of faults and then plug your base class of all faults into the FaultResponse type.

Summary

It's useful to make WSDL faults as extensible as possible. Hopefully you've learned how to do just that in this article.

Share this...

digg Digg this story
del.icio.us Post to del.icio.us
Slashdot Slashdot it!



Resources

Learn

Get products and technologies
  • Innovate your next development project with IBM trial software, available for download or on DVD.


Discuss


About the author

Russell Butek is an IBM SOA and Web services consultant. He has been one of the developers of the IBM WebSphere Web services engine. He has also been a member the JAX-RPC Java Specification Request (JSR) expert group. He was involved in the implementation of Apache's AXIS SOAP engine, driving AXIS 1.0 to comply with JAX-RPC.




Rate this page


Please take a moment to complete this form to help us better serve you.



YesNoDon't know
 


 


12345
Not
useful
Extremely
useful
 


Back to top


IBM and the IBM logo are registered trademarks of IBM in the United States, other countries or both. Java and all Java-based trademarks are trademarks of Sun Microsystems, Inc. in the United States, other countries, or both. Other company, product, or service names may be trademarks or service marks of others.