# Compaq ACMS for OpenVMS
Writing Server Procedures

Previous | Contents | Index

The following example illustrates how to handle RMS errors using BASIC. Note that the EXIT HANDLER statement is used to resignal the error and exit the error handler in BASIC.

        FUNCTION LONG pers_change_employee_proc( employee_record emp_wksp )

        %INCLUDE "pers_files:pers_common_defns"
        %INCLUDE %FROM %CDD "pers_cdd.employee_record"

        DECLARE LONG sts

        MAP ( emp_map ) employee_record emp_rec

        WHEN ERROR IN
            GET # emp_file,                                         &
                KEY # 0 EQ emp_wksp::emp_badge_number,              &
                ALLOW NONE,                                         &
                WAIT 20
            IF emp_rec::emp_last_update = emp_wksp::emp_last_update &
            THEN
                MOVE TO # emp_file, emp_wksp
                sts = SYS$GETTIM( emp_rec::emp_last_update BY REF )
                IF ( sts AND 1% ) = 0%                              &
                THEN
                    CALL LIB$STOP( sts )
                END IF
                UPDATE # emp_file
                pers_change_employee_proc = persmsg_success

            ELSE
                pers_change_employee_proc = persmsg_empchanged
            END IF
            UNLOCK # emp_file

        USE
            SELECT ERR
                CASE    basicerr_record_not_found
                    pers_change_employee_proc = persmsg_empdeleted
                CASE    basicerr_record_locked,                             &
                        basicerr_deadlock,                                  &
                        basicerr_wait_exhausted
                    CALL ACMS$RAISE_TRANS_EXCEPTION( ACMS$_TRANSTIMEDOUT )

                CASE    ELSE
                    IF ( RMSSTATUS( emp_file ) = RMS$_NRU ) OR              &
                       ( RMSSTATUS( emp_file ) = RMS$_DDTM_ERR )            &
                    THEN
                        CALL ACMS$RAISE_TRANS_EXCEPTION( RMSSTATUS( emp_file ) )
                    ELSE
                        CALL ACMS$RAISE_NONREC_EXCEPTION( RMSSTATUS( emp_file ) )
                        EXIT HANDLER
                    END IF
            END SELECT
        END WHEN

        END FUNCTION

# Chapter 5
Using Message Files with ACMS Tasks and Procedures

At times, tasks and procedures need to return messages to users telling them, for example, that information they requested is locked by another user, that information they typed is not valid for the file the task is using, or that other errors have occurred. You can simplify returning messages to users by setting up a message file that contains the text of messages you want to display. If you set up a message file, you can change the text of messages without having to recompile and relink the procedures and definitions in the application.

This chapter discusses the following topics:

- Creating a source file of messages, including setting up message file characteristics and writing messages
- Using the MESSAGE command to create two output files from your input message file
- Displaying user-defined messages by returning message names from procedures and using the GET MESSAGE clause to retrieve messages from the message file and display messages to users

For more information on creating message files than is in this chapter, see OpenVMS Command Definition, Librarian, and Message Utilities Manual.

# 5.1 Creating Source Files of Messages

A message source file has two main parts:

- Statements that apply to the entire message source file; they define characteristics of the message file. These statements are in the first two lines of the following example.
- Error messages, grouped by the facility to which they apply. These are in the remaining lines of the following example.

    .TITLE VRMSG Messages for AVERTZ
    .IDENT /Version 1.0/

    .FACILITY VR,1 / PREFIX=VR_

    .SEVERITY INFORMATION

    MULCURECFND <Multiple customer records found>
    MULRSRECFND <Multiple reservation records found>

    .END

The following sections explain how to write each part of a message source file. Example 5-1 contains a complete message source file.

## 5.1.1 Setting Up Message File Characteristics

Three kinds of information can appear in the first part of a message source file, which contains statements that apply to the entire message file:

- Module name
- Listing title
- Comments

The .TITLE statement defines the object module name, which is assigned to the object module when you compile the source file using the Message Utility. The object module does not need to have the same name as the source file or the file containing the object module, but it is common practice to do so. The maximum length of the module name is 31 characters.

In the .TITLE statement, include a module name and a listing title. For example:

    .TITLE VRMSG Messages for AVERTZ

After the module name (here, VRMSG) is a listing title. If you use the /LIST qualifier when compiling the source file, the listing title (in this case, Messages for AVERTZ), appears at the top of each page of the .LIS file. The maximum length of a listing title is 28 characters.

