Creating Web Services and Web Clients in Caché
SOAP Fault Handling
[Back] [Next]
   
Server:docs2
Instance:LATEST
User:UnknownUser
 
-
Go to:
Search:    

This chapter describes how to handle faults within a web service and within a web client.

For a detailed discussion of error processing, see the chapter on errors in the book Using Caché ObjectScript.
Note that the SOAPPREFIX parameter affects the prefix used in any SOAP faults; see Specifying the SOAP Envelope Prefix in the chapter Fine-Tuning a Caché Web Service.”
Default Fault Handling in a Web Service
By default, when your Caché web service encounters an error, it returns a standard SOAP message containing a fault. The following shows an example (for SOAP 1.1). The SOAP envelope is omitted in this example:
<SOAP-ENV:Body>
 <SOAP-ENV:Fault>
  <faultcode>SOAP-ENV:Server</faultcode>
  <faultstring>Server Application Error</faultstring>
  <detail>
     <error xmlns='http://www.myapp.org' >
       <text>ERROR #5002: Cache error: <DIVIDE>zDivide^FaultEx.Service.1</text>
     </error>
  </detail>
</SOAP-ENV:Fault>
</SOAP-ENV:Body>
Returning Custom SOAP Faults in a Caché Web Service
To create and return a custom SOAP fault, do the following within the appropriate area of your code that traps errors:
  1. Create a fault object that contains the appropriate information. To do so, call one of the following methods of your web service: MakeFault(), MakeFault12(), MakeSecurityFault(), or MakeStatusFault(). These are discussed in the following subsection.
    Or create a fault object manually, as described in later in this chapter.
  2. Call the ReturnFault() method of the web service, passing the fault object as an argument. Note that ReturnFault()) does not return to its caller; it just sends the fault and terminates processing of the web method.
The following shows an example:
Method Divide(arg1 As %Numeric, arg2 As %Numeric) As %Numeric [ WebMethod ]
{
  Try {
    Set ans=arg1 / arg2
    } Catch {

        //<detail> element must contain element(s) or whitespace
        //specify this element by passing valid XML as string argument to MakeFault() 
        set mydetail="<mymessage>Division error detail</mymessage>"

        set fault=..MakeFault($$$FAULTServer,"Division error",mydetail)
        
        // ReturnFault must be called to send the fault to the client.
        // ReturnFault will not return here.
        Do ..ReturnFault(fault)
      }
  Quit ans
}
Methods to Create Faults
MakeFault()
classmethod MakeFault(pFaultCode As %String, 
                      pFaultString As %String, 
                      pDetail As %String = "", 
                      pFaultActor As %String = "") as %SOAP.Fault
Returns a fault object suitable for SOAP 1.1. Here:
MakeFault12()
classmethod MakeFault12(pFaultCode As %String, 
            pFaultString As %String,
            pDetail As %String = "", 
            pFaultActor As %String = "") as %SOAP.Fault
Returns a fault object suitable for SOAP 1.2. Use this method only the SoapVersion property of the web service is "1.2". For a discussion of how Caché handles the SOAP versions of request messages, see Specifying Parameters of the Web Service,” earlier in this book.
For details on the arguments, see MakeFault().
MakeSecurityFault()
classmethod MakeSecurityFault(pFaultCode As %String, 
                              securityNamespace As %String) as %SOAP.Fault
Returns a fault object appropriate for a security failure. Specify FaultCode as one of the following: "FailedAuthentication", "FailedCheck", "InvalidSecurity", "InvalidSecurityToken", "SecurityTokenUnavailable", "UnsupportedAlgorithm", or "UnsupportedSecurityToken".
The namespace for this security fault is found in the SecurityNamespace property.
MakeStatusFault()
classmethod MakeStatusFault(pFaultCode As %String, 
                            pFaultString As %String, 
                            pStatus As %Status = "", 
                            pFaultActor As %String = "") as %SOAP.Fault
