UI program and the gateway service
- The UI program is an EGL main program that contains
your business logic. The logic might be controlled in a detailed way
by the requester, with the program providing specific sets of data
in response to each request. The logic also might control the conversation
to a greater extent, with the requester initiating a sequence of events.
For example, the program might submit data for presentation in an
on-screen form, might wait for the form input, and might use the input
to determine what form data to send next. The program is stereotyped as UIProgram, as shown in the following outline of requester-controlled logic:
program MyUIProgram type UIProgram {inputUIRecord = myInitialContainer} // the Record parts for the following two declarations are shown // in a later description of the "gateway record" data property myInitialContainer InitialContainer; myRepeatedContainer RepeatedContainer; endCondition Boolean = false; start, end Int; myDataArray MySQLRecord[]; function main() while (endCondition == false) // The logic retrieves data (not shown) // and determines what portion to send. for (i int from start to end) myRepeatedContainer.sendList[i] = myDataArray[n]; n = n + 1; end // no explicit JSON conversion is required here. converse myRepeatedContainer; // set endCondition in response to an input value end end endIn this case the while loop ends when the program sets the end condition in response to a particular value from the requester. In an alternative case, the while loop ends when the requester invokes ServiceLib.endStatefulServiceSession. That second option is not recommended, particularly in the following case: the requester of the gateway service is a Rich UI application, and the EGL Rich UI proxy is in the same session as the UI program. In that case, ending the UI program by invoking the ServiceLib.endStatefulServiceSession function also ends the Rich UI application's ability to access services.
Here is an outline of a second UI program, which controls the conversation with the requester:program MyOtherUIProgram type UIProgram {} const MENU_FORM int = 0; const FORM_ONE int = 1; const FORM_TWO int = 2; // the Record parts are not shown myMenuContainer MenuContainer; // holds an integer: a menu choice myFormOneContainer FormOneContainer; // holds data for form 1, with the form ID myFormTwoContainer FormTwoContainer; // holds data for form 2, with the form ID endCondition Boolean = false; formNumber Int = MENU_FORM; function main() while (endCondition == false) case (formNumber) when (MENU_FORM) converse myMENUContainer; // process in some way and set formNumber when (FORM_ONE) converse myFormOneContainer; // process in some way and set formNumber when (FORM_TWO) converse myFormTwoContainer; // process in some way endCondition = true; otherwise // throw an exception end end end end - The UI gateway service is a service that invokes
the UI program and that transfers data between a requester and that
program. You do not write the logic for this service, which is predefined
and has a single entry point named invokeProgram.You can deploy the UI gateway service as an EGL REST-RPC service, a stateless SOAP service, or both:
- An EGL REST-RPC service can remain in the application-server session to monitor a conversation between the requester and the UI program. This capability is necessary if you want to code the EGL converse statement in the UI program.
- A SOAP service might fit better with your corporate processes. You distribute details about service access by making available an EGL-generated WSDL file.
When you work with the EGL Deployment Descriptor editor to deploy the UI gateway service as a Web service, a deployment-descriptor entry is made available to you as if you had coded the service. To deploy a stateful EGL REST-RPC service, you can specify that the service is stateful in the Service Deployment tag of that editor.
- A converse statement, which causes the program to wait for a subsequent input from the same requester
- A show statement, which ends the program. A show statement can cause a deferred transfer, in which case a subsequent request from the requester to the UI gateway service initiates a second UI program.
- A call statement, which transfers control synchronously to a called program
- A transfer statement, which initiates another main program and ends the processing of the transferring program
A complete UI program example is available to you in End-to-end processing with a UI program and a data grid.
Gateway record
As noted in the next section, the requester passes and receives business data in JSON format, and the JSON string is embedded in a field of a record that is of type UIGatewayRecord. In general, you handle a record of this type when you code a requester but not when you code a UI program.
Record UIGatewayRecord
uiProgramName STRING;
data STRING;
dataEncoding EncodingKind;
terminated Boolean;
end- uiProgramName
- A string that represents the fully qualified name of the UI program
to invoke. For example, if a UI program in the
myPkgpackage is namedTranslateand if the gateway record is namedgateRec, the following assignment is valid:gateRec.uiProgramName = "myPkg.Translate";When the service responds to the requester, the service ensures that the field value represents the next EGL part to invoke, if any. Again, you typically do not update the gateway record explicitly in the UI program.
- data
- A string that contains the business data in JSON format. The requester
uses the ServiceLib conversion functions
as appropriate to store or retrieve the JSON string.The business data that is converted to or from JSON is typically a container that includes the content of interest. For example, the following Record part contains an integer:
Record InitialContainer initialValue INT; endThe following Record part contains two integers and an array of SQL records:Record RepeatedContainer numberOfRecords INT; pageNumber INT = 1; sendList theSQLRecord[]{}; end - dataEncoding
- A value that specifies the format of the business data that is sent between the requester and the UI program. This value causes some automatic data conversions. Data is transferred in JSON format, and the only valid value for the dataEncoding field is EncodingKind.JSON.
- terminated
- A Boolean value that indicates if the program is terminated. Do not assign a value to the terminated field. That field is set automatically by the UI program. The requester can read the field to guide subsequent processing.
Behavior of the requester
- Declares a service-access variable of type UIGatewayService:
gatewayServiceVar UIGatewayService{@BindService{bindingKey="UIGatewayService"}};TheUIGatewayServicebinding in the EGL deployment descriptor has a base URL entry similar to this:http://localhost:8080/MyWebProject/restservices/uiGatewayService - Declares a UI gateway record, which is a record of type UIGatewayRecord:
gateRec UIGatewayRecord; - Uses the ServiceLib.convertToJSON function
to convert business data into a JSON string, which is placed in the data field
of the UI gateway record. For example, if
sendToProgramis an EGL record that you are sending to the UI program, code the following statement:gatewayRec.data = ServiceLib.convertToJSON( sendToProgram );The string reflects the content that is intended for the UI program.
- Includes a service-access statement that passes the UI gateway
record. The invocation is asynchronous if it occurs in Rich UI and
is synchronous if it occurs outside of Rich UI. Here is an example
service-access statement for Rich UI:
call gatewayServiceVar.invokeProgram(gateRec) returning to callbackFunc onException handleException;The signature of the invokeProgram function of the UI gateway service is as follows:function invokeProgram(gatewayRecord UIGatewayRecord INOUT); - Uses a record of type UIGatewayRecord to receive the data that
is returned from the UI gateway service. Here is the signature of
a callback function in the Rich UI handler:
function callbackFunc(gatewayRecord UIGatewayRecord in)For the requester that is responding to a UI program converse statement, the structure of the data field content in the received gateway record must be equivalent to the structure of the data field content sent back to the UI program. Only the content of the data can vary.
The data sent to the UI program includes the fully qualified name of the EGL part to invoke; that is, the data includes the package name and part name. If the part has an alias, the alias is used in place of the part name. The part might be another UI program or might be an EGL library.
- Uses the ServiceLib.convertFromJSON function
to convert the data received from the UI program and to place the
converted data into an EGL variable. For example, if
dataRecordis an EGL record that has a structure that matches the structure of the data that is expected from the UI program, the following statement might be in the Rich UI callback function:ServiceLib.convertFromJSON( gatewayRecord.data, dataRecord); - If the UI gateway service is a stateful EGL REST-RPC service,
the requester can invoke ServiceLib.endStatefulServiceSession to
end the program. In this case, if the requester is a Rich UI application,
the user must download the application in the browser again before
the application can restart the UI program.Note that ending the session might result in an error message, which is displayed by the application server that runs the UI program. Here is an example:
EGL2156E The session associated with program MyUIProgram was invalidated.
The requester uses JSON conversion functions, but the UI program typically does not.
Behavior of the UI program
- Can receive data in one of two ways:
- If the invocation is directly from the requester, the data from
the requester is placed into the record that is identified in the inputUIRecord property.
The record must be a basic, non-structured record. The record is not
a gateway record.
Receipt of data into the record does not involve a JSON conversion function. The conversion is handled for you.
- If the invocation is a transfer from another program, the data from the transferring program is placed in the record that is identified in the inputRecord property. The record must be a basic record, which can be structured or non-structured. The record is not a gateway record.
- If the invocation is directly from the requester, the data from
the requester is placed into the record that is identified in the inputUIRecord property.
The record must be a basic, non-structured record. The record is not
a gateway record.
- Can return data to the requester in one of the following ways:
- By invoking a show statement. The I/O
object in the show statement must be non-structured
and can be a basic or SQL record. The statement can be in a library
function.
A show statement is valid in a library only when the library is invoked from a UI program.
- By returning control directly; that is, by ending without running the show statement and without transferring control to another program.
- By invoking a converse statement; but
only if the UI gateway service is deployed as an EGL REST-RPC service.
The I/O object in the converse statement
must be non-structured and can be a basic or SQL record. The statement
can be in a library function, but a converse statement
is valid in a library only when the library is invoked from a UI program.
The data sent by a particular converse statement must be structured like the data received by that statement.
If the UI program returns control to the requester, the requester receives the UI gateway record, and the following statements apply:- After the UI program invokes a show or converse statement, the data field of the UI gateway record holds the JSON equivalent of the business data.
- The programName field of the UI gateway
record is set to an empty string in the following cases:
- The UI program ended by returning control directly.
- The UI program ended by a show statement that did not involve a deferred transfer.
- The terminated field of the UI gateway
record is set to true in the following cases:
- The UI program ended by returning control directly.
- The UI program ended by a show statement.
The show and converse statements do not use a JSON conversion function. The required conversions are handled for you, including the conversion that occurs after the converse statement, when the requester re-invokes the program and causes the program to process the statement that follows the converse statement.
- By invoking a show statement. The I/O
object in the show statement must be non-structured
and can be a basic or SQL record. The statement can be in a library
function.
- alias
- An optional string that identifies the program. If this string is specified, the requester must use it in place of the program name.
- inputRecord
- A record that receives data from a transferring program, as noted earlier.
- inputUIRecord
- A record that receives data from the UI gateway service, as noted earlier.
- segmented
- A Boolean value that indicates whether the UI program runs in
segmented mode:
- true (the default)
- The program exits after the converse statements
and reloads at the appropriate point after the user responds.
The benefit of accepting the default value is that you free application-server resources during user think time. However, the effect of the program exit might require additional coding because the EGL runtime code closes files and database connections, releases libraries, and resets the value of those EGL system variables that are not saved across a converse statement.
- false
- The program remains in memory while waiting for the response from the requester.
For additional details, see Segmentation in Text UI programs and UI programs.
When you generate the UI program, ensure that the j2ee build descriptor option is set to yes.
- The source of the UI gateway service is not available to you, and the service cannot be debugged.
- You can debug a UI program only if the program is already running on a server.
Exceptions
Record MyException type Exception end
Program MyUIProgram type UIProgram {}
function main()
try
// get an array of data from a relational database
get mySQLRecord;
onException(except AnyException)
throw new MyException{message =
"Error at get mySQLRecord: " + except.message};
end
end
end
If the UI program times out during an ongoing conversation with a requester, the exception is returned the next time that the requester invokes the program.