26
Thu, Dec
0 New Articles

Genuine Dynamic Program-Exported External Data in IBM i

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

Learn the native dynamic external data mechanism we have had since System/38.

 

As an IBM i developer, you might be proud of the numerous dynamic features in either the OS level or the machine interface (MI) level that allow our developers to produce more reliable and maintainable software products with less effort. For example, the Override commands allow programmers to override (replace) a file that is used by a program or override certain parameters of the file being processed so that changes to either the actual file or manner of processing the file are transparent to the program that uses it.

The journal mechanism allows all changes to a physical file to be recorded as journal entries with no need of change to applications that use the physical file. Recorded journal entries can be used in bi-directional data recovery (applying journaled changes to or removing journaled changes from a physical file) or data replication. The Call/Return model, aka the external program-call model, provides a distinguished dynamic, late-binding program-invocation model. Similar invocation models appeared in some virtual machine architectures, such as the Java Virtual Machine (JVM), which was released in 1995, seventeen years after the announcement of System/38.

Just like the above-mentioned dynamic features, there's yet another dynamic feature that has been available since System/38the external scalar data exported by OPM MI programs that can be resolved by name at runtime with or without dependency on the program that exports it. Since I haven't found any official naming of the data items exported by OPM MI programs, I'll refer to them as program-exported data in the remaining portion of this article.

In my opinion, program-exported data is a complement to the Call/Return program-call model. In this article, I hope to show you the power of combining the two in the application designs.

Program-Exported Data

What is program-exported data? And what is the difference between program-exported data and exported data items in ILE?

The Integrated Language Environment (ILE) introduced to AS/400 at V2R3 was an important effort made by IBM to implement a procedure-oriented, early binding program model (which is widely adopted by common platforms) in AS/400. If you are new to ILE, please refer to the ILE Concepts book for detailed information.

An ILE service program (*SRVPGM, a kind of MI program object with MI object type code hex 0203) can export either procedures or data items. A service program is similar to a dynamic-link library (DLL) in Windows or a shared library in UNIX-like systems. A consumer program of the procedures or data items exported by a service program is linked to the service program at compile time so that, at run time, the consumer program is "invoked," the service program is "loaded" (activated into a proper activation group) implicitly, and the exports become usable.

Just like a DLL or a shared library, a service program can also be "loaded" explicitly at run time; a consumer program can then resolve an individual export of the service program. The following table shows the steps to resolve a procedure or data item exported by a service program, a shared library, or a DLL in IBM i, Linux, and Microsoft Windows, respectively.

DLL Solutions for Resolving   an Exported Data Item

Load a DLL /   Activate a *SRVPGM

Resolve Exports

IBM i Service Program

The Activate Bound Program APIs (QleActBndPgm,  QleActBndPgmLong)  or the Activate Bound Program MI instructions (ACTBPGM,  ACTBPGM2) activate a service program (identified by the input system   pointer addressing the service program) in a specified activation group.

The Get Export (QleGetExp)   and Get Export Long (QleGetExpLong)  APIs resolve a pointer to an export (either data or procedure) either by name   or export number.

Linux Shared Library

The function dlopen()  loads the dynamic library file named by the null-terminated string filename   and returns an opaque "handle" for the dynamic library.

The function dlsym()  takes a "handle" of a dynamic library returned by dlopen() and the   null-terminated symbol (either a function or a variable) name, returning the   address where that symbol is loaded into memory.

Windows DLL

The LoadLibrary  or LoadLibraryEx   Windows APIs load either a DLL or an executable file into the address space of the calling process.

The GetProcAddress  API returns the address of the exported function or variable from a specified DLL by name or ordinal value.

In comparison with the above-shown DLL solutions, the distinguishing feature of program-exported data is that an exported data item can be resolved by searching the export name within all activations within the current MI process instead of searching an export within an activated/loaded service program/DLL. This feature decouples an exported data item from the program that actually exports it, and hence provides additional flexibility. As you will see in the remaining portion of this article, with the complement of program-exported data, the already powerful Call/Return program-invocation model of IBM i can be more powerful.

How Does an OPM MI Program Export a Data Item?

A scalar data item defined in an OPM MI program with external scope (aka externally accessible) is a program-exported data item. To make a scalar data item externally accessible, the EXT scope keyword is used in the Declare (DCL) statement that defines the scalar. A scalar data item with external scope must have the static addressability attribute; therefore, a program-exported data item exported by an OPM MI program is always allocated in the static storage frame of the program at runtime. The following example OPM MI code defines a program-export data item named YOUNG-LION:

DCL DD YOUNG-LION CHAR(64)   STAT EXT INIT (

       "A lion cub"

)                              ;

Note that the EXT scope keyword is necessary, since the default scope attribute of a scalar is internal (INT). The STAT addressability keyword is not necessary, since in OPM MI the addressability of scalars defaults to STAT.

Also note that the INIT keyword in a DCL statement defines the initial value of a data item. When an OPM MI program containing program-exported data is activated, as static scalars of the program, the program-exported data items will be initialized as specified by the INIT keywords.

How Do You Access a Program-Exported Data Item?

The Resolve Data Pointer (RSLVDP) MI instruction resolves a program-exported data item by name and an optional system pointer to an activated program object. The RSLVDP instruction has three operands:

  • Operand 1: A data pointer with addressability to and the attributes of the resolved program-exported data item
  • Operand 2: A 32-byte character scalar indicating the name of the program-exported data item to resolve
  • Operand 3: A system pointer to an activated program that exports the target data or null

If you are not familiar with the program activation process and related terms (such as activation entry), please refer to the Common Program Call Processing section in the documentation of either the Call External (CALLX) MI instruction or the Transfer Control (XCTL) MI instruction.

RSLVDP's document in the Information Center (at either VRM540 or VRM710) says:

Operand 3 specifies a system pointer that identifies the program whose activation is to be searched for the external scalar definition. If operand 3 is null, the instruction searches all activations in the activation group from which the instruction is executed, starting with the most recent activation and continuing to the oldest. The activation under which the instruction is issued also participates in the search. If operand 3 is not null, the instruction searches the activation of the program addressed by the system pointer.

Note the highlighted words "in the activation group from which the instruction is executed," which in my opinion, is incorrect. The resolution scope should always be one of the two default activation groups of the current MI process (i.e., job) rather than the activation group from which the instruction is executed. Which default activation group is chosen depends on the state in which the program that issues the RSLVDP instruction is running. If the program is running in user state, activation entries in the user state default activation group will be searched. If the program is running in system state, activation entries in the system state default activation group will be searched.

If a program-exported data item cannot be found, an External Data Object Not Found (hex 0604) exception is signaled.

After a program-exported data item is resolved and returned in the data pointer operand (operand 1), the returned data pointer can be used directly as operands of MI instructions that accept data pointer operandsfor example, the Copy Bytes Left-Adjusted (CPYBLA) instruction and the Copy Extended Characters Left-Adjusted With Pad (CPYECLAP) instruction. You can also retrieve the addressability of the program-exported data by issuing a Set Space Pointer from Pointer (SETSPPFP) on the returned data pointer.

System built-ins that can be used in ILE high-level languages to resolve a program-exported data item include _RSLVDP2 and _RSLVDP3, the ILE RPG prototypes of which are the following (see mih-ptr.rpgleinc):

     /**

     * @BIF _RSLVDP2   (Resolve Data Pointer (RSLVDP))

     */

     d rslvdp2         pr                  extproc('_RSLVDP2')

     d     dta_ptr                     *

     d     obj_name                 32a

     /**

     * @BIF _RSLVDP3   (Resolve Data Pointer (RSLVDP))

     */

     d rslvdp3         pr                 extproc('_RSLVDP3')

     d    dta_ptr                     *

     d     obj_name                 32a

     d     pgm_ptr                     *

An invocation to _RSLVDP2 is equivalent to an invocation to _RSLVDP3 with pgm_ptr set to null.

The following is a pair of simple example programs. OPM MI program T083_B (t083_b.emi) exports two external data objects, named NOVEL and PERSONAL-INFO. ILE RPG program T083 (t083.rpgle) tries to resolve the exports of T083_B via _RSLVDP3 and _RSLVDP2, respectively.

T083_B

/**

* @file t083_b.emi

*

* Exports:

* - Character scalar named NOVEL

* - Data structure named PERSONAL-INFO

*/

DCL DD NOVEL CHAR(32) EXT

         INIT("Family, Spring, and Fall") ;

DCL DD PERSONAL-INFO CHAR(64) EXT ;

       DCL DD NAME   CHAR(32) DEF(PERSONAL-INFO) POS(1) INIT(

         "Sun   Wukong"

       )                       ;

       DCL DD AGE   PKD(5,0) DEF(PERSONAL-INFO) POS(33) INIT(

           P"1500"

       )                       ;

PEND                             ;

To compile an OPM MI program, you may choose a wrapper program of the Create Program (QPRCRTPG) API (e.g., mic).

