Versions Compared

Key

  • This line was added.
  • This line was removed.
  • Formatting was changed.
Comment: Posted Ken Giusti's updates

...

There are two classes (or types) of Schema - those that describe
QmfData objects, and those that describe QmfEvent objects.

...

These types may be represented by the strings "data" and "event",
respectively.

Schema Identifier

Schema are identified by a combination of their package name and class
name. A hash value over the body of the schema provides a revision
identifier. The class SchemaClassId represents this Schema
identifier.

No Format
class SchemaClassId:
      <constructor>( package=<package-name-str>, 
                     class=<class-name-str>,
                     type=<SchemaTypeData|SchemaTypeEvent>)
                     hash=<hash-str, format="%08x-%08x-%08x-%08x">, 
      .getPackageName(): returns <package-name-str>
      .getClassName(): returns <class-name-str>
      .getHashString(): returns <hash-str, "%08x-%08x-%08x-%08x">
      .getType(): returns SchemaTypeObject or SchemaTypeEvent
      .mapEncode(): returns a map encoding of the instance.

If the hash is not supplied, then the default value
"00000000-00000000-00000000-00000000" will be supplied. This may be
the case when a SchemaClass is being dynamically constructed, and a
proper hash is not yet available.

...

Index

Optional

Type

Description

"package_name"

N

string

The name of the associated package.

"class_name"

N

string

The name of the class within the package.

"type"

N

string

The type of schema, either "data" or "event".

"hash_str"

Y

string

The MD5 hash of the schema, in the format "%08x-%08x-%08x-%08x"

Schema

...

For Describing The Properties of Data

The SchemaProperty class represents the description of a single
data item. A SchemaProperty is a list of named attributes and their
values. QMF defines a set of primative attributes. An application
can extend this set of attributes with application-specific
attributes.

All application-specific attributes must be named using the prefix "x-",
and their values must be encoded by an AMQP type.

property datum. Once instantiated, the SchemaProperty is immutable.

No Format
class SchemaProperty:
      <constructor>( name=<name-value>, 
                     type=<type-value>,
                     ...)
      .getName(): name of property (string)
      .getType(): AMQP typecode for encoding/decoding the property data
      .getAccess(): "RC"=read/create, "RW"=read/write, "RO"=read only (default)
      .isIndexisOptional(): True if this property is an index.optional
      .isOptionalgetUnit(): Truestring ifdescribing this property is optionalunits (optional)
      .getUnitgetMin(): string describing units (optional)
      .getMin(): minimum minimum value (optional)
      .getMax(): maximum value (optional)
      .getMaxLen(): maximum length for string values (optional)
      .getDesc(): optional string description of this Property
      .getReferencegetDirection(): if type==objId, name (str) of referenced class"I"=input, "O"=output, or "IO"=input/output
                       (optional)required 
for method arguments, otherwise
   .isParentRef(): True if this property references an object in
            optional)
      .getSubtype(): string indicating the formal whichapplication thistype object
 is in a child-parent
                 for the data, example: "URL",  relationship."Telephone number",
      .mapEncode(): returns a map encoding of the instance.

The map encoding of a SchemaProperty:

Index

Optional

Type

Description

"name"

N

string

The name of the property.

"type"

N

integer

The QMF type code indicating property's data type.

"access"

Y

string

The access allowed to this property, default "RO"

"index"

Y

boolean

True if this property is an index value, default False

"optional"

Y

boolean

True if this property is optional, default False

"unit"

Y

string

Description of the units used to express this property.

"min"

Y

integer

The minimum allowed value for this property

"max"

Y

integer

The maximun allowed value for this property

"maxlen"

Y

integer

For string types, this is the maximum length in
bytes required to represent the longest permittable instance of this string.

"desc"

Y

string

Human-readable description of this property.

"reference"

Y

string

unknown?

"parent_ref"

Y

boolean

True if this property references an object
in which this object is in a child-parent relationship. Default False

Schema for describing a Statistic

The SchemaStatistic class represents the description of a statistic datum. Once instantiated, the SchemaStatistic is immutable.

No Format

class SchemaStatistic:
      <constructor>( name=<name-value>, 
                     type=<type-value>,
                     ... )
      .getName(): name of the statistic (string)
      .getType(): typecode for statistic
      .getUnit(): string describing units (optional)
      .getDesc(): string description of this statistic (optional)
      .mapEncode(): returns a map encoding of the instance.

The map encoding of a SchemaStatistic:

Index

Optional

Type

Description

"name"

N

string

The name of the statistic.

"type"

N

integer

The QMF type code indicating statistic's data type.

"unit"

Y

string

Description of the units used to express this statistic.

"desc"

Y

string

Human-readable description of this statistic.

Schema for describing Method Calls

The Schema for describing a method call involves two classes. The SchemaMethod class describes the method's structure, and contains a SchemaArgument class for each argument declared by the method. An Agent may construct a SchemaMethod's argument list.

               etc.
      .isPolled(): True if changes to the data cannot be practically 
                   monitored by an Agent.  Such a data item can only
                   be queried or polled - not published on change.
      .getReference(): if type==objId, name (str) of referenced class
                       (optional) 
      .isParentRef(): True if this property references an object in
                       which this object is in a child-parent
                       relationship.
      .getAttribute("name"): get the value of the attribute named
          "name". This method can be used to retrieve
          application-specific attributes.  "name" should start with
          the prefix "x-"
      .mapEncode(): returns a map encoding of the instance.

The map encoding of a SchemaProperty's body:

Index

Optional

Type

Description

"qmf_type"

N

integer

The QMF type code indicating property's data type.

"access"

N

string

The access allowed to this property, default "RO"

"optional"

N

boolean

True if this property is optional, default False

"unit"

Y

string

Description of the units used to express this property.

"min"

Y

integer

The minimum allowed value for this property

"max"

Y

integer

The maximun allowed value for this property

"maxlen"

Y

integer

For string types, this is the maximum length in bytes required to represent the longest permittable instance of this string.

"desc"

Y

string

Human-readable description of this property.

"dir"

Y

string

Direction for an argument when passed to a Method call: "I", "O", "IO", default value: "I"

"subtype"

Y

string

Type information for use by the application.

"polled"

Y

boolean

True if this property can only be queried/polled. Default False.

"reference"

Y

string

unknown?

"parent_ref"

Y

boolean

True if this property references an object in which this object is in a child-parent relationship. Default False

"x-"<varies>

Y

Any AMQP type

An application-defined attribute.

Schema For Describing Method Calls

SchemaMethod class identifies the method call and describes its
parameter list. The parameter list is represented by an unordered
map of SchemaProperty entries indexed by parameter name.

No Format

class SchemaMethod:
      <constructor>( name=<name-value>,
                     [args=<map of "name":<SchemaProperty> entries>]
      .getName(): name of method
      .getArgumentCount(): return the number of arguments
      .getArguments(): returns a copy of the map of "name":<SchemaProperty>
      .getArgument("name"): return the SchemaProperty for the parameter "name"

      .addArgument("name", SchemaProperty): adds an additional argument to
No Format

class SchemaMethod:
      <constructor>( name=<name-value>,
                     [args=<list of SchemaArguments>]
      .getName(): name of method
      .getArgCount(): count of arguments
      .getArguments(): returns a list of SchemaArgument instances, one
                  the     for each argumentparameter list.
      .getArgmapEncode(index): returnreturns thea SchemaArgumentmap atencoding indexof 
the      .addArgument(SchemaArgument): adds a SchemaArgument 
      .mapEncode(): returns a map encoding of the instance.

class SchemaArgument:
      <constructor>( name=<name-value>,
                     type=<type-value>,
                     ...)
      .getName(): name of argument
      .getType(): type of argument
      .getDirection(): "I"=input, "O"=output, or "IO"=input/output
      .getUnit(): string describing units (optional)
      .getMin(): minimum value (optional)
      .getMax(): maximum value (optional)
      .getMaxLen(): maximum length for string values (optional)
      .getDesc(): string description of this argument (optional)
      .getDefault(): default value.
      .getRefPackage(): return name of the package referenced by this argument
      .getRefClass(): return name of the class referenced by this argumentSchemaMethod instance

The map encoding of a SchemaMethod:

Index

Optional

Type

Description

"name"

N

string

The name of the method.

"arguments"

Y

map

Map of "name":<SchemaProperty> values, one for each argument to the method.

Note that the "dir" SchemaProperty attribute applies to each
argument. If "dir" is not specified, it is assumed to be "I".

Schema for Data Objects and Events

A top-level data object in QMF is a collection of properties and
methods. Data objects are described by the class SchemaObjectClass.
Data objects may be managed (owned) by an Agent.

Events describe a change within the underlying management system. Unlike
data objects, events do not correspond to a managable entity. They
are composed of a list of arguments that apply to the event. Event
objects are described by the class SchemaEventClass.

Both of these classes derive from the virtual base SchemaClass.

Agent applications may dynamically construct instances of these
objects by adding properties and methods at run time.
However, once the Schema is published, it must be considered
immutable, as the hash value must be constant once the Schema is
in use.

No Format

class SchemaClass:
      <constructor>( package=<package-name-str>, 
                     class=<class-name-str>,
                     type=<SchemaTypeData|SchemaTypeEvent>)
                     hash=<hash-str, format="%08x-%08x-%08x-%08x">)
      .mapEncodegetClassId(): returnsreturn athe mapSchemaClassId encodingthat ofidentifies the instance.

The map encoding of a SchemaArgument:

Index

Optional

Type

Description

"name"

N

string

The name of the argument.

"type"

N

integer

The QMF type code indicating the argument's data type.

"dir"

N

string

Direction for an argument when passed to a Method call: "I", "O", "IO", default value: "I"

"default"

Y

based on "type"

Default value to use if none provided.

"unit"

Y

string

Description of the units used to express this argument.

"min"

Y

integer

The minimum allowed value for this argument

"max"

Y

integer

The maximun allowed value for this argument

"maxlen"

Y

integer

For string types, this is the maximum length in bytes required to represent the longest permittable instance of this string.

"desc"

Y

string

Human-readable description of this argument.

"ref_package"

Y

string

Name of package referenced by this argument.

"ref_class"

Y

string

Name of class referenced by this argument.

The map encoding of a SchemaMethod:

Index

Optional

Type

Description

"name"

N

string

The name of the method.

"arguments"

Y

list

Ordered list of maps, one for each argument to the method.

"desc"

Y

string

Human-readable description of this method.

Schema for Data Objects and Events

A top-level data object in QMF is a collection of statistics, properties, and methods. Data objects are described by the class SchemaObjectClass. Data objects may be managed (owned) by an Agent.

Events describe a change within the underlying management system. Unlike data objects, events do not correspond to a managable entity. They are composed of a list of arguments that apply to the event. Event objects are described by the class SchemaEventClass.

Both of these classes derive from the virtual base SchemaClass.

Agent applications may dynamically construct instances of these objects by adding properties/statistics/methods/etc. at run time.However, once the Schema is published, it must be considered immutable, as the hash value must be constant once the Schema is in use.

No Format

class SchemaClass:
      <constructor>( package=<package-name-str>, this
                      Schema instance.
      .getDesc(): return a human-readable description of this schema.
      .generateHash(): generate a hash over the body of the schema,
                       and return a string representation of the hash
                       in format  "%08x-%08x-%08x-%08x"
      .mapEncode(): returns a map encoding of the instance.


class SchemaObjectClass(SchemaClass):
      <constructor>( package=<package-name-str>, 
                     class=<class-name-str>,
                     type=<SchemaTypeData|SchemaTypeEvent>)
                     hash=<hash-str, format="%08x-%08x-%08x-%08x">,
                     class=<class-name-str>_properties=<map of "name":SchemaProperty instances>,
                     type=<SchemaTypeData|SchemaTypeEvent>)
   _methods=<map of "name":SchemaMethod instances>)
      .getPrimaryKeyList(): return an order list of names of the
    hash=<hash-str, format="%08x-%08x-%08x-%08x">)
      .getClassIdproperty(s): return the SchemaClassId that identifiesare this
used to construct the key for
          identifying unique instances of this   Schema instanceclass.

      .generateHashgetPropertyCount(): generate a hash overreturn the bodynumber of thedata schema,properties.
      .getProperties(): return a map of "name":<SchemaProperty>
          entries for andeach return a string representation ofproperty in the hashobject.
      .getProperty("name"): return the SchemaProperty associated with "name"

      .getMethodCount(): return the number  in format  "%08x-%08x-%08x-%08x"of methods.
      .mapEncodegetMethods(): returnsreturn a map encoding of the instance.


class SchemaObjectClass(SchemaClass):
of "name":<SchemaMethod> entries for
         <constructor>( package=<package-name-str>, 
     each  method in the object.
      .getMethod("name"): return the SchemaMethod associated with the "name"

     class=<class-name-str>,
     .addProperty("name", SchemaProperty): add a new property
      .addMethod("name", SchemaMethod): add a new method.
      type=<SchemaTypeData|SchemaTypeEvent>)
       .appendPrimaryKey("name"): add "name" to the end of the list of
          names used to  hash=<hash-str, format="%08x-%08x-%08x-%08x">,construct the primary key.


class SchemaEventClass(SchemaClass):
      <constructor>( package=<package-name-str>, 
                     _properties=[list of SchemaProperty instances],class=<class-name-str>,
                     type=<SchemaTypeData|SchemaTypeEvent>)
                     _stats=[list of SchemaStatistics instances]hash=<hash-str, format="%08x-%08x-%08x-%08x">,
                     _methodsproperties=[list<map of SchemaMethod instances]"name":SchemaProperty instances>)
      .getPropertyCount(): return the number of data properties.
      .getStatisticCountgetProperties(): return thea numbermap of statistics."name":<SchemaProperty>
      .getMethodCount(): return the number ofentries methods.
for each property    .getProperty(index): return the index'th SchemaPropertyin the event.
      .getStatisticgetProperty(index"name"): return the index'th SchemaStatistic.
      .getMethod(index): return the index'th SchemaMethodSchemaProperty associated with "name"

      .addProperty("name", SchemaProperty): appendadd a new property
      .addStatistic(SchemaStatistic): append a new statistic
      .addMethod(SchemaMethod): append a new method.


class SchemaEventClass(SchemaClass):
      <constructor>( package=<package-name-str>, 
                     class=<class-name-str>,
                     type=<SchemaTypeData|SchemaTypeEvent>)
                     hash=<hash-str, format="%08x-%08x-%08x-%08x">,
                     _arguments=[list of SchemaArgument instances])
      .getArgCount(): return the count of arguments.
      .getArgument(index): return the index'th SchemaArgument.

      .addArgument(SchemaArgument): append a new argument.
.

The map encoding of a SchemaObjectClass:

Index

Optional

Type

Description

"schema_id"

N

map

Map containing the SchemaClassId for this object.

"desc"

Y

string

Human-readable description of this Schema.

"primary_key"

Y

list

Ordered list of property names used to construct the Primary Key.

"properties"

Y

map

Map of "name":<SchemaProperty> values, one for each property in the object.

"methods"

Y

map

Map of "name":<SchemaMethod> values, one for each method in this object.

The map encoding of a SchemaEventClassThe map encoding of a SchemaObjectClass:

Index

Optional

Type

Description

"classschema_id"

N

map

Map containing the SchemaClassId for this object.

"propertiesdesc"

Y

list

string

Human-readable description of this SchemaOrdered list of SchemaProperty maps. One map for each property in this object.

"statisticsproperties"

Y

listmap

Ordered list of SchemaStatistics maps. One map for each statistic in this object.

"methods"

Y

list

Ordered list of SchemaMethod maps. One map for each method in this object.

The map encoding of a SchemaEventClass:

Index

Optional

Type

Description

"class_id"

N

map

Map containing the SchemaClassId for this object.

"arguments"

Y

list

Order list of SchemaArgument maps, one map for each argument in this Map of "name":<SchemaProperty> values, one for each property in the event.

Data Model

The QMF defines three layers of data representation:

...

Arbitrarily structured data is represented by a map of named data
items. There is no schema associated with this data, as its structure
is arbitrary. This class of data is represented by the QmfData class.

Data that has a formally defined structure is represented by the
QmfDescribed class. This class extends the QmfData class by
associating the data with a formal schema.

Managed structured data extends the concept of structured data by
providing an owner for the data. In QMF, this owner is an Agent.
This class of data extends the QmfDescribed class by adding an
identifier of the owning Agent.

...

No Format
class QmfData:
      <constructor>( map of "name"=value"<AMQP Type> pairs, _const=False )

QmfDescribed Class

No Format

class QmfDescribed(QmfData):      .isManaged(): returns False for QmfData instances.
      <constructor>.isDescribed(): classreturns QmfData,False classfor SchemaClassIdQmfData )instances.
      .getSchemaClassIdgetProperty(name): returnsreturn the identifiervalue of the Schemanamed thatproperty
                          data, returns describesNone theif structurenamed of the data.property is
      .getIndex(): return a string composed from "index" property
                   valuesnot present. 
      .getPropertiessetProperty(name, value): returnset athe listvalue of (SchemaProperty, value) pairs
the named
                         for each of the object'sproperty properties.
data.  Creates a new property
       .getStatistics(): return a list of (SchemaStatistics, value)
                      if the named property does not exist.
     pairs for each of the object's statistics.

QmfManaged Class

The QmfManaged class represents a data object that is owned by a particular Agent. All QmfManaged objects contain a unique object identifier.

The QmfManaged class extends the QmfDescribed class:

No Format

class QmfManaged(QmfDescribed):
      .getObjectId(): return ObjectId for this object.
Object Identification

An instance of managed object must be uniquely identified within the management system. Each managed object is given a name that is unique within the domain of the object's managing Agent. Note that these names are not unique across Agents. Therefore, a globally unique name
for an instance of a managed object is the concatenation of the object's name and the managing Agent's name. This unique object identifier is represented by the ObjectId class.

ObjectIds are considered hashable. That is, it is a requirement that ObjectIds are deterministically sortable.

       Raises an exception if _const is True.
      .mapEncode(): returns a map representation of the QmfData
          instance, suitable for use by the constructor.

The map encoding of a QmfData Class is merely a map of the
"name"=<value> property pairs.

QmfDescribed Class

The isDescribed() method of an instance of a QmfDescribed class
returns True. The SchemaCache allows the QmfDescribed instance to
retrieve the instance of the schema identified by SchemaClassId (TBD).

No Format

class QmfDescribed(QmfData)
No Format

class ObjectId:
      <constructor>(agent="agent name",  map of "name"=<AMQP Type> pairs, _const=False,
                    name="object name" _schemaId=<class SchemaClassId>, SchemaCache )
      .getAgentName(): returns <agent name> string.<constructor>( map encoding of a QmfDescribed instance, SchemaCache )
      .getObjectNamegetSchemaClassId(): returns <object name> string the identifier of the Schema that
                            describes the structure of the data.
      .operators(==, !=, <, >) supported.

QmfEvent Class

A QMF Event is a type of QmfDescribed data that is not managed.
Events are notifications that are sent by Agents. Unlike QmfManaged objects, events do not correspond to managed data on the Agent. Instead, an event notifies a Console of a change in some
aspect of the system under managment. For example, an event may indicate that a threshold was exceeded, or a resource was returned. The structure of an event is described by the SchemaEventClass. An instance of an event is represented by the QmfEvent class.

No Format

class QmfEvent(QmfDescribed):
      <constructor>( timestamp, argument_list )
getPrimaryKey(): return a string composed from concantenating
            the values of all properties whose names appear in the schema's
         .getTimestamp(): return a timestamp indicating when the Event
           Primary Key List.  Each value is converted to an AMQP
            string, then concantenated in the order given by the
            schema's Primary Key triggeredList.
      .getArgumentsgetProperties(): return a listmap of (SchemaArgument, value) pairs"name"=<value> pairs for each
      .getArgument(<name>): return the value of argument <name>
             ?tbd? do we need to identifyof the originating Agent?

Data Management

The role of a QMF component determines how it will interact with managment data. Therefore the QmfManaged class is subclassed to provide an Agent specific implementation and a Console specific
implementation.

The Console application represents a managed data object by the QmfConsoleData class. The Console has "read only" access to the statistics and properties in the data object via this class. The Console can also invoke the methods defined by the object via this class. The actual data stored in this object is cached from the Agent. In order to update the cached values, the Console invokes the refresh() method.

Note that the refresh() and invokeMethod() methods require communication with the remote Agent. As such, they may block. For these two methods, the Console has the option of blocking in the call until the call completes. Optionally, the Console can receive a notification asynchronously when the operation is complete. See below for more detail regarding synchronous and asynchronous API calls.

object's properties. 
      .mapEncode(): returns a map representation of the QmfDescribed
        instance, suitable for use by the constructor.

The map encoding of an instance of the QmfDescribed class:

Index

Optional

Type

Description

"schema_id"

N

map

Map containing the SchemaClassId for this object.

"properties"

Y

map

Map of "name"=<value> pairs, one for each property.

QmfManaged Class

The QmfManaged class represents a data object that is owned by a
particular Agent. All QmfManaged objects contain a unique object
identifier.

The isManaged() method of an instance of a QmfManaged class
returns True.

The QmfManaged class extends the QmfDescribed class:

No Format

class QmfManaged(QmfDescribed
No Format

class QmfConsoleData(QmfManaged):
      <constructor>(?tbd?)
 map of "name"=<AMQP Type>  .getTimestamps(): returns a list of timestamps describing the
pairs, _const=False,
                     _schemaId=<class SchemaClassId>, SchemaCache,
        lifecycle of the object:
           _agentId=<class AgentId> )
      <constructor>(     [0] = time of last update from Agent,
  map encoding of a QmfManaged instance, SchemaCache )
      .getObjectId(): return ObjectId for this object.

The map encoding of an instance of the QmfManaged class:

Index

Optional

Type

Description

"schema_id"

N

map

Map containing the SchemaClassId for this object.

"agent_id"

N

map

Map representation of the AgentId value.

"properties"

Y

map

Map of "name"=<value> pairs, one for each property.

Object Identification

An instance of a managed object must be uniquely identified within the
management system. This is done by combining an object's Primary Key
with the identifier for the agent which manages the object.

Each managed object is identified by its Primary Key. The Primary Key
is constructed by concatenating the values of the object's properties
that are named in the schema's Primary Key List.

For example, assume a managed object with the following property map:

No Format

{"field1" : "foo",
 "field2" : "bar",
 "field3" : 42,
 "field4" : "baz"}

and assume the Primary Key List defined by the managed object's schema
is:

No Format

["field1", "field3"]

The Primary Key for this object would be:

No Format

"foo:42"

QMF inserts ":" between each field.

Note that these Primary Key values are not unique across Agents.
Therefore, a globally unique name for an instance of a managed object
is the concatenation of the object's name and the managing Agent's
AgentId. This unique object identifier is represented by the ObjectId class.

ObjectIds are considered hashable. That is, it is a requirement
that ObjectIds are deterministically sortable.

No Format

class ObjectId:
      <constructor>(agentid=class AgentId, 
                    key="primary key string")
      .getAgentId(): returns AgentId
      .getPrimaryKey(): returns the primary key string.
      .operators(==, !=, <, >) supported.
      .mapEncode(): returns a map representation of the ObjectId.

The map encoding of an instance of an ObjectId:

Index

Optional

Type

Description

"agent_id"

N

map

Map representation of the AgentId value.

"primary_key"

N

string

The Primary Key string.

QmfEvent Class

A QMF Event is a type of QmfDescribed data that is not managed.
Events are notifications that are sent by Agents.
Unlike QmfManaged objects, events do not correspond to managed data on the
Agent. Instead, an event notifies a Console of a change in some
aspect of the system under management. For example, an event may
indicate that a threshold was exceeded, or a resource was returned.
The structure of an event is described by the SchemaEventClass. An
instance of an event is represented by the QmfEvent class.

No Format

class QmfEvent(QmfDescribed):
      <constructor>( timestamp, agentId, map of "name"=<AMQP Type> pairs,
                     _const=False, _schemaId=<class SchemaClassId>,
                     SchemaCache )
      <constructor>( map encoding of a QmfEvent instance, SchemaCache )
      .getTimestamp(): return a timestamp indicating when the Event
                       occurred.
      .getAgentId(): return the class AgentId of this issuing agent.

The map encoding of an instance of the QmfDescribed class:

Index

Optional

Type

Description

"schema_id"

N

map

Map containing the SchemaClassId for this object.

"timestamp"

N

AMQP Timestamp

Time the event occurred.

"agent_id"

N

map

Map representation of the AgentId value.

"properties"

