Introduction to PLEXIL Application Framework
21 May 2015
This section gives a high-level overview of the PLEXIL Application Framework.
- 1 Overview
- 2 The universalExec Application
- 3 Adapters, Listeners, and Listener Filters
- 4 The Lifecycle Model
- 5 Concrete Classes
- 6 Abstract Base Classes
The core of the PLEXIL Executive is general and abstract by design. No top-level loop is provided, nor are any interfaces to external systems implemented in the core.
The PLEXIL application framework provides these essential capabilities. The framework consists of the ExecApplication, InterfaceManager and AdapterConfiguration classes, the universalExec executable application, and associated abstract base classes for external interfacing. Finally, a small library of essential interface adapter classes is provided.
This application framework is intended to support a wide range of uses with little or no custom code. However, some applications may require the developer to implement a custom framework. This is beyond the scope of this document. Please contact the PLEXIL team if you have such an application.
The following diagram illustrates the main classes of the application framework. Some of these classes are described in more detail in the remainder of this chapter.
The universalExec Application
The universalExec application is a flexible main program for applications of the PLEXIL Executive which have straightforward interfacing requirements. Interfaces can be specified at startup time by an interface configuration file.
The universalExec application is comprised of the following:
- The PlexilExec class, which implements the core plan execution logic of the Executive;
- The AdapterConfiguration class, responsible for routing interface requests to the appropriate interface adapter;
- The InterfaceManager class, which implements the high-level external interface required by the Executive core;
- The ExecApplication class, responsible for startup, shutdown, and (where appropriate) threading;
- A small main() program to parse the command line, set up the framework, start execution, wait for execution to end, and clean up at exit.
The source code of the universalExec application is in the directory $PLEXIL_HOME/src/universal-exec in the PLEXIL distribution. For applications needing more control over initialization and shutdown, the source code in this directory can be used as a template.
The universalExec requires additional interfacing code to perform any useful tasks. On Unix-like systems (e.g. Linux, Mac OS X) an adapter for OS time services is included in the distribution. This is not yet implemented for other systems.
Adapters, Listeners, and Listener Filters
Interface adapters serve as intermediaries between the InterfaceManager instance and the outside world. They direct commands, lookup requests, and planner updates to the appropriate external modules or devices, and translate their results back into the internal representations.
Exec listeners report on state changes within the Executive which may be of interest to outside observers. Optional exec listener filters can select the events to report.
The Lifecycle Model
The PLEXIL application framework divides the application and interface lifecycle into several phases. The ExecApplication class manages the phases as follows.
This is the state that applies to the application immediately upon startup.
Upon completion of ExecApplication::initialize(), the exec and all interfaces have been constructed and initialized, but not yet activated.
Upon completion of ExecApplication::startInterfaces(), interfaces have been started, but the executive is not running.
The application can also enter this state from the Running state.
After calling ExecApplication::run(), or after ExecApplication::resume()if the application had been suspended, all interfaces are active and the exec is executing plans.
A Running application can be paused - temporarily halting execution, but leaving interfaces up - by calling ExecApplication::suspend(), at which point it reverts to the Ready state.
Calling ExecApplication::stop() halts plan execution and deactivates the interfaces.
To restart the application from this state, calling ExecApplication::reset() will return the application to the Initialized state.
After calling ExecApplication::shutdown(), the exec and all interfaces have been disabled and potentially deleted. The application is finished.
These are the predefined classes which establish the PLEXIL Application Framework.
The concrete class PlexilExec is the engine responsible for executing plans and evaluating expressions. There should be little reason for any developer to access it directly, beyond instantiating it.
The concrete class AdapterConfiguration provides facilities to load, query, and modify the mapping of commands, lookups, and planner updates to interface adapters, and to load, query, and modify the list of exec listeners. It implements abstract factories for adapters and listeners.
In the PLEXIL Executive and many applications derived from the framework, the AdapterConfiguration instance is responsible for loading configuration data from the interface configuration file, and using the abstract factories to construct the adapters and listeners.
In other applications, a user-defined program can construct adapter and listener objects as required, and configure routing to them through imperative AdapterConfiguration method calls.
The concrete class InterfaceManager takes the requests for commands, lookups, and planner updates from the PlexilExec instance, queries the AdapterConfiguration instance for routing information, sends them to the appropriate Interface adapters, and enqueues the results for use by the PlexilExec.
The ExecApplication class implements the essential features necessary for a PLEXIL application, and implements a top-level loop, including optional multithreaded operations for platforms with POSIX-compliant threading facilities (pthreads).
Abstract Base Classes
The PLEXIL Application Framework defines the external interface API via two abstract base classes, InterfaceAdapter and ExecListener. A third abstract base class, ExecListenerFilter, defines an API for ExecListener instances to selectively filter their reporting.
An interface adapter is responsible for taking the command, lookup, or planner update call from the InterfaceManager instance, and communicating that to the world outside the Executive.
An exec listener notifies the outside world of an internal state change in the Executive, e.g. a node state transition, a variable assignment, or loading of a plan or library, with optional user-definable filtering.
An exec listener filter determines whether the associated exec listener instance should report or ignore a particular event.
Users may define classes derived from all three abstract base classes to implement an application's external interfaces.
The abstract base class InterfaceAdapter defines the API for adapters connecting an InterfaceManager instance to systems and modules external to the Plexil Executive. Instances of classes derived from InterfaceAdapter can be associated with specific commands, functions, and lookups by name, and these associations can be changed at run time, through the AdapterConfiguration interface.
The abstract base class ExecListener defines the API for reporting internal events of potential significance to the outside world. It can take
The abstract base class ExecListenerFilter defines the API for selecting the events an exec listener instance will report.
Copyright (c) 2006-2015, Universities Space Research Association (USRA). All rights reserved.