23
Sat, Nov
1 New Articles

The API Corner: More on Counting Active Jobs

APIs
Typography
  • Smaller Small Medium Big Bigger
  • Default Helvetica Segoe Georgia Times

Let's continue our discussion about using the List Job API.

 

Last month, in the API Corner article "Counting Active Jobs by Subsystem and/or User," we saw how to use the List Job (QUSLJOB) API in order to count the number of active jobs on the system by various combinations of subsystem and initial user. We also saw that there were (at least) three areas of improvement that could be made to the program:

  1. Returning the count of active jobs within the text of CPF9898 was not very user-friendly if a CL program, running the CntActJob command, wanted to work with the number. The CL program would need to parse the first-level text of the message to locate the number, which can "move" based on the length of the SBS and USR values. Is there a way to eliminate this need for the calling CL program to parse the first-level text of the message in order to access the active job count?
  2. The user profile parameter of CntActJob refers to the initial user profile of the job. Is there a way to also obtain a count of active jobs that are currently running under a given user? That is, add a third parameter such as CURUSR (while continuing to support the SBS and USR filters of the CntActJob command).
  3. There's a limit of around 160,000 job entries that can be returned with a single call to the List Job API when using key 1906. If there are more than 160,000 active jobs on the system that meet our criteria, is there a way to access these additional job entries?

Hopefully you aren't too surprised to find that the answers to the above questions are yes, yes, and yes. In this article, we'll look at what changes can be made to the CntActJob command and program in order to provide these improvements.

The first thing we'll do is stop using the rather generic message CPF9898. CPF9898 is handy when all you want to do is send a text message because the message simply defines one field, with a size of up to 512 bytes, and ends the text with a period. With item 1 above, what we want to do is return well-formatted data so that another program can easily access the variable information that is provided by the CntActJob command (for instance, the number of active jobs for a given subsystem and user combination).

To accomplish this, we'll add a new message description with a message ID of ACT0001. The following two commands (Create Message File and Add Message Description) will create the message file PlayMsgs in your current library and add message description ACT0001 to PlayMsgs, respectively.

CrtMsgF MsgF(PlayMsgs)

AddMsgD MsgID(ACT0001) MsgF(*CurLib/PlayMsgs)                             

  Msg('Subsystem &1 has &2 active jobs for user &3, current user &4: &5.')

  Fmt((*Char 10) (*UBin 4) (*Char 10) (*Char 10) (*UBin 4))               

The initial text associated with message ACT0001 (Subsystem xxx has yyy active jobs for user zzz) matches the text used last month with CPF9898. The additional text (current user aaa: bbb) reflects our planned enhancement to CntActJob per list item 2 above. This text is included here just so we don't have to later change the message description. The major improvement, though, is that the first-level text of ACT0001 uses replacement data variables for items such as the subsystem name rather than returning all of the text in one large text field (as done with CPF9898). By reviewing the Msg parameter and the Fmt parameter of AddMsgD, we can see that variable &1 is defined as a 10-byte character field representing the subsystem name, &2 is defined as a 4-byte unsigned integer representing the number of active jobs associated with an initial user, &3 is defined as a 10-byte character field representing the name of the initial user, &4 is defined as a 10-byte character field representing the name of the current user, and &5 is defined as a 4-byte unsigned integer representing the number of active jobs associated with the current user.