T083

     /**

     * @file t083.rpgle

     *

     * Test of   _RSLVDP3, _RSLVDP2.

     */

     h dftactgrp(*no)

     /copy mih-ptr

     /copy mih-pgmexec

     d spc_ptr         s               *

     d ext_data_obj   s             32a     based(spc_ptr)

     d ext_ds         ds                 qualified

     d                                    based(spc_ptr)

     d   name                       32a

     d   age                         5p 0

     d                 ds

     d proc_ptr                       *   procptr

     d dta_ptr                         *   overlay(proc_ptr)

     d ssf            s               *

     d pgm             s               *

     d dta_name       s             32a

     /free

           // [1] Test   of _RSLVDP3

           // [1.1]   Resolve program object T083_B

             rslvsp_tmpl.obj_type = x'0201';

          rslvsp_tmpl.obj_name = 'T083_B';

           rslvsp2(pgm :   rslvsp_tmpl);

           // [1.2]   Activate program T083_B

           actpg(ssf :   pgm);

           // [1.3]   Resolve external data object NOVEL

           dta_name =   'NOVEL';

           rslvdp3(dta_ptr   : dta_name : pgm);

           // [1.4]   Obtain space pointer from dta_ptr

           spc_ptr =   setsppfp(proc_ptr);

           dsply 'Novel'   '' ext_data_obj;

           // [2] Test   of _RSLVDP2

             deactpg1(pgm);           //   Deactivate PGM

          actpg(ssf : pgm);       // Activate PGM again

           dta_name =   'PERSONAL-INFO';

           // [2.1]   Resolve external data object PERSEONAL-INFO

             rslvdp2(dta_ptr : dta_name);

           // Obtain   space pointer from dta_ptr

          spc_ptr = setsppfp(proc_ptr);

           dsply   ext_ds.name '' ext_ds.age;

           *inlr = *on;

     /end-free

     /** Example Output

     *

     * 4 > call t083

     *     DSPLY   Novel   Family, Spring, and   Fall

     *     DSPLY   Sun Wukong                             1500

     */

Notes

[1] Test of _RSLVDP3

[1.1] Resolve program object T083_B

[1.2] Activate program T083_B

[1.3] Resolve external data object NOVEL

[1.4] Obtain space pointer from dta_ptr

[2] Test of _RSLVDP2

[2.1] Resolve external data object PERSEONAL-INFO

A Polymorphism Example Based on Program-Exported Data

It is an important feature of program-exported data that the target program-exported data item can be resolved by export name independently of the program that actually exports the data item. It would be extremely flexible to be able to combine this feature with the dynamic features provided by the external program-call mechanism. In this section, I'll show you a polymorphism example implemented via program-exported data.

In this example, OPM MI program KITTEN (kitten.emi) exports a collection of methods that are expected to be implemented by an animal via a program-exported data item named ANIMAL-METHODS. Each method is identified by an instruction pointer addressing the method's starting MI instruction in KITTEN:

  • Method chase() accepts no parameter
  • Method taste() accepts an input character parameter, food

Another OPM MI program, PUPPY (puppy.emi), exports the same collection of methods as KITTEN does, while PUPPY's implementation of these methods is different.

ILE RPG program TST_ANIMAL (tst_animal.rpgle) consumes the methods of an animal object, despite having no knowledge of what exactly the animal is. TST_ANIMAL resolves a data pointer addressing the program-exported data ANIMAL-METHODS via the RSLVDP instruction, retrieves a space pointer addressing the exported data via the SETSPPFP instruction, retrieves a system pointer to the actual "animal" (the program object that actually exports ANIMAL-METHODS) by issuing the Set System Pointer from Pointer (SETSPFP) instruction on one of the "methods" (instruction pointers) in ANIMAL-METHODS, and then invokes methods of the animal object via the instructions stored in the export. See the embedded comments in the following source of TST_ANIMAL.

Source of the OPM MI programs KITTEN, PUPPY, and the ILE RPG program TST_ANIMAL are the following:

KITTEN

/**

* @file kitten.emi

*/

dcl insptr @method parm           ;

dcl spcptr @p parm               ;

dcl ol pl-main(@method, @p) parm ext min(0);

entry *(pl-main) ext             ;

       stpllen   argc           ;

       cmpnv(b) argc, 0   / eq(see-you) ;

       b       @method        ;

see-you:

       rtx     *               ;

dcl dd argc bin(4) auto           ;

/* Exports: methods of an animal */

dcl dd animal-methods char(64) STAT EXT bdry(16)                 ;

       dcl insptr   @chase def(animal-methods) pos(1) init(chase)   ;

       dcl insptr   @taste def(animal-methods) pos(17) init(taste) ;

       dcl ptr *         def(animal-methods) pos(33)             ;

       dcl dd *   char(16) def(animal-methods) pos(49) init(

           "KITTEN-MOTHODS"

       )                                            ;

