Example #1
0
    def findClusters(self, toSend):
        """
        Return a list of tuples of (alias, deleteFlag) pairs,
        clustering recordsets that need to be serialized together
        (recurrence modifications and masters).  The first pair will
        be the master.

        For instance: [((master1, False), (mod1, False)), ((master2, False),)]

        """
        mastersChanged = set()
        mastersDeleted = set()

        view = self.itsView
        translator = self.translator(self.itsView)

        for alias, rs in toSend.iteritems():
            masterAlias, recurrenceID = splitUUID(view, alias)
            s = mastersChanged if (rs is not None
                                   or recurrenceID) else mastersDeleted
            s.add(masterAlias)

        mastersChanged = mastersChanged - mastersDeleted

        clusters = [((alias, True), ) for alias in mastersDeleted]
        for masterAlias in mastersChanged:
            cluster = [(masterAlias, False)]
            clusters.append(cluster)

            master = view.findUUID(masterAlias)
            for mod in getattr(EventStamp(master), 'modifications', []):
                cluster.append((translator.getAliasForItem(mod), False))
        return clusters
Example #2
0
    def findClusters(self, toSend):
        """
        Return a list of tuples of (alias, deleteFlag) pairs,
        clustering recordsets that need to be serialized together
        (recurrence modifications and masters).  The first pair will
        be the master.

        For instance: [((master1, False), (mod1, False)), ((master2, False),)]

        """
        mastersChanged = set()
        mastersDeleted = set()

        view = self.itsView
        translator = self.translator(self.itsView)

        for alias, rs in toSend.iteritems():
            masterAlias, recurrenceID = splitUUID(view, alias)
            s = mastersChanged if (rs is not None or recurrenceID) else mastersDeleted
            s.add(masterAlias)

        mastersChanged = mastersChanged - mastersDeleted

        clusters = [((alias, True),) for alias in mastersDeleted]
        for masterAlias in mastersChanged:
            cluster = [(masterAlias, False)]
            clusters.append(cluster)

            master = view.findUUID(masterAlias)
            for mod in getattr(EventStamp(master), 'modifications', []):
                cluster.append((translator.getAliasForItem(mod), False))
        return clusters
Example #3
0
def inbound(peer, text, filter=None, allowDeletion=False, debug=False):

    logger.info("itemcentric.inbound(%s)", str(peer))
    if isinstance(peer, list):
        # Peer email address items can have several that match.  We pass in
        # a list so this code can reuse the one (if any) already associated
        # to the inbound item.
        peers = peer
    else:
        peers = [peer]

    rv = peers[0].itsView

    # At some point, which serializer and translator to use should be
    # configurable
    serializer = eimml.EIMMLSerializer # only using class methods
    trans = translator.SharingTranslator(rv)

    inbound, extra = serializer.deserialize(rv, text, helperView=rv)

    peerRepoId = extra.get('repo', None)
    peerItemVersion = int(extra.get('version', '-1'))

    itemToReturn = None

    aliases = inbound.keys()
    aliases.sort()
    for alias in aliases:
        rsExternal = inbound[alias]

        uuid = trans.getUUIDForAlias(alias)
        if uuid:
            item = rv.findUUID(uuid)
        else:
            item = None

        if rsExternal is not None:

            if item is not None and not getattr(item, '_fake', False):

                # Item already exists
                if not pim.has_stamp(item, shares.SharedItem):
                    shares.SharedItem(item).add()
                shared = shares.SharedItem(item)

                if not getattr(shared, 'peerStates', False):
                    # has no peer states yet, use the first peer in list
                    peer = peers[0]
                else:
                    for state in shared.peerStates:
                        peerUUID = shared.peerStates.getAlias(state)
                        for peer in peers:
                            if peer.itsUUID.str16() == peerUUID:
                                # peer matches
                                break
                        else:
                            # no match; use the first one passed in
                            peer = peers[0]

                state = shared.getPeerState(peer)
                rsInternal= eim.RecordSet(trans.exportItem(item))

            else: # Item doesn't exist yet
                peer = peers[0]
                state = shares.State(itsView=rv, peer=peer)
                rsInternal = eim.RecordSet()


            if state.peerRepoId and (peerRepoId != state.peerRepoId):
                # This update is not from the peer repository we last saw.
                # Treat the update is entirely new
                state.clear()

            if uuid is not None:
                masterAlias, recurrenceID = utility.splitUUID(rv, alias)
                if masterAlias != alias and not state.agreed:
                    # This is a new inbound modification
                    state.agreed += eim.RecordSet(
                        recordset_conduit.getInheritRecords(
                        rsExternal.inclusions, alias))

            state.peerRepoId = peerRepoId

            # Only process recordsets whose version is greater than the last one
            # we say.  In the case of null-repository-view testing, versions are
            # always stuck at zero, so process those as well.

            if ((peerItemVersion == 0) or
                (peerItemVersion > state.peerItemVersion)):

                state.peerItemVersion = peerItemVersion

                dSend, dApply, pending = state.merge(rsInternal, rsExternal,
                    isDiff=False, filter=filter, debug=debug)

                state.autoResolve(rsInternal, dApply, dSend)
                state.updateConflicts(item)

                if dApply:
                    logger.debug("Applying: %s %s", uuid, dApply)
                    trans.startImport()
                    trans.importRecords(dApply)
                    trans.finishImport()

                uuid = trans.getUUIDForAlias(alias)
                if uuid:
                    item = rv.findUUID(uuid)
                else:
                    item = None

                if item is not None and item.isLive():
                    if not pim.has_stamp(item, shares.SharedItem):
                        shares.SharedItem(item).add()

                    shares.SharedItem(item).addPeerState(state, peer)

                    if itemToReturn is None:
                        # the item to return should always be a master, not
                        # a modification
                        itemToReturn = getattr(item, 'inheritFrom', item)

            else:
                logger.info("Out-of-sequence update for %s", uuid)
                raise errors.OutOfSequence("Update %d arrived after %d" %
                    (peerItemVersion, state.peerItemVersion))

        else: # Deletion

            if item is not None:

                # Remove the state
                if pim.has_stamp(item, shares.SharedItem):
                    shared = shares.SharedItem(item)
                    shared.removePeerState(peer)

                # Remove the item (if allowed)
                if allowDeletion:
                    logger.debug("Deleting item: %s", uuid)
                    item.delete(True)
                    item = None

    return itemToReturn
