Sunday, July 4, 2010

OSB: error handling, fault

First read the posts of my friend Jan and of Eric Elzinga (whom I have never had the pleasure to meet).

Here I have taken some notes.

Here a full explanation on the topic:

When a fault is handled in the fault handler, you have this:


<env:Body xmlns:env="">
   <java:CacheStateException xmlns:java="java:com.acme.cache.commons">
    <java:Status>Not initialized</java:Status>


<con:fault xmlns:con="">

Not necessarily "reason" and "details" are populated! Details should be retrieved from the $body variable. Reason is nowhere to be found.

(see also here for $fault definition)

To access individual info in the fault:

Error codes are here

the body uses the namespace
here you can find the XSD for the env:Fault

the fault uses the namespace

If you terminate the Error Handler with "Reply with failure", you return a HTTP 500 status. In SOAPUI, in the response panel click in RAW, you will see "HTTP/1.1 500 Internal Server Error".

The ambiguity is that if you get a fault internal to OSB - rather than from an external service - the $body doesn't contain the fault, but rather the original request message. In this case the $fault will contain the info required:

<con:fault xmlns:con="">
 <con:reason>OSB Replace action failed updating variable "body": Error parsing XML: {err}XP0006: "text '
      '": bad value for type element {}getLocationsByLocationIds { {http://www.w3.
org/2001/XMLSchema}anyType }</con:reason>

The rule for a "universal error handler" could be:
merge whatever information comes from $body (if it's a env:Fault) and from $fault, to build a meaningful env:Fault object to return to the caller with a HTTP 500 status.

This can be used to merge env:Fault and ctx:fault into a meaningful env:Fault:

xquery version "1.0" encoding "Cp1252";
xquery version "1.0" encoding "Cp1252";
(:: pragma  parameter="$theBody" type="xs:anyType" ::)
(:: pragma  parameter="$theFault" type="xs:anyType" ::)
(:: pragma  type="xs:anyType" ::)

declare namespace xf = "";
declare namespace env = "";
declare namespace con = "";

declare function xf:generateFault($theBody as element(*),
    $theFault as element(*))
    as element(*) {
    {fn:concat($theBody/env:Fault/faultcode/text(), ' ', $theFault/con:errorCode/text())}
    {fn:concat($theBody/env:Fault/faultstring/text(), ' ' , $theFault/con:reason/text())}
    {$theBody/env:Fault/detail/*} { $theFault/con:location} 

declare variable $theBody as element(*) external;
declare variable $theFault as element(*) external;

xf:generateFault($theBody, $theFault) 

Using Axis2 as a client, during unmarshalling of the response Axis will generate a org.apache.axis2.AxisFault Java exception upon reception of a env:Fault in the body;
reason, code and details are populated.
This is optional and can be disabled.
All this takes place in Axis2 kernel, org.apache.axis2.util.Utils.getInboundFaultFromMessageContext(...)

When unittesting for SOAP Fault, assert that an AxisFault exception is generated.

No comments: