November 1998
Newsletter

IOFTech    Maintenance   Release8G       Newsletters    Doc    FAQ    Contact    Home

IOF Rexx/Clist Tutorial, A Job Stream Control System

Topics

Introduction

Did you ever need to run several batch jobs that were required to execute in a prescribed order? Wouldn't you like to be able to submit them all at once and then automatically control the order in which they execute? Or, perhaps automatically control which jobs run based on return codes of previous jobs?

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.

Application Specifications

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:

Both procedures require a JOBNAME parm. All jobs submitted by the OWNER of the current job with a matching jobname will be either released or canceled, depending upon the procedure used. Generic jobnames are permitted.

Example.
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
   //
Sample Job Stream

IOFRELCN Clist

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
    .....
    .....
Clist Initialization

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

    .....
    .....
The IOF Command

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
    .....
    .....

Determining the Number of Jobs Found

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

    .....
    .....

Building Messages for Each Job

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
    .....
    .....

Cancel or Release Jobs

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         */
    .....
    .....

Checking the Return Code

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)
Terminating the Clist

Click here to view and/or download the executable version of the IOFRELCN clist.

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            */
    .....
    .....

Rexx Exec Initialization

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
    .....
    .....
Checking the Environment

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
    .....
    .....
Process Each Job

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
Terminate the IOF Rexx Exec

Click here to view and/or download the executable version of the IOFRELCN Rexx exec.

Cataloged Procedures

End 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

IOFJBREL Cataloged Procedure

//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

IOFJBCAN Cataloged Procedure

Summary

The 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.


Triangle Systems, Inc. PO Box 12752, Research Triangle Park, NC 27709
Email
IOFTech@Triangle-Systems.Com