Jan 2 ’13
The CICS Web Services Assistant and Support for Variable Arrays
First introduced in CICS TS 3.1, CICS Web Services support offers a powerful tool that lets CICS application programs access the Web as both consumers and providers of Web-based services. As with any new technology, Web services bring opportunity and confusion; initial implementation comes with a steep learning curve. To reduce this learning curve and encourage the use of Web services, IBM supplies the CICS Web Services Assistant.
IBM’s Web Service Assistant is a set of utilities designed to create COBOL or PL1 copybooks for CICS Web service requesters, Web Services Descriptor Language (WSDL) definitions for CICS Web service providers, and basic CICS infrastructure support for both providers and requesters. Use of the Web Services Assistant isn’t required, and has some limitations (such as the fact the Assistant only works with COBOL and PL1, and Assembler support isn’t provided) but it can significantly reduce the applications and systems programming effort required to build and implement a CICS Web service.
One of the least understood and most confusing of the Web Services Assistant’s features is the way in which it handles “variable array data”—that is, a data element that contains a table whose number of entries isn’t known at compile time. Variable array data is more commonly referred to in COBOL as the OCCURS DEPENDING ON feature. Support of variable array data becomes more complex if the variable arrays are “nested.” In COBOL terms, that means a table defined with OCCURS DEPENDING ON itself contains a table defined with OCCURS DEPENDING ON.
This article describes the processes the CICS Web Services Assistant uses when handling nested variable array data structures. (Note that while the WSDL to COBOL [DFHWS2LS] Web Services Assistant utility supports the use of nested variable arrays, the COBOL to WSDL Web Services Assistant utility lacks support for variable arrays. If a CICS Web services provider wishes to provide support for OCCURS DEPENDING ON, you must make a copy of the COBOL copybook, change all the OCCURS DEPENDING ON clauses to fixed [i.e., OCCURS 5 TIMES], manually modify the XML produced by the assistant to change the minOccurs and maxOccurs to their appropriate values, and run the DFHWS2LS utility to create a COBOL copybook that’s set up to support variable arrays in a manner the Web Services Assistant run-time support can handle.)
Support for Fixed Size Tables
Consider a straightforward example: a COBOL table with a fixed number of entries and no DEPENDING ON. The table field, MY-TABLE-ELEMENT, is defined in COBOL (see Figure 1). At compile time, the compiler recognizes there must be 25 bytes of storage reserved for this table (five entries multiplied by 5 bytes per entry) and builds the internal definitions accordingly. At run-time, the Web Services Assistant recognizes that the 25 bytes in question represent five MY-TABLE-ELEMENT table entries and parses the storage into five XML data definitions. This handling of fixed tables follows COBOL’s handling, so no special program code is required.
Variable Size Tables
When defining a Web service, using tables with a fixed number of entries will make data handling significantly simpler. In the real world, however, variable arrays are often required to fit the requirements of the functions being performed. Let’s enhance the previous example to a variable number of entries (see Figure 2).
At compile time, there’s no way for the compiler to determine how many entries will be in the table, so there’s no way for it to reserve the storage required for this table, making it difficult for the Assistant to handle the storage requirements at run-time. The Assistant does have a workaround to handle this situation using CICS channels; the table entries (MY-TABLE-ELEMENT in our example) are placed into a container. The naming convention of the containers is used to relate a container to a specific table, and includes a numeric counter to indicate the number of entries that have been placed in the container. The sample definition in Figure 3 shows what the MY-TABLE variable array would look like in XML.
The COBOL data definitions generated by the DFHWS2LS from the WSDL are much more complex than a normal OCCURS DEPENDING ON. First, in the COBOL copybook that describes all the data elements, the definitions of MY-TABLE and MY-TABLE-ELEMENT are removed and replaced with control information, resulting in something similar to Figure 4. Here, all the COBOL definitions referenced are formatted using the original definition. For several reasons (including, for example, XML data names don’t use a dash the way COBOL does), the data element names the Web Services Assistant produces from WSDL don’t follow common COBOL naming conventions.
Note that the suffixes “-num” and “-cont” have a special meaning to the Web Services Assistant. The value in the -num field is the number of entries that were in the MY-TABLE table (i.e., the value in the field referenced by the OCCURS DEPENDING ON). The value in the -cont field is the name of the container CICS created to hold the actual table entry data for the MY-TABLE table. The actual data contained in the table entries for the MY-TABLE table isn’t included in this data definition and doesn’t exist in this container.
Second, the DFHWS2LS utility creates a separate data definition for the MY-TABLE table data. This definition would contain all the data in the table entry (see Figure 5). If an incoming request arrived that had four MY-TABLE entries, DATA-AREA would consist of My-Table-num (containing +4), My-Table-cont (containing a constant such as “DFHPI00000000001”), and whatever data value was in OTHER-DATA. Using the information in the -num and -cont fields, the program knows there are four entries, and these entries can be found in the container whose name is contained in My-Table-cont. To create the data structure as defined by the original DATA-AREA, the program must loop through this container, moving each entry into the appropriate MY-TABLE-ELEMENT slot.
This same process applies if a CICS program is to ship variable array data to the Web, either to request a service or return data to a requester. The programmer must place a container name in the My-Table-cont field, create a unique container to hold the table, then place the number of entries in the Table-num field. The value placed in the -cont field must be a valid container name and can’t start with the letters DFH.
While the process the Web Services Assistant uses to manage variable array data is complex, it follows a series of fixed steps that remain consistent for all tables:
1. Remove the actual data contained in the variable table from the original data structure.
2. Replace this data with control information that describes the container used to hold the actual data.
3. Create a container that holds all the entries of actual data.
Nested Variable Size Tables
The next step is to see how these three steps are used to handle a situation where variable arrays are defined in a variable array. Let’s enhance our earlier example to include a second array in the first (see Figure 6).
As with the previous example, MY-TABLE-ELEMENT can occur up to five times. For each occurrence, there will be two data elements called NESTED-ELEMENT-1 and NESTED-ELEMENT-2, which can occur up to 10 times. Because these two data elements are defined as part of an OCCURS DEPENDING ON, they will be treated in the same way MY-TABLE-ELEMENT was. The only twist is that the NESTED-ELEMENTs can occur multiple times for each occurrence of MY-TABLE-ELEMENT.
In the previous example of a single variable array, the data definition was broken into two parts. The original definition of the fixed portion of the data remains intact. The definition of MY-TABLE is expanded to include the control information for the nested OCCURS DEPENDING ON by adding the appropriate -num and -cont fields (see Figure 7). Finally, a new group definition is added with the description of the fields in the nested table (see Figure 8).
How Many Containers?
When using the Web Services Assistant, for each first-level variable array (i.e., an OCCURS DEPENDING ON that isn’t defined in another OCCURS DEPENDING ON), CICS will remove all the table data from the data layout and place it into a separate container; it will remove the field definitions from the COBOL data definition copybook, replacing them with fields containing the number of entries in the table and the name of the new container.
For each second-level variable array (i.e., an OCCURS-DEPENDING-ON that’s defined in another OCCURS DEPENDING ON), CICS will remove all the table data from each entry of the defining table and place it into a separate container; it will remove the field definitions from the COBOL data definition copybook, replacing them with fields containing the number of entries in the table and the name of the new container. So, for each first-level variable array table entry, there will be one second-level variable array container.
In the first example, there was one variable table (MY-TABLE) that was defined in the group DATA-AREA, so the Assistant created a container to hold the table entries and added control information to describe the container to the DATA-AREA group.
In the second example, the new variable table (NESTED-MY-TABLE) was defined in the group MY-TABLE, so there’s an instance of NESTED-MY-TABLE for each entry of MY-TABLE. In this case, the Assistant will create a unique container to hold an instance of NESTED-MY-TABLE for each entry in MY-TABLE and place the appropriate control information in the NESTED-MY-TABLE table entry.
In this case, the number of containers will equal the number of entries in the NESTED-MY-TABLE (i.e., the value in SECOND-NUMBER-OF-ENTRIES plus one for the container holding the original MY-TABLE data entries).
Although CICS Web Services Assistant support for variable array data initially appears to be unwieldy and difficult to manage, the process is remarkably easy to manage.
When accepting input from the Web, the programmer can simply create a few brief routines to populate the existing data definitions from the multiple containers that the Assistant provides, allowing the actual business logic to remain as coded.
When creating output that will be processed by the Assistant, once again, a few routines to create the required containers and populate them from the existing data definitions will minimize the coding effort required.