Optionally, you can use an .IDENT statement after a .TITLE statement to include additional information (beyond that supplied by the .TITLE statement) in the object module and the listing file. For example, you can use .IDENT to identify the version of the file:

    .IDENT /Version 1.0/

The Message Utility includes the literal string from the .IDENT statement in the object module name.

To include comment text in your source file, use an exclamation mark (!). For example:

    ! History:
    !           V1.0    Created 12-May-91.

Comment text helps others understand the message file and documents the history of the file.

## 5.1.2 Writing Messages

The main part of a message source file includes the following:

- A .FACILITY statement
- .SEVERITY statements
- A list of message names and their accompanying text

The following sections explain how to write these.

### 5.1.2.1 .FACILITY Statement

You must have at least one .FACILITY statement and one .END statement in a message file.

The following example illustrates how to use the .FACILITY statement:

    .FACILITY VR,1
      .
      .
      .
    .END

Always include both a 1- to 9-character facility name and a facility number in each .FACILITY statement. In the example, VR is the facility name. Separate the facility name and the facility number with either a comma, one or more spaces, or tabs. The name used in a .FACILITY statement does not need to be unique in the message file.

The number in the .FACILITY statement must be a decimal value in the range of 1 to 2047. The facility number used must be unique for the facility name. In the example, 1 is the facility number. For a list of the qualifiers that you can use with the .FACILITY statement, see OpenVMS Command Definition, Librarian, and Message Utilities Manual.

The .END statement has no parameters or qualifiers. Always end the file with an .END statement.

### 5.1.2.2 .SEVERITY Statements

In each block of messages, group messages by their OpenVMS severity levels. The five severity level keywords are:

- SUCCESS
- INFORMATION
- WARNING
- ERROR
- FATAL (or SEVERE)

Use these keywords to mark the beginning of a subgroup of messages in the .SEVERITY statement. For example:

    .FACILITY VR,1
    .SEVERITY INFORMATION
      .
      .
      .
    .END

In message files for ACMS tasks, application developers can write the text of severity messages. In the AVERTZ sample application, most messages are either INFORMATION level or WARNING level messages. The messages for recoverable errors, for example, indicate that an error prevented the procedure from completing but that the user can recover from the error.

Chapter 3 and OpenVMS RTL Library (LIB$) Manual contain more information about severity levels.

### 5.1.2.3 Message Names and Text

Messages contain the following:

- Message name
  A message name is part of a message symbol, which ACMS uses to retrieve messages from a message file. (An explanation of message symbols follows.)
- Message text
  Message text is the 1- to 255-byte text displayed on the screen for the terminal user. Enclose message text in angle brackets (< >) or in quotation marks (" "). For example:

      .FACILITY VR,1

      .SEVERITY INFORMATION

      MULCURECFND <Multiple customer records found>
      MULRSRECFND <Multiple reservation records found>

      .END

  Note Never include $FAO directives in message text accessed by the GET MESSAGE clause. However, message text accessed directly by step procedures can include $FAO directives. See Chapter 3 for details.

In the previous example, each message text follows a message name (MULCURECFND, for example). ACMS uses message symbols (rather than message names) to retrieve message text from the message file. The linker also uses message symbols to resolve the message symbols in step procedures.

When you compile a message source file, the Message Utility creates a symbol for each message by putting the facility code and an underscore (_) in front of each message name.

Follow these guidelines when creating and using message symbols:

- You can define a shorter facility prefix in a message symbol by using a /PREFIX qualifier with the .FACILITY statement. For example:

      .FACILITY VEHICLE,1 / PREFIX=VR_

  If you define a prefix, the Message Utility then uses the prefix instead of the facility name when it creates the message symbol. For example:

      VR_MULCURECFND
      VR_MULRSRECFND

- Message symbols must be unique in each message file and in all files used by an ACMS task group. If an ACMS application uses more than one task group, each message symbol must be unique in all files used by all task groups in that application.
- If you use message files, make sure that the symbols created by the Message Utility when you compile the message source file are the same as the message symbols you define in your procedures. For example:

      01  MULCURECFND              PIC S9(11) COMP
                                   VALUE IS EXTERNAL VR_MULCURECFND.

Example 5-1 shows a complete message source file.

