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:

  1. 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
  2. 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
  3. Address the parsed data. For example:
    SET ADDRESS OF Body TO body-ptr
  4. 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
  5. 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
  6. 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
  7. 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.
Note: You can combine steps 1 and 2 into a single TRANSFORM command (and also combine steps 5 and 6).