By submitting my Email address I confirm that I have read and accepted the Terms of Use and Declaration of Consent.

By submitting your personal information, you agree that TechTarget and its partners may contact you regarding relevant content, products and special offers.

You also agree that your personal information may be transferred and processed in the United States, and that you have read and agree to the Terms of Use and the Privacy Policy.

for the help desk, the programmer who has to fix it and especially the user.

Did you ever hear this telephone conversation?

"Help Desk, how can I help you?"

"There is this strange message on the screen."

"Can you tell me what you were doing?"

"Accounts."

"Can you be more specific?"

"One of our customers had a problem with a credit note we had issued. He thought that the Tax would . . ."

"No. I meant what screen were you on when you got the message?"

"The one in the corner, overlooking the car park."

Or worse still, the user never calls the help desk. They press enter (which takes the default response of Cancel) and return to the menu. So everything is OK, there is no need to tell anyone. A CPF message such as Attempt to divide by zero (C G D F) is meaningless to a user and frightens the life out of most; it might as well say "Missile Launched."

More on this topic

It is impossible to test programs to ensure that they will never fail with a CPF message; there are too many outside influences that affect a program. What you want is a means of handling these errors in a more meaningful way. You want something along the lines of these:

The user gets a "friendly screen" that tells them there is a problem -- and it does not allow them to return to a menu

The Help Desk is notified that there is a problem

The program generates a Dump listing

A Job Log is printed

All of that can be achieved by writing a CL program, a standard subroutine and a few minor code changes.

Basically, if a program fails, you want to trap the error and handle the program failure in a meaningful way. If you are familiar with CL programming, you will be familiar with the MONMSG command; exception/error handling is the RPG equivalent, and it is so easy to implement that it always amazes me why every program doesn't do it.

What is an exception/error?

Your program makes a request (an RPG Operation) to the operating system. The request fails, and the operating system responds by sending an escape message to the program message queue. When the escape message arrives a check is made to see if the program is going to handle the error (MONMSG in CL) and if not, system error handling kicks in.

In RPG, there are Program Exception/Errors (divide by zero, array index error, etc.) and File Exception Errors (any file error). As with MONMSG in CL, you can trap errors at the program level or the command level.

Trapping at the program level

If a program encounters a program error, it checks to see if there is a *PSSR subroutine coded in the program. If there is, it executes the subroutine. If there isn't, the program "fails" with an error message. Below is an example of a *PSSR subroutine. The PSSRDone indicator and the prototype for FatalProgram would usually be included in a copy member along with other prototypes and standard fields.

The *PSSR routine shown above performs a DUMP operation and calls FatalProgram(). FATALPGM should reside in a library that is in the system portion of the library list and, therefore, in everybody's library list.

Some points to note.

The (A) extender means that a DEBUG keyword is not required on the H Spec.

The logic with the PSSRDone indicator is in case anything fails in the *PSSR subroutine --- which would cause the *PSSR subroutine to be executed, which would fail --- which would cause the *PSSR subroutine to be executed, which would fail . . . until the number of dump listings causes something to blow.

The EndSR for a *PSSR subroutine can contain a return-point instruction.

A *PSSR subroutines may be executed like any other subroutine (using ExSR or CASxx).

The following return-point operands can be specified on the EndSR operation for a *PSSR subroutine, but most of them apply only if you are using the RPG cycle.

*DETL. Continue at the beginning of detail output lines

*GETIN. Input Record Routine

*TOTC. Total Time Calculations

*TOTL. Continue at the beginning of total output lines

*OFL. Continue at the beginning of overflow lines

*DETC. Continue at the beginning of detail calculations.

*CANCL. Cancel the Execution of the program

Blank. Return control to the RPG default error handler. If the subroutine was called by the EXSR operation and factor 2 is blank, control returns to the next sequential instruction.

When *PSSR is invoked by an error, it does not return to the statement in error. It should be used as an exit from the program.

The fatal program

The code below shows a simple example of a fatal error handler. The program prints a job log, sends a message to the system operator and, if running interactively, displays a meaningful/helpful screen for the user. (The user has to press enter 1,000 times to get out of the screen!). You decide what you want to put on the screen format FATALERROR in the display file FATALDSP -- just keep it friendly and non-threatening. Don't take this as the finished article. It is only intended to demonstrate the type of thing you can do. What you do is totally up to you. Make it as complex or as easy as it needs to be.

The benefit of the above example is that all the user sees is the "friendly" screen while the help desk is automatically notified of the problem and the programmer has a job log and a dump listing to work from. That means in about 90% of the incidents, neither the help desk nor the programmer needs to talk to the user until the problem has been solved.

Can it get any easier?

Believe it or not, it can be easier. Since a *PSSR routine will be the same in every program, why not code it in its own member and include it in any program using a /COPY directive.

The coding overhead of program exception/error handling is now one line of code in a program.

What about the files?

Just as the program has an error handling subroutine in *PSSR, each file that you define on an F spec can also have its own error handling subroutine, identified by the INFSR keyword. Each file can have its own subroutine or a subroutine can be shared between different files.

These subroutines act in exactly the same way as *PSSR, so why not use the *PSSR subroutine? Below is an example of INFSR being defined on the F specs.

FDisplay CF E WorkStn InfSR(*PSSR)
FCustomer UF E K Disk InfSR(*PSSR)

Now, if there is an I/O error with a file, the *PSSR subroutine will be executed.

Well, not quite. The INFSR subroutine will trap all I/O errors except file open errors. The RPG cycle is automatically opening the files before the code is loaded, therefore it cannot execute *PSSR if there is a problem during file open (e.g., level check).

To trap file open errors, you need to perform an implicit open of the file by specifying conditional open for the file (USROPN keyword on F Spec) and use the OPEN operation to open the file (usually coded in the *INZSR subroutine).

Conclusion

All you have to do is this:

Write a standard *PSSR subroutine and place it in a copy member.

Write a "Fatal Error" program that is called from the *PSSR subroutine.

Include the *PSSR subroutine in programs using a /COPY directive.

Include an INFSR(*PSSR) keyword for every file.

Implicitly open the files by specifying the USROPN keyword for every file on the F spec the using the OPEN operation to open the files.

Just think of all the frustration and irritation that can be saved by making these few changes.

What about the equivalent of command level MONMSG, where you can trap individual errors and handle them without terminating the program? Maybe next month!

---------------------------About the author: Paul Tuohy is CEO of ComCon, an iSeries consulting company. He is the author of Re-Engineering RPG Legacy Applications and is one of the quoted industry experts in the IBM Redbook "Who Knew You Could Do That With RPG IV?"

0 comments

Register

Login

Forgot your password?

Your password has been sent to:

By submitting you agree to receive email from TechTarget and its partners. If you reside outside of the United States, you consent to having your personal data transferred to and processed in the United States. Privacy