Parsing SOAP fault messages
If you use the EXEC CICS INVOKE WEBSERVICE or EXEC CICS INVOKE SERVICE commands to call a remote web service, you might receive an INVREQ response with a RESP2 value of 6, indicating that a SOAP fault message was returned. You can parse a SOAP fault message from an application program in CICS® Transaction Server for z/OS® ( CICS TS) V4.1 or later.
Problem
You want to know more about a SOAP fault message from an application. For example, you want to know whether the fault message originated in CICS or in the remote application; or you want to access some embedded data in the fault message.
Response
From CICS TS V4.1, you can use the XML parsing application programming interface (API) command, TRANSFORM . (Previously, you read the DFHWS-BODY container returned by CICS to access the XML representation of the SOAP fault message, then parsed the XML data by using a mechanism of your choice.) You can use a similar approach to process SOAP V1.2 fault messages.
Use DFHSC2LS to build COBOL bindings for SOAP faults
Download a copy of the XML schema for SOAP Envelopes from the following location: http://schemas.xmlsoap.org/soap/envelope/. For example, save the schema to a location in the UNIX file system called /u/example/source/SOAP11.xsd. Use DFHSC2LS to process the XML schema and create as output a set of COBOL bindings for the schema, and an XSDBind file in a bundle directory. You could use JCL similar to the following example:
//EXAMPLE EXEC DFHSC2LS,
//INPUT.SYSUT1 DD *
MAPPING-LEVEL=3.0
ELEMENTS=Body,Fault
SCHEMA=/u/example/source/SOAP11.xsd
LANG=COBOL
PDSLIB=//EXAMPLE.COBOL.LIBRARY
PDSMEM=SOAP11
XSDBIND=SOAP11.xsdbind
BUNDLE=/u/example/output/bundle/SOAP11
LOGFILE=/u/example/output/logfile.log
*/
DFHSC2LS creates several COBOL language structures, as follows:
- Bindings for the body of the SOAP envelope:
03 Body.
06 Body-num PIC S9(9) COMP-5 SYNC.
06 Body-cont PIC X(16).
01 SOAP1101-Body.
03 Body-xml-cont PIC X(16).
03 Body-xmlns-cont PIC X(16).
This language
structure contains bindings to allow any number of XML tags to appear
in the SOAP body.
CICS
stores
the number of tags found in the
Body-num
field, and
information about the data in the container named by the
Body-cont
field.
Each XML tag from the body has two fields associated with it that
provide the XML for the tag in a container named in
Body-xml-cont
and
the in-scope XML namespace declarations in a container named in
Body-xmlns-cont
.
- Bindings for the fault in the body of the SOAP envelope:
03 Fault.
06 faultcode-length PIC S9999 COMP-5 SYNC.
06 faultcode PIC X(255).
06 faultstring-length PIC S9999 COMP-5 SYNC.
06 faultstring PIC X(255).
06 faultactor-num PIC S9(9) COMP-5 SYNC.
06 faultactor.
09 faultactor2-length PIC S9999 COMP-5 SYNC.
09 faultactor2 PIC X(255).
06 detail3-num PIC S9(9) COMP-5 SYNC.
06 detail2.
09 Xdetail-num PIC S9(9) COMP-5 SYNC.
09 Xdetail-cont PIC X(16).
01 SOAP1102-Xdetail.
03 detail-xml-cont PIC X(16).
03 detail-xmlns-cont PIC X(16).
This
language structure contains bindings to allow a single SOAP fault
to be parsed. It provides access to the
faultcode
,
faultstring
and
faultactor
fields,
together with structures to map any number of XML tags found within
the
detail
section of the SOAP fault.
Install the bundle into CICS
Create and install a BUNDLE definition such as the following example:
GROUP: EXAMPLE
DESCRIPTION: Bundle for mapping SOAP 1.1 SOAP Faults
BUNDLEDIR: /u/example/output/bundle/SOAP11
BUNDLEDIR
points
to the location that you specified by using the
BUNDLE
parameter
of DFHSC2LS. If you run DFHSC2LS on a different
z/OS
image from the one that
CICS
uses, you might need to copy the bundle
directory to the target machine. In this situation, use a different
directory path and set the value of
BUNDLEDIR
accordingly.
You can set any name for the bundle; it does not need to be
SOAP11
.
When the bundle is installed into CICS , you have a BUNDLE resource called SOAP11 and an XMLTRANSFORM resource also called SOAP11. The XMLTRANSFORM name is derived from the value of the XSDBIND parameter of DFHSC2LS.
Example SOAP fault message
The following example SOAP fault message might be found in the DFHWS-BODY container following an EXEC CICS INVOKE WEBSERVICE command:
SOAP-ENV:Body>
<SOAP-ENV:Fault xmlns="">
<faultcode>SOAP-ENV:Server</faultcode>
<faultstring>Conversion to SOAP failed</faultstring>
<detail>
<CICSFault xmlns="http://www.ibm.com/software/htp/cics/WSFault">
DFHPI1010 *** XML generation failed. A conversion error
INVALID_PACKED_DEC) occurred when converting field 'example' for
WEBSERVICE 'testWebservice'.
</CICSFault>
</detail>
</SOAP-ENV:Fault>
</SOAP-ENV:Body>
This example
is a fault message that
CICS
creates
when a conversion error occurs. When the
TRANSFORM
command
processes the fault message,
Body-num
is set to 1
to indicate that there is a single XML tag in the Body tag.
Body-cont
is
set to the name of a container, for example DFHPICC-00000001.
The names of two further containers are place inside container DFHPICC-00000001, for example DFHPICC-00000002 and DFHPICC-00000003.
Container DFHPICC-00000002 contains the first tag in the Body tag, for example:
SOAP-ENV:Fault xmlns="">
<faultcode>SOAP-ENV:Server</faultcode>
<faultstring>Conversion to SOAP failed</faultstring>
<detail>
<CICSFault xmlns="http://www.ibm.com/software/htp/cics/WSFault">
DFHPI1010 *** XML generation failed. A conversion error
INVALID_PACKED_DEC) occurred when converting field 'example' for
WEBSERVICE 'testWebservice'.
</CICSFault>
</detail>
</SOAP-ENV:Fault>
Container DFHPICC-00000003 contains any in-scope namespace declarations, for example:
xmlns:SOAP-ENV="http://schemas.xmlsoap.org/soap/envelope/"
xmlns:xsi= "http://www.w3.org/2001/XMLSchema-instance "
If
the DFHPICC-00000002 container is then parsed through a second
EXEC
CICS TRANSFORM
command, further output is created. The
faultcode
and
faultcode-length
fields
are set to SOAP-ENV:Server and 15. The
faultstring
and
faultstring-length
fields
are set to
Conversion to SOAP failed
and 25. The
faultactor-num
field
is set to 0. The
detail3-num
field is set to 1 to
indicate that the optional
detail
tag is present
in the fault. The
detail2-num
field is set to 1 to
indicate that there is one sub-tag in the optional
detail
tag.
The
detail2-cont
field is set to the name of a container,
for example DFHPICC-00000004.
Container DFHPICC-00000004 contains the names of two further containers, for example DFHPICC-00000005 and DFHPICC-00000006.
Container DFHPICC-00000005 contains the
first XML tag found in the
detail
section of the
SOAP fault, for example:
CICSFault
xmlns="http://www.ibm.com/software/htp/cics/WSFault ">
DFHPI1010 *** XML generation failed. A conversion error
(INVALID_PACKED_DEC) occurred when converting field 'example'
for WEBSERVICE 'testWebservice'.
</CICSFault>
Container DFHPICC-00000006 contains the in-scope namespace declarations, for example:
xmlns:SOAP-ENV="http://schemas.xmlsoap.org/soap/envelope/"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance "
Application Code
To implement an application to parse the SOAP fault, use the following procedure:
-
Call the
TRANSFORM
command to query the contents
of the DFHWS-BODY container. For example:
EXEC CICS TRANSFORM XMLTODATA CHANNEL(channel-name) XMLCONTAINER('DFHWS-BODY') NSCONTAINER('DFHWS-XMLNS') ELEMNAME(element-name) ELEMNAMELEN(element-name-len) END-EXEC
-
If the element-name is set to Body, parse the container. If it
is not, an error occurred. To parse the Body, use the following
commands:
EXEC CICS TRANSFORM XMLTODATA CHANNEL(channel-name) XMLTRANSFORM('SOAP11') XMLCONTAINER('DFHWS-BODY') NSCONTAINER('DFHWS-XMLNS') DATCONTAINER('PARSEDBODY') END-EXEC EXEC CICS GET CONTAINER('PARSEDBODY') SET(body-ptr) END-EXEC
-
Address the parsed data. For example:
SET ADDRESS OF Body TO body-ptr
-
Check
Body-num
to ensure there is at least one entry in the Body. If so, read the container that lists the details. For example:EXEC CICS GET CONTAINER(Body-cont) SET(body-cont-ptr) END-EXEC SET ADDRESS OF SOAP1101-Body TO body-cont-ptr
-
Call the
TRANSFORM
command a second time to
query the first tag in the Body:
EXEC CICS TRANSFORM XMLTODATA CHANNEL(channel-name) XMLCONTAINER(Body-xml-cont) NSCONTAINER(Body-xmlns-cont) ELEMNAME(element-name) ELEMNAMELEN(element-name-len) END-EXEC
-
If the element-name is set to Fault, parse the container:
EXEC CICS TRANSFORM XMLTODATA CHANNEL(channel-name) XMLTRANSFORM('SOAP11') XMLCONTAINER(Body-xml-cont) NSCONTAINER(Body-xmlns-cont) DATCONTAINER('PARSEDFAULT') END-EXEC EXEC CICS GET CONTAINER('PARSEDFAULT') SET(fault-ptr) END-EXEC SET ADDRESS OF Fault TO fault-ptr
-
You can now query the data from the fault. For example, you might
find the
faultstring
field useful. To parse application specific details from the detail' section of the fault, you an build further application-specific COBOL bindings by using DFHSC2LS and issuing further TRANSFORM commands in the application.