예제 #1
0
class ItemHandler(ValueHandler):
    """
    A SAX ContentHandler implementation responsible for loading items.
    """
    
    def __init__(self, repository, parent, afterLoadHooks, new):

        super(ItemHandler, self).__init__(repository)

        self.loading = repository.isLoading()
        self.parent = parent
        self.afterLoadHooks = afterLoadHooks
        self.item = None
        self.new = new
        self.values = None
        self.references = None
        
    def refStart(self, itemHandler, attrs):

        if self.tags[-1] == 'item':
            name = attrs['name']
            attribute = self.getAttribute(name)
            self.attributes.append(attribute)

            flags = attrs.get('flags', None)
            if flags is not None:
                flags = int(flags)
                self.references._setFlags(name, flags)
                readOnly = flags & Values.READONLY
            else:
                readOnly = False

            cardinality = self.getCardinality(attribute, attrs)
            if cardinality != 'single':
                if cardinality == 'dict':
                    self.repository.logger.warning("Warning, 'dict' cardinality for reference attribute %s on %s is deprecated, use 'list' instead", name, self.name or self.uuid)
                self._setupRefList(name, attribute, readOnly, attrs)

    def _setupRefList(self, name, attribute, readOnly, attrs):

        refList = None
        otherName = self.getOtherName(name, attribute, attrs)

        if 'uuid' in attrs:
            uuid = UUID(attrs['uuid'])
        else:
            uuid = None

        if self.update and attrs.get('operation') == 'append':
            refList = self.item._references.get(name)

        if refList is None:
            refList = self.repository._createRefList(None, name, otherName,
                                                     True, readOnly, self.new,
                                                     uuid)
                
        self.collections.append(refList)

    def itemStart(self, itemHandler, attrs):

        super(ItemHandler, self).itemStart(itemHandler, attrs)

        if self.values is None:
            self.values = Values(None)
        if self.references is None:
            self.references = References(None)

        self.refs = []
        self.name = None
        self.cls = None
        self.parentRef = None
        self.isContainer = False
        self.uuid = UUID(attrs.get('uuid'))
        self.version = int(attrs.get('version', '0'))
        self.update = update = attrs.get('update')
        self.delete = delete = attrs.get('delete')

        def _find(spec):

            typeAttr = attrs.get('type', 'path')
            if typeAttr == 'path':
                item = self.parent.find(Path(spec))
            elif typeAttr == 'uuid':
                item = self.parent.find(UUID(spec))
            else:
                raise TypeError, typeAttr

            if item is None:
                raise NoSuchItemError, (spec, self.version)

            return item

        if update is not None:
            item = _find(update)
        elif delete is not None:
            item = _find(delete)
        else:
            item = None

        if item is not None:
            self.item = item
            self.cls = type(item)
            self.version = item._version
            self.name = item.itsName
            self.kind = item.itsKind
            self.uuid = item.itsUUID
            self.parent = item.itsParent

    def itemEnd(self, itemHandler, attrs):

        from repository.item.Item import Item
        
        if self.withSchema:
            status = Item.CORESCHEMA
        else:
            status = 0

        cls = self.cls
        if cls is None:
            if self.kind is None:
                cls = Item
            else:
                cls = self.kind.getItemClass()

        instance = self.repository._reuseItemInstance(self.uuid)
        if instance is not None:
            if cls is not type(instance):
                raise TypeError, 'Class for item has changed from %s to %s' %(type(instance), cls)
            item = self.item = instance
            status |= item._status & item.PINNED
            instance = None

        elif self.update or self.delete:
            item = self.item
            values = item._values
            references = item._references

            for name, value in self.values.iteritems():
                values[name] = value
                item.setDirty(Item.VDIRTY, name, values, noMonitors=True)
            self.values = values

            for name, value in self.references.iteritems():
                if not isinstance(value, dict):
                    dirty = Item.VDIRTY
                    item.setAttributeValue(name, value, references,
                                           None, False)
                else:
                    dirty = Item.RDIRTY
                    references[name] = value
                item.setDirty(dirty, name, references, noMonitors=True)
            self.references = references

            status = item._status | Item.NDIRTY

        else:
            item = self.item = cls.__new__(cls)

        item._fillItem(self.name, self.parent, self.kind, uuid = self.uuid,
                       values = self.values, references = self.references,
                       afterLoadHooks = self.afterLoadHooks,
                       version = self.version, status = status,
                       update = self.update)

        if self.isContainer and item._children is None:
            item._children = self.repository._createChildren(item, self.new)

        if not (self.update or self.delete):
            self.repository._registerItem(item)
            self.values._setItem(item)
            self.references._setItem(item)

        for attribute, value in self.values.iteritems():
            if isinstance(value, ItemValue):
                value._setOwner(item, attribute)

        for refArgs in self.refs:
            other = refArgs._setItem(item)
            if self.loading:
                refArgs._setRef()
            elif other is None:
                self.afterLoadHooks.append(refArgs._setValue)
            else:
                refArgs._setValue(self.repository)

        self.afterLoadHooks.append(self.setupClass)
        if hasattr(cls, 'onItemLoad'):
            self.afterLoadHooks.append(item.onItemLoad)
        if self.delete:
            self.afterLoadHooks.append(item.delete)

    def setupClass(self, view):

        if self.update and isinstance(self.item, Kind):
            self.item.flushCaches('attributes', True)
        elif self.kind is not None:
            self.kind._setupClass(type(self.item))

    def kindEnd(self, itemHandler, attrs):

        assert not self.item

        super(ItemHandler, self).kindEnd(itemHandler, attrs)
        if self.kind is None:
            if self.withSchema:
                self.afterLoadHooks.append(self._setKind)
            else:
                raise ValueError, "While loading %s, kind %s not found" %(self.name or self.uuid, self.kindRef)

    def _setKind(self, view):

        if self.item._kind is None:
            self.kind = view.find(self.kindRef)
            if self.kind is None:
                raise ValueError, 'Kind %s not found' %(self.kindRef)
            else:
                self.item._kind = self.kind

    def parentEnd(self, itemHandler, attrs):

        if attrs['type'] == 'uuid':
            self.parentRef = UUID(self.data)
        else:
            self.parentRef = Path(self.data)

        self.isContainer = attrs.get('container', 'False') == 'True'
        self.parent = self.repository.find(self.parentRef)

        if self.parent is None:
            self.afterLoadHooks.append(self._move)

    def _move(self, view):

        if self.item._parent is None:
            self.parent = view.find(self.parentRef)
            if self.parent is None:
                raise ValueError, 'Parent %s not found' %(self.parentRef)
            else:
                self.item.move(self.parent)

    def classEnd(self, itemHandler, attrs):

        self.cls = ClassLoader.loadClass(self.data, attrs['module'])

    def nameEnd(self, itemHandler, attrs):

        self.name = self.data

    def refEnd(self, itemHandler, attrs):

        if self.tags[-1] == 'item':
            attribute = self.attributes.pop()
            cardinality = self.getCardinality(attribute, attrs)
            otherCard = attrs.get('otherCard', None)
            
        else:
            cardinality = 'single'
            otherCard = self.tagAttrs[-1].get('otherCard', None)

        if cardinality == 'single':     # cardinality of tag
            typeName = attrs.get('type', 'path')

            if typeName == 'path':
                ref = Path(self.data)
            elif typeName == 'none':
                self.references[attrs['name']] = None
                return
            else:
                ref = UUID(self.data)

            if self.collections:
                refList = self.collections[-1]
                self.refs.append(RefArgs(refList._name, None,
                                         refList._otherName, ref,
                                         otherCard=otherCard,
                                         otherAlias=attrs.get('otherAlias'),
                                         previous=self.refName(attrs, 'previous'),
                                         next=self.refName(attrs, 'next'),
                                         alias=attrs.get('alias')))
            else:
                name = attrs['name']
                otherName = self.getOtherName(name, self.getAttribute(name),
                                              attrs)
                self.refs.append(RefArgs(name, None, otherName, ref,
                                         otherCard=otherCard,
                                         otherAlias=attrs.get('otherAlias')))
        else:
            value = self.collections.pop()
            self.references[attrs['name']] = value
            if value._indexes:
                self.afterLoadHooks.append(value._restoreIndexes)

    def indexEnd(self, itemHandler, attrs):

        if not self.collections:
            raise ValueError, self.tagAttrs[-1]['name']

        refList = self.collections[-1]
        kwds = attrs.copy()
        del kwds['type']
        del kwds['name']
        refList.addIndex(attrs['name'], attrs['type'], **kwds)

    def refName(self, attrs, attr):

        try:
            return self.makeValue(attrs.get(attr + 'Type', 'str'), attrs[attr])
        except KeyError:
            return None

    def getOtherName(self, name, attribute, attrs):

        otherName = attrs.get('otherName')

        if otherName is None and attribute is not None:
            otherName = self.kind.getOtherName(name, None, None, None)

        if otherName is None:
            raise TypeError, 'Undefined other endpoint for %s.%s of kind %s' %(self.name or self.uuid, name, self.kind.itsPath)

        return otherName
