Wednesday, May 21, 2014

Capturing messages from Jar

java jar addenvvar rmvenvvar

In November I described how it was possible to zip files in the IFS using the Jar java command. John King emailed me to inform me that there is a way to monitor messages coming from QShell by using the environment variables QIBM_QSH_CMD_OUTPUT and QIBM_QSH_CMD_ESCAPE_MSG.

I am going to use the same example I used before. I have a file testfile.csv that I want to zip using the Jar. And then I will do the opposite and unzip the zipped file using the Jar. All of these files will be in my folder in the IFS called MyFolder.

To be able to make the QShell monitor-able I need to define the two environmental variables.

08    RMVENVVAR  ENVVAR(QIBM_QSH_CMD_OUTPUT)
09    MONMSG     MSGID(CPFA981)

10    RMVENVVAR  ENVVAR(QIBM_QSH_CMD_ESCAPE_MSG)
11    MONMSG     MSGID(CPFA981)

12    ADDENVVAR  ENVVAR(QIBM_QSH_CMD_OUTPUT) VALUE(NONE)
13    ADDENVVAR  ENVVAR(QIBM_QSH_CMD_ESCAPE_MSG) VALUE(Y)

On lines 8 and 10 I remove any existing values/definitions for environmental values. If they have not been defined in this job then the MONMSG, lines 9 and 11, will stop the program from erroring out.

Then I add the environmental values on lines 12 and 13.

I have passed the value of ‘NONE’ to QIBM_QSH_CMD_OUTPUT, line 12, as I do not want the STDOUT output or to output to an outfile, ‘FILE’.

I have passed the value of ‘Y’ to QIBM_QSH_CMD_ESCAPE_MSG, line 13, to ensure that the QSH0005 message is sent as an escape message if the exit status was successful and QSH0006 or QSH0007 is it was not.

Now for the rest of the program:

14    DEL        OBJLNK('MyFolder/zipfile.zip')
15    MONMSG     MSGID(CPFA0A9)