One way to have CntActJob send active job count information using our ACT0001 message, rather than CPF9898, is to define a data structure that maps to the replacement data variables of ACT0001. The following ACT0001 data structure and changed SndTotals() function accomplishes this (we'll get to the CurUsr_In and CurUsrJobCnt fields shortly).

d ACT0001         ds                  qualified              

d  Sbs_In                       10a                          

d  ActJobCnt                    10u 0                        

d  UsrPrf_In                    10a                          

d  CurUsr_In                    10a                          

d  CurUsrJobCnt                 10u 0                        

p SndTotals       b                                      

d SndTotals       pi                                     

                                                         

 /free                                                   

                                                         

  ACT0001.Sbs_In = Sbs_In;                               

  ACT0001.ActJobCnt = ActJobCnt;                         

  ACT0001.UsrPrf_In = UsrPrf_In;                         

  ACT0001.CurUsr_In = CurUsr_In;                         

  ACT0001.CurUsrJobCnt = CurUsrJobCnt;                   

                                                         

  SndPgmMsg('ACT0001' :'PLAYMSGS  *LIBL'                 

            :ACT0001 :%size(ACT0001)                     

            :'*COMP' :'*PGMBDY' :1 :MsgKey :QUSEC);      

                                                         

 /end-free                                               

                                                     

p SndTotals       e                                  

 

Because part of the motivation for using ACT0001, rather than CPF9898, was to simplify life for developers wanting to access the job counts provided in the message, a sample CL program demonstrating how to directly access this variable data is provided at the end of this article.

The second thing we'll do is add support for returning the number of active jobs associated with a given current user. To start, we'll add a current user (CurUsr) parameter to the CntActJob command. This is done by adding the following parameter definition after the Usr parameter of last month's command.

Parm       Kwd(CurUsr) Type(*Generic) Len(10) +  

             SpcVal((*ALL)) +                    

             Min(0) Dft(*ALL) +                  

             Prompt('Current user profile')      

To create the CNTACTJOB command, use this command:

CrtCmd Cmd(CntActJob) Pgm(CntActJob)

In support of the CurUsr parameter of the CntActJob command, we also need to make some changes to the ChkActJob program. These changes are adding a new parameter on the prototype and interface specifications as in the following.

d CntActJob      pr                                         

d  Sbs_In                       10a   const                  

d  UsrPrf_In                    10a   const                  

d  CurUsr_In                    10a   const                  

                                                             

d CntActJob      pi                                         

d  Sbs_In                       10a   const                  

d  UsrPrf_In                    10a   const                  

d  CurUsr_In                    10a   const                  

Now we add a few variables that will be used along the same lines as how Usr was supported last month:

d CurUsr_Ptr      s               *                          

d CurUsr          s             10a   based(CurUsr_Ptr)      

d CurUsrJobCnt    s             10u 0                        

d CurUsrOK        s               n                          

d LenCurUsr       s              5u 0                        

Because we want to count only active jobs for a given current user if the job also meets the subsystem name requirements, we add a variable to indicate that the subsystem associated with the job qualifies:

d SbsDOK          s               n                          

And as you will see shortly, CntActJob will now be processing the job entries returned by the List Jobs API with two FOR loopsone for each returned job entry (controlled by variable X) and one for each key value entry returned for each job entry (controlled by variable Y). So a second loop control variable is needed.

d Y               s             10i 0                        

Last month, we used key 1906 to access subsystem information on active jobs. This month, we will also use key 305, which will allow us to access current user information as well. Because we're adding an additional key value, CntActJob also needs to update NbrKeysToRtn so that the API can "see" this additional key.

  KeyValues(1) = 1906;            // Subsystem name          

  KeyValues(2) = 305;             // Current user            

  NbrKeysToRtn = 2;                                          

In the mainline of CntActJob, there are some minor changes related to checking for both Sbs_In and CurUsr_In being the special value *ALL and a determination of whether or not CurUsr_In represents a generic name. Likewise, there is additional work within the ProcessLst() procedure related to key 305 being processed. But all of this is very similar to the processing discussed last month when processing key 1906. These refinements can be found in the full program source provided later in this article and won't be repeated here for space reasons.

The last enhancement to CntActJob is related to accessing more job entries than can fit within one user space.

Many list APIs, when it's likely that the API can return more data than will fit within a single user space, support a parameter known as a Continuation handle. The size of this continuation handle parameter can vary across APIs (some might be 16 bytes in length, others 48 bytes, etc.), but the idea behind them is the same. A blank (or not passed) continuation handle value means the list should start at the beginning; a non-blank value being passed to the API means to resume the list from where it left off on a previous call to the API. For the List Jobs API, this continuation handle is the ninth parameter, a parameter that was not passed in last month's version of CntActJob. This month, CntActJob will test to see if only a partial list was returned on calls to List Jobs and, if that's the case, then call List Jobs again asking for the next set of job entries that will fit into the user space. This continual calling of List Jobs will end when the API indicates the list is complete.

In the generic header of list APIs, where we find information such as the number of list entries (LstJobsHdr.QUSNbrLE) and the offset to the first returned entry (LstJobsHdr.QUSOLD), there is also an Information status field (LstJobsHdr.QUSIS). This information status field can have one of three values:

  • 'C'The list is complete and accurate.
  • 'I'The list is incomplete and not accurate.
  • 'P'The list is partial but accurate.

For CntActJob, the two values of interest are 'C', indicating that the list of jobs to be returned is complete, and 'P', indicating that the list of jobs to be returned includes more jobs. The value of 'I', due to how CntActJob calls the List Jobs API with an error code parameter indicating that errors should be returned as escape messages (QUSEC with QUSBPrv set to 0), will not be encountered (though it could be if another program and/or job was creating the list and CntActJob was accessing the generated list at a later time) as CntActJob is not monitoring for escape messages.

When an information status value of 'P' is returned by the API, List Jobs also returns a continuation handle value enabling CntActJob to continue the list. This value can be found in the Header section of the user space with the generic header providing an offset to the header section (LstJobsHdr.QUSOHS). The definition of this API-specific header section is provided in the QSYSINC include for the API and, for ILE RPG, is the data structure QUSLH with subfield QUSCH03 providing the continuation handle value to resume the list.

With that introduction, here are additional definitions and mainline logic changes needed to access a complete list of jobs:

d APIHdr_Ptr      s               *                          

d APIHdr          ds                  likeds(QUSLH)          

                                                             

     dow 1 = 1;                                                

         ProcessLst();                                         

                                                               

         select;                                               

            when LstJobsHdr.QUSIS = 'C';                       

                 // All jobs have been processed               

                                                                    

                 leave;                                             

                                                                    

            when LstJobsHdr.QUSIS = 'P';                            

                 // More jobs to process                            

                                                                    

                 APIHdr_Ptr = LstJobsHdr_Ptr + LstJobsHdr.QUSOHS;   

                                                                    

                 LstJobs(LstJobsSpc :'JOBL0200'                     

                         :('*ALL      ' + UsrPrf_In + '*ALL      ') 

                         :'*ACTIVE' :QUSEC :'*'                     

                         :NbrKeysToRtn :KeyValues :APIHdr.QUSCH03); 

                                                                    

         endsl;                                                     

     enddo;                                                         

Rather than just calling ProcessLst() once, as was done last month, CntActJob now calls ProcessLst() within a DOW that runs until we explicitly leave the DOW. Within the DOW, ProcessLst() is called and after the current list entries have been processed, a check is made to determine if the entire list has been processed (LstJobsHdr.QUSIS is 'C') or if additional job entries exist (LstJobsHdr.QUSIS is 'P'). If the list is complete, the DOW is left. If the list is not complete, CntActJob accesses the API header section (APIHdr) using LstJobsHdr.QUSOHS, re-calls the List Jobs API using the continuation handle value found at APIHdr.QUSCH03, and reruns the DOW. That's it!

Here is the complete source for CntActJob, consolidating all the various changes we've discussed.

h DftActGrp(*no)                                             

                                                             

d CntActJob      pr                                         

d  Sbs_In                       10a   const                  

d  UsrPrf_In                    10a   const                  

d  CurUsr_In                    10a   const                  

                                                             

d CntActJob      pi                                         

d  Sbs_In                       10a   const                  

d  UsrPrf_In                    10a   const                  

d  CurUsr_In                    10a   const                  

                                                             

 ************************************************************

                                                             

d CrtUsrSpc       pr                  extpgm('QUSCRTUS')     

d  QualUsrSpcN                  20a   const                  

d  XAttr                        10a   const                          

d  IntSize                      10i 0 const                          

d  IntValue                      1a   const                          

d  PubAut                       10a   const                          

d  TxtDesc                      50a   const                          

d  ReplaceOpt                   10a   const options(*nopass)         

d  ErrCde                             likeds(QUSEC) options(*nopass) 

d  Domain                       10a   const options(*nopass)         

d  TfrSize                      10i 0 const options(*nopass)         

d  OptSpcAlgn                    1a   const options(*nopass)         

                                                                     

d LstJobs         pr                  extpgm('QUSLJOB')              

d  QualUsrSpcN                  20a   const                          

d  Format                        8a   const                          

d  QualJobName                  26a   const                          

d  Status                       10a   const                          

d  ErrCde                             likeds(QUSEC) options(*nopass) 

d  JobType                       1a   const options(*nopass)         

d  NbrFldsToRtn                 10i 0 const options(*nopass)         

d  FldsToRtn                          const options(*nopass)         

d                                     like(KeyValues)                

d                                     dim(%elem(KeyValues))          

d  ContinueHdl                  48a   const options(*nopass)         

                                                                     

d ProcessLst      pr                                                 

                                                                     

d RtvUsrSpcPtr    pr                  extpgm('QUSPTRUS')             

d  QualUsrSpcN                  20a   const                          

d  UsrSpcPtr                      *                                  

d  ErrCde                             likeds(QUSEC) options(*nopass) 

                                                                     

d SndPgmMsg       pr                  extpgm('QMHSNDPM')             

d  MsgID                         7a   const                          

d  QualMsgF                     20a   const                          

d  MsgDta                      256a   const options(*varsize)

d  LenMsgDta                    10i 0 const                  

d  MsgType                      10a   const                  

d  CSE                          10a   const                  

d  CSECtr                       10i 0 const                  

d  MsgKey                        4a                          

d  ErrCde                             likeds(QUSEC)          

d  LenCSE                       10i 0 const options(*nopass) 

d  CSEQual                      20a   const options(*nopass) 

d  DspMsgWait                   10i 0 const options(*nopass) 

d  CSEType                      10a   const options(*nopass) 

d  CCSID                        10i 0 const options(*nopass) 

                                                             

d SndTotals       pr                                         

                                                             

 ************************************************************

                                                             

d LstJobsHdr_Ptr  s               *                         

d LstJObsHdr      ds                  likeds(QUSH0100)      

d                                     based(LstJobsHdr_Ptr) 

                                                            

d JobHdr_Ptr      s               *                         

d JobHdr          ds                  likeds(QUSL020001)    

d                                     based(JobHdr_Ptr)     

                                                            

d JobFlds_Ptr     s               *                         

d JobFlds         ds                  likeds(QUSLKF)        

d                                     based(JobFlds_Ptr)    

                                                            

d QualSbsD_Ptr    s               *                         

d QualSbsD        ds                  qualified             

d                                     based(QualSbsD_Ptr)   

d  SbsDName                     10a                         

d  SbsDLib                      10a                         

                                                             

d APIHdr_Ptr      s               *                          

d APIHdr          ds                  likeds(QUSLH)          

                                                             

d ACT0001         ds                  qualified              

d  Sbs_In                       10a                          

d  ActJobCnt                    10u 0                        

d  UsrPrf_In                    10a                          

d  CurUsr_In                    10a                          

d  CurUsrJobCnt                 10u 0                        

                                                             

d ErrCde          ds                  qualified              

d  Hdr                                likeds(QUSEC)          

d  MsgDta                      256                           

                                                             

 ************************************************************

                                                             

d ActJobCnt       s             10u 0                        

d CurUsr_Ptr      s               *                          

d CurUsr          s             10a   based(CurUsr_Ptr)      

d CurUsrJobCnt    s             10u 0                        

d CurUsrOK        s               n                          

d KeyValues       s             10i 0 dim(MaxKeys)           

d LenCurUsr       s              5u 0                        

d LenSbsD         s              5u 0                        

d LstJobsSpc      s             20a   inz('CNTACTJOB QTEMP') 

d MsgDta          s            512a                          

d MsgKey          s              4a                          

d NbrKeysToRtn    s             10i 0                        

d SbsDOK          s               n                          

                                                             

d X               s             10i 0                        

d Y               s             10i 0                        

                                                             

d MaxKeys         c                   const(10)              

                                                             

 ************************************************************

                                                             

 /copy qsysinc/qrpglesrc,qusec                               

 /copy qsysinc/qrpglesrc,qusgen                              

 /copy qsysinc/qrpglesrc,qusljob                             

                                                             

 ************************************************************

                                                             

 /free                                                       

                                                             

  KeyValues(1) = 1906;            // Subsystem name          

  KeyValues(2) = 305;             // Current user            

  NbrKeysToRtn = 2;                                          

                                                             

  LstJobs(LstJobsSpc :'JOBL0200'                             

          :('*ALL      ' + UsrPrf_In + '*ALL      ')        

          :'*ACTIVE' :QUSEC :'*'                            

          :NbrKeysToRtn :KeyValues);                        

                                                            

  if ((Sbs_In = '*ALL') and                                 

      (CurUsr_In = '*ALL'));                                

     // Check for all filters being set to *ALL             

                                                            

     ActJobCnt = LstJobsHdr.QUSNbrLE;                       

     CurUsrJobCnt = LstJobsHdr.QUSNbrLE;                    

                                                            

  else;                                                     

     // Determine if Sbs_In is a generic                    

                                                            

     if %subst(Sbs_In :(%len(%trimr(Sbs_In))) :1) = '*';    

        LenSbsD = (%len(%trimr(Sbs_In))) - 1;               

     else;                                                  

        LenSbsD = %size(Sbs_In);                               

     endif;                                                    

                                                               

     // Determine if CurUsr_In is a generic                    

                                                               

     if %subst(CurUsr_In :(%len(%trimr(CurUsr_In))) :1) = '*'; 

        LenCurUsr = (%len(%trimr(CurUsr_In))) - 1;             

     else;                                                     

        LenCurUsr = %size(CurUsr_In);                          

     endif;                                                    

                                                               

     dow 1 = 1;                                                

         ProcessLst();                                         

                                                               

         select;                                               

            when LstJobsHdr.QUSIS = 'C';                       

                 // All jobs have been processed               

                                                                    

                 leave;                                             

                                                                    

            when LstJobsHdr.QUSIS = 'P';                            

                 // More jobs to process                            

                                                                    

                 APIHdr_Ptr = LstJobsHdr_Ptr + LstJobsHdr.QUSOHS;   

                                                                    

                 LstJobs(LstJobsSpc :'JOBL0200'                     

                         :('*ALL      ' + UsrPrf_In + '*ALL      ') 

                         :'*ACTIVE' :QUSEC :'*'                     

                         :NbrKeysToRtn :KeyValues :APIHdr.QUSCH03); 

                                                                    

         endsl;                                                     

     enddo;                                                         

                                                                    

  endif;                                                            

                                                             

  SndTotals();                                               

                                                             

  *inlr = *on;                                               

  return;                                                    

                                                             

  // ********************************************************

                                                             

  begsr *inzsr;                                              

                                                             

    // Set appropriate API Errcde error handling values      

                                                             

    QUSBPrv = 0;                                             

    ErrCde.Hdr.QUSBPrv = %size(ErrCde);                      

                                                             

    // Prepare to call QUSLJOB to get a list of all active   

    // jobs on the system                                    

                                                             

    RtvUsrSpcPtr(LstJobsSpc :LstJobsHdr_Ptr :ErrCde);        

                                                             

    select;                                                  

       when ErrCde.Hdr.QUSBAvl = 0;                          

            // All is OK                                     

                                                             

       when ErrCde.Hdr.QUSEI = 'CPF9801';                    

            // UsrSpc not found, so create it                

                                                             

            CrtUsrSpc(LstJobsSpc :'ActJob_Lst' :4096         

                      :x'00' :'*ALL' :'List of active jobs'  

                      :'*YES' :QUSEC :'*DEFAULT' :0 :'1');   

                                                             

            // Get accessibility to user space               

                                                             

            RtvUsrSpcPtr(LstJobsSpc :LstJobsHdr_Ptr :QUSEC); 

                                                        

       other;                                           

            // Something seriously wrong. Send Escape   

                                                        

            MsgDta = 'Failure accessing UsrSpc' +       

                     %trimr(LstJobsSpc) + ': ' +        

                     ErrCde.Hdr.QUSEI;                  

            SndPgmMsg('CPF9898' :'QCPFMSG   *LIBL'      

                      :MsgDta :%len(%trimr(MsgDta))     

                      :'*ESCAPE' :'*PGMBDY' :1          

                      :MsgKey :QUSEC);                  

    endsl;                                              

                                                        

  endsr;                                                

                                                        

 /end-free                                              

                                                        

 ************************************************************

                                                             

p ProcessLst      b                                          

d ProcessLst      pi                                         

                                                             

 /free                                                       

                                                             

  for X = 1 to LstJobsHdr.QUSNbrLE;                          

      // Loop through potential Jobs, tracking what meets    

      // filter requirements                                 

                                                             

      if X = 1;                                              

         JobHdr_Ptr = LstJobsHdr_Ptr + LstJobsHdr.QUSOLD;    

      else;                                                  

         JobHdr_Ptr += LstJobsHdr.QUSSEE;                    

      endif;                                                 

                                                             

      if JobHdr.QUSJIS = *blanks;                                

         SbsDOK = *off;                                          

         CurUsrOK = *off;                                        

                                                                 

         for Y = 1 to JobHdr.QUSNbrFR;                           

             // Access all additional info                       

                                                                 

             if Y = 1;                                           

                JobFlds_Ptr = JobHdr_Ptr + %size(JobHdr);        

             else;                                               

                JobFlds_Ptr += JobFlds.QUSLFIR;                  

             endif;                                              

                                                                 

             select;                                             

                when JobFlds.QUSKF = 1906;                       

                     QualSbsD_Ptr = JobFlds_Ptr + %size(JobFlds);

                                                                 

                     if ((Sbs_In = '*ALL') or                     

                         (%subst(QualSbsD.SbsDName :1 :LenSbsD) = 

                            %subst(Sbs_In :1 :LenSbsD)));         

                                                                  

                        SbsDOK = *on;                             

                     endif;                                       

                                                                  

                when JobFlds.QUSKF = 305;                         

                     CurUsr_Ptr = JobFlds_Ptr + %size(JobFlds);   

                                                                  

                     if ((CurUsr_In = '*ALL') or                  

                         (%subst(CurUsr :1 :LenCurUsr) =          

                            %subst(CurUsr_In :1 :LenCurUsr)));    

                                                                  

                        CurUsrOK = *on;                           

                     endif;                                       

             endsl;                                               

         endfor;                                             

                                                             

         if SbsDOK;                                          

            ActJobCnt += 1;                                  

                                                             

            if ((SbsDOK) and (CurUsrOK));                    

               CurUsrJobCnt += 1;                            

            endif;                                           

         endif;                                              

      endif;                                                 

  endfor;                                                    

                                                             

 /end-free                                                   

                                                             

p ProcessLst      e                                          

                                                             

 ************************************************************

                                                         

p SndTotals       b                                      

d SndTotals       pi                                     

                                                         

 /free                                                   

                                                         

  ACT0001.Sbs_In = Sbs_In;                               

  ACT0001.ActJobCnt = ActJobCnt;                         

  ACT0001.UsrPrf_In = UsrPrf_In;                         

  ACT0001.CurUsr_In = CurUsr_In;                         

  ACT0001.CurUsrJobCnt = CurUsrJobCnt;                   

                                                         

  SndPgmMsg('ACT0001' :'PLAYMSGS  *LIBL'                 

            :ACT0001 :%size(ACT0001)                     

            :'*COMP' :'*PGMBDY' :1 :MsgKey :QUSEC);      

                                                         

 /end-free                                               

                                                     

p SndTotals       e                                  

Assuming that you have stored the above program source in source file QRPGLESRC and that the library containing QRPGLESRC is in your current library list, then you can create the CntActJob program with the following command:

CrtBndRPG Pgm(CntActJob)    

To test the program and determine the number of active jobs currently running under the user profile BVINING across all subsystems and initial users, you can enter the following command:

CntActJob Sbs(*All) Usr(*All) CurUsr(BVining)

You may then see a message such as 'Subsystem *ALL has 3864 active jobs for user *ALL, current user BVINING: 4'.

Before I finish, just one note related to an earlier statement. You may have noticed that I previously mentioned "Many list APIs…support a parameter known as a Continuation handle" rather than "All" list APIs. Some list APIs can return more data than will fit in a single user space and do not provide a continuation handle parameter. The List Objects (QUSLOBJ) API is one example. In cases like this, an alternative API using an Open list approach is available, with the List Objects alternative being Open List of Objects (QGYOLOBJ). Two previous "API Corner" articles covering QGYOLOBJ and working with open lists include "Finding All *SRVPGMs on the System" and "Take Advantage of Open List APIs."

As mentioned earlier, one of the enhancements made to CntActJob was to make it easier for a CL program to run the CntActJob command and then work with the variable data returned in the message. The following program demonstrates how to run CntActJob and directly access the replacement data values.

Pgm                                                           

                                                              

Dcl        Var(&ACT0001)   Type(*Char) Len(38)                

 Dcl        Var(&SbsName)    Type(*Char) Stg(*Defined) +      

              Len(10) DefVar(&ACT0001 01)                     

 Dcl        Var(&InlUsrCnt)  Type(*UInt) Stg(*Defined) +      

              Len(4)  DefVar(&ACT0001 11)                     

 Dcl        Var(&InlUsrName) Type(*Char) Stg(*Defined) +      

              Len(10) DefVar(&ACT0001 15)                     

 Dcl        Var(&CurUsrName) Type(*Char) Stg(*Defined) +      

              Len(10) DefVar(&ACT0001 25)                     

 Dcl        Var(&CurUsrCnt)  Type(*UInt) Stg(*Defined) +      

              Len(4)  DefVar(&ACT0001 35)                     

                                                              

Dcl        Var(&MsgID)     Type(*Char) Len(7)                 

Dcl        Var(&MsgDtaLen) Type(*Dec)  Len(5 0) Value(38)     

                                                    

CntActJob Sbs(*All) CurUsr(BVINING)                

RcvMsg     Rmv(*No) MsgDta(&ACT0001) +              

             MsgDtaLen(&MsgDtaLen) MsgID(&MsgID)    

                                                    

If         Cond(&MsgID = 'ACT0001') Then(Do)        

           /* Whatever is appropriate  */           

           EndDo                                    

                                                    

EndPgm                                              

In the same manner that the CntActJob RPG program defines the data structure ACT0001 to send message ACT0001, here the CL program defines the data structure &ACT0001 to map the replacement data variables of the message being received. After running the CntActJob command, the CL program uses the Receive Message command, using the MsgDta parameter to specify where the message replacement data should be returned (&ACT0001), the MsgDtaLen parameter to specify how large the target variable &ACT0001 is (38 bytes), and the MsgID parameter to specify where the message ID of the message being received should be returned (&MsgID). If the received message is ACT0001, then the various subfield values of &ACT0001 (&SbsName through &CurUsrCnt) can be directly accessed.

Using the previous test case of CntActJob Sbs(*All) Usr(*All) CurUsr(BVining), the value of &SbsName will be *ALL, &InlUsrCnt will be 3864, &InlUsrName will be *ALL, &CurUsrName will be BVINING, and &CurUsrCnt will be 4.

As usual, if you have any API questions, send them to me at This email address is being protected from spambots. You need JavaScript enabled to view it..

Bruce Vining

Bruce Vining is president and co-founder of Bruce Vining Services, LLC, a firm providing contract programming and consulting services to the System i community. He began his career in 1979 as an IBM Systems Engineer in St. Louis, Missouri, and then transferred to Rochester, Minnesota, in 1985, where he continues to reside. From 1992 until leaving IBM in 2007, Bruce was a member of the System Design Control Group responsible for OS/400 and i5/OS areas such as System APIs, Globalization, and Software Serviceability. He is also the designer of Control Language for Files (CLF).A frequent speaker and writer, Bruce can be reached at This email address is being protected from spambots. You need JavaScript enabled to view it.. 


MC Press books written by Bruce Vining available now on the MC Press Bookstore.

IBM System i APIs at Work IBM System i APIs at Work
Leverage the power of APIs with this definitive resource.
List Price $89.95

Now On Sale

BLOG COMMENTS POWERED BY DISQUS

LATEST COMMENTS

Support MC Press Online

$

Book Reviews

Resource Center

  • SB Profound WC 5536 Have you been wondering about Node.js? Our free Node.js Webinar Series takes you from total beginner to creating a fully-functional IBM i Node.js business application. You can find Part 1 here. In Part 2 of our free Node.js Webinar Series, Brian May teaches you the different tooling options available for writing code, debugging, and using Git for version control. Brian will briefly discuss the different tools available, and demonstrate his preferred setup for Node development on IBM i or any platform. Attend this webinar to learn:

  • SB Profound WP 5539More than ever, there is a demand for IT to deliver innovation. Your IBM i has been an essential part of your business operations for years. However, your organization may struggle to maintain the current system and implement new projects. The thousands of customers we've worked with and surveyed state that expectations regarding the digital footprint and vision of the company are not aligned with the current IT environment.

  • SB HelpSystems ROBOT Generic IBM announced the E1080 servers using the latest Power10 processor in September 2021. The most powerful processor from IBM to date, Power10 is designed to handle the demands of doing business in today’s high-tech atmosphere, including running cloud applications, supporting big data, and managing AI workloads. But what does Power10 mean for your data center? In this recorded webinar, IBMers Dan Sundt and Dylan Boday join IBM Power Champion Tom Huntington for a discussion on why Power10 technology is the right strategic investment if you run IBM i, AIX, or Linux. In this action-packed hour, Tom will share trends from the IBM i and AIX user communities while Dan and Dylan dive into the tech specs for key hardware, including:

  • Magic MarkTRY the one package that solves all your document design and printing challenges on all your platforms. Produce bar code labels, electronic forms, ad hoc reports, and RFID tags – without programming! MarkMagic is the only document design and print solution that combines report writing, WYSIWYG label and forms design, and conditional printing in one integrated product. Make sure your data survives when catastrophe hits. Request your trial now!  Request Now.

  • SB HelpSystems ROBOT GenericForms of ransomware has been around for over 30 years, and with more and more organizations suffering attacks each year, it continues to endure. What has made ransomware such a durable threat and what is the best way to combat it? In order to prevent ransomware, organizations must first understand how it works.

  • SB HelpSystems ROBOT GenericIT security is a top priority for businesses around the world, but most IBM i pros don’t know where to begin—and most cybersecurity experts don’t know IBM i. In this session, Robin Tatam explores the business impact of lax IBM i security, the top vulnerabilities putting IBM i at risk, and the steps you can take to protect your organization. If you’re looking to avoid unexpected downtime or corrupted data, you don’t want to miss this session.

  • SB HelpSystems ROBOT GenericCan you trust all of your users all of the time? A typical end user receives 16 malicious emails each month, but only 17 percent of these phishing campaigns are reported to IT. Once an attack is underway, most organizations won’t discover the breach until six months later. A staggering amount of damage can occur in that time. Despite these risks, 93 percent of organizations are leaving their IBM i systems vulnerable to cybercrime. In this on-demand webinar, IBM i security experts Robin Tatam and Sandi Moore will reveal:

  • FORTRA Disaster protection is vital to every business. Yet, it often consists of patched together procedures that are prone to error. From automatic backups to data encryption to media management, Robot automates the routine (yet often complex) tasks of iSeries backup and recovery, saving you time and money and making the process safer and more reliable. Automate your backups with the Robot Backup and Recovery Solution. Key features include:

  • FORTRAManaging messages on your IBM i can be more than a full-time job if you have to do it manually. Messages need a response and resources must be monitored—often over multiple systems and across platforms. How can you be sure you won’t miss important system events? Automate your message center with the Robot Message Management Solution. Key features include:

  • FORTRAThe thought of printing, distributing, and storing iSeries reports manually may reduce you to tears. Paper and labor costs associated with report generation can spiral out of control. Mountains of paper threaten to swamp your files. Robot automates report bursting, distribution, bundling, and archiving, and offers secure, selective online report viewing. Manage your reports with the Robot Report Management Solution. Key features include:

  • FORTRAFor over 30 years, Robot has been a leader in systems management for IBM i. With batch job creation and scheduling at its core, the Robot Job Scheduling Solution reduces the opportunity for human error and helps you maintain service levels, automating even the biggest, most complex runbooks. Manage your job schedule with the Robot Job Scheduling Solution. Key features include:

  • LANSA Business users want new applications now. Market and regulatory pressures require faster application updates and delivery into production. Your IBM i developers may be approaching retirement, and you see no sure way to fill their positions with experienced developers. In addition, you may be caught between maintaining your existing applications and the uncertainty of moving to something new.

  • LANSAWhen it comes to creating your business applications, there are hundreds of coding platforms and programming languages to choose from. These options range from very complex traditional programming languages to Low-Code platforms where sometimes no traditional coding experience is needed. Download our whitepaper, The Power of Writing Code in a Low-Code Solution, and:

  • LANSASupply Chain is becoming increasingly complex and unpredictable. From raw materials for manufacturing to food supply chains, the journey from source to production to delivery to consumers is marred with inefficiencies, manual processes, shortages, recalls, counterfeits, and scandals. In this webinar, we discuss how:

  • The MC Resource Centers bring you the widest selection of white papers, trial software, and on-demand webcasts for you to choose from. >> Review the list of White Papers, Trial Software or On-Demand Webcast at the MC Press Resource Center. >> Add the items to yru Cart and complet he checkout process and submit

  • Profound Logic Have you been wondering about Node.js? Our free Node.js Webinar Series takes you from total beginner to creating a fully-functional IBM i Node.js business application.

  • SB Profound WC 5536Join us for this hour-long webcast that will explore:

  • Fortra IT managers hoping to find new IBM i talent are discovering that the pool of experienced RPG programmers and operators or administrators with intimate knowledge of the operating system and the applications that run on it is small. This begs the question: How will you manage the platform that supports such a big part of your business? This guide offers strategies and software suggestions to help you plan IT staffing and resources and smooth the transition after your AS/400 talent retires. Read on to learn: