Module Glish

Changes made in the current development cycle can be found in the changelog.

Description (classes)

AIPS++ wrapper classes for Glish values and events.

Review Status

Reviewed By:
pshannon
Date Reviewed:
28OCT94
Programs:
Demos:

Synopsis

The classes in the Glish module were created to make it easy to construct AIPS++ applications which interact with each other (via interprocess communications). This involves constructing values which are sent back and forth between the processes, sending and receiving these values, and managing all of the events (including X Windows events).

This module is built upon Glish. Glish is a language (and supporting infrastructure) for constructing loosely coupled distributed systems. The values which Glish and this module deal with can either be arrays or records. Arrays correspond to the arrays found in C and other languages, and records correspond to the heterogeneous structures found in most languages, e.g. the C struct.

The major external classes in this module are:

These classes insulate the user from the underlying Glish classes by hiding event management complications and translating Glish values into AIPS++ classes. It is very easy to construct an application which can stand alone or be started from the Glish CLI with these classes. In addition, the application could easily be a windowing application.

For information about the Glish system in general, a general introduction (75K) to Glish is available as well as a complete users manual (1Meg). These documents as well as the Glish source are available from the Lawrence Berkeley Laboratory.

Motivation

AIPS++ is using Glish as a user command line interpreter and as the communications infrastructure. Functionality is bound to the CLI by creating new clients which pass events back and forth between the client and the CLI. This module supports writing these clients in C++. While it would have been possible to use the native Glish classes, it is useful to have an independent interface which converts Glish classes into the classes used by AIPS++ programmers, e.g. GlishArray .

Procedural Example

The following example implements a simple statistics server for arrays which have been sent from some other process (for example, a user interactively manipulating a user interface). In this example, the Glish events are handled serially with the process blocked waiting for the next event. This is a procedural style where as the next example is an event driven style.

    #include <aips/Glish.h>                                           //  1
    #include <aips/Arrays/ArrayMath.h>                                //  2
    #include <aips/Arrays/IPosition.h>                              //  3
                                                                      //  4
    int main(int argc, char **argv)                                   //  5
    {                                                                 //  6
        GlishSysEventSource eventStream(argc, argv);                  //  7
        GlishSysEvent event;                                          //  8
        while (eventStream.connected()) {                             //  9
            event = eventStream.nextGlishEvent();                     // 10
            if (event.type() == "statistics") {                       // 11
                GlishArray ga = event.val();                          // 12
                Array<Double> ad(ga.shape());                         // 13
                ga.get(ad);                                           // 14
                GlishRecord response;                                 // 15
                response.add("mean", mean(ad));                       // 16
                response.add("median", median(ad));                   // 17
                eventStream.postEvent("statistics_result", response); // 18
            } else if (event.type() != "shutdown") {                  // 19
                eventStream.unrecognized();                           // 20
            }                                                         // 21
        }                                                             // 22
        return 0;                                                     // 23
    }                                                                 // 24
    
  1. Include the Glish module header.
  2. Where the statistics functions (mean and median here) are defined.
  3. IPosition is needed when dealing with shapes.
  4. When Glish starts up a server, it uses special command line arguments. Thus we need the command line arguments to get passed into main.
  5. The events from the "remote" Glish will appear to come from this object, which requires the command line arguments for construction.
  6. "event" will be used to hold the current event from eventStream.
  7. Run for as long as we are connected to the remote process.
  8. Get the event. This blocks until there's an event to be had.
  9. If the event type (name) is statistics
  10. Convert the event into a GlishArray. A more serious application would check that the event is a GlishValue::ARRAY before assigning it to one. In this case, an exception would be thrown if it wasn't.
  11. Create an AIPS++ array to hold the array (so we can compute upon it).
  12. Put the value into the AIPS++ array. We should really check that the elemental type is compatible with double, e.g. not String. If it was incompatible, an exception would be thrown.
  13. Create a record which will be used to hold the statistics we compute.
  14. Create a field in the record called "mean", holding the mean value of the array.
  15. Similarly for the median.
  16. Send the response back, naming the event "statistics_result".
  17. If the event is not "statistics", and it is not "shutdown" (this latter being system generated before the connection is "normally" severed) then it is unrecognized.
  18. Call the "unrecognized" member whenever this happens.

