[Zope-Checkins] CVS: Zope3/lib/python/Zope/ObjectHub - IObjectHub.py:1.2 IRuidObjectEvent.py:1.2 ObjectHub.py:1.2 RuidObjectEvent.py:1.2 __init__.py:1.2

Jim Fulton jim@zope.com
Mon, 10 Jun 2002 19:30:00 -0400


Update of /cvs-repository/Zope3/lib/python/Zope/ObjectHub
In directory cvs.zope.org:/tmp/cvs-serv20468/lib/python/Zope/ObjectHub

Added Files:
	IObjectHub.py IRuidObjectEvent.py ObjectHub.py 
	RuidObjectEvent.py __init__.py 
Log Message:
Merged Zope-3x-branch into newly forked Zope3 CVS Tree.

=== Zope3/lib/python/Zope/ObjectHub/IObjectHub.py 1.1 => 1.2 ===
+#
+# Copyright (c) 2001, 2002 Zope Corporation and Contributors.
+# All Rights Reserved.
+# 
+# This software is subject to the provisions of the Zope Public License,
+# Version 2.0 (ZPL).  A copy of the ZPL should accompany this distribution.
+# THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED
+# WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+# WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS
+# FOR A PARTICULAR PURPOSE.
+# 
+##############################################################################
+"""
+
+Revision information:
+$Id$
+"""
+
+from Zope.Event.IEventChannel import IEventChannel
+
+class IObjectHub(IEventChannel):
+    """ObjectHub.
+    
+    Receives Object Modify Events from the Event Service, and
+    changes these into RUID Object Modify Events, then passes
+    these on to its PlugIns (possibly via some other EventChannels).
+       
+    To map Object Modify Events onto RUID Object Modify Events, take
+    the location from the Object Modify Event, look up the RUID for this
+    location, and create an equivalent RUID Object Modify Event using this
+    RUID.
+       
+    Note that we are concerned with locations and not with Objects.
+    An object may have more than one location. That doesn't concern
+    us here.
+       
+    Table of decisions about maintaining the location<->ruid lookup:
+       
+      Register
+      
+         if location already in lookup:
+             raise ObjectHubError, as this is implies bad state somewhere
+         generate new ruid
+         place ruid<->location into lookup, to say that we have an
+             interesting object
+             
+         send out ruid object register event to plug-ins, via event channels
+         
+      Unregister
+         
+         if location not in lookup:
+             raise ObjectHubError, as this is implies bad state somewhere
+         remove location<->ruid from lookup
+            
+         send out ruid unregister event to plug-ins, via event channels
+       
+      Add (specialises Register)
+         
+         as Register, except at the end send out ruid object add event
+         instead
+         
+      Modify
+         
+         if location not in lookup:
+             ignore this event, as we're not interested in this object
+         else:
+             look up ruid for the location
+             send out ruid object modify event to plug-ins,
+                 via event channels
+                
+      Move 
+
+         if old_location not in lookup:
+             ignore this event, as we're not interested in this object
+         elif new_location is in lookup:
+             raise ObjectHubError
+         else:
+             look up ruid for old_location
+             change lookup:
+                 remove ruid<->old_location
+                 add ruid<->new_location
+             send out ruid object context-change event to plug-ins,
+                 via event channels
+         
+      Remove (specialises Unregister)
+
+         if old_location not in lookup:
+             ignore this event, as we're not interested in this object
+         else:
+             look up ruid for old_location
+             change lookup:
+                 remove ruid<->old_location
+             send out ruid object remove event to plug-ins,
+                 via event channels
+    
+     # XXX: Possibly add Link to EventChannel.
+     #      This implies multiple locations for a ruid. 
+     #      We'll refactor later if needed.
+        
+     # Possibly also add registerObject and unregisterObject methods
+     # unless these are better handled by events, or unless we don't
+     # need them.
+     """
+
+        
+    def lookupRuid(location):
+        """Returns the ruid int that is mapped to the given location.
+        
+        Location is either a string, or a sequence of strings.
+        It must be absolute, so if it is a string it must start with a '/',
+        and if it is a sequence, it must start with an empty string.
+        
+        ('','whatever','whatever2')
+        '/whatever/whatever2'
+        
+        If there is no ruid, raise Zope.Exceptions.NotFoundError.
+        
+        """
+        
+    def lookupLocation(ruid):
+        """Returns a location as a string.
+        
+        If there is no location, raise Zope.Exceptions.NotFoundError.
+        
+        """
+        
+    def getObject(ruid):
+        """Returns an object for the given ruid.
+        
+        If there is no such ruid, raise Zope.Exceptions.NotFoundError.
+        If there is no such object, passes through whatever error
+        the traversal service raises.
+        """


=== Zope3/lib/python/Zope/ObjectHub/IRuidObjectEvent.py 1.1 => 1.2 ===
+#
+# Copyright (c) 2001, 2002 Zope Corporation and Contributors.
+# All Rights Reserved.
+# 
+# This software is subject to the provisions of the Zope Public License,
+# Version 2.0 (ZPL).  A copy of the ZPL should accompany this distribution.
+# THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED
+# WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+# WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS
+# FOR A PARTICULAR PURPOSE.
+# 
+##############################################################################
+"""
+
+Revision information:
+$Id$
+"""
+from Zope.Event.IEvent import IEvent
+
+class IRuidObjectEvent(IEvent):
+    """Something has happened to an object for which there is an ruid.
+       An ruid is a way or refering to an object independent of location.
+    """
+
+    def getRuid():
+        """Returns the object's ruid."""
+        
+    def getLocation():
+        """Returns the object's current location."""
+        
+    def getObject():
+        """Returns the object."""
+        
+
+
+class IRuidObjectRegisteredEvent(IRuidObjectEvent):
+    """An ruid has been freshly created and mapped against an object."""
+
+
+class IRuidObjectUnregisteredEvent(IRuidObjectEvent):
+    """We are no longer interested in this object."""
+
+
+class IRuidObjectAddedEvent(IRuidObjectRegisteredEvent):
+    """An ruid has been freshly created and mapped against an object.
+       Also, implies the object has been newly added."""
+    
+    
+class IRuidObjectModifiedEvent(IRuidObjectEvent):
+    """An object with an ruid has been modified."""
+    
+    
+class IRuidObjectContextChangedEvent(IRuidObjectEvent):
+    """An object with an ruid has had its context changed. Typically, this
+       means that it has been moved."""
+
+       
+class IRuidObjectRemovedEvent(IRuidObjectUnregisteredEvent):
+    """An object with an ruid has been removed."""
+
+    def getLocation():
+        """Returns the object's location before it was removed."""
+
+    def getObject():
+        """Returns the object, or None if the object is unavailable."""


=== Zope3/lib/python/Zope/ObjectHub/ObjectHub.py 1.1 => 1.2 ===
+#
+# Copyright (c) 2001, 2002 Zope Corporation and Contributors.
+# All Rights Reserved.
+# 
+# This software is subject to the provisions of the Zope Public License,
+# Version 2.0 (ZPL).  A copy of the ZPL should accompany this distribution.
+# THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED
+# WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+# WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS
+# FOR A PARTICULAR PURPOSE.
+# 
+##############################################################################
+"""
+
+Revision information:
+$Id$
+"""
+
+from IObjectHub import IObjectHub
+from Zope.Event.IObjectEvent import IObjectAddedEvent, IObjectModifiedEvent
+from Zope.Event.IObjectEvent import IObjectRemovedEvent, IObjectMovedEvent
+from Zope.Event.IEvent import IEvent
+from Zope.Event.EventChannel import EventChannel
+from RuidObjectEvent import RuidObjectRegisteredEvent
+from RuidObjectEvent import RuidObjectUnregisteredEvent
+from RuidObjectEvent import RuidObjectAddedEvent
+from RuidObjectEvent import RuidObjectModifiedEvent
+from RuidObjectEvent import RuidObjectContextChangedEvent
+from RuidObjectEvent import RuidObjectRemovedEvent
+
+from Zope.Exceptions import NotFoundError
+from Persistence import Persistent
+from Interface.Implements import objectImplements
+from types import StringTypes
+from Persistence.BTrees.IOBTree import IOBTree
+from Persistence.BTrees.OIBTree import OIBTree
+
+from Zope.App.Traversing.ITraverser import ITraverser
+from Zope.ComponentArchitecture import getAdapter
+
+import random
+def randid():
+    # Return a random number between -2*10**9 and 2*10**9, but not 0.
+    abs = random.randrange(1, 2000000001)
+    if random.random() < 0.5:
+        return -abs
+    else:
+        return abs
+
+class ObjectHubError(Exception):
+    pass
+
+class ObjectHub(Persistent):
+
+    __implements__ =  IObjectHub
+
+    def __init__(self):
+        self.__ruid_to_location = IOBTree()
+        self.__location_to_ruid = OIBTree()
+        self.__eventchannel = EventChannel()
+        
+    _clear = __init__
+
+
+    ############################################################
+    # Implementation methods for interface
+    # Zope.ObjectHub.IObjectHub
+
+    def subscribe(self, subscriber, event_type=IEvent, filter=None):
+        '''See interface ISubscribable'''
+        self.__eventchannel.subscribe(subscriber, event_type, filter)
+
+    def unsubscribe(self, subscriber, event_type=None, filter=None):
+        '''See interface ISubscribable'''
+        self.__eventchannel.unsubscribe(subscriber, event_type, filter)
+    
+    def listSubscriptions(self, subscriber, event_type=None):
+        "See interface ISubscribable"
+        return self.__eventchannel.listSubscriptions(subscriber, event_type)
+
+    def notify(self, event):
+        '''See interface ISubscriber'''
+        if IObjectAddedEvent.isImplementedBy(event):
+            self._objectAdded(event.getLocation())
+            
+        elif IObjectModifiedEvent.isImplementedBy(event):
+            self._objectModified(event.getLocation())
+            
+        elif IObjectMovedEvent.isImplementedBy(event):
+            self._objectMoved(event.getFromLocation(),
+                              event.getLocation())
+                              
+        elif IObjectRemovedEvent.isImplementedBy(event):
+            self._objectRemoved(event.getLocation(), event.getObject())
+            
+        # otherwise, ignore the event
+
+    def lookupRuid(self, location):
+        '''See interface IObjectHub'''
+        try:
+            return self.__location_to_ruid[self._canonical(location)]
+        except KeyError:
+            raise NotFoundError, self._canonical(location)
+    
+    def lookupLocation(self, ruid):
+        '''See interface IObjectHub'''
+        try:
+            return self.__ruid_to_location[ruid]
+        except KeyError:
+            raise NotFoundError, ruid
+        
+    def getObject(self, ruid):
+        '''See interface IObjectHub'''
+        location = self.lookupLocation(ruid)
+        adapter = getAdapter(object, ITraverser)
+        return adapter.traverse(location)
+        
+    #
+    ############################################################
+
+    def _generateRuid(self, location):
+        index=getattr(self, '_v_nextid', 0)
+        if index%4000 == 0: index = randid()
+        ruid_to_location=self.__ruid_to_location
+        while not ruid_to_location.insert(index, location):
+            index=randid()
+        self._v_nextid=index+1
+        return index
+
+    def _canonical(location):
+        if not isinstance(location, StringTypes):
+            location='/'.join(location)
+        # URIs are ascii, right?
+        return str(location)
+        
+    _canonical=staticmethod(_canonical)
+
+    def _objectAdded(self, location):
+        canonical_location = self._canonical(location)
+        
+        location_to_ruid = self.__location_to_ruid
+                
+        if location_to_ruid.has_key(canonical_location):
+            raise ObjectHubError, 'location %s already in object hub' % \
+                canonical_location
+        ruid = self._generateRuid(canonical_location)
+        location_to_ruid[canonical_location] = ruid
+        
+        # send out to plugins IRuidObjectAddedEvent
+        event = RuidObjectAddedEvent(
+            self, 
+            ruid,
+            canonical_location)
+        self.__eventchannel.notify(event)
+        
+    
+    def _objectModified(self, location):
+        location_to_ruid = self.__location_to_ruid
+        canonical_location = self._canonical(location)
+        if not location_to_ruid.has_key(canonical_location):
+            # we're not interested in this event
+            return
+            
+        # send out to plugins IRuidObjectModifiedEvent
+        event = RuidObjectModifiedEvent(
+            self, 
+            location_to_ruid[canonical_location],
+            canonical_location)
+        self.__eventchannel.notify(event)
+        
+    
+    def _objectMoved(self, old_location, new_location):
+        location_to_ruid = self.__location_to_ruid
+        canonical_location = self._canonical(old_location)
+        canonical_new_location = self._canonical(new_location)
+        if location_to_ruid.has_key(canonical_new_location):
+            raise ObjectHubError(
+                'Cannot move to location %s, '
+                'as there is already something there'
+                % canonical_new_location)
+        if not location_to_ruid.has_key(canonical_location):
+            # we're not interested in this event
+            return
+
+        ruid = location_to_ruid[canonical_location]
+        del location_to_ruid[canonical_location]
+        location_to_ruid[canonical_new_location] = ruid
+        self.__ruid_to_location[ruid] = canonical_new_location
+        
+        # send out to plugins IRuidObjectContextChangedEvent
+        event = RuidObjectContextChangedEvent(
+            self, 
+            ruid,
+            canonical_new_location)
+        self.__eventchannel.notify(event)
+
+            
+    def _objectRemoved(self, location, obj):
+        location_to_ruid = self.__location_to_ruid
+        ruid_to_location = self.__ruid_to_location
+        canonical_location = self._canonical(location)
+        try:
+            ruid = location_to_ruid[canonical_location]
+        except KeyError:
+            # we don't know about this location, so we
+            # can ignore this event
+            return
+            
+        del ruid_to_location[ruid]
+        del location_to_ruid[canonical_location]
+            
+        # send out to plugins IRuidObjectRemovedEvent
+        event = RuidObjectRemovedEvent(
+            obj,
+            ruid,
+            canonical_location)
+        self.__eventchannel.notify(event)


