qpid-commits mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From gmur...@apache.org
Subject [4/9] qpid-dispatch git commit: DISPATCH-437 - Work in progress
Date Thu, 11 Aug 2016 17:42:57 GMT
DISPATCH-437 - Work in progress


Project: http://git-wip-us.apache.org/repos/asf/qpid-dispatch/repo
Commit: http://git-wip-us.apache.org/repos/asf/qpid-dispatch/commit/0beb839d
Tree: http://git-wip-us.apache.org/repos/asf/qpid-dispatch/tree/0beb839d
Diff: http://git-wip-us.apache.org/repos/asf/qpid-dispatch/diff/0beb839d

Branch: refs/heads/DISPATCH-437-1
Commit: 0beb839d44c9161d2421403dd8436a187044c685
Parents: 1df9681
Author: Ganesh Murthy <gmurthy@redhat.com>
Authored: Fri Aug 5 10:33:29 2016 -0400
Committer: Ganesh Murthy <gmurthy@redhat.com>
Committed: Fri Aug 5 10:33:29 2016 -0400

----------------------------------------------------------------------
 .../management/schema/qd_schema.py              | 699 +++++++++++++++++++
 1 file changed, 699 insertions(+)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/qpid-dispatch/blob/0beb839d/python/qpid_dispatch_internal/management/schema/qd_schema.py
