Compaq ACMS for OpenVMS
Writing Applications


Previous Contents Index

14.3.1 Task Definition

The task definition in Example 14-1 is an example of a simple inquiry task. This task definition is generic in that it can be used to call a TDMS request or a URP in a shareable image. This discussion provides the task definition for the sake of example. This example is part of the ACMS-supplied example that is provided in the ACMS$RI_EXAMPLES directory. It is also referred to in several subsequent sections.

The task definition consists of two exchange steps and a processing step. In this task, the user enters a customer number and presses [Return]. The task uses the customer number to read the customer data file and retrieve the appropriate record, displaying that record on the screen.

Example 14-1 Simple Inquiry Task

REPLACE TASK RI_INQ_TASK 
DEFAULT SERVER IS RI_SERVER; 
WORKSPACES ARE RI_EMPLOYEE_RECORD; 
BLOCK WORK 
   EX1: 
       EXCHANGE 
       REQUEST IS RI_INQ_REQUEST IN RI_REQUEST_LIBRARY1 
          USING RI_EMPLOYEE_RECORD; 
   SP1: 
       PROCESSING 
       CALL RI_GET_PROCEDURE IN RI_SERVER 
           USING RI_EMPLOYEE_RECORD; 
   EX2: 
       EXCHANGE 
       REQUEST IS RI_INQ_DISP_REQUEST IN RI_REQUEST_LIBRARY2 
          USING RI_EMPLOYEE_RECORD; 
END BLOCK WORK; 
END DEFINITION; 

In this example, the task calls a request in a library identified as REQUEST_LIBRARY1. Note that this does not indicate whether ACMS should use a TDMS request or a URP. This decision is not made until run time, when the RI calls a TDMS request or a URP depending on how the library is defined in the group and whether or not an ACMS$RI_LIB logical has been defined for this library.

In a single task, one exchange step can call a URP to do terminal I/O while another can use a TDMS request to do terminal I/O. ACMS passes workspaces to URPs in the same way that it passes workspaces to routines in procedure servers.

See Chapter 10 for more information on defining a task.

14.3.2 Defining a Task Group

When defining a task group whose tasks call only URPs, you can use the REQUEST LIBRARY IS clause to name the shareable image containing URP procedures. Example 14-2 shows an example of a task group definition. Alternatively, you can name an .RLB file and use an ACMS$RI_LIB logical name to point to a shareable image at run time. See Chapter 10 for more information on defining a task group.

Example 14-2 Task Group Definition

REPLACE GROUP RI_PASSED_GROUP 
REQUEST LIBRARY ARE  "ACMS$RI_EXAMPLES:RI_REQUEST_LIBRARY1.EXE" 
                          WITH NAME RI_REQUEST_LIBRARY1, 
                     "ACMS$RI_EXAMPLES:RI_REQUEST_LIBRARY2.RLB" 
                          WITH NAME RI_REQUEST_LIBRARY2; 
 
DEFAULT TASK GROUP FILE 
    IS "ACMS$RI_EXAMPLES:RI_PASSED_GROUP.TDB"; 
 
   SERVER IS 
       RI_SERVER: 
          PROCEDURE SERVER IMAGE IS 
                  "ACMS$RI_EXAMPLES:RI_SERVER.EXE"; 
          INITIALIZATION PROCEDURE IS RI_INIT_PROCEDURE; 
          TERMINATION PROCEDURE IS RI_TERM_PROCEDURE; 
          PROCEDURES ARE       RI_ADD_PROCEDURE, 
                               RI_GET_PROCEDURE; 
   END SERVER; 
 
   TASK IS 
       RI_ADD_TASK     : TASK DEFINITION IS RI_ADD_TASK; 
       RI_INQ_TASK     : TASK DEFINITION IS RI_INQ_TASK; 
   END TASK; 
END DEFINITION; 
 

Notice that this task group names both a URP shareable image file and a request library; the tasks in the group can use both user request procedures and TDMS requests.

However, be aware that you cannot use CP to select a task that uses a request in a library that is defined as an .EXE file. This is because CP cannot call URPs and does not translate ACMS$RI_LIB logical names in order to determine if an .RLB file is also available.