Y

map

Map of "name"=<value> pairs, one for each property.

Data Management

The role of a QMF component determines how it will interact with
managment data. Therefore the QmfManaged class is subclassed
to provide an Agent specific implementation and a Console specific
implementation.

The Console application represents a managed data object by the
QmfConsoleData class. The Console has "read only" access to the
properties in the data object via this class. The
Console can also invoke the methods defined by the object via this
class. The actual data stored in this object is cached from the
Agent. In order to update the cached values, the Console invokes the
refresh() method.

Note that the refresh() and invokeMethod() methods require
communication with the remote Agent. As such, they may block. For
these two methods, the Console has the option of blocking in the call
until the call completes. Optionally, the Console can receive a
notification asynchronously when the operation is complete. See below
for more detail regarding synchronous and asynchronous API calls.

No Format

class QmfConsoleData(QmfManaged):            [1] = creation timestamp 
                        [2] = deletion timestamp, or zero if not deleted.
      .isDeleted(): True if deletion timestamp not zero.
      .refresh([reply-handle | timeout]getTimestamps(): requestreturns thata thelist Agent
of timestamps describing the
                 update the value of this object's contents.
 lifecycle of    .invokeMethod(name, inArgs[], [[reply-handle] | [timeout]]): 
     the object:
                     invoke the named method.
      .getStatistic(name): return the value of the named statistic [0] = time of last update from Agent,
      .getProperty(name): return the value of the named property.

The Agent that manages the data represents it by the QmfAgentData class. The Agent is responsible for managing the values of the properties and statistics within the object, as well as
servicing the object's method calls. Unlike the Console, the Agent has full control of the state of the object.

No Format

class QmfAgentObject(QmfObject):
      <constructor>( ObjectId, ?tbd?)
  [1] = creation timestamp .destroy():
 mark the object as deleted by setting the deletion
               [2] = deletion timestamp, toor zero theif currentnot timedeleted.
      .setObjectIdisDeleted(ObjectId): setTrue theif valuedeletion oftimestamp thenot ObjectIdzero.
      .setProperty(name, value): refresh([reply-handle | timeout]): request that the Agent
                    update the value of this theobject's propertycontents.
      .setStatisticinvokeMethod(name, value, inArgs{}, [[reply-handle] | [timeout]]): set
 the value of a statistic.
      .incStatistic(name, delta): add the delta to the statistic.
      .decStatistic(name, delta): subtractinvoke the delta from the statistic.
      ?tbd?

Note that some languages will allow properties, statistics, and methods to act as attributes of the QmfObject itself. As an example, assume an QmfConsoleObject exists with a property named "state". In python, it will be possible to access the value of "state" as if it where an attribute of the QmfConsoleObject. The following two statements are equivalent:

named method.

The Agent that manages the data represents it by the
QmfAgentData class. The Agent is responsible for managing the
values of the properties within the object, as well as
servicing the object's method calls. Unlike the Console, the Agent
has full control of the state of the object.

No Format

class QmfAgentData(QmfManaged):
      .destroy(): mark the object as deleted by setting the deletion
    
No Format

           print("My state is '%s'" %
              timestamp to the myQmfConsoleObject.getProperty("state"))
current time.
      .setProperty(name, value): update the  print("My state is '%s'" %
         value of the property.
      .incProperty(name, delta): add the delta to the property
        myQmfConsoleObject.state)

Be aware - a QmfConsoleObject provides read-only access, so the
following statement would be illegal:

No Format

      .decProperty(name, delta): subtract the delta from the property
     myQmfConsoleObject.state = "up" ?tbd?
Invoking Methods

A managed object's methods provide a mechanisms for a Console application to
perform a "remote procedure call" against the object. The method
actually executes on the Agent, and the result is passed back to the
Console on completion.

The value(s) returned to the Console when the method call completes
are represented by the MethodResult class. The MethodResult class
indicates whether the method call succeeded or not, and, on success,
provides access to all data returned by the method call.

Should a method call result in a failure, this failure is indicated by
the presence of a QmfData object in the MethodResult. This object is
described as an "exception", and contains a description of the reason
for the failure. There are no returned arguments parameters when a method call
fails.

A successful method invokation is indicated by the absence of an
exception in the MethodResult. In addition, a map of returned argument
parameter values may be present. The structure of the returned
arguments parameters is described by the SchemaArgument list associated with the MethodSchema that defines the SchemaMethod for the method.
The map contains only those arguments parameters that the SchemaArgument SchemaMethod marks
with an "output" direction.

No Format
class MethodResult:
      <constructor>( QmfData <exception> | <argument-map> )
      .getException(): returns exception data if method fails.<map of properties> )
      .getArgumentCountgetException(): returns exception data numberif ofmethod argumentsfails.
      .getArguments(): returns a listmap of (SchemaArgument, value) "name"=<value> pairs
                       forof eachall returned argumentarguments.
      .getArgument(<name>): returns value of argument named "name".

...

A Query is a mechanism for interrogating the management database. A
Query represents a selector which is sent to an Agent. The Agent
applies the Query against the management database, and
returns those objects which meet the constraints contained in the query.

