diff options
Diffstat (limited to 'python/qmf2/common.py')
-rw-r--r-- | python/qmf2/common.py | 1943 |
1 files changed, 0 insertions, 1943 deletions
diff --git a/python/qmf2/common.py b/python/qmf2/common.py deleted file mode 100644 index 8107b86666..0000000000 --- a/python/qmf2/common.py +++ /dev/null @@ -1,1943 +0,0 @@ -# Licensed to the Apache Software Foundation (ASF) under one -# or more contributor license agreements. See the NOTICE file -# distributed with this work for additional information -# regarding copyright ownership. The ASF licenses this file -# to you under the Apache License, Version 2.0 (the -# "License"); you may not use this file except in compliance -# with the License. You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, -# software distributed under the License is distributed on an -# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY -# KIND, either express or implied. See the License for the -# specific language governing permissions and limitations -# under the License. -# -import time -from logging import getLogger -from threading import Lock -from threading import Condition -try: - import hashlib - _md5Obj = hashlib.md5 -except ImportError: - import md5 - _md5Obj = md5.new - -log = getLogger("qmf") -log_query = getLogger("qmf.query") - - -## -## Constants -## - -AMQP_QMF_SUBJECT = "qmf" -AMQP_QMF_VERSION = 4 -AMQP_QMF_SUBJECT_FMT = "%s%d.%s" - -class MsgKey(object): - agent_info = "agent_info" - query = "query" - package_info = "package_info" - schema_id = "schema_id" - schema = "schema" - object_id="object_id" - data_obj="object" - method="method" - event="event" - - -class OpCode(object): - noop = "noop" - - # codes sent by a console and processed by the agent - agent_locate = "agent-locate" - cancel_subscription = "cancel-subscription" - create_subscription = "create-subscription" - get_query = "get-query" - method_req = "method" - renew_subscription = "renew-subscription" - schema_query = "schema-query" # @todo: deprecate - - # codes sent by the agent to a console - agent_ind = "agent" - data_ind = "data" - event_ind = "event" - managed_object = "managed-object" - object_ind = "object" - response = "response" - schema_ind="schema" # @todo: deprecate - - - - -def make_subject(_code): - """ - Create a message subject field value. - """ - return AMQP_QMF_SUBJECT_FMT % (AMQP_QMF_SUBJECT, AMQP_QMF_VERSION, _code) - - -def parse_subject(_sub): - """ - Deconstruct a subject field, return version,opcode values - """ - if _sub[:3] != "qmf": - raise Exception("Non-QMF message received") - - return _sub[3:].split('.', 1) - -def timedelta_to_secs(td): - """ - Convert a time delta to a time interval in seconds (float) - """ - return td.days * 86400 + td.seconds + td.microseconds/1000000.0 - - -##============================================================================== -## Async Event Model -##============================================================================== - - -class Notifier(object): - """ - Virtual base class that defines a call back which alerts the application that - a QMF Console notification is pending. - """ - def indication(self): - """ - Called when one or more items are ready for the application to process. - This method may be called by an internal QMF library thread. Its purpose is to - indicate that the application should process pending work items. - """ - raise Exception("The indication method must be overridden by the application!") - - - -class WorkItem(object): - """ - Describes an event that has arrived for the application to process. The - Notifier is invoked when one or more of these WorkItems become available - for processing. - """ - # Enumeration of the types of WorkItems produced on the Console - AGENT_ADDED=1 - AGENT_DELETED=2 - NEW_PACKAGE=3 - NEW_CLASS=4 - OBJECT_UPDATE=5 - EVENT_RECEIVED=7 - AGENT_HEARTBEAT=8 - QUERY_COMPLETE=9 - METHOD_RESPONSE=10 - # Enumeration of the types of WorkItems produced on the Agent - METHOD_CALL=1000 - QUERY=1001 - SUBSCRIBE=1002 - UNSUBSCRIBE=1003 - - def __init__(self, kind, handle, _params=None): - """ - Used by the Console to create a work item. - - @type kind: int - @param kind: work item type - """ - self._kind = kind - self._handle = handle - self._params = _params - - def get_type(self): - return self._kind - - def get_handle(self): - return self._handle - - def get_params(self): - return self._params - - - -##============================================================================== -## Addressing -##============================================================================== - -class QmfAddress(object): - """ - Address format: "qmf.<domain>.[topic|direct]/<subject>" - TBD - """ - - TYPE_DIRECT = "direct" - TYPE_TOPIC = "topic" - - ADDRESS_FMT = "qmf.%s.%s/%s" - DEFAULT_DOMAIN = "default" - - # Directly-addressed messages: - # agent's direct address: "qmf.<domain>.direct/<agent-name> - # console's direct address: "qmf.<domain>.direct/<console-name> - - # Well-known Topic Addresses: - # "qmf.<domain>.topic/<subject> - # Where <subject> has the following format: - # "console.ind#" - indications sent from consoles - # "agent.ind#" - indications sent from agents - # - # The following "well known" subjects are defined: - # - # console.ind.locate[.<agent-name>] - agent discovery request - # agent.ind.heartbeat[.<agent-name>"] - agent heartbeats - # agent.ind.event[.<severity>.<agent-name>] - events - # agent.ind.schema[TBD] - schema updates - # - SUBJECT_AGENT_IND="agent.ind" - SUBJECT_AGENT_HEARTBEAT = "agent.ind.heartbeat" - SUBJECT_AGENT_EVENT="agent.ind.event" - SUBJECT_AGENT_SCHEMA="agent.ind.schema" - - SUBJECT_CONSOLE_IND="console.ind" - SUBJECT_CONSOLE_LOCATE_AGENT="console.ind.locate" - - - - def __init__(self, subject, domain, type_): - if '/' in domain or '.' in domain: - raise Exception("domain string must not contain '/' or '.'" - " characters.") - - self._subject = subject - self._domain = domain - self._type = type_ - - def _direct(cls, subject, _domain=None): - if _domain is None: - _domain = QmfAddress.DEFAULT_DOMAIN - return cls(subject, _domain, type_=QmfAddress.TYPE_DIRECT) - direct = classmethod(_direct) - - def _topic(cls, subject, _domain=None): - if _domain is None: - _domain = QmfAddress.DEFAULT_DOMAIN - return cls(subject, _domain, type_=QmfAddress.TYPE_TOPIC) - topic = classmethod(_topic) - - def __from_string(cls, address): - node,subject = address.split('/',1) - qmf,domain,type_ = node.split('.',2) - - if qmf != "qmf" or (type_ != QmfAddress.TYPE_DIRECT and - type_ != QmfAddress.TYPE_TOPIC): - raise ValueError("invalid QmfAddress format: %s" % address) - - return cls(subject, domain, type_) - from_string = classmethod(__from_string) - - def get_address(self): - """ - Return the QMF address as a string, suitable for use with the AMQP - messaging API. - """ - return str(self) - - def get_node(self): - """ - Return the 'node' portion of the address. - """ - return self.get_address().split('/',1)[0] - - def get_subject(self): - """ - Return the 'subject' portion of the address. - """ - return self.get_address().split('/',1)[1] - - def get_domain(self): - return self._domain - - def is_direct(self): - return self._type == self.TYPE_DIRECT - - def __repr__(self): - return QmfAddress.ADDRESS_FMT % (self._domain, self._type, self._subject) - - - - -class AgentName(object): - """ - Uniquely identifies a management agent within the management domain. - """ - _separator = ":" - - def __init__(self, vendor, product, name, _str=None): - """ - Note: this object must be immutable, as it is used to index into a dictionary - """ - if _str is not None: - # construct from string representation - if _str.count(AgentName._separator) < 2: - raise TypeError("AgentName string format must be 'vendor.product.name'") - self._vendor, self._product, self._name = _str.split(AgentName._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 - - def product(self): - return self._product - - def name(self): - return self._name - - def __cmp__(self, other): - if not isinstance(other, AgentName) : - raise TypeError("Invalid types for compare") - # return 1 - me = str(self) - them = str(other) - - if me < them: - return -1 - if me > them: - return 1 - return 0 - - def __hash__(self): - return (self._vendor, self._product, self._name).__hash__() - - def __repr__(self): - return self._vendor + AgentName._separator + \ - self._product + AgentName._separator + \ - self._name - - - -##============================================================================== -## DATA MODEL -##============================================================================== - - -class _mapEncoder(object): - """ - virtual base class for all objects that support being converted to a map - """ - - def map_encode(self): - raise Exception("The map_encode method my be overridden.") - - -class QmfData(_mapEncoder): - """ - Base class representing management data. - - Map format: - 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, _schema_id=None, - _ctime = 0, _utime = 0, _dtime = 0, - _map=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 - """ - 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: - _schema_id = SchemaClassId.from_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)) - - if _object_id is None: - raise Exception("An object_id must be provided.") - - self._values = _values.copy() - self._subtypes = _subtypes.copy() - self._tag = _tag - self._ctime = _ctime - self._utime = _utime - self._dtime = _dtime - self._const = _const - self._schema_id = _schema_id - self._object_id = str(_object_id) - - - def __create(cls, values, _subtypes={}, _tag=None, _object_id=None, - _schema_id=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_id=_schema_id, _const=_const) - create = classmethod(__create) - - def __from_map(cls, map_, _const=False): - return cls(_map=map_, _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): - """ - Will throw an AttributeError exception if the named value does not exist. - """ - # meta-properties first: - 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 - - try: - return self._values[name] - except KeyError: - raise AttributeError("no value named '%s' in this object" % 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 - - return name in self._values - - def set_value(self, _name, _value, _subType=None): - if self._const: - raise Exception("cannot modify constant data object") - self._values[_name] = _value - if _subType: - self._subtypes[_name] = _subType - return _value - - def get_subtype(self, _name): - return self._subtypes.get(_name) - - def get_schema_class_id(self): - """ - @rtype: class SchemaClassId - @returns: the identifier of the Schema that describes the structure of the data. - """ - return self._schema_id - - def get_object_id(self): - """ - Get the instance's identification string. - @rtype: str - @returns: the identification string, or None if not assigned and id. - """ - return self._object_id - - def map_encode(self): - _map = {} - if self._tag: - _map[self.KEY_TAG] = self._tag - - # 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 - - _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 __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 __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 __getitem__(self, _name): - return self.__getattr__(_name) - - def __setitem__(self, _name, _value): - return self.__setattr__(_name, _value) - - - -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. - """ - KEY_TIMESTAMP = "_timestamp" - KEY_SEVERITY = "_severity" - - SEV_EMERG = "emerg" - SEV_ALERT = "alert" - SEV_CRIT = "crit" - SEV_ERR = "err" - SEV_WARNING = "warning" - SEV_NOTICE = "notice" - SEV_INFO = "info" - SEV_DEBUG = "debug" - - def __init__(self, _timestamp=None, _sev=SEV_NOTICE, _values={}, - _subtypes={}, _tag=None, - _map=None, - _schema_id=None, _const=True): - """ - @type _map: dict - @param _map: if not None, construct instance from map representation. - @type _timestamp: int - @param _timestamp: moment in time when event occurred, expressed - as milliseconds since Midnight, Jan 1, 1970 UTC. - @type _agentId: class AgentId - @param _agentId: Identifies agent issuing this event. - @type _schema: class Schema - @param _schema: - @type _schemaId: class SchemaClassId (event) - @param _schemaId: identi - """ - - if _map is not None: - # construct from map - super(QmfEvent, self).__init__(_map=_map, _const=_const, - _object_id="_event") - _timestamp = _map.get(self.KEY_TIMESTAMP, _timestamp) - _sev = _map.get(self.KEY_SEVERITY, _sev) - else: - super(QmfEvent, self).__init__(_object_id="_event", - _values=_values, - _subtypes=_subtypes, _tag=_tag, - _schema_id=_schema_id, - _const=_const) - if _timestamp is None: - raise TypeError("QmfEvent: a valid timestamp is required.") - - try: - self._timestamp = long(_timestamp) - except: - raise TypeError("QmfEvent: a numeric timestamp is required.") - - self._severity = _sev - - def _create(cls, timestamp, severity, values, - _subtypes={}, _tag=None, _schema_id=None, _const=False): - return cls(_timestamp=timestamp, _sev=severity, _values=values, - _subtypes=_subtypes, _tag=_tag, _schema_id=_schema_id, _const=_const) - create = classmethod(_create) - - def _from_map(cls, map_, _const=False): - return cls(_map=map_, _const=_const) - from_map = classmethod(_from_map) - - def get_timestamp(self): - return self._timestamp - - def get_severity(self): - return self._severity - - def map_encode(self): - _map = super(QmfEvent, self).map_encode() - _map[self.KEY_TIMESTAMP] = self._timestamp - _map[self.KEY_SEVERITY] = self._severity - return _map - - - - - -#============================================================================== -#============================================================================== -#============================================================================== - - - - -class Arguments(object): - def __init__(self, map): - pass -# self.map = map -# self._by_hash = {} -# key_count = self.map.keyCount() -# a = 0 -# while a < key_count: -# self._by_hash[self.map.key(a)] = self.by_key(self.map.key(a)) -# a += 1 - - -# def __getitem__(self, key): -# return self._by_hash[key] - - -# def __setitem__(self, key, value): -# self._by_hash[key] = value -# self.set(key, value) - - -# def __iter__(self): -# return self._by_hash.__iter__ - - -# def __getattr__(self, name): -# if name in self._by_hash: -# return self._by_hash[name] -# return super.__getattr__(self, name) - - -# def __setattr__(self, name, value): -# # -# # ignore local data members -# # -# if (name[0] == '_' or -# name == 'map'): -# return super.__setattr__(self, name, value) - -# if name in self._by_hash: -# self._by_hash[name] = value -# return self.set(name, value) - -# return super.__setattr__(self, name, value) - - -# def by_key(self, key): -# val = self.map.byKey(key) -# 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? '%s'" % str(val.getType())) -# return None - - -# def set(self, key, value): -# val = self.map.byKey(key) -# vType = val.getType() -# if vType == TYPE_UINT8: return val.setUint(value) -# elif vType == TYPE_UINT16: return val.setUint(value) -# elif vType == TYPE_UINT32: return val.setUint(value) -# elif vType == TYPE_UINT64: return val.setUint64(value) -# elif vType == TYPE_SSTR: -# if value: -# return val.setString(value) -# else: -# return val.setString('') -# elif vType == TYPE_LSTR: -# if value: -# return val.setString(value) -# else: -# return val.setString('') -# elif vType == TYPE_ABSTIME: return val.setInt64(value) -# elif vType == TYPE_DELTATIME: return val.setUint64(value) -# elif vType == TYPE_REF: return val.setObjectId(value.impl) -# elif vType == TYPE_BOOL: return val.setBool(value) -# elif vType == TYPE_FLOAT: return val.setFloat(value) -# elif vType == TYPE_DOUBLE: return val.setDouble(value) -# elif vType == TYPE_UUID: return val.setUuid(value) -# elif vType == TYPE_INT8: return val.setInt(value) -# elif vType == TYPE_INT16: return val.setInt(value) -# elif vType == TYPE_INT32: return val.setInt(value) -# elif vType == TYPE_INT64: return val.setInt64(value) -# else: -# # when TYPE_MAP -# # when TYPE_OBJECT -# # when TYPE_LIST -# # when TYPE_ARRAY -# logging.error("Unsupported Type for Set? '%s'" % str(val.getType())) -# return None - - - -#class MethodResponse(object): -# def __init__(self, impl): -# pass -# self.impl = qmfengine.MethodResponse(impl) - - -# def status(self): -# return self.impl.getStatus() - - -# def exception(self): -# return self.impl.getException() - - -# def text(self): -# return exception().asString() - - -# def args(self): -# return Arguments(self.impl.getArgs()) - - -# def __getattr__(self, name): -# myArgs = self.args() -# return myArgs.__getattr__(name) - - -# def __setattr__(self, name, value): -# if name == 'impl': -# return super.__setattr__(self, name, value) - -# myArgs = self.args() -# return myArgs.__setattr__(name, value) - - - -# ##============================================================================== -# ## QUERY -# ##============================================================================== - - - -# def _doQuery(predicate, params ): -# """ -# Given the predicate from a query, and a map of named parameters, apply the predicate -# to the parameters, and return True or False. -# """ -# if type(predicate) != list or len(predicate) < 1: -# return False - -# elif opr == Query._LOGIC_AND: -# logging.debug("_doQuery() AND: [%s]" % predicate ) -# rc = False -# for exp in predicate[1:]: -# rc = _doQuery( exp, params ) -# if not rc: -# break -# return rc - -# elif opr == Query._LOGIC_OR: -# logging.debug("_doQuery() OR: [%s]" % predicate ) -# rc = False -# for exp in predicate[1:]: -# rc = _doQuery( exp, params ) -# if rc: -# break -# return rc - -# elif opr == Query._LOGIC_NOT: -# logging.debug("_doQuery() NOT: [%s]" % predicate ) -# if len(predicate) != 2: -# logging.warning("Malformed query not-expression received: '%s'" % predicate) -# return False -# return not _doQuery( predicate[1:], params ) - - - -# else: -# logging.warning("Unknown query operator received: '%s'" % opr) -# return False - - - -class QmfQuery(_mapEncoder): - - KEY_TARGET="what" - KEY_PREDICATE="where" - KEY_ID="id" - - ### Query Types - ID=1 - PREDICATE=2 - - #### Query Targets #### - TARGET_PACKAGES="schema_package" - # (returns just package names) - # allowed predicate key(s): - # - # SchemaClassId.KEY_PACKAGE - - TARGET_SCHEMA_ID="schema_id" - TARGET_SCHEMA="schema" - # allowed id: value: - # SchemaClassId - # - # allowed predicate key(s): - # SchemaClassId.KEY_PACKAGE - # SchemaClassId.KEY_CLASS - # SchemaClassId.KEY_TYPE - # SchemaClassId.KEY_HASH - # SchemaClass.KEY_SCHEMA_ID - # name of property (exist test only) - # name of method (exist test only) - - TARGET_AGENT="agent" - # allowed id: value: - # string name of agent - # allowed predicate keys(s): - # - KEY_AGENT_NAME="_name" - - TARGET_OBJECT_ID="object_id" - TARGET_OBJECT="object" - # If object is described by a schema, the value of the target map must - # include a "_schema_id": {map encoded schema id} value. - # - # allowed id: value: - # object_id string - # - # allowed predicate keys(s): - # - # QmfData.KEY_OBJECT_ID - # QmfData.KEY_UPDATE_TS - # QmfData.KEY_CREATE_TS - # QmfData.KEY_DELETE_TS - # <name of data value> - - # supported predicate operators - - # evaluation operators - QUOTE="quote" - UNQUOTE="unquote" - # boolean operators - EQ="eq" - NE="ne" - LT="lt" - LE="le" - GT="gt" - GE="ge" - RE_MATCH="re_match" - EXISTS="exists" - TRUE="true" - FALSE="false" - # logic operators - AND="and" - OR="or" - NOT="not" - - _valid_targets = [TARGET_PACKAGES, TARGET_OBJECT_ID, TARGET_SCHEMA, TARGET_SCHEMA_ID, - TARGET_OBJECT, TARGET_AGENT] - _valid_bool_ops = [EQ, NE, LT, GT, LE, GE, EXISTS, RE_MATCH, TRUE, FALSE] - _valid_logic_ops = [AND, OR, NOT] - _valid_eval_ops = [QUOTE, UNQUOTE] - - def __init__(self, _target=None, _target_params=None, _predicate=None, - _id=None, _map=None): - """ - """ - if _map is not None: - target_map = _map.get(self.KEY_TARGET) - if not target_map: - raise TypeError("QmfQuery requires a target map") - - _target = None - for key in target_map.iterkeys(): - if key in self._valid_targets: - _target = key - break - if _target is None: - raise TypeError("Invalid QmfQuery target: '%s'" % - str(target_map)) - - # convert target params from map format - _target_params = target_map.get(_target) - if _target_params: - if not isinstance(_target_params, type({})): - raise TypeError("target params must be a map: '%s'" % - str(_target_params)) - t_params = {} - for name,value in _target_params.iteritems(): - if name == QmfData.KEY_SCHEMA_ID: - t_params[name] = SchemaClassId.from_map(value) - else: - t_params[name] = value - _target_params = t_params - - _id = _map.get(self.KEY_ID) - if _id is not None: - # Convert identifier to native type if necessary - if _target == self.TARGET_SCHEMA: - _id = SchemaClassId.from_map(_id) - else: - _predicate = _map.get(self.KEY_PREDICATE, _predicate) - - self._target = _target - if not self._target: - raise TypeError("QmfQuery requires a target value") - self._target_params = _target_params - self._predicate = _predicate - self._id = _id - - # constructors - def _create_wildcard(cls, target, _target_params=None): - return cls(_target=target, _target_params=_target_params) - create_wildcard = classmethod(_create_wildcard) - - def _create_wildcard_object_id(cls, schema_id): - """ - Create a wildcard to match all object_ids for a given schema. - """ - if not isinstance(schema_id, SchemaClassId): - raise TypeError("class SchemaClassId expected") - params = {QmfData.KEY_SCHEMA_ID: schema_id} - return cls(_target=QmfQuery.TARGET_OBJECT_ID, - _target_params=params) - create_wildcard_object_id = classmethod(_create_wildcard_object_id) - - def _create_wildcard_object(cls, schema_id): - """ - Create a wildcard to match all objects for a given schema. - """ - if not isinstance(schema_id, SchemaClassId): - raise TypeError("class SchemaClassId expected") - params = {QmfData.KEY_SCHEMA_ID: schema_id} - return cls(_target=QmfQuery.TARGET_OBJECT, - _target_params=params) - create_wildcard_object = classmethod(_create_wildcard_object) - - def _create_predicate(cls, target, predicate, _target_params=None): - return cls(_target=target, _target_params=_target_params, - _predicate=predicate) - create_predicate = classmethod(_create_predicate) - - def _create_id(cls, target, ident, _target_params=None): - return cls(_target=target, _target_params=_target_params, _id=ident) - create_id = classmethod(_create_id) - - def _create_id_object(cls, object_id, _schema_id=None): - """ - Create a ID Query for an object (schema optional). - """ - if _schema_id is not None: - if not isinstance(_schema_id, SchemaClassId): - raise TypeError("class SchemaClassId expected") - params = {QmfData.KEY_SCHEMA_ID: _schema_id} - else: - params = None - return cls(_target=QmfQuery.TARGET_OBJECT, - _id=object_id, - _target_params=params) - create_id_object = classmethod(_create_id_object) - - def _create_id_object_id(cls, object_id, _schema_id=None): - """ - Create a ID Query for object_ids (schema optional). - """ - if _schema_id is not None: - if not isinstance(_schema_id, SchemaClassId): - raise TypeError("class SchemaClassId expected") - params = {QmfData.KEY_SCHEMA_ID: _schema_id} - else: - params = None - return cls(_target=QmfQuery.TARGET_OBJECT_ID, - _id=object_id, - _target_params=params) - create_id_object_id = classmethod(_create_id_object_id) - - def _from_map(cls, map_): - return cls(_map=map_) - from_map = classmethod(_from_map) - # end constructors - - def get_target(self): - return self._target - - def get_target_param(self): - return self._target_params - - def get_selector(self): - if self._id: - return QmfQuery.ID - else: - return QmfQuery.PREDICATE - - def get_id(self): - return self._id - - def get_predicate(self): - """ - """ - return self._predicate - - def evaluate(self, qmfData): - """ - """ - if self._id: - if self._target == self.TARGET_SCHEMA: - return (qmfData.has_value(qmfData.KEY_SCHEMA_ID) and - qmfData.get_value(qmfData.KEY_SCHEMA_ID) == self._id) - elif self._target == self.TARGET_OBJECT: - return (qmfData.has_value(qmfData.KEY_OBJECT_ID) and - qmfData.get_value(qmfData.KEY_OBJECT_ID) == self._id) - elif self._target == self.TARGET_AGENT: - return (qmfData.has_value(self.KEY_AGENT_NAME) and - qmfData.get_value(self.KEY_AGENT_NAME) == self._id) - - raise Exception("Unsupported query target '%s'" % str(self._target)) - - if self._predicate: - return self._eval_pred(self._predicate, qmfData) - # no predicate and no id - always match - return True - - def map_encode(self): - t_params = {} - if self._target_params: - for name,value in self._target_params.iteritems(): - if isinstance(value, _mapEncoder): - t_params[name] = value.map_encode() - else: - t_params[name] = value - if t_params: - _map = {self.KEY_TARGET: {self._target: t_params}} - else: - _map = {self.KEY_TARGET: {self._target: None}} - - if self._id is not None: - if isinstance(self._id, _mapEncoder): - _map[self.KEY_ID] = self._id.map_encode() - else: - _map[self.KEY_ID] = self._id - elif self._predicate is not None: - _map[self.KEY_PREDICATE] = self._predicate - return _map - - def _eval_pred(self, pred, qmfData): - """ - Evaluate the predicate expression against a QmfData object. - """ - if not isinstance(qmfData, QmfData): - raise TypeError("Query expects to evaluate QmfData types.") - - if not isinstance(pred, type([])): - log_query.warning("Invalid type for predicate expression: '%s'" % str(pred)) - return False - - # empty predicate - match all??? - if len(pred) == 0: - return True - - oper = pred[0] - if oper == QmfQuery.TRUE: - log_query.debug("query evaluate TRUE") - return True - - if oper == QmfQuery.FALSE: - log_query.debug("query evaluate FALSE") - return False - - if oper == QmfQuery.AND: - log_query.debug("query evaluate AND: '%s'" % str(pred)) - for exp in pred[1:]: - if not self._eval_pred(exp, qmfData): - log_query.debug("---> False") - return False - log_query.debug("---> True") - return True - - if oper == QmfQuery.OR: - log_query.debug("query evaluate OR: [%s]" % str(pred)) - for exp in pred[1:]: - if self._eval_pred(exp, qmfData): - log_query.debug("---> True") - return True - log_query.debug("---> False") - return False - - if oper == QmfQuery.NOT: - log_query.debug("query evaluate NOT: [%s]" % str(pred)) - for exp in pred[1:]: - if self._eval_pred(exp, qmfData): - log_query.debug("---> False") - return False - log_query.debug("---> True") - return True - - if oper == QmfQuery.EXISTS: - if len(pred) != 2: - log_query.warning("Malformed query: 'exists' operator" - " - bad arguments '%s'" % str(pred)) - return False - ### Q: Should we assume "quote", or should it be explicit? - ### "foo" or ["quote" "foo"] - ### my guess is "explicit" - log_query.debug("query evaluate EXISTS: [%s]" % str(pred)) - try: - arg = self._fetch_pred_arg(pred[1], qmfData) - except AttributeError: - log_query.debug("query parameter not found: '%s'" % str(pred)) - return False - v = qmfData.has_value(arg) - log_query.debug("---> %s" % str(v)) - return v - - # binary operators - if oper in [QmfQuery.EQ, QmfQuery.NE, QmfQuery.LT, - QmfQuery.LE, QmfQuery.GT, QmfQuery.GE, - QmfQuery.RE_MATCH]: - if len(pred) != 3: - log_query.warning("Malformed query: '%s' operator" - " - requires 2 arguments '%s'" % - (oper, str(pred))) - return False - # @todo: support regular expression match - log_query.debug("query evaluate binary op: [%s]" % str(pred)) - try: - arg1 = self._fetch_pred_arg(pred[1], qmfData) - arg2 = self._fetch_pred_arg(pred[2], qmfData) - except AttributeError: - log_query.debug("query parameter not found: '%s'" % str(pred)) - return False - log_query.debug("query evaluate %s: %s, %s" % (oper, str(arg1), str(arg2))) - v = False - try: - if oper == QmfQuery.EQ: v = arg1 == arg2 - elif oper == QmfQuery.NE: v = arg1 != arg2 - elif oper == QmfQuery.LT: v = arg1 < arg2 - elif oper == QmfQuery.LE: v = arg1 <= arg2 - elif oper == QmfQuery.GT: v = arg1 > arg2 - elif oper == QmfQuery.GE: v = arg1 >= arg2 - except TypeError: - log_query.warning("query comparison failed: '%s'" % str(pred)) - log_query.debug("---> %s" % str(v)) - return v - - log_query.warning("Unrecognized query operator: [%s]" % str(pred[0])) - return False - - def _fetch_pred_arg(self, arg, qmfData): - """ - Determine the value of a predicate argument by evaluating quoted - arguments. - """ - if isinstance(arg, basestring): - return qmfData.get_value(arg) - if isinstance(arg, type([])) and len(arg) == 2: - if arg[0] == QmfQuery.QUOTE: - return arg[1] - if arg[0] == QmfQuery.UNQUOTE: - return qmfData.get_value(arg[1]) - return arg - - def __repr__(self): - return "QmfQuery=<<" + str(self.map_encode()) + ">>" - - - - - -##============================================================================== -## SCHEMA -##============================================================================== - - -# Argument typecodes, access, and direction qualifiers - -class qmfTypes(object): - TYPE_UINT8 = 1 - TYPE_UINT16 = 2 - TYPE_UINT32 = 3 - TYPE_UINT64 = 4 - - TYPE_SSTR = 6 - TYPE_LSTR = 7 - - TYPE_ABSTIME = 8 - TYPE_DELTATIME = 9 - - TYPE_REF = 10 - - TYPE_BOOL = 11 - - TYPE_FLOAT = 12 - TYPE_DOUBLE = 13 - - TYPE_UUID = 14 - - TYPE_MAP = 15 - - TYPE_INT8 = 16 - TYPE_INT16 = 17 - TYPE_INT32 = 18 - TYPE_INT64 = 19 - - TYPE_OBJECT = 20 - - TYPE_LIST = 21 - - TYPE_ARRAY = 22 - -# New subtypes: -# integer (for time, duration, signed/unsigned) -# double (float) -# bool -# string -# map (ref, qmfdata) -# list -# uuid - - -class qmfAccess(object): - READ_CREATE = 1 - READ_WRITE = 2 - READ_ONLY = 3 - - -class qmfDirection(object): - DIR_IN = 1 - DIR_OUT = 2 - DIR_IN_OUT = 3 - - - -def _to_bool( param ): - """ - Helper routine to convert human-readable representations of - boolean values to python bool types. - """ - _false_strings = ["off", "no", "false", "0", "none"] - _true_strings = ["on", "yes", "true", "1"] - if type(param) == str: - lparam = param.lower() - if lparam in _false_strings: - return False - if lparam in _true_strings: - return True - raise TypeError("unrecognized boolean string: '%s'" % param ) - else: - return bool(param) - - - -class SchemaClassId(_mapEncoder): - """ - Unique identifier for an instance of a SchemaClass. - - Map format: - map["package_name"] = str, name of associated package - map["class_name"] = str, name of associated class - map["type"] = str, "data"|"event", default: "data" - optional: - map["hash_str"] = str, hash value in standard format or None - if hash is unknown. - """ - 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 [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 not in SchemaClassId._valid_types: - raise TypeError("Invalid SchemaClassId type: '%s'" % stype) - self._type = stype - self._hstr = hstr - if self._hstr: - try: - # sanity check the format of the hash string - hexValues = hstr.split("-") - h0 = int(hexValues[0], 16) - h1 = int(hexValues[1], 16) - h2 = int(hexValues[2], 16) - h3 = int(hexValues[3], 16) - 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 get_package_name(self): - """ - Access the package name in the SchemaClassId. - - @rtype: str - """ - return self._pname - - - def get_class_name(self): - """ - Access the class name in the SchemaClassId - - @rtype: str - """ - return self._cname - - - def get_hash_string(self): - """ - Access the schema's hash as a string value - - @rtype: str - """ - return self._hstr - - - def get_type(self): - """ - Returns the type code associated with this Schema - - @rtype: str - """ - return self._type - - def map_encode(self): - _map = {} - _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): - hstr = self.get_hash_string() - if not hstr: - hstr = SchemaClassId._schemaHashStrDefault - return self._pname + ":" + self._cname + ":" + self._type + "(" + hstr + ")" - - - def __cmp__(self, other): - 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) - them = str(other) - if me < them: - return -1 - if me > them: - return 1 - return 0 - - - def __hash__(self): - return (self._pname, self._cname, self._hstr).__hash__() - - - -class SchemaProperty(_mapEncoder): - """ - Describes the structure of a Property data object. - Map format: - map["amqp_type"] = int, AMQP type code indicating property's data type - - optional: - map["access"] = str, access allowed to this property, default "RO" - map["index"] = bool, True if this property is an index value, default False - map["optional"] = bool, True if this property is optional, default False - map["unit"] = str, describes units used - map["min"] = int, minimum allowed value - map["max"] = int, maximun allowed value - map["maxlen"] = int, if string type, this is the maximum length in bytes - required to represent the longest instance of this string. - map["desc"] = str, human-readable description of this argument - map["reference"] = str, ??? - map["parent_ref"] = bool, true if this property references an object in - which this object is in a child-parent relationship. Default False - """ - __hash__ = None - _access_strings = ["RO","RW","RC"] - _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 - self._unit = None - self._min = None - self._max = None - self._maxlen = None - self._desc = None - self._reference = None - self._isParentRef = False - self._dir = None - self._default = None - - for key, value in kwargs.items(): - if key == "access": - value = str(value).upper() - if value not in self._access_strings: - raise TypeError("invalid value for access parameter: '%s':" % value ) - self._access = value - elif key == "index" : self._isIndex = _to_bool(value) - elif key == "optional": self._isOptional = _to_bool(value) - elif key == "unit" : self._unit = value - elif key == "min" : self._min = value - elif key == "max" : self._max = value - elif key == "maxlen" : self._maxlen = value - elif key == "desc" : self._desc = value - elif key == "reference" : self._reference = value - elif key == "parent_ref" : self._isParentRef = _to_bool(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 get_type(self): return self._type - - def get_access(self): return self._access - - def is_optional(self): return self._isOptional - - def is_index(self): return self._isIndex - - def get_unit(self): return self._unit - - def get_min(self): return self._min - - def get_max(self): return self._max - - def get_max_len(self): return self._maxlen - - def get_desc(self): return self._desc - - def get_reference(self): return self._reference - - def is_parent_ref(self): return self._isParentRef - - def get_direction(self): return self._dir - - def get_default(self): return self._default - - def map_encode(self): - """ - Return the map encoding of this schema. - """ - _map = {} - _map["amqp_type"] = self._type - _map["access"] = self._access - _map["index"] = self._isIndex - _map["optional"] = self._isOptional - if self._unit: _map["unit"] = self._unit - if self._min: _map["min"] = self._min - if self._max: _map["max"] = self._max - if self._maxlen: _map["maxlen"] = self._maxlen - 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 "SchemaProperty=<<" + str(self.map_encode()) + ">>" - - def _update_hash(self, hasher): - """ - Update the given hash object with a hash computed over this schema. - """ - hasher.update(str(self._type)) - hasher.update(str(self._isIndex)) - hasher.update(str(self._isOptional)) - 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) - - - -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"=<SchemaProperty> pairs. - map["desc"] = str, description of the method - """ - KEY_NAME="_name" - KEY_ARGUMENTS="_arguments" - KEY_DESC="_desc" - KEY_ERROR="_error" - def __init__(self, _args={}, _desc=None, _map=None): - """ - Construct a SchemaMethod. - - @type args: map of "name"=<SchemaProperty> objects - @param args: describes the arguments accepted by the method - @type _desc: str - @param _desc: Human-readable description of the schema - """ - if _map is not None: - _desc = _map.get(self.KEY_DESC) - margs = _map.get(self.KEY_ARGUMENTS) - if margs: - # margs are in map format - covert to SchemaProperty - tmp_args = {} - for name,val in margs.iteritems(): - tmp_args[name] = SchemaProperty.from_map(val) - _args=tmp_args - - self._arguments = _args.copy() - self._desc = _desc - - # map constructor - def _from_map(cls, map_): - return cls(_map=map_) - from_map = classmethod(_from_map) - - def get_desc(self): return self._desc - - def get_arg_count(self): return len(self._arguments) - - def get_arguments(self): return self._arguments.copy() - - def get_argument(self, name): return self._arguments.get(name) - - 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. - - @type name: string - @param name: name of new argument - @type schema: SchemaProperty - @param schema: SchemaProperty to add to this method - """ - if not isinstance(schema, SchemaProperty): - raise TypeError("argument must be a SchemaProperty class") - # "Input" argument, by default - if schema._dir is None: - schema._dir = "I" - self._arguments[name] = schema - - def map_encode(self): - """ - Return the map encoding of this schema. - """ - _map = {} - _args = {} - for name,val in self._arguments.iteritems(): - _args[name] = val.map_encode() - _map[self.KEY_ARGUMENTS] = _args - if self._desc: _map[self.KEY_DESC] = self._desc - return _map - - def __repr__(self): - result = "SchemaMethod=<<args=(" - first = True - for name,arg in self._arguments.iteritems(): - if first: - first = False - else: - result += ", " - result += name - result += ")>>" - return result - - def _update_hash(self, hasher): - """ - Update the given hash object with a hash computed over this schema. - """ - for name,val in self._arguments.iteritems(): - hasher.update(name) - val._update_hash(hasher) - if self._desc: hasher.update(self._desc) - - - -class SchemaClass(QmfData): - """ - 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_PRIMARY_KEY_NAMES="_primary_key_names" - KEY_DESC = "_desc" - - SUBTYPE_PROPERTY="qmfProperty" - SUBTYPE_METHOD="qmfMethod" - - def __init__(self, _classId=None, _desc=None, _map=None): - """ - Schema Class constructor. - - @type classId: class SchemaClassId - @param classId: Identifier for this SchemaClass - @type _desc: str - @param _desc: Human-readable description of the schema - """ - 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: - if _classId is None: - raise Exception("A class identifier must be supplied.") - super(SchemaClass, self).__init__(_object_id=str(_classId)) - self._object_id_names = [] - - self._classId = _classId - self._desc = _desc - - def get_class_id(self): - if not self._classId.get_hash_string(): - self.generate_hash() - return self._classId - - def get_desc(self): return self._desc - - 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._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._update_hash( md5Hash ) - for name,value in self._subtypes.iteritems(): - md5Hash.update(name) - md5Hash.update(value) - idx = 0 - for name in self._object_id_names: - md5Hash.update(str(idx) + name) - idx += 1 - hstr = md5Hash.hexdigest()[0:8] + "-" +\ - md5Hash.hexdigest()[8:16] + "-" +\ - md5Hash.hexdigest()[16:24] + "-" +\ - md5Hash.hexdigest()[24:32] - # update classId with new hash value - self._classId._hstr = hstr - return hstr - - - 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._hstr = None - - def get_value(self, name): - # check for meta-properties first - 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).has_value(name) - - def map_encode(self): - """ - Return the map encoding of this schema. - """ - _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.get_class_id()) - - - -class SchemaObjectClass(SchemaClass): - """ - A schema class that describes a data object. The data object is composed - of zero or more properties and methods. An instance of the SchemaObjectClass - can be identified using a key generated by concantenating the values of - all properties named in the primary key list. - - Map format: - map(SchemaClass) - """ - def __init__(self, _classId=None, _desc=None, - _props={}, _methods={}, _object_id_names=[], - _map=None): - """ - @type pname: str - @param pname: name of package this schema belongs to - @type cname: str - @param cname: class name for this schema - @type desc: str - @param desc: Human-readable description of the schema - @type _hash: str - @param _methods: hash computed on the body of this schema, if known - @type _props: map of 'name':<SchemaProperty> objects - @param _props: all properties provided by this schema - @type _pkey: list of strings - @param _pkey: names of each property to be used for constructing the primary key - @type _methods: map of 'name':<SchemaMethod> objects - @param _methods: all methods provided by this schema - """ - 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) - - # map constructor - def __from_map(cls, map_): - return cls(_map=map_) - from_map = classmethod(__from_map) - - 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 add_method(self, name, method): - self.set_value(name, method, self.SUBTYPE_METHOD) - # need to re-generate schema hash - self._classId._hstr = None - - - - -class SchemaEventClass(SchemaClass): - """ - A schema class that describes an event. The event is composed - of zero or more properties. - - Map format: - map["schema_id"] = map, SchemaClassId map for this object. - map["desc"] = string description of this schema - map["properties"] = map of "name":SchemaProperty values. - """ - 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) - - # map constructor - def __from_map(cls, map_): - return cls(_map=map_) - from_map = classmethod(__from_map) - |