Versions Compared

Key

  • This line was added.
  • This line was removed.
  • Formatting was changed.
Comment: Migrated to Confluence 5.3

...

No Format
class QmfData:
      <constructor>( _values=map of "name"=<AMQP Type> pairs, 
                     _subtypes=optional map of "name"=<AMQP String> pairs for subtype information,
                     _tag=optional, application-specific tag applied to this QmfData instance
                     _object_id=optional AMQP string that uniquely identifies this QmfData instance.
                     _schema=optional <class SchemaClass> reference
                     _const=False )
      <constructor>( _map=map representation of QmfData, as generated by mapEncode() method, 
                     _schema=optional <class SchemaClass> reference
                     _const=False)
      .isManagedis_managed(): returns True if object identifier string assigned, else False.
      .isDescribedis_described(): returns True if schema is associated with this instance
      .getTagget_tag(): return this object's tag if present, else None
      .getValueget_value(name): return the value of the named data item, returns None if named property is not present.
      .hasValuehas_value(name): returns True if the named data item is present in the map, else False.
      .setValueset_value(name, value, subType=None): set the value of the named data item. Creates a new item if the named data does not exist. Raises an exception if _const is True. 
      .getSubTypeget_subtype(name): returns the sub type description string, else None if not present. 
      .setSubTypeset_subtype(name, subType): set or modify the subtype associated with name.
      .get_object_id(): returns the object id string associated with the object instance, or None if no id assigned.
      .get_schema_class_id: returns the identifier of the Schema that describes the structure of the data, or None if no schema.
      .mapEncodemap_encode(): returns a map representation of the QmfData instance, suitable for use by the constructor.

...

No Format
class QmfEvent(QmfData):
      <constructor>( timestamp, 
                     _severity=<string>,
                     _values=map of "name"=<AMQP Type> pairs,
                     _subtypes=optional map of "name"=<AMQP String> pairs for subtype information,
                     _tag=optional, application-specific tag applied to this QmfEvent instance
                     _schema=optional <class SchemaEventClass> )
       <constructor>( _map= map encoding of a QmfEvent instance, 
                     _schema=optional <class SchemaEventClass> )
      .get_timestamp(): return a timestamp indicating when the Event occurred.
      .get_severity(): return the severity associated with the Event.
      .map_encode(): return a map encoding of the Event.

...

No Format
class SchemaClassId:
      <constructor>( package=<package-name-str>, 
                     class=<class-name-str>,
                     type=<SchemaTypeData|SchemaTypeEvent>)
                     hash=<hash-str, format="%08x-%08x-%08x-%08x">, 
      .getPackageNameget_package_name(): returns <package-name-str>
      .getClassNameget_class_name(): returns <class-name-str>
      .getHashStringget_hash_string(): returns <hash-str, "%08x-%08x-%08x-%08x">
      .getTypeget_type(): returns SchemaTypeObject or SchemaTypeEvent
      .mapEncodemap_encode(): returns a map encoding of the instance.

...

No Format
class SchemaProperty:
      <constructor>( name=<name-value>, 
                     type=<type-value>,
                     ...)
      .getTypeget_type(): AMQP typecode for encoding/decoding the property data
      .getAccessget_access(): "RC"=read/create, "RW"=read/write, "RO"=read only (default)
      .isOptionalis_optional(): True if this property is optional
      .getUnitget_unit(): string describing units (optional)
      .getMinget_min(): minimum value (optional)
      .getMaxget_max(): maximum value (optional)
      .getMaxLenget_max_len(): maximum length for string values (optional)
      .getDescget_desc(): optional string description of this Property
      .getDirectionget_direction(): "I"=input, "O"=output, or "IO"=input/output (required for method arguments, otherwise optional)
      .getSubtypeget_subtype(): string indicating the formal application type for the data, example: "URL", "Telephone number", etc.
      .isPolledis_polled(): 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.
      .getReferenceget_reference(): if type==objId, name (str) of referenced class (optional) 
      .isParentRefis_parent_ref(): True if this property references an object in which this object is in a child-parent relationship.
      .getAttributeget_attribute("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-"
      .mapEncodemap_encode(): returns a map encoding of the instance.

...

No Format
class SchemaMethod:
      <constructor>( [args=<map of "name":<SchemaProperty> entries>],
                     desc="description of the method")
      .getDescget_desc(): return human-readable description of the method.
      .getArgumentCountget_argument_count(): return the number of arguments
      .getArgumentsget_arguments(): returns a copy of the map of "name":<SchemaProperty>
      .getArgumentget_argument("name"): return the SchemaProperty for the parameter "name"

      .addArgumentadd_argument("name", SchemaProperty): adds an additional argument to the parameter list.
      .map_encode(): returns a map encoding of the SchemaMethod instance

...

No Format
class SchemaClass(QmfData):
      <constructor>( classId=<class SchemaClassId>, 
                     _desc=optional AMQP string containing a human-readable description for this schema)
      .getClassIdget_class_id(): return the SchemaClassId that identifies this Schema instance.
      .generateHashgenerate_hash(): generate a hash over the body of the schema, and return a string representation of the hash in format  "%08x-%08x-%08x-%08x"

...

No Format
class SchemaObjectClass(SchemaClass):
      <constructor>( classId=<class SchemaClassId>, 
                     _desc=optional AMQP string containing a human-readable description for this schema,
                     _props=map of "name"=<SchemaProperty> instances,
                     _meths=map of "name"=<SchemaMethod> instances,
                     _id_names=(optional) ordered list of "name"s used to identify the properties whose values are used to construct the object identifier)

      .get_id_names(): return an ordered list of names of the values that are used to construct the key for identifying
          unique instances of this class.  Returns None if no list defined.
      .getPropertyCountget_property_count(): return the count of SchemaProperty's in this instance.
      .getPropertiesget_properties(): return a map of "name":<SchemaProperty> entries for each value in the object.
      .getPropertyget_property("name"): return the SchemaProperty associated with "name", else None if "name" value does not exist.

      .getMethodCountget_method_count(): return the count SchemaMethod's in this instance.
      .getMethodsget_methods(): return a map of "name":<SchemaMethod> entries for each method associated with the object.
      .getMethodget_method("name"): return the SchemaMethod associated with the "name", else None if "name" does not exist or is not a method.

      .addPropertyadd_property("name", SchemaProperty): add a new property.
      .addMethodadd_method("name", SchemaMethod): add a new method.
      .set_id_names([name-list]): set the value of the order list of names to use when constructing the object identifier.

...

No Format
class SchemaEventClass(SchemaClass):
      <constructor>( classId=<class SchemaClassId>,
                     _desc=optional AMQP string containing a human-readable description for this event,
                     _props=map of "name":SchemaProperty instances)
      .getPropertyCountget_property_count(): return the number of properties.
      .getPropertiesget_properties(): return a map of "name":<SchemaProperty> entries for each property in the event.
      .getPropertyget_property("name"): return the SchemaProperty associated with "name".

      .addPropertyadd_property("name", SchemaProperty): add a new property.

...

Subscriptions

A subscription is a mechanism for monitoring allows a Console application to monitor specific 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 The Agent will periodically publish updates to the subscribing Console(s). A
Subscription is represented by the SubscriptionId class. A Console
must   The update contains a snapshot of the of the monitored data. 

A subscription remains in effect for a predetermined amount of time.  Once the subscription expires, no further updates are published.  A console may elect to refresh a subscription prior to its expiration.   Alternatively, a Console may explicitly cancel the subscription when the console data no longer needs to
monitor the data.

No Format

class SubscriptionId:
      ?tbd?

be monitored.

Invoking Methods

QMF allows a Console application to perform a "remote procedure call" on the Agent. The procedure - or method - call executes on the Agent. On completion a result is passed back to the Console. Method calls can be associated with an instance of a data object, or applied to the Agent as a whole.

...

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 WorkItem class represents a single notification event that is read from the work queue:

...

No Format
class QmfConsoleData(QmfData):
      .get_timestamps(): returns a list of timestamps describing the
                        lifecycle of the object.  All timestamps are
                        represented by the AMQP timestamp type.
                        [0] = time of last update from Agent,
                        [1] = creation timestamp 
                        [2] = deletion timestamp, or zero if not deleted.
      .get_create_time(): returns the creation timestamp
      .get_update_time(): returns the update timestamp
      .get_delete_time(): returns the deletion timestamp, or zero if not yet deleted.
      .is_deleted(): True if deletion timestamp not zero.

      .refresh([reply-handle | timeout]): request that the Agent update the value of this object's contents.
      .invoke_method(name, inArgs{}, [[reply-handle] | [timeout]]): invoke the named method on this instance.

...

  • AGENT_ADDED
  • AGENT_DELETED
  • NEW_PACKAGE
  • NEW_CLASS
  • OBJECT_UPDATE
  • EVENT_RECEIVED
  • AGENT_HEARTBEAT
  • SUBSCRIBE_RESPONSE
  • RESUBSCRIBE_RESPONSE
  • SUBSCRIPTION_INDICATION

These WorkItem types are described in detail below:

...

OBJECT_UPDATE

TBD.

EVENT_RECEIVED

TBD

Local representation of a remote Agent.

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

SUBSCRIBE_RESPONSE

The SUBSCRIBE_RESPONSE WorkItem returns the result of a subscription request made by this Console.  This WorkItem is generated when the Console's create_subscription() is called in an asychronous manner, rather than pending for the result. 

The get_params() method of a SUBSCRIBE_RESPONSE  WorkItem will return an instance of the following object:

No Format

class SubscribeParams
No Format

class Agent:
      .get_subscription_nameid(): returnsIf the identifying name string of the agent.  This name is used to send AMQP messages directly to this agent.
      .isActive(): returns True if the agent is alive (heartbeats have not timed out) subscription is successful, this method returns a SubscriptionId object.
          Should the subscription fail, this method returns None, and get_error() can be used to obtain an
          application-specific QmfData error object.
      .invokeget_publish_method(name, inArgs{}, [[reply-handle] | [timeout]]): invoke the named method against the agent.
 interval(): returns the time interval in seconds on which the Agent will publish updates
     .enable_events(): allows reception of events fromfor this agentsubscription.
      .disableget_eventslifetime(): prevents reception of events from this agent.
      .destroy(): releases this Agent instance.  Once called, the console application should not reference this instance againreturns the time interval in seconds for the subscription. The subscription will automatically
          expire after this interval if not renewed by the console.
      ?tbd?

The Console Object.

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 under the given domain. If no name is supplied, a unique name will be synthesized in the format: "qmfc-<hostname>.<pid>"

.get_error(): (optional) returns an application-specific QmfData object indicating why the subscription
          request failed.  Returns None if not supported.
      .get_console_handle(): returns the console handle as passed to the create_subscription() call.

The SubscriptionId object must be used when the subscription is refreshed or cancelled - it must be passed to the Console's refresh_subscription() and cancel_subscription() methods.  The value of the SubscriptionId does not change over the lifetime of the subscription.

The console handle will be provided by the Agent on each data indication event that corresponds to this subscription.  It should not change for the lifetime of the subscription.

The get_handle() method returns the reply handle provided to the create_subscription() method call.  This handle is merely the handle used for the asynchronous response, it is not associated with the subscription in any other way.

Once a subscription is created, the Agent that maintains the subscription will periodically issue updates for the subscribed data.  This update will contain the current values of the subscribed data, and will appear as the first SUBSCRIPTION_INDICATION WorkItem for this subscription.

SUBSCRIPTION_INDICATION

The SUBSCRIPTION_INDICATION WorkItem signals the arrival of an update to subscribed data from the Agent. 

The get_params() method of a SUBSCRIPTION_INDICATION  WorkItem will return an instance of the following object:

No Format

class SubscribeIndication:
      .get_console_handle(): returns the console handle as passed to the create_subscription() call.
      .get_data(): returns a list containing all updated data objects associated with the subscripion.

The get_handle() method returns None.

RESUBSCRIBE_RESPONSE

The RESUBSCRIBE_RESPONSE WorkItem is generated in response to a subscription refresh request made by this Console.  This WorkItem is generated when the Console's refresh_subscription() is called in an asychronous manner, rather than pending for the result. 

The get_params() method of a RESUBSCRIBE_RESPONSE  WorkItem will return an instance of the following object:

No Format

class SubscribeParams:
      .get_subscription_id(): If the re-subscription is successful, this method returns an instance of
          the original SubscriptionId object.  Should the subscription fail, this method returns None,
          and get_error() can be used to obtain an application-specific QmfData error object.
      .get_publish_interval(): returns the time interval in seconds on which the Agent will publish updates
          for this subscription.
      .get_lifetime(): returns the time interval in seconds for the subscription. The subscription will automatically
          expire after this interval if not renewed by the console.
      .get_error(): (optional) returns an application-specific QmfData object indicating why the re-subscription
          request failed.  Returns None on successful resubscribe.
      .get_console_handle(): returns the console handle as passed to the create_subscription() call, if available.
No Format

class Console:
      <constructor>(name=<name-str>, 
                    domain=(optional) domain string for console's AMQP address,
                    notifier=<class Notifier>,
                    reply_timeout=<default for all blocking calls>,
                    agent_timeout=<default timeout for agent heartbeat>,
                    subscription_duration=<default lifetime of a subscription>)

      .destroy(timeout=None): Must be called to release Console's resources.

      .addConnection(QPID Connection): Connect the console to the AMQP cloud.

      .removeConnection(conn): Remove the AMQP connection from the console.  Un-does the addConnection() operation, and
          releases any agents associated with the connection.  All blocking methods are unblocked and given a failure status.
          All outstanding asynchronous operations are cancelled without producing WorkItems.

      .getAddress():
          Get the AMQP address this Console is listening to (type str).

      .find_agent( name string, [timeout] ): Query for the presence of a specific agent in the QMF domain. Returns a 
          classNote: Agent if the agentAgent isfailed present.the resubscribe Ifrequest thedue agentto isan not already known to the consoleunrecognized subscription, this call will send may
          a query for the agent and block (with default timeout override) waiting for a response.
return None.

The get_handle() method returns the reply handle provided to the refresh_subscription() method call.  This handle is merely the handle used for the asynchronous response, it is not associated with the subscription in any other way.

Local representation of a remote Agent.

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

No Format

class Agent:
      .enableget_agent_discovery( [Query] name(): Calledreturns tothe enableidentifying thename asynchronousstring Agentof Discoverythe processagent.  This name Onceis enabled, AGENT_ADDED
       used to send AMQP messages directly to this agent.
   and AGENT_DELETED work items can arrive on .is_active(): returns True if the WorkQueue.agent is Ifalive a(heartbeats queryhave isnot supplied, it will be used to filter agent 
          notifications.

timed out)
      .invoke_method(name, inArgs{}, [[reply-handle] | [timeout]]): invoke the named method against the agent.
      .disableenable_agent_discoveryevents(): allows Calledreception toof disableevents thefrom asyncthis Agentagent.
 Discovery process enabled by calling enableAgentDiscovery.disable_events().:  

      .getWorkItemCount(): Returns the countprevents reception of pendingevents WorkItemsfrom that can be retrieved. 
this agent.
      .getNextWorkItemdestroy([timeout=0]): Obtainsreleases thethis next pending work item, or None if none available. 

      .releaseWorkItem(wi): Releases a WorkItem instance obtained by getNextWorkItem(). Called when the application has finishedAgent instance.  Once called, the console application should not reference this instance again.
      ?tbd?

The Console Object.

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 under the given domain. If no name is supplied, a unique name will be synthesized in the format: "qmfc-<hostname>.<pid>"

No Format

class Console:
      <constructor>(name=<name-str>,
                 processing the WorkItem. 

      .getAgents(): Returns a list of available agents (class Agent)

      .getAgent( name string ): Return the class Agent for the named agent, if known. 

      .getPackages( [class Agent] ): Returns a list of the names of all known packages.  If an optional Agent is provided, then
       domain=(optional) domain string onlyfor thoseconsole's packagesAMQP availableaddress,
 from that Agent are returned.

      .getClasses( [class Agent] ):  Returns a list of SchemaClassIds for all available Schema.  If an optional Agent is provided,
notifier=<class Notifier>,
                    then the returned SchemaClassIds are limited to those Schema known to the given Agent.

reply_timeout=<default for all blocking calls>,
               .getSchema( class SchemaClassId [, class Agent]): Return a list of all available class SchemaClass across all known agents.
 agent_timeout=<default timeout for agent heartbeat>,
                  If an optional Agent is provided, restrict the returned schema to those supported by that Agentsubscription_duration=<default lifetime of a subscription>)

      .destroy(timeout=None): Must be called to release Console's resources.

      .getObjectsadd_connection( _SchemaClassId= | _package=, _class= |
   QPID Connection): Connect the console to the AMQP cloud.

      .remove_connection(conn): Remove the AMQP connection from the console.  Un-does the _object_identifier=,add_connection() operation, and
          releases any agents associated with the connection.   [timeout=],
        All blocking methods are unblocked and given a failure status.
           [list-of-class-Agent] ): perform a blocking query for QmfConsoleObjects.  Returns a list (possibly empty) of matching
All outstanding asynchronous operations are cancelled without producing WorkItems.

      .get_address():
          Get the AMQP objects.address Thethis selectorConsole foris thelistening queryto may be either:(type str).

      .find_agent( name string, [timeout] ): *Query classfor SchemaClassIdthe -presence allof objectsa whosespecific schemaagent matchin the schemaQMF identifieddomain. by _SchemaClassId parameter.Returns a
          class *Agent package/classif namethe -agent allis objectspresent. whose schemaIf arethe containedagent byis thenot namedalready packageknown andto class.
the console, this call will send
      * the object identified by _object_identifier
           This method will block until all known agents reply, or the timeout expires. Once the timeout expires, all
   a query for the agent and block (with default timeout override) waiting for a response.

      .enable_agent_discovery( [Query] ): Called to enable the asynchronous Agent Discovery process. Once enabled, AGENT_ADDED
          and AGENT_DELETED work dataitems retrievedcan toarrive dateon isthe returnedWorkQueue.  If a list ofquery agents is supplied, thenit thewill querybe isused sentto tofilter onlyagent
 those agents.  


      notifications.createSubscription(

 class Query [, duration=<secs> [, list of agents]  .disable_agent_discovery(): createsCalled ato subscriptiondisable using the givenasync Query.Agent Discovery Ifprocess aenabled listby of agentscalling enable_agent_discovery().

      .get_workitem_count(): Returns the count of ispending provided,WorkItems thethat Querycan will apply only to those agents. Otherwise it will apply to all active agents, including
    be retrieved.

      .get_next_workitem([timeout=0]): Obtains the next pending work item, or None if none available.

      those discovered during the lifetime of the subscription. The duration argument can be used to override the
.release_workitem(wi): Releases a WorkItem instance obtained by getNextWorkItem(). Called when the application has finished
          processing the  console's default subscription lifetime for this subscription. WorkItem.

      .get_agents(): Returns a list of available agents (class SubscriptionId.Agent)

      .refreshSubscriptionget_agent( SubscriptionIdname [, duration=<secs>] string ): (re)activates a subscription.  UsesReturn the class Agent for the console default durationnamed agent, if known.

      .get_packages( [class Agent] ): Returns a list unlessof the names durationof isall explicitlyknown specified.

      .cancelSubscription( SubscriptionId ): terminates the given subscription. 

Example Console Application

The following pseudo-code performs a blocking query for a particular agent.

No Format

logging.info( "Starting Connection" )
conn = Connection("localhost")
conn.connect()

logging.info( "Starting Console" )
myConsole = Console()
myConsole.addConnection( conn )

logging.info( "Finding Agent" )
myAgent = myConsole.findAgent( "com.aCompany.Examples.anAgent", _timeout=5 )

if myAgent:
   logging.info( "Agent Found: %s" % myAgent )
else:
   logging.info( "No Agent Found!")

logging.info( "Removing connection" )
myConsole.removeConnection( conn )

logging.info( "Destroying console:" )
myConsole.destroy( _timeout=10 )

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

No Format

class MyNotifier(Notifier):
    def __init__(self, context):packages.  If an optional Agent is provided, then
          only those packages available from that Agent are returned.

      .get_classes( [class Agent] ):  Returns a list of SchemaClassIds for all available Schema.  If an optional Agent is provided,
          then the returned SchemaClassIds are limited to those Schema known to the given Agent.

        self.get_myContextschema( =class context
SchemaClassId [, class Agent]): Return a list of self.WorkAvailableall =available False

class SchemaClass across all def indication(self):
known agents.
          If print("Indication received! context=%d" % self._myContext)
        self.WorkAvailable = True

noteMe = MyNotifier( 668 )

logging.info( "Starting Connection" )
conn = Connection("localhost")
conn.connect()

myConsole = Console(notifier=noteMe)
myConsole.addConnection( conn )

myConsole.enableAgentDiscovery()
logging.info("Waiting...")


while not noteMe.WorkAvailable:
    print("No work yet...sleeping!")
    time.sleep(1)


print("Work available = %d items!" % myConsole.getWorkItemCount())
wi = myConsole.getNextWorkitem(timeout=0)
while wi:
    print("work item %d:%s" % (wi.getType(), str(wi.getParams())))
    wi = myConsole.getNextWorkitem(timeout=0)


logging.info( "Removing connection" )
myConsole.remove_connection( conn )

logging.info( "Destroying console:" )
myConsole.destroy( 10 )

Agent Application Model

This section describes the API that is specific to Agent components.

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 set of objects managed by that agent
  • the set of schema that describes the structured objects owned by the agent
  • a collection of consoles that are interfacing with the agent

The Agent class communicates with the application using the same work-queue 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.

QmfAgentData Class

The Agent manages the data it represents by the QmfAgentData class - a derivative of the QmfData 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(QmfData):an optional Agent is provided, restrict the returned schema to those supported by that Agent.

      .get_objects( _SchemaClassId= | _package=, _class= |
                    _object_identifier=,
                   [timeout=],
                   [list-of-class-Agent] ): perform a blocking query for QmfConsoleObjects.  Returns a list (possibly empty) of matching
           objects. The selector for the query may be either:
           * class SchemaClassId - all objects whose schema match the schema identified by _SchemaClassId parameter.
           * package/class name - all objects whose schema are contained by the named package and class.
           * the object identified by _object_identifier
           This method will block until all known agents reply, or the timeout expires. Once the timeout expires, all
           data retrieved to date is returned. If a list of agents is supplied, then the query is sent to only those agents.

      .destroycreate_subscription(): markagent, theclass object as deleted by setting the deletion timestamp to the current time.
Query, console_handle [, reply_handle] [, timeout],
            .setValue(name, value): update the value of the property.
      .incValue(name, delta): add the delta   [, publish_interval] [, lifetime] ):  creates a subscription to the propertyagent
          using the given .decValue(name, delta): subtract the delta from the property
      ?tbd?

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

Internal Object Store

An agent that implements internal object store gives full responsibility for managing its data objects to the QMF infrastructure. In this model, the application passes a reference for each managed object to the QMF 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 as necessary.

However, the application must still service method calls. 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 could result in invalid data being read.

To prevent this from occuring, the QmfAgentObject class provides accessors for all 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.

Agent Class

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

Query.  The console_handle is an application-provided handle that will accompany each subscription update
          send from the Agent.  Subscription updates will appear as SUBSCRIPTION_INDICATION WorkItems on the Console's work queue.
          The publish_interval is the requested time interval in seconds on which the Agent should publish updates.  The lifetime
          parameter is the requested time interval in seconds for which this subscription should remain in effect.  Both the
          requested lifetime and publish_interval may be overridden by the Agent, as indicated in the subscription response.
          This method may be called asynchronously by providing a reply_handle argument.  When called asynchronously, the result
          of this method call is returned in a SUBSCRIBE_RESPONSE WorkItem with a handle matching the value of reply_handle.
          Timeout can be used to override the console's default reply timeout.  When called synchronously, this method returns a class
          SubscribeParams object containing the result of the subscription request.

      .refresh_subscription( SubscriptionId [, lifetime] [,reply_handle] [, timeout] ): renews a subscription identified by
          SubscriptionId.  The Console may request a new subscription duration by providing a requested lifetime. This
          method may be called asynchronously by providing a reply_handle argument. When called asynchronously, the result
          of this method call is returned in a SUBSCRIBE_RESPONSE WorkItem.  Timeout can be used to override the console's
          default reply timeout.  When called synchronously, this method returns a class SubscribeParams object containing
          the result of the subscription request.

      .cancel_subscription( SubscriptionId ): terminates the given subscription.

Example Console Application

The following pseudo-code performs a blocking query for a particular agent.

No Format

logging.info( "Starting Connection" )
conn = Connection("localhost")
conn.connect()

logging.info( "Starting Console" )
myConsole = Console()
myConsole.add_connection( conn )

logging.info( "Finding Agent" )
myAgent = myConsole.find_agent( "com.aCompany.Examples.anAgent", _timeout=5 )

if myAgent:
   logging.info( "Agent Found: %s" % myAgent )
else:
   logging.info( "No Agent Found!")

logging.info( "Removing connection" )
myConsole.remove_connection( conn )

logging.info( "Destroying console:" )
myConsole.destroy( _timeout=10 )

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

No Format

class MyNotifier(Notifier):
    def __init__(self, context):
        self._myContext = context
        self.WorkAvailable = False

    def indication(self):
        print("Indication received! context=%d" % self._myContext)
        self.WorkAvailable = True

noteMe = MyNotifier( 668 )

logging.info( "Starting Connection" )
conn = Connection("localhost")
conn.connect()

myConsole = Console(notifier=noteMe)
myConsole.add_connection( conn )

myConsole.enable_agent_discovery()
logging.info("Waiting...")


while not noteMe.WorkAvailable:
    print("No work yet...sleeping!")
    time.sleep(1)


print("Work available = %d items!" % myConsole.getWorkItemCount())
wi = myConsole.get_next_workitem(timeout=0)
while wi:
    print("work item %d:%s" % (wi.getType(), str(wi.getParams())))
    wi = myConsole.get_next_workitem(timeout=0)


logging.info( "Removing connection" )
myConsole.remove_connection( conn )

logging.info( "Destroying console:" )
myConsole.destroy( 10 )

Agent Application Model

This section describes the API that is specific to Agent components.

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 set of objects managed by that agent
  • the set of schema that describes the structured objects owned by the agent
  • a collection of consoles that are interfacing with the agent

The Agent class communicates with the application using the same work-queue 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.

QmfAgentData Class

The Agent manages the data it represents by the QmfAgentData class - a derivative of the QmfData 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(QmfData):
      .destroy(): mark the object as deleted by setting the deletion timestamp to the current time.
      .set_value(name, value): update the value of the property.
      .inc_value(name, delta): add the delta to the property
      .dec_value(name, delta): subtract the delta from the property
      ?tbd?

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

Internal Object Store

An agent that implements internal object store gives full responsibility for managing its data objects to the QMF infrastructure. In this model, the application passes a reference for each managed object to the QMF 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 as necessary.

However, the application must still service method calls. 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 could result in invalid data being read.

To prevent this from occuring, the QmfAgentObject class provides accessors for all 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.

Agent Class

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

No Format

class Agent:
      <constructor>( name=<name-string>,
                     domain=(optional) domain string for agent's AMQP address,
                     notifier=class Notifier,
                     heartbeat_interval=30,
                     max_msg_size=0)
      .get_name(): return the name string of the agent.
      .set_connection( QPID Connection ): connect the agent to the AMQP cloud.
      .register_object_class( class SchemaObjectClass ): Register a schema for an object class with the agent.  The agent must
            have a registered schema for an object class before it can handle objects of that class.
      .register_event_class( class SchemaEventClass ) : Register a schema for an event class with the agent.  The agent must
            have a registered schema for an event class before it can handle events of that class.
      .raise_event( class QmfEvent ): Cause the agent to raise the given event.
      .add_object( class QmfAgentData ): passes a reference to an instance of a managed QMF object to the agent. The object's
          name must uniquely identify this object among all objects known to this agent.
      .get_workitem_count(): Returns the count of pending WorkItems that can be retrieved.
      .get_next_workitem([timeout=0]): Obtains the next pending work item, or None if none available.
      .release_workitem(wi): Releases a WorkItem instance obtained by get_next_workitem(). Called when the application has finished
No Format

class Agent:
      <constructor>( name=<name-string>,
                     domain=(optional) domain string for agent's AMQP address,
                     notifier=class Notifier,
          processing the WorkItem.
         heartbeat_interval=30.method_response(name="method name",
                     max_msg_size=0)
  handle=<handle from WorkItem>,
  .get_name(): return the name string of the agent.
      .setConnection( QPID Connection ): connect the agent to the AMQP cloud. out_args={output argument map}
      .registerObjectClass( class SchemaObjectClass ): Register a
            schema for an object class with the agent.  The agent must
       error=<QmfData> ): Indicate to the agent that the application has completed processing a method
     have a registered schema for an object class before it can
        request. See the description handleof objectsthe METHOD_CALL WorkItem.

AgentExternal Class

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):of that class.
      .registerEventClass( class SchemaEventClass ) : Register a
<constructor>(name=<name-string>,
                     schemadomain=(optional) domain string for an event class with the agent.  The agent must
agent's AMQP address,
                    notifier= haveclass aNotifier,
 registered schema for an event class before it can
           heartbeat_interval=30,
 handle events of that class.
      .raise_event( class QmfEvent ): Cause the agent to raise the max_msg_size=65535)
      .alloc_object_id( name="object name"): indicate to QMF that giventhe event.
named object is available to be managed.addObject( class QmfAgentDataOnce ):
this method returns,
          passesthe aagent referencewill toservice anrequests instancefrom ofconsoles areferencing managed QMF objectthis data.
      .free_object_id( name="object name" ): indicate to QMF tothat the agent.named The object's nameis mustno uniquelylonger identifyavailable this
to be managed.
      .query_response( handle=<handle from WorkItem>,
 object among all objects known to this agent.
      .getWorkItemCount(): Returns the count of pending WorkItems that
 class QmfAgentObject): send a managed object in reply to a received can be retrievedquery.
 Note that ownership of  .getNextWorkItem([timeout=0]): Obtains the next pending work
the object
          instance is returned to the caller on item,return orfrom None if none available. this call.
      .releaseWorkItem(wi): Releases a WorkItem instance obtained by
query_complete( handle=<handle from WorkItem>,
                 getNextWorkItem(). Called when the application has finished
 result=<status code> ):  Indicate to the agent that the application has completed processing a thequery WorkItemrequest. 
      .method_response(name="method name",
   Zero or more calls to the queryResponse() method should be invoked before calling query_complete().  If the query should
  handle=<handle from WorkItem>,
      fail - for example, due to authentication error - the result should be set to a  out_args={output argument map}non-zero error code ?TBD?.

      .subscription_response( handle=<handle from WorkItem>,
              error=<QmfData> ): Indicate to the agent
            that the application has completed processing a method
console_handle=<handle provided by Console for this subscription>,
               request. See the description of the METHOD_CALL WorkItem.

AgentExternal Class

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>(name=<name-string>subscription_handle=<agent-provided context>,
                     domain=(optional) domain string for agent's AMQP address        lifetime=<seconds>, publish_interval=<seconds>,
                    notifier= class Notifier,
       error=<QmfData>): Indicate the result of a SUBSCRIBE_REQUEST WorkItem.
      heartbeat_interval=30,
    If the subscription request is successful, the Agent application must provide a unique subscription_handle.   max_msg_size=65535)If replying
      .allocObjectId( name="object name"): indicate to QMFa thatsucessful thesubscription namedrefresh, objectthe isoriginal availablesubscription_handle tomust be managedsupplied.  The Once this method returns, the agent will service requests from consoles referencing this data.
      .freeObjectId( name="object name" ): indicate to QMF that the named object is no longer available to be managed.
lifetime parameter should be
          set to the duration of the subscription in seconds.  The publish_interval should be set to the time interval in seconds
          between .queryResponse( handle=<handle from WorkItem>,
          successive publications on this subscription.  If the subscription or refresh fails, the subscription_handle
          should be classset QmfAgentObject):to sendNone aand managederror objectmay inbe 
set to an application-specific QmfData instance that describes the error.  Should
 reply to a received query. Note that ownership of the
a refresh request fail, the console_handle may be set to None if objectunknown.

 instance is returned to the caller on return from
            this call.  .subscription_indicate(console_handle, [list of subscribed data]): Send a list of updated subscribed data to the Console.

      .queryCompletesubscription_cancel( handle=<handle from WorkItem>, 
console_handle): Acknowledge a Subscription                   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>,Cancel WorkItem.

Asychronous Event Model.

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

  • METHOD_CALL
  • QUERY
  • SUBSCRIBE_REQUEST
  • RESUBSCRIBE_REQUEST
  • UNSUBSCRIBE_REQUEST

Note Well: 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.

METHOD_CALL

The METHOD_CALL WorkItem describes a method call that must be serviced by the application on behalf of this agent.

The get_params() method of a METHOD_CALL WorkItem will return an instance of the following object:

No Format

class MethodCallParams:
      .get_name(): returns a string containing the name of the method call.
      .get_object_id(): returns the identifier for the object on which this
          method needs to be invoked.  Returns None iff there is no associated
          object (a method call against the agent itself).
      .get_args(): returns a map of  result=<status code>,input arguments for the method. Arguments
          are in "name"=<value> pairs.  Returns None if no arguments are  supplied.
       subscription_handle=<application context>.get_user_id():
 returns authenticated user id of caller if present,    Indicate the status of a subscription request.  If result
           else None.

On completion of the method call, the application must provide the result of the call to the Agent. This is done by invoking the Agent's method_response() method. The method_response() method must be passed the handle from the METHOD_CALL WorkItem.

On successful completion of a method call, any output arguments from the method call must be passed in the out_args map parameter, in name=<value> pairs. The error parameter must be set to None.

If the method call fails the application must indicate the failure by passing a QmfData instance via the error parameter. The structure of this QmfData is application-specific, and meant to provide a description of the failure to the console.

QUERY

No Format

  QUERY parameters: ( class Query is zero, the subscription is accepted by the application,
            and an subscription handle is provided.  This handle must
 user_id=<authenticated id of the        be passed to the application when the agent unsubscribes.

Asychronous Event Model.

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

  • METHOD_CALL
  • QUERY
  • SUBSCRIBE
  • UNSUBSCRIBE

Note Well: 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.

METHOD_CALL

The METHOD_CALL WorkItem describes a method call that must be serviced by the application on behalf of this agent.

The get_params() method of a METHOD_CALL WorkItem will return an instance of the following object:

user> )

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

SUBSCRIBE_REQUEST

The SUBSCRIBE_REQUEST WorkItem provides a query that the agent application must periodically publish until the subscription is cancelled or expires. On receipt of this WorkItem, the application should call the Agent::subscription_response() method to acknowledge the request. On each publish interval, the application should call Agent::subscription_indicate(), passing a list of the objects that satisfy the query. The subscription remains in effect until an UNSUBSCRIBE_REQUEST WorkItem for the subscription is received, or the subscription expires.

The get_params() method call of the SUBSCRIBE_REQUEST WorkItem returns an instance of the following object:

No Format

class SubscriptionParams:
No Format

class MethodCallParams:
      .get_name(): returns a string containing the name of the method call.
      .get_object_id(): returns the identifier for the object on which this 
          method needs to be invoked.  Returns None iff there is no associated 
          object (a method call against the agent itself).
      .get_console_argshandle(): returns athe maphandle ofthat inputthe argumentsconsole foruses theto method.identify Argumentsthis subscription.
          areThis handle in "name"=<value> pairs.  Returns None if no arguments are suppliedmust be passed along with every published update from the Agent.
      .get_user_idquery(): returns authenticated user id of caller if present, else None.

On completion of the method call, the application must provide the result of the call to the Agent. This is done by invoking the Agent's method_response() method. The method_response() method must be passed the handle from the METHOD_CALL WorkItem.

On successful completion of a method call, any output arguments from the method call must be passed in the out_args map parameter, in name=<value> pairs. The error parameter must be set to None.

If the method call fails the application must indicate the failure by passing a QmfData instance via the error parameter. The structure of this QmfData is application-specific, and meant to provide a description of the failure to the console.

QUERY

No Format

  QUERY parameters: ( class Query,  the QmfQuery object associated with the subscription.
      .get_publish_interval(): returns the requested time interval in seconds for updates.  Returns
          zero if the Agent's default interval should be used.
      .get_lifetime(): returns the requested lifetime for the subscription.  Zero if the Agent's
          default subscription lifetime should be used.
      .get_user_id(): returns authenticated user_ id=<authenticated of idConsole ofif thepresent, user>else )None.

The QUERY WorkItem describes a query that the Agent application must
service. The application should call the queryResponseAgentExternal::subscription_response() 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.

SUBSCRIBE

in response to this WorkItem.

The get_handle() WorkItem method returns the reply handle which should be passed to the Agent's subscription_response() method.

RESUBSCRIBE_REQUEST

The RESUBSCRIBE_REQUEST is sent by a Console to renew an existing subscription.  The Console may request a new duration for the subscription, otherwise the previous lifetime interval is repeated.

The get_params() method call of the RESUBSCRIBE_REQUEST WorkItem returns an instance of the following object:

No Format

class ResubscribeParams:
    .get_subscription_id(): returns the subscription identifier provided by the Agent.
    .get_lifetime(): returns the requested lifetime for the subscription.  Zero if the previous
No Format

  SUBSCRIBE parameters: ( class Query, 
                    interval should be used.
    .get_user_id=<authenticated(): returns the authenticated user id of the user> ) Console if present, else None.

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.

UNSUBSCRIBE

No Format

  UNSUBSCRIBE parameters: ( <handle associated with subscription> )

Agent application must call the AgentExternal:subscription_reponse method in response to this WorkItem.

The get_handle() WorkItem method returns the reply handle which should be passed to the Agent's subscription_reponse() method

UNSUBSCRIBE_REQUEST

The UNSUBSCRIBE_REQUEST is sent by a Console to terminate an existing subscription.

The get_params() method call returns the subscription identifier assigned by the Agent when the subscription is created.

The Agent application should terminate the given subscription if it exists, and cancel sending any further updates against itAlerts the application that the corresponding subscription has been
cancelled. The application should no longer supply query updates
against the subscribed query.