The UX Demonstration Managed Object

The sources in this directory build a demonstration managed object (MO)
class called "UXMO1". The idea is to provide a model for implementors. The
code is reasonably well commented and so serves to some extent in lieu of
proper documentation. This file gives a little additional background. It is
written on the assumption that you are familiar with the OSI management
model and C++. 

It is easy to get confused between MO classes and C++ classes. Although the
former are represented by the latter, C++ classes are used for many other
things. For example attribute types correspond to C++ classes.

The UXMO1 MO class does not do anything very useful. It has five attributes
(loosely) related to the Unix operating system:

     uxbj1Id        - An arbitrary string which identifies an instance of 
                      the class - ie. the Relative Distinguished Attribute.
                      Since there is only ever one instance this does 
                      not achieve anything much. It has to be present 
                      though
     
     nusers 		- A gauge reflecting the current number of logged on 
     			  users
     
     nusersThld	- A gauge threshold related to the above
     
     systime		- The current time according to the system clock
     
     wiseSaying	- An arbitrary string which may be set using the OSI 
     			  management service

There is one notification which is triggered by the gauge threshold.

Like all MO classes in the GMS, this one is represented by a C++ class.
This is defined in UXMO1.h and is derived from the class "Top". You will
find the definition of "Top" in the file ../gms/TopMO.h. The derivation of
a C++ class, like the one in UXMO1.h, will be the normal starting point for
any new implementation. All such classes must ultimately be derived from
"Top" which is itself derived from the C++ class "MO" (see
../gms/GenericMO.h). "MO" includes many of the methods which help to locate
MO instances with the containment hierarchy.

Notice in UXMO1.h that a static instance of the MOClassInfo class is
declared. This contains maintenance information for the class as a whole
and must be present. Its definition can be found in ../gms/GenericMO.h.

Most of the attributes you will use are derived from a few common types -
gauges, counters etc. These are all provided by the GMS and all you have to
do is declare them. Their definitions may be found in ../gms/SmiAttr.h.
Where attributes with non-standard behaviours are used, these must be
implemented specially. The attribute types for "systime" and "wiseSaying"
are examples of this and their definitions may be found in UXAttr.h. The
"UXTime" C++ class differs from the generic "Time" class only in that its
value gets updated automatically every time it is read - hence the
specialised do_get() method. When a value of the UXTime attribute type is
carried by CMIP it uses a standard syntax (UTC time) and the coder and
decoder for this already exist. The "UXString" C++ class differs from the
generic "String" class only in that it is constrained to a maximum length
of 80 characters. In this case, slightly non-standard encoders and decoders
have been defined. These are generated by PEPY from the source in
UXAttrAsn.py. Since these are C routines, dummy C++ prototypes must be
provided in UXAttr.h. Generally speaking it is probably best to avoid
defining new syntaxes. If it is to be done properly a whole range of
routines should be provided to print and copy representations of the syntax
etc. This has been done for the generic syntaxes but not for the UX one. 

Once the MO class and attribute types have been defined, the corresponding
methods must be written. Those not defined inline will be found in UXMO1.cc
and UXAttr.cc respectively. As far as UXMO1.cc is concerned you should
note:

     The constructor calls the Gauge::associate_thld() method to tie the
     gauge to the appropriate threshold. It also registers the MO class
     instance with the KS object. This is discussed later.

     The methods which return "CMISErrors" are called as a result of
     requests received via CMIS. The agent function in the GMS handles all
     the filtering, scoping etc. to select the correct MO instanc(es) and
     then calls the appropriate methods. All you have to do is supply the
     methods. They all follow the same pattern: get_attrid() is called to
     map the OID onto an integer. This integer is then used in a switch to
     select the correct attribute method.

     The OID -> integer mapping is held in the MOClassInfo object and is
     set up be the initialisation routine described below.
     
     In general, a MO class will have been derived from another MO class
     and this will have been reflected in the derivation of the
     corresponding C++ objects. However, the switch statement referred to
     above only covers the additional attributes in the derived class. To
     ensure that the attributes of the parent class are covered we must
     also call the parent's do_??? routine. Hence, for example
     "return Top::do_get(id, res);"
     
     The UXMO1 object class is maintained by polling. At a pre-defined
     moment the GMS coordinator (see later) kicks the object instance which
     then updates itself. The do_update() method is the one used for this.
     It is this method that provides the interface between the OSI managed
     system and the "real resource". This routine is very much "real
     resource specific. 

     The event report generation mechanism is complex. In do_update() the
     gauge::do_set() method is used to update the gauge value. If the
     threshold has been triggered this will return "On" in which case
     EFDCheck() must be called to check whether any Event Forwarding
     Discriminators exist which are interested in turning the notification
     into an event report. If any dose exist, the make_report() method will
     be called to generate the report - this calls a PEPY generated coder
     for which the source is in UXRepAsn.py.

     The class_initialise() method is called to fill in the fields of the
     MOClassInfo structure for this class. It is called when the first
     instance of the class is initialised and, amongst other things, sets
     up the OID -> integer mapping table referred to above.

     The create() method does what its name suggests. It is referenced from
     the table in create.h which is discussed later.

