CL as a Never Ending Program

This is an example of a NEP written in CL.

NEP job stream CLP

There are time when it is desirable to create a Never Ending Program (NEP), a process that runs until instructed to quit. Here is an example that begins to monitor IFS folders for files to translate to DDB2 file data. The job delays at regular intervals until it receives instructions to stop.

Automated Data Mover

This program can function as a single pass, or as a NEP. If intended to run as a NEP the job will be submitted to a batch job queue. It may be run interactively, but it will make a single pass, and then exit. The multiple program calls use programs to retrieve control values from a database file to direct actions within the NEP. The program starts, checks the folder where data is expected (the import folder) and directs the data to the proper location. When it finishes the tasks, it checks to determine if it should exit, or wait until it is time to check for data again.

/*********************************************************************/
/* Program Name - ADM010CL                                           */
/*                                                                   */
/* Function     - This program was designed as a NEP to monitor and  */
/*                process inbound order data.                        */
/*                                                                   */
/* Programmer   - Steve Croy                      xx/xx/xxxx         */
/*********************************************************************/
/*********************************************************************/
/*                   Modification log                                */
/*                                                                   */
/*   Date    Programmer      Description                             */
/* xx/xx/xx  xxxxxxxxxxxx    xxxxxxxxxxxxxxx                         */
/*********************************************************************/
             PGM        PARM(&NEP)
             DCL        VAR(&NEP) TYPE(*CHAR) LEN(1)
             DCL        VAR(&IMPFOLDER) TYPE(*CHAR) LEN(128)
             DCL        VAR(&ARCFOLDER) TYPE(*CHAR) LEN(128)
             DCL        VAR(&LIBFILE) TYPE(*CHAR) LEN(128)
             DCL        VAR(&LIB) TYPE(*CHAR) LEN(10)
             DCL        VAR(&FILE) TYPE(*CHAR) LEN(10)
             DCL        VAR(&exit) TYPE(*CHAR) LEN(4)
             DCL        VAR(&SECONDS) TYPE(*DEC) LEN(3)
             DCL        VAR(&SECONDA) TYPE(*CHAR) LEN(3)
             DCL        VAR(&MSGKEY) TYPE(*CHAR) LEN(4)
             DCL        VAR(&PGMNAME) TYPE(*CHAR) LEN(10)
             DCL        VAR(&PROGRAM) TYPE(*CHAR) LEN(10)
             DCL        VAR(&SENDER) TYPE(*CHAR) LEN(80)
             DCL        VAR(&FILEPATH) TYPE(*CHAR) LEN(128)
             DCL        VAR(&RETURN) TYPE(*CHAR) LEN(128)
             DCL        VAR(&DB2FILE) TYPE(*CHAR) LEN(128)
             DCL        VAR(&SYSLIB) TYPE(*CHAR) LEN(15) +
                          VALUE('/QSYS.LIB/')
             DCL        VAR(&QLIB) TYPE(*CHAR) LEN(5) +
                          VALUE('.LIB/')
             DCL        VAR(&QFIL) TYPE(*CHAR) LEN(6) +
                          VALUE('.FILE/')
             DCL        VAR(&QMBR) TYPE(*CHAR) LEN(5) +
                          VALUE('.MBR/')
             DCL        VAR(&JOBTYPE) TYPE(*CHAR) LEN(1)

             RTVJOBA    TYPE(&JOBTYPE)
             IF         COND(&JOBTYPE *EQ '1' *AND &NEP *EQ '1') +
                          THEN(DO)
             SBMJOB     CMD(CALL PGM(ADM010CL) PARM('1')) JOB(ADM010CL)
             GOTO TERMINATE
             ENDDO
/*-------------------------------------------------------------------*/
/* Get the program name                                              */
/*-------------------------------------------------------------------*/
             SNDPGMMSG  MSG(' ') TOPGMQ(*SAME) MSGTYPE(*INFO) +
                          KEYVAR(&MSGKEY)
             RCVMSG     PGMQ(*SAME) MSGTYPE(*INFO) RMV(*YES) +
                          SENDER(&SENDER)
             CHGVAR     VAR(&PGMNAME) VALUE(%SST(&SENDER 56 10))

INITIATE:
             IF         COND(&NEP *EQ '0') THEN(GOTO CMDLBL(IMPORT))
/*-------------------------------------------------------------------*/
/* Check to see if the program should quit                           */
/*-------------------------------------------------------------------*/
 CHECKEXIT:  CALL       PGM(ADM005RP) PARM(&PGMNAME 'EXIT' &RETURN)
             IF         COND(&RETURN *EQ 'EXIT') THEN(GOTO +
                          CMDLBL(TERMINATE))
/*-------------------------------------------------------------------*/
/* Get the folder where the IFS file is stored                       */
/*-------------------------------------------------------------------*/
 IMPORT:
             CALL       PGM(ADM005RP) PARM(&PGMNAME 'IMPORT' +
                          &IMPFOLDER)
/*-------------------------------------------------------------------*/
/* Get the folder where the IFS file is to be archived               */
/*-------------------------------------------------------------------*/
 ARCHIVE:
             CALL       PGM(ADM005RP) PARM(&PGMNAME 'ARCHIVE' +
                          &ARCFOLDER)
