Service Programs

Service programs offer a method of leveraging common code or functions.

Service Programs vs. Modules

In general modules and service programs are object designed to share common code from application to application. Sharing a procedure means the code may be maintained in a single source member and not having to maintain dozens (or hundreds) of programs that use the same code. There is a performance benefit to moving to modules and service programs instead of using subprograms. Typically, a dynamic call (as to a subprogram) is slower than a call to a bound procedure. (Less handshaking between the objects to establish the parameters exchanged means faster execution.)

Though modules are convient to maximize code re-use, a better idea is to bind modules into a service program. Though I have created both modules and programs, there is less payback in using modules as opposed to creating a service program. What’s the difference? Primarily the difference lies in the binding.

Modules are ILE building blocks—they are not executable. In order to use a module, it must be bound to a program or a service program. When a program binds a module, the process is a bind by copy event. Once the program has been created, the module may be deleted—it is no longer required, because a copy of the instructions have been added into the program object. This is essentially what happens using the CRTBNDRPG command, whether the program is bound to another module, or not. A module of the program is created in QTEMP, a program is created from the module and when the job ends the module, created in QTEMP is destroyed along with the other contents of QTEMP.

The logical question is; why create a service program instead of a module? It is a good question and the answer requires a good understanding of ILE concepts. If a module is bound to a program, or number of programs, you must keep track of all the programs that bind to the module. If the module changes, in order for programs created with the module to recognize the changes in the code, all of the programs must be recreated (re-compiled, or re-bound--remember: bind by copy). By having the module bound to a service program instead, (a bind by reference), the module source could be changed, re-created, and the service program could be updated, without having to re-compile 100 separate programs. (If the signature of the procedure did not change, or if the previous signature is still supported, there is no need for the program to change.)

The answer to the question why use a service program, is that it provides the same code re-use with a greater degree of flexibility and ease of maintenance--an often overlooked advantage to using a service program. In terms of change management, the number of source file members checked out, changed, compiled, and tested, can be reduced to 1, when utilizing service programs.

There are some performance considerations when using a service program. The first reference to a bound procedure loads the entire service program to a job. However, after that point, invoking procedures from the service program are much faster than a dynamic call. The service program stays resident within the activation group so if 5, or 6 programs use the same service program, there is no need to perform the load operation for each program—it is a one-time only penalty.

Binding Directories

The more modules or service programs a binding directory contains, the longer it may take to bind the programs. Therefore, you should include only the necessary modules or service programs in your binding directory. Binding directories can reduce program size because you do not specify modules or service programs that do not get used.
During binding, processing happens in this order:

1. All of the modules specified on the MODULE parameter are examined. The binder determines the list of symbols imported and exported by the object. After being examined, modules are bound, in the order listed, into the program being created.
2. All of the service programs on the BNDSRVPGM parameter are examined in the order listed. The service programs are bound only if needed to resolve an import.
3. All of the binding directories on the BNDDIR parameter are processed in the order listed. All the objects listed in these binding directories are examined in the order listed, but they are bound only if needed to resolve imports. Duplicate entries in binding directories are silently ignored.
4. Each module has a list of reference system objects. This list is comprised of binding directories. The reference system objects from bound modules are processed sequentially—all the reference system objects from the first module are processed first, then the objects from the second module, etc. This processing continues only as long as unresolved imports exist.

Though it may be convenient to put all modules and service programs into a common binding directory, it works against fast, efficient, object creation. A better methodology would be to create binding directories for specific functional areas, keeping the directory entries to a minimum and relevant to the applications bound to the directory.

Record Lock Service Program

STRPGMEXP PGMLVL(*CURRENT)
/********************************************************************/
/*   *MODULE      SC0930RM     SCROY        01/19/10  14:18:20      */
/********************************************************************/
  EXPORT SYMBOL("DSPLCKMSG")
  EXPORT SYMBOL("RCDLCKMGR")
  EXPORT SYMBOL("SNDLCKMSG")