As noted above, the UXMO1 class is maintained by polling. This is not the
only mechanism available. For example, the OSI Transport layer objects in
../isode_mo are maintained by event reports from Transport protocol
entities which are received via a UDP socket. Another possibility is
illustrated by the UXTime attribute type which is updated only when a CMIS
GET is received. (Note that we cannot treat the nusers attribute in the
same way or the threshold would never work). The "coordinator" function in
the GMS is ultimately responsible for ensuring that polling occurs at the
right times and that incoming messages from "real resources" reach the
appropriate MO instances. Between the coordinator and the MO instances lie
the Knowledge Source (KS) objects. KSs exist to optimise
communication between a set of related MO instances and the corresponding
"real resources". Consider, for example, the case of retrieving information
from the kernel relating to TCP (sic) connections. A KS can be polled
once by the coordinator and can then retrieve the information for all
connections in one kernel read. It can then distribute updates to all the
TCP connection MO instances. Without the KS, each TCP connection would
have to be separately polled and would do its own kernel read. In order for
all this to work, MO instances must register with their KS at create time.
The KS in turn must register with the coordinator.

In the case of UXMO1 there can only ever be one instance, so the KS is
more or less redundant. However, for consistency it must still be present.
It is defined in UXKS.h and derived from the KS class defined in
../gms/GenericKS.h. Its methods are defined in UXKS.cc. The main task of
the  register_object() method is to ask the coordinator to do the polling.
In addition to the polling interval we pass the coordinator a string which
will be passed back to us when the poll occurs. This is done via the
methods of the coordinator object defined in ../gms/Coordinator.h. The
do_poll() method is called by the coordinator when a poll is required.
After some checking this calls the do_update() method for the (single)
object instance.

Once you have completed the definitions and methods for the MO classes,
attribute types and KSs needed for your piece of MIB you place the whole
lot in a library. Simple really!

Finally, let us look at how things get started. In the directory in which
you build your complete system (../sma for example) there should be a copy
of create.cc. You should produce a customised Create.h which specifies what
Object classes are supposed to be present, whether instances of these
should be created at start-up and whether they may be created as a result
of CMIS requests. (They may also be created as a result of some event
within the "real resource" - the opening of a new connection for example.
In this case the KS object will request creation). As the system starts up
it accesses several tables in the "etc" directory which will be familiar to
ISODE aficionados. Amongst these are the three "oidtable" files to which
you must add entries for any new object classes and attributes you create.
Note that MO class names used in Create.h must be identical to those used
in oidtable.oc. The "isobjects" file should also be updated with any OIDs
you add. These tables are used to map between strings and OIDs at various
times as per the Quipu Directory system. Finally there is the "mib.init"
file which contains the initial containment hierarchy for the MIB. Once
these tables have been consulted the initial MO instances will be created
and these will register with KSs and thence with the coordinator. The
managed system will now start to listen for incoming CMIS requests.

The files in the "etc" directory on your system may be managed centrally.
If you want to play around with specifying new objects you may want to have
your own copies of the oidtables and so on. In the ISODE tradition the GMS
code looks for a file called ".<executable filename>_tailor" in your home
directory. An entry in such a file of the form:

	etcpath: <etc pathname>

will cause the GMS to look in <etc pathname> for its table instead of the
usual place.

All I can say now is "good luck"!!

									
	Graham Knight