Event Driven Example

The previous example could also be written in an event driven style. This is the style of programming familiar to developers of graphical user interfaces. Here callbacks are set up for the Glish events and then control is given up until the callbacks are called. This implements the same functionality as the previous example. See the event driven example in the XSysEvent header file for an example of how X Windows events can be combined with Glish events.

    #include <aips/Glish.h>                                           //  1
    #include <aips/Arrays/ArrayMath.h>                                //  2
    #include <aips/Arrays/IPosition.h>                              //  3
                                                                      //  4
    Bool statCallbk(GlishSysEvent &e, void *) {                       //  5
        GlishSysEventSource *es = e.glishSource();                    //  6
        GlishArray ga = e.val();                                      //  7
        Array<Double> ad(ga.shape());                                 //  8
        ga.get(ad);                                                   //  9
        GlishRecord response;                                         // 10
        response.add("mean", mean(ad));                               // 11
        response.add("median", median(ad));                           // 12
        es->postEvent("statistics_result", response);                 // 13
        return True;                                                  // 14
    }                                                                 // 15
                                                                      // 16
    int main(int argc, char **argv)                                   // 17
    {                                                                 // 18
        GlishSysEventSource eventStream(argc, argv);                  // 19
        eventStream.addTarget(statCallbk,"^statistics$");             // 20
        eventStream.loop();                                           // 21
    }                                                                 // 22
    
  1. Include the Glish module header.
  2. Where the statistics functions (mean and median here) are defined.
  3. IPosition is needed when dealing with shapes.
  4. To handle Glish events in an event driven manner, callbacks must be created for each type of event. The callback parameters are the event, and a void* which can contain any user data. The user data is an optional parameter to GlishSysEventSource::addTarget.
  5. To post events, the event source must be retrieved from the event.
  6. Convert the event into a GlishArray. A more serious application would check that the event is a GlishValue::ARRAY before assigning it to one. In this case, an exception would be thrown if it wasn't.
  7. Create an AIPS++ array to hold the array (so we can compute upon it).
  8. Put the value into the AIPS++ array. We should really check that the elemental type is compatible with double, e.g. not String. If it was incompatible, an exception would be thrown.
  9. Create a record which will be used to hold the statistics we compute.
  10. Create a field in the record called "mean", holding the mean value of the array.
  11. Similarly for the median.
  12. Send the response back, naming the event "statistics_result".
  13. If the handler successfully handles the event, it should return True, otherwise another handler will be sought.
  14. When Glish starts up a server, it uses special command line arguments. Thus we need the command line arguments to get passed into main.
  15. This object will orchestrate the event handling. It requires the command line arguments for initialization.
  16. To make callback functions known, it must be registered with the GlishSysEventSource::addTarget. The string (the second parameter) is a regular expression which indicates which group of Glish events the function will accept. In this case, "^statistics$" indicates that this function will only accept events whose name equals statistics.
  17. This member function will cause the events to be processed and passed to a callback function (if possible) until all events have been processed.

Classes

GlishArray -- holds any Glish array (full description)
GlishRecord -- holds a Glish record (full description)
GlishRecordExpr -- Filter GlishRecords using a TaQL expression. (full description)
GlishSysEvent -- Glish event wrapper (full description)
GlishSysEventProcTargetInfo -- Internal class (full description)
GlishSysEventSource -- wrapper around Glish event generation (full description)
GlishSysEventTarget -- a generalized Glish event handler (full description)
GlishValue -- holds any type of Glish value (full description)
XSysEvent -- X event wrapper (full description)
XSysEventSource -- X event generation wrapper (full description)
XSysEventSourceInfo -- Internal class (full description)
XSysEventTarget -- X event handling wrapper (full description)
operator<< -- output GlishValue to an ostream (in ASCII) (full description)