ENDPGMEX


CRTSRVPGM SRVPGM(SCROY/SC0930SV) MODULE(SC0930RM) TEXT('Record lock services') BNDDIR(SC0930_BD) ACTGRP(QILE)

     H/TITLE  ** Record Lock error handlers **
     H DEBUG(*YES)
     H OPTION(*SRCSTMT : *NODEBUGIO)
     H nomain
      *********************************************************************
      * PROGRAM NAME - SC0930RM                                           *
      *                                                                   *
      * FUNCTION     - This member contains modules that may be used as   *
      *                record lock monitor for interactive and batch      *
      *                programs. Interactively, if will display a         *
      *                pop-up window to the user, with lock information.  *
      *                In batch mode, the program will send a message     *
      *                to the system operator message queue.              *
      *                                                                   *
      * PROGRAMMER   - STEVE CROY                                         *
      *********************************************************************
     D CF            E DS                  EXTNAME(SCKEYSPF) qualified    
     D PGMDS         ESDS                  EXTNAME(SCPSTSPf)              
     D DSPDS         E DS                  EXTNAME(SCDSPFPF)              

      /copy qrpglesrc,sc0000_pr
      /copy qrpglesrc,sc0930_pr

     D RCVM0100        DS                  qualified
     D   BytesRtn                    10I 0
     D   BytesAvail                  10I 0
     D   MsgSev                      10I 0
     D   MsgID                        7A
     D   MsgType                      2A
     D   MsgKey                       4A
     D                                7A
     D   CCSID_status                10I 0
     D   CCSID                       10I 0
     D   MsgDtaLen                   10I 0
     D   MsgDtaAvail                 10I 0
     D   MsgDta                    8000A

     D ErrorCode       ds                  qualified
     D   BytesProv                   10I 0 inz(0)
     D   BytesAvail                  10I 0 inz(0)
      *---------------------------------------------------------------------
      * Define constants
      *---------------------------------------------------------------------
     D Yes             C                   CONST('Y')
     D No              C                   CONST('N')
      *********************************************************************
      * Procedure  - rcdLckMgr                                            *
      *                                                                   *
      * FUNCTION  - This procedure is a general purpose record lock       *
      *             manager. This may be used to route the record lock    *
      *             messasge to the batch record lock procedure or the    *
      *             interactive record lock procedure.                    *
      *                                                                   *
      * PARAMTERS - Type    NAME           LEN ATR Desc                   *
      *             Input  -CPFmsg          80 a   CPF error message      *
      *                    -callingPgm      10 a   calling program        *
      *                    -fileName         8 a   file to be locked      *
      *                    -exitAllowed      1 a   exit flag Y/N          *
      *             I/O    -*NONE                                         *
      *             OUTPUT -byPassLock         n   bypass update '0'/'1'  *
      *                                                                   *
      * PROGRAMMER   - STEVE CROY        01/19/2010                       *
      *********************************************************************
      *********************************************************************
      *                   MODIFICATION LOG                                *
      *                                                                   *
      *   DATE           PROGRAMMER      DESCRIPTION                      *
      *                                                                   *
      *********************************************************************
     P rcdLckMgr       B                   export
     D rcdLckMgr       PI              n
     D   CPFMsg                      80
     D   callingPgm                  10
     D   filename                     8
     D   ExitAllowed                  1

      *---------------------------------------------------------------------
      * START of work fields
      *---------------------------------------------------------------------
     D JobAttr         S              1A
     D byPass          S               n
      *---------------------------------------------------------------------
      * END of work fields
      *--------------------------------------------------------------------
      /free
         JobAttr = GetJobAtr()                                            ;
         IF JobAttr = 'I'                                                 ;
            byPass = dsplckMsg(cpfmsg:callingPgm:fileName:exitAllowed)    ;
         ELSE                                                             ;
            byPass = sndlckMsg(cpfmsg:exitAllowed)                        ;
         ENDIF                                                            ;
         RETURN byPass                                                    ;
      /end-Free
     P rcdLckMgr       E
      *********************************************************************
      * Procedure  - SNDLCKMSG                                            *
      *                                                                   *
      * FUNCTION  - This procedure is used to send a record lock          *
      *             message to the QSYSOPR message queue. The proc        *
      *             will wait for a reply then time out and return        *
      *             to the calling program.                               *
      *                                                                   *
      * PARAMTERS - Type    NAME           LEN ATR Desc                   *
      *             Input  -CPFmsg          80 a   CPF error message      *
      *                    -exitAllowed      1 a   exit flag Y/N          *
      *             I/O    -*NONE                                         *
      *             OUTPUT -byPassLock         n   bypass update '0'/'1'  *
      *                                                                   *
      * PROGRAMMER   - STEVE CROY        01/19/2010                       *
      *********************************************************************
      *********************************************************************
      *                   MODIFICATION LOG                                *
      *                                                                   *
      *   DATE           PROGRAMMER      DESCRIPTION                      *
      *                                                                   *
      *********************************************************************

     P sndLckMsg       B                   export
     D sndLckMsg       PI              n
     D   CPFmsg                      80
     D   exitAllowed                  1
      *---------------------------------------------------------------------
      * START of work fields
      *---------------------------------------------------------------------
     D action1         s             25A   inz('Reply R, to retry lock')
     D action2         s             30A   inz('reply C, cancel (by-pass) lock')
     D NbrSecs         S             15  5 inz(180)
     D Message         s            256A   varying
     D MsgKey          s              4A
     D MsgQ            s             20A   dim(1) inz('*SYSOPR')
     D Reply           s            100A
     D bypass          s               n
      *---------------------------------------------------------------------
      * END of work fields
      *---------------------------------------------------------------------
      /free
        //----------------------------------------------------
        // Create a message to send to the system operator.
        // Send an *INQ message to QSYSOPR asking for a reply.
        //----------------------------------------------------

         Reply = 'R'                                                    ;
         Message = %trim(cpfmsg) + '  ' + %trim(action1)                ;
         IF exitAllowed = Yes                                           ;
            Message = %trim(Message) + ', ' + %trim(action2) + '.'      ;
         ELSE                                                           ;
            Message = %trim(Message) + '.'                              ;
         ENDIF                                                          ;

         QMHSNDM( *blanks                                               :
                  *blanks                                               :
                  Message                                               :
                  %len(Message)                                         :
                  '*INQ'                                                :
                  MsgQ                                                  :
                  %elem(MsgQ)                                           :
                  '*PGMQ'                                               :
                  MsgKey                                                :
                   ErrorCode )                                          ;

        //----------------------------------------------------
        // Wait up to 5 minutes (300 seconds) for a reply to the
        // above message. If you change the value of 300 below to
        // a value of -1, it will wait indefinitely.
        //----------------------------------------------------

         QMHRCVPM( RCVM0100                                             :
                   %size(RCVM0100)                                      :
                   'RCVM0100'                                           :
                   '*'                                                  :
                   0                                                    :
                   '*RPY'                                               :
                   MsgKey                                               :
                   300                                                  :
                   '*REMOVE'                                            :
                   ErrorCode )                                          ;

         //----------------------------------------------------
         // The "Reply" Variable contains the operator's reply
         // If the reply was C (cancel) by-pass update
         //----------------------------------------------------

         IF RCVM0100.BytesRtn > 0 AND RCVM0100.MsgDta <> *blank         ;
            Reply = %subst(RCVM0100.MsgDta: 1: RCVM0100.MsgDtaLen)      ;
         ENDIF                                                          ;
         IF Reply = *blank                                              ;
            Reply = 'R'                                                 ;
         ENDIF                                                          ;

         Reply = UpperCase(Reply:%size(Reply))                          ;
         IF %subst(Reply:1:1) = 'C'                                     ;
            byPass = *ON                                                ;
         ELSE                                                           ;
            byPass = *OFF                                               ;
         ENDIF                                                          ;

         RETURN byPass                                                  ;
      /END-free
     P sndLckMsg       E
      *********************************************************************
      * Procedure  - DSPLCKMSG                                            *
      *                                                                   *
      * FUNCTION  - This procedure is used to display a record lock       *
      *             message to an interactive application. The message    *
      *             is displayed and the user may send a cancel, or an    *
      *             an attempt a retry indicator to the calling program.  *
      *                                                                   *
      * PARAMTERS - Type    NAME           LEN ATR Desc                   *
      *             Input  -CPFmsg          80 a   CPF error message      *
      *                    -thisPgm         10 a   calling program        *
      *                    -fileName         8 a   file to be locked      *
      *                    -exitAllowed      1 a   exit flag Y/N          *
      *             I/O    -*NONE                                         *
      *             OUTPUT -byPassLock         n   bypass update '0'/'1'  *
      *                                                                   *
      * PROGRAMMER   - STEVE CROY        01/19/2010                       *
      *********************************************************************
      *********************************************************************
      *                   MODIFICATION LOG                                *
      *                                                                   *
      *   DATE           PROGRAMMER      DESCRIPTION                      *
      *                                                                   *
      *********************************************************************
     P dspLckMsg       B                   export
     D dspLckMsg       PI              n
     D   CPFmessage                  80
     D   thisPgm                     10
     D   filename                     8
     D   exitAllowed                  1

      *---------------------------------------------------------------------
      * START of work fields
      *---------------------------------------------------------------------
     D byPassLock      s               n
     D msgText         s            255a
     D msgTitle        s             27a
     D rtnKey          s              3a
     D endLoop         s               n
      *---------------------------------------------------------------------
      * END of work fields
      *---------------------------------------------------------------------
      /free
         //----------------------------------------------------
         // Format the message
         //----------------------------------------------------
         msgTitle = 'Program: ' + thisPgm                                  ;
         msgText = %trim(CPFmessage) + ' ' + 'File ' + %trim(fileName)     +
                   ' is locked for update.'                                ;

         // Determine if user allowed to use ESCAPE
         IF exitAllowed = Yes                                              ;
             msgText = %trim(CPFmessage) + ' F12 to bypass update,'        +
                   ' or ENTER to retry the record.'                        ;
         ELSE                                                              ;
             msgText = %trim(CPFmessage) + ' Press ENTER to attempt'       +
                   ' to get the record again.'                             ;
         ENDIF                                                             ;

         //----------------------------------------------------
         // Display record lock message
         //----------------------------------------------------

         bypassLock = *OFF                                                 ;
         DisplayMessage(msgText:msgTitle)                                  ;
         rtnKey = getJobKey()                                              ;
         IF (rtnKey = 'F3 ' or rtnKey = 'F12') and exitAllowed = Yes       ;
               bypassLock = *ON                                            ;
         ENDIF                                                             ;

         //----------------------------------------------------
         //  Reset job keys and return bypass
         //----------------------------------------------------

         setJobKey()                                                       ;
         RETURN bypassLock                                                 ;

      /END-free
     P dspLckMsg       E 

Bindiding Directory

The binding directory named on the CRTSRVPGM command incudes another service program. Binding entries may reference modules or other service programs. Procedures from the service program SC0065SV will be available to the record lock service program by naming the (SC0930_bd) binding directory on the CRTSRVPGM command.

Binding Directory:   SC0930_BD      Library:   SCROY                         
                                                                             
Type options, press Enter.                                                   
  1=Add   4=Remove                                                           
                                                                             
                                                       -------Creation-------
Opt   Object       Type      Library      Activation   Date         Time     
                                                                             
      SC0065SV     *SRVPGM   *LIBL        *IMMED       11/11/11     08:28:59