ILE provides many programming enhancements over the Original Program Model (OPM). One of those enhancements is in the way modules of code call one another. OPM only allows dynamic calls between AS/400 programs. ILE permits modules to be bound together statically to form one ILE program. Static calls are faster than dynamic calls, but, more important, they let programmers create building blocks of reusable code that can be integrated into applications as needed.
ILE is a better way to design industrial-strength applications, but it comes at a price. In this case, the price is a more complex compilation process. An ILE program is made of modules. Those modules may be standalone objects, or they may be collected in service programs. In either case, modules must be bound together each time a program is created, and thats what makes compilation more difficult under ILE than under OPM.
In this article, I review the concept of modules and show you the simplest ways to bind them into programsby listing modules and service programs in the Create Program (CRTPGM) command and by using a binding directory. In Part 2 of this series, I will discuss service programs in more detail and introduce you to binder language and service program signatures.
ILE Program Creation and Binding by Copy
When a programmer develops an OPM program, he writes source code and compiles it into a program. When a programmer develops an ILE program, he still writes source code, but he compiles it into an ILE module, not into a program. After this ILE module is created, it can be used in the creation of ILE programs.
These modules can be written in different high-level languages (HLLs). In any event, the modules are combined into a program in a process known as binding by copy. Ill illustrate how these concepts are used through the use of a business example, in conjunction with some coding examples.
Business Application for ILE Programming
Suppose you work for a retail store that sells liquid propane gas to consumers. At the end of every month, you have to compute the average cost of a gallon of liquid propane. The cost of a gallon is not constant because the wholesale prices and vendors
frequently change. During the month, you collect purchase information in a physical file named LPURCHASES. At month-end, you have to calculate the monthly costs and print out a simple report.
The application driver module is written in RPG IV and is named LPCOSTRPG. It has a source member attribute of RPGLE (see Figure 1). LPCOSTRPG will produce a simple report that lists the last date that the LPURCHASES file was changed, the total gallons purchased, the total liquid propane cost, and the average cost per gallon.
The RPG IV driver module uses the CALLB operation code to issue static calls to two other modules, one of them coded in ILE CL, the other in RPG IV.
This source code for CL module LPCHKDBCL is shown in Figure 2. LPCHKDBCL checks certain file member attributes of the LPURCHASE physical file. First, it determines that the file member exists and that it contains data. If either of these tests fails, the module sets the value of the error flag parameter to 1. If no errors are found, the module extracts the last changed date of LPURCHASES, in the format YYMMDD.
As program control returns to LPCOSTRPG, if the value of ErrorFlag is 0, then the program calls module LPAVGRPG and prints the report. If the value of ErrorFlag is 1, then an error message will be printed on the monthly report when subroutine PrnErrRpt is executed.
The other RPG IV module is LPAVGRPG (see Figure 3). This module reads the LPURCHASES file and calculates the monthly purchase quantity, the monthly total cost, and the average cost per gallon. All these values will be returned to the LPCOSTRPG module and printed out on the report.
The source code must be compiled into ILE modules, using the appropriate Create xxx Module (CRTxxxMOD) commands, where xxx is the language (RPG, CBL, C, or
CL) in which a module is written. After the CRTxxxMOD commands have completed successfully, objects of type *MODULE will exist. The last step is to create the ILE program object by binding these modules by copy. For this step, use the CRTPGM command. All these commands are listed in Figure 4. When these commands are completed, the LPCOSTRPG program can be called from the command line.
Binding by copy means that each modules code is included in the program object. The resulting *PGM object is slightly larger than the sum of the sizes of the modules that make it up.
I have placed ILE COBOL equivalents of the RPG IV examples on the Midrange Computing Web site (http://www.midrangecomputing.com/ mc/98/10). If you have an interest in ILE COBOL or would like to see how different ILE languages can be integrated on the AS/400, I encourage you to take a look at these programming examples.
Service Programs and Binding by Reference
Binding by copy is effective, but has two disadvantages. The first is program size. As mentioned previously, the size of the ILE program object is slightly larger than the size of the modules used when the CRTPGM command was invoked to create the program. If your shop has one ILE program using one or a few modules, your DASD probably wont be adversely affected. But if your shop has hundreds of programs that were created through binding by copy to the same few modules, then expensive DASD space will probably be negatively affected.
The other problem is that the program must be updated when a module changes. The reason for this is that the object code contained inside the program object is not changed when the *MODULE object is recreated. The program must be re-created (with CRTPGM) or updated (with UPDPGM) to bind in the modules updated code.
To address these and other issues, ILE service programs were developed. A service program is a collection of modules that cannot be executed as a program. Instead, the service program is bound by reference to other modules to make a program.
To create service programs, you still have to create the *MODULE objects by using the CRTxxxMOD command. But then, in order to create a service program, you must use
the Create Service Program (CRTSRVPGM) command. After you use CRTSRVPGM, you must use CRTPGM with a different syntax. In these examples, I make service programs out of LPCHKDBCL and LPAVGRPG, and then I bind these service programs by reference to LPCOSTRPG (see Figure 5).
Notice the use of the EXPORT(*ALL) parameter directive in the CRTSRVPGM command. This directive enables the service programs to export all the data and procedures that are exported by the specified modules. I will explain the EXPORT parameter in greater detail in Part 2 of this series.
Once these commands have been completed, LPCOSTRPG can be called again from the command line. The output from the program will be the same even though the method of module binding is different.
Once again, look at the new object sizes. Compare the size of the new program that uses binding by reference to the size of the old program that uses binding by copy. The size of the new ILE program should be less than the size of the old program.
ILE Utilities
Fortunately, OS/400 provides some useful utilities that help us get a handle on which objects we are using for our ILE programs. One of my favorite utilities is the Display Program (DSPPGM) command, because it provides an absolute ILE treasure chest of information.
The output from this command provides a lot of information about the ILE program, including, but not limited to, which modules, service programs, and activation groups the program uses. There is too much information to print here, but it is really worth examining.
Binding Directories
Binding directories are designed to keep track of the modules and service programs that are used in an ILE application. By using a binding directory during the program creation process, you avoid having to specify the individual modules and/or service programs at the command line.
Specifying four modules and/or service programs from the command line during the binding process isnt that difficult. But I can tell you from experience that when I had to work with ported programs that had about 100 modules that I didnt write, I was glad that the original programmers had the foresight to use binding directories. Otherwise, I would not have been able to understand how the applications worked.
The first step in working with a binding directory is to create it using the Create Binding Directory (CRTBNDDIR) command.
CRTBNDDIR BNDDIR(xxx/LPAPPBND)
This creates the object LPAPPBND with the object attribute of *BNDDIR in the specified library.
After the binding directory is created, use the Work with Binding Directory (WRKBNDDIR) command to work with the binding directory entries. This is where you enter the modules and/or service programs that the ILE program will use. The user interface is quite straightforward and allows you to easily enter modules and/or service programs into the binding directory. When you are done specifying the module and/or service program information, your WRKBNDDIR command screen should look like the screen displayed in Figure 6.
Although I entered these binding entries by using the WRKBNDDIR utility, I could have made such entries from the command line. Figure 7 shows what these commands and meanings are.
When you use the CRTPGM command, you can simply specify the binding directory, instead of the modules, and the LPCOSTRPG program will be created again. This is the specific CRTPGM syntax used in this example:
CRTPGM PGM(xxx/LPCOSTRPG) +
BNDDIR(xxx/LPAPPBND) +
ACTGRP(QILE)
Once again, when the program is called from the command line, the same report as before is printed.
ILE and AS/400 Application Directions
I have shown you several ways to bind modules when you run CRTPGM. First, you can list the modules that are to be bound together in the MODULE parameter. The modules will be bound by copy. Second, you can put the modules into service programs and list the service programs on the SRVPGM parameter. The modules will be bound by reference.
Last, you can list both modules and service programs in a binding directory. When you create the program, use the BNDDIR parameter, rather than the MODULE or SRVPGM parameters.
Ill be the first to admit that getting started using ILE is not the easiest thing to do. By the same token, I will also be one of the first to say that learning ILE concepts is not that difficult either.
By using a step-by-step approach, any proficient AS/400 professional can learn ILE. Its a safe bet that the vast majority of new programming enhancements on the AS/400 will apply to ILE. ILE represents the promising future of AS/400 application development. This includes programming Internet-enabled applications on the AS/400. The sooner AS/400 professionals embrace ILE, the better off their future careers will be.
References
AS/400 ILE Concepts (SC41-5606, CD-ROM QB3AQ701) ILE Application Development Examples (SC41-5602, CD-ROM QB3AQ400) ILE COBOL for AS/400 Programmers Guide ( SC09-2540, CD-ROM QB3AG400)
ILE COBOL for AS/400 Reference ( SC09-2539, CD-ROM QB3AG300) ILE RPG for AS/400 Programmers Guide (SC09-2507, CD-ROM QB3AGY00) ILE RPG for AS/400 Reference (SC09-2508, CD-ROM QB3AGZ00)
*================================================================
* Driver program that will statically call a CL module to check
* the attributes of the LPURCHASES physical file and statically
* call an RPG IV module that will calculate cost figures. If
* there are no file errors, the results will be printed out.
* If there are file errors, an error message will be printed.
*================================================================
FLPReport o e printer oflind(*in77)
DLPQuanAmt s 8s 2
DLPPriceAmt s 8s 2
DAvgLPPrice s 8s 4
DErrorFlag s 1a
DUpdateDate ds
DUpdateYY 2a
DUpdateMM 2a
DUpdateDD 2a
C callb LPCHKDBCL
C parm ErrorFlag
C parm UpdateDate
C ErrorFlag ifeq 0
C callb LPAVGRPG
C parm LPQuanAmt
C parm LPPriceAmt
C parm AvgLPPrice
C write GoodDetail
C else
C write ErrDetail
C endif
C eval *inlr = *on
Figure 1: RPG IV driver module to determine monthly LP costs
/*================================================================*/
/* Check for existence of LPURCHASES file, number of records, */
/* and last changed date of the file. If errors are encountered, */
/* the &ERRFLAG value will be changed to 1. */
/*================================================================*/
PGM PARM(&ERRFLAG &YMDATE)
DCL VAR(&ERRFLAG) TYPE(*CHAR) LEN(01)
DCL VAR(&YMDATE) TYPE(*CHAR) LEN(06)
DCL VAR(&LPRECORDS) TYPE(*DEC) LEN(10 0)
DCL VAR(&LUPDATE) TYPE(*CHAR) LEN(13)
CHGVAR VAR(&ERRFLAG) VALUE(0) /* assume all OK */
/* Check for file attributes, generate error if not found */
RTVMBRD FILE(*LIBL/LPURCHASES) NBRCURRCD(&LPRECORDS) +
CHGDATE(&LUPDATE)
MONMSG MSGID(CPF0000 CPF9812) EXEC(DO)
CHGVAR VAR(&ERRFLAG) VALUE(1)
SNDPGMMSG MSGID(CPF9898) MSGF(QCPFMSG) +
MSGDTA(File Error with LPURCHASES file) +
MSGTYPE(*INFO)
ENDDO
/* Extract YYMMDD portion of the LPURCHASES file timestamp */
CHGVAR VAR(&YMDATE) VALUE(%SST(&LUPDATE 2 6))
/* Check for file records, generate error if records equals zero */
IF COND(&LPRECORDS = 0) THEN(DO)
CHGVAR VAR(&ERRFLAG) VALUE(1)
SNDPGMMSG MSGID(CPF9898) MSGF(QCPFMSG) +
MSGDTA(No records in LPURCHASES file) +
MSGTYPE(*INFO)
ENDDO
/* Check for error flag, generate no file errors message */
IF COND(&ERRFLAG = 0) THEN(DO)
SNDPGMMSG MSGID(CPF9898) MSGF(QCPFMSG) +
MSGDTA(There were no file errors for LPURCHASES) +
MSGTYPE(*INFO)
ENDDO
ENDPGM
Figure 2: ILE CL module to retrieve LPURCHASES file information
*================================================================
* Calculate total quantity, total cost and average per gallon cost
* for the liquid propane monthly purchases.
*================================================================
FLPurchasesif e k disk
DLPQuanAmt s 8s 2
DLPPriceAmt s 8s 2
DAvgLPPrice s 8s 4
C *entry plist
C parm LPQuanAmt
C parm LPPriceAmt
C parm AvgLPPrice
C move *off *in99
C z-add *zeros LPQuanAmt
C z-add *zeros LPPriceAmt
C z-add *zeros AvgLPPrice
C *loval setll LPurchases
C read LPurchases 99
C dow (not *IN99)
C add LPQuantity LPQuanAmt
C add LPPrice LPPriceAmt
C read LPurchases 99
C enddo
C if LPQuanAmt <> 0
C eval AvgLPPrice = ( LPPriceAmt / LPQuanAmt )
C endif
C return
Figure 3: RPG IV module to compute monthly LP cost figures
CRTRPGMOD MODULE(xxx/LPCOSTRPG) SRCFILE(xxx/QRPGLESRC)
CRTRPGMOD MODULE(xxx/LPAVGRPG) SRCFILE(xxx/QRPGLESRC)
CRTCLMOD MODULE(xxx/LPCHKDBCL) SRCFILE(xxx/QCLSRC)
CRTPGM PGM(xxx/LPCOSTRPG) +
MODULE(xxx/LPCOSTRPG xxx/LPCHKDBCL xxx/LPAVGRPG) +
ACTGRP(QILE)
Figure 4: Commands to bind by copy ILE modules into a program object
CRTSRVPGM SRVPGM(xxx/LPCHKDBCL) EXPORT(*ALL)
CRTSRVPGM SRVPGM(xxx/LPAVGRPG) EXPORT(*ALL)
CRTPGM PGM(xxx/LPCOSTRPG) +
MODULE(xxx/LPCOSTRPG) +
BNDSRVPGM(xxx/LPCHKDBCL xxx/LPAVGRPG) +
ACTGRP(QILE)
Figure 5: Commands to bind by reference ILE service programs into a program object
Figure 6: WRKBNDDIR screen for LPAPPBND binding directory
Command Name Function
ADDBNDDIRE Add a binding directory entry CRTBNDDIR Create a binding directory DLTBNDDIR Delete a binding directory DSPBNDDIR Display a binding directory RMVBNDDIRE Remove a binding directory entry WRKBNDDIR Work with a binding directory WRKBNDDIRE Work with a binding directory entry
Figure 7: CL commands for binding directories
LATEST COMMENTS
MC Press Online