-
Notifications
You must be signed in to change notification settings - Fork 2
objects
HS objects support methods and events. An event occurs when an incoming EVENT or QUERY message is received, and a method is executed in response to that event. Events are initiated when a remote object calls the event or query method (or generates an appropriate EVENT or QUERY message conforming to the Ab Initio Protocol). A process that responds to incoming event messages is a server object, while a process that sends event messages is a client object.
When a HS object starts up, it has a designated class name, which is typically the username of the process. The objects complete designation is class@node, where node is the name of the computer where the object resides. This class object can act as a client, or as a server for one or more clients. In the case where a server object needs to provide exclusive services to a client, it can create a unique instance of the class object by calling the instantiate method. The object designation thus becomes instance.class@node.
Event messages conform to the Ab Initio Protocol, and contain the following essential elements:
The method arguments provide the mechanism for data exchange; arguments with values are received by the target, while arguments without values are assigned and returned to the sender in a REPLY message.
Server objects respond to event messages. A server object typically performs the following steps:
- Define methods.
- Enable the methods for remote execution.
- Call the idle method and wait for event messages.
Generally, the methods provided by a server object should be well defined so that client objects can invoke the methods with the expected arguments. The methods should also assign values to the arguments which were passed in without values; they will be automatically returned to the sender in a REPLY message.. If the server object needs to be restricted to serving only one client, it should create a unique instance of itself by calling the instantiate_method.
Client objects execute methods on server objects by sending an EVENT or QUERY message. Typically, a HS program does this by calling the event or query method, following these steps:
- Define and initialize variables to send in the message.
- Define handlers for run-time conditions, such as timeout.
- Call event or query.
Variables are needed to specify arguments to the remote method, and to receive data from the target. Variables are passed by reference. Input variables are initialized with values, while return variables must be set to empty. If the query was successful, the REPLY message will return the values of the variables that were requested.
Calling methods and passing arguments between two HS objects is illustrated in this simple example. (For a complete description of all the steps involved in running a simple application, see the HS "Hello World" Application.)
The server object defines and enables a method, GREETING, then calls the idle method to enter the IDLE state. The GREETING method expects two string arguments: "InText", which it prints, and "OutText", which is assigned the value, "Hello from server!". GREETING is called remotely by the client object using the query method, which passes the string, "Hello from client!", and receives the string, "OutText", which it prints.
/**********************************************
* Server
*
* Define and enable the GREETING method.
* Enter the IDLE state and wait for a message.
*/
GREETING()
{
/* Check for the expected number of arguments */
if ( count ( args ) ) != 2 )
return "%ERROR";
/* Check for the arguments, InText and OutText */
if ( args[0] != "InText" || args[1] != "OutText" )
return "%ERROR";
/* OK, print out InText, assign OutText, and return */
put ( InText ) ;
OutText = "Hello from server!";
return;
}
main()
{
/* Enable the GREETING method to be called remotely */
enable ( GREETING ) ;
/* Enter the IDLE state and wait for a message */
idle() ;
}
/* Bootstrap. Start the program. */
main() ;
/**********************************************
* Client
*
* Call the GREETING method in server
*/
/* Define the InText variable to pass as an input argument */
str InText = "Hello from client!";
/* Define the (empty) OutText variable as an output argument */
str OutText = {};
/* Execute the GREETING method on server */
query ( "server", "GREETING", { &InText, "OutText" } );
/* Print the received value of OutText */
put ( OutText );
The output from server is "Hello from client!", and the output from client is "Hello from server!".
Note that we did not have to define OutText, since it would have been done for us when it was returned from the query call. Also note that OutText was passed in quotes, which is a common way to pass tokens for which we expect to receive a result back. Since OutTest was defined and initialized to empty, we could also have made the call like this:
query ( "server", "GREETING", { &InText, &OutText } );
But if we were to make another query call, then OutText would have to be re-initialized to empty.