Compaq ACMS for OpenVMS
Writing Applications


Previous Contents Index

14.5 Providing an RI Agent

When using the RI, do not use the ACMS-supplied agent (CP). Instead, use an RI agent to interface the task submitter to ACMS. An RI agent is provided as part of the ACMS software. You can use either this ACMS-supplied agent, called ACMS$RI_AGENT, or you can write your own agent to meet the specific needs of an application.

The ACMS$RI_AGENT provides an example of how an agent program can be developed to utilize the RI interface. An RI agent uses the Systems Interface (SI) services to sign users in to ACMS, enable the RI agent to perform I/O through the request interface, and call tasks in an ACMS application. The ACMS$RI_EXAMPLES directory contains a listing of the source code of the ACMS-supplied RI agent. See Compaq ACMS for OpenVMS Systems Interface Programming for more information about the Systems Interface and its services.

Always run an RI agent from a user process so there is one RI agent for each user process. An RI agent submits tasks to ACMS under the OpenVMS user name of the user process. The RI agent signs in each user process to identify it to the ACMS system. Just as in a standard ACMS system, only users authorized with the ACMS User Definition Utility can gain access to ACMS. Also, all terminals or devices accessing ACMS must be authorized with the ACMS Device Definition Utility. See Compaq ACMS for OpenVMS Managing Applications for more information about authorizing users and devices.

The RI agent ACMS$RI_AGENT (by default) prompts the user for an application and task name. An RI agent can also call a menu interface through which the user can enter data. You can write your own menu interface modules, or if you are interfacing to FMS, you might want to use the ACMS-supplied FMS menu interface. Section 14.5.1 describes more about how to provide a menu interface.

Figure 14-4 shows the pseudocode for the Request Interface agent and two menu interface routines. The routines in the figure use FMS calls to display the menu and retrieve the data.

Figure 14-4 Pseudocode for an RI Agent Using an FMS Menu Interface


In this figure, the RI agent:

  1. Signs in the user to the ACMS system. The agent uses the ACMS$SIGN_IN service to sign in the user. By default, the user name signed in is the agent's OpenVMS user name.
  2. Calls the ACMS$INIT_EXCHANGE_IO service to prepare the agent for use with the RI. The RI agent uses the ACMS$M_IO_ENABLE_SYNC_RI flag to indicate to the ACMS EXC that the RI agent performs all task I/O. See Compaq ACMS for OpenVMS Systems Interface Programming for more information on flags used by the ACMS$INIT_EXCHANGE_IO service.
  3. Determines whether or not the agent calls a user-written menu. The user-written menu routine can be linked into the agent, or into a shared image that is pointed to by the ACMS$RI_MENU logical name. The RI agent uses the ACMS$RI_MENU logical to locate the menu interface image, if any, that contains the ACMS$RI_MENU_INIT and ACMS$RI_MENU_ROUTINE user interface routines. If there is no menu, ACMS prompts the user for the application name and task name.
  4. Performs the exit processing starting at step 7 if the user enters $EXIT in response to the "Enter task name:" prompt. Otherwise, the agent calls the ACMS$GET_PROCEDURE_INFO service to find out what I/O method (terminal, request, stream, or none) and procedure ID to use for the task.
  5. Uses the ACMS$START_CALL service to submit an ACMS task if the task and application names are valid. Because the ACMS$START_CALL service only starts the task, the agent must also include an ACMS$WAIT_FOR_CALL_END service to wait for the task to end.
  6. Loops back to step 4 to prompt for another task selection.
  7. Calls the ACMS$TERM_EXCHANGE_IO service to terminate the exchange I/O enabled earlier.
  8. Calls the ACMS$SIGNOUT service to sign the user out of ACMS.

While taking these steps to develop an agent, you may need to define several logical names and routines for use at run time. Table 14-1, Table 14-2, and Table 14-3 summarize these names and routines.

Table 14-1 Logical Names Used by the Request Interface
Logical Name Used by ACMS at Run Time
ACMS$RI_LIB_library-name A logical defined by the user that identifies the request library or shareable image associated with the name used in a REQUEST IS USING clause.
ACMS$RI_MENU A logical defined by the user that identifies the shareable image created by linking the ACMS$RI_MENU_INIT menu initialization procedure and the ACMS$RI_MENU_ROUTINE menu interface procedure.

Table 14-2 Routines Used by the Request Interface
Routine Name Identifies
ACMS$RI_LIB_CANCEL An optional user-written cancel procedure that the RI calls to do cleanup work when a task is canceled.
ACMS$RI_DEBUG_ROUTINE An ACMS-supplied routine that the Request Interface starts up when you debug URP object modules.
ACMS$RI_LIB_INIT An optional user-written initialization procedure that sets up the necessary data structures for the RI executable image.