Consider the steps ACMS takes when processing the task and task group shown in Example 14-1 and Example 14-2:

  1. At application startup time, the EXC determines the file type of the request libraries (.RLB or .EXE). It opens the ACMS$RI_EXAMPLES:RI_REQUEST_LIBRARY2.RLB file but does not open the ACMS$RI_EXAMPLES:RI_REQUEST_LIBRARY1.EXE file.
    If there is an ACMS$RI_LIB logical name that redefines the .EXE file to be an .RLB file, the Request Interface opens that request library at run time. See Section 14.3.3 for information on defining the ACMS$RI_LIB logical name.
  2. When the task step begins executing, the EXC passes the following names to the RI agent:
  3. The Request Interface does the following:

14.3.3 How and When to Use the ACMS$RI_LIB Logical Name

The TDMS request libraries (.RLB) files or the URP (.EXE) shareable image files can be defined and referenced in the REQUEST LIBRARY IS clause in the task group definition or with the ACMS$RI_LIB_libraryname logical. In either case, the ACMS$RI_LIB logical name can replace or override whatever is defined in the task group definition.

The ACMS shareable image, ACMRRSHR (in the RI agent process), translates the ACMS$RI_LIB logical name at run time to determine whether the task should use TDMS or a URP. Define the ACMS$RI_LIB logical name in any logical name table that is accessible by the RI agent program. For example, defining it as a process logical name means that only a specific user has access to the request library or shareable image defined by the logical. However, defining it as a group logical name means that all users with the same UIC group can have access to the request library or shareable image file defined by the logical.

You use the DEFINE command to define the logical name ACMS$RI_LIB_file-name for a shareable image or request library. It is important that the request library that is referenced by the ACMS$RI_LIB logical name has the same library name as defined in the task group definition, and it must include the .RLB or .EXE file extension:


$ DEFINE ACMS$RI_LIB_RI_REQUEST_LIBRARY1 -
_$ ACMS$RI_EXAMPLES:RI_REQUEST_LIBRARY1.EXE/GROUP

This example defines a group logical for the shareable image named
RI_REQUEST_LIBRARY1.EXE. When defining the ACMS$RI_LIB logical, provide the full file specification. Otherwise, ACMS assumes the file is located in SYS$SHARE.

If you use TDMS applications with the RI, you do not need to make any modifications to existing task, task group, or application definitions. However, try to avoid misleading other users by what you have defined in the task definition. Consider the following options to improve the readability of a task group definition:

Remember that ACMS makes the final determination at run time to call a TDMS request or a URP. You can use the ACMS$RI_LIB logical to override what is defined in the task group definition. Use this logical to enable or disable the RI on a user-by-user basis so that you can have one person use TDMS and another use a URP in the same ACMS application. This makes the RI attractive for testing an application because you can use logicals to redefine the RLB that is hard-coded in the task group definition.

14.4 Writing User Request Procedures

Write user request procedures, URPs, to perform I/O for ACMS tasks in place of TDMS requests. You can write a URP in any OpenVMS-supported high-level language and include the necessary facility calls (for example, FMS, SMG, QIO) that allow you to interface ACMS with the appropriate device.

A URP can use all the facilities available to a normal program and extend the terminal I/O capabilities of the ACMS application without impacting the task definition or task group definition. Use the following guidelines when writing RI procedures:

Example 14-1 and Example 14-2 depict a task and a task group in which the first exchange step in the task calls a URP. Example 14-3 shows RI_INQ_REQUEST, a FORTRAN URP that displays the inquiry form and prompts the user to enter the customer number.

Example 14-3 FORTRAN User Request Procedure

 
!********************** RI_INQ_REQUEST ******************* 
! 
       INTEGER FUNCTION RI_INQ_REQUEST (DATA_REC) 
       INCLUDE '($IODEF)'              !OpenVMS I/O definitions 
! 
!   Declaration of variables 
! 
!       Declare external routines 
! 
        INTEGER                SYS$QIOW 
! 
!       Declare the workspaces that will be passed as parameters 
! 
        STRUCTURE /RI_EMPLOYEE_RECORD/ 
          INTEGER*4   EMPLOYEE_ID 
          CHARACTER*10 EMPLOYEE_FIRST_NAME 
          CHARACTER*10 EMPLOYEE_LAST_NAME 
        END STRUCTURE 
        RECORD /RI_EMPLOYEE_RECORD /DATA_REC 
! 
!       Declare the IOSB to be used in the OpenVMS QIO system service 
! 
        STRUCTURE /IOSTAT_BLOCK/ 
          INTEGER*2   IOSTAT 
          INTEGER*2   TERM_OFFSET 
          INTEGER*2   TERMINATOR 
          INTEGER*2   TERM_SIZE 
        END STRUCTURE 
        RECORD /IOSTAT_BLOCK/ IOSB 
