[Zope3-checkins] SVN: Zope3/branches/srichter-blow-services/src/zope/app/ Okay, now we truly have a mess.

Stephan Richter srichter at cosmos.phy.tufts.edu
Wed Dec 22 12:17:54 EST 2004


Log message for revision 28687:
  Okay, now we truly have a mess.
  

Changed:
  U   Zope3/branches/srichter-blow-services/src/zope/app/component/__init__.py
  A   Zope3/branches/srichter-blow-services/src/zope/app/component/adapter.py
  A   Zope3/branches/srichter-blow-services/src/zope/app/component/bbb/meta.zcml
  A   Zope3/branches/srichter-blow-services/src/zope/app/component/bbb/metaconfigure.py
  A   Zope3/branches/srichter-blow-services/src/zope/app/component/bbb/metadirectives.py
  A   Zope3/branches/srichter-blow-services/src/zope/app/component/bbb/registration/
  A   Zope3/branches/srichter-blow-services/src/zope/app/component/bbb/servicenames.py
  A   Zope3/branches/srichter-blow-services/src/zope/app/component/interfaces.py
  U   Zope3/branches/srichter-blow-services/src/zope/app/component/meta.zcml
  U   Zope3/branches/srichter-blow-services/src/zope/app/component/metaconfigure.py
  U   Zope3/branches/srichter-blow-services/src/zope/app/component/metadirectives.py
  A   Zope3/branches/srichter-blow-services/src/zope/app/component/site.py
  A   Zope3/branches/srichter-blow-services/src/zope/app/component/testing.py
  A   Zope3/branches/srichter-blow-services/src/zope/app/component/vocabulary.py
  D   Zope3/branches/srichter-blow-services/src/zope/app/registration/

-=-
Modified: Zope3/branches/srichter-blow-services/src/zope/app/component/__init__.py
===================================================================
--- Zope3/branches/srichter-blow-services/src/zope/app/component/__init__.py	2004-12-22 17:05:09 UTC (rev 28686)
+++ Zope3/branches/srichter-blow-services/src/zope/app/component/__init__.py	2004-12-22 17:17:53 UTC (rev 28687)
@@ -1,2 +1,83 @@
+##############################################################################
 #
