 | 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> |
 |
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.
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
|  |