You are currently on IBM Systems Media’s archival website. Click here to view our new website.

IBM i > DEVELOPER > RPG

List Handling With Open Access


As we mentioned in our recent blog post, “Open Access—Oh the Thinks You Can Think!” , we’ve been thinking about different ways we can use RPG Open Access (OA). One approach suggested by IBM’s Dan Cruikshank was in the area of processing lists of data returned by APIs. That thought inspired this month’s column.

Despite the list API inspiration, we decided not to build the example around that but rather provide a more generic list-handling example. There are several reasons for this, one being that we didn’t want you to ignore this example simply because you had no interest in the API that we chose to use. Lists can come from many sources, including calls to Web services. In our example, we have a simple array. The data in an element of the array plus the element position in the array make up the record content for each access (i.e., READ or CHAIN). The array data itself also serves as the key of the “file.”

By using an example based on a simple array, we can focus our attention on what we need to do to in the handler to enable it to respond appropriately to the RPG op-codes we typically use in processing lists—namely CHAIN, READ and SETLL. For some lists, you might also need to implement READE or even other flavors of SETxx and READxx, but hopefully should you need such functionality, the examples provided here will make it clear what you need to do.

If this is your first introduction to OA, you should read one or two of our earlier articles first as this piece is going to assume that you’re familiar with the basics. A good starting point would be “RPG Open Access Revisited” and “Implementing Open Access With RPG.” The first of these discusses the basic theory behind OA; the second introduces a buffer handler that utilizes a Web service. Since the handler used in this article also uses the buffer approach, that one would be a good introduction for you.

Time to Get Started

First, let’s look at the test programs we used to exercise the handler. The first uses CHAIN, displays the result and then issues a single READ to show the following “record.” The second uses SETLL to position to a key and then READs to the end of the file displaying all the “records” it finds.

Both programs use the file ArrayFile, which simply consists of a five-digit sequence number followed by a four-character key. The DDS for the file is shown here. Hopefully at this point in your OA education, it’s clear to you that no data will ever be placed in this file. It simply forms the contract between the user program and the handler for the format of data, and the key information that they will use.

     A          R ARRAYREC
     A            SEQNO          5P 0
     A            DATA           4A
     A          K DATA
 

Looking now at the first test program, the F-spec at (A) defines a perfectly normal DISK file with, of course, the minor exception that it associates the file with the handler program. At (B) we CHAIN to the file and then at (C) check the result, displaying an appropriate message. This is followed at (D) by a simple READ to retrieve the next record and report its status.

       // This program demonstrates the CHAIN and READ capabilities of                              
       //   the OA list handler                                                                     
(A)  FArrayFile IF   E           K DISK    Handler('LISTHANDLR')                                    
                                                                                                    
     D key             s                   Like(Data)                                                                                                   
     D exit            c                   'exit'                                                   
                                                                                                    
      /Free                                                                                         
                                                                                                    
       DoU key = exit;                                                                              
                                                                                                    
         Dsply ('Enter record key: ("exit" to end)') ' ' key;                                       
                                                                                                    
         If key = exit;                                                                             
           Leave;                                                                                   
         EndIf;                                                                                     
                                                                                                    
(B)      Chain key ArrayFile; // Chain using key entered                                            
                                                                                                    
         // Report success/failure                                                                   
(C)      If %Found(ArrayFile);                                                                      
           Dsply ('Key ' + key + ' found at sequence ' + %Char(seqno));                             
         Else;                                                                                      
           Dsply ('Unable to locate ' + key);                                                       
         EndIf;                                                                                     
                                                                                                    
         // Read and display the next record regardless of the CHAIN's success                       
(D)      Read ArrayFile;                                                                            
                                                                                                    
         If %Eof(ArrayFile);                                                                        
           Dsply ('EOF reached');                                                                   
         Else;                                                                                      
           Dsply ('Key ' + data + ' found at position ' + %Char(seqno));                            
         EndIf;                                                                                     
                                                                                                    
       EndDo;                                                                                       
                                                                                                    
       *InLr = *On;

What we’d like you to notice about this program is how normal it is. Other than the HANDLER keyword, there’s nary a hint that we’re doing anything other than reading a simple DISK file—and that’s just as it should be. We won’t waste space describing the second test program but take it from us that it too is a perfectly normal SETLL/READ program just like hundreds you’ve probably written in the past. If you want to study the source, you’ll find both test programs and the handler on our website.

Designing the Handler

For this particular handler, we used our standard OA Handler template as the base. It’s amazing how much quicker it is to write new handlers now that we have the base code in place.

As we stated earlier, we decided that we’d only handle the basic CHAIN, READ and SETLL operations in this initial version. We should also note that the *START and *END variants of SETLL are not supported. Later, as we develop more of these list handlers, we will undoubtedly add support for additional op-codes and the SETLL variants. One other feature that would be simple to add is a feedback to RPG of the current RRN.

As far as possible, we attempted to mimic all of the expected behaviors of the op-codes we were using. For example, a READ following a successful SETLL will always return the actual key requested on the SETLL if one was found or the next higher key if an exact match was not found. There are probably behaviors under specific conditions that we’ve not mirrored. If you discover any omissions, please let us know.

Before we look at the handler logic for each of the supported operation codes, let’s take a quick look at the data that is going to represent our list. Here are the definitions we used:

       // This is the list that this demo handler will process - it could be
       //   anything and it could be anywhere. For example a web service
       //   might return a list of orders for a customer. It could be a list
       //   of spool files from a spool API. etc. etc.
(E)  D listKeys        DS
     D   keyData                     60a   Inz('A001+
     D                                          B002+
     D                                          B099+
     D                                          B199+
     D                                          C200+
     D                                          C399+
     D                                          D001+
     D                                          E002+
     D                                          F099+
     D                                          G199+
     D                                          J200+
     D                                          J399+
     D                                          P001+
     D                                          R399+
     D                                          T001')
     D   keyArray                     4a   Dim(15) Overlay(keyData) Ascend

As you can see, there are 15 elements currently in the array. If the array were larger, but not completely filled, then in subsequent logic we’d simply use the active number of elements together with %SubArr and %Lookupxx to restrict sorts and searches to the active portion. We decided not to complicate this example by adding that logic.

As is typical of all our OA handlers, the main logic of the handler program simply finds out what operation (i.e., Open, Chain, Read, etc.) was requested and calls the appropriate procedure to implement that operation.

       Select;

         When (info.rpgOperation = QrnOperation_SETLL);
           doSETLL();

         When (info.rpgOperation = QrnOperation_CHAIN);
           doCHAIN();

         When (info.rpgOperation = QrnOperation_READ);
           doREAD();

         When (info.rpgOperation = QrnOperation_OPEN);
           OpenFile();

         When (info.rpgOperation = QrnOperation_CLOSE);
           CloseFile();

         Other; // We don't know how to do this operation
           Dsply ('Unsupported function ' + %Char(info.rpgOperation)
                 + ' on queue ' + info.externalFile.name );
           info.rpgStatus = errIO;

         EndSl;                                  

Jon Paris is a technical editor with IBM Systems Magazine and co-owner of Partner400.

Susan Gantner is a technical editor with IBM Systems Magazine and co-owner of Partner400.



Advertisement

Advertisement

2019 Solutions Edition

A Comprehensive Online Buyer's Guide to Solutions, Services and Education.

New and Improved XML-INTO

Namespace support makes the opcode a viable option

Authenticating on the Web

The finer points of OpenRPGUI, Part 1

The Microphone is Open

Add your voice: Should IBM i include open-source RPG tools?

IBM Systems Magazine Subscribe Box Read Now Link Subscribe Now Link iPad App Google Play Store
IBMi News Sign Up Today! Past News Letters