Asynchronous Processing with Open List APIs

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

By now, everyone knows what the initials API stand for. They stand for AS/400 Private Investigator. Well, actually they stand for Application Programming Interface, but they could just as well stand for the first interpretation because APIs do the same things that private investigators do. In the world of the AS/400, APIs explore their environment (more commonly referred to as the machine interface), gathering information not normally available to the average Joe. But unlike a PI, you do not need to pay an API to go search for deep dark secrets and report back to you. APIs come with your AS/400 Operating System, courtesy of IBM.

At first glance, our comparison between APIs and private investigators probably appears to be nothing but poppycock. But there is one type of API that will actually perform its work while your program is busy off doing something else. This particular classification of API is called the Open List API. In this article, we will explore the mysteries of these little known APIs, and if we do our job right, leave you wanting more. In case you do want more, see the Web sidebar titled “Additional Open List API Information,” at

Two Heads Are Better than One

APIs that return a great deal of information will generally do so to an object on the AS/400 called a user space. And even though Open List APIs can return a lot of information, they return the retrieved information into a program variable. The reason Open List APIs return their information through a receiver variable is that these APIs return a “partial” list of the information. While your program is processing the original information the API returned, the API is out busily getting more information for your program to process. This type of processing is referred to as asynchronous processing.

Open List APIs were created with a single goal in mind—speed. Open List APIs will return the records you request in the blink of an eye. And while your program is acting on the initial partial list, the API will continue to finish the list. Asynchronous processing is especially helpful in interactive programming, as the program operator does not have to wait while the complete list is being created. Because both your program and the API are

working on different parts of the same task, operator response time is improved. It’s kind of like a variation of the old adage: “Two heads are better than one.”

As of V4R5, the types of information that may be retrieved via the Open List APIs can be seen in Figure 1. There is no reason to believe that IBM will not continue to expand the list as the various releases of OS/400 are rolled out.

Better in Pairs

Processing Open List APIs is generally a two-step process. First, you open the list (retrieving the first set of records), and then you utilize another API named the Get List Entry API (QGYGTLE) to retrieve the remaining records. When you initially call the Open List API, it will return only the number of records requested into a receiver variable. This initial call will also return what is referred to as a “request handle” that can be used by QGYGTLE to get the next set of records into the variable. QGYGTLE may be called repetitively, using the request handle, to fill the variable whenever it is called. The point is that you call the Open List API only once, and QGYGTLE as many times as needed to get the rest of the records, one block of records at a time.


The Open List APIs return a control data structure that contains information about the list. The control data structure contains information such as how many records were returned, the length of each record returned, as well as a code to indicate if you have finished processing the list. The control information allows you to process the list in the return variable. The source code for the control data structure for the Open List of Spooled Files API (QGYOLSPL) can be found in the Web sidebar. This code was taken from source member QGYOLSPL, source file QRPGLESRC, found in library QSYSINC. The QSYSINC library comes as a nonchargeable feature with every AS/400, but the odds are that you will need to load the feature before you can use it.

Each of the Open List APIs has its own data structure with its own uniquely named fields, but the format is the same. The Web sidebar describes each of the fields in the data structure. The field names can vary from API to API, but we’ve used the field names from the Open List of Spooled Files API for our table.

Spooled Files for Two Users

We’ll now examine a program to see one of the Open List APIs in action. Figure 2 (page
111) illustrates parts of a program that will create a subfile of all spooled files belonging to two different users.

The user ID for each of the Users is passed as parameters to our program. The purpose of the program is to demonstrate the usage of the QGYOLSPL and to show how to process open lists in general. The complete program and its display file are available for download from

One of the first things our program in Figure 2 does is to take the parameters passed into the program and fold them into the format defined by the FilterInfo parameter of the Open List of Spooled Files API. We perform this function in the CrtFiltInf subroutine. The FilterInfo parameter is where we tell the API exactly which spooled files we want to include in the list. We’ll cover this in more detail later.

After the FilterInfo parameter is built, we call the Open List Spooled Files API. The first parameter is where the API returns the data you are requesting. The second parameter is the length of the first parameter. The third parameter is the control data structure format that is common to most Open List APIs. The API returns information about the list that it put in the receiver variable in parameter 1. We would like to call your attention to the filter information, which is found in the sixth parameter of the API. You can filter on user, output queues, form type, user data, status code, or device name. You can mix and match these filters to get rather specific entries in the list, or you can ignore them entirely and get

all spooled files. The Web sidebar includes a detailed table that describes the format of the filter information array.

