× The internal search function is temporarily non-functional. The current search engine is no longer viable and we are researching alternatives.
As a stop gap measure, we are using Google's custom search engine service.
If you know of an easy to use, open source, search engine ... please contact support@midrange.com.




What is the best way to use Activation groups? I am really worried about
file access.

There's no "One True Way" of using activation groups. You should use them as they are appropriate for your application.


I have a lot of Utility procedures with core business logic that is right
now repeated in most of the programs.
I am trying a progressive approach as to when ever we change a particular
program find the generalizable procedures and put it in a service program.
Change the program to use these procedures. Also I have made all the utility
Service Programs to run in one activation group.

Unless you have a good reason not to, I'd suggest always putting a service program in ACTGRP(*CALLER).

A service prgoram is intended to provide services to the program that calls it. That's why it should always run in the same activation group as the program that calls it. It's the caller who should be deciding on the activation group.

There are exceptions, however. For example, when a service program is called from Java, I prefer to put it in a named activation group. Otherwise, the Java program (which isn't ILE and knows nothing about ACTGRPs) may load it into the wrong place.

The major question I have is:
Should I use it with OVRDBF ..... Share(*YES) ? What are the advantages over
not using  Share(*YES)

Also how do I control open and close of files.. I do not want to open and
close a file each time a procedure is called.

These questions aren't related to activation groups (at least not directly), but I'll answer them anyway.

Should you use SHARE(*YES)? I don't know... do you need share the ODP between more than one program? In other words, do you want a SETLL in one program to affect the record that gets read in a different program? If so, specify SHARE(*YES). If not, specify SHARE(*NO) which is the default.

How do you control open and close of files? I prefer to open everything when my service program is called for the first time, and then leave them open until the activation group ends (or the caller specifically asks for them to be closed)

To implement this, I add "open" and "close" subprocedures to my service program.

Consider a simple example... You want to write a module that works with customer information. To start with, it'll have three main subprocedures:

cust_getAddr() -- gets the address information for a customer.
cust_startOrdList() -- start a list of orders for customer
cust_readOrdList() -- read the next order from the list

To make these subprocedures work, you'll need two files. CUSTMAS which as the customer's address info in it, and ORDBYCUST which is a logical of the orders file by customer number.

To open & close the files, I'll add two more subprocedures:

cust_init() -- initialize service program (open files)
cust_done() -- done with service program (close files)

Note that I don't want my caller to have to call these. If for some reason the calling program NEEDS to be able to control when the files are opened and when they're closed, I'll have it call the above subprocedures. But I want them to be optional -- the caller ONLY calls them if it needs to. Otherwise, it can just call cust_getAddr() and cust_startOrdList() and the files will "magically" be opened before they're used.

I'll also have a subprocedure that I can call to get an error message, in case something should go wrong. That subproc will be
cust_error() -- get error message (and optionally error number)


Here's a sample of how I might implement this service program:

     H NOMAIN

     FCUSTFILE  IF   E           K DISK    USROPN
     FORDBYCUST IF   E           K DISK    USROPN

      /copy prototypes,custr4

     D CEE4RAGE        PR
     D   procedure                     *   procptr const
     D   feedback                    12A   options(*omit)

     D SetError        PR
     D   ErrNo                       10I 0 value
     D   Msg                         80A   varying const

     D Initialized     s              1N   inz(*OFF)
     D LastCust        s              8A
     D save_Errno      s             10I 0 inz(0)
     D save_ErrMsg     s             80A   varying
     D                                     inz('No Error')

      *+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
      * cust_init():  Initialize customer module
      *   Note: If you don't call this manually, it'll be called
      *         automatically when you call another subprocedure
      *+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
     P cust_Init       B                   export
     D cust_Init       PI
      /free
         if (Initialized);
           return;
         endif;

         open CUSTFILE;
         open ORDBYCUST;

         CEE4RAGE( %paddr(Cust_Done): *omit );
         Initialized = *on;
      /end-free
     P                 E


      *+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
      * cust_Done():  Done with module
      *   Note: If you don't call this manually, it'll be called
      *         automatically when the activation group is reclaimed
      *+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
     P cust_Done       B                   export
     D cust_Done       PI
      /free
         if %open(CUSTFILE);
           close CUSTFILE;
         endif;
         if %open(ORDBYCUST);
           close ORDBYCUST;
         endif;
         Initialized = *OFF;
      /end-free
     P                 E


      *+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
      * cust_getAddr(): Get a customer's address
      *
      *     CustNo = (input) customer number to retrieve
      *       Addr = (output) Customer's address
      *
      * returns *ON if successful, *OFF otherwise
      *+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
     P cust_getAddr    B                   export
     D cust_getAddr    PI             1N
     D   CustNo                       8A   const
     D   Addr                              likeds(Cust_address_t)
     D Err             s             10I 0
      /free
         Cust_Init();

         chain(e) CustNo CUSTFILE;
         if %error;
            err = %status();
            SetError(CUST_ECHNERR: 'RPG status ' + %char(err)
                    + ' on CHAIN operation.');
            return *OFF;
         endif;

         if not %found;
            SetError(CUST_ENOTFND: 'Customer Not Found');
            return *OFF;
         endif;

         Addr.Name    = Name;
         Addr.Street  = Street;
         Addr.City    = City;
         Addr.State   = State;
         Addr.ZipCode = ZipCode;
         return *ON;
      /end-free
     P                 E


      *+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
      * cust_StartOrdList(): Start a list of orders for a customer
      *
      *    CustNo = (input) Customer to get orders for
      *+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
     P cust_StartOrdList...
     P                 B                   Export
     D cust_StartOrdList...
     D                 PI             1N
     D   CustNo                       8A   const
      /free
         Cust_Init();

         setll CustNo ORDBYCUST;
         if not %equal;
            SetError(CUST_ENOORDS: 'No Orders Found for Cust '
                                 + CustNo );
            return *OFF;
         endif;

         LastCust = CustNo;
         return *ON;
      /end-free
     P                 E


      *+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
      * cust_ReadOrdList(): Get next order from order list
      *
      *   Ord = (output) Order number of next order
      *
      * Returns *ON if successful, or *OFF at the end of the list
      *+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
     P cust_ReadOrdList...
     P                 B                   Export
     D cust_ReadOrdList...
     D                 PI             1N
     D   Ord                          5A
      /free
         Cust_Init();

         reade LastCust ORDBYCUST;
         if %eof;
            return *OFF;
         endif;
         Ord = OrderNo;
         return *ON;
      /end-free
     P                 E


      *+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
      * cust_Error(): Get last error that occurred in this module
      *
      *   ErrNo = (output/optional) Error number
      *
      * Returns the last error message
      *+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
     P cust_Error      B                   Export
     D cust_Error      PI            80A   varying
     D   ErrNo                       10I 0 options(*nopass:*omit)
      /free
         Cust_Init();

         if %parms>=1 and %addr(Errno)<>*NULL;
            ErrNo = save_Errno;
         endif;
         return save_ErrMsg;
      /end-free
     P                 E


      *+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
      * SetError(): (INTERNAL) set the error number and message
      *+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
     P SetError        B
     D SetError        PI
     D   ErrNo                       10I 0 value
     D   Msg                         80A   varying const
      /free
         save_Errno = Errno;
         save_ErrMsg = Msg;
      /end-free
     P                 E


Note the following:

 a) cust_getAddr() and cust_startOrdList() call cust_init() to open
    the files.  Since that subprocedure will do nothing if the
    Initialized variable is *ON, the files won't get opened twice.

 b) cust_init() uses the CEE4RAGE() API to register a subprocedure
    that will be automatically called when the activation group is
    ended.  It registers cust_done() so that the files can be closed.

    (Technically, this is unnecessary, since files are closed
     automatically when an actgrp ends -- however, I personally like
     to have code that explicitly closes the files that's visible in
     my code.  Plus, you might create a temporary file in QTEMP or
     a temporary user space, or something like that, that should be
     deleted when the actgrp ends -- this gives you the chance to do
     that, or any other code you want to run when the caller is done.)

 c) Because cust_init() is called by cust_getAddr() and
    cust_startOrdList(), my caller doesn't HAVE to call it.  Likewise,
    because cust_done() will automatically be called when the actgrp
    ends, the caller doesn't HAVE to call it.

 d) However, if the caller WANTS my files to close without reclaiming
    the ACTGRP, or he wants them to be closed and then re-opened, he
    has the option of calling cust_init() or cust_done(), making things
    a little more flexible.

 e) The error constants, and customer address data structure are defined
    with the prototypes in the /COPY member.  I always take pains to start
    everything that's in that /COPY member with a common prefix.  In this
    case I started everything with CUST_.  If all of my modules/srvpgm's
    follow this convention, I won't run into trouble with the same
    defintions popping up for another module.

 f) Since my module is called CUSTR4 (for CUST, RPG IV) it'll be
    easy for the caller to understand where the code is.  Anytime he sees
    a call to a CUST_ routine, he'll know it's calling something in the
    CUSTR4 module.