Table 14-3 Menu Interfaces Used by the Request Interface
Routine Name Identifies
ACMS$RI_MENU_INIT An optional user-written initialization procedure that sets up to use the ACMS$RI_MENU_ROUTINE menu interface.
ACMS$RI_MENU_ROUTINE A user-written (URP) menu interface procedure.

14.5.1 Providing a Menu Interface

There are two ways to obtain task selection information from the user: write your own menu interface, or code the RI agent to prompt you automatically for information. If you choose not to write a menu interface and you use the ACMS-supplied RI agent, by default the ACMS$RI_AGENT prompts the user to enter the task and application selections. If you choose to use a menu interface, the ACMS$RI_AGENT can optionally call special-purpose menu interface (URP) procedures with which the user can enter the task and application information.

With a menu interface in place, the application is easier to use because you do not have to select an application and the specific task each time you want to run a task. To use a menu interface with the ACMS$RI_AGENT, a programmer must write a menu initialization procedure and a menu interface procedure. These procedures must be named ACMS$RI_MENU_INIT and ACMS$RI_MENU_ROUTINE, respectively.

Include these procedures in the RI agent code in one of the following ways:

If interfacing to FMS, you may want to use the ACMS-supplied FMS menu interface. ACMS supplies an FMS-based menu interface as part of the RI software. The sample FMS form library for the menu interface is located in the ACMS$RI_EXAMPLES directory.

As with the user-written menu interface described previously, you can include the ACMS-supplied FMS menu interface in an RI agent by either defining the logical ACMS$RI_MENU to point to a shared image that contains the ACMS$RI_MENU_INIT and ACMS$RI_MENU_ROUTINE procedures, or relinking the RI agent with the ACMS$RI_MENU_INIT and ACMS$RI_MENU_ROUTINE procedures.

The layout of the FMS menu form is similar to the ACMS menu format. The FMS menu form contains a menu header, a selection list, a prompt line and a message line. The menu header is the name of the menu. The selection list shows the tasks to run and the menus for display. The prompt line includes both the SELECTION: prompt and the blank spaces after the prompt. You type the number or keyword for the task or menu you want in the blank space after the prompt. Press [Return] after your selection.

Example 14-11 and Example 14-12 show FMS-supplied initialization and menu interface definitions.

Example 14-11 FMS Initialization Procedure

FUNCTION LONG ACMS$RI_MENU_INIT 
 
        RET_STATUS = FDV$ATERM(TCA%(),12%,12%) 
 
        RET_STATUS = FDV$AWKSP(FMS_WORKSPACE%(),2000%) 
 
        RET_STATUS = FDV$LOPEN('ACMS$RI_FMS_MENU_LIB'm10%) 
 
END FUNCTION 

Example 14-12 FMS Menu Procedure

FUNCTION LONG ACMS$RI_MENU_ROUTINE ( STRING TASK_NAME ,        & 
                                     STRING APPLICATION_NAME,  & 
                                     LONG   EXECUTION_STATUS ) 
 
        RET_STATUS = FDV$CDISP(TRM$(CURRENT_FORM)) 
 
        RET_STATUS = FDV$GET ( MENU_OPTION, TERMINATOR, 'OPTION') 
 
        RET_STATUS = FDV$RETDI(VAL%(DATA_INDEX),NAMED_DATA) 
 
END FUNCTION 

To change FMS menus, change only the form definition. You do not need to make code changes to change FMS menus. The NAMED_DATA syntax is part of FMS forms definition and is explained in the FMS documentation. For more information about how to modify the ACMS-supplied FMS menu interface to work with your application, see Appendix F.

14.5.2 Compiling and Linking Menu Interface URPs with the RI Agent

After writing the menu initialization and interface procedures, compile those procedures and link the resulting object modules with the RI agent in one of the following ways:

For example, type the following command to link the RI agent to include the FMS menu interface:


$ LINK/EXE=fmsagent.exe  sys$input/option
       sys$library:acms$ri.olb/include=acms$ri_agent_module
       sys$library:acms$ri_fms_menu.olb/include=
       (acms$ri_menu_init, acms$ri_menu_routine)   
 
$ DEFINE ACMS$RI_LIB_libraryname ri_request_library.exe
 
$ DEFINE ACMS$RI_FMS_MENU_LIB fmsformmenulib.flb
 
$ RUN fmsagent