-# This file is necessary to make this directory a package.
+# Copyright (c) 2004 Zope Corporation and Contributors.
+# All Rights Reserved.
+#
+# This software is subject to the provisions of the Zope Public License,
+# Version 2.1 (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 Component Architecture
+
+$Id$
+"""
+__docformat__ = "reStructuredText"
+
+
+_marker = object()
+
+def getNextUtility(context, interface, name=''):
+    """Get the next available utility.
+
+    If no utility was found, a `ComponentLookupError` is raised.
+    """
+    util = queryNextUtility(context, interface, name, _marker)
+    if util is _marker:
+        raise ComponentLookupError, \
+              "No more utilities for %s, '%s' have been found." %(interface,
+                                                                  name)
+    return util
+
+
+def queryNextUtility(context, interface, name='', default=None):
+    """Query for the next available utility.
+
+    Find the next available utility providing `interface` and having the
+    specified name. If no utility was found, return the specified `default`
+    value.
+
+    It is very important that this method really finds the next utility and
+    does not abort, if the utility was not found in the next utility service.
+
+    Let's start out by declaring a utility interface and an implementation:
+
+      >>> from zope.interface import Interface, implements
+      >>> class IAnyUtility(Interface):
+      ...     pass
+      
+      >>> class AnyUtility(object):
+      ...     implements(IAnyUtility)
+      ...     def __init__(self, id):
+      ...         self.id = id
+      
+      >>> any1 = AnyUtility(1)
+      >>> any1next = AnyUtility(2)
+
+    Now that we have the utilities, let's register them:
+
+      >>> testingNextUtility(any1, any1next, IAnyUtility)
+
+    The next utility of `any1` ahould be `any1next`:
+
+      >>> queryNextUtility(any1, IAnyUtility) is any1next
+      True
+
+    But `any1next` does not have a next utility, so the default is returned:
+
+      >>> queryNextUtility(any1next, IAnyUtility) is None
+      True
+
+    """    
+    util = _marker
+    while util is _marker:
+        utilservice = queryNextService(context, zapi.servicenames.Utilities)
+        if utilservice is None:
+            return default
+        util = utilservice.queryUtility(interface, name, _marker)
+        context = utilservice
+        
+    return util

Copied: Zope3/branches/srichter-blow-services/src/zope/app/component/adapter.py (from rev 28678, Zope3/branches/srichter-blow-services/src/zope/app/component/bbb/adapter/adapter.py)
===================================================================
--- Zope3/branches/srichter-blow-services/src/zope/app/component/bbb/adapter/adapter.py	2004-12-21 23:28:27 UTC (rev 28678)
+++ Zope3/branches/srichter-blow-services/src/zope/app/component/adapter.py	2004-12-22 17:17:53 UTC (rev 28687)
@@ -0,0 +1,257 @@
+##############################################################################
+#
+# Copyright (c) 2002 Zope Corporation and Contributors.
+# All Rights Reserved.
+#
+# This software is subject to the provisions of the Zope Public License,
+# Version 2.1 (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.
+#
+##############################################################################
+"""Adapter Service
+
+$Id$
+"""
+__docformat__ = 'restructuredtext' 
+
+from persistent.dict import PersistentDict
+from persistent import Persistent
+from zope.app import zapi
+from zope.app.registration.registration import NotifyingRegistrationStack
+from zope.interface.adapter import adapterImplied, Default
+from zope.interface.adapter import Surrogate, AdapterRegistry
+from zope.security.proxy import removeSecurityProxy
+import sys
+import zope.app.component.localservice
+import zope.app.container.contained
+import zope.app.registration.interfaces
+import zope.app.site.interfaces
+import zope.app.registration
+import zope.component.interfaces
+import zope.component.adapter
+import zope.interface
+import zope.schema
+from zope.app.i18n import ZopeMessageIDFactory as _
+
+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 LocalAdapterRegistry(AdapterRegistry, Persistent):
+    """Local/persistent surrogate registry
+    """
+
+    zope.interface.implements(
+        zope.app.registration.interfaces.IRegistry,
+        )
+    
+    _surrogateClass = LocalSurrogate
+
+    # Next local registry, may be None
+    next = None
+
+    subs = ()
+
+    def __init__(self, base, next=None):
+
+        # Base registry. This is always a global registry
+        self.base = base
+
+        self.adapters = {}
+        self.stacks = PersistentDict()
+        AdapterRegistry.__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()
+        
+        for name in ('_default', '_null', 'adapter_hook',
+                     'lookup', 'lookup1', 'queryAdapter', 'get',
+                     'subscriptions', 'queryMultiAdapter', 'subscribers'
+                     ):
+            del state[name]
+        return state
+
+    def __setstate__(self, state):
+        Persistent.__setstate__(self, state)
+        AdapterRegistry.__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((False, 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 = (False, registration.with, registration.name,
+               registration.provided)
+        stack = stacks.get(key)
+        if stack is None:
+            stack = self._stackType(self)
+            stacks[key] = stack
+
+        return stack
+
+
+    def _updateAdaptersFromLocalData(self, adapters):
+        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:
+
+                    # Needs more thought:
+                    # We have to remove the proxy because we're
+                    # storing the value amd we can't store proxies.
+                    # (Why can't we?)  we need to think more about
+                    # why/if this is truly safe
+                    
+                    radapters[key] = removeSecurityProxy(registration.factory)
+
+    def adaptersChanged(self, *args):
+
+        adapters = {}
+        if self.next is not None:
+            for required, radapters in self.next.adapters.iteritems():
+                adapters[required] = radapters.copy()
+        
+        self._updateAdaptersFromLocalData(adapters)
+
+        if adapters != self.adapters:
+            self.adapters = adapters
+
+            # Throw away all of our surrogates, rather than dirtrying
+            # them individually
+            AdapterRegistry.__init__(self)
+
+            for sub in self.subs:
+                sub.adaptersChanged()
+
+    notifyActivated = notifyDeactivated = adaptersChanged
+
+    def baseChanged(self):
+        """Someone changed the base service
+
+        This should only happen during testing
+        """
+        AdapterRegistry.__init__(self)
+        for sub in self.subs:
+            sub.baseChanged()
+                
+
+    def registrations(self):
+        for stacks in self.stacks.itervalues():
+            for stack in stacks.itervalues():
+                for info in stack.info():
+                    yield info['registration']
+
+
+class LocalAdapterBasedService(
+    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.site.interfaces.IBindingAware,
+        )
+
+    def __updateNext(self, servicename):
+        next = zope.app.component.localservice.getNextService(
+            self, servicename)
+        global_ = zapi.getGlobalServices().getService(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.getServices(self)
+        self.__notifySubs(sm.subSites, servicename)
+
+    def unbound(self, servicename):
+        sm = zapi.getServices(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)
+

Copied: Zope3/branches/srichter-blow-services/src/zope/app/component/bbb/meta.zcml (from rev 28677, Zope3/branches/srichter-blow-services/src/zope/app/component/meta.zcml)
===================================================================
--- Zope3/branches/srichter-blow-services/src/zope/app/component/meta.zcml	2004-12-21 23:18:34 UTC (rev 28677)
+++ Zope3/branches/srichter-blow-services/src/zope/app/component/bbb/meta.zcml	2004-12-22 17:17:53 UTC (rev 28687)
@@ -0,0 +1,160 @@
+<configure
+    xmlns="http://namespaces.zope.org/zope"
+    xmlns:meta="http://namespaces.zope.org/meta">
+
+  <meta:directives namespace="http://namespaces.zope.org/zope">
+
+    <meta:directive
+        name="interface"
+        schema=".metadirectives.IInterfaceDirective"
+        handler="zope.app.component.metaconfigure.interface"
+        />
+
+    <meta:directive
+        name="adapter"
+        schema=".metadirectives.IAdapterDirective"
+        handler="zope.app.component.metaconfigure.adapter"
+        />
+
+    <meta:directive
+        name="subscriber"
+        schema=".metadirectives.ISubscriberDirective"
+        handler="zope.app.component.metaconfigure.subscriber"
+        />
+
+
+    <meta:directive
+        name="utility"
+        schema=".metadirectives.IUtilityDirective"
+        handler="zope.app.component.metaconfigure.utility"
+        />
+
+    <meta:directive
+        name="factory"
+        schema=".metadirectives.IFactoryDirective"
+        handler="zope.app.component.metaconfigure.factory"
+        />
+
+    <meta:directive
+        name="view"
+        schema=".metadirectives.IViewDirective"
+        handler="zope.app.component.metaconfigure.view"
+        />
+
+    <meta:directive
+        name="defaultView"
+        schema=".metadirectives.IDefaultViewDirective"
+        handler="zope.app.component.metaconfigure.defaultView"
+        />
+
+    <meta:directive
+        name="resource"
+        schema=".metadirectives.IResourceDirective"
+        handler="zope.app.component.metaconfigure.resource"
+        />
+
+    <meta:directive
+        name="serviceType"
+        schema=".metadirectives.IServiceTypeDirective"
+        handler="zope.app.component.metaconfigure.serviceType"
+        />
+
+    <meta:directive
+        name="defaultLayer"
+        schema=".metadirectives.IDefaultLayerDirective"
+        handler="zope.app.component.metaconfigure.defaultLayer"
+        />
+
+    <meta:directive
+        name="service" 
+        schema=".metadirectives.IServiceDirective"
+        handler="zope.app.component.metaconfigure.service"
+        />
+
+    <meta:complexDirective
+        name="class"
+        schema=".metadirectives.IClassDirective"
+        handler="zope.app.component.contentdirective.ContentDirective"
+        >
+
+      <meta:subdirective
+          name="implements"
+          schema=".metadirectives.IImplementsSubdirective"
+          />
+
+      <meta:subdirective
+          name="require"
+          schema=".metadirectives.IRequireSubdirective"
+          />
+
+      <meta:subdirective
+          name="allow"
+          schema=".metadirectives.IAllowSubdirective"
+          />
+
+      <meta:subdirective
+          name="factory"
+          schema=".metadirectives.IFactorySubdirective"
+          />
+
+    </meta:complexDirective>
+
+    <meta:complexDirective
+        name="content"
+        schema=".metadirectives.IClassDirective"
+        handler="zope.app.component.contentdirective.ContentDirective"
+        >
+
+      <meta:subdirective
+          name="implements"
+          schema=".metadirectives.IImplementsSubdirective"
+          />
+
+      <meta:subdirective
+          name="require"
+          schema=".metadirectives.IRequireSubdirective"
+          />
+
+      <meta:subdirective
+          name="allow"
+          schema=".metadirectives.IAllowSubdirective"
+          />
+
+      <meta:subdirective
+          name="factory"
+          schema=".metadirectives.IFactorySubdirective"
+          />
+
+    </meta:complexDirective>
+
+    <meta:complexDirective
+        name="localUtility"
+        schema=".metadirectives.IClassDirective"
+        handler=".metaconfigure.LocalUtilityDirective"
+        >
+
+      <meta:subdirective
+          name="implements"
+          schema=".metadirectives.IImplementsSubdirective"
+          />
+
+      <meta:subdirective
+          name="require"
+          schema=".metadirectives.IRequireSubdirective"
+          />
+
+      <meta:subdirective
+          name="allow"
+          schema=".metadirectives.IAllowSubdirective"
+          />
+
+      <meta:subdirective
+          name="factory"
+          schema=".metadirectives.IFactorySubdirective"
+          />
+
+    </meta:complexDirective>
+
+  </meta:directives>
+
+</configure>

Copied: Zope3/branches/srichter-blow-services/src/zope/app/component/bbb/metaconfigure.py (from rev 28677, Zope3/branches/srichter-blow-services/src/zope/app/component/metaconfigure.py)

Copied: Zope3/branches/srichter-blow-services/src/zope/app/component/bbb/metadirectives.py (from rev 28677, Zope3/branches/srichter-blow-services/src/zope/app/component/metadirectives.py)

Copied: Zope3/branches/srichter-blow-services/src/zope/app/component/bbb/registration (from rev 28677, Zope3/branches/srichter-blow-services/src/zope/app/registration)

Copied: Zope3/branches/srichter-blow-services/src/zope/app/component/bbb/servicenames.py (from rev 28677, Zope3/branches/srichter-blow-services/src/zope/app/servicenames.py)

Copied: Zope3/branches/srichter-blow-services/src/zope/app/component/interfaces.py (from rev 28678, Zope3/branches/srichter-blow-services/src/zope/app/component/bbb/site/interfaces.py)
===================================================================
--- Zope3/branches/srichter-blow-services/src/zope/app/component/bbb/site/interfaces.py	2004-12-21 23:28:27 UTC (rev 28678)
+++ Zope3/branches/srichter-blow-services/src/zope/app/component/interfaces.py	2004-12-22 17:17:53 UTC (rev 28687)
@@ -0,0 +1,218 @@
+##############################################################################
+#
+# Copyright (c) 2002 Zope Corporation and Contributors.
+# All Rights Reserved.
+#
+# This software is subject to the provisions of the Zope Public License,
+# Version 2.1 (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.
+#
+##############################################################################
+"""Interfaces for the Local Component Architecture
+
+$Id$
+"""
+import zope.interface
+import zope.schema
+from zope.component.interfaces import ISiteManager
+from zope.app.container.interfaces import IContainer
+from zope.app.container.constraints import ContainerTypesConstraint
+from zope.app.container.constraints import ItemTypePrecondition
+from zope.app.registration import interfaces as registration
+
+
+class IComponentManager(zope.interface.Interface):
+
+    def queryComponent(type=None, filter=None, all=0):
+        """Return all components that match the given type and filter
+
+        The objects are returned a sequence of mapping objects with keys:
+
+        path -- The component path
+
+        component -- The component
+
+        all -- A flag indicating whether all component managers in
+               this place should be queried, or just the local one.
+        """
+
+class IBindingAware(Interface):
+
+    def bound(name):
+        """Inform a service component that it is providing a service
+
+        Called when an immediately-containing service manager binds
+        this object to perform the named service.
+        """
+
+    def unbound(name):
+        """Inform a service component that it is no longer providing a service
+
+        Called when an immediately-containing service manager unbinds
+        this object from performing the named service.
+        """
+
+class IPossibleSite(zope.interface.Interface):
+    """An object that could be a site
+    """
+
+    def setSiteManager(sm):
+        """Sets the service manager for this object.
+        """
+
+    def getSiteManager():
+        """Returns the service manager contained in this object.
+
+        If there isn't a service manager, raise a component lookup.
+        """
+
+class ISite(IPossibleSite):
+    """Marker interface to indicate that we have a site
+    """
+
+class ILocalSiteManager(ISiteManager, IComponentManager,
+                        registration.IRegistry):
+    """Service Managers act as containers for Services.
+
+    If a Service Manager is asked for a service, it checks for those it
+    contains before using a context-based lookup to find another service
+    manager to delegate to.  If no other service manager is found they defer
+    to the ComponentArchitecture ServiceManager which contains file based
+    services.
+    """
+
+    def queryRegistrations(name, default=None):
+        """Return an IRegistrationRegistry for the registration name.
+
+        queryRegistrationsFor(cfg, default) is equivalent to
+        queryRegistrations(cfg.name, default)
+        """
+
+    def createRegistrationsFor(registration):
+        """Create and return an IRegistrationRegistry for the registration
+        name.
+
+        createRegistrationsFor(cfg, default) is equivalent to
+        createRegistrations(cfg.name, default)
+        """
+
+    def listRegistrationNames():
+        """Return a list of all registered registration names.
+        """
+
+    def queryActiveComponent(name, default=None):
+        """Finds the registration registry for a given name, checks if it has
+        an active registration, and if so, returns its component.  Otherwise
+        returns default.
+        """
+
+    def queryLocalService(service_type, default=None):
+        """Return a local service, if there is one
+
+        A local service is one configured in the local service manager.
+        """
+
+    def addSubsite(subsite):
+        """Add a subsite of the site
+
+        Local sites are connected in a tree. Each site knows about
+        its containing sites and its subsites.
+        """
+
+    next = Attribute('The site that this site is a subsite of.')
+
+
+class ISiteManagementFolder(registration.IRegisterableContainer,
+                            IContainer):
+    """Component and component registration containers."""
+
+    __parent__ = zope.schema.Field(
+        constraint = ContainerTypesConstraint(
+            ISiteManager,
+            registration.IRegisterableContainer,
+            ),
+        )
+
+class ISiteManagementFolders(IContainer, IComponentManager):
+    """A collection of ISiteManagementFolder objects.
+
+    An ISiteManagementFolders object supports simple containment as
+    well as package query and lookup.
+    
+    """
+
+class ILocalUtility(registration.IRegisterable):
+    """Local utility marker.
+
+    A marker interface that indicates that a component can be used as
+    a local utility.
+
+    Utilities should usually also declare they implement
+    IAttributeAnnotatable, so that the standard adapter to
+    IRegistered can be used; otherwise, they must provide
+    another way to be adaptable to IRegistered.
+    """
+
+
+class IAdapterRegistration(registration.IRegistration):
+
+    required = zope.schema.Choice(
+        title = _(u"For interface"),
+        description = _(u"The interface of the objects being adapted"),
+        vocabulary="Interfaces",
+        readonly = True)
+
+    provided = zope.schema.Choice(
+        title = _(u"Provided interface"),
+        description = _(u"The interface provided"),
+        vocabulary="Interfaces",
+        readonly = True,
+        required = True)
+
+    name = zope.schema.TextLine(
+        title=_(u"Name"),
+        readonly=True,
+        required=False,
+        )
+
+    factoryName = zope.schema.BytesLine(
+        title=_(u"The dotted name of a factory for creating the adapter"),
+        readonly = True,
+        required = True,
+        )
+
+    permission = zope.schema.Choice(
+        title=_(u"The permission required for use"),
+        vocabulary="Permission Ids",
+        readonly=False,
+        required=False,
+        )
+        
+    factory = zope.interface.Attribute(
+        _("Factory to be called to construct the component")
+        )
+
+class IUtilityRegistration(registration.IComponentRegistration):
+    """Utility registration object.
+
+    This is keyed off name (which may be empty) and interface. It inherits the
+    `component` property.
+    """
+
+    name = zope.schema.TextLine(
+        title=_("Register As"),
+        description=_("The name that is registered"),
+        readonly=True,
+        required=True,
+        )
+
+    interface = zope.schema.Choice(
+        title=_("Provided interface"),
+        description=_("The interface provided by the utility"),
+        vocabulary="Utility Component Interfaces",
+        readonly=True,
+        required=True,
+        )

Modified: Zope3/branches/srichter-blow-services/src/zope/app/component/meta.zcml
===================================================================
--- Zope3/branches/srichter-blow-services/src/zope/app/component/meta.zcml	2004-12-22 17:05:09 UTC (rev 28686)
+++ Zope3/branches/srichter-blow-services/src/zope/app/component/meta.zcml	2004-12-22 17:17:53 UTC (rev 28687)
@@ -54,27 +54,15 @@
         />
 
     <meta:directive
-        name="serviceType"
-        schema=".metadirectives.IServiceTypeDirective"
-        handler="zope.app.component.metaconfigure.serviceType"
-        />
-
-    <meta:directive
         name="defaultLayer"
         schema=".metadirectives.IDefaultLayerDirective"
         handler="zope.app.component.metaconfigure.defaultLayer"
         />
 
-    <meta:directive
-        name="service" 
-        schema=".metadirectives.IServiceDirective"
-        handler="zope.app.component.metaconfigure.service"
-        />
-
     <meta:complexDirective
         name="class"
         schema=".metadirectives.IClassDirective"
-        handler="zope.app.component.contentdirective.ContentDirective"
+        handler=".contentdirective.ContentDirective"
         >
 
       <meta:subdirective
@@ -102,7 +90,7 @@
     <meta:complexDirective
         name="content"
         schema=".metadirectives.IClassDirective"
-        handler="zope.app.component.contentdirective.ContentDirective"
+        handler=".contentdirective.ContentDirective"
         >
 
       <meta:subdirective
@@ -127,6 +115,34 @@
 
     </meta:complexDirective>
 
+    <meta:complexDirective
+        name="localUtility"
+        schema=".metadirectives.IClassDirective"
+        handler=".metaconfigure.LocalUtilityDirective"
+        >
+
+      <meta:subdirective
+          name="implements"
+          schema=".metadirectives.IImplementsSubdirective"
+          />
+
+      <meta:subdirective
+          name="require"
+          schema=".metadirectives.IRequireSubdirective"
+          />
+
+      <meta:subdirective
+          name="allow"
+          schema=".metadirectives.IAllowSubdirective"
+          />
+
+      <meta:subdirective
+          name="factory"
+          schema=".metadirectives.IFactorySubdirective"
+          />
+
+    </meta:complexDirective>
+
   </meta:directives>
 
 </configure>

Modified: Zope3/branches/srichter-blow-services/src/zope/app/component/metaconfigure.py
===================================================================
--- Zope3/branches/srichter-blow-services/src/zope/app/component/metaconfigure.py	2004-12-22 17:05:09 UTC (rev 28686)
+++ Zope3/branches/srichter-blow-services/src/zope/app/component/metaconfigure.py	2004-12-22 17:17:53 UTC (rev 28687)
@@ -16,11 +16,12 @@
 $Id$
 """
 __docformat__ = 'restructuredtext'