Example 5-1 Source File of Messages

    .TITLE VRMSG Messages for AVERTZ
    .IDENT /Version 1.0/
    .FACILITY VR,1 /PREFIX=VR_

    .SEVERITY INFORMATION
    MULCURECFND <Multiple customer records found>
    MULRSRECFND <Multiple reservation records found>
    VEUPGPRF    <Vehicle upgrade performed - no charge>
    VEDNGPRF    <Vehicle downgrade performed - rates adjusted>
    CURECUPD    <Customer record has been updated in database-hit RETURN to continue>
    CURECINS    <Customer record has been inserted in database>
    CHKINCOMP   <Vehicle Checking-in completed successfully - hit RETURN to continue>
    CHKOUTCOM   <Vehicle Checkout completed successfully - hit RETURN to continue>
    RESVCOMP    <Vehicle reservation completed successfully - hit RETURN to continue>
    VERECFND    <Vehicle(s) found in class requested, choose one>
    RESSUCCNCLD <Reservation successfully canceled - hit RETURN to continue>

    .SEVERITY WARNING
    CURECNOTFND  <Customer record not found>
    RCRECNOTFND  <Rental class record not found>
    RERECNOTFND  <Invalid state/country-reenter valid state/country names>
    RSRECNOTFND  <Reservation record not found >
    SIRECNOTFND  <Site record not found, press PF1 S for a list of sites>
    VERECNOTFND  <No vehicles available for checkout - hit RETURN to continue>
    VRHRECNOTFND <Vehicle rental history record not found>
    NOTCHKOUT    <Vehicle not checked out>
    RESCNCLD     <Reservation was canceled - reenter data or PF1 Q to quit>
    CARCHKIN     <Reservation archived,car checked in,paid in full>
    CARCHKOUT    <Vehicle has already been checked out - reenter data or PF1 Q to quit>
    RESCLOSED    <Reservation archived,car checked in,payment pending>
    DLRENOTFND   <Invalid Driver's license state/country>
    NOCANCEL     <Reservation cannot be canceled at this stage>
    INACTIVE     <Please enter data or task will be canceled due to inactivity>
    DDTM_TIMEOUT <The distributed transaction timed out --- please retry>

    .SEVERITY ERROR
    NO_DUP           <Duplicate database key>
    DEADLOCK         <Database deadlock>
    INTEG_FAIL       <Database integrity failure>
    LOCK_CONFLICT    <Database lock conflict>
    CAR_UNAVAILABLE  <Vehicle unavailable - hit RETURN to continue>
    CHK_CANCL_ERR    <Error in checkout or cancel reservation>
    HIST_WRITE_ERR   <Error in writing to history file>
    UPDATE_ERROR     <Error updating file>

    .SEVERITY FATAL
    BILLERR          <Bill computation error - canceling transaction>
    DB_FATAL         <Fatal database error - check audit log>
    ICRECNOTFND      <ID increment control record not found>

    .END

Example 5-1 lists the messages available to tasks in the AVERTZ Vehicle Rental task group. For example, the example lists both CURECNOTFND and RCRECNOTFND under a .SEVERITY WARNING statement. When you compile the file, the Message Utility sets the low three bits of the longwords representing the message symbols to the binary value corresponding to WARNING level (000).

Regardless of what the error level was when the procedure trapped the error, if you return CURECNOTFND or RCRECNOTFND as status values of your procedure, the error level of the return status is WARNING. For information on returning status values, see Chapter 3.

# 5.2 Compiling Message Files

To use message files with ACMS applications, create two output files from your source file:

- The image (.EXE) file containing the message texts and their corresponding symbols. This file is a shared image.
- Object module containing pointers to the .EXE message file.

Figure 5-1 shows the steps you take and the files you create when you compile message files. Following the figure are numbered instructions that correspond to the numbers in the figure.

Figure 5-1 Creating Message Files

1. Edit a message file (.MSG) with an editor.
   Follow the instructions in Section 5.1 to create a source file containing the text of messages.
2. Create the object module (.OBJ) containing the message text from the message file by running the Message Utility with the /OBJECT qualifier. For example:

       $ MESSAGE /OBJECT=VRMSG.OBJ VRMSG.MSG

   The optional /OBJECT qualifier defines the name of the object module. If you omit the qualifier (and do not use /NOOBJECT), the utility assigns the file name of the input file to the object module with a file type of .OBJ. The default file type for the input file is .MSG.
3. Create an .EXE message file by using the LINK command with the /SHARE qualifier. For example:

       $ LINK /SHARE=VRMSG.EXE VRMSG.OBJ

   The /SHARE qualifier defines the name of the shareable image to be created by the Linker. If you omit the file name from the /SHARE qualifier, the Linker assigns the file name of the input file to the object module output file, giving the output file a file type of .EXE. The default file type for the input file is .OBJ.
