[Zope3-checkins] CVS: Zope3/src/zope/app/services - surrogate.py:1.2

Jim Fulton cvs-admin at zope.org
Fri Nov 21 12:10:23 EST 2003


Update of /cvs-repository/Zope3/src/zope/app/services
In directory cvs.zope.org:/tmp/cvs-serv29907/src/zope/app/services

Added Files:
	surrogate.py 
Log Message:
Local surrogates maintain adapter registration information for local
adapter and presentation services.  We actually cache information in
such a way that we don't have to access sites above when doing
lookups.


=== Zope3/src/zope/app/services/surrogate.py 1.1 => 1.2 ===
--- /dev/null	Fri Nov 21 12:10:23 2003
+++ Zope3/src/zope/app/services/surrogate.py	Fri Nov 21 12:09:52 2003
@@ -0,0 +1,206 @@
+##############################################################################
+#
+# Copyright (c) 2003 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.
+#
+##############################################################################
+"""Local/persistent surrogate (adapter) registry support
+
+$Id$
+"""
+
+from persistence import Persistent
+from persistence.dict import PersistentDict
+from zope.interface.surrogate import Surrogate, SurrogateRegistry
+from zope.interface.surrogate import adapterImplied, Default
+from zope.app.services.registration import NotifyingRegistrationStack
+import zope.app.component.nextservice
+import zope.app.container.contained
+import zope.app.interfaces.services.service
+import zope.app.interfaces.services.registration
+from zope.app import zapi
+
+class LocalSurrogate(Surrogate):
+    """Local surrogates
+
+    Local surrogates are transient, rather than persistent.
+
+    Their adapter data are stored in their registry objects.
+    """
+
+    def __init__(self, spec, registry):
+        Surrogate.__init__(self, spec, registry)
+        self.registry = registry
+        registry.baseFor(spec).subscribe(self)
+
+    def clean(self):
+        spec = self.spec()
+        base = self.registry.baseFor(spec)
+        ladapters = self.registry.adapters.get(spec)
+        if ladapters:
+            adapters = base.adapters.copy()
+            adapters.update(ladapters)
+        else:
+            adapters = base.adapters
+        self.adapters = adapters
+        Surrogate.clean(self)
+
+class LocalSurrogateRegistry(SurrogateRegistry, Persistent):
+    """Local/persistent surrogate registry
+    """
+
+    zope.interface.implements(
+        zope.app.interfaces.services.registration.IRegistry,
+        )
+    
+    _surrogateClass = LocalSurrogate
+    next = None
+    subs = ()
+
+    def __init__(self, base, next=None):
+        self.base = base
+        self.adapters = {}
+        self.stacks = PersistentDict()
+        SurrogateRegistry.__init__(self)
+        self.setNext(next)
+
+    def setNext(self, next, base=None):
+        if base is not None:
+            self.base = base
+        if self.next is not None:
+            self.next.removeSub(self)
+        if next is not None:
+            next.addSub(self)
+        self.next = next
+        self.adaptersChanged()
+
+    def addSub(self, sub):
+        self.subs += (sub, )
+
+    def removeSub(self, sub):
+        self.subs = tuple([s for s in self.subs if s is not sub])
+
+    def __getstate__(self):
+        state = Persistent.__getstate__(self).copy()
+        del state['_surrogates']
+        del state['_default']
+        del state['_remove']
+        return state
+
+    def __setstate__(self, state):
+        Persistent.__setstate__(self, state)
+        SurrogateRegistry.__init__(self)
+    
+    def baseFor(self, spec):
+        return self.base.get(spec)
+
+    def queryRegistrationsFor(self, registration, default=None):
+        stacks = self.stacks.get(registration.required)
+        if stacks:
+            stack = stacks.get((registration.with, registration.name,
+                                registration.provided))
+            if stack is not None:
+                return stack
+
+        return default
+
+    _stackType = NotifyingRegistrationStack
+
+    def createRegistrationsFor(self, registration):
+        stacks = self.stacks.get(registration.required)
+        if stacks is None:
+            stacks = PersistentDict()
+            self.stacks[registration.required] = stacks
+
+        key = registration.with, registration.name, registration.provided
+        stack = stacks.get(key)
+        if stack is None:
+            stack = self._stackType(self)
+            stacks[key] = stack
+
+        return stack
+
+    def adaptersChanged(self, *args):
+
+        adapters = {}
+        if self.next is not None:
+            for required, radapters in self.next.adapters.iteritems():
+                adapters[required] = radapters.copy()
+        
+        for required, stacks in self.stacks.iteritems():
+            if required is None:
+                required = Default
+            radapters = adapters.get(required)
+            if not radapters:
+                radapters = {}
+                adapters[required] = radapters
+
+            for key, stack in stacks.iteritems():
+                registration = stack.active()
+                if registration is not None:
+                    radapters[key] = registration.factories
+
+
+        if adapters != self.adapters:
+            self.adapters = adapters
+            for surrogate in self._surrogates.values():
+                surrogate.dirty()
+            for sub in self.subs:
+                sub.adaptersChanged()
+
+    notifyActivated = notifyDeactivated = adaptersChanged
+
+class LocalSurrogateBasedService(
+    zope.app.container.contained.Contained,
+    Persistent,
+    ):
+    """A service that uses local surrogate registries
+
+    A local surrogate-based service needs to maintain connections
+    between it's surrogate registries and those of containing ans
+    sub-services.
+
+    The service must implement a setNext method that will be called
+    with the next local service, which may be None, and the global
+    service. This method will be called when a service is bound.
+    
+    """
+
+    zope.interface.implements(
+        zope.app.interfaces.services.service.IBindingAware,
+        )
+
+    def __updateNext(self, servicename):
+        next = zope.app.component.nextservice.getNextService(self, servicename)
+        global_ = zapi.getService(None, servicename)
+        if next == global_:
+            next = None
+        self.setNext(next, global_)
+        
+    def bound(self, servicename):
+        self.__updateNext(servicename)
+        
+        # Now, we need to notify any sub-site services. This is
+        # a bit complicated because our immediate subsites might not have
+        # the same service. Sigh
+        sm = zapi.getServiceManager(self)
+        self.__notifySubs(sm.subSites, servicename)
+
+    def unbound(self, servicename):
+        sm = zapi.getServiceManager(self)
+        self.__notifySubs(sm.subSites, servicename)
+
+    def __notifySubs(self, subs, servicename):
+        for sub in subs:
+            s = sub.queryLocalService(servicename)
+            if s is not None:
+                s.__updateNext(servicename)
+            else:
+                self.__notifySubs(sub.subSites, servicename)




More information about the Zope3-Checkins mailing list