Handling SOAP fault-s in Axis2/C
The example in this document implements a simple division service: the client sends two integers, and the server sends back their quotient. If the divisor is zero, the server sends back a custom SOAP fault with the following body:
<message>
Division by zero
</message>
The complication with Axis2/C is that C has no exception mechanism, and the generated code does not support retrieving of the fault object in case of error. If the server sends fault, the client side service stub method returns NULL, and we need to dig out the fault object directly from the SOAP envelope, by using the AXIOM XML parsing facilities. However, Axis2/C does generate serializer, deserializer, getters and setters for the fault objects, so we need to cross the gap between the SOAP envelope and the deserielizer only.
Building the example
In this document, I do not explain the details of the steps of building and deploying the code, see the details in the
Axis2/C documentation
.
- First, create the Axis2/C development and runtime environment by Axis2SetUp. As for Axis2/Java, follow Method 1.
- Download the example:
wget https://twiki.cern.ch/twiki/pub/EGEE/Axis2SoapFault/division.tgz
tar -zxf division.tgz
- Generate the client stub and databinding code for the client:
pushd division/client
WSDL2C.sh -uri ../Division.wsdl -u -d adb
The sources were generated in the
src directory. For the description of the command line flags, see
WSDL2C.sh --help
make div
- Build and deploy the server:
popd
pushd division/server
make div
mkdir -p $AXIS2C_HOME/services/division
cp libdivision.so services.xml $AXIS2C_HOME/services/division
- Try it. Open two terminal windows, make sure that the environment variables specified in Axis2SetUp are set in both terminals. Start the server:
cd $AXIS2C_HOME/bin
./axis2_http_server
This will pick up the service code compiled to
libdivision.so
- Try the client with two set of parameters (in the other terminal):
cd division/client
./div 10 2
./div 10 0
The first should print
Result: div (10 2 ) = 5
The second should display the fault message that the server returns:
FAULT occurred: Division by zero
The client also prints the fault XML for the curious minds...
Some explanation
Client side
On the client side, the trick is in
division/client/div.c:get_fault_message
See the code comments for the details, as well as the Axis2/C API document. The API document was created when you compiled Axis2/C, but you can also download from
here. In general what we need to do is:
- Check if the last server response really contains a fault.
- Retrieve the SOAP envelope encoding the response (fault).
- Fetch the SOAP body from the envelope
- Fetch the fault XML from the SOAP body. It looks about like (plus namespaces, and other subtleties):
<detail>
<divFault>
<message>
Division by zero
</message>
</divFault>
</detail>
- Using the AXIOM XML parser, get the "detail" node
- Get the "divFault" node.
- The content of "divFault" can be deserialized by the generated code in
src/adb_divFault.c
Use the deserializer to build the fault object.
- Using the message getter function, get the fault string.
Mind, that the code is not complete, as it is not defensive: never checks the validity of the return values. I ignored them in purpose, to demonstrate the point.
Server side
On the server side, the situation is more complicated. The server side code was generated with the following command:
pushd division/server
WSDL2C.sh -uri ../Division.wsdl -u -d adb -ss
The implementation of the service method should go to the generated
src/axis2_skel_Division.c file
. We moved this file to
server/division.c
, and implemented the service logic. In case of normal behavior, the service function (
axis2_skel_Division_div
) should return an
adb_divResponse_t
object, containing the server response. In case of fault, the function must return NULL. In this case, the web service engine calls the (also generated)
axis2_svc_skel_Division.c : axis2_svc_skel_Division_on_fault
function. It is set as a static and constant callback, we cannot change it in runtime. The function just sends a specific, static fault string that has nothing to to with the
divFault
object. In order to make the example usable, we needed to hack the generated code: removed the generated implementation of
axis2_svc_skel_Division_on_fault
and reimplemented it in
division.c
: it serializes an
adb_divFault
object instead of the default one.
UPDATE: The good news is that on 9 February, the Axis2/C developers checked in a code generator version that explicitly supports the custom fault objects. See the details
in one of their developer's blog
.
--
ZsoltMolnar - 26 Jan 2009