Compaq ACMS for OpenVMS
Writing Applications


Previous Contents Index

4.5 Using User Workspaces

Just as group workspaces let you keep information for many users in many tasks or instances of the same task, user workspaces let you store information used by a single user in many tasks or many task instances.

Because a user workspace is specific to a single user rather than to tasks in an application, you do not run a task at application startup to initialize a user workspace (as you would for a group workspace). Instead, you can include an initial processing step that tests the contents of the workspace. If the workspace is empty, a procedure or form gets information and writes it to the workspace.

The user may need to see several kinds of information about an employee, for example. The user must select a separate task to see each kind of information. To see information about the employee's education, the user selects the Display Education task. To see family information, the user selects the Display Family task.

In each of these tasks, the user begins by typing in the employee number. Because all the information displayed by different tasks is about a single employee in this case, you do not want the user to have to supply the employee number for each task selection. Instead you can use the contents of a user workspace in the initial step of each task. Displaying those contents allows the user either to change the employee number or to press [Return] to see information about the employee.

Example 4-8 shows the record definition for DISPLAY_USER_WKSP.

Example 4-8 Record Definition for DISPLAY_USER_WKSP

DEFINE RECORD 
       DISK1:[CDDPLUS]ACMS$DIR.ACMS$EXAMPLES_RMS.DISPLAY_USER_WKSP. 
  DISPLAY_USER_WKSP STRUCTURE. 
    EMP_NUMBER    DATATYPE SIGNED LONGWORD. 
  END DISPLAY_USER_WKSP STRUCTURE. 
END DISPLAY_USER_WKSP. 

This workspace has a single field for the number of the employee whose records the user wants to see.

The first exchange step of each of the display tasks can use this workspace to display the current employee number. Here is the first exchange step of the Display Basic task:


VALIDATE_EMPLOYEE: 
  EXCHANGE 
    TRANSCEIVE FORM RECORD DISPLAY_NUMBER_FORM_REC, 
                           DISPLAY_NUMBER_FORM_REC_LIS 
      SENDING DISPLAY_USER_WKSP 
      RECEIVING DISPLAY_USER_WKSP, QUIT_CTRL_WKSP; 
    CONTROL FIELD QUIT_CTRL_WKSP.QUIT_KEY 
      "QUIT"  :  EXIT TASK; 
    END CONTROL FIELD; 

This exchange step displays the current employee number, and lets the terminal user change the employee number to see information about a different employee. The processing step then uses the DISPLAY_BASIC_GET procedure to retrieve records for the employee whose number is in DISPLAY_USER_WKSP.

Example 4-9 shows the complete definition for the Display Basic task using a user workspace.

Example 4-9 Definition for Display Basic Task with User Workspace

REPLACE TASK DISPLAY_BASIC 
  USE WORKSPACES 
    ADMIN_WORKSPACE, 
    DISPLAY_USER_WKSP WITH ACCESS UPDATE, 
    HIST_RECORD, PERS_RECORD; 
  DEFAULT SERVER IS ADMINISTRATION_SERVER; 
  DEFAULT FORM IS DISPLAY_BASIC_FORM; 
  BLOCK 
    WORK WITH NO SERVER CONTEXT FORM I/O 
    VALIDATE_EMPLOYEE: 
      EXCHANGE 
    TRANSCEIVE FORM RECORD DISPLAY_NUMBER_FORM_REC, 
                           DISPLAY_NUMBER_FORM_REC_LIS 
      SENDING DISPLAY_USER_WKSP 
      RECEIVING DISPLAY_USER_WKSP, QUIT_CTRL_WKSP; 
    ACTION IS 
      CONTROL FIELD QUIT_CTRL_WKSP.QUIT_KEY 
        "QUIT"  :  EXIT TASK; 
      END CONTROL FIELD; 
 
      PROCESSING 
        CALL DISPLAY_BASIC_GET 
          USING ADMIN_WORKSPACE, DISPLAY_USER_WKSP, 
                HIST_RECORD, PERS_RECORD; 
        CONTROL FIELD ACMS$T_STATUS_TYPE 
          "G"        : GOTO NEXT STEP; 
          "B"        : GET ERROR MESSAGE; 
                       GOTO PREVIOUS EXCHANGE; 
        END CONTROL FIELD; 
    DISPLAY_BASIC_DATA: 
      EXCHANGE 
        TRANSCEIVE FORM RECORD DISPLAY_BASIC_FORM_REC, QUIT_CTRL_FORM_REC 
          SENDING ADMIN_WORKSPACE 
          RECEIVING QUIT_CTRL_WKSP; 
      ACTION IS 
        CONTROL FIELD QUIT_CTRL_WKSP.QUIT_KEY 
          "QUIT"  :  EXIT TASK; 
        END CONTROL FIELD; 
    END BLOCK WORK; 
    ACTION 
      REPEAT STEP; 