4. Create an object module that points to the .EXE message file containing the message text by running the Message Utility again, using the /FILE_NAME qualifier with the MESSAGE command. For example:

       $ MESSAGE /FILE_NAME=ACMS$EXAMPLES:VRMSG.EXE/OBJ=VRMSG_PTR  VRMSG

   When you use this command, the Message Utility creates an object module named VRMSG_PTR.OBJ. This object module contains the message symbols from the source file, but points to VRMSG.EXE for the text corresponding to those symbols. The default file name for the text message file is the same file name as the source file; the default file type is .EXE.
   Always include the device and directory specification for the text message file. Otherwise, ACMS looks for the text message file in the same directory as the ACMS software. Make sure that the name you use in the /FILE_NAME qualifier is the same as the name of the file you created with the LINK command.
5. After creating the pointer object module, link it into the procedure server images for all servers that handle tasks using that message file. The procedure server image contains all the modules for the procedure server, including step, initialization, and termination procedures; the message object module; and the server control object module created by the BUILD command of the Application Definition Utility. For example:

       $ LINK /DEBUG /EXE=VR_SERVER.EXE VR_SERVER.OBJ, -
       _$ ...,VRMSG_PTR

   This example is an abbreviated version of the LINK command. See Chapter 6 for instructions and examples of full LINK commands.

Do not link the text message file into the server image. The .EXE file created with the MESSAGE command is separate from the server image, in the same way that a run-time library is separate from a program.

If you need to change the wording of a message, change the message source file; then use the MESSAGE and LINK commands to create a new text message file (.EXE). You do not need to relink the procedure server image. For example:

    $ MESSAGE /OBJ=VRMSG.OBJ VRMSG.MSG
    $ LINK/SHARE=VRMSG.EXE VRMSG.OBJ

If you change only the message text, you do not need to create a new object module pointer file. However, if you add a new message, delete a message, change the order of messages in the file, or change a message symbol, you must create a new object module pointer file and relink the server image to include that new module (steps 4 and 5). Otherwise, the symbols in the message file and in the server image do not correspond to one another.

# 5.3 Displaying User-Defined Messages

After you define error messages in a message file, you can return message names from a server procedure and have the task calling the procedure trap for errors. Follow these steps for returning and displaying user-defined messages:

1. Define all symbols that you want a procedure to return as external to the program. In COBOL, use the VALUE IS EXTERNAL clause in the procedure. For example:

       01  CURECNOTFND              PIC S9(11) COMP
                                    VALUE IS EXTERNAL VR_CURECNOTFND.

   In the previous example, the message name is CURECNOTFND; the message symbol is VR_CURECNOTFND.
   In BASIC, use the EXTERNAL CONSTANT statement to define the message symbol in the procedure. For example:

              EXTERNAL LONG CONSTANT VR_CURECNOTFND

   You can define return values either in the program or in a library file of values.
2. In the procedure, move the message name into the return-status workspace. For example:

       SQL-NOT-FOUND.
       * If no customer record was found, return warning status.
               IF CTRL_KEY = "CUSID" THEN
                       MOVE CURECNOTFND TO RET-STAT
               . . .
               END-IF.

   When a procedure returns a value in a return status field, ACMS does the following:
   - Stores the return status values in ACMS$L_STATUS field of the ACMS$PROCESSING_STATUS workspace.
   - Sets the value of the ACMS$T_SEVERITY_LEVEL field; here, the value is set to W (warning).
   - Also sets the value of the ACMS$T_STATUS_TYPE field; here, the value is set to B (bad).
   Chapter 3 explains fields in the ACMS$PROCESSING_STATUS workspace.
3. Have the task definition check the ACMS$T_STATUS_TYPE field of the ACMS$PROCESSING_STATUS workspace.
   Include the GET MESSAGE clause in the task definition to direct ACMS to store the error message associated with the message symbol in the ACMS$T_STATUS_MESSAGE workspace. For example:

       ACTION IS
          IF (ACMS$T_STATUS_TYPE = "B") THEN
              GET MESSAGE INTO vr_control_wksp.messagepanel;
              GOTO PREVIOUS EXCHANGE;
          END IF;

   According to the previous instructions, ACMS checks the ACMS$T_STATUS_TYPE field. If it is B (bad), ACMS retrieves the error message. ACMS then goes to the previous exchange step in the task definition to display the error message.

Previous | Next | Contents | Index