CEStatus Technical Documentation

(This document lives at http://www.gnosis.cx/docs/cestatus_doc.html)
If you have received a printed version, consult the URL for the most current version

Introduction to CEStatus

CEStatus consists of several sub-components. Agent/license information is stored persistently through access to the cfgagent.py CGI script; A Java or JavaScript/HTML user interface is presented by the client browser to update and modify agent/license information; Another CGI script, cestatus.py, is called to produce license/compliance status reports.


CEStatus CGI/Command-Line Call Interface

The script cfgagent.py (or cfgagent.cgi) persistently stores information about agents and licenses, and is the official interface by which all agent/license information is configured in the CEStatus module. When called as a CGI, the script will generally use the GET CGI method (so as to produce a replicable URI). By its design, cfgagent.py can also easily be used for local access to agent/license information, for example in the case where a batch initialization of agent/license data comes from a pre-existing data source.

cfgagent.py allows a few variations in calling details. What is documented in the below syntax diagram is the command-line version of a call, which is the most general version. This type of call may be performed via CGI by URL-encoding the address, e.g.

    http://gnosis.cx/cfgagent.cgi?ssn%3d111-11-1111+firstname%3djohn

The equivalent instruction generated by an HTML GET method form would be:

    http://gnosis.cx/cfgagent.cgi?ssn=111-11-1111&firstname=john

Either of these calling conventions, and also a POST method HTML form containing the same data, will produce identical modifications to the agent data storage.

Calls to cfgagent.py should obey the following syntax (adjusting for allowed call styles):

   [python] cfgagent.py [PERMISSION=<useridstring>]
                        SSN=<ssn>
                        [DELETE]
                        [FIRSTNAME=<firstname>]
                        [MIDNAME=<middlename>]
                        [LASTNAME=<lastname>]
                        [BIRTHDATE=<birthdate>]
                        [ [LICINFO=<stateabbrev>:<line>[:<licensenum>[:<issuedate>]]]
                          [...] ]
                        [HOME1=<addressline1>]
                        [HOME2=<addressline2>]
                        [HOMECITY=<city>
                        [RESSTATE=<residentstate>]
                        [OFFICE1=<addressline1>]
                        [OFFICE2=<addressline2>]
                        [OFFICECITY=<city>
                        [OFFICESTATE=<residentstate>]

All keywords are case insensitive, but are listed in the syntax diagram in upper case for visual distinction. Order of arguments does not matter.

If the LICINFO keyword is specified, a few special rules apply to its compound value. The components of LICINFO are separated by colons. A stateabbrevmust be provided first, followed by a mandatory line. Thelinemay have the special value None; if this value is used, all the license information for the specified state is removed from the agent record. If a regular value is provided for line, the new lineis added to the list of lines held in the specified state. licensenumand issuedateare both optional components. Any values provided will overwrite any previously stored value, if such exist. Due to the order of the components, it is not possible to modify/create an issuedatewithout also providing licensenumin the same call. In practice, this limitation is of little significance.

As is indicated in the syntax diagram, multiple occurances of the LICINFO keyword may occur. These occurances may specify license information in multiple states, and/or may be used to specify multiple license lines within a state. For example, the below is a legal call:

   cfgagent.py SSN=111-11-1111 LICINFO=ma:health LICINFO=ma:life LICINFO=ct:life

However, it should be noted that cfgagent.py is not guaranteed to handle multiple instance of the LICINFO field within an HTML form correctly. It is best, when designing a web-browser interface to cfgagent.py to generate multiple requests, each with a single LICINFO field. A wrapper CGI around the actual cfgagent.py script can also be used to provide a command-line (URL-encoding) style call. The below series of calls will cummulatively have an effect identical to the above use of multiple occurances of LICINFO:

   http://gnosis.cx/cfgagent.cgi?SSN=111-11-1111&LICINFO=
   ma:healthhttp://gnosis.cx/cfgagent.cgi?SSN=111-11-1111&LICINFO=
   ma:lifehttp://gnosis.cx/cfgagent.cgi?SSN=111-11-1111&LICINFO=ct:life

The DELETE keyword causes the entire agent record with the specified SSN to be removed from the data storage. It makes no sense practically to specify any additional optional keywords when the DELETE keyword is used.

The keyword PERMISSION is reserved for future use, but has no effect at present. In the future, this keyword may be used as part of an access control system.

The semantics of cfgagent.pycalls are more restricted than the syntax itself indicates. That is, some parameter lists which are syntactically valid, may nonetheless return an error message if run. The chief cause of such an error return is if one or more required fields in a call are omitted, which prevents the indicated data from being stored persistently. The semantic validity of a call will depend, in many cases, on previous calls (and therefore on existing data state). If all required fields were indicated on an initial call, subsequent "update" calls need not specify the values of unchanged fields. Key fields, however, must be specified in all cases, and this is indicated in the syntax diagram itself. For a clarification of required and optional fields, consult the below Object Model documentation

One additional important caveat should be noted. Spaces within fields will not parse correctly. Therefore, in those fields where spaces are a natural part of the field values, these spaces should be converted to underscores (or other desired replacement strings) prior to passing arguments to cfgagent.py. Such a replacements may be easily accomplished with Java or JavaScript within a browser interface, but must be kept in mind when other interfaces are developed or modified. cfgagent.py itself makes no effort to convert underscores (or anything) back to spaces for internal storage, so where necessary user interfaces need to perform a reverse conversion prior to presenting information to users.


CEStatus HTML Return Format


CEStatus Agents/License Object Model

The object model of CEStatus is largely identical to the syntax diagram for cfgagent.py calls. Agents are OOP objects which hold bundles of data, some of which are themselves objects. Objects at the various levels may have methods among their attributes. The below hierarchical diagram shows the structure of an agent object and its dependents. Also indicated is the mutability and requirement of each object attribute. Key fields are, of course, required and immutable. In general, unless otherwise indicated, all non-key data members are mutable, if only because entry mistakes are possible (update of fields is still controlled by selective access permissions). The following symbols are used for visual identification of elements (ellipses are used to indicate held objects whose type may occur multiple times):


Object Ordinary Data Member Method Key Data Member Immutable Data Member Required


Two features of the CEStatus development language, Python, make the below object model a natural representation of agent/state licensing requirements. One is the dynamic attribution of Python. Optional data members need not be pre-defined with initial placeholder values, but may simply be added as needed. In the OOP parlance of C++ or Java, every Python class is a sort of container class. Second - and probably most importantly - Python provides a facility for persistent storage of objects (class instances) in a manner which allows for reimplementation of methods when those objects are used later (or by other processes). For our purposes, this has the nice property that we can change the business logic of calculating individual state requirements, even while this logic is implemented as a method of a stored object. Once the object is re-read from disk, it takes on the brand new method logic.