=== Zope3/lib/python/Zope/ObjectHub/RuidObjectEvent.py 1.1 => 1.2 ===
+#
+# Copyright (c) 2001, 2002 Zope Corporation and Contributors.
+# All Rights Reserved.
+# 
+# This software is subject to the provisions of the Zope Public License,
+# Version 2.0 (ZPL).  A copy of the ZPL should accompany this distribution.
+# THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED
+# WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+# WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS
+# FOR A PARTICULAR PURPOSE.
+# 
+##############################################################################
+"""
+
+Revision information:
+$Id$
+"""
+
+from IRuidObjectEvent import IRuidObjectRegisteredEvent
+from IRuidObjectEvent import IRuidObjectAddedEvent
+from IRuidObjectEvent import IRuidObjectUnregisteredEvent
+from IRuidObjectEvent import IRuidObjectModifiedEvent
+from IRuidObjectEvent import IRuidObjectContextChangedEvent
+from IRuidObjectEvent import IRuidObjectRemovedEvent
+
+class RuidObjectEvent:
+    """Convenient mix-in for RuidObjectEvents"""
+    
+    def __init__(self, objecthub, ruid, location):
+        # we keep all three, to avoid unnecessary lookups
+        # and to give the objecthub an opportunity to do
+        # caching of objects
+        self.__objecthub = objecthub
+        self.__ruid = ruid
+        self.__location = location
+        
+    def getRuid(self):
+        return self.__ruid
+        
+    def getLocation(self):
+        return self.__location
+        
+    def getObject(self):
+        if hasattr(self, '_v_object'):
+            return self._v_object
+        obj = self._v_object = self.__objecthub.getObject(self.__ruid)
+        return obj
+
+
+class RuidObjectRegisteredEvent(RuidObjectEvent):
+    """An ruid has been freshly created and mapped against an object."""
+
+    __implements__ = IRuidObjectRegisteredEvent
+
+
+class RuidObjectUnregisteredEvent(RuidObjectEvent):
+    """We are no longer interested in this object."""
+
+    __implements__ = IRuidObjectUnregisteredEvent
+
+
+class RuidObjectAddedEvent(RuidObjectEvent):
+    """An ruid has been freshly created and mapped against an object.
+       Also, implies the object has been newly added."""
+    
+    __implements__ = IRuidObjectAddedEvent
+    
+    
+class RuidObjectModifiedEvent(RuidObjectEvent):
+    """An object with an ruid has been modified."""
+    
+    __implements__ = IRuidObjectModifiedEvent
+    
+    
+class RuidObjectContextChangedEvent(RuidObjectEvent):
+    """An object with an ruid has had its context changed. Typically, this
+       means that it has been moved."""
+       
+    __implements__ = IRuidObjectContextChangedEvent
+
+
+class RuidObjectRemovedEvent(RuidObjectEvent):
+    """An object with an ruid has been removed."""
+
+    __implements__ = IRuidObjectRemovedEvent
+
+    def __init__(self, obj, ruid, location):
+        self.__object = obj
+        self.__ruid = ruid
+        self.__location = location
+
+    def getRuid(self):
+        return self.__ruid
+        
+    def getLocation(self):
+        return self.__location
+
+    def getObject(self):
+        return self.__object


=== Zope3/lib/python/Zope/ObjectHub/__init__.py 1.1 => 1.2 ===
+#
+# Copyright (c) 2001, 2002 Zope Corporation and Contributors.
+# All Rights Reserved.
+# 
+# This software is subject to the provisions of the Zope Public License,
+# Version 2.0 (ZPL).  A copy of the ZPL should accompany this distribution.
+# THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED
+# WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+# WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS
+# FOR A PARTICULAR PURPOSE.
+# 
+##############################################################################
+"""
+
+Revision information:
+$Id$
+"""
+