ContextClient Lambda Overview

 

Introduction

Instances of the contextClient Lambda provide a general purpose connection to AIS Servers. The Lambda allows a context (the "local context") to connect to an AIS server as a remote client reaching the server through the AIS appPort. The AIS appPort is the port used by the AIS Remote IDE (RIDE). Typically, you use a contextClient Lambda instance to establish a connection to an AIS server. Use the connection to logon to the server, open a session on a running context and then execute AMP Lambdas in that context. With appropriate security levels, you may use a contextClient Lambda instance to open and close contexts on an AIS server.

Terms:

A Remote Client, a Local Context, and a Remote Context may be instantiated on a single machine or each one may be running on a separate machine in a separate part of the world. In the remote case, these programs communicate over TCP/IP internet connections using a variety protocols (HTTP, XML, and AIS). The Local Context and the Remote Context must run on AIS servers. The Remote Client is a client application that can issue requests using one of the standard internet protocols such as HTTP. Examples are a browser such as Internet Explorer, or a Macromedia Flash plug-in. The HTTP protocol requires that the client receives exactly one response to each request. The other protocols support messages originating from the server with no corresponding outstanding request.

Remote Client A client connected to an AIS port that runs a Client application. The client is an internet aware application that uses any of the AIS supported TCP-oriented interface. For example, a Macromedia flash application, a Remote IDE written in C++, or an HTML application running Javascript may serve as a Remote Client. The instance of the program running in this application is referred to as the Client Program
Local Context The context instantiating the contextClient Lambda. The instance of the aisLisp program being executed in this context is referred to as the Local Lambda.
Remote Context Session The context session that the Local Lambda opens on the remote AIS server. The instance of the aisLisp program being executed in this session is referred to as the Remote Lambda.

The terms "Local" and "Remote" are relative. In a complex application, any one of the contexts may play the role of a Local Context or a Remote Context. In fact, a context may even play both roles.

Lambda Execution in Remote Context Sessions

The usual reason for using contextClient is to open a remote context session and execute Lambdas in that context. It is an error to open a context session on the same context that instantiated the contextClient - in other words "don't try talking to yourself". It is legal for the Remote Client, the Local Context and/or the Remote Context to be on the same server.

The primary reason contextClient exists is to support the farm Lambda. The farm Lambda implements a distributed processing architecture. You will find numerous references and examples in this documentation to the use of contextClient by the farm Lambda. It is recommended that you read the farm documentation as a supplement to this documentation on the contextClient. The farm.selfTest Lambda is a particularly good source of information on advanced usage of contextClient. The contextClient.selfTest Lambda is a good example of less advanced usage.

Before getting into the more advanced use of contextClient by the farm Lambda, lets look at the more rudimentary usage of contextClient in an local Lambda.

Lets say you have an local Lambda that needs to execute an Lambda in a remote context. Here is one approach your application could take:

The advantage of this approach is that it is very simple. However, it is a synchronous process because the local context will have to wait for a return result to be returned from the myContextClient.eval call.

If you desire an asynchronous execution of an Lambda in a remote context session, call myContextClient.eval with returnType and notifyType options that cause the return result from the remote context session to be sent back to the local context as an event message. A numeric is immediately returned from the call to myContextClient.eval. The local Lambda should use this RequestID to keep track of a request that has been submitted to a remote context session. Event messages are AMP messages that specify the contextClient.notify Lambda be executed in the local context. The event message contains a "Remote Result" element which will carry the value of the return result from the Lambda executed in the remote context. The event message has a "RequestID" element that carries the same value as was returned from the original myContextClient.eval call.
Consider the following steps:

The advantage of this approach is that it allows you to create event-driven applications or applications that check for return results at convenient times. Note that only the myContextClient.eval Lambda used non default values for ReturnType and NotifyType. While ReturnType and NotifyType are valid options on most contextClient child Lambdas, they are most commonly used on the contextClient.eval Lambda.