예제 #2
0
class ItemHandler(ValueHandler):
    """
    A SAX ContentHandler implementation responsible for loading items.
    """
    def __init__(self, repository, parent, afterLoadHooks, new):

        super(ItemHandler, self).__init__(repository)

        self.loading = repository.isLoading()
        self.parent = parent
        self.afterLoadHooks = afterLoadHooks
        self.item = None
        self.new = new
        self.values = None
        self.references = None

    def refStart(self, itemHandler, attrs):

        if self.tags[-1] == 'item':
            name = attrs['name']
            attribute = self.getAttribute(name)
            self.attributes.append(attribute)

            flags = attrs.get('flags', None)
            if flags is not None:
                flags = int(flags)
                self.references._setFlags(name, flags)
                readOnly = flags & Values.READONLY
            else:
                readOnly = False

            cardinality = self.getCardinality(attribute, attrs)
            if cardinality != 'single':
                if cardinality == 'dict':
                    self.repository.logger.warning(
                        "Warning, 'dict' cardinality for reference attribute %s on %s is deprecated, use 'list' instead",
                        name, self.name or self.uuid)
                self._setupRefList(name, attribute, readOnly, attrs)

    def _setupRefList(self, name, attribute, readOnly, attrs):

        refList = None
        otherName = self.getOtherName(name, attribute, attrs)

        if 'uuid' in attrs:
            uuid = UUID(attrs['uuid'])
        else:
            uuid = None

        if self.update and attrs.get('operation') == 'append':
            refList = self.item._references.get(name)

        if refList is None:
            refList = self.repository._createRefList(None, name, otherName,
                                                     True, readOnly, self.new,
                                                     uuid)

        self.collections.append(refList)

    def itemStart(self, itemHandler, attrs):

        super(ItemHandler, self).itemStart(itemHandler, attrs)

        if self.values is None:
            self.values = Values(None)
        if self.references is None:
            self.references = References(None)

        self.refs = []
        self.name = None
        self.cls = None
        self.parentRef = None
        self.isContainer = False
        self.uuid = UUID(attrs.get('uuid'))
        self.version = int(attrs.get('version', '0'))
        self.update = update = attrs.get('update')
        self.delete = delete = attrs.get('delete')

        def _find(spec):

            typeAttr = attrs.get('type', 'path')
            if typeAttr == 'path':
                item = self.parent.find(Path(spec))
            elif typeAttr == 'uuid':
                item = self.parent.find(UUID(spec))
            else:
                raise TypeError, typeAttr

            if item is None:
                raise NoSuchItemError, (spec, self.version)

            return item

        if update is not None:
            item = _find(update)
        elif delete is not None:
            item = _find(delete)
        else:
            item = None

        if item is not None:
            self.item = item
            self.cls = type(item)
            self.version = item._version
            self.name = item.itsName
            self.kind = item.itsKind
            self.uuid = item.itsUUID
            self.parent = item.itsParent

    def itemEnd(self, itemHandler, attrs):

        from repository.item.Item import Item

        if self.withSchema:
            status = Item.CORESCHEMA
        else:
            status = 0

        cls = self.cls
        if cls is None:
            if self.kind is None:
                cls = Item
            else:
                cls = self.kind.getItemClass()

        instance = self.repository._reuseItemInstance(self.uuid)
        if instance is not None:
            if cls is not type(instance):
                raise TypeError, 'Class for item has changed from %s to %s' % (
                    type(instance), cls)
            item = self.item = instance
            status |= item._status & item.PINNED
            instance = None

        elif self.update or self.delete:
            item = self.item
            values = item._values
            references = item._references

            for name, value in self.values.iteritems():
                values[name] = value
                item.setDirty(Item.VDIRTY, name, values, noMonitors=True)
            self.values = values

            for name, value in self.references.iteritems():
                if not isinstance(value, dict):
                    dirty = Item.VDIRTY
                    item.setAttributeValue(name, value, references, None,
                                           False)
                else:
                    dirty = Item.RDIRTY
                    references[name] = value
                item.setDirty(dirty, name, references, noMonitors=True)
            self.references = references

            status = item._status | Item.NDIRTY

        else:
            item = self.item = cls.__new__(cls)

        item._fillItem(self.name,
                       self.parent,
                       self.kind,
                       uuid=self.uuid,
                       values=self.values,
                       references=self.references,
                       afterLoadHooks=self.afterLoadHooks,
                       version=self.version,
                       status=status,
                       update=self.update)

        if self.isContainer and item._children is None:
            item._children = self.repository._createChildren(item, self.new)

        if not (self.update or self.delete):
            self.repository._registerItem(item)
            self.values._setItem(item)
            self.references._setItem(item)

        for attribute, value in self.values.iteritems():
            if isinstance(value, ItemValue):
                value._setOwner(item, attribute)

        for refArgs in self.refs:
            other = refArgs._setItem(item)
            if self.loading:
                refArgs._setRef()
            elif other is None:
                self.afterLoadHooks.append(refArgs._setValue)
            else:
                refArgs._setValue(self.repository)

        self.afterLoadHooks.append(self.setupClass)
        if hasattr(cls, 'onItemLoad'):
            self.afterLoadHooks.append(item.onItemLoad)
        if self.delete:
            self.afterLoadHooks.append(item.delete)

    def setupClass(self, view):

        if self.update and isinstance(self.item, Kind):
            self.item.flushCaches('attributes', True)
        elif self.kind is not None:
            self.kind._setupClass(type(self.item))

    def kindEnd(self, itemHandler, attrs):

        assert not self.item

        super(ItemHandler, self).kindEnd(itemHandler, attrs)
        if self.kind is None:
            if self.withSchema:
                self.afterLoadHooks.append(self._setKind)
            else:
                raise ValueError, "While loading %s, kind %s not found" % (
                    self.name or self.uuid, self.kindRef)

    def _setKind(self, view):

        if self.item._kind is None:
            self.kind = view.find(self.kindRef)
            if self.kind is None:
                raise ValueError, 'Kind %s not found' % (self.kindRef)
            else:
                self.item._kind = self.kind

    def parentEnd(self, itemHandler, attrs):

        if attrs['type'] == 'uuid':
            self.parentRef = UUID(self.data)
        else:
            self.parentRef = Path(self.data)

        self.isContainer = attrs.get('container', 'False') == 'True'
        self.parent = self.repository.find(self.parentRef)

        if self.parent is None:
            self.afterLoadHooks.append(self._move)

    def _move(self, view):

        if self.item._parent is None:
            self.parent = view.find(self.parentRef)
            if self.parent is None:
                raise ValueError, 'Parent %s not found' % (self.parentRef)
            else:
                self.item.move(self.parent)

    def classEnd(self, itemHandler, attrs):

        self.cls = ClassLoader.loadClass(self.data, attrs['module'])

    def nameEnd(self, itemHandler, attrs):

        self.name = self.data

    def refEnd(self, itemHandler, attrs):

        if self.tags[-1] == 'item':
            attribute = self.attributes.pop()
            cardinality = self.getCardinality(attribute, attrs)
            otherCard = attrs.get('otherCard', None)

        else:
            cardinality = 'single'
            otherCard = self.tagAttrs[-1].get('otherCard', None)

        if cardinality == 'single':  # cardinality of tag
            typeName = attrs.get('type', 'path')

            if typeName == 'path':
                ref = Path(self.data)
            elif typeName == 'none':
                self.references[attrs['name']] = None
                return
            else:
                ref = UUID(self.data)

            if self.collections:
                refList = self.collections[-1]
                self.refs.append(
                    RefArgs(refList._name,
                            None,
                            refList._otherName,
                            ref,
                            otherCard=otherCard,
                            otherAlias=attrs.get('otherAlias'),
                            previous=self.refName(attrs, 'previous'),
                            next=self.refName(attrs, 'next'),
                            alias=attrs.get('alias')))
            else:
                name = attrs['name']
                otherName = self.getOtherName(name, self.getAttribute(name),
                                              attrs)
                self.refs.append(
                    RefArgs(name,
                            None,
                            otherName,
                            ref,
                            otherCard=otherCard,
                            otherAlias=attrs.get('otherAlias')))
        else:
            value = self.collections.pop()
            self.references[attrs['name']] = value
            if value._indexes:
                self.afterLoadHooks.append(value._restoreIndexes)

    def indexEnd(self, itemHandler, attrs):

        if not self.collections:
            raise ValueError, self.tagAttrs[-1]['name']

        refList = self.collections[-1]
        kwds = attrs.copy()
        del kwds['type']
        del kwds['name']
        refList.addIndex(attrs['name'], attrs['type'], **kwds)

    def refName(self, attrs, attr):

        try:
            return self.makeValue(attrs.get(attr + 'Type', 'str'), attrs[attr])
        except KeyError:
            return None

    def getOtherName(self, name, attribute, attrs):

        otherName = attrs.get('otherName')

        if otherName is None and attribute is not None:
            otherName = self.kind.getOtherName(name, None, None, None)

        if otherName is None:
            raise TypeError, 'Undefined other endpoint for %s.%s of kind %s' % (
                self.name or self.uuid, name, self.kind.itsPath)

        return otherName