[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