Returns a fault object based on a value in a %Status object.
pStatus is the %Status object to use.
For details on the other arguments, see MakeFault().
Macros for SOAP Fault Codes
The SOAP include file (%soap.inc) defines macros for some of the standard SOAP fault codes; these are listed in the following table. You can use these macros to specify SOAP fault codes. The table notes the version or versions of SOAP to which each macro applies.
Caché ObjectScript Macros for SOAP Fault Codes
Macro SOAP Version(s) When to Use This Macro
$$$FAULTVersionMismatch 1.1 and 1.2 When the web service receives a SOAP message that contained an invalid element information item instead of the expected envelope element information item.
A mismatch occurs if either the namespace or the local name do not match.
$$$FAULTMustUnderstand 1.1 and 1.2 When the web service receives a SOAP message that contained an unexpected element that was marked with mustUnderstand="true"
$$$FAULTServer 1.1 When other server-side errors occur.
$$$FAULTClient 1.1 When the client made an incomplete or incorrect request.
$$$FAULTDataEncodingUnknown 1.2 When the arguments are encoded in a data encoding unknown to the receiver.
$$$FAULTSender 1.2 When the sender made an incomplete, incorrect, or unsupported request.
$$$FAULTReceiver 1.2 When the receiver cannot handle the message because of some temporary condition, for example, when it is out of memory.
Creating a Fault Object Manually
If you need more control than is given by the steps in the previous section, you can create and return a custom SOAP fault as follows:
  1. Create a fault object manually.
    To do so, create an instance of %SOAP.Fault (for SOAP 1.1) or %SOAP.Fault12 (for SOAP 1.2) and then set its properties, as described in the following sections.
    Note:
    You can use %SOAP.Fault in all cases. If a web service receives a SOAP 1.2 request and needs to return a fault, the web service automatically converts the fault to SOAP 1.2 format.
  2. Call the ReturnFault() method of the web service, passing the fault object as an argument. Note that ReturnFault()) does not return to its caller; it just sends the fault and terminates processing of the web method.
SOAP 1.1 Faults
This section provides information on %SOAP.Fault, which represents SOAP 1.1 faults. This section includes the following:
Example SOAP Fault
For reference, here is an example of a SOAP 1.1 fault, including the SOAP envelope:
<SOAP-ENV:Envelope 
xmlns:SOAP-ENV='http://schemas.xmlsoap.org/soap/envelope/' 
xmlns:xsi='http://www.w3.org/2001/XMLSchema-instance' 
xmlns:s='http://www.w3.org/2001/XMLSchema' 
xmlns:flt="http://myfault.org" >
  <SOAP-ENV:Body>
    <SOAP-ENV:Fault>
      <faultcode>SOAP-ENV:Server</faultcode>
      <faultstring>Division error</faultstring>
      <detail><mymessage>Division error detail</mymessage></detail>
    </SOAP-ENV:Fault>
  </SOAP-ENV:Body>
</SOAP-ENV:Envelope>
%SOAP.Fault Properties
Caché represents a SOAP 1.1 fault as an instance of %SOAP.Fault, which has the following properties:
detail
Used within the <detail> element of the SOAP fault. Use this to specify information about the cause of the fault.
If specified, this argument should be a string containing valid XML that can be used within the <detail> element. Caché does not verify that the string you provide is valid; it is the responsibility of your application to check this.
faultcode
Used within the <faultcode> element of the SOAP fault. Set this property equal to one of the SOAP 1.1 macros listed in Macros for SOAP Fault Codes,” earlier in this chapter.
faultstring
Used within the <faultstring> element of the SOAP fault. Specify a string that indicates the reason for the fault, as intended for users to see.
faultactor
Specifies the URI of the SOAP node on the SOAP message path that caused the fault to happen.
This is useful if the SOAP message travels through several nodes in the SOAP message path, and the client needs to know which node caused the error. It is beyond the scope of this book to discuss this advanced topic.
faultPrefixDefinition
Specifies a namespace prefix declaration that is added to the envelope of the SOAP fault. Use a value of the following form:
xmlns:prefix="namespace"
Where prefix is the prefix and namespace is the namespace URI.
For example:
 set fault.faultPrefixDefinition = "xmlns:FLT=""http://myfault.com"""
