Error-Proof Exception Handling
Learn how to properly code JAX-RPC–compliant Web services
by Shridhar Mysore
October 13, 2004
An important task in the Web services world is learning how to handle exceptions. Exception handling in JAX-RPC (Java API for XML-based RPC)–compliant Web services shouldn't be particularly tricky because the JAX-RPC spec governs such tasks. However, it is good to know some coding nuances for writing different types of clients (stubs-based vs. dynamic).
Although the market currently has a good number of implementers of the JAX-RPC spec, BEA WebLogic was one of the first to do so. Recently, exception handling in WebLogic Web services has undergone a facelift, mainly as the result of incorporating support for service-specific exception handling. Let's take a look at exception handling in BEA WebLogic Server Web services. To ensure that you are handling exceptions properly, we will cover relevant aspects of the spec, its implementation in BEA WebLogic Server, coding practices, and troubleshooting tips. First let's go over some nuts and bolts of exception handling.
Back to Basics
In Web services, an exception thrown by the Web service end point is passed on to the client as a SOAP fault. According to the JAX-RPC specification, a SOAP fault is mapped either to a javax.xml.rpc.soap.SOAPFaultException, a service-specific exception class, or a java.rmi.RemoteException.
Although some exceptions can be thrown from the server side:
java.lang.RuntimeException
java.rmi.RemoteException
javax.xml.rpc.soap.SOAPFaultException
(which extends java.lang.RuntimeException)
user-defined exceptions
(mapped to wsdl:fault in the WSDL).
on the client side, the following exceptions could be caught (including SOAPFaultException, but excluding java.lang.RuntimeException):
java.rmi.RemoteException
javax.xml.rpc.soap.SOAPFaultException
user-defined exceptions.
In Web Services Description Language (WSDL) the wsdl:fault element, which is an optional element in a wsdl:operation, specifies the abstract message format for any error messages that may be output as a result of a remote operation. According to the WSDL specification, a fault message must have a single part. A wsdl:fault is mapped to either a java.rmi.RemoteException (or its subclass), a service-specific Java exception, or a javax.xml.rpc.soap.SOAPFaultException.
Listing 1 shows an excerpt from a WSDL that defines a wsdl:fault. A wsdl:fault MyException is defined in the wsdl:operation sendSOAPFault, and the wsdl:fault message MyException is defined with a single part, which is mapped to a java:examples.webservices.basic.javaclass:MyException type.
A service-specific Java exception (mapped from a wsdl:fault and the corresponding wsdl:message) extends the class java.lang.Exception directly or indirectly. The single message part in the wsdl:message (referenced from the wsdl:fault element) may be either xsd:complexType or a simple XML type.
Now let's discuss the handling of SOAPFaultException and service-specific exceptions.
Handling SOAPFaultException
The SOAPFaultException represents a SOAP fault. This exception is thrown from the Java method mapped from the corresponding wsdl:operation.
The message part in the SOAP fault maps to the contents of the detail element that is accessible through the getDetail method on the SOAPFaultException. The method createDetail on the javax.xml.soap.SOAPFactory creates an instance of the javax.xml.soap.Detail. The faultstring provides a human-readable description of the SOAP fault. The faultcode element provides an algorithmic mapping of the SOAP fault.
The following is the structure of SOAPFaultException class:
package javax.xml.rpc.soap;
public class SOAPFaultException extends java.lang.RuntimeException {
public SOAPFaultException(QName faultcode,
String faultstring,
String faultactor,
javax.xml.soap.Detail detail) { ... }
public QName getFaultCode() { ... }
public String getFaultString() { ... }
public String getFaultActor() { ... }
public javax.xml.soap.Detail getDetail() { ... }
}
Let's take a look at a couple of examples. As an example of service implementation, Listing 2 shows the server-side implementation of a Web service where a method sendSOAPFault() throws a SOAPFaultException. As an example of client implementation, Listing 3 shows a Web service client invoking the sendSOAPFault() operation. This is a stubs-based client which catches the SOAPFaultException thrown from sendSOAPFault() operation.
In the WebLogic Server Web service client stub, since the fault (caused by the server throwing SOAPFaultException) is mapped to java.rmi.RemoteException, Client.java, which is a stubs-based client, would need to catch java.rmi.RemoteException. However when using the Dynamic Invocation Interface (DII) client, which uses the javax.xml.rpc.Call interface, you would need to catch SOAPFaultException.
For an example of a SOAP request/response message when invoking sendSOAPFault(), check out Listing 4 online.
Handling Service-Specific Exceptions
A service-specific Java exception (mapped from a wsdl:fault and the corresponding wsdl:message) extends the class java.lang.Exception directly or indirectly. The single message part in the wsdl:message (referenced from the wsdl:fault element) may be either xsd:complexType or a simple XML type.
Listing 5 shows mapping of a wsdl:fault to a service-specific Java exception. The wsdl:message has a single part of type MyException which is a complexType.
Note that in WLS 7.0.x and WLS 8.1, the handling of service-specific exceptions was not supported. Hence generating Web services in WLS 7.0.x and WLS 8.1 from a WSDL that defines a wsdl:fault of complexType, results in the following:
- the method(s) in the generated service do not throw the associated exception.
- upon throwing the exception from the server side, the SOAP message on the wire will refer to this exception as having a primitive type instead of being the MyException type.
- generating the client stubs/proxies via clientgen doesn't generate the proper implementation of the exception.
Conversely, similar issues are encountered when generating a Web service from a Java application that throws user-defined or service-specific exceptions.
In WLS 8.1 SP1 and higher, this support was added by implementing sections 5.5.5 and 4.3.6 of the JAX-RPC specification. In WLS 7.0.x and WLS 8.1, you would need to throw a SOAPFaultException instead of a service-specific exception on the server side as a workaround.
For the purpose of capturing the true semantics of an exception, it is a good programming/design practice to define checked, user-defined exceptions as part of the service end point interface (SEI). In the model where the Web service is being generated from a source (like a Java class or Enterprise JavaBean [EJB]), a user-defined exception would be mapped to the wsdl:fault inside wsdl:operation in the WSDL. Conversely in the model where the Web service is being generated from the WSDL, the appropriate wsdl:faults should be defined based on the types of exceptions that are expected to be thrown.
Listing 6 is an example that illustrates the handling of a service-specific exception. This listing has the server-side implementation of a Web service where a method sendSOAPFault() throws MyException, which is a service-specific exception.
Listings 7 and 8 contain implementations of Web service clients invoking the sendSOAPFault() operation. Listing 7 provides implementation for stubs-based clients and Listing 8 provides implementation for Dynamic Invocation Interface (DII) or dynamic Web service clients that catch the SOAPFaultException thrown from the sendSOAPFault() operation.
In the WebLogic Server Web service client stub, since the fault (caused by the server throwing the service-specific exception) is mapped to a service-specific exception, Client.java, which is a stubs-based client, would need to catch the service-specific exception. However the DII client, which uses the javax.xml.rpc.Call interface, would need to catch either RemoteException or SOAPFaultException. The service-specific exception would be wrapped inside the SOAPFaultException.
For an example of a SOAP request/response message when invoking sendSOAPFault() from a stubs-based client, check out Listing 9 online, and when doing so from a dynamic client, see Listing 10 online.
It is good coding practice to implement the use of service-specific exceptions. If you run into trouble, check out the sidebar "Troubleshooting Tips for Exception Handling." You should soon be handling exceptions like a pro.
About the Author
Shridhar Mysore is a senior engineer at BEA Systems. He has worked in various J2EE and service-oriented technologies in design, implementation, and support roles. Contact him at smysore@bea.com.
|