/*-------------------------------------------------------------------*/
/* Get file name to use to convert the web data                      */
/*-------------------------------------------------------------------*/
 DB2FILE:
             CALL       PGM(ADM005RP) PARM(&PGMNAME 'DB2FILE' &LIBFILE)

             CHGVAR     VAR(&LIB) VALUE(%SST(&LIBFILE 1 10))
             CHGVAR     VAR(&FILE) VALUE(%SST(&LIBFILE 11 10))
             CHGVAR     VAR(&DB2FILE) VALUE(&SYSLIB *TCAT &LIB *TCAT +
                          &QLIB *TCAT &FILE *TCAT &QFIL *TCAT &FILE +
                          *TCAT &QMBR)
/*-------------------------------------------------------------------*/
/* Create a list of files in the folder                              */
/*-------------------------------------------------------------------*/
LIST:
             CALL       PGM(ADM010RP) PARM(&IMPFOLDER)
/*-------------------------------------------------------------------*/
/* Get the library and file as the target of the copy function.      */
/*-------------------------------------------------------------------*/
READ:
             CALL       PGM(ADM020RP) PARM(&FILEPATH)
             IF         COND(&FILEPATH *NE '*****') THEN(DO)

             CPYFRMSTMF FROMSTMF(&FILEPATH) TOMBR(&DB2FILE) +
                          MBROPT(*REPLACE)
/*-------------------------------------------------------------------*/
/* Retrieve the translate program name.                              */
/*-------------------------------------------------------------------*/
 XLATEPGM:
             CALL       PGM(ADM005RP) PARM(&file 'XLATE' +
                          &RETURN)

             CHGVAR     VAR(&PROGRAM) VALUE(%SST(&RETURN 1 10))

             CALL       PGM(&PROGRAM)

             MOVE       OBJ(&FILEPATH) TODIR(&ARCFOLDER) DTAFMT(*TEXT)
             GOTO       CMDLBL(READ)
             ENDDO

             IF         COND(&NEP *EQ '0') THEN(GOTO CMDLBL(TERMINATE))
 GETDELAY:
             CALL       PGM(ADM005RP) PARM(&PGMNAME 'DELAY' +
                          &RETURN)

             CHGVAR     VAR(&SECONDA) VALUE(%SST(&RETURN 1 3))
             CHGVAR     VAR(&SECONDS) VALUE(&SECONDA)

             DLYJOB     DLY(&SECONDS)
             GOTO       CMDLBL(INITIATE)

TERMINATE:

ENDPGM

Editor NEP

This program was designed to edit the inbound data. Like the data mover, it wakes at regular intervals to determine if there is any data to editor. It checks the incoming data for errors and completness. Errors will be flagged. If there are no errors it will forward the data to the translator. After checking for data to edit it tests whether a request to exit has been issued.

/*********************************************************************/
/* Program Name - ADM350CL                                           */
/*                                                                   */
/* Function     - This program was designed call the order editor    */
/*                for the Automated Data Mover system                */
/*                                                                   */
/* Programmer   - Steve Croy                      99/99/9999         */
/*********************************************************************/
/*********************************************************************/
/*                   Modification log                                */
/*                                                                   */
/*   Date    Programmer      Description                             */
/*********************************************************************/
             PGM        PARM(&NEP)
             DCL        VAR(&NEP) TYPE(*CHAR) LEN(1)
             DCL        VAR(&JOBTYPE) TYPE(*CHAR) LEN(1)
             DCL        VAR(&exit) TYPE(*CHAR) LEN(4)
             DCL        VAR(&SECONDS) TYPE(*DEC) LEN(3)
             DCL        VAR(&SECONDA) TYPE(*CHAR) LEN(3)
             DCL        VAR(&MSGKEY) TYPE(*CHAR) LEN(4)
             DCL        VAR(&PGMNAME) TYPE(*CHAR) LEN(10)
             DCL        VAR(&PROGRAM) TYPE(*CHAR) LEN(10)
             DCL        VAR(&SENDER) TYPE(*CHAR) LEN(80)
             DCL        VAR(&RETURN) TYPE(*CHAR) LEN(128)
             RTVJOBA    TYPE(&JOBTYPE)

             IF         COND(&JOBTYPE *EQ '1') THEN(DO)
             SBMJOB     CMD(CALL PGM(ADM350CL) PARM(&NEP)) +
                          JOB(ADM350CL)
             GOTO TERMINATE
             ENDDO
/*-------------------------------------------------------------------*/
/* Get the program name                                              */
/*-------------------------------------------------------------------*/
             SNDPGMMSG  MSG(' ') TOPGMQ(*SAME) MSGTYPE(*INFO) +
                          KEYVAR(&MSGKEY)
             RCVMSG     PGMQ(*SAME) MSGTYPE(*INFO) RMV(*YES) +
                          SENDER(&SENDER)
             CHGVAR     VAR(&PGMNAME) VALUE(%SST(&SENDER 56 10))
