KICKS |
A transaction processing system for CMS & TSO |
Designing and implementing simple KICKS COBOL programs, part II
Using LINK and XCTL to merge several simple programs into more powerful applications
The name of the first transaction KICKS runs (before any you type from the terminal) is specified by the PLTPI (Program Load Table Initial Program) argument in the SIT. By default this is KSGM. We looked at that program last time.
The name of the last transaction KICKS runs (after you initiate shutdown) is specified by the PLTSD (Program Load Table Shut Down) argument in the SIT. By default this is K999. This time we will examine K999 to explore the LINK api.
You know what the KICKS shutdown sequence looks like from the terminal side: You type KSSF on a clear screen; a message saying ’KICKS is shutting down…’ is briefly displayed; then you are returned to the TSO READY prompt.
From an internal perspective: KSSF starts the KSSFPGM program (procedure division below).
PROCEDURE DIVISION.
* --- (KSSF) send shutdown message ---
EXEC KICKS
SEND TEXT FROM(SHUTDOWN-MSG) STRFIELD
END-EXEC.
* --- signoff (signoff is same as shutdown to KICKS!) ---
EXEC KICKS SIGNOFF END-EXEC.
* --- shutdown happens after transaction ends ---
EXEC KICKS RETURN END-EXEC.
This displays the message you see; tells KICKS it’s time to quit; and then the KSSF transaction ends. After that KICKS notices that it’s time to quit and stops polling the terminal for input. But before KICKS completely shuts down it runs one more transaction, K999 (or whatever you named in PLTSD). The K999 transaction starts the K999PGM program (procedure division below).
PROCEDURE DIVISION.
* --- (K999) just a sample for user modification ---
EXEC KICKS DELAY INTERVAL(2) END-EXEC.
* --- 'final' shutdown happens after transaction ends ---
EXEC KICKS RETURN END-EXEC.
When this transaction ends (or abends), KICKS exits and you return to the TSO READY prompt.
The purpose of the PLTPI and PLTSD entries is to allow you to customize KICKS startup and shutdown. This is usually necessary for some sort of application startup and shutdown. For example (not a particularly realistic one), logging a user’s starting and ending data entry time independent of the actual transactions entered. The beginning time could be logged in a PLTPI transaction; the ending time in a PLTSD transaction.
Suppose you have an ‘ABC’ application that needs this done. It has a vsam ESDS named ABCLOG and a record ABCL-REC with fields ABCLR-USER for a userid, ABCLR‑DATE for the date, ABCLR-TIME for the time, and ABCLR-BE that’s a flag for begin/end. You could add the following procedure division code to K999 to write the logout record
PROCEDURE DIVISION.
* --- (K999) just a sample for user modification ---
EXEC KICKS DELAY INTERVAL(2) END-EXEC.
++ * --- Note ABC app user logout ---
++ MOVE EIBUSER TO ABCLR-USER.
++ MOVE EIBDATE TO ABCLR-DATE.
++ MOVE EIBTIME TO ABCLR-TIME.
++ MOVE 'E' TO ABCLR-BE.
++ EXEC KICKS
++ WRITE DATASET('ABCLOG') FROM(ABCLOG-REC)
++ END-EXEC.
++ * --- 'final' shutdown happens after transaction ends ---
EXEC KICKS RETURN END-EXEC.
You could also add similar code to KSGM to write the ‘B’ login record. The effect is that when KICKS starts a record is written to the ABCLOG file showing the start date/time of the user’s access, and when KICKS shuts down another record is written showing the end date/time of the user’s access.
If you get another application that needs something similar you could do the same – say adding appropriate user logging for the ‘DEF’ application. And the ‘GHI’ application. And the ‘JKL’ application. …
But if you have many applications that need such service that might get clumsy, especially if (as is usually the case) the applications’ needs are each a little different from all the others, and even more so if (as is usually the case) application updates require changes to this startup/shutdown coding.
One way to make maintenance a bit less clumsy would be to compartmentalize the application startup/shutdown code. Suppose the ‘ABC’, ‘DEF’, ‘GHI’, … applications each had a program like this one for the ‘ABC’ app:
ID DIVISION.
PROGRAM-ID. ABCPLT.
ENVIRONMENT DIVISION.
DATA DIVISION.
WORKING-STORAGE SECTION.
01 ABCLOG-REC.
05 ABCLR-DATE PIC S9(7) COMP-3.
05 ABCLR-TIME PIC S9(7) COMP-3.
05 ABCLR-USER PIC X(8).
05 ABCLR-BE PIC X.
LINKAGE SECTION.
01 DFHCOMMAREA PIC X.
PROCEDURE DIVISION.
MOVE EIBUSER TO ABCLR-USER.
MOVE EIBDATE TO ABCLR-DATE.
MOVE EIBTIME TO ABCLR-TIME.
MOVE DFHCOMMAREA TO ABCLR-BE.
EXEC KICKS
WRITE DATASET('ABCLOG') FROM(ABCLOG-REC)
END-EXEC.
EXEC CICS RETURN END-EXEC.
Then the KSGM and K999 transactions would only need to call the one program for each application; they (the KSGM and K999 transactions) would be independent of all the fine points of what each application needed; and they would not need to be recompiled when any of the application requirements changed. The KSGM and KSSF programs would do each call with a generic LINK like this
EXEC KICKS
LINK PROGRAM('ABCPLT') COMMAREA(B-E)
END-EXEC.
Where the working storage item B-E would have a VALUE ‘B’ in KSGMPRG and ‘E’ in K999PRG. The application startup/shutdown code would interpret a passed value of ‘B’ (begin) to mean it was being called by the PLTPI transaction at startup; a passed value of ‘E’ (end) to mean it was being called by the PLTSD transaction at shutdown. The ABCPLT program for example just puts the ‘B’ or ‘E’ into the record it writes to indicate startup or shutdown respectively.
Note that LINK is by PROGRAM (the PPT entity), whereas RETURN TRANSID as by TRANSID (the PCT entry). Perhaps a little confusing, but also handy: it means you don’t need to define transaction id’s for all your programs, only the ones you want to be able to invoke directly. Programs that are only referenced by LINK (or XCTL, we’ll get to that) won’t need a PCT entry.
When you LINK to a program the calling program remains active and when the called program returns the calling program resumes right after the LINK – this is just like a subroutine call.
Since LINK is like a subroutine call you might ask why not just use a normal COBOL subroutine call?
Of course there are also some disadvantages to using LINK instead of a normal COBOL subroutine call, the primary one being that the normal call is faster. If a routine does not use KICKS services, and if the processing time for a routine is very small, and/or the number of times the routine must be called is very large, it may be more efficient to use a normal call despite LINK’s other advantages.
The first control transfer method we looked at was RETURN TRANSID, which causes a named transaction to be started the next time user input is available, and of course this ends up running whatever program is associated with the transaction.
The second control transfer method we (just) looked at was LINK, which causes the current program to be suspended, the named program to be run, and the suspended program to be resumed when the named program finishes. You could think of it as the KICKS version of a subroutine call.
There is a third control transfer method, that being XCTL, which causes the current program to be terminated, the named program to be run, and KICKS gains control again when the named program finishes. You could think of it as the KICKS version of a ‘go to’.
XCTL is often used to implement menus in pseudo-conversational systems. A ‘main’ program displays a screen with menu choices and when the user makes a selection it uses XCTL to transfer to another program to handle the logic of that selection. When the selection logic program has finished its interaction it can either RETURN TRANSID to get back to the menu, or perhaps just do another XCTL to get back to the menu.
Why not just use LINK/RETURN instead of this XCTLing around? Because using LINK/RETURN makes the application conversational if the LINK’d to program does any screen I/O (which it almost certainly will if the 1st screen was just a menu).
So the rule of thumb is: Use LINK for programs that will not do user interactions (like the startup/shutdown routines we looked at earlier). Use XCTL for any program that does do user interactions. Break the rule when you have already decided the application will be conversational.
You’ll find LINK is only occasionally used; most KICKS apps will rely on XCTL for the lion’s share of their control switching. Let’s look at an example. One of the sample systems that comes with KICKS is the ‘TAC’ system (programs with names starting with ‘TAC’ in the pds HERC01.KICKS.COB, maps similarly named in the pds HERC01.KICKS.MAPSRC. Its menu is the program TACMENU, initiated by the BTC0 transaction. When you start the transaction it displays a menu and does a RETURN TRANSID(BTC0) to get your response (which should be a PF key). When you press a PF key it starts again, gets your input, and dispatches another program based on the PF key you pressed – like this
...
IF CA-PFKEY EQUAL 1 THEN
EXEC CICS XCTL PROGRAM('TACARA')
COMMAREA(COMM-AREA) END-EXEC.
IF CA-PFKEY EQUAL 2 THEN
EXEC CICS XCTL PROGRAM('TACARR')
COMMAREA(COMM-AREA) END-EXEC.
IF CA-PFKEY EQUAL 3 THEN
EXEC CICS XCTL PROGRAM('TACARC')
COMMAREA(COMM-AREA) END-EXEC.
IF CA-PFKEY EQUAL 4 THEN
EXEC CICS XCTL PROGRAM('TACARD')
COMMAREA(COMM-AREA) END-EXEC.
GO TO DF-RETURN-CHECK.
...
Supposed you had pressed PF1. The program TACARA would be started with the same comm-area TACMENU was using. TACARA sends its own screen and does a RETURN TRANSID(BTC2). BTC2 being the transaction id associated with TACARA, so that when you press enter on that screen TACARA is restarted to read the screen and act on it. When it’s finished it does another XCTL to go back to the menu…
...
EXEC CICS XCTL PROGRAM('TACMENU') COMMAREA(COMM-AREA) END-EXEC.
...
Then TACMENU is immediately started with the same comm-area TACARA was using. TACMENU displays its menu again and does a RETURN TRANSID(BTC0) to get your response. The process continues until you enter the CLEAR key to finish, at which point TACMENU uses a RETURN without the TRANSID option to allow you to enter other transactions.
Another example that’s worth examining is ORDRENT. This program uses COBOL subroutine calls, LINK’s, and XCTL’s all in one program! This program is discussed in considerable detail in Murach's CICS for the COBOL Programmer.
ORDRENT uses COBOL subroutine calls for routines that do not use CICS services. It calls the NUMEDIT and INTEDIT subroutines to validate user numeric input.
ORDRENT uses LINK for routines that do use CICS services, but non-interactively (ie, no screen i/o). It LINK’s to the GETINV routine to obtain a new invoice number from a file and updating the file with the next invoice number. GETINV uses EXEC CICS READ and EXEC CICS REWRITE services for the file access.
ORDRENT uses XCTL when the routines will put up their own screens and interact with the user. When an error occurs, it XCTL’s to the SYSERR routine to display a message and quit.
You’ve seen how to prepare, compile and use simple KICKS COBOL programs. Not all COBOL programs are so simple! Real world applications involve the correct implementation of sophisticated business rules which invariably leads to complex user interactions and data structures.