The flexibility of the filter information creates somewhat of a challenge when formatting the filter parameter. It is basically a series of arrays. A binary number that tells how many entries are in the array precedes each array. Since each array is variable in length, there are no set positions within the parameter. So you have to build the parameter as you go, “bumping” each new array to the end of the previous. None of the arrays can be omitted. If you don’t want to use one of the filter capabilities you must use the special value *ALL for the name and still indicate that there is one entry in the array. If you look at the CrtFiltInf subroutine you will see that we used the %replace built-in function to accomplish this. Since our example is only providing the capability of filtering on specified users, we only had to load values into one array. If you wanted to make this program more robust, this subroutine could get more complicated as you filled the other arrays, but the technique would remain the same.

The format name parameter (parameter 8) is where you specify the format of the data you want returned. This is the same concept that all APIs use. You select a record format name from a list provided by the API and the data will be returned in that format. There are two possible formats you can use: QGYV010000 or QGYV020000. The latter format contains everything that the former does and then some. If you look at the program in Figure 2 and find the QGYV020000 data structure, you will see the layout for this format.

The last parameter is the standard error handling data structure, common to almost all APIs.

After calling the API, the variable receiver will contain the 10 records that we requested. While we are processing the initial 10 records into a subfile, the API is continuing to create the list that we requested. It will store the list in a hidden user space and return a handle that we can use to access the rest of the list via the Get List Entries API.

We set up a loop in our program for processing our spooled files subfile. The first thing done within the loop is to process the records in the return variable into the subfile. We then display the subfile records. If the user presses the Page Down key, we will execute the subroutine GetMoreRecs, which will, appropriately enough, get more records.

The GetMoreRecs subroutine calls the Get List Entry API. This API is used to retrieve another batch of records from the list that we already opened using the Open List of Spooled Files API. We’ve used the same return variable field in both APIs to make it easier to process the information. We’ll now consider the parameters to the Get List Entry API.

The first parameter is the variable receiver to hold the next set of records. The second parameter is the length of the data in the first parameter. The third parameter is the request handle. This field was retrieved from the Open List control data structure (parameter number 3 on the QGYOLSPL API). It tells the API which “hidden” user space contains the list that we want to process. The sixth parameter (StartRcd) is the starting record number that you want to retrieve from the list. We bump this number by the number of records we retrieved the last time. Basically, this is a counter for the number of records you have retrieved (plus one). Now that you know your way around Open List APIs, we’ll introduce the prerequisites.

Tea for Two

It is important to note that because the Open List APIs process asynchronously, they are only available if you have installed the Host Servers option of OS/400. To install the Host Servers option, you can use Option 1 from the LICPGM menu to access the Work with Licensed Programs display. From there, select the Host Servers option to install.

Another thing to be aware of when dealing with Open List APIs is the fact that they reside in library QGY. You will have to take some action to ensure that your application

program can find this library, either by adding it to your library list or hard coding the call (an option we would never recommend).

Asynchronous processing and APIs are becoming basic components in information processing today. Understanding and learning about them will expand your repertoire and increase your value as an information systems professional. Get in-two APIs!

QGYOLJBL Open list of job log messages QGYOLMSG Open list of messages QGYOLOBJ Open list of objects QEZOLBKL Open list of objects to be backed up QGYRPRTL Open list of printers
QGYOLSPL Open list of spooled files QGYCHGSJ Change server job
QGYRTVSJ Retrieve server job information

Figure 1: These Open List APIs are available as of V4R5.

fAPI101DS cf e Workstn sfile(sflrcd:rrn) infds(info)

d Pagedn c const(x’F5’)

d Info ds

d key 369 369

d FmtName S 8

d FormType s 10 inz(‘*ALL’)

d GetNbrRcds s 10i 0 inz(10)

d JobName S 26

d ListInfo s 80

d Rrn s 4 0

d StartRcd s 10i 0 inz(1)

d Users s 12 dim(2)

d UsrSpcData s 10 inz(‘*ALL’)

d Variable s 1920

d VarLength s 10i 0 inz(%len(Variable))

d VarStart s 5 0

d X S 4 0 Inz(1)

d Y S 4 0

* Filter/select information data structure

dFilterInfo DS 1000

d NbrUsrName 1 4b 0 inz(1)

d FilterInf 5 1000

* OutQueue Selection array

dOutQueDs DS

d NbrOutQs 1 4b 0 inz(1)

d OutqFilt 5 24 inz(‘*ALL’)

* Status selection array

dStatusDs DS

d NbrStats 1 4b 0 inz(1)

d StatusFilt 5 16 inz(‘*ALL’)

* Device selection array

dDeviceDs DS

d NbrDevices 1 4b 0 inz(1)

d DeviceFilt 5 16 inz(‘*ALL’)

* Sort information data structure

dSortInfo DS

d NbrKeySort 1 4B 0 Inz(0)

d KeySortStr 5 8B 0 Inz(0)

