New software development methodologies, such as Extreme Programming (XP) and Rational Unified Process (RUP), demand the continuous deployment of software releases, both from the development environment to the test environment and from the test environment to the production environment. Because of the iterative, or cyclic, nature of this paradigm, anything that can be effectively automated should be automated. Even some usually manual operations, such as packaging all the objects that make up a release in a SAVF and transferring it (with FTP) to the destination server, can be automated. In this article, I present a Cobol program (BUILDSAVF) for programmatically building a SAVF. The objective is to achieve the smooth deployment of a software product from the development environment to the target (either test or production) environment.
To accomplish this goal, BUILDSAVF (downloadable via the link at the end of this article) uses the Save Object List (QSRSAVO) API. This API falls into the Backup and Recovery APIs category. Unlike the List APIs, which employ a user space to return information from the operating system to the caller program, the QSRSAVO API uses a user space to receive information from the caller program. Therefore, the caller program has the burden of building a relatively complex data structure onto a user space, passing it as a parameter to the API.
The QSRSAVO API offers the same functionality that we find in the Save Object (SAVOBJ) command. Each SAVOBJ command parameter has an equivalent key in the QSRSAVO API, which is identified by a number and with a specific format. The data structure built by the program consists of a four-byte binary field that represents the number of key formats in the user space followed by a series of data structures, each one representing one key format. Each key format is a variable-length record made up of the following fields:
Some of the functional requirements of BULDSAVF are:
As a result of these requirements, the data structure created by the programs looks like this:
01 user-space-fmt.
02 number-of-records PIC 9(9) BINARY.
*-------------------------------------------------*
* Library key format # 2 *
*-------------------------------------------------*
02 library-key-format.
03 length-of-overall-key-fmt PIC 9(9) BINARY.
03 format-key PIC 9(9) BINARY.
03 length-of-data-segment PIC 9(9) BINARY.
03 library-data.
04 number-of-libraries PIC 9(9) BINARY.
04 library-name PIC x(10).
03 FILLER PIC XX.
*--------------------------------------------------*
* Device key format # 3 *
*--------------------------------------------------*
02 device-key-format.
03 length-of-overall-key-fmt PIC 9(9) BINARY.
03 format-key PIC 9(9) BINARY.
03 length-of-data-segment PIC 9(9) BINARY.
03 device-data.
04 number-of-devices PIC 9(9) BINARY.
04 device-name PIC x(10).
03 FILLER PIC XX.
*--------------------------------------------------*
* SAVF key format # 4 *
*--------------------------------------------------*
02 savf-key-format.
03 length-of-overall-key-fmt PIC 9(9) BINARY.
03 format-key PIC 9(9) BINARY.
03 length-of-data-segment PIC 9(9) BINARY.
03 savf-data.
04 qual-savf-name.
05 savf-name PIC x(10).
05 savf-library PIC x(10).
*--------------------------------------------------*
* Object information key format # 1 *
*--------------------------------------------------*
02 object-key-format.
03 fixed-portion.
04 length-of-overall-key-fmt PIC 9(9) BINARY.
04 format-key PIC 9(9) BINARY.
04 length-of-data-segment PIC 9(9) BINARY.
04 number-of-entries PIC 9(9) BINARY.
03 variable-portion.
04 objects-array OCCURS 0 TO 500 TIMES
DEPENDING ON number-of-entries
INDEXED BY t-index.
05 object-name PIC x(10).
05 object-type PIC x(10).
Now let me some characteristics of the above data structure.
The data structure (called user-space-fmt) is declared below the LINKAGE SECTION. Therefore, the compiler doesn't allocate storage for it. It can be referenced only after its address has been set to a pointer data item containing a valid address. BUILDSAVF creates a user space by using the Create User Space (QUSCRTUS) API and obtains its address with the Retrieve Pointer to User Space (QUSPTRUS) API. Later, the pointer returned by this API is assigned to the address of the user-space-fmt data structure. At this point, the program can set all the fields in the data structure.
The BUILDSAVF program declares four keys to be read by the API. Therefore, the program assigns the integer value "4" to the variable called number-of-records. IBM Information Center documents 36 keys (link is provided at the end of this article), two of which (library key and device key) are required and the rest of which are optional. Although the required keys contain arrays, BUILDSAVF uses only one element for each. That is, there is only one library to be saved in one device (the SAVF). For that reason, these two key formats don't contain the OCCURS clause (an "OCCURS 1 TIMES" clause sounds like a nonsense statement).
The object information key format, instead, defines an array that can hold up to 500 elements. At least in my shop, this is large enough to hold a single software release. But, regardless of the number of array elements declared in the OCCURS clause, the amount of data read by the API is determined by the value of the number-of-entries field. It's initialized with the value zero. For each record read from the database file, a new element is added to the array incrementing the number-of-entries field by 1. Thence, the object information obtained from the database file is loaded in the newly created array element.
To avoid hard-coding "magic numbers," the numeric fields in each key format are initialized using the LENGTH OF Cobol intrinsic function:
MOVE LENGTH OF library-key-format TO
length-of-overall-key-fmt IN library-key-format.
MOVE LENGTH OF library-data TO
length-of-data-segment IN library-key-format.
At the end of the device key and library key formats, I've added a two-byte filler to align these variable-length records on a four-byte boundary. The Information Center includes the following advice: "You should make the length of each variable-length record a multiple of 4, even if the data length is not a multiple of 4."
Notice that I've defined the object information key format after the other key formats, because this is a variable-length record. That is, the program doesn't know its length in advance because the length depends on the number of records in the input file. For that reason, the program can set the numeric fields of this data structure only when it leaves the main loop and the array has reached its maximum length:
COMPUTE length-of-data-segment IN object-key-format =
LENGTH OF variable-portion.
COMPUTE length-of-overall-key-fmt IN object-key-format =
LENGTH OF variable-portion +
LENGTH OF fixed-portion.
Once all the fields in the user-space-fmt data structure have been properly set, the BUILDSAVF program can call the QSRSAVO API. It accepts only two parameters: the qualified user space name and the error code data structure. Both are mandatory. The error code output parameter is a variable-length data structure used by many system APIs to return error or exception conditions to the caller program. IBM provides it in QSYSINC/QLBLSRC, and it's called QUSEC.
You should take the sample program presented here only as a code snippet. In my shop, a similar program does things not shown here, for example:
It's worth noting that this program is intended for a shop that develops in-house applications. For independent software vendors, IBM provides a suite of tools specifically designed for packaging its software as a "product" such as:
The IBM Information Center documents the QSRSAVO API. I haven't found any Cobol examples of using the QSRSAVO API. Instead, there are a lot of RPG examples on the web. You can read an RPG implementation written by Ron Turull. In this article, the author uses QSRSAVO API to implement an unattended backup strategy.
To learn about the new methodology approach, you can read "The New Methodology," by Martin Fowler.
You can download the source code for BUILDSAVF here:
http://www.pentontech.com/IBMContent/Documents/article/57613_797_BuildSavf.zip