The typical advanced usage of a contextClient Lambda instance is found in its use by the farm agency. The farm agency allows one context, the farm context, to receive requests from one or more remote clients that are forwarded for execution in one or more worker contexts. The farm context acts as a traffic cop. It knows what each worker context can do and how busy each worker context is. The farm agency's usage of contextClient instances is briefly illustrated (and oversimplified) in the following steps:

The scenario above is only one of many possible ways that contextClient Lambda instances may be used. The key to using contextClient Lambda instances successfully lies in a complete understanding of the ReturnType and NotifyType options. These options are described below in some detail and then a variety of use cases are explored to more fully explain their usage.

Request ID

As noted in the Function descriptions below, calls to the contextClient return a request ID. The request ID is a unique integer (incrementing from 1 since the local context was started). The same request ID is also included in messages returned later along with the return result from the context client. The request ID provides the mechanism for associating asynchronous events with the originating request. This mechanism is essential in those cases where asynchronous events from multiple outstanding requests must be sorted out by the local context or the remote client.

Remote Client

It is possible for a local Lambda to issue remote requests to a remote client without a remote client involved. This simpler case is shown in some of the figures below. In this case, the ReturnRemote ReturnType is not applicable. It is possible for the localClient to issue a remote request and then wait for a return from the remote server or the localClient may issue a remote request, return immediately to do other tasks and then receive a notification when a long-running remote task finishes.

It is also possible for the localLambda to act as an intermediary between a remote client and a remote server. This case is shown in all of the figures below. Here, a request from the remote client is forwarded on to the remote server. If the ReturnType is NoReturn, and acknowledgement is returned immediately from the localLambda back to the remote client. In the other cases, a result is either returned directly from the remote server or a result is returned back by the localLambda to the remote client after the local Lambda receives the remote . In this last case, the localLambda is frozen in a loop waiting for the response from the remote server.

ReturnType and NotifyType

As mentioned earlier most contextClient child Lambdas allow the specification of ReturnType and NotifyType. For instance, the logon, openSession, eval, and closeSession contextClient child Lambdas all allow you to specify a ReturnType and NotifyType. In theory, you could code a local context application to handle all of the steps in the previous examples in a fully event-driven manner by keeping state information about the contextClient calls made and then picking up where each call left off as the event messages are processed. In practice, there is little to gain in using the ReturnType and NotifyType options for calls that execute quickly so only the contextClient eval child Lambda is normally executed with these options set to anything other than the default values of ReturnType=Wait and NotifyType=NoNotify.

So far we have only discussed the Local Context and the Remote Context Session. The contextClient can also manage the output of display information and return results to a Remote Client active on the Local Context. The contextClient Lambda can make return results and output, from the execution of an Lambda in a Remote Context Session, appear to be coming from the Local Context directly to the Remote Client. This facility is very useful for building distributed processing applications.

As a brief review of this more complex relationship: The Remote Client submits requests for processing to the Local Context. The Local Context submits requests for processing in the Remote Context. The Remote Context send return results and display output to either the Local Context or the Remote Client or both as defined by the ReturnType and NotifyType options specified during the Local Context's submission of the request to the Remote Context.

ReturnType options:

>
  1. Wait: (default) Wait for remote execution to complete. The polling loop is in the SBGlue layer. Local context receives remote context return result in return from contextClient call. Remote client receives local context return result. Remote context display is sent to the remote client.
  2. NoReturn: Return result is discarded. Use FullNotify to post the return result into local context. Remote context display may be cached for later retrieval by the local context.
  3. ReturnRemote: Local context return result is discarded (not sent back to remote client). Request stays on request queue until return result is received from remote context execution. Remote context display output is sent back to the remote client. Remote client receives remote context return result when it is returned from the remote context session.

NotifyType options:

  1. NoNotify: (default) No Notification Message is generated.
  2. FullNotify: Local context receives a Notification Message on completion of request. Return result is included.
  3. Notify: Local context receives a Notification Message on successful completion of request. Return result is not included in message.

The following are some Return/Notify combinations when calling contextClient.eval to submit a request on a remote context.