/* Method Chase() */

chase:

       cpyblap msg,   "A kitten chases mice.", " " ;

       %sendmsg(msg,   32)       ;

brk       "CHASE"                   ;

       b       see-you         ;

/* Method Taste() */

taste:    

dcl dd food char(16) bas(*)     ;

       cpybla msg(1:16), @p->food             ;

       cpyblap   msg(17:16), "taste bad :(", " " ;

       cmpbla(b)   @p->food, "Fish" / neq(=+2) ;

       cpyblap   msg(17:16), "TASTY!", " "     ;

:

       %sendmsg(msg,   32)       ;

brk       "TASTE"                   ;

       b       see-you         ;

dcl dd msg char(32) auto         ;

pend                             ;

PUPPY

/**

* @file puppy.emi

*/

dcl insptr @method parm           ;

dcl spcptr @p parm               ;

dcl ol pl-main(@method, @p) parm ext min(0);

entry *(pl-main) ext             ;

       stpllen   argc           ;

       cmpnv(b) argc, 0   / eq(see-you) ;

       b       @method         ;

see-you:

       rtx     *               ;

dcl dd argc bin(4) auto           ;

/* Exports: methods of an animal */

dcl dd animal-methods char(64) STAT EXT bdry(16)                 ;

       dcl insptr   @chase def(animal-methods) pos(1) init(chase)   ;

       dcl insptr   @taste def(animal-methods) pos(17) init(taste) ;

       dcl ptr *        def(animal-methods) pos(33)             ;

       dcl dd *   char(16) def(animal-methods) pos(49) init(

           "PUPPY-MOTHODS"

       )                                               ;

/* Method Chase() */

chase:

       cpyblap msg,   "A puppy chases cats.", " " ;

       %sendmsg(msg,   32)       ;

brk       "CHASE"                   ;

       b       see-you         ;

/* Method Taste() */

taste:    

dcl dd food char(16) bas(*)     ;

       cpybla msg(1:16), @p->food             ;

       cpyblap msg(17:16),   "taste bad :(", " " ;

       cmpbla(b)   @p->food, "Meat" / neq(=+2) ;

       cpyblap   msg(17:16), "TASTY!", " "     ;

:

       %sendmsg(msg,   32)       ;

brk       "TASTE"                   ;

       b       see-you         ;

dcl dd msg char(32) auto         ;

pend                             ;

TST_ANIMAL

     /**

     * @file   tst_animal.rpgle

     *

     */

     h dftactgrp(*no)

     /copy mih-ptr

     /copy mih-pgmexec

     d spc_ptr         s               *

     d methods         ds                  based(spc_ptr)

     d   chase                         *   procptr

     d   taste                         *   procptr

     d   no_more                       *

     d   eye_catcher                 16a

     d                 ds

     d proc_ptr                      *   procptr

     d dta_ptr                         *   overlay(proc_ptr)

     d ssf             s               *

     d argds           ds

     d   insptr                       *   procptr

     d   argv                         *   dim(2)

     d   args                         *   dim(3) overlay(argds)

     d pgm             s               *

     d dta_name       s             32a

     d food           s             16a     inz('Meat bones')

     /free

           // [1]   Resolve external data object ANIMAL-METHODS

           dta_name =   'ANIMAL-METHODS';

           monitor;

                 rslvdp2(dta_ptr : dta_name);

           on-error;

               // Error   handling

           endmon;

           // [2] Obtain   a space pointer from dta_ptr so that

           //   instruction pointers in data struture @var methods

           // become   valid.

           spc_ptr =   setsppfp(proc_ptr);

           // [3]   Retrieve a system pointer to the program object

           // which   exports instruction pointer @var chase

           pgm =   rpg_setspfp(chase); // Debug: ev   %var(pgm)

           // [4] Invoke   method Chase()

           insptr =   chase;

           callpgmv(pgm   : args : 1);

           // [5] Invoke   method Taste()

           insptr = taste;

           argv(1) =   %addr(food);

           callpgmv(pgm   : args : 2);

           *inlr = *on;

     /end-free

Compile the example programs, run TST_ANIMAL like the following, and examine the output of TST_ANIMAL.

4 > call kitten

4 > call tst_animal

     A kitten chases   mice.

     Meat bones     taste bad :(

4 > rclrsc

4 > call puppy

4 > call tst_animal

     A puppy chases   cats.

     Meat bones     TASTY!

Yeah, we did it!

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: