24
Tue, Dec
1 New Articles

The API Corner: More on Customizing Application Behavior for Each User

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

Find out the rest of the story about the User Application Information APIs.

 

In the last column, we saw how to use the Update User Application Information API to set default values for a new user of the RPG_DEVELOPER_MY_APPLICATION application. Today, we will look at how to combine the Update API with the Retrieve User Application Information API in order to provide application awareness of past user preferences.

 

Specifically, we will see how to recall the previous file, library, member, and full-screen mode that was in use by the application user in the most recent use of the Start My Application (STRMYAPP) command. The command processing program (CPP) SMACPP used by STRMYAPP is provided here:

 

 

h dftactgrp(*no)                                                      

                                                                      

fMyAppFile if   f32766       disk   usropn                          

f                                     extfile(MyFile)                

f                                     extmbr(ApplInfo.Member)        

                                                                      

dSMACPP           pr                 extpgm('SMACPP')                

d QualFileName                 20                                    

d MbrName                       10                                    

                                                                      

dSMACPP           pi                                                  

d QualFileName                 20                                    

d MbrName                       10                                    

                                                                      

dRtvUsrInf       pr                 extproc(                        

d                                     'QsyRetrieveUserApplicationInfo')

d RcvVar                         1   options(*varsize)              

d LenRcvVar                     10i 0 const                          

d RtnRcdFdBk                         likeds(QSYUAIFI)              

d Format                        8   const                          

d UsrPrf                       10   const                          

d ApplID                       200   const options(*varsize)        

d LenApplID                     10i 0 const                          

d QUSEC                               likeds(QUSEC)                  

                                                                    

dUpdUsrInf       pr                 extproc(                      

d                                    'QsyUpdateUserApplicationInfo')

d UsrPrf                       10   const                          

d ApplID                       200   const options(*varsize)        

d LenApplID                     10i 0 const                          

d ApplInfo                   1700   const options(*varsize)        

d LenApplInfo                   10i 0 const                          

d MinVRM                         6   const                          

d QUSEC                               likeds(QUSEC)              

                                                                  

d/copy qsysinc/qrpglesrc,qsyusrin                                

d/copy qsysinc/qrpglesrc,qusec                                    

                                                                  

dApplInfo         ds           100   qualified                  

d File                         10                                

d Library                       10                                

d Member                      10                                

d FullScreen                     1                                

                                                                  

dRcvVar           ds                 likeds(QSYI010004)          

d                                     based(RcvVarPtr)            

                                                                  

dRcvVarApplInfo   ds                 likeds(ApplInfo)            

d                                     based(RcvVarInfoPtr)        

                                                                  

dMyFile           s             21                                    

dRcvVarPtr       s               *                                  

dRcvVarInfoPtr   s              *                                  

dApplID           s           200   inz(                            

d                                     'RPG_DEVELOPER_MY_APPLICATION')

dMinVRM           s             6   inz('V5R3M0')                    

dWait             s             1                                    

                                                                      

iMyAppFile ns                                                        

i                                  1   6 2SrcSeq                    

i                                 7   12 0SrcDat                    

i                                 1332766 SrcDta                    

                                                                    

/free                                                                

                                                                      

QUSBPRV = 0;                                                        

                                                                      

// Determine if data exists for this user                      

RtvUsrInf(QSYI010004 :%size(QSYI010004) :QSYUAIFI :'RUAI0100'  

           :'*CURRENT' :ApplID :%len(%trimr(ApplID)) :QUSEC);    

                                                                  

// New User?                                                    

if QSYBAVL15 = 0;                                              

     ApplInfo.File = 'QRPGLESRC';                                

   ApplInfo.Library = '*LIBL';                                  

     ApplInfo.Member = '*FIRST';                                  

     ApplInfo.FullScreen = 'N';                                  

                                                                  

else;                                                          

     RcvVarPtr = %alloc(QSYBAVL15);                              

                                                                      

     RtvUsrInf(RcvVar :QSYBAVL15 :QSYUAIFI :'RUAI0100'                

               :'*CURRENT' :ApplID :%len(%trimr(ApplID)) :QUSEC);    

     RcvVarInfoPtr = RcvVarPtr + RcvVar.QSYDAI;                      

     ApplInfo = RcvVarApplInfo;                                      

   dealloc RcvVarPtr;                                              

endif;                                                              

                                                                      

// The *USRPRF values are now set, time to check for cmd parameters

select;                                                            

     when QualFileName = '*PRV';           // do nothing            

     when ((%subst(QualFileName :1 :10) = '*PRV') and                

         (%subst(QualFileName :11 :10) <> *blanks));                

           ApplInfo.Library = %subst(QualFileName :11 :10);          

     other;                                                          

           ApplInfo.File = %subst(QualFileName :1 :10);              

           ApplInfo.Library = %subst(QualFileName :11 :10);          

endsl;                                                            

if MbrName <> '*PRV';                                              

     ApplInfo.Member = MbrName;                                      

endif;                                                            

                                                                    

// Now open the file and perform normal functions of MyApplication

MyFile = %trimr(ApplInfo.Library) + '/' + ApplInfo.File;          

                                                                    

monitor;                                                          

open MyAppFile;                                                    

on-error;                                                          

     dsply ('File ' + %trimr(MyFile) + '.' +                        

           %trimr(ApplInfo.Member) + ' not found');                

     *inlr = *on;                                                    

     return;                                                        

endmon;                                                            

                                                                      

read MyAppFile;                                                    

if not %eof(MyAppFile);                                            

     dsply %subst(SrcDta :1 :50);                                    

else;                                                              

     dsply 'Empty file';                                              

endif;                                                              

                                                                      

// If the user changes the 'Full Screen Mode', reflect that change  

//   in ApplInfo.FullScreen so that the most recent setting is saved

//   at exit from MyApplication                                    

                                                                      

// When exiting close the file                                      

close MyAppFile;                                                    

                                                                      

// When exiting under normal conditions update the *USRPRF          

//   application information with the most recent settings.      

// When exiting under an error condition you may or may not want

//   to save these setting -- your call                          

UpdUsrInf('*CURRENT' :ApplID :%len(%trimr(ApplID))              

           :ApplInfo :%size(ApplInfo) :MinVRM :QUSEC);            

                                                                  

*inlr = *on;                                                    

return;                                                          

                                                                  

/end-free                                                        

The sample application opens a source file member, displays the first 50 source data bytes of the first record found in the member, and then ends. If the member is not found, a message similar to "File VINING/QRPGLESRC.NOTHERE not found" is displayed. If the member exists but contains no records, the message "Empty file" is displayed. This is not an overly robust application but does serve the purpose of demonstrating the use of the User Application APIs.

Following the logical flow of the program, rather than the physical sequence of RPG specifications, SMACPP accepts two parameters from the STRMYAPP command. The first parameter, QualFileName, is the qualified file name of the file to be opened. It is defined as a 20-byte character field where the first 10 bytes are the file name and the second 10 bytes are the library name. The second parameter, MbrName, is the 10-byte member name to be opened from QualFileName.

Moving to the calculation specifications, SMACPP first sets Bytes provided of the error code structure, QUSBPRV, to 0 so that any API detected errors are returned as escape messages. SMACPP then calls the Retrieve User Application Information (QsyRetrieveUserApplicationInfo) API. This API is documented here.

The API defines eight parameters.

The first parameter, Receiver_variable, is where the API will return information related to the user profile later identified by the fifth parameter, User_profile, and the application identified by the sixth parameter, Application_information_ID.

The second parameter, Length_of_receiver_variable, is the length in bytes of the provided Receiver_variable (the first parameter).

The third parameter, Return_records_feedback_information, is a fixed-size 12-byte structure returned by the API. It provides information about the entries returned in the first parameter, Receiver_variable. This is the definition of this structure:

Offset

Type

Field

Dec

Hex

0

0

BINARY(4)

Bytes returned

4

4

BINARY(4)

Bytes available

8

8

BINARY(4)

Number of user application information entries

The QSYSINC-provided structure for this parameter, found in QRPGLESRC.QSYUSRIN, is this:

D*****************************************************************

D*Record structure for Return Records Feedback Information      

D*****************************************************************

DQSYUAIFI         DS                                            

D*                                             Qsy RUAI Feedback Info

D QSYBRTN15               1     4B 0                            

D*                                             Bytes Returned    

D QSYBAVL15               5     8B 0                            

D*                                            Bytes Available  

D QSYNBRER04             9     12B 0                            

D*                                            
Number Entries Returned

The first field, Bytes returned (or QSYBRTN15), indicates how many bytes of application-related information were returned in the Receiver_variable. The second field, Bytes available (or QSYBAVL15), indicates how many bytes of application-related information could have been returned in the Receiver_variable. If this field, QSYBAVL15, is set to 0 on return from the API, then no entry was found for the specified user profile and application ID. In other words, the user has not previously used the application, and default values should be used. The third field, Number of user application information entries (or QSYNBRER04), indicates how many complete entries were returned in the Receiver_variable.

The fourth parameter, Format_name, specifies the format that is to be used for returning information in the Receiver_variable. The only format currently supported is RUAI0100, which is defined this way:

Offset

Type

Field

Dec

Hex

0

0

BINARY(4)

Length of entry

4

4

CHAR(200)

Application information ID

204

CC

BINARY(4)

Displacement to user application information

208

D0

BINARY(4)

Length of user application information

212

D4

BINARY(4)

CCSID of user application information

216

D8

CHAR(6)

First valid release

   

CHAR(*)

User application information

This is the QSYSINC-provided structure for this format:

 

D*****************************************************************

D*Record structure for RUAI0100 format                          

D*****************************************************************

DQSYI010004       DS                                            

D*                                            Qsy RUAI0100      

D QSYEL10                 1     4B 0                            

D*                                             Entry Length      

D QSYAIID                 5   204                              

D*                                            Application Info ID

D QSYDAI               205   208B 0                            

D*                                             Displacement Application Inf

D QSYLAI               209   212B 0                            

D*                                             Length Application Info

D QSYIDOAI             213   216B 0                            

D*                                             CCSID of Application Info

D QSYFVR               217   222                              

D*                                             First Valid Release

D*QSYAI00               223   223                              

D*                                                              

D*                                    Varying length            

The first field, Length of entry (or QSYEL10), is the length in bytes for the current entry being processed. You may recall from the previous article that the Update User Application Information API can only support an application information entry of up to 1700 bytes. You can, however, have multiple of these entries, so your application does not need to be constrained to retaining only 1700 bytes of application-related information per user. This field allows you to step through each entry by using the length of the current entry, which is essentially a displacement to the next entry.

The second field, Application information ID (or QSYAIID), is the 200-byte application identifier for the current entry. It is by using a generic application information ID that you can retrieve multiple entries with one call to the Retrieve API.

The third field, Displacement to user application information (or QSYDAI), is the byte offset from the start of the current entry to the application-related data returned for this entry.

The fourth field, Length of user application information (or QSYLAI), is the number of bytes returned for the application-related data associated with this entry.

The fifth field, CCSID of user application information (or QSYIDOAI), reflects the job default CCSID that was in use when the Update User Application Information API was used to store the application-related data that is being returned for this entry.

The sixth field, First valid release (or QSYFVR), is the first release level supported by this application entry.

The seventh field, User application information (or QSYAI00), is a commented field that reflects that a variable amount of application-related data will be returned at a variable location in the Receiver variable. The actual location and length are provided to you by the fields QSYDAI and QSYLAI, respectively.

The next four parameters, User_profile through Error_code, are used in the same manner as they were for the Update User Application Information API introduced in the previous article.

So returning to the program flow of SMACPP, the program calls the Retrieve User Application Information API requesting that only minimal information be returned (the %size(QSYI010004) value for the second parameter leaves no room for actual application-related information entries) using format RUAI0100 for the *CURRENT user of application RPG_DEVELOPER_MY_APPLICATION.

SMACPP then examines the value of QSYBAVL15: the number of bytes that are available to be returned for this format, application, and user. If the value is 0, then this user has no prior application-related data stored for RPG_DEVELOPER_MY_APPLICATION, and SMACPP sets default values for this user in the data structure ApplInfo. If the bytes available value is non-zero, then SMACPP allocates sufficient storage to reflect all application-related data associated with the current user and application, calls the Retrieve User Application Information API a second time in order to access the application-related data using the allocated storage, accesses the application-related data by setting the pointer variable RcvVarInfoPtr to the address of the receiver variable using RcvVarPtr, which address the first byte of the previously allocated storage plus the displacement to the application-related data (RcvVar.QSYDAI), moves the retrieved application data from the RcvVarInfoPtr based structure RcvVarApplInfo to the data structure ApplInfo, and then deallocates the storage previously allocated.

At this point, the subfields of the ApplInfo data structure reflect either the default values or the most recently stored values for the current user. It is now time to examine the parameters passed to SMACPP. If all 20 bytes of QualFileName are set to the blank padded value *PRV, then SMACPP does nothing: ApplInfo reflects the previous (or initial) values. If only the first 10 bytes of QualFileName are set to the blank padded value *PRV, then SMACPP moves the library portion of QualFileName to the library subfield of ApplInfo. Otherwise, SMACPP sets both the file and library subfields of ApplInfo to the corresponding values found in QualFileName. The same type of analysis is then done for the MbrName parameter.

Having now established the library and file to be opened, SMACPP sets the variable MyFile to the appropriate value, starts a Monitor for any errors that might occur when opening the file, and opens the file.

The file MyFile is defined as a program-described input-only file with a maximum record length of 32766 bytes (the largest record length supported for a source file though many compilers support a much smaller record length). The file is also defined as being "user open" with the actual file name to be opened determined at run time by the variable MyFile and the actual member to be opened by the subfield ApplInfo.Member. Both of these fields have been previously set by SMACPP.

If an error is encountered when opening the member, an appropriate error message is displayed and SMACPP ends. Note that in this error case SMACPP does not update the application-related data because an update would, in this application scenario, store the name of a file and member that cannot be opened. This stored value would then cause the user, if using the *PRV support of STRMYAPP, to simply fail again next time. I would much rather retain the last successfully used file and member information. This decision, to update or not, is however one that should be made on an application-by-application basis.

If no error is encountered on the open, the monitor block is ended.

SMACPP then reads the first record from MyAppFile and displays either the first 50 bytes of the source found in the record or, if the member contains no records, the message "Empty file." The main point is that you are now into the application logic of RPG_DEVELOPER_MY_APPLICATION.

When the user exits RPG_DEVELOPER_MY_APPLICATION, SMACPP calls the Update User Application Information API in order to store the current values found in the ApplInfo data structure. Now when the user subsequently returns to the application, SMACPP will be able to access the application-related information associated with the most recent use of RPG_DEVELOPER_MY_APPLICATION. If, during normal application usage, the user for instance toggled full-screen mode from "off" to "on," then, as long as this "on" condition is reflected by the subfield ApplInfo.FullScreen and this field is examined by the application logic, the user will still be in "on" mode when RPG_DEVELOPER_MY_APPLICATION is run again at a later time. This approach can be applied to any user preference that the application wishes to support. In this example program, SMACPP is retaining information related to library, file, member, and full-screen mode. In your applications, I suspect you can think of many other attributes that users might want to have retained across application calls.

This concludes the introduction to the User Application APIs and hopefully gives you some ideas on how existing and future applications for your company might be enhanced with improved usability.

If you have other API questions, send them to me at This email address is being protected from spambots. You need JavaScript enabled to view it.. I'll see what I can do about answering your burning questions in future columns.

 

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: