A Practical Way to Add Exports to a Service Program
October 15, 2008 Ted Holt
My life was confusing enough already. Then along came IBM with binder language, the CL-like language we use to define the list of exports of a service program. Awhile back I sat down to try to find an effective way to deal with service program exports. Here’s what I came up with. When you create a service program, you must list the exports, that is, the data and/or modules that are available to callers. There is a shortcut. If you specify EXPORT(*ALL) in the Create Service Program (CRTSRVPGM) command, the system will generate the list of exports for you. However, you don’t have any guarantee that the generated list will be compatible with existing callers, therefore you will need to rebind the newly created service program to existing callers. You can use binder language to avoid the rebinding process, because binder language gives you a way to order the list of exports. Binder language is stored in physical file members, like RPG, CL, and DDS source code. Create a source physical file called QSRVSRC. I recommend you put it and the source code for all the modules in the same library. The first line of a binder language source member is the Start Program Export (STRPGMEXP) command. The last line is the End Program Export (ENDPGMEXP) command. Between the two, use the EXPORT command to list each export. Here’s an example: strpgmexp pgmlvl(*current) lvlchk(*yes) signature('BR549') export symbol('JUNIOR') export symbol('SAMPLES') endpgmexp Notice that the STRPGMEXP command has three parameters:
Suppose we have a service program, NUMBERS, which is made of one module, also called NUMBERS, which consists of two subprocedures, THREE and FOUR. H nomain D/copy prototypes,numbers P Three b export D pi 5i 0 /free return 3; /end-free P e * ========================================= P Four b export D pi 5i 0 /free return 4; /end-free P e For completeness, here’s the prototype referred to in the source. D Three pr 5i 0 D Four pr 5i 0 Which of the various combinations of the STRPGMEXP parameters would be most conducive to change? That is, what binder language would be easy to add exports to? What binder language would not require that callers be rebound to the service program? Here’s one possibility: strpgmexp pgmlvl(*current) lvlchk(*yes) signature('NUMBERS') export symbol('THREE') export symbol('FOUR') endpgmexp Suppose I decide to add three more subprocedures–ONE, TWO, and FIVE–to this module and service program. H nomain D/copy prototypes,numbers P One b export D pi 5i 0 /free return 1; /end-free P e * ========================================== P Two b export D pi 5i 0 /free return 2; /end-free P e * ========================================== P Three b export D pi 5i 0 /free return 3; /end-free P e * ========================================== P Four b export D pi 5i 0 /free return 4; /end-free P e * ========================================== P Five b export D pi 5i 0 /free return 5; /end-free P e After I recreate the module, I am ready to recreate the service program. How should I modify the binder language? I could change the previous binder language to a *PRV signature, and add a new current signature, like this: strpgmexp pgmlvl(*current) lvlchk(*yes) signature(*gen) export symbol('ONE') export symbol('TWO') export symbol('THREE') export symbol('FOUR') export symbol('FIVE') endpgmexp strpgmexp pgmlvl(*prv) lvlchk(*yes) signature(*gen) export symbol('THREE') export symbol('FOUR') endpgmexp But guess what? This binder language won’t work. When I run a program that calls this service program, calls to THREE return 1 and calls to FOUR return 2. To ensure that the callers continue to work correctly, I have to add the new exports to the end of the list, like this: strpgmexp pgmlvl(*current) lvlchk(*yes) signature(*gen) export symbol('THREE') export symbol('FOUR') export symbol('ONE') export symbol('TWO') export symbol('FIVE') endpgmexp strpgmexp pgmlvl(*prv) lvlchk(*yes) signature(*gen) export symbol('THREE') export symbol('FOUR') endpgmexp According to my tests, I can add the subprocedures anywhere in the module. The only thing that matters to callers is that the new exports be added to the end of the list. But if the new exports must be added to the end of the list, why fool around with *PRV lists anyway? For that reason, I use only a *CURRENT signature, to which I give a name, and I add new exports to the end of the list. strpgmexp pgmlvl(*current) lvlchk(*yes) signature('NUMBERS') export symbol('THREE') export symbol('FOUR') export symbol('ONE') export symbol('TWO') export symbol('FIVE') endpgmexp The result is the same, and I have less complexity to deal with. To sum it up:
|