[Zope3-checkins] SVN: Zope3/trunk/src/zope/app/ Made getServices() to use the site stored as a thread global for local

Albertas Agejevas alga at pov.lt
Fri May 21 21:56:54 EDT 2004


Log message for revision 24871:

Made getServices() to use the site stored as a thread global for local
services lookup.  ZopePublication sends events before traversing each
object, and the site thread global is set by a subscriber to that
event if the object being traversed is an ISite.




-=-
Modified: Zope3/trunk/src/zope/app/component/configure.zcml
===================================================================
--- Zope3/trunk/src/zope/app/component/configure.zcml	2004-05-22 01:56:42 UTC (rev 24870)
+++ Zope3/trunk/src/zope/app/component/configure.zcml	2004-05-22 01:56:54 UTC (rev 24871)
@@ -1,51 +1,67 @@
 <configure
    xmlns="http://namespaces.zope.org/zope"
-   >
+   xmlns:event="http://namespaces.zope.org/event"
+  >
 
-  <serviceType 
+  <serviceType
       id="Utilities"
       interface="zope.component.interfaces.IUtilityService" />
-  
-  <service 
+
+  <service
       serviceType="Utilities"
       permission="zope.Public"
       factory="zope.component.utility.GlobalUtilityService" />
-  
-  <serviceType 
+
+  <serviceType
       id="Adapters"
       interface="zope.component.interfaces.IAdapterService" />
-  
-  <service 
+
+  <service
       serviceType="Adapters"
       permission="zope.Public"
       factory="zope.component.adapter.GlobalAdapterService" />
-  
-  <serviceType 
+
+  <serviceType
       id="Presentation"
       interface="zope.component.interfaces.IPresentationService" />
-  
-  <service 
+
+  <service
       serviceType="Presentation"
       permission="zope.Public"
       factory="zope.component.presentation.GlobalPresentationService" />
-  
+
   <vocabulary
       name="Interfaces"
       factory="zope.app.utility.vocabulary.UtilityVocabulary"
       interface="zope.interface.interfaces.IInterface" />
-  
-  <hook 
+
+  <hook
       module="zope.component"
-      name="getServiceManager"
-      implementation="zope.app.component.hooks.getServiceManager_hook" />
-           
-  <hook 
+      name="getServices"
+      implementation="zope.app.component.hooks.getServices_hook" />
+
+  <hook
       module="zope.component"
       name="queryView"
       implementation="zope.app.component.hooks.queryView" />
-  
+
   <interface interface="zope.interface.Interface" />
 
+  <adapter
+      factory=".localservice.serviceServiceAdapter"
+      provides="zope.component.IServiceService"
+      for="zope.interface.Interface" />
+
+  <event:subscribe
+      subscriber=".localservice.threadSiteSubscriber"
+      event_types="zope.app.publication.interfaces.IBeforeTraverseEvent"
+      />
+
+  <event:subscribe
+      subscriber=".localservice.clearThreadSiteSubscriber"
+      event_types="zope.app.publication.interfaces.IEndRequestEvent"
+      />
+
 </configure>
 
 

Modified: Zope3/trunk/src/zope/app/component/hooks.py
===================================================================
--- Zope3/trunk/src/zope/app/component/hooks.py	2004-05-22 01:56:42 UTC (rev 24870)
+++ Zope3/trunk/src/zope/app/component/hooks.py	2004-05-22 01:56:54 UTC (rev 24871)
@@ -16,10 +16,12 @@
 $Id$
 """
 
-from zope.component import getService
+import warnings
+from zope.component import getService, getAdapter, queryAdapter
 from zope.component.interfaces import IServiceService
 from zope.app.site.interfaces import ISite
 from zope.component.service import serviceManager
+from zope.component.exceptions import ComponentLookupError
 from zope.proxy import removeAllProxies
 from zope.security.proxy import trustedRemoveSecurityProxy
 from zope.app.traversing import IContainmentRoot
@@ -27,44 +29,34 @@
 from zope.app.location import locate
 from zope.component.servicenames import Presentation
 from zope.interface import Interface
+from zope.thread import thread_globals
 
-def getServiceManager_hook(context, local=False, recurse=False):
+def getServices_hook(context=None):
 
     if context is None:
-        return serviceManager
-
-    clean_context = removeAllProxies(context)
-
-    # if the context is actually a service or site manager...
-    if IServiceService.providedBy(clean_context):
-        return trustedRemoveSecurityProxy(context)
-
-    elif (ISite.providedBy(clean_context)):
-        return trustedRemoveSecurityProxy(context.getSiteManager())
-    else:
-        container = getattr(context, '__parent__', None)
-        if container is None:
-            if local:
-                # Check to make sure that when we run out of context, we
-                # have a root object:
-                if not IContainmentRoot.providedBy(context):
-                    raise TypeError("Not enough context to get next "
-                                    "site manager")
-
-            # Fall back to global:
-            sm = serviceManager
+        site = thread_globals().site
+        if site is None:
+            return serviceManager
         else:
-            # We have a container, so context is a wrapper.  We still
-            # don't have a site manager, so try again, recursively:
-            sm = getServiceManager_hook(container, local, True)
+            return trustedRemoveSecurityProxy(site.getSiteManager())
 
-    return sm
+    try:
+        # This try-except is just backward compatibility really
+        return trustedRemoveSecurityProxy(getAdapter(context, IServiceService))
+    except ComponentLookupError:
+        # Deprecated support for a context that isn't adaptable to
+        # IServiceService.  Return the default service manager.
+        ## warnings.warn("getServices' context arg must be None or"
+        ##               "  adaptable to IServiceService.",
+        ##               DeprecationWarning, warningLevel())
+        return serviceManager
 
 
-def queryView(object, name, request, default=None, context=None,
-              providing=Interface):
-    if context is None:
-        context = object
+def queryView(object, name, request, default=None,
+              providing=Interface, context=None):
+    # XXX test
+    #if context is None:
+    #    context = object
     views = getService(context, Presentation)
     view = views.queryView(object, name, request, default=default,
                            providing=providing)

Modified: Zope3/trunk/src/zope/app/publication/interfaces.py
===================================================================
--- Zope3/trunk/src/zope/app/publication/interfaces.py	2004-05-22 01:56:42 UTC (rev 24870)
+++ Zope3/trunk/src/zope/app/publication/interfaces.py	2004-05-22 01:56:54 UTC (rev 24871)
@@ -16,7 +16,8 @@
 $Id$
 """
 
-from zope.interface import Interface
+from zope.interface import implements, Interface
+from zope.app.event.interfaces import IEvent
 
 
 class IPublicationRequestFactoryFactory(Interface):
@@ -44,3 +45,27 @@
     """This is a pure read-only interface, since the values are set through
        a ZCML directive and we shouldn't be able to change them.
     """
+
+
+class IBeforeTraverseEvent(IEvent):
+    """An event which gets sent on publication traverse"""
+
+
+class BeforeTraverseEvent:
+    """An event which gets sent on publication traverse"""
+    implements(IBeforeTraverseEvent)
+    def __init__(self, ob, request):
+        self.object = ob
+        self.request = request
+
+
+class IEndRequestEvent(IEvent):
+    """An event which gets sent when the publication is ended"""
+
+
+class EndRequestEvent:
+    """An event which gets sent when the publication is ended"""
+    implements(IEndRequestEvent)
+    def __init__(self, ob, request):
+        self.object = ob
+        self.request = request

Modified: Zope3/trunk/src/zope/app/publication/tests/test_zopepublication.py
===================================================================
--- Zope3/trunk/src/zope/app/publication/tests/test_zopepublication.py	2004-05-22 01:56:42 UTC (rev 24870)
+++ Zope3/trunk/src/zope/app/publication/tests/test_zopepublication.py	2004-05-22 01:56:54 UTC (rev 24871)
@@ -26,7 +26,7 @@
 from zope.interface.verify import verifyClass
 from zope.interface import implements, classImplements, implementedBy
 from zope.i18n.interfaces import IUserPreferredCharsets
-from zope.component import getServiceManager
+from zope.component import getGlobalServices
 from zope.component.interfaces import IServiceService
 from zope.publisher.base import TestPublication, TestRequest
 from zope.publisher.http import IHTTPRequest, HTTPCharsets
@@ -37,11 +37,13 @@
 
 from zope.app import zapi
 from zope.app.tests.placelesssetup import PlacelessSetup
+from zope.app.tests import setup
 from zope.app.tests import ztapi
 
 from zope.app.errorservice.interfaces import IErrorReportingService
 from zope.app.servicenames import ErrorLogging, Authentication
 from zope.app.location.interfaces import ILocation
+from zope.app.traversing.interfaces import IPhysicallyLocatable
 from zope.app.security.principalregistry import principalRegistry
 from zope.app.security.interfaces import IUnauthenticatedPrincipal, IPrincipal
 from zope.app.publication.zopepublication import ZopePublication
@@ -154,6 +156,7 @@
         for interface in implementedBy(ZopePublication):
             verifyClass(interface, TestPublication)
 
+
 class ZopePublicationErrorHandling(BasePublicationTests):
 
     def testRetryAllowed(self):
@@ -317,7 +320,7 @@
 
     def testAbortTransactionWithErrorLoggingService(self):
         # provide our fake error logging service
-        sm = getServiceManager(None)
+        sm = getGlobalServices()
         sm.defineService(ErrorLogging, IErrorReportingService)
         sm.provideService(ErrorLogging, ErrorLoggingService())
 
@@ -327,7 +330,7 @@
         last_txn_info = self.db.undoInfo()[0]
         try:
             raise FooError
-        except:
+        except FooError:
             pass
         self.publication.handleException(
             self.object, self.request, sys.exc_info(), retry_allowed=False)
@@ -434,8 +437,45 @@
         self.publication.afterCall(self.request, bar.foo)
         self.assertEqual(txn_info['location'], expected_path)
 
-        
+    def testSiteEvents(self):
+        from zope.app.publication.interfaces import IBeforeTraverseEvent
+        from zope.app.publication.interfaces import IEndRequestEvent
+        from zope.app.event.interfaces import ISubscriber
+        from zope.app.servicenames import EventPublication
+        from zope.app.event.localservice import EventService
 
+        class Subscriber:
+            implements(ISubscriber)
+            def __init__(self):
+                self.events = []
+            def notify(self, event):
+                self.events.append(event)
+
+        events = zapi.getService(EventPublication)
+        set = Subscriber()
+        clear = Subscriber()
+        events.globalSubscribe(set, IBeforeTraverseEvent)
+        events.globalSubscribe(clear, IEndRequestEvent)
+
+        ob = object()
+
+        # This should fire the BeforeTraverseEvent
+        self.publication.callTraversalHooks(self.request, ob)
+
+        self.assertEqual(len(set.events), 1)
+        self.assertEqual(len(clear.events), 0)
+        self.assertEqual(set.events[0].object, ob)
+
+        ob2 = object()
+
+        # This should fire the EndRequestEvent
+        self.publication.endRequest(self.request, ob2)
+
+        self.assertEqual(len(set.events), 1)
+        self.assertEqual(len(clear.events), 1)
+        self.assertEqual(clear.events[0].object, ob2)
+
+
 def test_suite():
     return unittest.TestSuite((
         unittest.makeSuite(ZopePublicationTests),

Modified: Zope3/trunk/src/zope/app/publication/zopepublication.py
===================================================================
--- Zope3/trunk/src/zope/app/publication/zopepublication.py	2004-05-22 01:56:42 UTC (rev 24870)
+++ Zope3/trunk/src/zope/app/publication/zopepublication.py	2004-05-22 01:56:54 UTC (rev 24871)
@@ -22,7 +22,9 @@
 from ZODB.POSException import ConflictError
 
 from zope.interface import implements, providedBy
-from zope.component import queryService
+from zope.component import getService
+from zope.app.servicenames import ErrorLogging
+from zope.component.exceptions import ComponentLookupError
 from zope.publisher.publish import mapply
 from zope.publisher.interfaces import Retry, IExceptionSideEffects
 from zope.publisher.interfaces import IRequest, IPublication
@@ -44,6 +46,9 @@
 from zope.app.publication.publicationtraverse import PublicationTraverse
 from zope.app.traversing.interfaces import IPhysicallyLocatable
 from zope.app.location import LocationProxy
+from zope.app.event import publish
+from zope.app.publication.interfaces import BeforeTraverseEvent
+from zope.app.publication.interfaces import EndRequestEvent
 
 class Cleanup(object):
 
@@ -87,7 +92,7 @@
             return
 
         sm = removeAllProxies(ob).getSiteManager()
-        
+
         auth_service = sm.queryService(Authentication)
         if auth_service is None:
             # No auth service here
@@ -105,7 +110,7 @@
 
     def callTraversalHooks(self, request, ob):
         # Call __before_publishing_traverse__ hooks
-
+        publish(None, BeforeTraverseEvent(ob, request))
         # This is also a handy place to try and authenticate.
         self._maybePlacefullyAuthenticate(request, ob)
 
@@ -154,8 +159,8 @@
         txn.commit()
 
     def endRequest(self, request, ob):
-        # Make sure the interaction is ended
         endInteraction()
+        publish(None, EndRequestEvent(ob, request))
 
     def annotateTransaction(self, txn, request, ob):
         """Set some useful meta-information on the transaction. This
@@ -201,9 +206,13 @@
         self.beginErrorHandlingTransaction(request, object,
                                            'error reporting service')
         try:
-            errService = queryService(object, ErrorLogging)
-            if errService is not None:
+            try:
+                errService = getService(ErrorLogging)
                 errService.raising(exc_info, request)
+            except ComponentLookupError:
+                # There is no local error reporting service.
+                # XXX We need to build a local error reporting service.
+                pass
             # It is important that an error in errService.raising
             # does not propagate outside of here. Otherwise, nothing
             # meaningful will be returned to the user.
@@ -224,7 +233,6 @@
                 ErrorLogging)
             get_transaction().abort()
 
-
     def handleException(self, object, request, exc_info, retry_allowed=True):
         # This transaction had an exception that reached the publisher.
         # It must definitely be aborted.
@@ -233,7 +241,7 @@
         # Convert ConflictErrors to Retry exceptions.
         if retry_allowed and isinstance(exc_info[1], ConflictError):
             tryToLogWarning('ZopePublication',
-                'Competing writes/reads at %s' % 
+                'Competing writes/reads at %s' %
                 request.get('PATH_INFO', '???'),
                 exc_info=True)
             raise Retry
@@ -280,11 +288,11 @@
                     if loc is loc:
                         loc = getattr(loc, '__self__', loc)
                     loc = ProxyFactory(loc)
-                
+
                 exception = LocationProxy(exc_info[1], loc)
-                name = zapi.queryDefaultViewName(exception, request, context=object)
+                name = zapi.queryDefaultViewName(exception, request)
                 if name is not None:
-                    view = zapi.queryView(exception, name, request, context=object)
+                    view = zapi.queryView(exception, name, request)
             except:
                 # Problem getting a view for this exception. Log an error.
                 tryToLogException(




More information about the Zope3-Checkins mailing list