
            REPORT ON THE OSIMIS GMS API CHANGES TO SUPPORT:
CONDITIONAL PACKAGES, FULL ERRORS, ATOMICITY AND ASYNCHRONOUS FEATURES
----------------------------------------------------------------------

This is a short report on the OSIMIS GMS API changes to support
the future introduction of conditional packages, atomicity and asynchronous
features and to allow user-defined error parameters to be returned in
processing failure errors.


GENERAL API ENHANCEMENT
-----------------------

Managed object attributes in OSIMIS are held as an array of Attr* in every
class and can be accessed through the integer index the GDMO compiler produces:

uxObj1::createRR
    // ...
    ((Gauge*) _attrs[I_nUsers]) -> setType(OV_INTEGER);

The problem with that approach is that explicit typing is lost and the
implementor has to cast it back to the actual type. This is both tedious
and also dangerous if wrong casting is forced that will manifest itself
at runtime as a coredump in the best case or as obscure behaviour in the worst.
The GDMO compiler back-end has now been modified to produce inline methods
with the name of an attribute which return the actual type, so the above
code could be written as:

uxObj1::createRR
    // ...
    nUsers() -> setType(OV_INTEGER);

Errors will be cought at compile time and this tedious casting is not needed.
This is an incremental change and implementors are strongly encouraged
to use this way of dereferencing attributes.


CONCEPTUAL ADDITIONS / MODIFICATIONS
------------------------------------

The support for conditional packages requires full access to meta-class
information for an object instance before the latter is created. Such
information may be also used to optimise the creation of objects by
checking name bindings before creation etc. It is also in line with the
architectural principle that wants meta-class information separate
from managed object instances and possibly available also to semantic free
managing applications such as browsers etc.
As a result of the above, the meta-class object instances (of C++ class
MOClassInfo) should be initialised first and linked in a tree that mirrors
the inheritance one at run time e.g. evForwDiscr -> discr -> top.

The other three aspects, namely error parameters, atomicity and asynchronous
API features dictate the enhancement of the current polymorphic GMS API
with additional parameters.


API CHANGES
-----------

The first API change relates to the information present in class definitions
in the header file that tells the GMS which MO classes an application will
use e.g. Sma.h for the SMA application.

In the past, the class name and pointers to static creation methods
were used. The latter are now part of the MOClassInfo meta-object for the
class which acts as a "factory" in the ObjectiveC/Smalltalk sense.
As such, the information now used is the class name and pointers to methods
that will return the meta-class object and will initialise it.
A concrete example:

Old style:

{   "uxObj1",           uxObj1::cmisCreate,     uxObj1::create },
{   "uxObj2",           uxObj2::cmisCreate,     uxObj2::create },


New style:

//  classes specific to this application i.e. SMA

{ "uxObj1",             uxObj1::getClassInfo,   uxObj1::initialiseClass },
{ "uxObj2",             uxObj2::getClassInfo,   uxObj2::initialiseClass },


The meta-class object for a class is now called _classInfo and it is
of type MOClassInfo* instead of MOClassInfo . This is used in createRR
to complete the class initialisation for aspects that the GDMO compiler
cannot know and elsewhere to access other class information (attr OIDs etc.)
The old style of refering to the meta-class object using the _info variable
(an aggregate MOClassInfo type) is still available but it will not be
supported in future versions, so implementors are encouraged to migrate
to the use of _classInfo now.



OLD POLYMORPHIC GMS API (ICM versions up to 3.3x)
-------------------------------------------------

The old GMS polymorphic API and the current one are shown below with
the changes discussed afterwards. It is noted there has been an intermediate
MIDAS version 3.4 in between with a few of the final changes - this
is not discussed in this document as it is a MIDAS issue.


static  int		<MO>::makeRdnAndSuperior (RDN&, MO*&);

virtual int             MO::createRR (void* genParm = NULLVD);
virtual int             MO::deleteRR (void* genParm = NULLVD);

virtual CMISErrors      MO::refreshSubordinates ();
virtual CMISErrors      MO::refreshSubordinate (RDN rdn);

virtual int             MO::get (int attrId, int classLevel);
virtual CMISErrors      MO::set (CMISModifyOp setMode,
                                int attrId, int classLevel, void* attrValue);
virtual CMISErrors      MO::action (int attrId, int classLevel,
                                void* actionInfo, void** actionReply);

virtual int             MO::buildReport (int attrId, int classLevel,
                                PE* report);


NEW POLYMORPHIC GMS API (version 3.5)
-------------------------------------

static  RDN	<MO>::makeRdn (MO*);

virtual int     MO::createRR (AVA*& errorInfo, void* genParm = NULLVD);
virtual int     MO::deleteRR (AVA*& errorInfo, void* genParm = NULLVD,
                                Bool checkOnly);

virtual int     MO::refreshSubordinates (AVA*& errorInfo,
                                         int operationId = -1);
virtual int     MO::refreshSubordinate (RDN rdn, AVA*& errorInfo,
                                         int operationId = -1);

virtual int     MO::get (int attrId, int classLevel, AVA*& errorInfo,
                        Bool checkOnly = False, int operationId = -1);
virtual int     MO::set (CMISModifyOp setMode, int attrId, int classLevel,
                        void* attrValue, AVA*& errorInfo,
                        Bool checkOnly = False, int operationId = -1);
virtual int     MO::action (int attrId, int classLevel, void* actionInfo,
                        void*& actionReply, Bool& freeFlag, AVA*& errorInfo,
                        Bool checkOnly = False, int operationId = -1);

virtual int     MO::buildReport (int eventId, int classLevel,
                        void*& report, Bool& freeFlag);


THE STATIC MAKERDN METHOD
-------------------------

The previous makeRdnAndSuperior method is now called makeRdn
and returns only the RDN as the GMS finds the superior
according to the name binding(s). The MO* argument is the superior
managed object. This may be needed in the case of a class with
multiple name bindings and possibly more than one naming attributes.
In this case, the class may need to know where it is created in order
to construct the RDN accordingly. This is a rather esoteric feature
but OSIMIS provides it nevertheless - in most circumstances this
argument will not be used.



DISCUSSION OF THE OTHER CHANGES
-------------------------------

Return value
------------

The return value for all the polymorphic methods is of type int.
Allowed values are OK (success) and NOTOK (failure) at present.
ASYNC in the future will be used to denote that the operation will
take place in asynchronous fashion.


Elimination of PEs and double pointers
--------------------------------------

The buildReport primitive was the last place where explicit ASN.1
manipulation was visible to application implementors. The GMS now
takes care of such details and the report data structure is passed instead.

On a cosmetic level, arguments passed by reference to be created within
the method are now passed as double pointers (** - C-style) but as
references to pointers (*& - C++ style). This affects the
actionReply old argument and is the case with many new arguments of this
nature.


Additional arguments
--------------------

First of all, all the new arguments are AFTER the old ones in each primitive
in the following order according to functionality:

1. any additional arguments to give more flexibility to the old methods
   without adding new functionality: the boolean freeFlag (of type Bool&)

2. any additional arguments to enable the better reporting of errors:
   the errorInfo flag (of type AVA*&)
 
3. any additional arguments to enable the GMS to exercise atomicity:
   the checkOnly boolean flag (of type Bool)
 
4. any additional arguments to enable the GMS to handle asynchronous replies:
   the operationId integer flag (of type int)
 

The free flag gives more flexibility as to how GMS deals with action reply
and event report structures. The default value is True which means that
the GMS will free them if the action/buildReport code does not set it
to False. The latter case is useful when converting old buildReport methods
to the new style as in the old case the MO was responsible for freeing
the event report structure.

In the past, the createRR/deleteRR/get/set/action methods could not
return any information with processing failure errors. In addition,
createRR could not tell the GMS in the case of invalid/missingAttributeValue
errors which attribute caused the problem. This is now fixed through the
errorInfo parameter which may contain:

a. a CMISError code
b. an identifier i.e. a name as registered in oidtable.at
c. an arbitrary value i.e. a Attr* with a value corresponding to the identifier

a. should always be present when a NOTOK is returned to tell the
GMS what error it was and the allowed values are:

createRR: invalidAttributeValue, missingAttributeValue, processingFailure
deleteRR: processingFailure
get:      processingFailure
set:      invalidAttributeValue, invalidOperation, processingFailure
action:   invalidArgumentValue, processingFailure
refreshSubordinate(s):
          processingFailure

With processingFailure one could pass b./c. to inform the remote
application of what exactly went wrong. If not supplied, the GMS
fills in general values (not saying much) as these are mandatory for CMIS.
b. should be supplied in the case of createRR invalid/missingAttributeValue
errors. Note that the methods allocate space for the error info which
is freed by the GMS. Some examples:

uxObj1::createRR
    // ..
    // no value passed as the identifier says it all
    err = new AVA(m_processingFailure, "singleInstanceClass");

    // it could have been though
    // (assume singleInstanceClass/GraphicString binding):
    err = new AVA(m_processingFailure, "singleInstanceClass",
                  new String("an instance of uxObj1 already exists!"));

monitorMetric::createRR
    // ..
    // not supplied
    err = new AVA(m_missingAttributeValue, "observedObjectInstance");

    // ..
    // supplied but with a wrong name (non-existing)
    err = new AVA(m_invalidAttributeValue, "observedObjectInstance");

monitorMetric::set
    // ..
    // trying to set a threshold with administrativeState unlocked
    err = new AVA(m_invalidOperation);


The parameter for atomicity is a boolean checkOnly flag. For the moment
it could be more or less ignored as the GMS does not support atomicity (yet)
but ideally code should be written using it now so that it becomes immediately
functional when the GMS is enhanced.

If you don't want to bother, add in the beginning of your method
(after the call of the same parent method):

    if (checkOnly)
        return NOTOK;   // don't need to set the error in this case

This will refuse atomic requests for this class. If though you want
to support atomicity, check if the request can be performed but do
not do it, simply return OK or NOTOK. Look at uxObj1/uxObj2 and
scanner/monitorMetric classes as examples.

The only difference to this style holds for the deleteRR method
which should call the parent class deleteRR last (destruction from
the leaf of the inheritance branch):

int <moclass>::deleteRR (AVA*& err, void* info, Bool checkOnly, int)
{
    if (!checkOnly) {
	// do what you were doing before here
    }
    else {
	// check if you can be destructed and if not return NOTOK
    }

    return <parentclass>::deleteRR(err, info, checkOnly);
}


Finally, the operationId parameter could be ignored for all classes
using the synchronous GMS interface i.e. all! It will be used by
classes using the asynchronous API when the latter becomes available.