END DEFINITION; 

You can test the contents of the user workspace, just as you would the contents of a group workspace. For example, in the Display Basic task, you can test the contents of the workspace in the initial exchange step. If the workspace is empty, you can use a form to display a panel asking for an employee number.

In the final steps of the task, you can use function keys to let the user clear or save the contents of the user workspace. To test the EMP_NUMBER field, you must be careful to redefine it as a text field, or you get a "datatype mismatch" error when you build the task group. If you change the data type of EMP_NUMBER to text, the procedure must then convert that information to a numeric datatype before moving the key to the personnel record.

You might want to let the user:

The following example shows the final exchange steps:


DISPLAY_BASIC_DATA: 
  EXCHANGE 
        TRANSCEIVE FORM RECORD DISPLAY_BASIC_FORM_REC, 
                               QUIT_CTRL_FORM_REC 
          SENDING ADMIN_WORKSPACE 
          RECEIVING QUIT_CTRL_WKSP; 
        CONTROL FIELD  QUIT_CTRL_WKSP.CTRL_KEY 
          "NEXT"   :  GOTO NEXT STEP; 
          "QUIT"   :  EXIT TASK; 
          "REPET"   :  EXIT BLOCK; 
          NOMATCH   :  GOTO NEXT STEP; 
        END CONTROL FIELD; 
  EXCHANGE 
        RECEIVE FORM RECORD CLEAR_WKSP_FORM_REC_LIS 
          RECEIVING DISPLAY_USER_WKSP, QUIT_CTRL_WKSP; 
        CONTROL FIELD  QUIT_CTRL_WKSP.CTRL_KEY 
          "QUIT"   :  EXIT TASK; 
          NOMATCH   :  EXIT BLOCK; 
        END CONTROL FIELD; 
ACTION 
  REPEAT TASK; 

In the first of these exchange steps, the user presses either one of three function keys or [Return].

To return to the menu and discard the current employee number, the user presses GOLD-E, which returns the value "NEXT" to the CTRL_KEY field. The CLEAR_WKSP_FORM_REC in the final exchange step clears the employee number from DISPLAY_USER_WKSP.

To return to the menu and keep the same employee number, the user presses GOLD-D, which returns the value "QUIT" to the CTRL_KEY field. ACMS exits the task and returns the user to the menu, but ACMS does not clear the employee number from DISPLAY_USER_WKSP.

To repeat the task by using the same employee number, the user presses GOLD-R, which returns the value "REPET" to the CTRL_KEY field. ACMS processes the block action, REPEAT STEP, without clearing the employee number from DISPLAY_USER_WKSP.

To repeat the task with a new employee number, the user presses [Return]. The CLEAR_WKSP_FORM_REC clears the employee number from DISPLAY_USER_WKSP, and ACMS processes the block action REPEAT STEP.

Keeping a value such as an employee number in a user workspace when a task instance is finished lets you write other task definitions that can use that value.

4.6 Moving Data to a Workspace Field

One method of moving data into a workspace field is by using the ADU MOVE clause. The MOVE clause specifies that ADU moves one of the following elements into a workspace field:

Note