----------------------------------------------------------------------
diff --git a/python/qpid_dispatch_internal/management/schema/qd_schema.py b/python/qpid_dispatch_internal/management/schema/qd_schema.py
new file mode 100644
index 0000000..0131bb2
--- /dev/null
+++ b/python/qpid_dispatch_internal/management/schema/qd_schema.py
@@ -0,0 +1,699 @@
+##
+## 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
+##
+
+"""
+Schema for AMQP management entity types.
+
+Schema validation will validate and transform values, add default values and
+check for uniqueness of enties/attributes that are specified to be unique.
+
+A Schema can be loaded/dumped to a json file.
+"""
+
+import sys
+from qpid_dispatch.management.entity import EntityBase
+from qpid_dispatch.management.error import NotImplementedStatus
+from ...compat import OrderedDict, JSON_LOAD_KWARGS
+import json
+from pkgutil import get_data
+
+class ValidationError(Exception):
+    """Error raised if schema validation fails"""
+    pass
+
+def quotestr(value, quote="'"):
+    """Quote value if it is a string type, str() it if not """
+    if isinstance(value, basestring): return "'%s'" % value
+    else: return str(value)
+
+
+class Type(object):
+    """Base class for schema types.
+
+    @ivar name: The type name.
+    @ivar pytype: The python type for this schema type.
+    """
+    def __init__(self, name, pytype):
+        """
+        @param name: The type name.
+        @param pytype: The python type for this schema type.
+        """
+        self.name, self.pytype = name, pytype
+
+    def validate(self, value, **kwargs): # pylint: disable=unused-argument
+        """
+        Convert value to the correct python type.
+
+        @param kwargs: See L{Schema.validate_all}
+        """
+        return self.pytype(value)
+
+    def dump(self):
+        """
+        @return: Representation of the type to dump to json. Normally the type name,
+            EnumType.dump is the exception.
+        """
+        return self.name
+
+    def __str__(self):
+        """String name of type."""
+        return str(self.dump())
+
+
+class BooleanType(Type):
+    """A boolean schema type"""
+
+    def __init__(self):
+        super(BooleanType, self).__init__("boolean", bool)
+
+    VALUES = {"yes":1, "true":1, "on":1, "no":0, "false":0, "off":0}
+
+    def validate(self, value, **kwargs):
+        """
+        @param value: A string such as "yes", "false" etc. is converted appropriately.
+            Any other type is converted using python's bool()
+        @param kwargs: See L{Schema.validate_all}
+        @return A python bool.
+        """
+        try:
+            if isinstance(value, basestring):
+                return self.VALUES[value.lower()]
+            return bool(value)
+        except:
+            raise ValidationError("Invalid Boolean value '%r'"%value)
+
+
+class EnumValue(str):
+    """A string that convets to an integer value via int()"""
+
+    def __new__(cls, name, value):
+        s = super(EnumValue, cls).__new__(cls, name)
+        setattr(s, 'value', value)
+        return s
+
+    def __int__(self): return self.value
+    def __eq__(self, x): return str(self) == x or int(self) == x
+    def __ne__(self, x): return not self == x
+    def __repr__(self): return "EnumValue('%s', %s)"%(str(self), int(self))
+
+
+class EnumType(Type):
+    """An enumerated type"""
+
+    def __init__(self, tags):
+        """
+        @param tags: A list of string values for the enumerated type.
+        """
+        assert isinstance(tags, list)
+        super(EnumType, self).__init__("enum%s"%([str(t) for t in tags]), int)
+        self.tags = tags
+
+    def validate(self, value, **kwargs):
+        """
+        @param value: May be a string from the set of enum tag strings or anything
+            that can convert to an int - in which case it must be in the enum range.
+        @param kwargs: See L{Schema.validate_all}
+        @return: An EnumValue.
+        """
+        if value in self.tags:
+            return EnumValue(value, self.tags.index(value))
+        else:
+            try:
+                i = int(value)
+                return EnumValue(self.tags[i], i)
+            except (ValueError, IndexError):
+                pass
+        raise ValidationError("Invalid value for %s: %r"%(self.name, value))
+
+    def dump(self):
+        """
+        @return: A list of the enum tags.
+        """
+        return self.tags
+
+    def __str__(self):
+        """String description of enum type."""
+        return "One of [%s]" % ', '.join([quotestr(tag) for tag in self.tags])
+
+BUILTIN_TYPES = OrderedDict(
+    (t.name, t) for t in [Type("string", str),
+                          Type("path", str),
+                          Type("entityId", str),
+                          Type("integer", int),
+                          Type("list", list),
+                          Type("map", dict),
+                          Type("dict", dict),
+                          BooleanType()])
+
+def get_type(rep):
+    """
+    Get a schema type.
+    @param rep: json representation of the type.
+    """
+    if isinstance(rep, list):
+        return EnumType(rep)
+    if rep in BUILTIN_TYPES:
+        return BUILTIN_TYPES[rep]
+    raise ValidationError("No such schema type: %s" % rep)
+
+def _dump_dict(items):
+    """
+    Remove all items with None value from a mapping.
+    @return: Map of non-None items.
+    """
+    return OrderedDict((k, v) for k, v in items if v)
+
+def _is_unique(found, item):
+    """
+    Return true if found is None or item is not in found (adds item to found.)
+    Return false if item is in found.
+    """
+    if found is None or found is False:
+        return True
+    if item not in found:
+        found.add(item)
+        return True
+    return False
+
+class AttributeType(object):
+    """
+    Definition of an attribute.
+
+    @ivar name: Attribute name.
+    @ivar atype: Attribute L{Type}
+    @ivar required: True if the attribute is required.
+    @ivar default: Default value for the attribute or None if no default. Can be a reference.
+    @ivar value: Fixed value for the attribute. Can be a reference.
+    @ivar unique: True if the attribute value is unique.
+    @ivar description: Description of the attribute type.
+    @ivar defined_in: EntityType in which this attribute is defined.
+    @ivar create: If true the attribute can be set by CREATE.
+    @ivar update: If true the attribute can be modified by UPDATE.
+    @ivar graph: If true the attribute could be graphed by a console.
+    """
+
+    def __init__(self, name, type=None, defined_in=None, default=None,
+                 required=False, unique=False, hidden=False, deprecated=False,
+                 value=None, description="", create=False, update=False, graph=False, ordinality=0):
+        """
+        See L{AttributeType} instance variables.
+        """
+        try:
+            self.name = name
+            self.type = type
+            self.defined_in = defined_in
+            self.atype = get_type(self.type)
+            self.required = required
+            self.hidden = hidden
+            self.deprecated = deprecated
+            self.default = default
+            self.value = value
+            self.unique = unique
+            self.description = description
+            self.ordinality = ordinality
+            if self.value is not None and self.default is not None:
+                raise ValidationError("Attribute '%s' has default value and fixed value"
%
+                                      self.name)
+            self.create=create
+            self.update=update
+            self.graph=graph
+        except:
+            ex, msg, trace = sys.exc_info()
+            raise ValidationError, "Attribute '%s': %s" % (name, msg), trace
+
+    def missing_value(self, check_required=True, add_default=True, **kwargs):
+        """
+        Fill in missing default and fixed values.
+        @keyword check_required: Raise an exception if required attributes are misssing.
+        @keyword add_default:  Add a default value for missing attributes.
+        @param kwargs: See L{Schema.validate_all}
+        """
+        if self.value is not None: # Fixed value attribute
+            return self.value
+        if add_default and self.default is not None:
+            return self.default
+        if check_required and self.required:
+            raise ValidationError("Missing required attribute '%s'" % (self.name))
+
+    def validate(self, value, check_unique=None, **kwargs):
+        """
+        Validate value for this attribute definition.
+        @param value: The value to validate.
+        @keyword check_unique: set of (name, value) to check for attribute uniqueness.
+            None means don't check for uniqueness.
+        @param create: if true, check that the attribute allows create
+        @param update: if true, check that the attribute allows update
+        @param kwargs: See L{Schema.validate_all}
+        @return: value converted to the correct python type. Rais exception if any check
fails.
+        """
+        if self.unique and not _is_unique(check_unique, (self.name, value)):
+            raise ValidationError("Duplicate value '%s' for unique attribute '%s'"%(value,
self.name))
+        if self.value and value != self.value:
+            raise ValidationError("Attribute '%s' has fixed value '%s' but given '%s'"%(
+                self.name, self.value, value))
+        try:
+            return self.atype.validate(value, **kwargs)
+        except (TypeError, ValueError), e:
+            raise ValidationError, str(e), sys.exc_info()[2]
+
+    def dump(self):
+        """
+        @return: Json-friendly representation of an attribute type
+        """
+        return _dump_dict([
+            ('type', self.atype.dump()),
+            ('default', self.default),
+            ('required', self.required),
+            ('unique', self.unique),
+            ('deprecated', self.deprecated),
+            ('description', self.description),
+            ('graph', self.graph)
+        ])
+
+    def __str__(self):
+        return self.name
+
+
+class MessageDef(object):
+    """A request or response message"""
+    def __init__(self, body=None, properties=None):
+        self.body = None
+        if body: self.body = AttributeType("body", **body)
+        self.properties = dict((name, AttributeType(name, **value))
+                               for name, value in (properties or {}).iteritems())
+
+
+class OperationDef(object):
+    """An operation definition"""
+    def __init__(self, name, description=None, request=None, response=None):
+        try:
+            self.name = name
+            self.description = description
+            self.request = self.response = None
+            if request: self.request = MessageDef(**request)
+            if response: self.response = MessageDef(**response)
+        except:
+            ex, msg, trace = sys.exc_info()
+            raise ValidationError, "Operation '%s': %s" % (name, msg), trace
+
+
+class EntityType(object):
+    """
+    An entity type defines a set of attributes for an entity.
+
+    @ivar name: Fully qualified entity type name.
+    @ivar short_name: Un-prefixed short name.
+    @ivar attributes: Map of L{AttributeType} for entity.
+    @ivar singleton: If true only one entity of this type is allowed.
+    @ivar referential: True if an entity can be referred to by name from another entity.
+    """
+    def __init__(self, name, schema, attributes=None, operations=None, operationDefs=None,
description="",
+                 fullName=True, singleton=False, deprecated=False, extends=None, referential=False,
ordinality=0, **kwargs):
+        """
+        @param name: name of the entity type.
+        @param schema: schema for this type.
+        @param singleton: True if entity type is a singleton.
+        @param attributes: Map of attributes {name: {type:, default:, required:, unique:}}
+        @param description: Human readable description.
+        @param operations: Allowed operations, list of operation names.
+        """
+        try:
+            self.schema = schema
+            self.description = description
+            if fullName:
+                self.name = schema.long_name(name)
+                self.short_name = schema.short_name(name)
+
+                if self.short_name.startswith("router.config."):
+                    self.short_name = self.short_name.replace("router.config.", "")
+            else:
+                self.name = self.short_name = name
+
+            self.attributes = OrderedDict((k, AttributeType(k, defined_in=self, **v))
+                                          for k, v in (attributes or {}).iteritems())
+            self.operations = operations or []
+            # Bases are resolved in self.init()
+            self.base = extends
+            self.all_bases = []
+
+            self.references = []
+            self.singleton = singleton
+            self.deprecated = deprecated
+            self.referential = referential
+            self.ordinality = ordinality
+            self._init = False      # Have not yet initialized from base and attributes.
+            # Operation definitions
+            self.operation_defs = dict((name, OperationDef(name, **op))
+                                  for name, op in (operationDefs or {}).iteritems())
+        except:
+            ex, msg, trace = sys.exc_info()
+            raise ValidationError, "%s '%s': %s" % (type(self).__name__, name, msg), trace
+
+    def init(self):
+        """Find bases after all types are loaded."""
+        if self._init: return
+        self._init = True
+        if self.base:
+            self.base = self.schema.entity_type(self.base)
+            self.base.init()
+            self.all_bases = [self.base] + self.base.all_bases
+            self._extend(self.base, 'extend')
+
+    def _extend(self, other, how):
+        """Add attributes and operations from other"""
+        def check(a, b, what):
+            overlap = set(a) & set(b)
+            if overlap:
+                raise ValidationError("'%s' cannot %s '%s', re-defines %s: %s"
+                                      % (self.name, how, other.short_name, what, ",".join(overlap)))
+        check(self.operations, other.operations, "operations")
+        self.operations += other.operations
+        check(self.attributes.iterkeys(), other.attributes.itervalues(), "attributes")
+        self.attributes.update(other.attributes)
+
+        if other.name == 'entity':
+            # Fill in entity "type" attribute automatically.
+            self.attributes["type"]["value"] = self.name
+
+        ordinality = 0
+        for attrib in self.attributes.values():
+            attrib.ordinality = ordinality
+            ordinality += 1
+
+    def extends(self, base):
+        return base in self.all_bases
+
+    def is_a(self, type):
+        return type == self or self.extends(type)
+
+    def attribute(self, name):
+        """Get the AttributeType for name"""
+        if not name in self.attributes:
+            raise ValidationError("Unknown attribute '%s' for '%s'" % (name, self))
+        return self.attributes[name]
+
+    @property
+    def my_attributes(self):
+        """Return only attribute types defined in this entity type"""
+        return [a for a in self.attributes.itervalues() if a.defined_in == self]
+
+    def validate(self, attributes, check_singleton=None, **kwargs):
+        """
+        Validate attributes for entity type.
+        @param attributes: Map attributes name:value or Entity with attributes property.
+            Modifies attributes: adds defaults, converts values.
+        @param check_singleton: set of entity-type name to enable singleton checking.
+            None to disable.
+        @param kwargs: See L{Schema.validate_all}
+        """
+
+        if isinstance(attributes, SchemaEntity): attributes = attributes.attributes
+
+        if self.singleton and not _is_unique(check_singleton, self.name):
+            raise ValidationError("Multiple instances of singleton '%s'"%self.name)
+        try:
+            # Add missing values
+            for attr in self.attributes.itervalues():
+                if attributes.get(attr.name) is None:
+                    value = attr.missing_value(**kwargs)
+                    if value is not None: attributes[attr.name] = value
+                    if value is None and attr.name in attributes:
+                        del attributes[attr.name]
+
+            # Validate attributes.
+            for name, value in attributes.iteritems():
+                if name == 'type':
+                    value = self.schema.long_name(value)
+                attributes[name] = self.attribute(name).validate(value, **kwargs)
+        except ValidationError, e:
+            raise  ValidationError, "%s: %s"%(self, e), sys.exc_info()[2]
+
+        return attributes
+
+    def allowed(self, op):
+        """Raise exception if op is not a valid operation on entity."""
+        op = op.upper()
+        if not op in self.operations:
+            raise NotImplementedStatus("Operation '%s' not implemented for '%s' %s" % (
+                op, self.name, self.operations))
+
+    def create_check(self, attributes):
+        for a in attributes:
+            if not self.attribute(a).create:
+                raise ValidationError("Cannot set attribute '%s' in CREATE" % a)
+
+    def update_check(self, new_attributes, old_attributes):
+        for a, v in new_attributes.iteritems():
+            # Its not an error to include an attribute in UPDATE if the value is not changed.
+            if not self.attribute(a).update and \
+               not (a in old_attributes and old_attributes[a] == v):
+                raise ValidationError("Cannot update attribute '%s' in UPDATE" % a)
+
+    def dump(self):
+        """Json friendly representation"""
+        return _dump_dict([
+            ('attributes', OrderedDict(
+                (k, v.dump()) for k, v in self.attributes.iteritems()
+                if k != 'type')), # Don't dump 'type' attribute, dumped separately.
+            ('operations', self.operations),
+            ('description', self.description or None),
+            ('fullyQualifiedType', self.name or None),
+            ('references', self.references),
+            ('deprecated', self.deprecated),
+            ('singleton', self.singleton)
+        ])
+
+    def __repr__(self):
+        return "%s(%s)" % (type(self).__name__, self.name)
+
+    def __str__(self):
+        return self.name
+
+    def name_is(self, name):
+        return self.name == self.schema.long_name(name)
+
+
+
+class Schema(object):
+    """
+    Schema defining entity types.
+    Note: keyword arguments come from schema so use camelCase
+
+    @ivar prefix: Prefix to prepend to short entity type names.
+    @ivar entityTypes: Map of L{EntityType} by name.
+    @ivar description: Text description of schema.
+    """
+    def __init__(self, prefix="", entityTypes=None, description=""):
+        """
+        @param prefix: Prefix for entity names.
+        @param entity_types: Map of  { entityTypeName: { singleton:, attributes:{...}}}
+        @param description: Human readable description.
+        """
+        print "In Schema init *******"
+        if prefix:
+            self.prefix = prefix.strip('.')
+            self.prefixdot = self.prefix + '.'
+        else:
+            self.prefix = self.prefixdot = ""
+        self.description = description
+
+        def parsedefs(cls, defs):
+            return OrderedDict((self.long_name(k), cls(k, self, **v))
+                               for k, v in (defs or {}).iteritems())
+
+        self.entity_types = parsedefs(EntityType, entityTypes)
+
+        self.all_attributes = set()
+
+        ordinality = 0
+        for e in self.entity_types.itervalues():
+            e.init()
+            e.ordinality = ordinality
+            self.all_attributes.update(e.attributes.keys())
+            ordinality += 1
+
+    def short_name(self, name):
+        """Remove prefix from name if present"""
+        if not name:
+            return name
+        if name.startswith(self.prefixdot):
+            name = name[len(self.prefixdot):]
+        return name
+
+    def long_name(self, name):
+        """Add prefix to unqualified name"""
+        if not name:
+            return name
+        if not name.startswith(self.prefixdot):
+            name = self.prefixdot + name
+        return name
+
+    def is_long_name(self, name):
+        if not name:
+            return False
+        if self.prefixdot in name:
+            return True
+        return False
+
+    def dump(self):
+        """Return json-friendly representation"""
+        return OrderedDict([
+            ('prefix', self.prefix),
+            ('entityTypes',
+             OrderedDict((e.short_name, e.dump()) for e in self.entity_types.itervalues()))
+        ])
+
+    def _lookup(self, map, name, message, error):
+        found = map.get(name) or map.get(self.long_name(name))
+        if not found and error:
+            raise ValidationError(message % name)
+        return found
+
+    def entity_type(self, name, error=True):
+        return self._lookup(self.entity_types, name, "No such entity type '%s'", error)
+
+    def validate_entity(self, attributes, check_required=True, add_default=True,
+                        check_unique=None, check_singleton=None):
+        """
+        Validate a single entity.
+
+        @param attributes: Map of attribute name: value
+        @keyword check_required: Raise exception if required attributes are missing.
+        @keyword add_default: Add defaults for missing attributes.
+        @keyword check_unique: Used by L{validate_all}
+        @keyword check_singleton: Used by L{validate_all}
+        """
+        attributes['type'] = self.long_name(attributes['type'])
+        entity_type = self.entity_type(attributes['type'])
+        entity_type.validate(
+            attributes,
+            check_required=check_required,
+            add_default=add_default,
+            check_unique=check_unique,
+            check_singleton=check_singleton)
+
+    def validate_all(self, attribute_maps, check_required=True, add_default=True,
+                     check_unique=True, check_singleton=True):
+        """
+        Validate a list of attribute maps representing entity attributes.
+        Verify singleton entities and unique attributes are unique.
+        Modifies attribute_maps, adds default values, converts values.
+
+        @param attribute_maps: List of attribute name:value maps.
+        @keyword check_required: Raise exception if required attributes are missing.
+        @keyword add_default: Add defaults for missing attributes.
+        @keyword check_unique: Raise exception if unique attributes are duplicated.
+        @keyword check_singleton: Raise exception if singleton entities are duplicated
+        """
+        if check_singleton: check_singleton = set()
+        if check_unique: check_unique = set()
+
+        for e in attribute_maps:
+            self.validate_entity(e,
+                                 check_required=check_required,
+                                 add_default=add_default,
+                                 check_unique=check_unique,
+                                 check_singleton=check_singleton)
+
+    def entity(self, attributes):
+        """Convert an attribute map into an L{SchemaEntity}"""
+        attributes = dict((k, v) for k, v in attributes.iteritems() if v is not None)
+        return SchemaEntity(self.entity_type(attributes['type']), attributes)
+
+    def entities(self, attribute_maps):
+        """Convert a list of attribute maps into a list of L{SchemaEntity}"""
+        return [self.entity(m) for m in attribute_maps]
+
+    def filter(self, predicate):
+        """Return an iterator over entity types that satisfy predicate."""
+        if predicate is None: return self.entity_types.itervalues()
+        return (t for t in self.entity_types.itervalues() if predicate(t))
+
+    def by_type(self, type):
+        """Return an iterator over entity types that extend or are type.
+        If type is None return all entities."""
+        if not type:
+            return self.entity_types.itervalues()
+        else:
+            return self.filter(lambda t: t.is_a(type))
+
+
+class QdSchema(Schema):
+    """
+    Qpid Dispatch Router management schema.
+    """
+
+    CONFIGURATION_ENTITY = u"configurationEntity"
+    OPERATIONAL_ENTITY = u"operationalEntity"
+
+    def __init__(self):
+        """Load schema."""
+        qd_schema = get_data('qpid_dispatch.management', 'qdrouter.json')
+        try:
+            print "In QdSchema init *****"
+            super(QdSchema, self).__init__(**json.loads(qd_schema, **JSON_LOAD_KWARGS))
+        except Exception,e:
+            raise ValueError("Invalid schema qdrouter.json: %s" % e)
+        self.configuration_entity = self.entity_type(self.CONFIGURATION_ENTITY)
+        self.operational_entity = self.entity_type(self.OPERATIONAL_ENTITY)
+
+    def validate_full(self, entities, **kwargs):
+        """
+        In addition to L{schema.Schema.validate}, check the following:
+
+        listeners and connectors can only have role=inter-router if the
+        router has mode=interior.
+
+
+        @param entities: List of attribute name:value maps.
+        @param kwargs: See L{schema.Schema.validate}
+        """
+        entities = list(entities) # Need to traverse twice
+        super(QdSchema, self).validate_all(entities, **kwargs)
+        inter_router = not_interior = None
+        for e in entities:
+            if self.short_name(e.type) == "router" and e.mode != "interior":
+                not_interior = e.mode
+            if self.short_name(e.type) in ["listener", "connector"] and e.role == "inter-router":
+                inter_router = e
+            if not_interior and inter_router:
+                raise ValidationError(
+                    "role='inter-router' only allowed with router mode='interior' for %s."
% inter_router)
+
+    def is_configuration(self, entity_type):
+        return entity_type and self.configuration_entity in entity_type.all_bases
+
+    def is_operational(self, entity_type):
+        return entity_type and self.operational_entity in entity_type.all_bases
+
+
+class SchemaEntity(EntityBase):
+    """A map of attributes associated with an L{EntityType}"""
+    def __init__(self, entity_type, attributes=None, validate=True, **kwattrs):
+        super(SchemaEntity, self).__init__(attributes, **kwattrs)
+        self.__dict__['entity_type'] = entity_type
+        self.attributes.setdefault('type', entity_type.name)
+        if validate: self.validate()
+
+    def _set(self, name, value):
+        super(SchemaEntity, self)._set(name, value)
+        self.validate()
+
+    def validate(self, **kwargs):
+        self.entity_type.validate(self.attributes, **kwargs)


---------------------------------------------------------------------
To unsubscribe, e-mail: commits-unsubscribe@qpid.apache.org
For additional commands, e-mail: commits-help@qpid.apache.org


Mime
View raw message