Displaying field-dependent errors in the message line

From Try-AS/400
Revision as of 14:33, 18 March 2019 by PoC (talk | contribs) (Addition: Display File, SFL stuff still to do.)
Jump to navigation Jump to search

It is always considered good habit to let a program's users know what's going on. Or what failed, and why. OS/400 provides components to relatively easily display field-dependent errors in the message line (at the bottom of the screens). Surely you already have seen such messages by other OS/400 components.

Probably you didn't notice that this message line is often a subfile. With one line, though, but you can place the cursor there and scroll through it's content with the appropriate Page-Up and Page-Down-Keys. If you ever wondered how to see other messages from one program invocation without bringing up the job log, now you know.

There are multiple ways to provide this functionality. I'm showing the way I considered the best for me. That's my choice and doesn't have to match yours. At least it should provide a starting point for your own experimentation.

We use the following ingredients:

  • Message Files,
  • Display Files (certain statements within, that is),
  • ILE RPG Code.

For the following examples, we assume an already existing application which should not show the standard error screen when an already locked record is encountered. Instead, it should show a message in the message line and skip the record. Your current library is assumed to be the library of that mentioned application.

Message Files

Message Files are special database files. Before elaborating, let's create a message file:

CRTMSGF MSGF(GENERICMSG) CCSID(*JOB)

Now, we populate this file with a message:

ADDMSGD MSGID(ERR1218) MSGF(*CURLIB/GENERICMSG) MSG('Record &1 is already in use.') SECLVL('Record &1 has been locked by another user for update. Wait until the lock will be released or use WRKOBJLCK OBJ(*CURLIB/MYPF) OBJTYPE(*FILE)  MBR(*FIRST) to find out who is locking. So you can contact the user in question to close that record.') SEV(10) FMT((*CHAR 10 0)) TYPE(*NONE) LEN(*NONE)

Noteworthy stuff:

  • The &1 in the message text is a variable which we'll use later to customize this message a bit before showing it to the user.
  • The MSG is to be shown in the message line. It should give a concise description of what's going on. The SECLVL text will be shown when the user positions the cursor in the message line and presses the HELP- or F1-Key. It should provide information what to do next to probably solve the issue.

There's a system wide message file QSYS/QCPFMSG, with proper localized texts. Problem with this file is that it contains hundreds of standard messages, so it is cumbersome to find the right one.

To change and view content of a message file, you can use:

WRKMSGD MSGF(GENERICMSG)
Conclusion
Message files enable the to have a proper place for probably longer text, because handling string literals in RPG is really cumbersome. Plus, with a message file, your application can be more easily localized for other languages without wading through all the RPG program code.

Display Files

Display Files define the screen appearance to the user and provide an interface in program code to get data in and out of this screen. The message line is usually part of that screen, and thus of a message file.

We could handle the entire message subfile ourselves. But we also could let OS/400 do that for us. This is accomplished by adding the ERRSFL Keyword in the global (top) section of any DSPF DDS file. I strongly recommend to include this statement per default.

The next steps are dependent on your Record Format types. That is, we need to differ between ordinary Record Formats with just one page, and Subfile Record Format, which always come in twos: The SFL record to describe one block[1] of data, and the SFLCTL which actually controls the behavior of the SFL itself. See List views: Subfiles for details.

For clarity, ordinary record formats will be called Details Record Formats[2] and Subfile Record Formats will be called Subfiles, unless we're referencing the SFL or SFLCTL itself.

To understand the next sections it is important that you understand that the shown DDS keywords always tie messages to a certain field.

Automatic Error Handling


A somewhat automatic error handling can be established with the CHKMSGID keyword to a field. It must be used together with some predefined check provided by DDS statements, such as a VALUES option for a field which lists valid data to be entered into the field.

Often, this is used in a SFL for the OPT-Field, where the user enters (usually) decimal numbers to tell the system what to do with the chosen record. With this facility you can offer the user a better understandable error message then the standard text from OS/400. Example:

     A            OPT            1A  I  9  3VALUES(' ' '2' '4' '5' '+' '-')
     A                                      CHKMSGID(SFL0001 GENERICMSG)

Again, noteworthy stuff:

  • SFL0001 is an example ID. There's no definition for it in the above example message file!
  • If the VALUES-Check of the corresponding field fails, the corresponding field will be automatically set to DSPATR(RI) (Reverse Image) to show the user where the error occurred.[3]

CHKMSGID is not limited to subfiles, and not limited to provide error messages for a range of valid entries!

Programmatic Error Handling


In contrast to the above, the next section applies when your program has to cope with other error conditions, for which OS/400 doesn't provide a proper handling procedure.

Details Record Format

This is a relatively easy one. See the following example minimal DDS Excerpt:

    A                                      ERRSFL
    A            TYP       R        B  8 12
    A  91                                  ERRMSGID(ERR1218 GENERICMSG 91 &ERRSTR)
    A            ERRSTR        16A  P

Again, noteworthy stuff:

  • TYP is an ordinary field, referenced from a file not shown or otherwise referenced here for minimality.
  • The ERRMSG(ID) statement is conditioned with *IN91. When this indicator is set to true and the Record Format is written to, then
    • The referenced message is pulled from the message file and displayed in the message line.
    • The field will be automatically set to DSPATR(RI) (Reverse Image) to show the user where the error occurred.
    • The given *IN91 (third parameter) will be reset after the Record Format is read, to automatically clear the error condition when the user submits the screen for processing.
  • ERRSTR is a (P)rogram defined field. This equals to a global variable in ILE RPG though the usual file reference. You may write a program provided string into this variable which is then shown at the corresponding position (&1) in the message file text. (See above.)

Subfile Record Format

SFLMSG(ID) SFLNXTCHG

Again, noteworthy stuff:

  • *IN92 is set on.

Footnotes

  1. I deliberately don't state one line, since one record in a subfile display may actually span multiple lines in a display file. This is not limited to an implicit wrap around at the right end of the screen.
  2. Since they usually contain more fields to display than a subfile.
  3. Now you probably understand why the ERRMSG(ID) is always tied to a field.

Weblinks