+from persistent.interfaces import IPersistent
 
 from zope.component.interfaces import IDefaultViewName, IFactory
 from zope.component.service import UndefinedService
 from zope.configuration.exceptions import ConfigurationError
-from zope.interface import Interface
+from zope.interface import Interface, classImplements
 from zope.interface.interfaces import IInterface
 
 from zope.security.checker import InterfaceChecker, CheckerPublic
@@ -28,9 +29,14 @@
 from zope.security.proxy import Proxy, ProxyFactory
 
 from zope.app import zapi
+from zope.app.annotation.interfaces import IAttributeAnnotatable
+from zope.app.component.contentdirective import ContentDirective
 from zope.app.component.interface import queryInterface
+from zope.app.component.interfaces import ILocalUtility
+from zope.app.location.interfaces import ILocation
 from zope.app.security.adapter import TrustedAdapterFactory
 
+
 PublicPermission = 'zope.Public'
 
 # I prefer the indirection (using getService and getServices vs.
@@ -384,66 +390,67 @@
         args = ('', for_)
         )
 
-def serviceType(_context, id, interface):
+def defaultLayer(_context, type, layer):
     _context.action(
-        discriminator = ('serviceType', id),
-        callable = managerHandler,
-        args = ('defineService', id, interface),
+        discriminator=('defaultLayer', type, layer),
+        callable=handler,
+        args = (zapi.servicenames.Adapters, 'register',
+               (type,), IInterface, 'defaultLayer',
+               lambda request: layer, _context.info)
         )
 
-    if interface.__name__ not in ['IUtilityService']:
-        _context.action(
-            discriminator = None,
-             callable = provideInterface,
-             args = (interface.__module__+'.'+interface.getName(),
-                     interface)
-             )
 
-def provideService(serviceType, component, permission):
-    # This is needed so we can add a security proxy.
-    # We have to wait till execution time so we can find out the interface.
-    # Waaaa.
+class LocalUtilityDirective(ContentDirective):
+    r"""localUtility directive handler.
 
-    service_manager = zapi.getGlobalServices()
+    Examples:
 
-    if permission:
-        for stype, interface in service_manager.getServiceDefinitions():
-            if stype == serviceType:
-                break
-        else:
-            raise UndefinedService(serviceType)
+      >>> from zope.interface import implements
+      >>> class LU1(object):
+      ...     pass
 
-        if permission == PublicPermission:
-            permission = CheckerPublic
+      >>> class LU2(LU1):
+      ...     implements(ILocation)
 
-        checker = InterfaceChecker(interface, permission)
+      >>> class LU3(LU1):
+      ...     __parent__ = None
 
-        try:
-            component.__Security_checker__ = checker
-        except: # too bad exceptions aren't more predictable
-            component = proxify(component, checker)
+      >>> class LU4(LU2):
+      ...     implements(IPersistent)
 
-    service_manager.provideService(serviceType, component)
+      >>> dir = LocalUtilityDirective(None, LU4)
+      >>> IAttributeAnnotatable.implementedBy(LU4)
+      True
+      >>> ILocalUtility.implementedBy(LU4)
+      True
 
-def service(_context, serviceType, component=None, permission=None,
-            factory=None):
-    if factory:
-        if component:
-            raise TypeError("Can't specify factory and component.")
+      >>> LocalUtilityDirective(None, LU3)
+      Traceback (most recent call last):
+      ...
+      ConfigurationError: Class `LU3` does not implement `IPersistent`.
 
-        component = factory()
+      >>> LocalUtilityDirective(None, LU2)
+      Traceback (most recent call last):
+      ...
+      ConfigurationError: Class `LU2` does not implement `IPersistent`.
 
-    _context.action(
-        discriminator = ('service', serviceType),
-        callable = provideService,
-        args = (serviceType, component, permission),
-        )
+      >>> LocalUtilityDirective(None, LU1)
+      Traceback (most recent call last):
+      ...
+      ConfigurationError: Class `LU1` does not implement `ILocation`.
+    """
 
-def defaultLayer(_context, type, layer):
-    _context.action(
-        discriminator=('defaultLayer', type, layer),
-        callable=handler,
-        args = (zapi.servicenames.Adapters, 'register',
-               (type,), IInterface, 'defaultLayer',
-               lambda request: layer, _context.info)
-        )
+    def __init__(self, _context, class_):
+        if not ILocation.implementedBy(class_) and \
+               not hasattr(class_, '__parent__'):
+            raise ConfigurationError, \
+                  'Class `%s` does not implement `ILocation`.' %class_.__name__
+
+        if not IPersistent.implementedBy(class_):
+            raise ConfigurationError, \
+                 'Class `%s` does not implement `IPersistent`.' %class_.__name__
+
+        classImplements(class_, IAttributeAnnotatable)
+        classImplements(class_, ILocalUtility)
+
+        super(LocalUtilityDirective, self).__init__(_context, class_)

Modified: Zope3/branches/srichter-blow-services/src/zope/app/component/metadirectives.py
===================================================================
--- Zope3/branches/srichter-blow-services/src/zope/app/component/metadirectives.py	2004-12-22 17:05:09 UTC (rev 28686)
+++ Zope3/branches/srichter-blow-services/src/zope/app/component/metadirectives.py	2004-12-22 17:17:53 UTC (rev 28687)
@@ -333,7 +333,6 @@
         )
 
 
-
 class IResourceDirective(IBasicComponentInformation,
                          IBasicResourceInformation):
     """Register a resource"""
@@ -357,26 +356,6 @@
         )
 
 
-class IServiceTypeDirective(zope.interface.Interface):
-
-    id = zope.schema.TextLine(
-        title=_("ID of the service type"),
-        required=True
-        )
-
-    interface = zope.configuration.fields.GlobalInterface(
-        title=_("Interface of the service type"),
-        required=True
-        )
-
-class IServiceDirective(IBasicComponentInformation):
-    """Register a service"""
-
-    serviceType = zope.schema.TextLine(
-        title=_("ID of service type"),
-        required=True
-        )
-
 class IClassDirective(zope.interface.Interface):
     """Make statements about a class"""
 

Copied: Zope3/branches/srichter-blow-services/src/zope/app/component/site.py (from rev 28678, Zope3/branches/srichter-blow-services/src/zope/app/component/bbb/site/service.py)
===================================================================
--- Zope3/branches/srichter-blow-services/src/zope/app/component/bbb/site/service.py	2004-12-21 23:28:27 UTC (rev 28678)
+++ Zope3/branches/srichter-blow-services/src/zope/app/component/site.py	2004-12-22 17:17:53 UTC (rev 28687)
@@ -0,0 +1,284 @@
+##############################################################################
+#
+# 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.1 (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.
+#
+##############################################################################
+"""Site and Local Site Manager implementation
+
+A local manager has a number of roles:
+
+  - A service service
+
+  - A place to do TTW development or to manage database-based code
+
+  - A registry for persistent modules.  The Zope import hook uses the
+    ServiceManager to search for modules.  (This functionality will
+    eventually be replaced by a separate module service.)
+
+$Id$
+"""
+import sys
+from transaction import get_transaction
+from zodbcode.module import PersistentModuleRegistry
+
+import zope.event
+import zope.interface
+from zope.component.exceptions import ComponentLookupError
+
+import zope.app.registration.interfaces
+from zope.app import zapi
+from zope.app.component.hooks import setSite
+from zope.app.container.btree import BTreeContainer
+from zope.app.container.constraints import ItemTypePrecondition
+from zope.app.container.contained import Contained
+from zope.app.container.interfaces import IContainer
+from zope.app.event import objectevent
+from zope.app.location import inside
+from zope.app.registration.interfaces import IRegistry
+from zope.app.registration.registration import ComponentRegistration
+from zope.app.registration.registration import RegistrationStack
+from zope.app.site.folder import SiteManagementFolder
+from zope.app.traversing.interfaces import IContainmentRoot
+
+from zope.app.site.interfaces import IPossibleSite, ISite, ISiteManager
+
+class IRegisterableContainerContainer(zope.interface.Interface):
+
+    def __setitem__(name, folder):
+        """Add a site-management folder
+        """
+    __setitem__.precondition = ItemTypePrecondition(
+       zope.app.registration.interfaces.IRegisterableContainer)
+
+
+class LocalSiteManager(BTreeContainer, PersistentModuleRegistry):
+
+    zope.interface.implements(ILocalSiteManager,
+                              IRegisterableContainerContainer,
+                              IRegistry)
+
+    def __init__(self, site):
+        self._bindings = {}
+        self.__parent__ = site
+        self.__name__ = '++etc++site'
+        BTreeContainer.__init__(self)
+        PersistentModuleRegistry.__init__(self)
+        self.subSites = ()
+        self._setNext(site)
+        folder = SiteManagementFolder()
+        zope.event.notify(objectevent.ObjectCreatedEvent(folder))
+        self['default'] = folder
+
+    def _setNext(self, site):
+        """Find set the next service manager
+        """
+        while True:
+            if IContainmentRoot.providedBy(site):
+                # we're the root site, use the global sm
+                self.next = zapi.getGlobalServices()
+                return
+            site = site.__parent__
+            if site is None:
+                raise TypeError("Not enough context information")
+            if ISite.providedBy(site):
+                self.next = site.getSiteManager()
+                self.next.addSubsite(self)
+                return
+
+    def addSubsite(self, sub):
+        """See ISiteManager interface
+        """
+        subsite = sub.__parent__
+
+        # Update any sites that are now in the subsite:
+        subsites = []
+        for s in self.subSites:
+            if inside(s, subsite):
+                s.next = sub
+                sub.addSubsite(s)
+            else:
+                subsites.append(s)
+
+        subsites.append(sub)
+        self.subSites = tuple(subsites)
+
+    def queryRegistrationsFor(self, cfg, default=None):
+        """See IRegistry"""
+        return self.queryRegistrations(cfg.name, default)
+
+    def queryRegistrations(self, name, default=None):
+        """See INameRegistry"""
+        return self._bindings.get(name, default)
+
+    def createRegistrationsFor(self, cfg):
+        """See IRegistry"""
+        return self.createRegistrations(cfg.name)
+
+    def createRegistrations(self, name):
+        try:
+            registry = self._bindings[name]
+        except KeyError:
+            registry = RegistrationStack(self)
+            self._bindings[name] = registry
+            self._p_changed = 1
+        return registry
+
+    def listRegistrationNames(self):
+        return filter(self._bindings.get,
+                      self._bindings.keys())
+
+    def queryActiveComponent(self, name, default=None):
+        registry = self.queryRegistrations(name)
+        if registry:
+            registration = registry.active()
+            if registration is not None:
+                return registration.component
+        return default
+
+
+    def queryComponent(self, type=None, filter=None, all=0):
+        local = []
+        path = zapi.getPath(self)
+        for pkg_name in self:
+            package = self[pkg_name]
+            for name in package:
+                component = package[name]
+                if type is not None and not type.providedBy(component):
+                    continue
+                if filter is not None and not filter(component):
+                    continue
+                local.append({'path': "%s/%s/%s" % (path, pkg_name, name),
+                              'component': component,
+                              })
+
+        if all:
+            next_service_manager = self.next
+            if IComponentManager.providedBy(next_service_manager):
+                next_service_manager.queryComponent(type, filter, all)
+
+            local += list(all)
+
+        return local
+
+    def findModule(self, name):
+        # override to pass call up to next service manager
+        mod = super(ServiceManager, self).findModule(name)
+        if mod is not None:
+            return mod
+
+        sm = self.next
+        try:
+            findModule = sm.findModule
+        except AttributeError:
+            # The only service manager that doesn't implement this
+            # interface is the global service manager.  There is no
+            # direct way to ask if sm is the global service manager.
+            return None
+        return findModule(name)
+
+    def __import(self, module_name):
+        mod = self.findModule(module_name)
+        if mod is None:
+            mod = sys.modules.get(module_name)
+            if mod is None:
+                raise ImportError(module_name)
+
+        return mod
+
+
+class AdapterRegistration(
+    zope.app.registration.registration.SimpleRegistration):
+
+    zope.interface.implements(IAdapterRegistration)
+
+    serviceType = zapi.servicenames.Adapters
+
+    with = () # Don't support multi-adapters yet
+
+    # TODO: These should be positional arguments, except that required
+    #       isn't passed in if it is omitted. To fix this, we need a
+    #       required=False,explicitly_unrequired=True in the schema field
+    #       so None will get passed in.
+    def __init__(self, provided, factoryName,
+                 name='', required=None, permission=None):
+        self.required = required
+        self.provided = provided
+        self.name = name
+        self.factoryName = factoryName
+        self.permission = permission
+
+    def factory(self):
+        folder = self.__parent__.__parent__
+        factory = folder.resolve(self.factoryName)
+        return factory
+    factory = property(factory)
+
+
+
+class UtilityRegistration(ComponentRegistration):
+    """Utility component registration for persistent components
+
+    This registration configures persistent components in packages to
+    be utilities.
+    """
+    zope.interface.implements(IUtilityRegistration)
+
+    serviceType = zapi.servicenames.Utilities
+
+    ############################################################
+    # To make adapter code happy. Are we going too far?
+    #
+    required = zope.interface.adapter.Null
+    with = ()
+    provided = property(lambda self: self.interface)
+    factory = property(lambda self: self.component)
+    #
+    ############################################################
+
+    def __init__(self, name, interface, component, permission=None):
+        super(UtilityRegistration, self).__init__(component, permission)
+        self.name = name
+        self.interface = interface
+
+    def usageSummary(self):
+        # Override IRegistration.usageSummary()
+        s = self.getInterface().getName()
+        if self.name:
+            s += " registered as '%s'" % self.name
+        s += ", implemented by %s" %self.component.__class__.__name__
+        s += " '%s'"%zapi.name(self.component)
+        return s
+
+    def getInterface(self):
+        # ComponentRegistration calls this when you specify a
+        # permission; it needs the interface to create a security
+        # proxy for the interface with the given permission.
+        return self.interface
+
+
+def threadSiteSubscriber(event):
+    """A subscriber to BeforeTraverseEvent
+
+    Sets the 'site' thread global if the object traversed is a site.
+    """
+    if ISite.providedBy(event.object):
+        setSite(event.object)
+
+
+def clearThreadSiteSubscriber(event):
+    """A subscriber to EndRequestEvent
+
+    Cleans up the site thread global after the request is processed.
+    """
+    clearSite()
+
+# Clear the site thread global
+clearSite = setSite