INITIATE:
/*-------------------------------------------------------------------*/
/* Check to see if the program should quit                           */
/*-------------------------------------------------------------------*/
 CHECKEXIT:  CALL       PGM(ADM005RP) PARM(&PGMNAME 'EXIT' &RETURN)
             IF         COND(&RETURN *EQ 'EXIT') THEN(GOTO +
                          CMDLBL(TERMINATE))

/*-------------------------------------------------------------------*/
/* Check to see if any pending orders should be split                */
/* Orders with both 01 and 05 frames will be split into separate     */
/* orders. Orders with 02 and 04 frames will also be split.          */
/*-------------------------------------------------------------------*/
SPLIT:
             CALL       PGM(ADM005RP) PARM(&PGMNAME 'SPLIT' +
                          &RETURN)
             IF         COND(%SST(&RETURN 1 3) *EQ 'YES') THEN(CALL +
                          PGM(ADM325RP))
             ELSE       CMD(CALL PGM(ADM326RP))
EDIT:
             CALL       PGM(ADM350RP)
             IF         COND(&NEP *EQ '0') THEN(GOTO CMDLBL(TERMINATE))

 GETDELAY:
             CALL       PGM(ADM005RP) PARM(&PGMNAME 'DELAY' +
                          &RETURN)

             CHGVAR     VAR(&SECONDA) VALUE(%SST(&RETURN 1 3))
             CHGVAR     VAR(&SECONDS) VALUE(&SECONDA)

             DLYJOB     DLY(&SECONDS)
             GOTO       CMDLBL(INITIATE)

TERMINATE:

ENDPGM

Tranlator NEP

This NEP program functions as a translation process. Inbound data is stored in a standard format. This process examines the data received and maps the data to the prodcution database format. Like the mover and the editor, it wakes periodically to determine if there is data needing translation. It performs the task, then tests to see if it should exit or continue working.

/*********************************************************************/
/* Program Name - ADM400CL                                           */
/*                                                                   */
/* Function     - This program was designed call the order XLATE     */
/*                for the Automated Data Mover system                */
/*                                                                   */
/* Programmer   - Steve Croy                      99/99/9999         */
/*********************************************************************/
/*********************************************************************/
/*                   Modification log                                */
/*                                                                   */
/*   Date    Programmer      Description                             */
/* xx/xx/xx  xxxxxxxxxxxx    xxxxxxxxxxxxxxx                         */
/*********************************************************************/
             PGM        PARM(&NEP)
             DCL        VAR(&NEP) TYPE(*CHAR) LEN(1)
             DCL        VAR(&JOBTYPE) TYPE(*CHAR) LEN(1)
             DCL        VAR(&exit) TYPE(*CHAR) LEN(4)
             DCL        VAR(&SECONDS) TYPE(*DEC) LEN(3)
             DCL        VAR(&SECONDA) TYPE(*CHAR) LEN(3)
             DCL        VAR(&MSGKEY) TYPE(*CHAR) LEN(4)
             DCL        VAR(&PGMNAME) TYPE(*CHAR) LEN(10)
             DCL        VAR(&PROGRAM) TYPE(*CHAR) LEN(10)
             DCL        VAR(&SENDER) TYPE(*CHAR) LEN(80)
             DCL        VAR(&RETURN) TYPE(*CHAR) LEN(128)
             RTVJOBA    TYPE(&JOBTYPE)

             IF         COND(&JOBTYPE *EQ '1') THEN(DO)
             SBMJOB     CMD(CALL PGM(ADM400CL) PARM(&NEP)) +
                          JOB(ADM400CL)
             GOTO TERMINATE
             ENDDO
/*-------------------------------------------------------------------*/
/* Get the program name                                              */
/*-------------------------------------------------------------------*/
             SNDPGMMSG  MSG(' ') TOPGMQ(*SAME) MSGTYPE(*INFO) +
                          KEYVAR(&MSGKEY)
             RCVMSG     PGMQ(*SAME) MSGTYPE(*INFO) RMV(*YES) +
                          SENDER(&SENDER)
             CHGVAR     VAR(&PGMNAME) VALUE(%SST(&SENDER 56 10))
INITIATE:
/*-------------------------------------------------------------------*/
/* Check to see if the program should quit                           */
/*-------------------------------------------------------------------*/
 CHECKEXIT:  CALL       PGM(ADM005RP) PARM(&PGMNAME 'EXIT' &RETURN)
             IF         COND(&RETURN *EQ 'EXIT') THEN(GOTO +
                          CMDLBL(TERMINATE))

EDIT:
             CALL       PGM(ADM400RP)
             IF         COND(&NEP *EQ '0') THEN(GOTO CMDLBL(TERMINATE))

 GETDELAY:
             CALL       PGM(ADM005RP) PARM(&PGMNAME 'DELAY' +
                          &RETURN)

             CHGVAR     VAR(&SECONDA) VALUE(%SST(&RETURN 1 3))
             CHGVAR     VAR(&SECONDS) VALUE(&SECONDA)

             DLYJOB     DLY(&SECONDS)
             GOTO       CMDLBL(INITIATE)

TERMINATE:

ENDPGM