Here's what the /COPY member looks like:


      /if defined(CUST_PROTOTYPE_DEFINED)
      /eof
      /endif
      /define (CUST_PROTOTYPE_DEFINED)

      *+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
      * cust_init():  Initialize customer module
      *   Note: If you don't call this manually, it'll be called
      *         automatically when you call another subprocedure
      *+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
     D cust_Init       PR


      *+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
      * cust_Done():  Done with module
      *   Note: If you don't call this manually, it'll be called
      *         automatically when the activation group is reclaimed
      *+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
     D cust_Done       PR


      *+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
      * cust_getAddr(): Get a customer's address
      *
      *     CustNo = (input) customer number to retrieve
      *       Addr = (output) Customer's address
      *
      * returns *ON if successful, *OFF otherwise
      *+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
     D cust_getAddr    PR             1N
     D   CustNo                       8A   const
     D   Addr                              likeds(Cust_address_t)


      *+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
      * cust_StartOrdList(): Start a list of orders for a customer
      *
      *    CustNo = (input) Customer to get orders for
      *+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
     D cust_StartOrdList...
     D                 PR             1N
     D   CustNo                       8A   const


      *+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
      * cust_ReadOrdList(): Get next order from order list
      *
      *   Ord = (output) Order number of next order
      *
      * Returns *ON if successful, or *OFF at the end of the list
      *+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
     D cust_ReadOrdList...
     D                 PR             1N
     D   Ord                          5A


      *+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
      * cust_Error(): Get last error that occurred in this module
      *
      *   ErrNo = (output/optional) Error number
      *
      * Returns the last error message
      *+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
     D cust_Error      PR            80A   varying
     D   ErrNo                       10I 0 options(*nopass:*omit)

      *+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
      * Data structure that contains a customer's address
      *+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
     D CUST_Address_t  DS                  qualified
     D                                     based(TEMPLATE)
     D   Name                        25A
     D   Street                      30A
     D   City                        15A
     D   State                        2A
     D   ZipCode                      9S 0

      *
      *  Error message numbers:
      *
     D CUST_ECHNERR    C                   1101
     D CUST_ENOTFND    C                   1102
     D CUST_ENOORDS    C                   1103

Hope that helps...

As an Amazon Associate we earn from qualifying purchases.

This thread ...

Follow-Ups:
Replies:

Follow On AppleNews
Return to Archive home page | Return to MIDRANGE.COM home page

This mailing list archive is Copyright 1997-2024 by midrange.com and David Gibbs as a compilation work. Use of the archive is restricted to research of a business or technical nature. Any other uses are prohibited. Full details are available on our policy page. If you have questions about this, please contact [javascript protected email address].

Operating expenses for this site are earned using the Amazon Associate program and Google Adsense.