Release 10.1A: OpenEdge Application Server:
Developing AppServer Applications

> ## 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. OpenEdge 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. OpenEdge processes the event like any other Progress 4GL event. You also 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, OpenEdge:

> - Decrements the `ASYNC-REQUEST-COUNT` attribute on the following handles:

> - The server handle contained in the `SERVER` attribute of the asynchronous request handle.
> - The procedure handle contained in the `PERSISTENT-PROCEDURE` attribute of the asynchronous request handle, if the `PERSISTENT-PROCEDURE` attribute refers to a valid persistent procedure.
> - Sets the `COMPLETE` attribute for the asynchronous request handle to `TRUE`.

> - Sets the `STOP`, `QUIT`, or `ERROR` attribute for the asynchronous request handle appropriately as indicated by the response message from the AppServer, and stores any error information returned from the AppServer for the request in the `ERROR-STATUS` system handle.

> - Sets the return value for the `RETURN-VALUE` function, if a return value was returned by the AppServer.

> - Attempts to execute the event procedure specified by the `EVENT-PROCEDURE` and the `EVENT-PROCEDURE-CONTEXT` attributes for the asynchronous request handle, if `EVENT-PROCEDURE` is not the empty string (`""`), and:

> - Sets each `INPUT` parameter for the event procedure to the Unknown value (`?`) or, if the parameter is a `TEMP-TABLE` parameter, the temp-table remains unchanged, if the response message indicates that the remote request finished with a `STOP`, `ERROR`, or `QUIT` condition.
> - Sets the `INPUT` parameter values for the event procedure to the `OUTPUT` and `INPUT-OUTPUT` parameter values returned by the remote procedure, if the response message indicates that the remote request completed successfully.
> - Displays an error message, if a specified event procedure fails to execute for any reason.

> ##### 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:

> - Specify the name of the event procedure using the `EVENT-PROCEDURE` option on the `RUN...ASYNCHRONOUS` statement that executes the request.

> - Define an internal procedure with the same name as the event procedure specified in the `RUN...ASYNCHRONOUS` statement.

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

> - The same procedure context as the `RUN...ASYNCHRONOUS` statement that specifies the event procedure.

> - An external procedure context that you specify using the `EVENT-PROCEDURE` option on the `RUN...ASYNCHRONOUS` statement using its procedure handle. In this case, the external procedure context must be active in the client session before you execute the `RUN...ASYNCHRONOUS` statement.

> 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:

> - The asynchronous request handle for the request using the `SELF` system handle.

> - The attributes and methods of the `ERROR-STATUS` system handle to obtain error information from the request.

> - Values passed as output parameters from the remote procedure to corresponding input parameters in the event procedure.

> - The `RETURN-VALUE` function to get the return value from the request.

> ##### 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:

> - `ERROR` attribute indicates if the request completed with an `ERROR` condition.

> - `STOP` attribute indicates if the request completed with a `STOP` condition.

> - `QUIT` attribute indicates if the request completed with a `QUIT` condition.

> 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, OpenEdge 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, as shown:

>     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`, OpenEdge 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 © 2005 Progress Software Corporation www.progress.com Voice: (781) 280-4000 Fax: (781) 280-4095