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 http://www.javamonamour.org/2010/04/soap-fault-in-osb.html I have taken some notes.

Here a full explanation on the topic:
http://download.oracle.com/docs/cd/E14571_01/doc.1111/e15867/modelingmessageflow.htm#i1040168


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

$body

<env:Body xmlns:env="http://schemas.xmlsoap.org/soap/envelope/">
 <env:Fault>
  <faultcode>env:Server</faultcode>
  <faultstring/>
  <detail>
   <java:CacheStateException xmlns:java="java:com.acme.cache.commons">
    <java:CacheName>geo-data-geographic-area</java:CacheName>
    <java:Status>Not initialized</java:Status>
   </java:CacheStateException>
  </detail>
 </env:Fault>
</env:Body>


$fault

<con:fault xmlns:con="http://www.bea.com/wli/sb/context">
 <con:errorCode>BEA-380001</con:errorCode>
 <con:location>
  <con:node>RouteNodeToEJBBS</con:node>
  <con:path>response-pipeline</con:path>
 </con:location>
</con:fault>

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

(see also here http://download.oracle.com/docs/cd/E13159_01/osb/docs10gr3/userguide/context.html#wp1051816 for $fault definition)


To access individual info in the fault:
$fault/ctx:errorCode/text()

Error codes are here http://download.oracle.com/docs/cd/E13159_01/osb/docs10gr3/consolehelp/errorcodes.html

NB:
the body uses the namespace http://schemas.xmlsoap.org/soap/envelope/
here http://schemas.xmlsoap.org/soap/envelope/ you can find the XSD for the env:Fault

the fault uses the namespace http://www.bea.com/wli/sb/context



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="http://www.bea.com/wli/sb/context">
 <con:errorCode>BEA-382513</con:errorCode>
 <con:reason>OSB Replace action failed updating variable "body": Error parsing XML: {err}XP0006: "text '
      '": bad value for type element {http://www.acme.com/schema/GeoServicePS/v1}getLocationsByLocationIds { {http://www.w3.
org/2001/XMLSchema}anyType }</con:reason>
 <con:location>
  <con:node>RouteNodeToEJBBS</con:node>
  <con:path>request-pipeline</con:path>
 </con:location>
</con:fault>

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 = "http://tempuri.org/GEO_OSB_MARIA_EJBProxyProject/XQ/generateFault/";
declare namespace env = "http://schemas.xmlsoap.org/soap/envelope/";
declare namespace con = "http://www.bea.com/wli/sb/context";

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: