Guild Companies, Inc.  
 
Midrange Programmer - How-To Advice & Free Code
OS/400 Edition
Volume 1, Number 3 - February 14, 2002

CL-Like Error Handling in RPG

by Kevin Vandever

How many programs in your shop handle file errors? What about general program errors, such as divide by zero, array index, or pointer exceptions? The tools are there to do so. The program and file information data structures provide error information, and the *PSSR subroutine and %STATUS built-in function can be used to trap and handle that information, but that isn't enough. Well, with V5R1, IBM has given RPG the capability to handle errors much the way CL does and, in doing so, has kicked RPG up a few notches!

HelpSystems

The Old Way

It's not impossible to handle errors in RPG. For example, if you open a file for update, when you CHAIN to that file, you can easily interrogate whether that record is locked and act accordingly, as in the following code:



C                   
DoU                   %Status       <>  1218
C     CustomerID    Chain(e)  Customer             
C                   EndDo                          

That's pretty simple stuff. If a record is locked (1218 status code), the program will try again until it is unlocked. If any other file error is encountered, the program will not bomb, thanks to the error extender, e, on the CHAIN, but you will not have control over the error, and so the program will continue to run under false pretenses, so to speak. Of course, you could insert an error-handling subroutine either manually or by defining an information file subroutine in your file spec, as below:

FCustomer  UF A E           K Disk    InFSR(*PSSR) 

Once you've defined the subroutine in the F-spec, you must write the *PSSR subroutine as you would any other subroutine and then let it tell your program what to do with the errors it encounters. Now, any exception caused by an operation to the CUSTOMER file--if that operation includes the error extender, e--will be trapped and subsequently handled in your error routine, if you've written code to handle that error.

Well, that's great for the CUSTOMER file, although there are a lot of IFs or any other file you define with a File Information Subroutine (INFSR) entry in the F-spec, but what about program errors? You can use the %STATUS built-in function to trap those errors, but you have to specifically check the program status using the %STATUS function after every operation you want to handle. No wonder we don't handle these errors very well.

The New Way

Have you ever noticed that most CL programs handle errors significantly better than RPG programs? Isn't that odd, since it is the RPG programs that contain the most critical business rules, data access, and processing logic? CL handles errors better, because, well, it's extremely easy to trap and handle errors in CL. Throw some Monitor Message (MONMSG) statements around your code, and you're done, right? What if I told you that error trapping and handling in RPG has recently become as easy as in CL? I thought so! That's how I reacted, too. With the addition of three new op codes, you can now monitor for any program- or file-related error, in a consistent manner, and handle it accordingly.

I have provided two example RPG programs: one in traditional coding style, CSTMNT, and one in the new free-form style, CSTMNTFREE; these files are also available for download. (For more information on free-form RPG, check out my article "Let Your Hair Down With Free-Formed C-Specs.")

MONITOR, ON-ERROR, and ENDMON

OK, not much to these programs. They accept some data and, depending on that data, update or write the CUSTOMER file. But they do illustrate error handing. Three new operation codes were added to RPG in V5R1 to perform kicked-up error handling: MONITOR, ON-ERROR, and ENDMON. Let's first look at the MONITOR operation.

MONITOR

The MONITOR op code is used to begin error monitoring. Once the MONITOR operation is entered, the program monitors all C-specifications between it and the ENDMON operation. When a program or file exception is encountered on any statement within the monitor block, control is passed to the appropriate ON-ERROR operation, and the logic within that ON-ERROR section is performed. If all the statements within the monitor block complete successfully, control is then passed to the statement following the ENDMON operation.

ON-ERROR

The ON-ERROR operation acts much like the WHEN operation, the difference being that, when an exception is encountered in your RPG program, control is immediately passed to the appropriate ON-ERROR statement; whereas WHEN clauses are interrogated in order until the appropriate one is reached. Each ON-ERROR statement is followed by one or more statements that will execute when that specific ON-ERROR block is triggered. The block is ended when another ON-ERROR or the ENDMON statement is reached. As you can see by my code, I have trapped for very specific errors as well as for more generic, catch-all errors. The first ON-ERROR statement traps a record lock error. I have created a constant called RecordLock in my D-specs and set it to the status code for a record lock, which is 01218. When I encounter a record lock, I simply display a message to the screen using the DSPLY operation. The next ON-ERROR traps for *FILE--that is, any file-related exception not already trapped with another ON-ERROR. File-related status codes range from 1000 to 9999, and they are all trapped with the ON-ERROR *FILE statement. With these two statements, I am covered for any file-related exception that may arise. In my example, I am telling the program to do something specific on a record lock but handle all other file exceptions the same way. Depending on your requirements, you may choose to monitor for other specific file-related exceptions; however, whatever you do, I recommend that you always insert an ON-ERROR *FILE statement for added protection.

The third ON-ERROR statement traps a program exception that occurs when a result field isn't large enough. Again, I have defined a constant called Result2Big to hold the actual status code, 00103. I do this to make my code more readable for the next person who has to get in and marvel at it. Ha! Anyway, anytime this exception is raised within the monitor block, the logic under this ON-ERROR statement will execute. This is where this enhancement really starts to shine. To perform this type of program exception handling prior to V5R1 would have taken a lot more effort.

The next ON-ERROR statement, ON-ERROR *PROGRAM, traps all program exceptions not being trapped by other ON-ERROR operations. Any program exception within the monitor block will be trapped and handled by this ON-ERROR block. Program status codes range from 00000 to 00999. Pretty nifty, eh? The last ON-ERROR statement is the mother of all catch-alls. It is coded either ON-ERROR *ALL or simply ON-ERROR. *ALL, which is the default. As you may imagine, this statement will trap any file or program exception that isn't already being trapped. In my example, this code would never get executed, because I am already performing *FILE and *PROGRAM error handling.

Last, I use the ENDMON operation to end error monitoring. Any C-specifications coded after the ENDMON operation will not be trapped unless you start another monitor block with the MONITOR operation.

Cans and Cannots

For each monitor block, you must have at least one ON-ERROR operation. The ON-ERROR operations must be coded in the same routine as the MONITOR and ENDMON operations. For example, you cannot code a MONITOR and ENDMON in the mainline and place the ON-ERROR statements in a subroutine that is called within the monitor block. I tried this one; it won't work.

Monitor blocks can be placed anywhere within the C-specs. You can embed monitor blocks within IF, DO, SELECTs, and other monitor blocks. And IF, DO, and SELECT can be used with monitor blocks, as my code illustrates. For monitor blocks that are embedded within other monitor blocks, the inner-most block is used first when an exception arises. You can also place ON-ERROR statements anywhere within the monitor block, but, where possible, you are probably better off to keep things modular. My preference is to follow a structure as follows:

MONITOR
Program logic 
ON-ERROR block
ENDMON

Level indicators can be used with the MONITOR operation to indicate that the MONITOR operation is associated with a specific total level. You can also use level indicators on the ON-ERROR and ENDMON operations, but they have no effect and would only be used for documentation purposes.

Conditioning indicators can also be used with the MONITOR operation. If the conditioning indicator is *OFF, control is passed to the first statement after the ENDMON. This technique might be useful for debugging. You cannot use conditioning indicators with ON-ERROR or ENDMON.

You cannot branch out of a monitor block; however, branching is allowed in the ON-ERROR block.

Let the Monitoring Begin

So what do you think? It's about time, right? I think so, too. I can already see it: support calls down, fewer 3:00 a.m. pages, productivity at an all-time high. The sky's the limit, but you first have to implement it. Download my code and add a call to a bogus program or generate a divide-by-zero error and see how monitoring works. Once you're comfortable with the technique, you'll be on your way toward bulletproofing your RPG applications.

Kevin Vandever is a lead IT engineer at Boise Cascade Office Products in Itasca, Illinois, and is co-editor of Midrange Programmer, OS/400 Edition. He can be reached at kvandever@itjungle.com.

Sponsored By
HELP/SYSTEMS

GET NOTIFICATION OF SYSTEM EVENTS ON YOUR FAVORITE MOBILE DEVICE!

Robot/ALERT 5.0, the popular iSeries (AS/400) software, now works with palm devices, pagers, and cell phones.

Receive e-mail messages and attachments using TCP/IP.

Send messages to broadcast lists that include both e-mail and paging recipients.

Learn more: http://www.helpsystems.com/ad_in.cgi?ad_id=62

THIS ISSUE
SPONSORED BY:
Help/Systems
SoftLanding Systems
BCD Int'l
Jacada Ltd.
Profound Logic Software
WorksRight Software
BACK ISSUES
TABLE OF CONTENTS
CL-Like Error Handling in RPG
Installing and Configuring Tomcat on iSeries
Learning Basic HTML Tags
Java Concepts for iSeries Programmers
Build Dynamic Web Apps With iSeries Tomcat
Five More Cool Things You Can Do With OpsNav
  Newsletters | Subscribe | Advertise | About Us | Contact | Search | Home  
  Last Updated: 2/13/02
Copyright © 1996-2008 Guild Companies, Inc. All Rights Reserved.