Example #4
0
def inbound(peer, text, filter=None, allowDeletion=False, debug=False):

    logger.info("itemcentric.inbound(%s)", str(peer))
    if isinstance(peer, list):
        # Peer email address items can have several that match.  We pass in
        # a list so this code can reuse the one (if any) already associated
        # to the inbound item.
        peers = peer
    else:
        peers = [peer]

    rv = peers[0].itsView

    # At some point, which serializer and translator to use should be
    # configurable
    serializer = eimml.EIMMLSerializer  # only using class methods
    trans = translator.SharingTranslator(rv)

    inbound, extra = serializer.deserialize(rv, text, helperView=rv)

    peerRepoId = extra.get('repo', None)
    peerItemVersion = int(extra.get('version', '-1'))

    itemToReturn = None

    aliases = inbound.keys()
    aliases.sort()
    for alias in aliases:
        rsExternal = inbound[alias]

        uuid = trans.getUUIDForAlias(alias)
        if uuid:
            item = rv.findUUID(uuid)
        else:
            item = None

        if rsExternal is not None:

            if item is not None and not getattr(item, '_fake', False):

                # Item already exists
                if not pim.has_stamp(item, shares.SharedItem):
                    shares.SharedItem(item).add()
                shared = shares.SharedItem(item)

                if not getattr(shared, 'peerStates', False):
                    # has no peer states yet, use the first peer in list
                    peer = peers[0]
                else:
                    for state in shared.peerStates:
                        peerUUID = shared.peerStates.getAlias(state)
                        for peer in peers:
                            if peer.itsUUID.str16() == peerUUID:
                                # peer matches
                                break
                        else:
                            # no match; use the first one passed in
                            peer = peers[0]

                state = shared.getPeerState(peer)
                rsInternal = eim.RecordSet(trans.exportItem(item))

            else:  # Item doesn't exist yet
                peer = peers[0]
                state = shares.State(itsView=rv, peer=peer)
                rsInternal = eim.RecordSet()

            if state.peerRepoId and (peerRepoId != state.peerRepoId):
                # This update is not from the peer repository we last saw.
                # Treat the update is entirely new
                state.clear()

            if uuid is not None:
                masterAlias, recurrenceID = utility.splitUUID(rv, alias)
                if masterAlias != alias and not state.agreed:
                    # This is a new inbound modification
                    state.agreed += eim.RecordSet(
                        recordset_conduit.getInheritRecords(
                            rsExternal.inclusions, alias))

            state.peerRepoId = peerRepoId

            # Only process recordsets whose version is greater than the last one
            # we say.  In the case of null-repository-view testing, versions are
            # always stuck at zero, so process those as well.

            if ((peerItemVersion == 0)
                    or (peerItemVersion > state.peerItemVersion)):

                state.peerItemVersion = peerItemVersion

                dSend, dApply, pending = state.merge(rsInternal,
                                                     rsExternal,
                                                     isDiff=False,
                                                     filter=filter,
                                                     debug=debug)

                state.autoResolve(rsInternal, dApply, dSend)
                state.updateConflicts(item)

                if dApply:
                    logger.debug("Applying: %s %s", uuid, dApply)
                    trans.startImport()
                    trans.importRecords(dApply)
                    trans.finishImport()

                uuid = trans.getUUIDForAlias(alias)
                if uuid:
                    item = rv.findUUID(uuid)
                else:
                    item = None

                if item is not None and item.isLive():
                    if not pim.has_stamp(item, shares.SharedItem):
                        shares.SharedItem(item).add()

                    shares.SharedItem(item).addPeerState(state, peer)

                    if itemToReturn is None:
                        # the item to return should always be a master, not
                        # a modification
                        itemToReturn = getattr(item, 'inheritFrom', item)

            else:
                logger.info("Out-of-sequence update for %s", uuid)
                raise errors.OutOfSequence(
                    "Update %d arrived after %d" %
                    (peerItemVersion, state.peerItemVersion))

        else:  # Deletion

            if item is not None:

                # Remove the state
                if pim.has_stamp(item, shares.SharedItem):
                    shared = shares.SharedItem(item)
                    shared.removePeerState(peer)

                # Remove the item (if allowed)
                if allowDeletion:
                    logger.debug("Deleting item: %s", uuid)
                    item.delete(True)
                    item = None

    return itemToReturn