ACMS does not let you pass arrays to workspace fields.

Example 4-10 demonstrates the use of the MOVE clause.

Example 4-10 Moving Data to a Workspace Field

SET VERIFY 
REPLACE TASK TASK01 
WORKSPACES ARE 
  WKSP_1, WKSP_2; 
PROCESSING IS 
 CALL NULL_TRANSACTION   IN TEST_SERVER 
  USING WKSP_1; 
 MOVE   RMS$_EOF INTO WKSP_1.L_MESSAGE, 
        -2 INTO WKSP_1.L_NUMBER, 
        "GOOD"   INTO  ( WKSP_1.T_TEXT,WKSP_1.T_STRING ), 
        WKSP_2.V_BASIC   INTO WKSP_1.V_EMPL ; 
END DEFINITION; 
 
BUILD GROUP  TEST_GROUP /SYSSHR - 
                        /SYSLIB 

Example 4-10 uses the MOVE clause to move information from various sources to fields in the workspace called WKSP_1. The workspace fields in this example receive data in the following form:

The following restrictions apply to MOVE clauses:

You can also use the MOVE clause in CONTROL FIELD and SELECT FIRST clauses. For example:


SELECT FIRST TRUE 
     (WK_VALUE EQL 1): MOVE 2 TO NUMBER; 
     (WK_VALUE EQL 2): MOVE 3 TO NUMBER; 

4.7 Passing Data with User-Written Agents

Another method of passing information to an ACMS task is by using a Systems Interface (SI) agent or another task. An SI agent can call an ACMS task and optionally pass workspaces to that task for read, write, or modify purposes. The called task can return the modified workspace back to the agent at the end of the task instance. The agent can then use the contents of this workspace in subsequent task executions. The agent passes workspaces in an argument list on either the ACMS$CALL or ACMS$START_CALL services. The agent can pass task workspaces only.

See Compaq ACMS for OpenVMS Systems Interface Programming for information about passing arguments from an SI agent to an ACMS task.

4.8 Using External Global Symbols in Task Definitions

Task definitions can reference external global symbols in place of a workspace field reference in the following instances (RMS$_EOF and RMS$_OK_DUP represent external global symbols):

Global symbols have a signed longword data type.

ACMS resolves global symbols during BUILD GROUP processing, where ADU searches for a matching workspace field reference. If it does not find a matching reference, ADU then searches the object modules and libraries that you specified on the BUILD GROUP command line with the /SYSLIB, /SYSSHR, /OBJECT, and /USERLIBRARY qualifiers and takes the following actions:

ADU does not use the MESSAGE FILES ARE clause to resolve global symbols at build time.


Chapter 5
Using the Task-Call-Task Feature

In processing steps, you can call another task in the same task group, instead of calling a procedure in a server. This capability is called the task-call-task feature.

Task calling extends the capabilities of an ACMS task definition. Applications of the task-call-task feature include:

See Compaq ACMS for OpenVMS Concepts and Design Guidelines for further information on these applications of the task-call-task feature.

5.1 Calling Another Task

The task-call-task feature is based on the subroutine call-and-return model. You call another task in basically the same way that you make a subroutine call to a server procedure. Control passes to the task you call (along with whatever workspaces you name as parameters) and then returns to the place from which you made the call.

A calling task is referred to in this section as a parent task. A called task can become a parent task if it calls another task in turn.

A called task can return a status value to a parent task similarly to the way a routine in a procedure server can return a status value to a task. A parent task can use this value, or the contents of a task workspace field modified by the called task, to control subsequent task execution.

You must pay particular attention to the rules for passing workspaces. See Section 5.1.3 for further information on passing workspaces in task calling.

There is no limit to the number of task calls you can make other than that imposed by the maximum number of task instances specified in the application definition, and resource limits such as the task workspace pool and virtual memory inside the Application Execution Controller (EXC) process.

5.1.1 Defining a Task Call

To create a task call, you specify a task name instead of a server procedure. For example:


REPLACE TASK ENTER_ORDER 
   .
   .
   .
  PROCESSING 
    CALL TASK ORDER_LINES USING 
      CUSTOMER_INFO_RECORD, 
      CUSTOMER_ACCOUNT_RECORD, 
      ORDER_DATA_RECORD; 
   .
   .
   .

In this example, the processing step calls the ORDER_LINES task, passing the CUSTOMER_INFO_RECORD, CUSTOMER_ACCOUNT_RECORD, and ORDER_DATA_RECORD workspaces. The task name specified in a CALL TASK clause must be a group task name, not an application task name.

You must also specify the workspaces that the called task will receive as arguments.


REPLACE TASK ORDER_LINES 
 
WORKSPACES ARE 
    CUSTOMER_INFO_RECORD, 
    CUSTOMER_ACCOUNT_RECORD, 
    ORDER_DATA_RECORD, 
    TASK_CONTROL_RECORD; 
 
TASK ARGUMENTS ARE 
    CUSTOMER_INFO_RECORD WITH ACCESS READ, 
    CUSTOMER_ACCOUNT_RECORD WITH ACCESS MODIFY, 
    ORDER_DATA_RECORD WITH ACCESS WRITE; 
   .
   .
   .

The ENTER_ORDER task controls the entry of general information about the order (such as customer name and address, shipping address, type of order, sales representative, and so on) and then passes control to the ORDER_LINES task. The ORDER_LINES task receives customer information in the CUSTOMER_INFO_RECORD, updates the customer's accounts information in the CUSTOMER_ACCOUNT_RECORD, and returns line totals in the ORDER_DATA_RECORD.

Workspaces you use as task call arguments must be defined as task workspaces (the default) in the called task. Workspaces received by the called task must be listed in the TASK ARGUMENTS statement in the order in which the calling task passes them. You can specify MODIFY, READ, or WRITE access to those workspaces for the calling task. Use MODIFY to pass and return data, READ to pass data only, and WRITE to return data only.

You must be careful not to unintentionally overwrite data when accessing group and user workspaces from both the parent task and the called task. See Section 5.1.3 for further information on using workspaces.

5.1.2 Task Call Example

This section presents a complete example of how to use the task calling feature. The example shows a simple order-entry transaction. The example is limited to ACMS task definition syntax, with one exception: a BASIC program the order-detail task uses.

Example 5-1 shows the ACMS task definition syntax that defines the order-header portion of the order-entry transaction.

Example 5-1 Task ENTER_ORDER

REPLACE TASK ENTER_ORDER 
 
WORKSPACES ARE          
    HEADER_DATA_WSP, 
    MSG_WKSP, 
    ORDER_DATA_RECORD, 
    TASK_CTL_WSP; 
 
DEFAULT SERVER IS ORDER_SERVER; 
DEFAULT FORM IS ORDER_FORM; 
GLOBAL; 
 
BLOCK WORK WITH FORM I/O 
 
    EXCHANGE 
        RECEIVE FORM RECORD HEADER_DATA_FORM_REC_LIS 
          RECEIVING HEADER_DATA_WSP, TASK_CTL_WSP; 
        ACTION IS 
          CONTROL FIELD TASK_CTL_WSP.TASK_CTL_FIELD 
          "QUIT"  :  EXIT TASK; 
          END CONTROL FIELD;  
 
    PROCESSING 
        CALL WRITE_ORDER_HEADER_DATA USING HEADER_DATA_WSP; 
 
DO_ORDER_LINE: 
    PROCESSING 
        CALL TASK PROCESS_ORDER_LINE USING 
            ORDER_DATA_RECORD, 
            TASK_CTL_WSP, MSG_WKSP; 
        ACTION IS 
          CONTROL FIELD TASK_CTL_WSP.TASK_CTL_FIELD 
          "QUIT"  :  MOVE "Order completed successfully" TO 
                      MSG_WKSP.MESSAGE_PANEL; 
                      GOTO STEP END_ORDER; 
          END CONTROL FIELD;  
 
    PROCESSING 
        CALL INCREMENT_ORDER_TOTALS USING 
            ORDER_DATA_RECORD, 
            HEADER_DATA_WSP; 
        ACTION IS 
          GOTO STEP DO_ORDER_LINE; 
 