...

The target for a Query is determined by the constructor. When a Query
is created using a SchemaClassId, it will match against the
SchemaClass identified by that key. When a Query is created using an
ObjectId, it will match against the QmfObject or Event identified by
that ObjectId. When a Query is created with only a package name, it
will return all class names that belong to that package. If both the
package and class names are provided, the Query will match against the
SchemaClassId identified by the combination of those names.

...

A subscription is a mechanism for monitoring management data for
changes in its state. A Console creates a subscription with an Agent
based on a Query. The Query specifies the set of management data that
is to be monitored. When the Agent detects changes to the selected
set, a notification is sent to the subscribing Console(s). A
Subscription is represented by the SubscriptionId class. A Console
must cancel the subscription when the console no longer needs to
monitor the data.

No Format
class SubscriptionId:
      ?tbd?

...

An Agent is uniquely identified by an AgentId. An AgentId is a
three-tuple containing:

  • the name of the vendor that produced the agent
  • the name of the product using the agent
  • the name of the agent component within the product.

This naming convention allows for a single product to host multiple
distinct Agents. The Agent identifier is represented by the AgentId
class. An AgentId is considered hashable. That is, it is a
requirement that AgentIds are deterministically sortable.

...

By convention, AgentIds are specified as a string containing the
vendor, product, and name strings separated by colons ":", in that
order. For example: "company.com:OurProduct:AnAgent"

...

A QMF console component is represented by a Console class. This class
is the topmost object of the console application's object model.

...

The connection to the AMQP bus is used to communicate with remote
Agents. The queue is used as a source for notifications coming from
remote Agents.

Asychronous event model.

The original QMF API defined a set of callback methods that a Console
application needed to provide in order to process asynchronous QMF
events. Each asynchonous event defined its own callback method.

The new API replaces this callback model with a work-queue approach.
All asynchronous events are represented by a WorkItem object. When
a QMF event occurs it is translated into a WorkItem object and placed
in a FIFO queue. It is left to the console application to drain
this queue as needed.

This new API does require the console application to provide a single
callback. The callback is used to notify the console application that
WorkItem object(s) are pending on the work queue. This callback is
invoked by QMF when the work queue transitions from the empty to the
non-empty state. To avoid any potential threading issues, the console
application is not allowed to call any QMF API from within the
callback context. The purpose of the callback is to allow the console
application to schedule itself to drain the work queue at the next
available opportunity.

For example, a console application may be designed using a select()
loop. The application waits in the select() for any of a number
of different descriptors to become ready. In this case, the callback
could be written to simply make one of the descriptors ready, and then
return. This would cause the application to exit the wait state, and
start processing pending events.

The callback is represented by the Notifier virtual base class. This
base class contains a single method. A console application derives a
custom handler from this class, and makes it available to the Console
object.

No Format
class Notifier:
    .indication():  Called when the internal work queue becomes
    non-empty due to the arrival of one or more WorkItems. This method
    will be called by the internal QMF management thread - it is
    illegal to invoke any QMF APIs from within this callback.  The
    purpose of this callback is to indicate that the application
    should schedule itself to process the work items.  

...

The console application maintains a list of all known remote Agents.
Each Agent is represented by the Agent class:

...

The Console class is the top-level object used by a console
application. All QMF console functionality is made available by this
object. A console application must instatiate one of these objects.

As noted below, some Console methods require contacting a remote
Agent. For these methods, the caller has the option to either block
for a (non-infinite) timeout waiting for a reply, or to allow the
method to complete asynchonously. When the asynchronous approach is
used, the caller must provide a unique handle that identifies the
request. When the method eventually completes, a WorkItem will be
placed on the work queue. The WorkItem will contain the handle that
was provided to the corresponding method call.

All blocking calls are considered thread safe - it is possible to have
a multi-threaded implementation have multiple blocking calls in flight
simultaineously.

If a name is supplied, it must be unique across all Consoles attached
to the AMQP bus. If no name is supplied, a unique name will be
synthesized in the format: "qmfc-<hostname>.<pid>"

...

The following pseudo-code performs a non-blocking query for all
agents. It completes when at least one agent is found.

...

A QMF agent component is represented by a instance of the Agent
class. This class is the topmost object of the agent application's
object model. Associated with a particular agent are

...

The Agent class communicates with the application using the same
notification-based model as the console. The agent maintains a
work-queue of pending requests. Each pending request is
associated with a handle. When the application is done servicing the
work request, it passes the response to the agent along with the
handle associated with the originating request.

An agent can support one of two different models for managing its
object database: internal or external store.

...

An agent that implements internal object store takes full
responsibility for managing its associated objects. In this model,
the application passes a reference for each managed objects to the
agent. The agent manages the set of objects internally, directly
accessing the contents of the object in order to service console
requests.

With this model, the application's complexity is reduced. The
application needs to instantiate the object and register it with the
agent. The application also maintains a reference to the object, as
the application is responsible for updating the object's properties and the statistics
as necessary.