16    CHGVAR     VAR(&CMD) VALUE('Jar cfM MyFolder/zipfile.zip +
                     MyFolder/testfile.csv')

17    CALLSUBR   SUBR(SUBR_1)

18    DEL        OBJLNK('MyFolder/testfile.csv')
19    MONMSG     MSGID(CPFA0A9)

20    CHGVAR     VAR(&CMD) VALUE('Jar xf MyFolder/zipfile.zip +
                          MyFolder/testfile.csv')
21    CALLSUBR   SUBR(SUBR_1)
/*==============================================================*/
22   SUBR       SUBR(SUBR_1)
23     CHGVAR VAR(&ERROR) VALUE('0')

24     STRQSH CMD(&CMD)
25     MONMSG MSGID(QSH0005 QSH0006 QSH0007) +
                EXEC(CHGVAR VAR(&ERROR) VALUE('1'))

26     IF COND(&ERROR = '0') THEN(RTNSUBR)

27     RCVMSG MSGTYPE(*LAST) RMV(*YES) MSGDTA(&MSGDTA) +
                MSGID(&MSGID)

28     SELECT
     /* QSH0005 - ended normally */
29       WHEN COND(&MSGID = 'QSH0005') THEN(DO)
30         CHGVAR VAR(&RESULT) VALUE(%SST(&MSGDTA 1 4))
31         CHGVAR VAR(&STATUS) VALUE(%BIN(&RESULT))
          ENDDO
     /* QSH0006 - ended when it received a signal */
32       WHEN COND(&MSGID = 'QSH0006') THEN(DO)
33         CHGVAR VAR(&RESULT) VALUE(%SST(&MSGDTA 1 4))
34         CHGVAR VAR(&STATUS) VALUE(%BIN(&RESULT))
35        ENDDO
    /* QSH0007 - ended due to exception (pgm crash) */
36       WHEN COND(&MSGID = 'QSH0007') THEN(DO)
37         CHGVAR VAR(&STATUS) VALUE(-1)
38        ENDDO
39     ENDSELECT

40     IF COND(&STATUS *NE 0) THEN(+
41        SNDPGMMSG MSGID(CPF9897) MSGF(QCPFMSG) +
            MSGDTA('Call to QSHELL ''' || &CMD |< +
                   ''' encountered errors'))
42   ENDSUBR
/*==============================================================*/
43   ENDPGM

On line 14 I delete the zip file.

I move the Jar I want to execute to a variable &CMD on line 15.

I then call the subroutine, line 17, to perform the Jar and perform error checking. Click on this link to learn more about subroutines in CL.

I execute the Jar command, on line 24, in the field &CMD. As I have define the environmental variables I can monitor for the QShell error codes QSH0005, QSH0006, and QSH0007, on line 25.

On line 27 I use the RCVMSG command to receive/retrieve the details of the previous message issued in this job.

Rather than use nested If statements I have used a Select group in lines 28–39. To learn about the Select group in CL read Select in CL.

Depending on the message id I get the status of the message received/retrieved on lines 30-31, 33-34, or in the case of QSH0007 I hard code in a negative value. This status is then used to condition a message, on line 41, to tell the user that the Jar encountered errors.

On lines 18 – 21 I take the zip file and extract the file from it.

Below is the program in its entirety:

01    PGM

02    DCL        VAR(&CMD) TYPE(*CHAR) LEN(3000)
03    DCL        VAR(&ERROR) TYPE(*LGL)
04    DCL        VAR(&MSGDTA) TYPE(*CHAR) LEN(256)
05    DCL        VAR(&MSGID) TYPE(*CHAR) LEN(7)
06    DCL        VAR(&RESULT) TYPE(*CHAR) LEN(4)
07    DCL        VAR(&STATUS) TYPE(*DEC) LEN(10 0)

08    RMVENVVAR  ENVVAR(QIBM_QSH_CMD_OUTPUT)
09    MONMSG     MSGID(CPFA981)

10    RMVENVVAR  ENVVAR(QIBM_QSH_CMD_ESCAPE_MSG)
11    MONMSG     MSGID(CPFA981)

12    ADDENVVAR  ENVVAR(QIBM_QSH_CMD_OUTPUT) VALUE(NONE)
13    ADDENVVAR  ENVVAR(QIBM_QSH_CMD_ESCAPE_MSG) VALUE(Y)

14    DEL        OBJLNK('MyFolder/zipfile.zip')
15    MONMSG     MSGID(CPFA0A9)

16    CHGVAR     VAR(&CMD) VALUE('Jar cfM MyFolder/zipfile.zip +
                     MyFolder/testfile.csv')

17    CALLSUBR   SUBR(SUBR_1)

18    DEL        OBJLNK('MyFolder/testfile.csv')
19    MONMSG     MSGID(CPFA0A9)

20    CHGVAR     VAR(&CMD) VALUE('Jar xf MyFolder/zipfile.zip +
                          MyFolder/testfile.csv')
21    CALLSUBR   SUBR(SUBR_1)
/*==============================================================*/
22   SUBR       SUBR(SUBR_1)
23     CHGVAR VAR(&ERROR) VALUE('0')

24     STRQSH CMD(&CMD)
25     MONMSG MSGID(QSH0005 QSH0006 QSH0007) +
                EXEC(CHGVAR VAR(&ERROR) VALUE('1'))

26     IF COND(&ERROR = '0') THEN(RTNSUBR)

27     RCVMSG MSGTYPE(*LAST) RMV(*YES) MSGDTA(&MSGDTA) +
                MSGID(&MSGID)

28     SELECT
     /* QSH0005 - ended normally */
29       WHEN COND(&MSGID = 'QSH0005') THEN(DO)
30         CHGVAR VAR(&RESULT) VALUE(%SST(&MSGDTA 1 4))
31         CHGVAR VAR(&STATUS) VALUE(%BIN(&RESULT))
          ENDDO
     /* QSH0006 - ended when it received a signal */
32       WHEN COND(&MSGID = 'QSH0006') THEN(DO)
33         CHGVAR VAR(&RESULT) VALUE(%SST(&MSGDTA 1 4))
34         CHGVAR VAR(&STATUS) VALUE(%BIN(&RESULT))
35        ENDDO
    /* QSH0007 - ended due to exception (pgm crash) */
36       WHEN COND(&MSGID = 'QSH0007') THEN(DO)
37         CHGVAR VAR(&STATUS) VALUE(-1)
38        ENDDO
39     ENDSELECT

40     IF COND(&STATUS *NE 0) THEN(+
41        SNDPGMMSG MSGID(CPF9897) MSGF(QCPFMSG) +
            MSGDTA('Call to QSHELL ''' || &CMD |< +
                   ''' encountered errors'))
42   ENDSUBR
/*==============================================================*/
43   ENDPGM

You can learn more about this from the IBM website:

 

This article was written for IBM i 7.1, and it should work with earlier releases too.

3 comments:

  1. Great information. The ADDENVVAR command has a REPLACE parameter, so if it's coded as ADDENVVAR ENVVAR(...) VALUE(...) REPLACE(*YES), then the RMVENVVAR (and the following MONMSG) command is not needed.

    Also, if the &RESULT variable is declared as a defined variable
    DCL VAR(&RESULT) TYPE(*INT) STG(*DEFINED) LEN(4) DEFVAR(&MSGDTA)
    then this
    CHGVAR VAR(&RESULT) VALUE(%SST(&MSGDTA 1 4))
    CHGVAR VAR(&STATUS) VALUE(%BIN(&RESULT))
    can be replace with this
    CHGVAR VAR(&STATUS) VALUE(&RESULT).


    ReplyDelete
  2. A couple observations about RCVMSG:

    1) MSGTYPE(*EXCP) could also be used. By definition this receives the last (most recent) exception message.

    2) The default for RMV is *YES, so this parameter could be omitted. However if there is a failure, leaving the exception message in the job log may aid in problem determination later. This could be done with a combination of RMV(*NO) and capturing the message key via KEYVAR. Then later, when no failure is detected, the message can be removed using RMVMSG and the message key.


    DCL VAR(&MSGKEY) TYPE(*CHAR) LEN(4)

    RCVMSG MSGTYPE(*LAST) RMV(*NO) MSGDTA(&MSGDTA) +
    MSGID(&MSGID) KEYVAR(&MSGKEY)
    .
    .
    .
    IF COND(&STATUS *NE 0) THEN(+
    SNDPGMMSG MSGID(CPF9897) MSGF(QCPFMSG) +
    MSGDTA('Call to QSHELL ''' || &CMD |< +
    ''' encountered errors'))
    ELSE RMVMSG MSGKEY(&MSGKEY)

    ReplyDelete
  3. Michael Mayer-OakesMay 27, 2014 at 12:31 AM

    No offense but using tar and compress has worked well for ifs or library files as well.

    ReplyDelete

To prevent "comment spam" all comments are moderated.
Learn about this website's comments policy here.

Some people have reported that they cannot post a comment using certain computers and browsers. If this is you feel free to use the Contact Form to send me the comment and I will post it for you, please include the title of the post so I know which one to post the comment to.