Oracle® Fusion Middleware Programming Advanced Features of JAX-WS Web Services for Oracle WebLogic Server 11g Release 1 (10.3.6) Part Number E13734-05 |
|
|
PDF · Mobi · ePub |
This chapter describes how to handle exceptions that occur when a message is being processed using Simple Object Access Protocol (SOAP) faults for WebLogic Web services using Java API for XML Web Services (JAX-WS).
This chapter includes the following sections:
When a Web service request is being processed, if an error is encountered, the nature of the error needs to be communicated to the client, or sender of the request. Because clients can be written on a variety of platforms using different languages, there must exist a standard, platform-independent mechanism for communicating the error.
The SOAP specification (available at http://www.w3.org/TR/soap/
) defines a standard, platform-independent way of describing the error within the SOAP message using a SOAP fault. In general, a SOAP fault is analogous to an application exception. SOAP faults are generated by receivers to report business logic errors or unexpected conditions.
In JAX-WS, Java exceptions (java.lang.Exception
) that are thrown by your Java Web service are mapped to a SOAP fault and returned to the client to communicate the reason for failure. SOAP faults can be one of the following types:
Modeled—Maps to an exception that is thrown explicitly from the business logic of the Java code and mapped to wsdl:fault
definitions in the WSDL file, when the Web service is deployed. In this case, the SOAP faults are predefined.
Unmodeled—Maps to an exception (for example, java.lang.RuntimeException
) that is generated at run-time when no business logic fault is defined in the WSDL. In this case, Java exceptions are represented as generic SOAP fault exceptions, javax.xml.ws.soap.SOAPFaultException
.
The faults are returned to the sender only if request/response messaging is in use. If a Web service operation is configured as one-way, the SOAP fault is not returned to the sender, but stored for further processing.
As illustrated in Figure 16-1, JAX-WS handles SOAP fault processing during SOAP protocol binding. The SOAP binding maps exceptions to SOAP fault messages.
Figure 16-1 How SOAP Faults Are Processed
The SOAP <Fault>
element is used to transmit error and status information within a SOAP message. The <Fault>
element is a child of the body element. There can be only one <Fault>
element in the body of a SOAP message.
The SOAP <Fault>
element contents for SOAP 1.2 and 1.1 are defined in the following sections:
The <Fault>
element for SOAP 1.2 contains the subelements defined in Table 16-1.
Table 16-1 Subelements of the SOAP 1.2 <Fault> Element
Subelement | Description | Required? |
---|---|---|
|
Information pertaining to the fault error code. The
The subelements are defined below. |
Required |
|
Code value that provides more information about the fault. A set of code values is predefined by the SOAP specification, including:
|
Required |
|
Subcode value that provides more information about the fault. This subelement can have a recursive structure. |
Optional |
|
Human-readable description of fault. The |
Required |
|
Information regarding the actor (SOAP node) that caused the fault. |
Optional |
|
Role being performed by actor at the time of the fault. |
Optional |
|
Application-specific information, such as the exception that was thrown. |
Optional |
The following provides an example of a SOAP 1.2 fault message.
Example 16-1 Example of SOAP 1.2 Fault Message
<?xml version="1.0"?> <env:Envelope xmlns:env=http://www.w3.org/2003/05/soap-envelope> <env:Body> <env:Fault> <env:Code> <env:Value>env:Sender</env:Value> <env:Subcode> <env:Value>rpc:BadArguments</env:Value> </env:Subcode> </env:Code> <env:Reason> <env:Text xml:lang=en-US>Processing error<env:Text> </env:Reason> <env:Detail> <e:myFaultDetails xmlns:e=http://travelcompany.example.org/faults> <e:message>Name does not match card number</e:message> <e:errorcode>999</e:errorcode> </e:myFaultDetails> </env:Detail> </env:Fault> </env:Body> </env:Envelope>
The <Fault>
element for SOAP 1.1 contains the subelements defined in Table 16-2.
Table 16-2 Subelements of the SOAP 1.1 <Fault> Element
Subelement | Description |
---|---|
|
Standard code that provides more information about the fault. A set of code values is predefined by the SOAP specification, as defined below. This set of fault code values can be extended by the application. Predefined fault code values include:
|
|
Human-readable description of fault. |
|
URI associated with the actor (SOAP node) that caused the fault. In RPC-style messaging, the actor is the URI of the Web service. |
|
Application-specific information, such as the exception that was thrown. This element can be an XML structure or plain text. |
The following provides an example of a SOAP 1.1 fault message.
Example 16-2 Example of SOAP 1.1 Fault Message
<?xml version="1.0"?> <soap:Envelope xmlns:soap='http://schemas.xmlsoap.org/soap/envelope'> <soap:Body> <soap:Fault> <faultcode>soap:VersionMismatch</faultcode> <faultstring, xml:lang='en"> Message was not SOAP 1.1 compliant </faultstring> <faultactor> http://sample.org.ocm/jws/authnticator </faultactor> </soap:Fault> </soap:Body> </soap:Envelope>
As described previously, a modeled fault is mapped to an exception that is thrown explicitly from the business logic of the Java code. In this case, the exception is mapped to a wsdl:fault
definitions in the WSDL file, when the Web service is deployed.
The following sections provide more information about using modeled faults:
To use modeled faults, you need to create a custom Java exception and throw it from within your Web service.
Example 16-3 provides a simple example of a custom exception being thrown by a a Web service. The exception is called MissingName
and is thrown when the input argument is empty.
Example 16-3 Web Service With Custom Exception
package examples; import javax.jws.WebService; @WebService(name="HelloWorld", serviceName="HelloWorldService") public class HelloWorld { public String sayHelloWorld(String message) throws MissingName { System.out.println("Say Hello World: " + message); if (message == null || message.isEmpty()) { throw new MissingName(); } return "Here is the message: '" + message + "'"; } }
Example 16-4 shows the he class for the exception, MissingName.java
.
The JAX-WS Java-to-WSDL mapping binds subclasses of java.lang.Exception
to wsdl:fault
messages. Example 16-4 shows the WSDL that is generated from the annotated Web service in Example 16-3.*
n this example:
The <message name="MissingName">
element defines the parts of the MissingName
message, namely fault
, and its associated data type, tns:MissingName
.
<message name="MissingName"> <part name="fault" element="tns:MissingName" /> </message>
The MissingName
SOAP fault is mapped to the sayHelloWorld
operation.
<operation name="sayHelloWorld"> <input message="tns:sayHelloWorld" /> <output message="tns:sayHelloWorldResponse" /> <fault message="tns:MissingName" name="MissingName" /> </operation>
This <fault>
subelement in this example is derived from the throws MissingName
clause of the sayHelloWorld()
method declaration (see Example 16-3).
public String sayHelloWorld(String message) throws MissingName { ... }
The fault message is mapped to the sayHelloWorld
operation in the <binding>
element, as well.
<fault name="MissingName"> <soap:fault name="MissingName" use="literal" /> </fault>
Example 16-5 Example of WSDL with Modeled Exceptions
<?xml version="1.0" encoding="UTF-8" ?> <definitions xmlns:soap="http://schemas.xmlsoap.org/wsdl/soap/" xmlns:tns="http://examples/" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns="http://schemas.xmlsoap.org/wsdl/" targetNamespace="http://examples/" name="HelloWorldService"> <types> <xsd:schema> <xsd:import namespace="http://examples/" schemaLocation="http://localhost:7001/HelloWorld/HelloWorldService?xsd=1"/> </xsd:schema> </types> <message name="sayHelloWorld"> <part name="parameters" element="tns:sayHelloWorld" /> </message> <message name="sayHelloWorldResponse"> <part name="parameters" element="tns:sayHelloWorldResponse" /> </message> <message name="MissingName"> <part name="fault" element="tns:MissingName" /> </message> <portType name="HelloWorld"> <operation name="sayHelloWorld"> <input message="tns:sayHelloWorld" /> <output message="tns:sayHelloWorldResponse" /> <fault message="tns:MissingName" name="MissingName" /> </operation> </portType> <binding name="HelloWorldPortBinding" type="tns:HelloWorld"> <soap:binding transport="http://schemas.xmlsoap.org/soap/http" style="document" /> <operation name="sayHelloWorld"> <soap:operation soapAction="" /> <input> <soap:body use="literal" /> </input> <output> <soap:body use="literal" /> </output> <fault name="MissingName"> <soap:fault name="MissingName" use="literal" /> </fault> </operation> </binding> <service name="HelloWorldService"> <port name="HelloWorldPort" binding="tns:HelloWorldPortBinding"> <soap:address location="http://localhost:7001/HelloWorld/HelloWorldService" /> </port> </service>
Example 16-6 shows how the SOAP fault is communicated in the resulting SOAP message when the MissingName
Java exception is thrown.
Example 16-6 Example SOAP Fault Message for MissingName Exception
<?xml version = '1.0' encoding = 'UTF-8'?> <S:Envelope xmlns:S="http://schemas.xmlsoap.org/soap/envelope/"> <S:Body> <S:Fault xmlns:ns4="http://www.w3.org/2003/05/soap-envelope"> <faultcode>S:Server</faultcode> <faultstring>Your name is required.</faultstring> <detail> <ns2:MissingName xmlns:ns2="http://examples/"> <message>Your name is required.</message> </ns2:MissingName> <ns2:exception xmlns:ns2="http://jax-ws.dev.java.net/" class="examples.MissingName" note="To disable this feature, set com.sun.xml.ws.fault.SOAPFaultBuilder.disableCaptureStackTrace system property to false"> <message>Your name is required.</message> <ns2:stackTrace> <ns2:frame class="examples.HelloWorld" file="HelloWorld.java" line="14" method="sayHelloWorld"/> ... </ns2:stackTrace> </ns2:exception> </detail> </S:Fault> </S:Body> </S:Envelope>
When you generate a Web service client from a WSDL file that contains mapped faults using clientgen
, the required exception classes are generated automatically, including the mapped exception, fault bean, service implementation classes client implementation class, which you must modify, as described in the following sections.
For more information about clientgen, see "clientgen" in WebLogic Web Services Reference for Oracle WebLogic Server.
An example of the generated Java exception class is shown in Example 16-7. The @WebFault
annotation identifies the class as a mapped exception.
Example 16-7 Example of Generated Java Exception Class
package examples.client; import javax.xml.ws.WebFault; @WebFault(name = "MissingName", targetNamespace = "http://examples/") public class MissingName_Exception extends Exception { private MissingName faultInfo; public MissingName_Exception(String message, MissingName faultInfo) { ... } public MissingName_Exception(String message, MissingName faultInfo, Throwable cause) { ... } public MissingName getFaultInfo() { ... } }
An example of the generated Java fault bean class is shown in Example 16-8, defining the getters and setters for the fault message.
Example 16-8 Example of Generated Java Fault Bean Class
package examples.client; import javax.xml.bind.annotation.XmlAccessType; import javax.xml.bind.annotation.XmlAccessorType; import javax.xml.bind.annotation.XmlType; @XmlAccessorType(XmlAccessType.FIELD) @XmlType(name = "MissingName", propOrder = { "message" }) public class MissingName { protected String message; public String getMessage() { return message; } public void setMessage(String value) { this.message = value; } }
An example of the generated client-side service implementation class is shown in Example 16-9.
Example 16-9 Client-side Service Implementation
package examples.client; ... @WebService(name = "HelloWorld", targetNamespace = "http://examples/") @XmlSeeAlso({ ObjectFactory.class }) public interface HelloWorld { @WebMethod @WebResult(targetNamespace = "") @RequestWrapper(localName = "sayHelloWorld", targetNamespace = "http://examples/", className = "examples.client.SayHelloWorld") @ResponseWrapper(localName = "sayHelloWorldResponse", targetNamespace = "http://examples/", className = "examples.client.SayHelloWorldResponse") public String sayHelloWorld( @WebParam(name = "arg0", targetNamespace = "") String arg0) throws MissingName_Exception; }
Create the client implementation class to call the Web service method and throw the custom exception. Then, compile and run the client. For more information about creating Web service clients, see "Invoking Web Services" in Getting Started With JAX-WS Web Services for Oracle WebLogic Server.
Example 16-10 shows an example client implementation class.
Example 16-10 Client Implementation Class
package examples.client; import javax.xml.namespace.QName; import java.net.MalformedURLException; import java.net.URL; import examples.client.MissingName_Exception; public class Main { public static void main(String[] args) throws MissingName_Exception { HelloWorldService service; try { service = new HelloWorldService(new URL(args[0] + "?WSDL"), new QName("http://examples/", "HelloWorldService") ); } catch (MalformedURLException murl) { throw new RuntimeException(murl); } HelloWorld port = service.getHelloWorldPort(); String result = null; try { result = port.sayHelloWorld(""); } catch (MissingName_Exception e) { System.err.println("Error: " + e); } System.out.println( "Got result: " + result ); } }
As noted previously, an unmodeled fault maps to an exception (for example, java.lang.RuntimeException
) that is generated at run-time when no business logic fault is defined in the WSDL. In this case, Java exceptions are represented as generic SOAP fault exceptions, javax.xml.ws.soap.SOAPFaultException
.
The following shows an example of an exception that maps to an unmodeled fault.
Example 16-11 Example of Web Service Using Unmodeled Fault
package examples;
import javax.jws.WebService;
@WebService(name="HelloWorld", serviceName="HelloWorldService")
public class HelloWorld {
public String sayHelloWorld(String message) throws MissingName {
System.out.println("Say Hello World: " + message);
if (message == null || message.isEmpty()) {
throw new MissingName(); // Modeled fault
} else if (message.equalsIgnoreCase("abc")) {
throw new RuntimeException("Please enter a name."); //Unmodeled fault
}
return "Here is the message: '" + message + "'";
}
}
In this example, if the string "abc" is passed to the method, the following SOAPFaultException
and RuntimeException
messages are returned in the log file:
You can customize the SOAP fault handling process using SOAP message handlers. A SOAP message handler provides a mechanism for intercepting the SOAP message in both the request and response of the Web service. You can create SOAP message handlers to enable Web services and clients to perform additional processing on the SOAP message. For more information, see Chapter 17, "Creating and Using SOAP Message Handlers."
Note:
Thecom.sun.xml.ws.fault.SOAPFaultBuilder.disableCaptureStackTrace
property is supported as an extension to the JDK 6.0. Because this API is not provided as part of the JDK 6.0 kit, it is subject to change.By default, the entire stack trace, including nested exceptions, is included in the details of the SOAP fault message. For example, the following shows an example of a SOAP fault message that includes the stack trace:
Example 16-13 Example of Stack Trace in SOAP Fault Message
<?xml version = '1.0' encoding = 'UTF-8'?> <S:Envelope xmlns:S="http://www.w3.org/2003/05/soap-envelope"> <S:Body> <S:Fault xmlns:ns4="http://schemas.xmlsoap.org/soap/envelope/"> <S:Code> <S:Value>S:Receiver</S:Value> </S:Code> <S:Reason> <S:Text xml:lang="en">String index out of range: 3</S:Text> </S:Reason> <S:Detail> <ns2:exception xmlns:ns2="http://jax-ws.dev.java.net/" class="java.lang.StringIndexOutOfBoundsException" note="To disable this feature, set com.sun.xml.ws.fault.SOAPFaultBuilder.disableCaptureStackTrace system property to false"> <message>String index out of range: 3</message> <ns2:stackTrace> <ns2:frame class="java.lang.String" file="String.java" line="1934" method="substring"/> <ns2:frame class="ratingservice.CreditRating" file="CreditRating.java" line="21" method="processRating"/> <ns2:frame class="sun.reflect.NativeMethodAccessorImpl" file="NativeMethodAccessorImpl.java" line="native" method="invoke0"/> <ns2:frame class="sun.reflect.NativeMethodAccessorImpl" file="NativeMethodAccessorImpl.java" line="39" method="invoke"/> <ns2:frame class="sun.reflect.DelegatingMethodAccessorImpl" file="DelegatingMethodAccessorImpl.java" line="25" method="invoke"/> <ns2:frame class="java.lang.reflect.Method" file="Method.java" line="597" method="invoke"/> ... </ns2:stackTrace> </ns2:exception> </S:Detail> </S:Fault> </S:Body> </S:Envelope>
You can disable the inclusion of the stack trace in the SOAP fault message by setting the com.sun.xml.ws.fault.SOAPFaultBuilder.disableCaptureStackTrace
Java startup property to false
.
To disable the stack trace:
Locate the following entry in the WL_HOME
user_projects/domains
domainName
/startWebLogic.cmd
file, where WL_HOME
refers to the main WebLogic Server installation directory:
set JAVA_OPTIONS=%SAVE_JAVA_OPTIONS%
Edit the entry as follows:
set JAVA_OPTIONS=-Dcom.sun.xml.ws.fault.SOAPFaultBuilder.disableCaptureStackTrace=false %SAVE_JAVA_OPTIONS%
Save the startWebLogic.cmd
file.
Note that in addition to the custom exceptions that are thrown explicitly in your Web service and the SOAPFaultExceptions
that are used to map exceptions that are not caught by your business logic, there are two other exceptions that might be communicated to the Web service client, and that you should be aware of.
Table 16-3 Other Exceptions
Exception | Description |
---|---|
|
Base exception for all JAX-WS API runtime exceptions, used when calls to JAX-WS Java classes fail, such as |
|
Used by JAX-WS asynchronous calls, when a client tries to get the response from an asynchronous call. |