IOF Rexx/Clist Tutorial, A Job Stream Control System
This newsletter contains examples of both a Rexx exec and a clist job control application which use the IOF programmable interface to JES2. The instructions, commands, and techniques used are described in detail. The resulting clist and Rexx exec are functionally identical. These examples provide both a simple tutorial and a useful tool. Click here to see a downloadable version of the executable CLIST and/or the REXX EXEC.
The IOF User Guide, Chapter 18 documents the clist and Rexx programmable interface. Refer to this document for specific command syntax and additional examples.
For example, if the first job runs with all return codes of zero,
the second job will be released to run. The second job will
release the third job if it has all return codes of zero. If any
job has any non-zero return codes, then the remaining jobs in the
job stream are canceled.
Two new catalogued procedures are used:
Each of the jobs in the job stream to be controlled will be held
by using the TYPRUN=HOLD parm on the JOB statement. The first
job either will be RELEASED by an operator to start the job
stream, or it will be submitted without being held. Then, it
will either RELEASE or CANCEL the second job (and perhaps
additional jobs) based on return codes. This is accomplished by
adding new RELEASE and/or CANCEL step(s) to the first job. The
new steps can be added to other jobs in the jobstream as required
by the application.
For example, if the first job runs with all return codes of zero, the second job will be released to run. The second job will release the third job if it has all return codes of zero. If any job has any non-zero return codes, then the remaining jobs in the job stream are canceled.
Two new catalogued procedures are used:
Job TSTJS01 will release job TSTJS02 if it runs successfully, or cancel all jobs with jobnames beginning TSTJS if it has any non- zero return codes. Job TSTJS02 will release TSTJS03 if it runs successfully, and cancel TSTJS03 if it has any non-zero return codes.
//TSTJS01 JOB .... // ..... one or more job steps //REL2 EXEC IOFJBREL,JOBNAME=TSTJS02,COND=(0,NE) //CAN2 EXEC IOFJBCAN,JOBNAME=TSTJS*,COND=(0,GT) // //TSTJS02 JOB ....,TYPRUN=HOLD // ..... one or more job steps //REL3 EXEC IOFJBREL,JOBNAME=TSTJS03,COND=(0,NE) //CAN3 EXEC IOFJBCAN,JOBNAME=TSTJS03,COND=(0,GT) // //TSTJS03 JOB ....,TYPRUN=HOLD // ..... one or more job steps //
The clist has 2 positional parms:
The first section of the clist checks input parms and does other
required initialization. The initializaion statements are shown
This application is slightly easier to develop in clist than in
Rexx, so the clist example is given first. The clist will be
explained section by section. If you prefer to see the whole
clist without interspersed comments, please
download the executable clist and
refer to the downloaded copy.
The clist has 2 positional parms:
The first section of the clist checks input parms and does other required initialization. The initializaion statements are shown below.
PROC 2 FUNCTION /* Function. RELEASE or CANCEL */+ JOB_NAME /* Name of job to release or cancel */+ TEST /* Trace CLIST if specified */ CONTROL END(ENDO) NOFLUSH ASIS IF &TEST = TEST THEN CONTROL LIST CONLIST SELECT WHEN (&FUNCTION = CANCEL) SET ACTION = Canceling WHEN (&FUNCTION = RELEASE) DO SET FUNCTION = A SET ACTION = Releasing ENDO OTHERWISE DO SET FUNCTION = '' SET ACTION = Found ENDO ENDO ..... .....
Next, the IOF command is issued to get a list of HELD INPUT jobs owned by the current user. See the IOF User Guide, Chapter 5 for a complete description of the IOF command. The command used in this example has the following parms:
IOF Command name. &JOB_NAME the jobname input parm. JOBLIST display a job list menu, even if there are no matching jobs. INPUT select only input jobs. SELECT(HELD) select only HELD jobs. SCOPE(ME) select only jobs submitted by the owner of the current job. CLIST invoked from a clist so no IOF panels are displayed until the clist terminates.
..... ..... /* Issue IOF command to get a list of HELD INPUT JOBS with matching */ /* JOBNAME. Only get jobs submitted by this user. */ IOF &JOB_NAME JOBLIST INPUT SELECT(HELD) SCOPE(ME) CLIST ..... .....
Subsequent commands will be processed by IOF. Clists switch from the batch TSO environment to the IOF environment easily, which is why this application is easier to implement in clist than in Rexx.
If you entered the command above (minus the CLIST parm) from you TSO terminal, the IOF Job List Menu would be displayed. Logically, the same procedure occurs when running under a clist (or Rexx exec), except that no display is produced. Instead, the necessary variables are assigned to clist variables, and the clist makes the decisions you would normally make manually at the terminal.
The first thing we need to know is how many jobs were found. If no jobs were found, then we simply exit the clist with a message. The TSICOPY command is use to retrieve internal IOF information to clist (and Rexx) variables. The variable ROWS is the number of rows on the (logical) screen. There is one row on the screen for each displayed job, so ROWS also contains the number of jobs that were found.
..... ..... /* How many jobs were found? Variable ROWS will contain the number */ /* of rows on the screen, which is the number of jobs found */ TSICOPY NAME(ROWS) TO(CLIST) SECTION(PANEL) /* EXTEND the display so that extended fields are accessible */ EXTEND /* If no jobs were found, give error message */ IF &ROWS = 0 THEN + WRITE &JOB_NAME is not a held input job, &FUNCTION not done ..... .....
Assuming one or more jobs were found, we will either RELEASE or CANCEL each found job depending upon the input function specified. In addition, we will write a message saying what was done.
Remember that IOF panels have a menu number assigned to each item on the panel. On the Job List Menu the top job has menu number 1, the second job has menu number 2, etc. An alternate way to issue an IOF line command is to enter a menu number followed by the line command in the COMMAND input area. For example, entering 5C in the COMMAND area has the same meaning as entering C to the left of the fifth job on the menu.
All clist (and Rexx) IOF line commands must use the menu number form.
There is a line mode TSICOPY command as well as the normal panel line commands. Continuing the example clist, several variables will be fetched for each found job using the TSICOPY line command. These variables are used to build a message for each job that is released or canceled.
..... ..... ELSE DO MENUNBR = 1 TO &ROWS /* Retrieve the jobname, jobid, etc for job with current MENUNBR */ &MENUNBR TSICOPY NAME(JOBNAME JOBID OWNER USERNAME RAN) TO(CLIST) /* Format CANCELING or RELEASING message and issue it */ SET JOBNAME = &JOBNAME SET OWNER = &OWNER SET USERNAME= &USERNAME WRITE &ACTION job &JOBNAME(&JOBID) submitted by &OWNER + &USERNAME at &RAN ..... .....
Next, issue the RELEASE or CANCEL command for each job using the menu number followed by the "A" or "CANCEL" command which is in variable &FUNCTION.
..... ..... /* CANCEL or RELEASE the current job at row "MENUNBR" */ IF &FUNCTION NE '' THEN DO &MENUNBR &FUNCTION ..... .....
Check the return code of the RELEASE or CANCEL command. If there is an error, fetch the IOF error message text and write it out.
..... ..... /* Check Return Code. If non-zero, issue IOF error message and */ /* force return code 4. */ IF &LASTCC NE 0 THEN DO TSICOPY NAME(MESSAGE) SECTION(PANEL) TO(CLIST) WRITE *** ERROR *** &MESSAGE SET ROWS = 0 ENDO /* End Return Code check */ ENDO /* End RELEASE/CANCEL one job */ ENDO /* End RELEASE/CANCEL loop */ ..... .....
Finally, terminate the IOF command and give a return code of 0 or 4 to batch TSO. The JUMP command logically jumps to the IOF Option Menu where the X (exit) option is executed.
..... ..... /* Exit from IOF */ JUMP X /* Exit with return code: 0 - jobname found 4 - not found */ IF &ROWS = 0 THEN EXIT CODE(4) ELSE EXIT CODE(0)
Click here to view and/or download the executable version of the IOFRELCN clist.
Each section of the Rexx exec will be explained in detail.
Download the executable copy and
if you prefer to see the complete exec without additional
IOFRELCN Rexx Exec
The Rexx version of IOFRELCN has identical input parms as the
clist version and functions the same. Most of the instructions
are comparable as well, and the clist descriptions of IOF
functions apply directly to the Rexx implementation. However, a
single Rexx exec can not switch environments. A new exec must be
invoked whenever the environment changes from batch TSO to IOF
and back. We chose to handle these switches in a single Rexx
exec that checks the environment and takes the appropriate
action. A new RETURNCODE function is defined to pass the final
return code back to the batch TSO session.
Each section of the Rexx exec will be explained in detail. Download the executable copy and if you prefer to see the complete exec without additional comments.
/* Parse input parm to get jobname or "RETURNCODE" */ parse arg Function Job_Name TestParm if TestParm = 'TEST' then trace 'R' /* If parm is "RETURNCODE" then exit with the return code */ /* This is a trick to get the return code back to the batch job */ if Function = 'RETURNCODE' then exit Job_Name /* Job_name parm is return code */ ..... .....
If the function is not RETURNCODE, check the environment. If the environment is not IOF, PUSH the IOF command onto the STACK and EXIT. The Rexx exec issues the same IOF command that the clist issued but must add a concatenated string to re-invoke itself in order to switch environments.
..... ..... /* Check the environment. If not in the IOF environment then PUSH */ /* the IOF command to select HELD INPUT jobs matching the specified */ /* jobname. Only select jobs that were submitted (owned) by the */ /* current user. Exit this exec and re-enter in IOF environment. */ parse source . . MyName . . . . . env . if env <> 'IOF' then do push 'IOF' Job_Name, 'INPUT SELECT(HELD) SCOPE(ME) JOBLIST.%'MyName Function Job_Name exit end ..... .....
The exec is re-entered in the IOF environment. The logic at this point is identical to the clist logic:
..... ..... /* Analyze the requested Function */ Select When Function = 'CANCEL' then Action = 'Canceling' When Function = 'RELEASE' then do Function = 'A' /* Change function to IOF Release line cmd */ Action = 'Releasing' end Otherwise do Action = 'Found' Function = 'FIND' end end address IOF /* How many jobs were found. Variable ROWS will contain the number */ /* of rows on the screen, which is the number of jobs found */ 'TSICOPY NAME(ROWS) TO(REXX) SECTION(PANEL)' /* EXTEND the display so that extended fields are accessible */ 'EXTEND' /* If no jobs were found, give error message */ if rows = 0 then say Job_Name 'is not a held input job,' Function 'not done' /* Issue a message for each found job, then CANCEL or RELEASE */ else do menu_nbr = 1 to rows /* Retrieve the jobname, jobid, etc for job with "menu_nbr" */ menu_nbr 'TSICOPY NAME(JOBNAME JOBID OWNER USERNAME RAN) TO(REXX)' /* Format CANCELING or RELEASING message and issue it */ jobname = strip(jobname) owner = strip(owner) username= strip(username) say Action 'job' jobname'('jobid') submitted by' owner, username 'at' ran /* CANCEL or RELEASE the current job at row "menu_number" */ if Function \= 'FIND' then do menu_nbr Function /* Check return code of the RELEASE or CANCEL. If non-zero then */ /* issue the IOF error message and force return code 4 on exit */ if rc \= 0 then do 'TSICOPY NAME(MESSAGE) TO(REXX) SECTION(PANEL)' say '*** Error ***' message rows = 0 end end ..... .....
Finally, terminate IOF. In order to give a return code to batch TSO, we must re-invoke the exec with the RETURNCODE function described above.
..... ..... /* Exit from IOF */ 'JUMP X' /* Set the return code: 0 - jobname found 4 - not found */ if rows = 0 then retcod = 4 else retcod = 0 /* Re-invoke the exec to give the return code to the batch job */ push '%'MyName 'RETURNCODE' retcod 'JUMP X' exit
Click here to view and/or download the executable version of the IOFRELCN Rexx exec.
Cataloged ProceduresEnd users execute the IOFJBREL and IOFJBCAN catalogued procedures
(or whatever you decide to name them) to interface to IOFRELCN.
Both these procedures invoke the IOFRELCN clist or exec. The
choice of using a clist or exec depends on which version you copy
to your SYSPROC or SYSEXEC library. The sample procedures below
show a SYSPROC DD statement. Both clists and Rexx execs can
reside in SYSPROC. If you chose to use the Rexx version, you can
use a SYSEXEC DD statement instead of SYSPROC.
//IOFJBREL PROC JOBNAME= //* //* Release HELD INPUT JOB sample catalogued procedure //* Specify the name of the job to be released in the JOBNAME parm //* //RELEASE EXEC PGM=IKJEFT1B,PARM='%IOFRELCN RELEASE &JOBNAME' //SYSPROC DD DISP=SHR,DSN=your.clist.library //SYSTSPRT DD SYSOUT=* //SYSTSIN DD DUMMY //* // PEND
//IOFJBCAN PROC JOBNAME= //* //* Cancel HELD INPUT JOB sample catalogued procedure //* Specify the name of the job to be canceled in the JOBNAME parm //* //CANCEL EXEC PGM=IKJEFT1B,PARM='%IOFRELCN CANCEL &JOBNAME' //SYSPROC DD DISP=SHR,DSN=your.clist.library //SYSTSPRT DD SYSOUT=* //SYSTSIN DD DUMMY //* // PEND
The IOF Programmable Interface is a very powerful
automation tool. Any IOF function that can be done by a user at
a TSO terminal can be accomplished by a clist or Rexx exec from
either TSO or batch TSO. Additional tutorial examples of useful
clists/execs will be given in future newsletters.
SummaryThe cataloged procedures, clist, and Rexx exec shown here can be
run unmodified to do the release and/or cancel function
described. These functions can be modified as needed to meet
your local requirements. The descriptions hopefully are adequate
to allow you to tailor these functions as required.
The IOF Programmable Interface is a very powerful automation tool. Any IOF function that can be done by a user at a TSO terminal can be accomplished by a clist or Rexx exec from either TSO or batch TSO. Additional tutorial examples of useful clists/execs will be given in future newsletters.