The application must also service method calls invoked on the object.
The agent notifies the application when a method call has been
requested by a console. The application services the method call,
passing the result of the method back to the agent. The agent then
relays the response to the originating console.

The application may decide to delete an object instance. The
application does this by invoking the destroy() method on the object.
This notifies the agent, which will mark the object as deleted in its
database. Once the application invokes the destroy() method on an
object, it must no longer access the object. The agent will clean up
the object at a later point in time.

Internal object store is the default model for agent object
managment.

Data Consistency

The internal object store requires sharing of the managed data
between the agent and the application. The application is responsible
for keeping the data up to date, while the agent is responsible for
providing the data to client consoles. It is likely that these
components may be implemented in separate execution contexts. This
raises the possibility that a data item could be in the process of
being written to by the application at the same moment the agent
attempts to read it. This would result in invalid data being read.

To prevent this from occuring, the QmfAgentObject class provides
accessors for all property and statistic data in the object. These accessors provide
atomic access to the underlying data. Therefore, both the agent and
the application code must use these accessors to manipulate a shared
object's data.

External Object Store

An alternate agent implementation allows the application to take
full responsibility for managing the objects. With this model, all
instances of managed objects exist external to the agent. When a
console requests an action against an object, that action is
transferred from the agent to the application. The application then
must process the request, and send the result to the agent. The agent
then sends a reply to the requesting console.

The model gives full control of the managed objects to the
application, but usually requires more application development work.

...

The base class for the agent object is the Agent class. This base
class represents a single agent implementing internal store.

...

The AgentExternal class must be used by those applications that
implement the external store model. The AgentExternal class extends
the Agent class by adding interfaces that notify the application when
it needs to service a request for management operations from the
agent.

No Format
class AgentExternal(Agent):
      <constructor>(vendor, product, name, class Notifier)
      .allocObjectId( name="object name"): create a class ObjectId
            using the object name provided.  The object name must be
            unique across all objects known to this agent.  Returns a
            class ObjectId.  Once this method returns, the agent will
            service requests from consoles referencing this ObjectId.
      .freeObjectId( class ObjectId ): releases the ObjectId
            previously allocated by allocObjectId() method.  Once
            this call is complete, the agent will reject all further
            requests from consoles referencing this ObjectId.
      .queryResponse( handle=<handle from WorkItem>,
                      class QmfAgentObject,
                      prop=<True | False>,
                      stat=<True | False>): send a managed object in
 WorkItem>,
                reply to a received query.  Ifclass (propQmfAgentObject),: send object'sa managed object in 
            properties.reply If (stat), send object's statistics.  Note
    to a received query. Note that ownership of the
        that ownership of the object instance is returned to the
 caller on return from
        caller on return from this call. 
      .queryComplete( handle=<handle from WorkItem>, 
                      result=<status code> ):  Indicate to the agent
            that the application has completed processing a query request.
            Zero or more calls to the queryResponse() method should be
            invoked before calling queryComplete().  If the query should
            fail - for example, due to authentication error - the result
            should be set to a non-zero error code ?TBD?.
      .subscriptionResponse( handle=<handle from WorkItem>,
                             result=<status code>,
                             subscription_handle=<application context>):
            Indicate the status of a subscription request.  If result
            is zero, the subscription is accepted by the application,
            and an subscription handle is provided.  This handle must
            be passed to the application when the agent unsubscribes.

...

The Agent uses the same notification driven work queue model as the
Console. In the Agent case, the WorkItem supports the following set
of work types:

  • METHOD_CALL
  • QUERY
  • SUBSCRIBE
  • UNSUBSCRIBE

In the case of an internal store agent implementation, only the
METHOD_CALL work item is generated. An external store agent must support
all work item types.

No Format
  METHOD_CALL parameters: ( name=<method name>, 
                            [argument list],
                            class ObjectId,
                            user_id=<authenticated id of the user> )

The METHOD_CALL WorkItem describes a method call that must be serviced by the
application on behalf of this agent. On completion of the
method call, the application must invoke the agent's
methodResponse() method.

...

The QUERY WorkItem describes a query that the application must
service. The application should call the queryResponse() method for
each object that satisfies the query. When complete, the application
must call the queryComplete() method. If a failure occurs, the
application should indicate the error to the agent by calling the
queryComplete() method with a description of the error.

...

The SUBSCRIBE WorkItem provides a query that the application should
monitor until the subscription is cancelled. On receipt of this
WorkItem, the application should call the subscriptionResponse() agent
method to acknowledge the response. Whenever the matching objects are
updated, the application should call queryResponse() for each updated
object, followed by a call to queryComplete() when done. The
subscription remains in effect until an UNSUBSCRIBE WorkItem for the
subscription is received.

...

Alerts the application that the corresponding subscription has been
cancelled. The application should no longer supply query updates
against the subscribed query.

...

11/20/2009 - First Revision
11/24/2009 - Added agent classes
12/01/2009 - Cleaned up Schema api and added map definitions.
12/04/2009 - Removed distinction between properties and statistics.
Object identification now based on Primary Key List.
Added more map definitions.