d SortKeyLen 9 12B 0 inz(0)

d KeyDataTyp 13 14B 0 inz(x’0000’)

d SortOrder 15 15 inz(x’00’)

d Reserved 16 16 inz(x’00’)

* Error Code data structure


d QUSBPRV 1 4B 0 inz(116) Bytes Provided

d QUSBAVL 5 8B 0 inz(0) Bytes Available

d QUSEI 9 15 Exception Id

d QUSERVED 16 16 Reserved

d QUSED01 17 116 Varying length

d*Type Definitions for the Receiver Variable Formats

dQGYV020000 DS

d QGYSFILN04 1 10 Spooled File Name

d QGYJN02 11 20 Job Name

d QGYUN02 21 30 User Name

d QGYJN03 31 36 Job No

d QGYSFILN05 37 40B 0 Spooled File No

d QGYTP00 41 44B 0 Total Pages

d QGYCP05 45 48B 0 Current Page

d QGYCTP00 49 52B 0 Copies To Print

d QGYOQN03 53 62 Out Q Name

d QGYOQLN01 63 72 Out Q Lib Name

d QGYUSD00 73 82 User Spec Data

d QGYTATUS01 83 92 Status

d QGYFT01 93 102 Form Type

d QGYORITY00 103 104 Priority

d QGYIJID00 105 120 Int Job ID

d QGYISFID00 121 136 Int SF ID

d QGYDT06 137 146 Device Type

d QGYERVED36 147 160 Reserved

d QGYDO 161 167 Date Opened

d QGYTO 168 173 Time Opened

d QGYPA 174 174 Printer Assigned

d QGYPN 175 184 Printer Name

d QGYERVED37 185 192 Reserved

d*Type Definition for the List Information Format


d QGYTR03 1 4B 0 Total Records

d QGYRR02 5 8B 0 Records Retd

d QGYRH03 9 12 Request Handle

d QGYRL03 13 16B 0 Record Length

d QGYIC03 17 17 Info Complete

d QGYDT07 18 30 Date Time

d QGYLS02 31 31 List Status

d QGYRSV108 32 32 Reserved1

d QGYIL02 33 36B 0 Info Length

d QGYFR02 37 40B 0 First Record

d QGYRSV207 41 80 Reserved2

c *entry plist

c parm User1 10

c parm User2 10

c movel User1 Users(1)

c if %parms = 2

c add 1 NbrUsrName

c movel User2 Users(2)

c endif

* Create FilterInfo field

c exsr CrtFiltInf

* List spooled files to variable


C Parm Variable

C Parm VarLength

C Parm QgyOLI02

C Parm GetNbrRcds

C Parm SortInfo

C Parm FilterInfo

C Parm JobName

C Parm ‘OSPL0200’ FmtName

C Parm QusEc

c Dou Key PageDn

* Process the variable field into subfile records

c Exsr ProcessVar

c Exfmt SflCtl

* If there were more records than what were returned

c if Key = PageDn

c Exsr GetMorRecs

c Endif

c Enddo

* Close the list


C Parm QgyRH03

C Parm QusEc

c eval *inlr = *on


** Get more records from the open list via QGYGTLE

c GetMorRecs Begsr

c Eval StartRcd = StartRcd + QgyRR02


C Parm Variable

C Parm VarLength

C Parm QgyRH03

C Parm QgyOLI02

C Parm GetNbrRcds

C Parm StartRcd

C Parm QusEc

C Endsr


** Process variable returned from open list API

c ProcessVar Begsr

c Eval VarStart = 1

c Do QgyRR02

c Eval QgyV020000 = %subst(Variable:VarStart:

c QgyRL03)

c move QgySFilN04 spname

c move QgyJN02 jobnam

c move QgyUN02 UserNam

c move QgyOQLN01 OutqLib

c eval Rrn = Rrn + 1

c write Sflrcd

c Eval VarStart = VarStart + QgyRL03

c Enddo

c Endsr


** Create filter info field using parameters passed to program

c CrtFiltInf Begsr

c do NbrUsrName Y

c eval FilterInf = %replace(Users(Y):FilterInf:x)

c eval x = x + 12

c enddo

c eval FilterInf = %replace(OutqueDs:FilterInf:x)

c eval x = x + 24

c eval FilterInf = %replace(FormType:FilterInf:x)

c eval x = x + 10

c eval FilterInf = %replace(UsrSpcData:FilterInf:x)

c eval x = x + 10

c eval FilterInf = %replace(StatusDs:FilterInf:x)

c eval x = x + 16

c eval FilterInf = %replace(DeviceDs:FilterInf:x)

c eval x = x + 16

c Endsr

Figure 2: This RPG program lists spool files for one or two users. (continued)