END_ORDER: 
    EXCHANGE 
        SEND FORM RECORD MSG_WKSP_FORM_REC 
          SENDING MSG_WKSP; 
 
END BLOCK WORK; 

The first exchange step in Example 5-1 displays the order entry panel and uses the HEADER_DATA_WSP to store the data the user types in. If the TASK_CTL_FIELD contains the word "QUIT" (which the user can place there by using a DECforms-defined function key), the task exits. Otherwise, the first processing step calls a server procedure to write the contents of HEADER_DATA_WSP to a file.

The second processing step calls the PROCESS_ORDER_LINE task, passing the ORDER_DATA_RECORD and TASK_CTL_WSP workspaces. Control passes from this point in the task definition to the PROCESS_ORDER_LINE task (see Example 5-2).

When control returns to the ENTER_ORDER task, the TASK_CTL_FIELD is again checked for the word "QUIT". If the user did not press the QUIT function key, the third processing step in the ENTER_ORDER task increments the order totals and passes control back to the DO_ORDER_LINE step, which calls the PROCESS_ORDER_LINE task to input the next line of the order.

This sequence continues until the user presses the QUIT function key and control passes to the second, and final, exchange step.

Note

Whenever the user presses the QUIT key, all tests for the word "QUIT" in both task definitions evaluate to TRUE. This is because the PROCESS_ORDER_LINE task accepts the TASK_CTL_WSP workspace using WRITE access; when control returns to the ENTER_ORDER task, ACMS writes the contents of that workspace into the parent task's workspace.

Example 5-2 shows the ACMS task definition syntax for the order-detail portion of the order-entry transaction.

Example 5-2 Task PROCESS_ORDER_LINE

REPLACE TASK PROCESS_ORDER_LINE 
 
WORKSPACES ARE 
    DATA_RECORD, 
    MSG_WKSP, 
    ORDER_DATA_RECORD, 
    TASK_CTL_WSP; 
 
DEFAULT SERVER ORDER_SERVER; 
DEFAULT FORM ORDER_FORM; 
 
LOCAL; 
 
TASK ARGUMENTS ARE 
    ORDER_DATA_RECORD WITH ACCESS MODIFY, 
    TASK_CTL_WSP WITH ACCESS WRITE; 
    MSG_WKSP WITH ACCESS WRITE; 
BLOCK WORK WITH FORM I/O 
 
    EXCHANGE 
        RECEIVE FORM RECORD INPUT_DATA_FORM_REC_LIS 
          RECEIVING DATA_RECORD, TASK_CTL_WSP; 
        ACTION IS 
            CONTROL FIELD TASK_CTL_WSP.TASK_CTL_FIELD 
            "QUIT"  :  EXIT TASK; 
            END CONTROL FIELD; 
 
    PROCESSING 
        CALL WRITE_ORDER_LINE USING 
            DATA_RECORD, 
            ORDER_DATA_RECORD, 
            TASK_CTL_WSP; 
        ACTION IS 
            SELECT FIRST TRUE 
            ( TASK_CTL_FIELD = "DUPL" ): GOTO PREVIOUS EXCHANGE; 
            NOMATCH  : MOVE "Order line record successfully 
                       added to database" TO MSG_WKSP.MESSAGE_PANEL; 
            END SELECT; 
 
    EXCHANGE 
        SEND FORM RECORD MSG_WKSP_FORM_REC 
          SENDING MSG_WKSP; 
        ACTION IS 
            EXIT TASK; 
 
END BLOCK WORK; 

The PROCESS_ORDER_LINE task is a LOCAL task, which means that it can be called only from another task. It cannot be initiated by using a menu selection. You assign the LOCAL attribute in the application definition.