! 
!       Declare input channel number to be shareable 
!       by all User Request Procedures (URP). 
! 
        INTEGER*2      INPUT_CHAN 
       COMMON /INPUT_CHANNEL/INPUT_CHAN 
! 
!       Declare local variables 
! 
       INTEGER*4       CODE,STATUS 
 
        CHARACTER*1    ESC 
        DATA           ESC /27/ 
        CHARACTER*3    CLEAR 
        DATA           CLEAR /'[2J'/ 
        CHARACTER*7    POSITION 
        DATA           POSITION /'[00;24f'/ 
 
       CHARACTER*80    PROMPT 
        CHARACTER*10    INPUT_STRING 
 
! 
!   Perform the RI_INQ_REQUEST User Request Procedure.  This 
!   routine will duplicate the work done by the RI_INQ_REQUEST 
!   TDMS request, which displays a form to accept employee id from 
!   the terminal user. 
! 
!       Set return status success 
! 
        RI_INQ_REQUEST = 1 
! 
!       Screen is cleared and cursor is positioned at 6th line, 
!       24th column then user is requested to input Employee ID. 
! 
        POSITION(2:3) = '06' 
       PROMPT = ESC//CLEAR//ESC//POSITION//'EMPLOYEE ID: ' 
       CODE = IO$_READVBLK.OR.IO$_READPROMPT 
       STATUS = SYS$QIOW (,%VAL(INPUT_CHAN), %VAL(CODE),IOSB,,, 
       1                %REF(INPUT_STRING), %VAL(6),,, 
       1                %REF(PROMPT), %VAL(25)) 
       IF (.NOT. STATUS) THEN 
            RI_INQ_REQUEST = STATUS 
            RETURN 
        END IF 
! 
!       Employee ID is converted from a string to the integer 
!       field in the workspace record. 
! 
       DECODE (IOSB.TERM_OFFSET,100,INPUT_STRING) DATA_REC.EMPLOYEE_ID 
100    FORMAT (I6) 
 
       END 

Example 14-4 shows RI_INQ_DISP_REQUEST, a TDMS request used in the second exchange step of the task shown in Example 14-1.

Example 14-4 TDMS Request

REPLACE REQUEST RI_INQ_DISP_REQUEST 
 
FORM   IS RI_INQ_DISP_FORM; 
RECORD IS RI_EMPLOYEE_RECORD; 
 
CLEAR SCREEN; 
DISPLAY FORM RI_INQ_DISP_FORM; 
 
OUTPUT  EMPLOYEE_ID             TO EMPLOYEE_ID, 
        EMPLOYEE_FIRST_NAME     TO EMPLOYEE_FIRST_NAME, 
        EMPLOYEE_LAST_NAME      TO EMPLOYEE_LAST_NAME; 
 
WAIT; 
END DEFINITION; 
 

14.4.1 Writing an ACMS$RI_LIB_INIT Initialization Procedure

As an option, you can write an initialization procedure that sets up the necessary data structures for the RI shared image. For example, if the URP use an FMS-supported device, the initialization procedure might set up FMS workspaces, open an I/O channel to the terminal, open forms libraries, and do other initialization work necessary to perform I/O to the terminal. The initialization procedure must return a status value, or the RI reports a failure and cancels the current task.

The ACMSRRSHR component calls the ACMS$RI_LIB_INIT procedure only once (when it first maps the shared image) before it calls a URP in the shared image for the first time. Always name this procedure ACMS$RI_LIB_INIT. Link the initialization procedure with the shared image.

Example 14-5 shows an initialization procedure written in FORTRAN.

Example 14-5 FORTRAN Initialization Procedure

!****************  ACMS$RI_LIB_INIT ********************** 
! 
        INTEGER FUNCTION ACMS$RI_LIB_INIT 
! 
!   This procedure is the initialization routine for the TDMS_LIB 
!   library file.  The initialization procedure is not required, 
!   but if one exists it must be named ACMS$RI_LIB_INIT. 
! 
!   Since this library file will perform QIOs to the terminal 
!   instead of executing the normal TDMS request for each exchange 
!   step, the initialization procedure will open a channel to 
!   the user terminal. 
! 
!   Declaration of variables 
! 
!       Declare external routines 
! 
        INTEGER        SYS$ASSIGN 
