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>
|
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 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 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
faultcontains 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 throught:Faultto 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; |
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.
It's useful to make WSDL faults as extensible as possible. Hopefully you've learned how to do just that in this article.
Learn
- Read the
WSDL 1.1 specification.
- Get the specification, API classes, and Javadocs
for JAX-RPC 1.1.
- Learn more details about the
JAX-RPC mapping of
WSDL faults to Java exceptions.
- Check
out more Web services tips
on developerWorks.
- The
SOA and Web services zone
on IBM developerWorks hosts hundreds of informative articles and introductory,
intermediate, and advanced tutorials on how to develop Web services applications.
- Play in the
IBM SOA Sandbox!
Increase your SOA skills through practical, hands-on experience with the IBM SOA
entry points.
- The
IBM SOA Web site
offers an overview of SOA and how IBM can help you get there.
- Stay current with
developerWorks technical events and webcasts.
- Browse for books on these and other technical
topics at the
Safari bookstore.
- Check out a quick
Web services on demand demo.
Get products and technologies
- Innovate your next
development project with
IBM trial software,
available for download or on DVD.
Discuss
- Participate in the discussion forum.
- Get involved in the developerWorks community
by participating in
developerWorks blogs.
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.
Comments (Undergoing maintenance)





