You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@qpid.apache.org by tr...@apache.org on 2010/01/11 21:46:07 UTC
svn commit: r898057 [2/3] - in /qpid/branches/qmfv2/qpid/python/qmf:
qmfAgent.py qmfCommon.py qmfConsole.py test/agent_test.py
test/console_test.py
Modified: qpid/branches/qmfv2/qpid/python/qmf/qmfCommon.py
URL: http://svn.apache.org/viewvc/qpid/branches/qmfv2/qpid/python/qmf/qmfCommon.py?rev=898057&r1=898056&r2=898057&view=diff
==============================================================================
--- qpid/branches/qmfv2/qpid/python/qmf/qmfCommon.py (original)
+++ qpid/branches/qmfv2/qpid/python/qmf/qmfCommon.py Mon Jan 11 20:46:07 2010
@@ -34,11 +34,10 @@
## Constants
##
-AMQP_QMF_TOPIC = "amq.topic"
-AMQP_QMF_DIRECT = "amq.direct"
-AMQP_QMF_NAME_SEPARATOR = "/"
-AMQP_QMF_AGENT_LOCATE = "amq.topic/agent.locate"
-AMQP_QMF_AGENT_INDICATION = "amq.topic/agent.ind"
+
+AMQP_QMF_AGENT_LOCATE = "agent.locate"
+AMQP_QMF_AGENT_INDICATION = "agent.ind"
+
AMQP_QMF_SUBJECT = "qmf"
AMQP_QMF_VERSION = 4
@@ -49,6 +48,7 @@
query = "query"
package_info = "package_info"
schema_id = "schema_id"
+ schema = "schema"
class OpCode(object):
@@ -108,26 +108,71 @@
##==============================================================================
-## Agent Identification
+## Addressing
##==============================================================================
-class AgentId(object):
+class QmfAddress(object):
"""
- Uniquely identifies a management agent within the entire management domain.
-
- Map format:
- map["vendor"] = str, name of vendor of the agent
- map["product"] = str, name of product using agent
- map["name"] = str, name of agent, unique within vendor and product.
+ TBD
+ """
+ TYPE_DIRECT = "direct"
+ TYPE_TOPIC = "topic"
+
+ ADDRESS_FMT = "qmf.%s.%s/%s"
+ DEFAULT_DOMAIN = "default"
+
+
+ def __init__(self, name, domain, type_):
+ self._name = name
+ self._domain = domain
+ self._type = type_
+
+ def _direct(cls, name, _domain=None):
+ if _domain is None:
+ _domain = QmfAddress.DEFAULT_DOMAIN
+ return cls(name, _domain, type_=QmfAddress.TYPE_DIRECT)
+ direct = classmethod(_direct)
+
+ def _topic(cls, name, _domain=None):
+ if _domain is None:
+ _domain = QmfAddress.DEFAULT_DOMAIN
+ return cls(name, _domain, type_=QmfAddress.TYPE_TOPIC)
+ topic = classmethod(_topic)
+
+
+ def get_address(self):
+ return str(self)
+
+ def __repr__(self):
+ return QmfAddress.ADDRESS_FMT % (self._domain, self._type, self._name)
+
+
+
+
+class AgentName(object):
+ """
+ Uniquely identifies a management agent within the management domain.
"""
_separator = ":"
- def __init__(self, vendor, product, name):
+
+ def __init__(self, vendor, product, name, str_=None):
"""
Note: this object must be immutable, as it is used to index into a dictionary
"""
- self._vendor = vendor
- self._product = product
- self._name = name
+ if str_:
+ # construct from string representation
+ if _str.count(AgentId._separator) < 2:
+ raise TypeError("AgentId string format must be 'vendor.product.name'")
+ self._vendor, self._product, self._name = param.split(AgentId._separator)
+ else:
+ self._vendor = vendor
+ self._product = product
+ self._name = name
+
+
+ def _from_str(cls, str_):
+ return cls(None, None, None, str_=str_)
+ from_str = classmethod(_from_str)
def vendor(self):
return self._vendor
@@ -138,15 +183,8 @@
def name(self):
return self._name
- def mapEncode(self):
- _map = {}
- _map["vendor"] = self._vendor
- _map["product"] = self._product
- _map["name"] = self._name
- return _map
-
def __cmp__(self, other):
- if not isinstance(other, AgentId) :
+ if not isinstance(other, AgentName) :
raise TypeError("Invalid types for compare")
# return 1
me = str(self)
@@ -162,40 +200,10 @@
return (self._vendor, self._product, self._name).__hash__()
def __repr__(self):
- return self._vendor + AgentId._separator + \
- self._product + AgentId._separator + \
+ return self._vendor + AgentName._separator + \
+ self._product + AgentName._separator + \
self._name
- def __str__(self):
- return self.__repr__()
-
-
-
-def AgentIdFactory( param ):
- """
- Factory for constructing an AgentId class from various sources.
-
- @type param: various
- @param param: object to use for constructing AgentId
- @rtype: AgentId
- @returns: a new AgentId instance
- """
- if type(param) == str:
- if param.count(AgentId._separator) < 2:
- raise TypeError("AgentId string format must be 'vendor:product:name'")
- vendor, product, name = param.split(AgentId._separator)
- return AgentId(vendor, product, name)
- if type(param) == dict:
- # construct from map encoding
- if not "vendor" in param:
- raise TypeError("requires 'vendor' value")
- if not "product" in param:
- raise TypeError("requires 'product' value")
- if not "name" in param:
- raise TypeError("requires 'name' value")
- return AgentId( param["vendor"], param["product"], param["name"] )
- raise TypeError("Invalid type for AgentId construction")
-
##==============================================================================
@@ -203,451 +211,293 @@
##==============================================================================
-
-class ObjectId(object):
- """
- An instance of managed object must be uniquely identified within the
- management system. Each managed object is given a key that is unique
- within the domain of the object's managing Agent. Note that these
- keys are not unique across Agents. Therefore, a globally unique name
- for an instance of a managed object is the concatenation of the
- object's key and the managing Agent's AgentId.
-
- Map format:
- map["agent_id"] = map representation of AgentId
- map["primary_key"] = str, key for managed object
- """
- def __init__(self, agentid, name):
- if not isinstance(agentid, AgentId):
- raise TypeError("requires an AgentId class")
- self._agentId = agentid;
- self._name = name;
-
- def getAgentId(self):
- """
- @rtype: class AgentId
- @returns: Id of agent that manages the object.
- """
- return self._agentId
-
- def getPrimaryKey(self):
- """
- @rtype: str
- @returns: Key of managed object.
- """
- return self._name
-
- def mapEncode(self):
- _map = {}
- _map["agent_id"] = self._agentId.mapEncode()
- _map["primary_key"] = self._name
- return _map
-
- def __repr__(self):
- return "%s:%s" % (self._agentId, self._name)
-
- def __cmp__(self, other):
- if not isinstance(other, ObjectId) :
- raise TypeError("Invalid types for compare")
-
- if self._agentId < other._agentId:
- return -1
- if self._agentId > other._agentId:
- return 1
- if self._name < other._name:
- return -1
- if self._name > other._name:
- return 1
- return 0
-
- def __hash__(self):
- return (hash(self._agentId), self._name).__hash__()
-
-
-def ObjectIdFactory( param ):
- """
- Factory for constructing ObjectIds from various sources
-
- @type param: various
- @param param: object to use for constructing ObjectId
- @rtype: ObjectId
- @returns: a new ObjectId instance
+class _mapEncoder(object):
+ """
+ virtual base class for all objects that support being converted to a map
"""
- if type(param) == dict:
- # construct from map
- if "agent_id" not in param:
- raise TypeError("requires 'agent_id' value")
- if "primary_key" not in param:
- raise TypeError("requires 'primary_key' value")
-
- return ObjectId( AgentIdFactory(param["agent_id"]), param["primary_key"] )
-
- else:
- raise TypeError("Invalid type for ObjectId construction")
-
+ def map_encode(self):
+ raise Exception("The map_encode method my be overridden.")
-class QmfData(object):
+class QmfData(_mapEncoder):
"""
Base data class representing arbitrarily structure data. No schema or
managing agent is associated with data of this class.
Map format:
- map["properties"] = map of unordered "name"=<value> pairs (optional)
- """
- def __init__(self, _props={}, _const=False):
- """
- @type _props: dict
- @param _props: dictionary of initial name=value pairs for object's property data.
+ map["_values"] = map of unordered "name"=<value> pairs (optional)
+ map["_subtype"] = map of unordered "name"="subtype string" pairs (optional)
+ map["_tag"] = application-specific tag for this instance (optional)
+ """
+ KEY_VALUES = "_values"
+ KEY_SUBTYPES = "_subtypes"
+ KEY_TAG="_tag"
+ KEY_OBJECT_ID = "_object_id"
+ KEY_SCHEMA_ID = "_schema_id"
+ KEY_UPDATE_TS = "_update_ts"
+ KEY_CREATE_TS = "_create_ts"
+ KEY_DELETE_TS = "_delete_ts"
+
+ def __init__(self,
+ _values={}, _subtypes={}, _tag=None, _object_id=None,
+ _ctime = 0, _utime = 0, _dtime = 0,
+ _map=None,
+ _schema=None, _const=False):
+ """
+ @type _values: dict
+ @param _values: dictionary of initial name=value pairs for object's
+ named data.
+ @type _subtypes: dict
+ @param _subtype: dictionary of subtype strings for each of the object's
+ named data.
+ @type _desc: string
+ @param _desc: Human-readable description of this data object.
@type _const: boolean
@param _const: if true, this object cannot be modified
"""
- self._properties = _props.copy()
+ self._schema_id = None
+ if _map is not None:
+ # construct from map
+ _tag = _map.get(self.KEY_TAG, _tag)
+ _values = _map.get(self.KEY_VALUES, _values)
+ _subtypes = _map.get(self.KEY_SUBTYPES, _subtypes)
+ _object_id = _map.get(self.KEY_OBJECT_ID, _object_id)
+ sid = _map.get(self.KEY_SCHEMA_ID)
+ if sid:
+ self._schema_id = SchemaClassId(_map=sid)
+ _ctime = long(_map.get(self.KEY_CREATE_TS, _ctime))
+ _utime = long(_map.get(self.KEY_UPDATE_TS, _utime))
+ _dtime = long(_map.get(self.KEY_DELETE_TS, _dtime))
+
+ self._values = _values.copy()
+ self._subtypes = _subtypes.copy()
+ self._tag = _tag
+ self._ctime = _ctime
+ self._utime = _utime
+ self._dtime = _dtime
self._const = _const
- self._managed = False # not managed by an Agent
- self._described = False # not described by a schema
-
- def isManaged(self):
- return self._managed
- def isDescribed(self):
- return self._described
-
- def getProperties(self):
- return self._properties.copy()
+ if _object_id is not None:
+ self._object_id = str(_object_id)
+ else:
+ self._object_id = None
- def getProperty(self, _name):
- return self._properties[_name]
+ if _schema is not None:
+ self._set_schema(_schema)
+ else:
+ # careful: map constructor may have already set self._schema_id, do
+ # not override it!
+ self._schema = None
+
+ def _create(cls, values, _subtypes={}, _tag=None, _object_id=None,
+ _schema=None, _const=False):
+ # timestamp in millisec since epoch UTC
+ ctime = long(time.time() * 1000)
+ return cls(_values=values, _subtypes=_subtypes, _tag=_tag,
+ _ctime=ctime, _utime=ctime,
+ _object_id=_object_id, _schema=_schema, _const=_const)
+ create = classmethod(_create)
+
+ def _from_map(cls, map_, _schema=None, _const=False):
+ return cls(_map=map_, _schema=_schema, _const=_const)
+ from_map = classmethod(_from_map)
+
+ def is_managed(self):
+ return self._object_id is not None
+
+ def is_described(self):
+ return self._schema_id is not None
+
+ def get_tag(self):
+ return self._tag
+
+ def get_value(self, name):
+ # meta-properties:
+ if name == SchemaClassId.KEY_PACKAGE:
+ if self._schema_id:
+ return self._schema_id.get_package_name()
+ return None
+ if name == SchemaClassId.KEY_CLASS:
+ if self._schema_id:
+ return self._schema_id.get_class_name()
+ return None
+ if name == SchemaClassId.KEY_TYPE:
+ if self._schema_id:
+ return self._schema_id.get_type()
+ return None
+ if name == SchemaClassId.KEY_HASH:
+ if self._schema_id:
+ return self._schema_id.get_hash_string()
+ return None
+ if name == self.KEY_SCHEMA_ID:
+ return self._schema_id
+ if name == self.KEY_OBJECT_ID:
+ return self._object_id
+ if name == self.KEY_TAG:
+ return self._tag
+ if name == self.KEY_UPDATE_TS:
+ return self._utime
+ if name == self.KEY_CREATE_TS:
+ return self._ctime
+ if name == self.KEY_DELETE_TS:
+ return self._dtime
+
+ return self._values.get(name)
+
+ def has_value(self, name):
+
+ if name in [SchemaClassId.KEY_PACKAGE, SchemaClassId.KEY_CLASS,
+ SchemaClassId.KEY_TYPE, SchemaClassId.KEY_HASH,
+ self.KEY_SCHEMA_ID]:
+ return self._schema_id is not None
+ if name in [self.KEY_UPDATE_TS, self.KEY_CREATE_TS,
+ self.KEY_DELETE_TS]:
+ return True
+ if name == self.KEY_OBJECT_ID:
+ return self._object_id is not None
+ if name == self.KEY_TAG:
+ return self._tag is not None
- def hasProperty(self, _name):
- return _name in self._properties
+ return name in self._values
- def setProperty(self, _name, _value):
+ def set_value(self, _name, _value, _subType=None):
if self._const:
raise Exception("cannot modify constant data object")
- self._properties[_name] = _value
+ self._values[_name] = _value
+ if _subType:
+ self._subtypes[_name] = _subType
return _value
- def mapEncode(self):
- return self._properties.copy()
-
- def __repr__(self):
- return str(self.mapEncode())
-
- def __setattr__(self, _name, _value):
- # ignore private data members
- if _name[0] == '_':
- return super.__setattr__(self, _name, _value)
- if _name in self._properties:
- return self.setProperty(_name, _value)
- return super.__setattr__(self, _name, _value)
-
- def __getattr__(self, _name):
- if _name in self._properties: return self.getProperty(_name)
- raise AttributeError("no item named '%s' in this object" % _name)
-
- def __getitem__(self, _name):
- return self.__getattr__(_name)
-
- def __setitem__(self, _name, _value):
- return self.__setattr__(_name, _value)
-
-
-def QmfDataFactory( param, const=False ):
- """
- Factory for constructing an QmfData class from various sources.
-
- @type param: various
- @param param: object to use for constructing QmfData instance
- @rtype: QmfData
- @returns: a new QmfData instance
- """
- if type(param) == dict:
- # construct from map
- return QmfData( _props=param, _const=const )
-
- else:
- raise TypeError("Invalid type for QmfData construction")
-
-
-
-class QmfDescribed(QmfData):
- """
- 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 (SchemaObjectClass).
-
- Map format:
- map["schema_id"] = map representation of a SchemaClassId instance
- map["properties"] = map representation of a QmfData instance
- """
- def __init__(self, _schema=None, _schemaId=None, _props={}, _const=False ):
- """
- @type _schema: class SchemaClass or derivative
- @param _schema: an instance of the schema used to describe this object.
- @type _schemaId: class SchemaClassId
- @param _schemaId: if schema instance not available, this is mandatory.
- @type _props: dict
- @param _props: dictionary of initial name=value pairs for object's property data.
- @type _const: boolean
- @param _const: if true, this object cannot be modified
- """
- super(QmfDescribed, self).__init__(_props, _const)
- self._validated = False
- self._described = True
- self._schema = _schema
- if _schema:
- self._schemaId = _schema.getClassId()
- if self._const:
- self._validate()
- else:
- if _schemaId:
- self._schemaId = _schemaId
- else:
- raise Exception("A SchemaClass or SchemaClassId must be provided")
-
+ def get_subtype(self, _name):
+ return self._subtypes.get(_name)
- def getSchemaClassId(self):
+ def get_schema_class_id(self):
"""
@rtype: class SchemaClassId
@returns: the identifier of the Schema that describes the structure of the data.
"""
- return self._schemaId
-
- def setSchema(self, _schema):
- """
- @type _schema: class SchemaClass or derivative
- @param _schema: instance of schema used to describe the structure of the data.
- """
- if self._schemaId != _schema.getClassId():
- raise Exception("Cannot reset current schema to a different schema")
- oldSchema = self._schema
- self._schema = _schema
- if not oldSchema and self._const:
- self._validate()
+ return self._schema_id
- def getPrimaryKey(self):
+ def get_object_id(self):
"""
- Get a string composed of the object's primary key properties.
+ Get the instance's identification string.
@rtype: str
- @returns: a string composed from primary key property values.
+ @returns: the identification string, or None if not assigned and id.
"""
+ if self._object_id:
+ return self._object_id
+
+ # if object id not assigned, see if schema defines a set of field
+ # values to use as an id
if not self._schema:
- raise Exception("schema not available")
+ return None
+
+ ids = self._schema.get_id_names()
+ if not ids:
+ return None
if not self._validated:
self._validate()
- if self._schema._pkeyNames == 0:
- if len(self._properties) != 1:
- raise Exception("no primary key defined")
- return str(self._properties.values()[0])
-
result = u""
- for pkey in self._schema._pkeyNames:
- if result != u"":
- result += u":"
+ for key in ids:
try:
- valstr = unicode(self._properties[pkey])
+ result += unicode(self._values[key])
except:
- valstr = u"<undecodable>"
- result += valstr
+ logging.error("get_object_id(): cannot convert value '%s'."
+ % key)
+ return None
+ self._object_id = result
return result
+ def map_encode(self):
+ _map = {}
+ if self._tag:
+ _map[self.KEY_TAG] = self._tag
- def getProperty(self, name):
- # meta-properties
- if name == QmfQuery._PRED_PACKAGE:
- return self._schemaId.getClassId().getPackageName()
- if name == QmfQuery._PRED_CLASS:
- return self._schemaId.getClassId().getClassName()
- if name == QmfQuery._PRED_TYPE:
- return self._schemaId.getClassId().getType()
- if name == QmfQuery._PRED_HASH:
- return self._schemaId.getClassId().getHashString()
- if name == QmfQuery._PRED_SCHEMA_ID:
- return self._schemaId.getClassId()
- if name == QmfQuery._PRED_PRIMARY_KEY:
- return self.getPrimaryKey()
-
- return super(QmfDescribed, self).getProperty(name)
-
-
- def hasProperty(self, name):
- if name in [QmfQuery._PRED_PACKAGE, QmfQuery._PRED_CLASS, QmfQuery._PRED_TYPE,
- QmfQuery._PRED_HASH, QmfQuery._PRED_SCHEMA_ID, QmfQuery._PRED_PRIMARY_KEY]:
- return True
-
- return super(QmfDescribed, self).hasProperty(name)
-
+ # data in the _values map may require recursive map_encode()
+ vmap = {}
+ for name,val in self._values.iteritems():
+ if isinstance(val, _mapEncoder):
+ vmap[name] = val.map_encode()
+ else:
+ # otherwise, just toss in the native type...
+ vmap[name] = val
- def mapEncode(self):
- _map = {}
- _map["schema_id"] = self._schemaId.mapEncode()
- _map["properties"] = super(QmfDescribed, self).mapEncode()
+ _map[self.KEY_VALUES] = vmap
+ # subtypes are never complex, so safe to just copy
+ _map[self.KEY_SUBTYPES] = self._subtypes.copy()
+ if self._object_id:
+ _map[self.KEY_OBJECT_ID] = self._object_id
+ if self._schema_id:
+ _map[self.KEY_SCHEMA_ID] = self._schema_id.map_encode()
return _map
+ def _set_schema(self, schema):
+ self._validated = False
+ self._schema = schema
+ if schema:
+ self._schema_id = schema.get_class_id()
+ if self._const:
+ self._validate()
+ else:
+ self._schema_id = None
+
def _validate(self):
"""
Compares this object's data against the associated schema. Throws an
exception if the data does not conform to the schema.
"""
- for name,val in self._schema._properties.iteritems():
+ props = self._schema.get_properties()
+ for name,val in props.iteritems():
# @todo validate: type compatible with amqp_type?
# @todo validate: primary keys have values
- if name not in self._properties:
+ if name not in self._values:
if val._isOptional:
# ok not to be present, put in dummy value
# to simplify access
- self._properties[name] = None
+ self._values[name] = None
else:
raise Exception("Required property '%s' not present." % name)
self._validated = True
+ def __repr__(self):
+ return "QmfData=<<" + str(self.map_encode()) + ">>"
+
+ def __setattr__(self, _name, _value):
+ # ignore private data members
+ if _name[0] == '_':
+ return super(QmfData, self).__setattr__(_name, _value)
+ if _name in self._values:
+ return self.set_value(_name, _value)
+ return super(QmfData, self).__setattr__(_name, _value)
-def QmfDescribedFactory( param, _schema=None ):
- """
- Factory for constructing an QmfDescribed class from various sources.
-
- @type param: various
- @param param: object to use for constructing QmfDescribed instance
- @type _schema: SchemaClass
- @param _schema: instance of the SchemaClass that describes this instance
- @rtype: QmfDescribed
- @returns: a new QmfDescribed instance
- """
- if type(param) == dict:
- # construct from map
- if "schema_id" not in param:
- raise TypeError("requires 'schema_id' value")
- if "properties" not in param:
- raise TypeError("requires 'properties' value")
-
- return QmfDescribed( _schema=_schema, _schemaId=SchemaClassIdFactory( param["schema_id"] ),
- _props = param["properties"] )
- else:
- raise TypeError("Invalid type for QmfDescribed construction")
-
-
-
-class QmfManaged(QmfDescribed):
- """
- Data that has a formally defined structure, and for which each
- instance of the data is managed by a particular Agent is represented
- by the QmfManaged class. This class extends the QmfDescribed class by
- associating the described data with a particular Agent.
-
- Map format:
- map["object_id"] = map representation of an ObjectId value
- map["schema_id"] = map representation of a SchemaClassId instance
- map["qmf_data"] = map representation of a QmfData instance
- map["timestamps"] = array of AMQP timestamps. [0] = time of last update,
- [1] = creation timestamp, [2] = deletion timestamp or zero.
- """
- _ts_update = 0
- _ts_create = 1
- _ts_delete = 2
- def __init__( self, _agentId=None, _schema=None, _schemaId=None,
- _props={}, _const=False ):
- """
- @type _agentId: class AgentId
- @param _agentId: globally unique identifier of the managing agent.
- @type _schema: class SchemaClass or derivative
- @param _schema: an instance of the schema used to describe this object.
- @type _schemaId: class SchemaClassId
- @param _schemaId: if schema instance not available, this is mandatory.
- @type _props: dict
- @param _props: dictionary of initial name=value pairs for object's property data.
- @type _const: boolean
- @param _const: if true, this object cannot be modified
- """
- super(QmfManaged, self).__init__(_schema=_schema, _schemaId=_schemaId,
- _props=_props, _const=_const)
- self._managed = True
- self._agentId = _agentId
- # timestamp, in millisec since epoch UTC
- _ctime = long(time.time() * 1000)
- self._timestamps = [_ctime,_ctime,0]
-
-
- def getObjectId(self):
- """
- @rtype: class ObjectId
- @returns: the ObjectId that uniquely identifies this managed object.
- """
- return ObjectId(self._agentId, self.getPrimaryKey())
-
- def isDeleted(self):
- return self._timestamps[QmfManaged._ts_delete] == 0
-
-
- def getProperty(self, name):
- # meta-properties
- if name == QmfQuery._PRED_OBJECT_ID:
- return self.getObjectId()
- if name == QmfQuery._PRED_UPDATE_TS:
- return self._timestamps[QmfManaged._ts_update]
- if name == QmfQuery._PRED_CREATE_TS:
- return self._timestamps[QmfManaged._ts_create]
- if name == QmfQuery._PRED_DELETE_TS:
- return self._timestamps[QmfManaged._ts_delete]
-
- return super(QmfManaged, self).getProperty(name)
-
-
- def hasProperty(self, name):
- if name in [QmfQuery._PRED_OBJECT_ID, QmfQuery._PRED_UPDATE_TS,
- QmfQuery._PRED_CREATE_TS, QmfQuery._PRED_DELETE_TS]:
- return True
-
- return super(QmfManaged, self).hasProperty(name)
-
-
- def mapEncode(self):
- _map = super(QmfManaged, self).mapEncode()
- _map["agent_id"] = self._agentId.mapEncode()
- _map["timestamps"] = self._timestamps[:]
- return _map
-
-
+ def __getattr__(self, _name):
+ if _name != "_values" and _name in self._values:
+ return self._values[_name]
+ raise AttributeError("no value named '%s' in this object" % _name)
-def QmfManagedFactory( param, _schema=None ):
- """
- Factory for constructing an QmfManaged instance from various sources.
+ def __getitem__(self, _name):
+ return self.__getattr__(_name)
- @type param: various
- @param param: object to use for constructing QmfManaged instance
- @type _schema: SchemaClass
- @param _schema: instance of the SchemaClass that describes this instance
- @rtype: QmfManaged
- @returns: a new QmfManaged instance
- """
- if type(param) == dict:
- # construct from map
- if "agent_id" not in param:
- raise TypeError("requires 'agent_id' value")
- _qd = QmfDescribedFactory( param, _schema )
-
- return QmfManaged( _agentId = AgentIdFactory(param["agent_id"]),
- _schema=_schema, _schemaId=_qd._schemaId,
- _props = _qd._properties )
- else:
- raise TypeError("Invalid type for QmfManaged construction")
+ def __setitem__(self, _name, _value):
+ return self.__setattr__(_name, _value)
-class QmfEvent(QmfDescribed):
+class QmfEvent(QmfData):
"""
A QMF Event is a type of described data that is not managed. Events are
notifications that are sent by Agents. An event notifies a Console of a
change in some aspect of the system under managment.
"""
- def __init__(self, _map=None,
- _timestamp=None, _agentId=None,
- _schema=None, _schemaId=None,
- _props={}, _const=False):
+ KEY_TIMESTAMP = "_timestamp"
+
+ def __init__(self, _timestamp=None, _values={}, _subtypes={}, _tag=None,
+ _map=None,
+ _schema=None, _const=True):
"""
@type _map: dict
@param _map: if not None, construct instance from map representation.
@@ -661,33 +511,43 @@
@type _schemaId: class SchemaClassId (event)
@param _schemaId: identi
"""
- if _map:
- if type(_map) != dict:
- raise TypeError("parameter '_map' must be of type 'dict'")
- if "timestamp" not in _map:
- pass
- if "agent_id" not in _map:
- pass
- _qe = QmfDescribedFactory( _map, _schema )
- super(QmfEvent, self).__init__( _schema=_qe._schema, _schemaId=_qe._schemaId,
- _props=_qe._properties, _const=_qe._const )
- self._timestamp = long(_map["timestamp"])
- self._agentId = AgentIdFactory(_map["agent_id"])
+
+ if _map is not None:
+ # construct from map
+ super(QmfEvent, self).__init__(_map=_map, _schema=_schema,
+ _const=_const)
+ _timestamp = _map.get(self.KEY_TIMESTAMP, _timestamp)
else:
- super(QmfEvent, self).__init__(_schema=_schema, _schemaId=_schemaId,
- _props=_props, _const=_const)
+ super(QmfEvent, self).__init__(_values=_values,
+ _subtypes=_subtypes, _tag=_tag,
+ _schema=_schema, _const=_const)
+ if _timestamp is None:
+ raise TypeError("QmfEvent: a valid timestamp is required.")
+
+ try:
self._timestamp = long(_timestamp)
- self._agentId = _agentId
+ except:
+ raise TypeError("QmfEvent: a numeric timestamp is required.")
- def getTimestamp(self): return self._timestamp
+ def _create(cls, timestamp, values,
+ _subtypes={}, _tag=None, _schema=None, _const=False):
+ return cls(_timestamp=timestamp, _values=values, _subtypes=_subtypes,
+ _tag=_tag, _schema=_schema, _const=_const)
+ create = classmethod(_create)
+
+ def _from_map(cls, map_, _schema=None, _const=False):
+ return cls(_map=map_, _schema=_schema, _const=_const)
+ from_map = classmethod(_from_map)
+
+ def get_timestamp(self):
+ return self._timestamp
+
+ def map_encode(self):
+ _map = super(QmfEvent, self).map_encode()
+ _map[self.KEY_TIMESTAMP] = self._timestamp
+ return _map
- def getAgentId(self): return self._agentId
- def mapEncode(self):
- _map = super(QmfEvent, self).mapEncode()
- _map["timestamp"] = self._timestamp
- _map["agent_id"] = self._agentId.mapEncode()
- return _map
@@ -697,204 +557,6 @@
-class QmfObject(object):
- # attr_reader :impl, :object_class
- def __init__(self, cls, kwargs={}):
- pass
-# self._cv = Condition()
-# self._sync_count = 0
-# self._sync_result = None
-# self._allow_sets = False
-# if kwargs.has_key("broker"):
-# self._broker = kwargs["broker"]
-# else:
-# self._broker = None
-# if cls:
-# self.object_class = cls
-# self.impl = qmfengine.Object(self.object_class.impl)
-# elif kwargs.has_key("impl"):
-# self.impl = qmfengine.Object(kwargs["impl"])
-# self.object_class = SchemaObjectClass(None,
-# None,
-# {"impl":self.impl.getClass()})
-# else:
-# raise Exception("Argument error: required parameter ('impl') not supplied")
-
-
-# def destroy(self):
-# self.impl.destroy()
-
-
-# def object_id(self):
-# return ObjectId(self.impl.getObjectId())
-
-
-# def set_object_id(self, oid):
-# self.impl.setObjectId(oid.impl)
-
-
-# def properties(self):
-# list = []
-# for prop in self.object_class.properties:
-# list.append([prop, self.get_attr(prop.name())])
-# return list
-
-
-# def statistics(self):
-# list = []
-# for stat in self.object_class.statistics:
-# list.append([stat, self.get_attr(stat.name())])
-# return list
-
-
-# def get_attr(self, name):
-# val = self._value(name)
-# vType = val.getType()
-# if vType == TYPE_UINT8: return val.asUint()
-# elif vType == TYPE_UINT16: return val.asUint()
-# elif vType == TYPE_UINT32: return val.asUint()
-# elif vType == TYPE_UINT64: return val.asUint64()
-# elif vType == TYPE_SSTR: return val.asString()
-# elif vType == TYPE_LSTR: return val.asString()
-# elif vType == TYPE_ABSTIME: return val.asInt64()
-# elif vType == TYPE_DELTATIME: return val.asUint64()
-# elif vType == TYPE_REF: return ObjectId(val.asObjectId())
-# elif vType == TYPE_BOOL: return val.asBool()
-# elif vType == TYPE_FLOAT: return val.asFloat()
-# elif vType == TYPE_DOUBLE: return val.asDouble()
-# elif vType == TYPE_UUID: return val.asUuid()
-# elif vType == TYPE_INT8: return val.asInt()
-# elif vType == TYPE_INT16: return val.asInt()
-# elif vType == TYPE_INT32: return val.asInt()
-# elif vType == TYPE_INT64: return val.asInt64()
-# else:
-# # when TYPE_MAP
-# # when TYPE_OBJECT
-# # when TYPE_LIST
-# # when TYPE_ARRAY
-# logging.error( "Unsupported type for get_attr? '%s'" % str(val.getType()) )
-# return None
-
-
-# def set_attr(self, name, v):
-# val = self._value(name)
-# vType = val.getType()
-# if vType == TYPE_UINT8: return val.setUint(v)
-# elif vType == TYPE_UINT16: return val.setUint(v)
-# elif vType == TYPE_UINT32: return val.setUint(v)
-# elif vType == TYPE_UINT64: return val.setUint64(v)
-# elif vType == TYPE_SSTR:
-# if v: return val.setString(v)
-# else: return val.setString('')
-# elif vType == TYPE_LSTR:
-# if v: return val.setString(v)
-# else: return val.setString('')
-# elif vType == TYPE_ABSTIME: return val.setInt64(v)
-# elif vType == TYPE_DELTATIME: return val.setUint64(v)
-# elif vType == TYPE_REF: return val.setObjectId(v.impl)
-# elif vType == TYPE_BOOL: return val.setBool(v)
-# elif vType == TYPE_FLOAT: return val.setFloat(v)
-# elif vType == TYPE_DOUBLE: return val.setDouble(v)
-# elif vType == TYPE_UUID: return val.setUuid(v)
-# elif vType == TYPE_INT8: return val.setInt(v)
-# elif vType == TYPE_INT16: return val.setInt(v)
-# elif vType == TYPE_INT32: return val.setInt(v)
-# elif vType == TYPE_INT64: return val.setInt64(v)
-# else:
-# # when TYPE_MAP
-# # when TYPE_OBJECT
-# # when TYPE_LIST
-# # when TYPE_ARRAY
-# logging.error("Unsupported type for get_attr? '%s'" % str(val.getType()))
-# return None
-
-
-# def __getitem__(self, name):
-# return self.get_attr(name)
-
-
-# def __setitem__(self, name, value):
-# self.set_attr(name, value)
-
-
-# def inc_attr(self, name, by=1):
-# self.set_attr(name, self.get_attr(name) + by)
-
-
-# def dec_attr(self, name, by=1):
-# self.set_attr(name, self.get_attr(name) - by)
-
-
-
-
-# def _invokeMethod(self, name, argMap):
-# """
-# Private: Helper function that invokes an object's method, and waits for the result.
-# """
-# self._cv.acquire()
-# try:
-# timeout = 30
-# self._sync_count = 1
-# self.impl.invokeMethod(name, argMap, self)
-# if self._broker:
-# self._broker.conn.kick()
-# self._cv.wait(timeout)
-# if self._sync_count == 1:
-# raise Exception("Timed out: waiting for response to method call.")
-# finally:
-# self._cv.release()
-
-# return self._sync_result
-
-
-# def _method_result(self, result):
-# """
-# Called to return the result of a method call on an object
-# """
-# self._cv.acquire();
-# try:
-# self._sync_result = result
-# self._sync_count -= 1
-# self._cv.notify()
-# finally:
-# self._cv.release()
-
-
-# def _marshall(schema, args):
-# '''
-# Private: Convert a list of arguments (positional) into a Value object of type "map".
-# Used to create the argument parameter for an object's method invokation.
-# '''
-# # Build a map of the method's arguments
-# map = qmfengine.Value(TYPE_MAP)
-# for arg in schema.arguments:
-# if arg.direction == DIR_IN or arg.direction == DIR_IN_OUT:
-# map.insert(arg.name, qmfengine.Value(arg.typecode))
-
-# # install each argument's value into the map
-# marshalled = Arguments(map)
-# idx = 0
-# for arg in schema.arguments:
-# if arg.direction == DIR_IN or arg.direction == DIR_IN_OUT:
-# if args[idx]:
-# marshalled[arg.name] = args[idx]
-# idx += 1
-
-# return marshalled.map
-
-
-# def _value(self, name):
-# val = self.impl.getValue(name)
-# if not val:
-# raise Exception("Argument error: attribute named '%s' not defined for package %s, class %s" %
-# (name,
-# self.object_class.impl.getClassKey().getPackageName(),
-# self.object_class.impl.getClassKey().getClassName()))
-# return val
-
-
-
-
class Arguments(object):
def __init__(self, map):
@@ -1092,7 +754,7 @@
-class QmfQuery(object):
+class QmfQuery(_mapEncoder):
_TARGET="what"
_PREDICATE="where"
@@ -1223,18 +885,19 @@
def getPredicate(self):
return self._predicate
- def mapEncode(self):
+ def map_encode(self):
_map = {}
_map[self._TARGET] = self._target_map
- _map[self._PREDICATE] = self._predicate.mapEncode()
+ if self._predicate is not None:
+ _map[self._PREDICATE] = self._predicate.map_encode()
return _map
def __repr__(self):
- return str(self.mapEncode())
+ return "QmfQuery=<<" + str(self.map_encode()) + ">>"
-class QmfQueryPredicate(object):
+class QmfQueryPredicate(_mapEncoder):
"""
Class for Query predicates.
"""
@@ -1255,7 +918,6 @@
logic_op = False
if type(pmap) == dict:
for key in pmap.iterkeys():
- logging.error("key = %s" % key)
if key in self._valid_cmp_ops:
# coparison operation - may have "name" and "value"
self._oper = key
@@ -1283,7 +945,6 @@
"""
Append another operand to a predicate expression
"""
- logging.error("Appending: '%s'" % str(operand))
self._operands.append(operand)
@@ -1311,15 +972,16 @@
# @todo: support regular expression match
name = self._operands[0]
logging.debug("looking for: '%s'" % str(name))
- if not qmfData.hasProperty(name):
- logging.warning("Malformed query, attribute '%s' not present." % name)
+ if not qmfData.has_value(name):
+ logging.warning("Malformed query, attribute '%s' not present."
+ % name)
return False
- arg1 = qmfData.getProperty(name)
- arg1Type = type(arg1)
+
+ arg1 = qmfData.get_value(name)
+ arg2 = self._operands[1]
logging.debug("query evaluate %s: '%s' '%s' '%s'" %
- (name, str(arg1), self._oper, str(self._operands[1])))
+ (name, str(arg1), self._oper, str(arg2)))
try:
- arg2 = arg1Type(self._operands[1])
if self._oper == QmfQuery._CMP_EQ: return arg1 == arg2
if self._oper == QmfQuery._CMP_NE: return arg1 != arg2
if self._oper == QmfQuery._CMP_LT: return arg1 < arg2
@@ -1342,7 +1004,7 @@
return False
name = self._operands[0]
logging.debug("query evaluate PRESENT: [%s]" % str(name))
- return qmfData.hasProperty(name)
+ return qmfData.has_value(name)
if self._oper == QmfQuery._LOGIC_AND:
logging.debug("query evaluate AND: '%s'" % str(self._operands))
@@ -1369,12 +1031,12 @@
return False
- def mapEncode(self):
+ def map_encode(self):
_map = {}
_list = []
for exp in self._operands:
if isinstance(exp, QmfQueryPredicate):
- _list.append(exp.mapEncode())
+ _list.append(exp.map_encode())
else:
_list.append(exp)
_map[self._oper] = _list
@@ -1382,7 +1044,7 @@
def __repr__(self):
- return str(self.mapEncode())
+ return "QmfQueryPredicate=<<" + str(self.map_encode()) + ">>"
@@ -1390,15 +1052,6 @@
## SCHEMA
##==============================================================================
-# known schema types
-
-SchemaTypeData = "data"
-SchemaTypeEvent = "event"
-
-# format convention for schema hash
-
-_schemaHashStrFormat = "%08x-%08x-%08x-%08x"
-_schemaHashStrDefault = "00000000-00000000-00000000-00000000"
# Argument typecodes, access, and direction qualifiers
@@ -1458,7 +1111,7 @@
-class SchemaClassId(object):
+class SchemaClassId(_mapEncoder):
"""
Unique identifier for an instance of a SchemaClass.
@@ -1470,20 +1123,40 @@
map["hash_str"] = str, hash value in standard format or None
if hash is unknown.
"""
- def __init__(self, pname, cname, stype=SchemaTypeData, hstr=None):
+ KEY_PACKAGE="_package_name"
+ KEY_CLASS="_class_name"
+ KEY_TYPE="_type"
+ KEY_HASH="_hash_str"
+
+ TYPE_DATA = "_data"
+ TYPE_EVENT = "event"
+
+ _valid_types=[TYPE_DATA, TYPE_EVENT]
+ _schemaHashStrFormat = "%08x-%08x-%08x-%08x"
+ _schemaHashStrDefault = "00000000-00000000-00000000-00000000"
+
+ def __init__(self, pname=None, cname=None, stype=TYPE_DATA, hstr=None,
+ _map=None):
"""
@type pname: str
@param pname: the name of the class's package
@type cname: str
@param cname: name of the class
@type stype: str
- @param stype: schema type [SchemaTypeData | SchemaTypeEvent]
+ @param stype: schema type [data | event]
@type hstr: str
@param hstr: the hash value in '%08x-%08x-%08x-%08x' format
"""
+ if _map is not None:
+ # construct from map
+ pname = _map.get(self.KEY_PACKAGE, pname)
+ cname = _map.get(self.KEY_CLASS, cname)
+ stype = _map.get(self.KEY_TYPE, stype)
+ hstr = _map.get(self.KEY_HASH, hstr)
+
self._pname = pname
self._cname = cname
- if stype != SchemaTypeData and stype != SchemaTypeEvent:
+ if stype not in SchemaClassId._valid_types:
raise TypeError("Invalid SchemaClassId type: '%s'" % stype)
self._type = stype
self._hstr = hstr
@@ -1498,8 +1171,17 @@
except:
raise Exception("Invalid SchemaClassId format: bad hash string: '%s':"
% hstr)
+ # constructor
+ def _create(cls, pname, cname, stype=TYPE_DATA, hstr=None):
+ return cls(pname=pname, cname=cname, stype=stype, hstr=hstr)
+ create = classmethod(_create)
+
+ # map constructor
+ def _from_map(cls, map_):
+ return cls(_map=map_)
+ from_map = classmethod(_from_map)
- def getPackageName(self):
+ def get_package_name(self):
"""
Access the package name in the SchemaClassId.
@@ -1508,7 +1190,7 @@
return self._pname
- def getClassName(self):
+ def get_class_name(self):
"""
Access the class name in the SchemaClassId
@@ -1517,7 +1199,7 @@
return self._cname
- def getHashString(self):
+ def get_hash_string(self):
"""
Access the schema's hash as a string value
@@ -1526,7 +1208,7 @@
return self._hstr
- def getType(self):
+ def get_type(self):
"""
Returns the type code associated with this Schema
@@ -1534,27 +1216,25 @@
"""
return self._type
- def mapEncode(self):
+ def map_encode(self):
_map = {}
- _map["package_name"] = self._pname
- _map["class_name"] = self._cname
- _map["type"] = self._type
- if self._hstr: _map["hash_str"] = self._hstr
+ _map[self.KEY_PACKAGE] = self._pname
+ _map[self.KEY_CLASS] = self._cname
+ _map[self.KEY_TYPE] = self._type
+ if self._hstr: _map[self.KEY_HASH] = self._hstr
return _map
def __repr__(self):
- if self._type == SchemaTypeEvent:
- stype = "event"
- else:
- stype = "data"
- hstr = self.getHashString()
+ hstr = self.get_hash_string()
if not hstr:
- hstr = _schemaHashStrDefault
- return self._pname + ":" + self._cname + ":" + stype + "(" + hstr + ")"
+ hstr = SchemaClassId._schemaHashStrDefault
+ return self._pname + ":" + self._cname + ":" + self._type + "(" + hstr + ")"
def __cmp__(self, other):
- if not isinstance(other, SchemaClassId) :
+ if isinstance(other, dict):
+ other = SchemaClassId.from_map(other)
+ if not isinstance(other, SchemaClassId):
raise TypeError("Invalid types for compare")
# return 1
me = str(self)
@@ -1571,55 +1251,7 @@
-def SchemaClassIdFactory( param ):
- """
- Factory for constructing SchemaClassIds from various sources
-
- @type param: various
- @param param: object to use for constructing SchemaClassId
- @rtype: SchemaClassId
- @returns: a new SchemaClassId instance
- """
- if type(param) == str:
- # construct from __repr__/__str__ representation
- try:
- pname, cname, rest = param.split(":")
- stype,rest = rest.split("(");
- hstr = rest.rstrip(")");
- if hstr == _schemaHashStrDefault:
- hstr = None
- return SchemaClassId( pname, cname, stype, hstr )
- except:
- raise TypeError("Invalid string format: '%s'" % param)
-
- if type(param) == dict:
- # construct from map representation
- if "package_name" in param:
- pname = param["package_name"]
- else:
- raise TypeError("'package_name' attribute is required")
-
- if "class_name" in param:
- cname = param["class_name"]
- else:
- raise TypeError("'class_name' attribute is required")
-
- hstr = None
- if "hash_str" in param:
- hstr = param["hash_str"]
-
- stype = "data"
- if "type" in param:
- stype = param["type"]
-
- return SchemaClassId( pname, cname, stype, hstr )
-
- else:
- raise TypeError("Invalid type for SchemaClassId construction")
-
-
-
-class SchemaProperty(object):
+class SchemaProperty(_mapEncoder):
"""
Describes the structure of a Property data object.
Map format:
@@ -1641,8 +1273,17 @@
"""
__hash__ = None
_access_strings = ["RO","RW","RC"]
- def __init__(self, typeCode, kwargs={}):
- self._type = typeCode
+ _dir_strings = ["I", "O", "IO"]
+ def __init__(self, _type_code=None, _map=None, kwargs={}):
+ if _map is not None:
+ # construct from map
+ _type_code = _map.get("amqp_type", _type_code)
+ kwargs = _map
+ if not _type_code:
+ raise TypeError("SchemaProperty: amqp_type is a mandatory"
+ " parameter")
+
+ self._type = _type_code
self._access = "RO"
self._isIndex = False
self._isOptional = False
@@ -1653,6 +1294,8 @@
self._desc = None
self._reference = None
self._isParentRef = False
+ self._dir = None
+ self._default = None
for key, value in kwargs.items():
if key == "access":
@@ -1669,6 +1312,22 @@
elif key == "desc" : self._desc = value
elif key == "reference" : self._reference = value
elif key == "parent_ref" : self._isParentRef = _toBool(value)
+ elif key == "dir":
+ value = str(value).upper()
+ if value not in self._dir_strings:
+ raise TypeError("invalid value for direction parameter: '%s'" % value)
+ self._dir = value
+ elif key == "default" : self._default = value
+
+ # constructor
+ def _create(cls, type_code, kwargs={}):
+ return cls(_type_code=type_code, kwargs=kwargs)
+ create = classmethod(_create)
+
+ # map constructor
+ def _from_map(cls, map_):
+ return cls(_map=map_)
+ from_map = classmethod(_from_map)
def getType(self): return self._type
@@ -1692,7 +1351,11 @@
def isParentRef(self): return self._isParentRef
- def mapEncode(self):
+ def getDirection(self): return self._dir
+
+ def getDefault(self): return self._default
+
+ def map_encode(self):
"""
Return the map encoding of this schema.
"""
@@ -1708,9 +1371,12 @@
if self._desc: _map["desc"] = self._desc
if self._reference: _map["reference"] = self._reference
_map["parent_ref"] = self._isParentRef
+ if self._dir: _map["dir"] = self._dir
+ if self._default: _map["default"] = self._default
return _map
- def __repr__(self): return str(self.mapEncode())
+ def __repr__(self):
+ return "SchemaProperty=<<" + str(self.map_encode()) + ">>"
def _updateHash(self, hasher):
"""
@@ -1722,122 +1388,21 @@
if self._access: hasher.update(self._access)
if self._unit: hasher.update(self._unit)
if self._desc: hasher.update(self._desc)
+ if self._dir: hasher.update(self._dir)
+ if self._default: hasher.update(self._default)
-def SchemaPropertyFactory( _map ):
- """
- Factory for constructing SchemaProperty from a map
-
- @type _map: dict
- @param _map: from mapEncode() of SchemaProperty
- @rtype: SchemaProperty
- @returns: a new SchemaProperty instance
- """
- if type(_map) == dict:
- # construct from map
- if "amqp_type" not in _map:
- raise TypeError("requires 'amqp_type' value")
-
- return SchemaProperty( _map["amqp_type"], _map )
-
- else:
- raise TypeError("Invalid type for SchemaProperty construction")
-
-
-
-
-class SchemaArgument(object):
- """
- Describes the structure of an Argument to a Method call.
- Map format:
- map["amqp_type"] = int, type code indicating argument's data type
- map["dir"] = str, direction for an argument associated with a
- Method, "I"|"O"|"IO", default value: "I"
- optional:
- map["desc"] = str, human-readable description of this argument
- map["default"] = by amqp_type, default value to use if none provided
- """
- __hash__ = None
- _dir_strings = ["I", "O", "IO"]
- def __init__(self, typeCode, kwargs={}):
- self._type = typeCode
- self._dir = "I"
- self._desc = None
- self._default = None
-
- for key, value in kwargs.items():
- if key == "dir":
- value = str(value).upper()
- if value not in self._dir_strings:
- raise TypeError("invalid value for dir parameter: '%s'" % value)
- self._dir = value
- elif key == "desc" : self._desc = value
- elif key == "default" : self._default = value
-
- def getType(self): return self._type
-
- def getDirection(self): return self._dir
-
- def getDesc(self): return self._desc
-
- def getDefault(self): return self._default
-
- def mapEncode(self):
- """
- Return the map encoding of this schema.
- """
- _map = {}
- _map["amqp_type"] = self._type
- _map["dir"] = self._dir
- # optional:
- if self._default: _map["default"] = self._default
- if self._desc: _map["desc"] = self._desc
- return _map
-
- def __repr__(self): return str(self.mapEncode())
-
- def _updateHash(self, hasher):
- """
- Update the given hash object with a hash computed over this schema.
- """
- hasher.update(str(self._type))
- hasher.update(self._dir)
- if self._desc: hasher.update(self._desc)
-
-
-
-def SchemaArgumentFactory( param ):
- """
- Factory for constructing SchemaArguments from various sources
-
- @type param: various
- @param param: object to use for constructing SchemaArgument
- @rtype: SchemaArgument
- @returns: a new SchemaArgument instance
- """
- if type(param) == dict:
- # construct from map
- if not "amqp_type" in param:
- raise TypeError("requires 'amqp_type' value")
-
- return SchemaArgument( param["amqp_type"], param )
-
- else:
- raise TypeError("Invalid type for SchemaArgument construction")
-
-
-
-class SchemaMethod(object):
+class SchemaMethod(_mapEncoder):
"""
The SchemaMethod class describes the method's structure, and contains a
SchemaProperty class for each argument declared by the method.
Map format:
- map["arguments"] = map of "name"=<SchemaArgument> pairs.
+ map["arguments"] = map of "name"=<SchemaProperty> pairs.
map["desc"] = str, description of the method
"""
- def __init__(self, args={}, _desc=None):
+ def __init__(self, args={}, _desc=None, _map=None):
"""
Construct a SchemaMethod.
@@ -1846,9 +1411,22 @@
@type _desc: str
@param _desc: Human-readable description of the schema
"""
+ if _map is not None:
+ _desc = _map.get("desc")
+ margs = _map.get("arguments", args)
+ # margs are in map format - covert to SchemaProperty
+ args = {}
+ for name,val in margs.iteritems():
+ args[name] = SchemaProperty.from_map(val)
+
self._arguments = args.copy()
self._desc = _desc
+ # map constructor
+ def _from_map(cls, map_):
+ return cls(_map=map_)
+ from_map = classmethod(_from_map)
+
def getDesc(self): return self._desc
def getArgCount(self): return len(self._arguments)
@@ -1857,7 +1435,7 @@
def getArgument(self, name): return self._arguments[name]
- def addArgument(self, name, schema):
+ def add_argument(self, name, schema):
"""
Add an argument to the list of arguments passed to this method.
Used by an agent for dynamically creating method schema.
@@ -1871,29 +1449,28 @@
raise TypeError("argument must be a SchemaProperty class")
self._arguments[name] = schema
- def mapEncode(self):
+ def map_encode(self):
"""
Return the map encoding of this schema.
"""
_map = {}
_args = {}
for name,val in self._arguments.iteritems():
- _args[name] = val.mapEncode()
+ _args[name] = val.map_encode()
_map["arguments"] = _args
if self._desc: _map["desc"] = self._desc
return _map
def __repr__(self):
- result = "("
+ result = "SchemaMethod=<<args=("
first = True
for name,arg in self._arguments.iteritems():
- if arg._dir.find("I") != -1:
- if first:
- first = False
- else:
- result += ", "
- result += name
- result += ")"
+ if first:
+ first = False
+ else:
+ result += ", "
+ result += name
+ result += ")>>"
return result
def _updateHash(self, hasher):
@@ -1907,89 +1484,77 @@
-def SchemaMethodFactory( param ):
+class SchemaClass(QmfData):
"""
- Factory for constructing a SchemaMethod from various sources
-
- @type param: various
- @param param: object to use for constructing a SchemaMethod
- @rtype: SchemaMethod
- @returns: a new SchemaMethod instance
- """
- if type(param) == dict:
- # construct from map
- args = {}
- desc = None
- if "arguments" in param:
- for name,val in param["arguments"].iteritems():
- args[name] = SchemaArgumentFactory(val)
- if "desc" in param:
- desc = param["desc"]
-
- return SchemaMethod( args, desc )
-
- else:
- raise TypeError("Invalid type for SchemaMethod construction")
+ Base class for Data and Event Schema classes.
+ Map format:
+ map(QmfData), plus:
+ map["_schema_id"] = map representation of a SchemaClassId instance
+ map["_primary_key_names"] = order list of primary key names
+ """
+ KEY_SCHEMA_ID="_schema_id"
+ KEY_PRIMARY_KEY_NAMES="_primary_key_names"
+ KEY_DESC = "_desc"
+ SUBTYPE_PROPERTY="qmfProperty"
+ SUBTYPE_METHOD="qmfMethod"
-class SchemaClass(QmfData):
- """
- Base class for Data and Event Schema classes.
- """
- def __init__(self, pname, cname, stype, desc=None, hstr=None):
+ def __init__(self, _classId=None, _desc=None, _map=None):
"""
Schema Class constructor.
- @type pname: str
- @param pname: package name
- @type cname: str
- @param cname: class name
- @type stype: str
- @param stype: type of schema, either "data" or "event"
- @type desc: str
- @param desc: Human-readable description of the schema
- @type hstr: str
- @param hstr: hash computed over the schema body, else None
+ @type classId: class SchemaClassId
+ @param classId: Identifier for this SchemaClass
+ @type _desc: str
+ @param _desc: Human-readable description of the schema
"""
- self._pname = pname
- self._cname = cname
- self._type = stype
- self._desc = desc
- if hstr:
- self._classId = SchemaClassId( pname, cname, stype, hstr )
+ if _map is not None:
+ super(SchemaClass, self).__init__(_map=_map)
+
+ # decode each value based on its type
+ for name,value in self._values.iteritems():
+ if self._subtypes.get(name) == self.SUBTYPE_METHOD:
+ self._values[name] = SchemaMethod.from_map(value)
+ else:
+ self._values[name] = SchemaProperty.from_map(value)
+ cid = _map.get(self.KEY_SCHEMA_ID)
+ if cid:
+ _classId = SchemaClassId.from_map(cid)
+ self._object_id_names = _map.get(self.KEY_PRIMARY_KEY_NAMES,[])
+ _desc = _map.get(self.KEY_DESC)
else:
- self._classId = None
- self._properties = {}
- self._methods = {}
- self._pkeyNames = []
+ super(SchemaClass, self).__init__()
+ self._object_id_names = []
+ self._classId = _classId
+ self._desc = _desc
- def getClassId(self):
- if not self._classId:
- self.generateHash()
+ def get_class_id(self):
+ if not self._classId.get_hash_string():
+ self.generate_hash()
return self._classId
- def getDesc(self): return self._desc
+ def get_desc(self): return self._desc
- def generateHash(self):
+ def generate_hash(self):
"""
generate an md5 hash over the body of the schema,
and return a string representation of the hash
in format "%08x-%08x-%08x-%08x"
"""
md5Hash = _md5Obj()
- md5Hash.update(self._pname)
- md5Hash.update(self._cname)
- md5Hash.update(self._type)
- for name,x in self._properties.iteritems():
+ md5Hash.update(self._classId.get_package_name())
+ md5Hash.update(self._classId.get_class_name())
+ md5Hash.update(self._classId.get_type())
+ for name,x in self._values.iteritems():
md5Hash.update(name)
x._updateHash( md5Hash )
- for name,x in self._methods.iteritems():
+ for name,value in self._subtypes.iteritems():
md5Hash.update(name)
- x._updateHash( md5Hash )
+ md5Hash.update(value)
idx = 0
- for name in self._pkeyNames:
+ for name in self._object_id_names:
md5Hash.update(str(idx) + name)
idx += 1
hstr = md5Hash.hexdigest()[0:8] + "-" +\
@@ -1997,65 +1562,70 @@
md5Hash.hexdigest()[16:24] + "-" +\
md5Hash.hexdigest()[24:32]
# update classId with new hash value
- self._classId = SchemaClassId( self._pname,
- self._cname,
- self._type,
- hstr )
+ self._classId._hstr = hstr
return hstr
- def getPropertyCount(self): return len(self._properties)
- def getProperties(self): return self._properties.copy()
- def addProperty(self, name, prop):
- self._properties[name] = prop
+ def get_property_count(self):
+ count = 0
+ for value in self._subtypes.itervalues():
+ if value == self.SUBTYPE_PROPERTY:
+ count += 1
+ return count
+
+ def get_properties(self):
+ props = {}
+ for name,value in self._subtypes.iteritems():
+ if value == self.SUBTYPE_PROPERTY:
+ props[name] = self._values.get(name)
+ return props
+
+ def get_property(self, name):
+ if self._subtypes.get(name) == self.SUBTYPE_PROPERTY:
+ return self._values.get(name)
+ return None
+
+ def add_property(self, name, prop):
+ self.set_value(name, prop, self.SUBTYPE_PROPERTY)
# need to re-generate schema hash
- self._classId = None
+ self._classId._hstr = None
- def getProperty(self, name):
+ def get_value(self, name):
# check for meta-properties first
- if name == QmfQuery._PRED_PACKAGE:
- return self._pname
- if name == QmfQuery._PRED_CLASS:
- return self._cname
- if name == QmfQuery._PRED_TYPE:
- return self._type
- if name == QmfQuery._PRED_HASH:
- return self.getClassId().getHashString()
- if name == QmfQuery._PRED_SCHEMA_ID:
- return self.getClassId()
- return super(SchemaClass, self).getProperty(name)
-
- def hasProperty(self, name):
- if name in [QmfQuery._PRED_PACKAGE, QmfQuery._PRED_CLASS,
- QmfQuery._PRED_TYPE, QmfQuery._PRED_HASH, QmfQuery._PRED_SCHEMA_ID]:
+ if name == SchemaClassId.KEY_PACKAGE:
+ return self._classId.get_package_name()
+ if name == SchemaClassId.KEY_CLASS:
+ return self._classId.get_class_name()
+ if name == SchemaClassId.KEY_TYPE:
+ return self._classId.get_type()
+ if name == SchemaClassId.KEY_HASH:
+ return self.get_class_id().get_hash_string()
+ if name == self.KEY_SCHEMA_ID:
+ return self.get_class_id()
+ if name == self.KEY_PRIMARY_KEY_NAMES:
+ return self._object_id_names[:]
+ return super(SchemaClass, self).get_value(name)
+
+ def has_value(self, name):
+ if name in [SchemaClassId.KEY_PACKAGE, SchemaClassId.KEY_CLASS, SchemaClassId.KEY_TYPE,
+ SchemaClassId.KEY_HASH, self.KEY_SCHEMA_ID, self.KEY_PRIMARY_KEY_NAMES]:
return True
- super(SchemaClass, self).hasProperty(name)
+ super(SchemaClass, self).has_value(name)
- def mapEncode(self):
+ def map_encode(self):
"""
Return the map encoding of this schema.
"""
- _map = {}
- _map["schema_id"] = self.getClassId().mapEncode()
- _map["desc"] = self._desc
- if len(self._properties):
- _props = {}
- for name,val in self._properties.iteritems():
- _props[name] = val.mapEncode()
- _map["properties"] = _props
-
- if len(self._methods):
- _meths = {}
- for name,val in self._methods.iteritems():
- _meths[name] = val.mapEncode()
- _map["methods"] = _meths
-
- if len(self._pkeyNames):
- _map["primary_key"] = self._pkeyNames[:]
+ _map = super(SchemaClass,self).map_encode()
+ _map[self.KEY_SCHEMA_ID] = self.get_class_id().map_encode()
+ if self._object_id_names:
+ _map[self.KEY_PRIMARY_KEY_NAMES] = self._object_id_names[:]
+ if self._desc:
+ _map[self.KEY_DESC] = self._desc
return _map
def __repr__(self):
- return str(self.getClassId())
+ return str(self.get_class_id())
@@ -2067,14 +1637,11 @@
all properties named in the primary key list.
Map format:
- map["schema_id"] = map, SchemaClassId map for this object.
- map["desc"] = human readable description of this schema.
- map["primary_key"] = ordered list of property names used to construct the Primary Key"
- map["properties"] = map of "name":SchemaProperty instances.
- map["methods"] = map of "name":SchemaMethods instances.
+ map(SchemaClass)
"""
- def __init__( self, pname, cname, desc=None, _hash=None,
- _props={}, _pkey=[], _methods={}):
+ def __init__(self, _classId=None, _desc=None,
+ _props={}, _methods={}, _object_id_names=None,
+ _map=None):
"""
@type pname: str
@param pname: name of package this schema belongs to
@@ -2091,64 +1658,46 @@
@type _methods: map of 'name':<SchemaMethod> objects
@param _methods: all methods provided by this schema
"""
- super(SchemaObjectClass, self).__init__(pname,
- cname,
- SchemaTypeData,
- desc,
- _hash)
- self._properties = _props.copy()
- self._pkeyNames = _pkey[:]
- self._methods = _methods.copy()
-
- def getPrimaryKeyList(self): return self._pkeyNames[:]
-
- def getMethodCount(self): return len(self._methods)
- def getMethods(self): return self._methods.copy()
- def getMethod(self, name): return self._methods[name]
- def addMethod(self, name, method):
- self._methods[name] = method
- self._classId = None
-
-
+ if _map is not None:
+ super(SchemaObjectClass,self).__init__(_map=_map)
+ else:
+ super(SchemaObjectClass, self).__init__(_classId=_classId, _desc=_desc)
+ self._object_id_names = _object_id_names
+ for name,value in _props.iteritems():
+ self.set_value(name, value, self.SUBTYPE_PROPERTY)
+ for name,value in _methods.iteritems():
+ self.set_value(name, value, self.SUBTYPE_METHOD)
+
+ if self._classId.get_type() != SchemaClassId.TYPE_DATA:
+ raise TypeError("Invalid ClassId type for data schema: %s" % self._classId)
+
+ def get_id_names(self):
+ return self._object_id_names[:]
+
+ def get_method_count(self):
+ count = 0
+ for value in self._subtypes.itervalues():
+ if value == self.SUBTYPE_METHOD:
+ count += 1
+ return count
+
+ def get_methods(self):
+ meths = {}
+ for name,value in self._subtypes.iteritems():
+ if value == self.SUBTYPE_METHOD:
+ meths[name] = self._values.get(name)
+ return meths
+
+ def get_method(self, name):
+ if self._subtypes.get(name) == self.SUBTYPE_METHOD:
+ return self._values.get(name)
+ return None
-def SchemaObjectClassFactory( param ):
- """
- Factory for constructing a SchemaObjectClass from various sources.
-
- @type param: various
- @param param: object to use for constructing a SchemaObjectClass instance
- @rtype: SchemaObjectClass
- @returns: a new SchemaObjectClass instance
- """
- if type(param) == dict:
- classId = None
- properties = {}
- methods = {}
- pkey = []
- if "schema_id" in param:
- classId = SchemaClassIdFactory(param["schema_id"])
- if (not classId) or (classId.getType() != SchemaTypeData):
- raise TypeError("Invalid SchemaClassId specified: %s" % classId)
- if "desc" in param:
- desc = param["desc"]
- if "primary_key" in param:
- pkey = param["primary_key"]
- if "properties" in param:
- for name,val in param["properties"].iteritems():
- properties[name] = SchemaPropertyFactory(val)
- if "methods" in param:
- for name,val in param["methods"].iteritems():
- methods[name] = SchemaMethodFactory(val)
-
- return SchemaObjectClass( classId.getPackageName(),
- classId.getClassName(),
- desc,
- _hash = classId.getHashString(),
- _props = properties, _pkey = pkey,
- _methods = methods)
+ def add_method(self, name, method):
+ self.set_value(name, method, self.SUBTYPE_METHOD)
+ # need to re-generate schema hash
+ self._classId._hstr = None
- else:
- raise TypeError("Invalid type for SchemaObjectClass construction")
@@ -2162,46 +1711,21 @@
map["desc"] = string description of this schema
map["properties"] = map of "name":SchemaProperty values.
"""
- def __init__( self, pname, cname, desc=None, _props={}, _hash=None ):
- super(SchemaEventClass, self).__init__(pname,
- cname,
- SchemaTypeEvent,
- desc,
- _hash )
- self._properties = _props.copy()
-
+ def __init__(self, _classId=None, _desc=None, _props={},
+ _map=None):
+ if _map is not None:
+ super(SchemaEventClass,self).__init__(_map=_map)
+ else:
+ super(SchemaEventClass, self).__init__(_classId=_classId,
+ _desc=_desc)
+ for name,value in _props.iteritems():
+ self.set_value(name, value, self.SUBTYPE_PROPERTY)
+
+ if self._classId.get_type() != SchemaClassId.TYPE_EVENT:
+ raise TypeError("Invalid ClassId type for event schema: %s" %
+ self._classId)
-def SchemaEventClassFactory( param ):
- """
- Factory for constructing a SchemaEventClass from various sources.
-
- @type param: various
- @param param: object to use for constructing a SchemaEventClass instance
- @rtype: SchemaEventClass
- @returns: a new SchemaEventClass instance
- """
- if type(param) == dict:
- logging.debug( "constructing SchemaEventClass from map '%s'" % param )
- classId = None
- properties = {}
- if "schema_id" in param:
- classId = SchemaClassIdFactory(param["schema_id"])
- if (not classId) or (classId.getType() != SchemaTypeEvent):
- raise TypeError("Invalid SchemaClassId specified: %s" % classId)
- if "desc" in param:
- desc = param["desc"]
- if "properties" in param:
- for name,val in param["properties"].iteritems():
- properties[name] = SchemaPropertyFactory(val)
-
- return SchemaEventClass( classId.getPackageName(),
- classId.getClassName(),
- desc,
- _hash = classId.getHashString(),
- _props = properties )
- else:
- raise TypeError("Invalid type for SchemaEventClass construction")
---------------------------------------------------------------------
Apache Qpid - AMQP Messaging Implementation
Project: http://qpid.apache.org
Use/Interact: mailto:commits-subscribe@qpid.apache.org