! 
!       Declare input channel number to be shareable 
!       by all User Request Procedures (URP). 
! 
        INTEGER*2      INPUT_CHAN 
       COMMON /INPUT_CHANNEL/INPUT_CHAN 
! 
!       Set up local variables 
! 
       INTEGER*4      STATUS 
! 
!   **IMPORTANT: 
!   A status must be passed back from the initialization procedure 
!   or the RI will report a failure and cancel the current task. 
! 
!       Set the return status equal to success, 
! 
        ACMS$RI_LIB_INIT = 1 
! 
!   Perform the initialization procedure for the QIO 
!   library file. 
! 
!       Assign the terminal pointed to by SYS$INPUT and provide 
!       the I/O channel number to perform subsequent QIO calls. 
! 
       STATUS = SYS$ASSIGN ('SYS$INPUT',INPUT_CHAN,,) 
! 
!       Check the status that was return from the 
!       SYS$ASSIGN system service call.  If an error 
!       occurred, then return the error to the Request 
!       Interface which will report the error in 
!       ACMS audit log and cancel the task. 
! 
        IF (.NOT. STATUS) THEN 
           ACMS$RI_LIB_INIT = STATUS 
           RETURN 
       END IF 
 
       END 

The name of the URP in this example is in a function statement. The URP does not pass any parameters, but it defines a COMMON area with which to open a channel to a user terminal. This initialization URP sets the return status to success. When using the RI, it is important to return a status from the URP whether it is an initialization URP or any other URP. The RI agent checks the status returned. If there is an error, the message is returned to the RI. The RI reports the error to ACMS, cancels the current task, and logs the message in the ACMS audit trail log. If you do not return status information from a URP, the RI agent:

Example 14-6 shows an example of the error messages that would be recorded in the audit trail log if the RI agent was unable to open the I/O channel for the RI_INQ task.

Example 14-6 Example of Audit Trail Error Messages

Task canceled in STEP EX1 task RI_INQ_REQUEST in Group RI_PASSED_GROUP 
Error processing request interface call 
Error executing initialization routine for request library file 
      DEVICE:$[$DIR]LIBRARY1.EXE 
PROGRAM ERROR: 
 
Error processing request interface call 
Error in Request RI_INQ_REQUEST, error returned from URP in 
      DEVICE:$[$DIR]LIBRARY1.EXE 
SYSTEM-F-INVCHAN, invalid I/O channel 

14.4.2 Writing an ACMS$RI_LIB_CANCEL Cancellation Procedure

You can optionally write a cancel procedure to abort any I/O in progress and do any necessary cleanup work for a task. If a task is canceled for any reason such as by the ACMS/CANCEL operator command (discussed in Compaq ACMS for OpenVMS Managing Applications), the Request Interface searches for the ACMS$RI_LIB_CANCEL routine in the shareable image and uses that routine as the cancellation procedure for the task. Example 14-7 shows a cancellation procedure written in FORTRAN.

Example 14-7 FORTRAN Cancel Procedure

!****************** ACMS$RI_LIB_CANCEL  *********************** 
! 
        INTEGER FUNCTION ACMS$RI_LIB_CANCEL 
! 
!   This procedure is the cancellation routine for the TDMS_LIB 
!   library file.  The cancellation procedure is not required, 
!   but if one exists it must be named ACMS$RI_LIB_CANCEL. 
! 
!   This routine will get called when the current task gets 
!   canceled either by the operator command "ACMS/CANCEL TASK" 
!   or the using typing [Ctrl] during an exchange step.  It 
!   signals an ACMS$_CANCELD error, which will abort any 
!   QIO's that were in progress and will unwind the call 
!   stack. 
! 
!   Declaration of variables 
! 
!       Declare external symbols and routines 
! 
        EXTERNAL    ACMS$_CANCELD 
        INTEGER     LIB$SIGNAL,SYS$CANCEL 
! 
!       Declare input channel number to be shareable 
!       by all User Request Procedures (URP). 
! 
        INTEGER*2      INPUT_CHAN 
       COMMON /INPUT_CHANNEL/INPUT_CHAN 
! 
!       Declare local variables 
! 
        INTEGER*4   STATUS 
! 
!   Perform the cancellation procedure for the TDMS_LIB 
!   library file. 
! 
!       Cancel any QIO that is outstanding 
! 
        STATUS = SYS$CANCEL(%VAL(INPUT_CHAN)) 
        CALL LIB$SIGNAL(ACMS$_CANCELD) 
! 
        END 

14.4.3 Compiling and Linking URPs