The %SOAP.Fault class also provides the AsString() method, which returns the fault object as a string.
SOAP 1.2 Faults
This section provides information on %SOAP.Fault12 and related classes, which represent SOAP 1.2 faults. This section includes the following:
Example SOAP Fault
For reference, here is an example of a SOAP 1.2 fault, including the SOAP envelope:
<?xml version="1.0" encoding="UTF-8"?>
<SOAP-ENV:Envelope xmlns:SOAP-ENV="http://www.w3.org/2003/05/soap-envelope" xmlns:flt="http://myfault.org">
  <SOAP-ENV:Body>
    <SOAP-ENV:Fault>
      <SOAP-ENV:Code>
        <SOAP-ENV:Value>SOAP-ENV:Receiver</SOAP-ENV:Value>
      </SOAP-ENV:Code>
      <SOAP-ENV:Reason>
        <SOAP-ENV:Text xml:lang="en">Division error</SOAP-ENV:Text>
        <SOAP-ENV:Text xml:lang="it">Errore di applicazione</SOAP-ENV:Text>
        <SOAP-ENV:Text xml:lang="es">Error del uso</SOAP-ENV:Text>
      </SOAP-ENV:Reason>
      <SOAP-ENV:Detail><mymessage>Division error detail</mymessage></SOAP-ENV:Detail>
    </SOAP-ENV:Fault>
  </SOAP-ENV:Body>
</SOAP-ENV:Envelope>
%SOAP.Fault12 Properties
The class %SOAP.Fault12 represents a SOAP 1.2 fault. This class has the following properties:
Code
An instance of %SOAP.Fault12.Code, discussed in the following section.
Detail
Used within the <detail> element of the SOAP fault. Use this to specify information about the cause of the fault.
If specified, this argument should be a string containing valid XML that can be used within the <detail> element. Caché does not verify that the string you provide is valid; it is the responsibility of your application to check this.
Node
Specifies the URI of the SOAP node on the SOAP message path that caused the fault to happen; optional for the destination node.
This is useful if the SOAP message travels through several nodes in the SOAP message path, and the client needs to know which node caused the error. It is beyond the scope of this book to discuss this advanced use of SOAP.
Reason
A list of instances of %SOAP.Fault12.Text, discussed in a following section. Each instance contains a reason string and a language code that indicates the language or locality of the reason string. These are used within the <Reason> element.
Role
Role that the node was operating in. See the preceding remarks for Node.
faultPrefixDefinition
Specifies a namespace prefix declaration that is added to the envelope of the SOAP fault. Use a value of the following form:
xmlns:prefix="namespace"
Where prefix is the prefix and namespace is the namespace URI.
For example:
 set fault.faultPrefixDefinition = "xmlns:FLT=""http://myfault.com"""