At run time, the ACMS$RI_AGENT uses the following steps to run the menu interface procedures:

  1. If the menu interface procedures have been linked with the agent object module, it runs those procedures.
  2. If the menu interface procedures have not been linked with the agent object module, the ACMS$RI_AGENT uses the logical name ACMS$RI_MENU to locate the menu interface image containing the menu initialization and interface procedures.
  3. If the menu interface procedure is not available, then the ACMS$RI_AGENT prompts the user for an application and task name.

To debug menu initialization and menu interface procedures, follow the instructions for debugging URPs in Section 14.6.

14.5.3 User-Written Menus for the ACMS$RI_AGENT

When you write a user-written menu routine for the ACMS$RI_AGENT, it is important to be aware of how your chosen language handles dynamic string descriptors. The task name and application name arguments in the ACMS$RI_AGENT are passed to the ACMS$RI_MENU_ROUTINE as dynamic descriptors. If the language you have chosen does not support dynamic string descriptors, you must use an OpenVMS run-time library routine to return the task and application names to the ACMS$RI_AGENT.

The following FORTRAN example accepts an application name and a task name into two fixed-length strings. The STR$TRIM OpenVMS RTL routine is then used to remove trailing spaces and copy the names into the arguments supplied by the ACMS$RI_AGENT.


! 
!   THIS ROUTINE GETS THE TASK AND APPLICATION 
!   NAMES FROM THE USER.... 
! 
INTEGER FUNCTION ACMS$RI_MENU_ROUTINE(TASK,APPL,TASK_STS) 
! 
! Addresses of appl and task name dynamic string descriptors 
INTEGER*4 TASK, APPL 
! 
! Completion status of previous task (0 if 1st time through) 
INTEGER*4 TASK_STS 
! 
! Local strings to input application and task names 
CHARACTER*32 TNAME, ANAME 
! 
! RTL completion status 
INTEGER*4 STATUS 
! 
! RTL routine to trim spaces from a string 
INTEGER*4 STR$TRIM 
! 
WRITE( UNIT=5,FMT='(A,$)' ) ' INPUT APPLICATION SELECTION: ' 
READ ( UNIT=5,FMT='(A32)' ) ANAME 
WRITE( UNIT=5,FMT='(A,$)' ) ' INPUT TASK SELECTION: ' 
READ ( UNIT=5,FMT='(A32)' ) TNAME 
! 
STATUS = STR$TRIM( %REF(TASK), %DESCR(TNAME) ) 
IF (STATUS) THEN 
STATUS = STR$TRIM( %REF(APPL), %DESCR(ANAME) ) 
END IF 
! 
ACMS$RI_MENU_ROUTINE = STATUS 
RETURN 
END 

14.6 Debugging Applications that Call URPs

The method used to debug the RI user request procedures depends on whether or not:

Section 14.6.1 discusses using the OpenVMS Debugger to debug applications that are already up and running, but are currently using TDMS requests. Section 14.6.2 describes using the ACMS Task Debugger to debug URPs and the tasks that they call.

Do the following to prepare to debug:

  1. Link the RI agent with the debugger:


    $ LINK/DEBUG/EXE=debug_agent -
    _$ sys$library:acms$ri.olb/include=acms$ri_agent_module
     
    

    This command creates an image named DEBUG_AGENT.EXE in your default directory. You can use the optional /EXE qualifier to assign a name to the image. If you do not use the qualifier, the linker uses the file name of the first object module in the LINK command as the name of the server image. The default file type is .EXE. Make sure that the name of the server image is the same as the name in the IMAGE clause of the task group definition.
    Include the /DEBUG qualifier in the LINK command to set up the table of symbols used for debugging.

  2. Include the ACMS$RI_DEBUG_MODULE object module in the RI shareable image file by adding the following line to the LINK command in Example 14-10:


     sys$library:acms$ri.olb/include=acms$ri_debug_module
     
    

    ACMS supplies the ACMS$RI_DEBUG_MODULE to debug URPs. Link the ACMS$RI_DEBUG_MODULE in the shared image that contains the URPs so that when the shared image is activated, the RI agent (ACMRRSHR component) will invoke the debugger. The image is activated by the LIB$FIND_IMAGE_SYMBOL RTL routine in the RI agent. The ACMS$DEBUG_ROUTINE is then invoked to signal the debugger. The user sets the module to the URP module to set breaks and so on.

To protect business data, set up test files to run against the task. If your procedures use logical names to identify the files used, create a set of data files in another directory and temporarily redefine the logical names to point to that directory. If defining these logical names from DCL command mode, be sure to define the names as group or system logicals using the /GROUP or /SYSTEM logical on the DEFINE or ASSIGN command.

14.6.1 Using the OpenVMS Debugger to Debug URPs Using a Running Application