After writing the user request procedures for all the tasks in a task group and any initialization and cancellation procedures, compile those procedures and link them into a shareable image file. Reference the shareable image file in either of the following ways:

An application can use multiple shareable image files. Each shareable image file contains any number of URPs, an optional URP initialization procedure to set up the necessary work areas, and an optional URP cancellation procedure. Figure 14-3 shows the contents of a shareable image file.

Figure 14-3 User-Written Shareable Image File


The following command compiles request procedures RI_INQ_REQUEST, ACMS$RI_LIB_INIT, and ACMS$RI_CANCEL, and produces three object modules:


FORTRAN RI_INQ_REQUEST, ACMS$RI_LIB_INIT, ACMS$RI_LIB_CANCEL/DEBUG

When linking your request procedures, you must:

Example 14-8 REQPROCS.OPT Options File on VAX

UNIVERSAL = RI_INQ_REQUEST 
UNIVERSAL = ACMS$RI_DEBUG_ROUTINE 
UNIVERSAL = ACMS$RI_LIB_INIT 
UNIVERSAL = ACMS$RI_LIB_CANCEL 
PSECT_ATTR = INPUT_CHANNEL,PIC,USR,OVR,REL,GBL,NOSHR,NOEXE,RD,WRT,NOVEC 

Example 14-9 REQPROCS.OPT Options File on Alpha

SYMBOL_VECTOR = (RI_INQ_REQUEST = PROCEDURE,- 
                 ACMS$RI_DEBUG_ROUTINE = PROCEDURE ,- 
                 ACMS$RI_LIB_INIT = PROCEDURE ,- 
                 ACMS$RI_LIB_CANCEL = PROCEDURE) 
PSECT_ATTR = INPUT_CHANNEL,PIC,USR,OVR,REL,GBL,NOSHR,NOEXE,RD,WRT,NOVEC 

The RI uses the OpenVMS Run-Time Library (RTL) routine LIB$FIND_IMAGE_SYMBOL to locate the URP to call. Therefore, the request library executable image must meet the following requirements of the LIB$FIND_IMAGE_SYMBOL routine:

You can use any OpenVMS file names for your procedures and for the shareable image file.

Example 14-10 links into a shareable image the four object modules. It also shows how to use the options file in Example 14-8 and Example 14-9 and how to meet the requirements of the LIB$FIND_IMAGE_SYMBOL RTL service.

Example 14-10 Linking Shareable Images and Using an Options File

$ LINK/DEBUG/SHARE/EXECUTABLE=REQPROCS.EXE RI_INQ_REQUEST, -
_$ ACMS$RI_LIBINIT, ACMS$RI_LIB_CANCEL, -
_$ SYS$LIBRARY:ACMS$RI.OLB/INCLUDE=ACMS$RI_DEBUG_MODULE, -
_$ REQPROCS.OPT

In this list of commands:

  1. The /SHARE qualifier creates an OpenVMS shareable image. If you forget this qualifier and attempt to use the image, the RI logs the error "Reserved addressing fault" in the ACMS audit trail log to notify you that the image has not been linked as a shareable image.
  2. The UNIVERSAL command in the options file on a VAX system sets up the global symbols as keys into the image. The SYMBOL_VECTOR command in the options file on an Alpha system sets up the global symbols as keys into the image. The symbols referenced must be global to be defined as universal. You define a symbol as universal on VAX by using the UNIVERSAL command and on Alpha by using the SYMBOL_VECTOR command. All URPs, including the initialization, debugger, and cancellation URPs, must be defined as universal symbols. If you try to access a URP that was not declared as a universal symbol, the RI logs the following error in the ACMS audit trail log:


    %LIB-F-KEYNOTFOU, key not found in tree 
    

  3. The PSECT_ATTR command in the option file sets the URP common area as not shareable. By default, all common areas have the PSECT attribute SHR. This attribute lets multiple processes share the same data area if it is installed (using the OpenVMS Install Utility) as writable.
    Be sure that all URPs for a given RI request library can share the data areas. However, those data areas should not be shareable across different processes. If you define the PSECT attribute as NOSHR, each user (process) can have a separate copy of the data area. If you try to run the RI with the PSECT attribute set to SHR, the RI logs an error in the ACMS audit trail log, notifying you that the image must be installed as WRITABLE. This message indicates that the PSECT attribute is set to SHR. Remember, if you install the image as writable, the data areas are shared by many processes and the URPs may access corrupted data.


Previous Next Contents Index