[Zope3-checkins] CVS: Zope3/lib/python/Zope/App/index - subscribers.py:1.2
Guido van Rossum
guido@python.org
Fri, 6 Dec 2002 08:20:16 -0500
Update of /cvs-repository/Zope3/lib/python/Zope/App/index
In directory cvs.zope.org:/tmp/cvs-serv8171
Modified Files:
subscribers.py
Log Message:
Refactored a bit.
Added module comments.
Added registerExisting() method which traverses the content tree from
the folder containing the current service manager and registers
everything it finds (ignoring registration errors).
=== Zope3/lib/python/Zope/App/index/subscribers.py 1.1 => 1.2 ===
--- Zope3/lib/python/Zope/App/index/subscribers.py:1.1 Thu Dec 5 08:47:43 2002
+++ Zope3/lib/python/Zope/App/index/subscribers.py Fri Dec 6 08:20:15 2002
@@ -11,20 +11,36 @@
# FOR A PARTICULAR PURPOSE.
#
##############################################################################
-"""XXX short summary goes here.
+"""A stupid registration thingie.
-XXX longer description goes here.
+In order to do indexing, objects need to be registered with the object
+hub. A real site should define a policy for when objects are to be
+registered. This particular implementation subscribes to
+IObjectAddedEvent events from the event service, and registers
+absolutely everything. It also has a way of registering all
+pre-existing objects.
+
+XXX This is really just an example! There are no unit tests, and it
+hardcodes all the policy decisions. Also, it has some "viewish"
+properties. The traversal code in registerExisting could be useful
+for creating a general "Find" facility like the Zope2 Find tab.
$Id$
"""
__metaclass__ = type
from Interface import Interface
+from Persistence import Persistent
+
from Zope.Event.ISubscriber import ISubscriber
from Zope.Event.IObjectEvent import IObjectAddedEvent
+from Zope.App.OFS.Content.Folder.Folder import IFolder
from Zope.ContextWrapper import ContextMethod
-from Persistence import Persistent
-from Zope.ComponentArchitecture import getService
+from Zope.ComponentArchitecture import getService, queryAdapter
+
+from Zope.App.Traversing import traverse, traverseName, \
+ getPhysicalPath, getPhysicalRoot
+from Zope.App.OFS.Services.ObjectHub.IObjectHub import ObjectHubError
class ISubscriptionControl(Interface):
def subscribe():
@@ -36,13 +52,16 @@
def isSubscribed():
"""Return whether we are currently subscribed."""
+ def registerExisting():
+ """Register all existing objects (for some definition of all)."""
+
class Registration(Persistent):
__implements__ = ISubscriptionControl, ISubscriber
def notify(wrapped_self, event):
"""An event occured. Perhaps register this object with the hub."""
- getService(wrapped_self, "ObjectHub").register(event.object)
+ self._registerObject(event.object)
notify = ContextMethod(notify)
currentlySubscribed = False # Default subscription state
@@ -66,9 +85,69 @@
def isSubscribed(self):
return self.currentlySubscribed
+ def registerExisting(wrapped_self):
+ object = findContentObject(wrapped_self)
+ wrapped_self._registerTree(object)
+ registerExisting = ContextMethod(registerExisting)
+
+ def _registerTree(wrapped_self, object):
+ wrapped_self._registerObject(object)
+ # XXX Policy decision: only traverse into folders
+ if not IFolder.isImplementedBy(object):
+ return
+ # Register subobjects
+ names = object.keys()
+ for name in names:
+ # XXX Once traverseName is refactored, should get an
+ # ITraversable from object and pass it to traverseName
+ sub_object = traverseName(object, name)
+ wrapped_self._registerTree(sub_object)
+ _registerTree = ContextMethod(_registerTree)
+
+ def _registerObject(wrapped_self, object):
+ # XXX Policy decision: register absolutely everything
+ try:
+ getService(wrapped_self, "ObjectHub").register(object)
+ except ObjectHubError:
+ # Probably already registered
+ # XXX It would be more convenient if register() returned
+ # a bool indicating whether the object was already
+ # registered, we wouldn't have to catch this exception.
+ pass
+ _registerObject = ContextMethod(_registerObject)
+
def _getChannel(wrapped_self, channel):
if channel is None:
channel = getService(wrapped_self, "ObjectHub")
return channel
_getChannel = ContextMethod(_getChannel)
+def findContentObject(context):
+ # We want to find the (content) Folder in whose service manager we
+ # live. There are man y way to do this. Perhaps the simplest is
+ # looking for '++etc++...' in the location. We could also walk up
+ # the path looking for something that implements IFolder; the
+ # service manager and packages don't implement this. Or (perhaps
+ # better, because a service manager might be attached to a
+ # non-folder container) assume we're in service space, and walk up
+ # until we find a service manager, and then go up one more step.
+ # Walking up the path could be done by stripping components from
+ # the end of the path one at a time and doing a lookup each time,
+ # or more directly by traversing the context. Traversing the
+ # context can be done by getting the context and following the
+ # chain back; there's a convenience class, ContainmentIterator to
+ # do that. Use the version of ContainmentIterator from
+ # Zope.Proxy, which is aware of the complications caused by
+ # security proxies.
+
+ # For now, we pick the first approach.
+ location = getPhysicalPath(context)
+ # Location is a tuple of strings, starting with '' (for the root)
+ for i in range(len(location)):
+ if location[i].startswith("++etc++"):
+ location = location[:i]
+ break
+ else:
+ raise ValueError, "can't find ++etc++ in path"
+ root = getPhysicalRoot(context)
+ return traverse(root, location)