Module Glish
Changes made in the current development cycle can be
found in the changelog.
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:
- GlishValue is the class for all
Glish value objects in this module. GlishValues follow copy-on-write
semantics, so assignment and passing and return by value are cheap.
- GlishArray is a (possibly
n-dimensional) array of glish values, all of which have the same
type. This is also the class which is used to hold a single value.
- GlishRecord is a "structure" of
values, made up of named arrays and records (the latter makes it
hierarchical).
- GlishSysEvent is a named value
which has been sent from an external source.
- GlishSysEventSource the
object inside the program which emits the GlishSysEvent objects.
It is also the object to which events from this executable are
posted. This object can also be used to register callbacks and
and handle incoming events in an event driven manner.
- XSysEventSource allows the
user to handle both Glish and X events using the same event
loop. See XSysEventSource for
an example.
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
- Include the Glish module header.
- Where the statistics functions (mean and median here) are defined.
- IPosition is needed when dealing with shapes.
-
- When Glish starts up a server, it uses special command line
arguments. Thus we need the command line arguments to get passed
into main.
-
- The events from the "remote" Glish will appear to come from this
object, which requires the command line arguments for construction.
- "event" will be used to hold the current event from eventStream.
- Run for as long as we are connected to the remote process.
- Get the event. This blocks until there's an event to be had.
- If the event type (name) is statistics
- 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.
- Create an AIPS++ array to hold the array (so we can compute upon
it).
- 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.
- Create a record which will be used to hold the statistics we
compute.
- Create a field in the record called "mean", holding the mean value
of the array.
- Similarly for the median.
- Send the response back, naming the event "statistics_result".
- 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.
- 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
- Include the Glish module header.
- Where the statistics functions (mean and median here) are defined.
- IPosition is needed when dealing with shapes.
-
- 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.
- To post events, the event source must be retrieved from the event.
- 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.
- Create an AIPS++ array to hold the array (so we can compute upon
it).
- 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.
- Create a record which will be used to hold the statistics we
compute.
- Create a field in the record called "mean", holding the mean value
of the array.
- Similarly for the median.
- Send the response back, naming the event "statistics_result".
- If the handler successfully handles the event, it should return
True, otherwise another handler will be sought.
-
-
- When Glish starts up a server, it uses special command line
arguments. Thus we need the command line arguments to get passed
into main.
-
- This object will orchestrate the event handling. It requires the
command line arguments for initialization.
- 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.
- This member function will cause the events to be processed and
passed to a callback function (if possible) until all events
have been processed.
- 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)