The TASK ARGUMENTS clause lists the workspaces the PROCESS_ORDER_LINE task can receive when called from another task. ORDER_DATA_RECORD is defined as a modify-access workspace; that is, any data written to it by the PROCESS_ORDER_LINE task can be modified, and is returned to the calling task. TASK_CTL_WSP and MSG_WKSP are defined as write-only workspaces; that is, no data are passed into them from the calling task, but any data written to them by the PROCESS_ORDER_LINE task is returned to the calling task. This way of passing workspaces is more efficient than using MODIFY (or read-write) access.

The PROCESS_ORDER_LINE task calls a DECforms form to display the order-lines panel and accept data that the user types in. After accepting data from the user, the task calls the WRITE_ORDER_LINE procedure (see Example 5-3) by using data from the order header as well as data from the order line.

The WRITE_ORDER_LINE procedure checks for a duplicate key value and returns to the first exchange step if it finds one. If the order line is written successfully to the file, a second exchange step writes a success message, the task exits, and control returns to the ENTER_ORDER task.

When the user presses the QUIT key, the task exits, and control returns immediately to the ENTER_ORDER task, without calling the server procedure or the second exchange step.

Example 5-3 shows the BASIC program that writes the order-line information to a file.

Example 5-3 Procedure WRITE_ORDER_LINE (in BASIC)

10 SUB WRITE_ORDER_LINE( DATA_RECORD DATA_REC,            & 
                         ORDER_DATA_RECORD ORD_VALUE_REC, & 
                         TASK_CTL_WSP TASK_CTL ) 
   %INCLUDE %FROM %CDD "DATA_RECORD" 
   %INCLUDE %FROM %CDD "ORD_VALUE_REC" 
   %INCLUDE %FROM %CDD "TASK_CTL_WSP" 
   MAP (DATA_FILE) DATA_RECORD FILE_REC 
 
   FILE_REC = DATA_REC             ! Transfer data to file buffer 
   ON ERROR GOTO 20                ! Set up an error trap 
   PUT #1%                         ! Store the data 
   ORD_VALUE_REC::ORD_LINE_TOTAL = DATA_REC::PRICE * DATA_REC::QTY 
                                   ! Calculate order line total 
   TASK_CTL::TASK_CTL_FIELD = "OK" ! It all worked so return success 
   EXIT SUB                        ! And exit 
 
20 IF ERR = 134% THEN              ! If duplicate key detected then 
     TASK_CTL::TASK_CTL_FIELD = "DUPL" ! Return failure indicator 
     RESUME 99                     !     And exit 
 
   ELSE                            ! Otherwise 
     CALL ACMSAD$REQ_CANCEL        !     Something serious occurred 
   END IF                          !     so cancel the task. 
 
99 END SUB 

The procedure shown in Example 5-3 moves the data from the workspace to the file buffer and then writes a record to the file. If the write operation succeeds, the procedure returns a success code in a task control workspace. If it detects a duplicate key, which indicates that a duplicate item exists in the same order, the procedure returns a failure code to the task. Any other error causes the procedure to cancel the task.

If there are any unexpected errors (such as a device-full RMS error) or the server process terminates unexpectedly while the WRITE_ORDER_LINE procedure is running, ACMS automatically cancels the PROCESS_ORDER_LINE task. When a called task is canceled, ACMS by default also cancels the parent task.

In this example, ACMS automatically cancels the ENTER_ORDER task under the following conditions:

The ENTER_ORDER task does not need to check the status from the call to the PROCESS_ORDER_LINE task to determine whether the task has failed. The ENTER_ORDER task does not expect the called task to return anything other than a success status and uses the contents of the TASK_CTL_FIELD workspace field to control task execution. If the PROCESS_ORDER_LINE task fails, the ENTER_ORDER task expects to be canceled. For example, the ENTER_ORDER task expects to be canceled if:

When a called task is canceled, by default the calling task also is canceled. For information on how to override this default so that ACMS does not automatically cancel the calling task when the called task is canceled, see Chapter 8.


Previous Next Contents Index