Building Distributed
Applications
Using the Progress AppServer


Handling the Response from an Asynchronous Request

When an asynchronous request completes execution, it sends a response to the AppServer client, which places it on the response queue for the appropriate server handle. To signify that the response is ready to be processed, the PROCEDURE-COMPLETE event is placed on the event queue where it can be processed in the context of blocking I/O statements, such as WAIT-FOR or the PROCESS EVENTS statement.

PROCEDURE-COMPLETE Events

The PROCEDURE-COMPLETE event is an event on the asynchronous request handle. It indicates that the asynchronous request associated with the handle has completed execution, and that the corresponding event procedure can be executed. Progress executes the event procedure in the context of a blocking I/O statement much like it executes the trigger for a user-interface event.

Note that you do not have to specify the PROCEDURE-COMPLETE event explicitly in your client code. Progress processes the event like any other 4GL event. However, you do not have to define a trigger for the event (for example, using an ON statement) because you specify an event procedure in the RUN...ASYNCHRONOUS statement that defines the “trigger code” for the event.

To process a PROCEDURE-COMPLETE event for a particular asynchronous request handle, Progress:

Event Procedures

To handle the response from an asynchronous request, you must define an event procedure. In this context, an event procedure is an internal procedure that executes in response to a PROCEDURE-COMPLETE event. To define an event procedure you must:

Typical places where you might define the specified internal procedure include:

You must define the specified internal procedure with INPUT parameters that correspond in type and order to the OUTPUT and INPUT-OUTPUT parameters that you specify on the RUN...ASYNCHRONOUS statement.

To receive results from the asynchronous request in an event procedure, you can access:

Obtaining Error Information

With an asynchronous remote procedure request, the RUN...ASYNCHRONOUS statement returns once the client request has been validated. Any errors that occur while processing the RUN...ASYNCHRONOUS statement are returned as a STOP or ERROR condition in the context of the RUN...ASYNCHRONOUS statement. Information on errors that occur once the asynchronous request has been submitted can be obtained by using the ERROR-STATUS system handle within the event procedure for the asynchronous request.

If the asynchronous request completes with a condition, you can use attributes on the asynchronous request handle to determine the condition that the request completed with, as follows:

Note that any asynchronous request that raises the STOP condition (by executing the STOP statement), and does not handle the condition itself, also sets the STOP attribute of its corresponding asynchronous request handle to TRUE.

If any errors occur when the event procedure attempts to execute, Progress displays an error message in the context of the blocking I/O statement, and no information is stored in the asynchronous request handle. Errors where this might occur include, for example, an event procedure whose INPUT parameters do not match in order and type with the output parameters from the remote request.

Obtaining Parameter Values

As explained earlier, the values returned for OUTPUT or INPUT-OUTPUT parameters on an asynchronous remote procedure are not returned to the RUN statement as for a synchronous remote procedure. Instead, they are returned in the corresponding INPUT parameters of the specified event procedure.

Note that INPUT parameters in an event procedure observe the same rules of definition and scoping as any internal procedure:

DEFINE TEMP-TABLE order-table ...
DEFINE VARIABLE icount AS INTEGER INITIAL 0.
DEFINE VARIABLE hAsync AS HANDLE.
DEFINE BUTTON bCheckOrders. ...

CREATE SERVER hAppSrv.
hAppSrv:CONNECT().

RUN order.p
  ON SERVER hAppSrv ASYNCHRONOUS SET hAsync
  EVENT-PROCEDURE GetOrderRecords IN THIS-PROCEDURE
  (INPUT-OUTPUT TABLE order-table, OUTPUT icount).
DISPLAY icount. /* Displays 0 */
ON CHOOSE OF bCheckOrders
  IF icount > 0
  THEN MESSAGE "You have" icount "orders." VIEW-AS ALERT-BOX
  ELSE MESSAGE "Orders are pending ..." VIEW-AS ALERT-BOX.
                   .
                   .
                   .
WAIT-FOR WINDOW-CLOSE OF CURRENT-WINDOW.

PROCEDURE GetOrderRecords:
  DEFINE INPUT PARAMETER TABLE FOR order-table.
  DEFINE INPUT PARAMETER order-count AS INTEGER.
  IF SELF:ERROR OR SELF:STOP THEN ... /* Handle condition */
  ELSE icount = order-count.
  RETURN.
END. 

Thus, in this example, the order-table TEMP-TABLE (defined in the outer block) receives its content directly from the order-table INPUT parameter of the GetOrderRecords event procedure. However, you must explicitly assign the icount variable (defined in the outer block) to the order-count parameter in order to make the parameter value available to the outer block. (That is, if you define the INPUT parameter as icount instead of order-count, Progress does not automatically make the parameter value available as icount in the outer block. Only the TABLE parameter is scoped to the outer block and thus receives its value from the parameter.)

Note also that the event procedure checks for and handles any unhandled conditions generated from the execution of order.p using AppServer error-handling mechanisms.

Obtaining the Return Value

You can obtain the return value for a remote procedure that you call asynchronously by invoking the RETURN-VALUE function within the event procedure that handles the asynchronous request. This function thus returns the value specified by a corresponding RETURN statement executed in the remote procedure. As for a synchronous request, if the remote procedure returns no value in the RETURN statement, the RETURN-VALUE function returns the empty string ("").


Copyright © 2004 Progress Software Corporation
www.progress.com
Voice: (781) 280-4000
Fax: (781) 280-4095