Wait/NoNotify. This acts just like a regular local execution of the message. Note that the local context's thread is doing no work while it waits for a return result from the remote context that is executing the AMP message. This option combo offers no distributed processing utility because the local context thread is tied up while it waits for the remote context to finish its work. Display output from the remote context will be sent to the remote client as if they were generated in the local context.

Wait/Notify. Since the local Lambda is frozen until the remote result is returned from the remote context session, there is very little reason to ever include a notify option.

ReturnRemote/NoNotify - This option combo causes a request to be evaluated in a remote context and when the return result arrives at the local context, it will be forwarded directly to the remote client (shown as a direct return in the diagram below). The queue entry on the local context is cleared at this time. The return result from the currently executing Lambda in the local context will be discarded. Usually, you should return from the executing Lambda (in the local context) immediately after making the submission to the remote context to allow the processing of the next request in the local context's request queue.
This option combo provides full distributed processing if the requests, submitted by remote clients, result only in submissions to remote contexts. This option combo does not provide the local context with enough information to directly monitor the successful completion of requests in remote contexts. Display information from the remote context is sent to the remote client directly.

ReturnRemote/Notify - This option combo is the same as ReturnRemote/NoNotify with one added step. When a result is returned from execution in a remote context, a Notification Message is also placed in the local context's request queue. This message contains the associated with the submission to the remote context. If, in the original Lambda making a submission to the remote context, a record of that submission's RequestID was made then it is possible to match up the the information in the message with this record. Use ReturnRemote/Notify or ReturnRemote/FullNofify if you are building a distributed processing model where the local context will be "monitoring" the completion of requests submitted to remote contexts. Display information from the remote context is sent to the remote client directly.

Note: The Notification Message is submitted to the local context on the context's admin session. Any return result from the execution of the message in the local context will be thrown away - there is nowhere for it to go. This is desirable behavior as it allows the construction of "event-driven" applications.

NoReturn/NoNotify. In this case, the remote client gets an acknowledgement back from the local Lambda when the remote request is submitted to the remote context session, but neither the local context or the remote client would ever get a remote result from the remote context session. Since the work done in the remote context session is lost, this pair of options is never used.

NoReturn,FullNotify - A remote request is submitted to the remote context session by the localLambda. The local Lambda returns immediately. If this request was initiated by a call from a remote client, an acknowledgement containing the RequestID is returned to the remote client. When the remote client completes the request, a remote result is placed in a Notification Message that is returned to the local context. Just as for all Notify options, this message is placed in the local context's request queue. This message will contain the RequestID of the submission to the remote context as well as the full return result of the submission. This option does not automatically send the return result from the remote request back to the remote client. This option combo makes it possible for the local context to manage the returned results generated by execution of Lambdas in a remote context. For instance, suppose a remote client submits a request to the local context that results in a long running task on the remote context. In this model, the remote client is informed of a successful "job start" and might check back later to see if the job had completed. If the remote client was on a asynchronous port, say the XML port, occasional messages could be sent to the remote client informing the client of changes in the job status, including the final result returned from the remote context. This model requires a high level of application level code as the contextClient itself does not provide these higher-level functions.

In addition, because the local context would be handling the return result and generating additional messages to the remote client, this model would provide lower overall throughput of requests in the local context.
Display information from the remote context will be ignored by default. You can set options to have display information from the remote context cached for later retrieval by the local context.

Note: The Notification Message is submitted to the local context on the context's admin session. Any return result from the execution of the message in the local context will be thrown away - there is nowhere for it to go. This is desirable behavior as it allows the construction of "event-driven" applications.

Implementation

The flow of data in AIS is shown in the following diagram:

The local Lambda is written in AisLisp and is the API that you use. This Lambda makes calls to the _ContextClient function which in turn creates and makes calls on the AContextClient object. The _ContextClient function is implemented in the SBGlue layer as a C function. The AContextClient object is implemented in the AIS server in C++.

When you create a new contextClient instance, a corresponding AContextClient C++ object is created. Calls to child Lambdas of the contextClient Lambda instance result in corresponding calls to the member functions of the C++ AContextClient object instance. All of these calls are made through the _ContextClient function. The C++ object will always be destroyed when the contextClient Lambda that created it is garbage collected.

Wait/NoNotify. A simplified version of the above diagram is shown below for the wait/no notify case. SBGlue_ContextClient eval request generates a remote request and then falls into a wait loop. Display from the remote server is routed directly back to the remote client, iff a remote client generated the request. The result from the remote server is returned to waiting SBGlue_ContextClient eval function which then exits from the wait loop to return the result back to the Lisp Engine. Note that this context is not able to process any incoming requests while it is waiting for a return.

ReturnRemote/NoNotify. A simplified version of the Figure 5 is shown below for the return remote/no notify case. SBGlue_ContextClient eval request generates a remote request and then returns immediately. Display from the remote server is routed directly back to the remote client. Later, the result from the remote server is also returned back to the waiting client. The local context is unaware of the returned result.

NoRetun/Notify. A simplified version of Figure 5 is shown below for the no return/ notify or full notify case. SBGlue_ContextClient eval request generates a remote request and then returns immediately. Display from the remote server is discarded. The result from the remote server is submitted as an event on the local context's input request queue. This event on is processed in the Lisp Engine by a notify Lambda. The notify Lambda is a part of the application code. It may record the event in a table, send a response back to the client, or generate new requests based upon the returned result.

Message Handling

This section provides an overview of how an application can implement message handling when using the contextClient Lambda.

Most calls to contextClient child Lambdas allow Return Type and Notify Type arguments. The Return Type argument affects the type of return received from the child Lambda call. A Return Type of Wait will cause the child Lambda to return an AMP message structure, discussed later in this section, while all other Return Types cause the return of a numeric RequestID and optionally a Notification Message as specified by the NotifyType argument.

The NotifyType argument determines if a Notification Message is generated, in the request queue of the local context, when the return result is received from the remote context. Notification Messages are AMP messages.

To illustrate the power of contextClient messaging we will examine the way calls with the NoReturn/FullNotify combination can be handled by an application. This will introduce the use of the contextClient.notifyRegister child Lambda.

First, lets review the NoReturn/FullNotify combination example from the Introduction:
> NoReturn,FullNotify - This option combo causes the return result generated by execution of Lambdas in a remote context (a remote Lambda request) to arrive as a Notification Message in the local context's request queue. as shown in Figure 4 above.

The Notification Message is an AMP message with a target Lambda of contextClient and a speech act of notify. Thus, the contextClient.notify child Lambda is executed with the AMP message structure passed to it as an argument. Review the AMP documentation for more information on the AMP protocol.

The contextClient.notify child Lambda is responsible for passing Notification Messages to zero or more "subscribers". Applications call contextClient.registerNotify to specify which Lambdas should be notified when a Notification Message is received by contextClient - these Lambdas are called notification subscribers.

So far we have discussed the following Lambdas: local Lambda, contextClient, contextClient.notify Lambda, contextClient.registerNotify Lambda, remote Lambda. The following list provides a somewhat abbreviated example of when and how these Lambdas are created and used.

AMP Message Return Structure

Most contextClient child Lambdas return AMP Message Return structures - either immediately or as an Notification Message. See the Messaging section for a more detailed discussion of Notification Messages.

The AMP Message return structure has the following elements:

Context Client Request Call Chain

Local Context. This level of detail is of little interest to users of the Context Client. It is here just for developers who need to maintain or enhance the Context Client. Figure 9 below shows in more detail the sequence of calls and transmissions that carry the message from one context to another and back again. The process is initiated by an Lambda that sends an execution string and an object to a remote client that is responsible for using the execution string to operate on the object in the remote context. After a byte array has been filled with a serialized representation of the object closure, this request results in a call to ASBGlue_ContextClient with a reference to the execution string. The task to be performed is specified by a function handle. In this case, the function handle specifies a write operation. After the call is made, ASBGlue_ContextClient falls into a loop that waits from a flag named mComplete to be set in a task structure when the result is finally returned from the remote context. The request and a reference to the byte vector is passed to AContextClient and then via AAppClient to the remote context. If both contexts are in-process, a direct function call is made to the remote context; otherwise, the request and the byte array are transmitted as a serial byte stream over a TCP connection to the remote context. If a TCP connection is required, the ownership of the byte array is transferred to ASocket which deletes the byte array after it is transmitted to the remote context. The entire call chain is carried out on the local context's thread. This is made possible by the recent addition of an event loop in Qt's thread implementation.

Remote Context. No matter which method was used, in-proc or TCP, the exact same sequence of operations are made from the AAppSvr's submit method through the rest of the call chain. In the case of a TCP connection, a new byte array is created and a reference to this array is passed on in the same fashion as for the in-process case. In the case of a TCP connection, the call chain is executed on the main thread; else, the call chain continues to execute on the local context's thread. In ASessionMgr's submit method, the request and a reference to the byte array is placed in a request structure that is, in turn, placed in a request queue. Later, the processNextRequest method is called on the remote context's thread which then removes the oldest request from the queue and then hands the execution string and byte array to ASBGlue_Eval for evaluation.

Context Client Return Output Call Chain

Remote Context. Figure 10 above shows in more detail the sequence of calls and transmissions that carry the result back from the remote context to the waiting local context. In some cases, such as a read request from ASBGlue_ContextClient, a byte array may also be returned containing a requested serialized object closure. The return output call chain is initiated on the remote context's thread. ASessionMgr's cbReturnResult generates an event that is caught by AAisMgr's event handler, named event. This event handler is running in the remote server's main thread.

Local Context Just as described above for the request call chain, the result and its byte array, if any, are passed back to the local context. In either case, the AAppClient's returnOutput method receives the same inputs. In this case, returnOutput is running on the main thread of the local server. AContextClient is an instance of an AppClient. Its postMessage method places the return result and byte array reference in the task structure created when the request was first initiated by ASBGlue_ContextClient. Finally, postMessage sets the mComplete in this task structure. Meanwhile, back at the ranch, the local context thread that is still stuck in a wait loop calls getReturnResult and discovers that the mComplete flag is set. Then, ASBGlue_ContextClient proceeds to return from back to the caller with the returned result and byteArray. Ownership of the byte array that arrived with the return result is transferred to ASBGlue_ContextClient. It deletes the byte array after it has been processed by loadObject in the engine.

Source Code.To delve into this process even deeper, consult the extensive source-code documentation for each class shown in the above figures. The table below shows the project name for every class shown in the above diagram. You can open the aisdev or aiswip solution in Visual Studio and then view the projects in the solution explorer. Open the project shown in the table and then view the class source file to examine the source-code documentation for the method shown in the class nodes in the above diagram.

Class Project
ASBGlueglue
AContextClientasessionmgr
AAppClientappclient
ASocketappclient
AAppSvrappsvr
AAisSvraissvr
AAisMgraismgr
ASessionMgrasessionmgr

General Request Case. The flow diagram shown in Figure 9 also applies to the general case. A request may be initiated by any remote client by calling the AAppclient submit method. The request follows the rest of the call chain from this point. Even other protocol servers, such as AHttpSvr and AXmlSvr, call the AAppSvr submit method and then the request follows the rest of the call chain.

General Return Case. The flow diagram shown in Figure 10 also applies to the general case. Results generated by smtbase are returned by calling the ASessionMgr cbReturnResult method. The return output follows the rest of the call chain back to the AAppClient returnOutput method. From there, the AAppClient returnMsg method returns the result back to the remote client.

Other Protocols. Even in the case of other protocol servers, such as AHttpSvr and AXmlSvr, the result is handled in exactly the way up to AAppClient's returnMsg. AAppClient returnMsg returns the result back to the protocol server's returnOutput method which formats and returns the result back to the remote client. Some restrictions apply. For example, these protocol servers do not currently have the capability to return serialized objects.