The %SOAP.Fault12 class also provides the AsString() method, which returns the fault object as a string.
%SOAP.Fault12.Code Properties
You use %SOAP.Fault12.Code as a value for the Code property of an instance of %SOAP.Fault12. The %SOAP.Fault12.Code class has the following properties:
Subcode
An optional subcode.
Value
The value you provide depends on whether you have provided a subcode:
%SOAP.Fault12.Text Properties
You use %SOAP.Fault12.Text as a list element in the Reason property of an instance of %SOAP.Fault12. The %SOAP.Fault12.Text class has the following properties:
Text
A string indicating the reason for the fault, as intended for users to see.
lang
A code that corresponds to the language or locality in which the fault text is phrased. For information, see the W3 web site (http://www.w3.org/).
Adding WS-Addressing Header Elements When Faults Occur
Your Caché web service can add WS-Addressing header elements when faults occur. To do this, include the following additional steps within the fault handling of your web service:
  1. Choose a fault destination and a fault action to use in case of faults.
  2. Using these as arguments, call the GetDefaultResponseProperties() class method of %SOAP.Addressing.Properties. This returns an instance of %SOAP.Addressing.Properties that is populated with values as typically needed.
  3. Optionally set other properties of the instance of %SOAP.Addressing.Properties, as needed.
    For details, see the class documentation for %SOAP.Addressing.Properties.
  4. Set the FaultAddressing property of your web service equal to the instance of %SOAP.Addressing.Properties.
Adding Other Header Elements When Faults Occur
In addition to or instead of the options discussed in the previous section, your Caché web service can add custom header elements when faults occur. To do this:
  1. Create a subclass of %SOAP.Header. In this subclass, add properties to contain the additional data.
  2. Within the fault handling of your web service (as described earlier in this chapter), include the following additional steps:
    1. Create an instance of your header subclass.
      Note:
      Despite the name of this class, this object is really a SOAP header element, not an entire header. A SOAP message has one header, which contains multiple elements.
    2. Set its properties as needed.
    3. Insert this header element into the FaultHeaders array property of the web service. To do so, call the SetAt() of that property. The key that you provide is used as the main header element name.
For example, consider the following custom header class:
Class Fault.CustomHeader Extends %SOAP.Header
{

Parameter XMLTYPE = "CustomHeaderElement";

Property SubElement1 As %String;

Property SubElement2 As %String;

Property SubElement3 As %String;

}
We could modify the web method shown previously as follows:
Method DivideAlt(arg1 As %Numeric, arg2 As %Numeric) As %Numeric [ WebMethod ]
{
  Try {
    Set ans=arg1 / arg2
    } Catch {

        //<detail> element must contain element(s) or whitespace
        //specify this element by passing valid XML as string argument to MakeFault() 
        set mydetail="<mymessage>Division error detail</mymessage>"

        set fault=..MakeFault($$$FAULTServer,"Division error",mydetail)

        //Set fault header
        Set header=##class(CustomHeader).%New()
        Set header.SubElement1="custom fault header element"
        Set header.SubElement2="another custom fault header element"
        Set header.SubElement3="yet another custom fault header element"
        Do ..FaultHeaders.SetAt(header,"CustomFaultElement")

        // ReturnFault must be called to send the fault to the client.
        // ReturnFault will not return here.
        Do ..ReturnFault(fault)
      }
  Quit ans
}
When the web client invokes the Divide() web method and uses 0 as the denominator, the web service responds as follows:
<?xml version='1.0' encoding='UTF-8' standalone='no' ?>
<SOAP-ENV:Envelope xmlns:SOAP-ENV='http://schemas.xmlsoap.org/soap/envelope/' 
xmlns:xsi='http://www.w3.org/2001/XMLSchema-instance' 
xmlns:s='http://www.w3.org/2001/XMLSchema' xmlns:flt="http://myfault.org" >
  <SOAP-ENV:Header>
<CustomHeaderElement xmlns:hdr="http://www.mynamespace.org">
    <SubElement1>custom fault header element</SubElement1>
    <SubElement2>another custom fault header element</SubElement2>
    <SubElement3>yet another custom fault header element</SubElement3>
</CustomHeaderElement>
</SOAP-ENV:Header>
  <SOAP-ENV:Body>
...
Here line breaks were added for readability.
Handling SOAP Faults and Other Errors in a Caché Web Client
In a Caché web client, you can use the TRY-CATCH mechanism or the older $ZTRAP mechanism.
In either case, when a Caché web client receives an error, Caché sets the special variables $ZERROR and %objlasterror:
Example 1: Try-Catch
The following method uses TRY-CATCH:
ClassMethod Divide(arg1 As %Numeric, arg2 As %Numeric) As %Numeric
{
    Set $ZERROR=""
    Set client=##class(FaultClient.DivideSoap).%New()

    Try {
        Set ans=client.Divide(arg1,arg2)
        }
    Catch {
        If $ZERROR["<ZSOAP>" {
            Set ans=%objlasterror
            } 
            Else {
            Set ans=$$$ERROR($$$CacheError,$ZERROR)
        }
    }
    
    Quit ans
}
This method uses system macros defined in the %systemInclude include file, so the class that contains this method starts with the following:
Include %systemInclude 
Example 2: $ZTRAP
The following example uses the older $ZTRAP mechanism. In this case, when a Caché web client receives an error, control is transferred to the label indicated by the $ZTRAP special variable (if that label is defined).
ClassMethod DivideWithZTRAP(arg1 As %Numeric = 1, arg2 As %Numeric = 2) As %Numeric
{
    Set $ZERROR=""
    Set $ZTRAP="ERRORTRAP"
    Set client=##class(FaultClient.DivideSoap).%New()
    Set ans=client.Divide(arg1,arg2)
    Quit ans
 
    //control goes here in case of error
ERRORTRAP 
    if $ZERROR["<ZSOAP>" 
    {
         quit client.SoapFault.Detail
        } 
    else 
    {
        quit %objlasterror
       }
}
SSL Handshake Errors
If a Caché web client uses an SSL connection and a SSL handshake error has occurred, then the SSLError property of the client contains text that describes the SSL error.