Start with a running ACMS application that is currently working by using TDMS requests. Then define the ACMS$RI_LIB_library-name logical name to point to the URP shareable image file. Then run the RI agent you linked with the debugger. For example:


$ ACMS/START APPLICATION test_application
$ DEFINE ACMS$RI_LIB_request_library1  request_lib_image.exe
$ RUN debug_agent
DBG> GO
Task Name:
Application Name:
DBG>

In this example, test_application is a fully developed ACMS application that contains a TDMS request library named request_library1.rlb. The shareable image created to replace that TDMS request library is named request_lib_image.exe.

14.6.2 Using the ACMS Task Debugger to Debug URPs and Their Tasks

This section provides an outline of the steps to debug URPs and their tasks by using the ACMS Task Debugger. This method of debugging is very similar to the method for debugging tasks submitted by user-written agents that is discussed in Compaq ACMS for OpenVMS Writing Server Procedures. By following these instructions and supplementing this discussion with the one in Compaq ACMS for OpenVMS Writing Server Procedures, you can debug URPs with the RI debugger and debug tasks with the ACMS Task Debugger. To use this debugging method, do the following:

  1. Type the following commands to start the ACMS Task Debugger process:


    $ SET PROCESS/PRIVILEGE=SHARE
    $ ACMS/DEBUG/AGENT_HANDLE=dummyapplicationname testgroup.tdb
    ACMSDBG>
    

    In response to the ACMSDBG prompt, start servers needed by the task and set breakpoints before selecting the task (see Compaq ACMS for OpenVMS Writing Server Procedures). Then type the ACCEPT command to allow the ACMS Task Debugger to accept calls from the RI agent program:


    ACMSDBG> ACCEPT
    

  2. Make tasks selected by the RI agent program run in the ACMS Task Debugger by defining the following before you run the RI agent:


    $ DEFINE ACMS$RI_LIB_request_library1  request_lib_image.exe
    $ DEFINE ACMS$DEBUG_AGENT_TASK "TRUE"
    $ RUN debug_agent
    DBG> GO
    Task Name:
    Application Name: dummyapplicationname
    DBG>
    

    When you run the RI agent linked with the OpenVMS debugger, the debugger prompt appears. In these commands, the dummyapplicationname is the agent handle that was used in the ACMS/DEBUG/AGENT_HANDLE command in the debugger process (see Compaq ACMS for OpenVMS Writing Server Procedures).

After setting up the debugger process, start the agent process and enter the GO command at the DBG> prompt. Because a menu interface was not linked into the RI agent in this example, the ACMS$RI_AGENT prompts you for a task name and an application name.

After you enter the task and application names, the RI determines if the RI request library shareable image file contains the ACMS$RI_DEBUG_MODULE procedure (URP). If the debugger procedure exists, the OpenVMS debugger (DBG>) prompt appears.

At this point, use the SET IMAGE command to tell the debugger that you are going to use the RI request library shareable image file. The name of the image specified with this command must be the same as the logical name used to point to the RI request library image. Then you can set breakpoints at any URPs, including the initialization and cancellation URPs. For example:


DBG> SET IMAGE ACMS$RI_LIB_<!OPEN>requestlibraryname<!CLOSE>
DBG> SET BREAK urp1
DBG> SET BREAK urp2
DBG> GO

Type $EXIT in response to the "Enter Task Name:" prompt to exit from the RI agent.

14.7 Defining an Application that Uses the Request Interface

There are no differences between an application definition that uses DECforms or TDMS and one that uses the Request Interface. Example 14-13 shows the application definition that uses the task group and tasks defined in this document.

Example 14-13 Example Application Definition

REPLACE APPLICATION RI_SAMPLE_APPL 
  AUDIT; 
APPLICATION USERNAME IS adf$exc; 
DEFAULT APPLICATION FILE IS 
              "ACMS$RI_EXAMPLES:RI_SAMPLE_APPL.ADB"; 
 
SERVER DEFAULTS ARE 
  AUDIT; 
  USERNAME IS adf$server; 
END SERVER DEFAULTS; 
 
TASK DEFAULTS ARE 
   AUDIT; 
END TASK DEFAULTS; 
 
TASK GROUP IS 
   RI_LOGICAL_GROUP: 
       TASK GROUP FILE IS "ACMS$RI_EXAMPLES:RI_PASSED_GROUP.TDB"; 
END TASK GROUP; 
END DEFINITION; 
 

14.8 Running the Agent

To run your agent in a production environment, relink the request procedures, omitting the /DEBUG qualifier and the RI debug object module ACMS$RI_DEBUG_MODULE. Then use the DCL RUN command followed by the name of the RI agent image. For example:


$ RUN ACMS$RI_AGENT


Previous Next Contents Index