Copied: Zope3/branches/srichter-blow-services/src/zope/app/component/testing.py (from rev 28678, Zope3/branches/srichter-blow-services/src/zope/app/component/bbb/site/tests/placefulsetup.py)
===================================================================
--- Zope3/branches/srichter-blow-services/src/zope/app/component/bbb/site/tests/placefulsetup.py	2004-12-21 23:28:27 UTC (rev 28678)
+++ Zope3/branches/srichter-blow-services/src/zope/app/component/testing.py	2004-12-22 17:17:53 UTC (rev 28687)
@@ -0,0 +1,153 @@
+##############################################################################
+#
+# 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.1 (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.
+#
+##############################################################################
+"""Base Mix-in class for Placeful Setups 
+
+$Id$
+"""
+from zope.app import zapi
+from zope.app.testing import setup
+from zope.app.testing.placelesssetup import PlacelessSetup
+from zope.app.folder import rootFolder
+
+class Place(object):
+
+    def __init__(self, path):
+        self.path = path
+
+    def __get__(self, inst, cls=None):
+        if inst is None:
+            return self
+
+        try:
+            # Use __dict__ directly to avoid infinite recursion
+            root = inst.__dict__['rootFolder']
+        except KeyError:
+            root = inst.rootFolder = setup.buildSampleFolderTree()
+
+        return zapi.traverse(root, self.path)
+
+
+class PlacefulSetup(PlacelessSetup):
+
+    # Places :)
+    rootFolder  = Place('')
+
+    folder1     = Place('folder1')
+    folder1_1   = Place('folder1/folder1_1')
+    folder1_1_1 = Place('folder1/folder1_1/folder1_1_1')
+    folder1_1_2 = Place('folder1/folder1_2/folder1_1_2')
+    folder1_2   = Place('folder1/folder1_2')
+    folder1_2_1 = Place('folder1/folder1_2/folder1_2_1')
+
+    folder2     = Place('folder2')
+    folder2_1   = Place('folder2/folder2_1')
+    folder2_1_1 = Place('folder2/folder2_1/folder2_1_1')
+
+
+    def setUp(self, folders=False, site=False):
+        setup.placefulSetUp()
+        if folders or site:
+            return self.buildFolders(site)
+
+    def tearDown(self):
+        setup.placefulTearDown()
+        # clean up folders and placeful service managers and services too?
+
+    def buildFolders(self, site=False):
+        self.rootFolder = setup.buildSampleFolderTree()
+        if site:
+            return self.makeSite()
+
+    def makeSite(self, path='/'):
+        folder = zapi.traverse(self.rootFolder, path)
+        return setup.createServiceManager(folder, True)
+
+    def createRootFolder(self):
+        self.rootFolder = rootFolder()
+
+    def createStandardServices(self):
+        '''Create a bunch of standard placeful services'''
+
+        setup.createStandardServices(self.rootFolder)
+
+
+def testingNextUtility(utility, nextutility, interface, name='',
+                       service=None, nextservice=None):
+    """Provide a next utility for testing.
+
+    Since utilities must be registered in services, we really provide a next
+    utility service in which we place the next utility. If you do not pass in
+    any services, they will be created for you.
+
+    For a simple usage of this function, see the doc test of
+    `queryNextUtility()`. Here is a demonstration that passes in the services
+    directly and ensures that the `__parent__` attributes are set correctly.
+
+    First, we need to create a utility interface and implementation:
+
+      >>> from zope.interface import Interface, implements
+      >>> class IAnyUtility(Interface):
+      ...     pass
+      
+      >>> class AnyUtility(object):
+      ...     implements(IAnyUtility)
+      ...     def __init__(self, id):
+      ...         self.id = id
+      
+      >>> any1 = AnyUtility(1)
+      >>> any1next = AnyUtility(2)
+
+    Now we create a special utility service that can have a location:
+
+      >>> UtilityService = type('UtilityService', (GlobalUtilityService,),
+      ...                       {'__parent__': None})
+
+    Let's now create one utility service
+
+      >>> utils = UtilityService()
+
+    and pass it in as the original utility service to the function:
+
+      >>> testingNextUtility(any1, any1next, IAnyUtility, service=utils)
+      >>> any1.__parent__ is utils
+      True
+      >>> utilsnext = any1next.__parent__
+      >>> utils.__parent__.next.data['Utilities'] is utilsnext
+      True
+
+    or if we pass the current and the next utility service:
+
+      >>> utils = UtilityService()
+      >>> utilsnext = UtilityService()
+      >>> testingNextUtility(any1, any1next, IAnyUtility,
+      ...                    service=utils, nextservice=utilsnext)
+      >>> any1.__parent__ is utils
+      True
+      >>> any1next.__parent__ is utilsnext
+      True
+    
+    """
+    UtilityService = type('UtilityService', (GlobalUtilityService,),
+                          {'__parent__': None})
+    if service is None:
+        service = UtilityService()
+    if nextservice is None:
+        nextservice = UtilityService()
+    from zope.app.component.localservice import testingNextService
+    testingNextService(service, nextservice, zapi.servicenames.Utilities)
+
+    service.provideUtility(interface, utility, name)
+    utility.__parent__ = service
+    nextservice.provideUtility(interface, nextutility, name)
+    nextutility.__parent__ = nextservice

Copied: Zope3/branches/srichter-blow-services/src/zope/app/component/vocabulary.py (from rev 28678, Zope3/branches/srichter-blow-services/src/zope/app/component/bbb/utility/vocabulary.py)



More information about the Zope3-Checkins mailing list