[Zope3-checkins] CVS: Zope3/src/zope/app/component - __init__.py:1.2 classfactory.py:1.2 configure.zcml:1.2 globalinterfaceservice.py:1.2 hooks.py:1.2 interfacefield.py:1.2 meta.zcml:1.2 metaconfigure.py:1.2 nextservice.py:1.2

Jim Fulton jim@zope.com
Wed, 25 Dec 2002 09:13:47 -0500


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

Added Files:
	__init__.py classfactory.py configure.zcml 
	globalinterfaceservice.py hooks.py interfacefield.py meta.zcml 
	metaconfigure.py nextservice.py 
Log Message:
Grand renaming:

- Renamed most files (especially python modules) to lower case.

- Moved views and interfaces into separate hierarchies within each
  project, where each top-level directory under the zope package
  is a separate project.

- Moved everything to src from lib/python.

  lib/python will eventually go away. I need access to the cvs
  repository to make this happen, however.

There are probably some bits that are broken. All tests pass
and zope runs, but I haven't tried everything. There are a number
of cleanups I'll work on tomorrow.



=== Zope3/src/zope/app/component/__init__.py 1.1 => 1.2 ===
--- /dev/null	Wed Dec 25 09:13:46 2002
+++ Zope3/src/zope/app/component/__init__.py	Wed Dec 25 09:12:45 2002
@@ -0,0 +1,2 @@
+#
+# This file is necessary to make this directory a package.


=== Zope3/src/zope/app/component/classfactory.py 1.1 => 1.2 ===
--- /dev/null	Wed Dec 25 09:13:46 2002
+++ Zope3/src/zope/app/component/classfactory.py	Wed Dec 25 09:12:45 2002
@@ -0,0 +1,32 @@
+##############################################################################
+#
+# 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.0 (ZPL).  A copy of the ZPL should accompany this distribution.
+# THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED
+# WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+# WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS
+# FOR A PARTICULAR PURPOSE.
+#
+##############################################################################
+"$Id$"
+
+from zope.component.interfaces import IFactory
+
+class ClassFactory:
+    "Class that creates a factory component from a class"
+
+    __implements__ = IFactory
+
+    def __init__(self, _class):
+        self._class = _class
+
+    def __call__(self, *args, **kwargs):
+        return self._class(*args, **kwargs)
+
+    def getInterfaces(self):
+        return getattr(self._class, '__implements__', None)
+
+__doc__ = "%s\n\n%s" % (ClassFactory.__doc__, __doc__)


=== Zope3/src/zope/app/component/configure.zcml 1.1 => 1.2 ===
--- /dev/null	Wed Dec 25 09:13:46 2002
+++ Zope3/src/zope/app/component/configure.zcml	Wed Dec 25 09:12:45 2002
@@ -0,0 +1,62 @@
+<zopeConfigure
+   xmlns='http://namespaces.zope.org/zope'
+   package="zope.component"
+>
+
+  <serviceType id='Utilities'
+               interface='zope.component.interfaces.IUtilityService' />
+  <service serviceType='Utilities'
+           permission='zope.Public'
+           component='zope.component.utility.utilityService' />
+             
+  <serviceType id='Adapters'
+               interface='zope.component.interfaces.IAdapterService' />
+  <service serviceType='Adapters'
+           permission='zope.Public'
+           component='zope.component.adapter.adapterService' />
+
+  <serviceType id='Factories'
+               interface='zope.component.interfaces.IFactoryService' />
+  <service serviceType='Factories'
+           permission='zope.Public'
+           component='zope.component.factory.factoryService' />
+
+  <serviceType id='Skins'
+               interface='zope.component.interfaces.ISkinService' />
+  <service serviceType='Skins'
+           permission='zope.Public'
+           component='zope.component.skin.skinService' />
+
+  <serviceType id='Views' 
+               interface='zope.component.interfaces.IViewService' />
+  <service serviceType='Views'
+           permission='zope.Public'
+           component='zope.component.view.viewService' />
+           
+  <serviceType id='Resources'
+               interface='zope.component.interfaces.IResourceService' />
+  <service serviceType='Resources'
+           permission='zope.Public'
+           component='zope.component.resource.resourceService' />
+           
+  <hookable name=".getServiceManager" />
+
+  <hook module="zope.component"
+        name="getServiceManager"
+        implementation="
+           zope.app.component.hooks.getServiceManager_hook" />
+  
+  <serviceType id='Interfaces'
+               interface='zope.app.component.globalinterfaceservice.IInterfaceService' />
+	   
+  <service 
+     serviceType='Interfaces'
+     permission='zope.Public'
+     component=
+        'zope.app.component.globalinterfaceservice.interfaceService' />
+
+  <interface interface="zope.interface.Interface" />
+
+</zopeConfigure>
+
+


=== Zope3/src/zope/app/component/globalinterfaceservice.py 1.1 => 1.2 ===
--- /dev/null	Wed Dec 25 09:13:46 2002
+++ Zope3/src/zope/app/component/globalinterfaceservice.py	Wed Dec 25 09:12:45 2002
@@ -0,0 +1,138 @@
+##############################################################################
+#
+# 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.0 (ZPL).  A copy of the ZPL should accompany this distribution.
+# THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED
+# WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+# WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS
+# FOR A PARTICULAR PURPOSE.
+#
+##############################################################################
+"""
+$Id$
+"""
+
+from zope.interface import Interface
+
+class IInterfaceService(Interface):
+    """Service that keeps track of used interfaces
+    """
+
+    def getInterface(id):
+        """Return the interface registered for the given id
+
+        A ComponentLookupError is raised if the interface can't be found.
+        """
+
+    def queryInterface(id, default=None):
+        """Return the interface registered for the given id
+
+        The default is returned if the interface can't be found.
+        """
+
+    def searchInterface(search_string='', base=None):
+        """Return the interfaces that match the search criteria
+
+        If a search string is given, only interfaces that contain the
+        string in their documentation will be returned.
+
+        If base is given, only interfaces that equal or extend base
+        will be returned.
+
+        """
+
+    def searchInterfaceIds(search_string='', base=None):
+        """Return the ids of the interfaces that match the search criteria.
+
+        See searchInterface
+
+        """
+
+
+__doc__ = IInterfaceService.__doc__ + __doc__
+
+
+"""
+$Id$
+"""
+from zope.app.interfaces.component.globalinterfaceservice import IGlobalInterfaceService
+from zope.component.exceptions import ComponentLookupError
+
+class InterfaceService:
+    __implements__ = IGlobalInterfaceService
+
+    def __init__(self, data=None):
+        if data is None:
+            data = {}
+        self.__data = data
+
+    def getInterface(self, id):
+        if id in self.__data:
+            return self.__data[id][0]
+        else:
+            raise ComponentLookupError
+
+    def queryInterface(self, id, default=None):
+        if self.__data.has_key(id):
+            return self.__data[id][0]
+        else:
+            return default
+
+    def searchInterfaceIds(self, search_string='', base=None):
+        result = []
+
+        data = self.__data
+        search_string = search_string.lower()
+
+        for id in data:
+            interface, doc = data[id]
+
+            if search_string:
+                if doc.find(search_string) < 0:
+                    continue
+
+            if base is not None and not interface.extends(base, 0):
+                continue
+
+            result.append(id)
+
+        return result
+
+    def searchInterface(self, search_string='', base=None):
+        data = self.__data
+        return [data[id][0]
+                for id in self.searchInterfaceIds(search_string, base)]
+
+    def _getAllDocs(self,interface):
+        docs = [str(interface.__name__).lower(),
+                str(interface.__doc__).lower()]
+
+        for name in interface:
+            docs.append(str(interface.getDescriptionFor(name).__doc__).lower())
+
+        return '\n'.join(docs)
+
+    def provideInterface(self, id, interface):
+        if not id:
+            id = "%s.%s" % (interface.__module__, interface.__name__)
+
+        self.__data[id]=(interface, self._getAllDocs(interface))
+
+    _clear = __init__
+
+
+
+interfaceService = InterfaceService()
+provideInterface = interfaceService.provideInterface
+getInterface = interfaceService.getInterface
+queryInterface = interfaceService.queryInterface
+searchInterface = interfaceService.searchInterface
+
+_clear = interfaceService._clear
+
+from zope.testing.cleanup import addCleanUp
+addCleanUp(_clear)
+del addCleanUp


=== Zope3/src/zope/app/component/hooks.py 1.1 => 1.2 ===
--- /dev/null	Wed Dec 25 09:13:46 2002
+++ Zope3/src/zope/app/component/hooks.py	Wed Dec 25 09:12:45 2002
@@ -0,0 +1,52 @@
+##############################################################################
+#
+# 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.0 (ZPL).  A copy of the ZPL should accompany this distribution.
+# THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED
+# WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+# WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS
+# FOR A PARTICULAR PURPOSE.
+#
+##############################################################################
+"""
+
+$Id$
+"""
+from zope.component.interfaces import IServiceService
+from zope.app.interfaces.services.service \
+     import IServiceManagerContainer
+from zope.component.exceptions import ComponentLookupError
+from zope.proxy.context import getWrapperContainer, ContextWrapper
+from zope.component import getServiceManager
+from zope.component.exceptions import ComponentLookupError
+from zope.component.service import serviceManager
+from zope.proxy.introspection import removeAllProxies
+from zope.security.proxy import trustedRemoveSecurityProxy
+
+def getServiceManager_hook(context):
+    """
+    context based lookup, with fallback to component architecture
+    service manager if no service manager found within context
+    """
+    while context is not None:
+        clean_context = removeAllProxies(context)
+
+        # if the context is actually a service or service manager...
+        if IServiceService.isImplementedBy(clean_context):
+            return trustedRemoveSecurityProxy(context)
+
+        if (IServiceManagerContainer.isImplementedBy(clean_context) and
+            clean_context.hasServiceManager()
+            ):
+            return ContextWrapper(
+                trustedRemoveSecurityProxy(context.getServiceManager()),
+                context,
+                name="++etc++Services",
+                )
+
+        context = getWrapperContainer(context)
+
+    return serviceManager


=== Zope3/src/zope/app/component/interfacefield.py 1.1 => 1.2 ===
--- /dev/null	Wed Dec 25 09:13:46 2002
+++ Zope3/src/zope/app/component/interfacefield.py	Wed Dec 25 09:12:45 2002
@@ -0,0 +1,43 @@
+##############################################################################
+#
+# Copyright (c) 2002 Zope Corporation and Contributors.
+# All Rights Reserved.
+#
+# This software is subject to the provisions of the Zope Public License,
+# Version 2.0 (ZPL).  A copy of the ZPL should accompany this distribution.
+# THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED
+# WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+# WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS
+# FOR A PARTICULAR PURPOSE.
+#
+##############################################################################
+"""These are the interfaces for the common fields.
+
+$Id$
+"""
+
+from zope.schema import ValueSet
+from zope.interface import Interface
+from zope.interface.interfaces import IInterface
+from zope.schema.interfaces import ValidationError
+from zope.app.interfaces.component.interfacefield import IInterfaceField
+
+class InterfaceField(ValueSet):
+    __doc__ = IInterfaceField.__doc__
+    __implements__ = IInterfaceField
+
+    type = Interface
+
+    def __init__(self, type=Interface, *args, **kw):
+        super(InterfaceField, self).__init__(*args, **kw)
+        self.validate(type)
+        self.type = type
+
+    def _validate(self, value):
+        super(InterfaceField, self)._validate(value)
+
+        if not IInterface.isImplementedBy(value):
+            raise ValidationError("Not an interface", value)
+
+        if not value.extends(self.type, 0):
+            raise ValidationError("Does not extend", value, self.type)


=== Zope3/src/zope/app/component/meta.zcml 1.1 => 1.2 ===
--- /dev/null	Wed Dec 25 09:13:47 2002
+++ Zope3/src/zope/app/component/meta.zcml	Wed Dec 25 09:12:45 2002
@@ -0,0 +1,44 @@
+<zopeConfigure xmlns='http://namespaces.zope.org/zope'>
+
+  <directives namespace="http://namespaces.zope.org/zope">
+
+    <directive name="interface" attributes="interface"
+       handler="zope.app.component.metaconfigure.interface" />
+
+    <directive name="adapter" attributes="factory provides for permission"
+       handler="zope.app.component.metaconfigure.adapter" />
+
+    <directive name="utility" attributes="component provides permission name"
+       handler="zope.app.component.metaconfigure.utility" />
+
+    <directive name="factory" attributes="component id"
+       handler="zope.app.component.metaconfigure.factory" />
+
+    <directive 
+       name="view" 
+       attributes="component type name for layer
+                   permission allowed_interface allowed_attributes"
+       handler="zope.app.component.metaconfigure.view" />
+
+    <directive name="defaultView" 
+               attributes="component type name for layer"
+       handler="zope.app.component.metaconfigure.defaultView" />
+
+    <directive 
+       name="resource" 
+       attributes="component type name layer
+                   permission allowed_interface allowed_attributes"
+       handler="zope.app.component.metaconfigure.resource" />
+
+    <directive name="skin" attributes="name type layers" 
+        handler="zope.app.component.metaconfigure.skin" />
+    
+    <directive name="serviceType" attributes="id interface"
+       handler="zope.app.component.metaconfigure.serviceType" />
+
+    <directive name="service" attributes="serviceType component permission"
+       handler="zope.app.component.metaconfigure.service" />
+
+  </directives>
+
+</zopeConfigure>


=== Zope3/src/zope/app/component/metaconfigure.py 1.1 => 1.2 ===
--- /dev/null	Wed Dec 25 09:13:47 2002
+++ Zope3/src/zope/app/component/metaconfigure.py	Wed Dec 25 09:12:45 2002
@@ -0,0 +1,382 @@
+##############################################################################
+#
+# 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.0 (ZPL).  A copy of the ZPL should accompany this distribution.
+# THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED
+# WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+# WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS
+# FOR A PARTICULAR PURPOSE.
+#
+##############################################################################
+
+from zope.configuration.exceptions import ConfigurationError
+from zope.security.proxy import Proxy
+from zope.component import getService, getServiceManager
+from zope.configuration import namespace
+from zope.interface import Interface
+from zope.configuration.action import Action
+from zope.security.checker \
+     import InterfaceChecker, CheckerPublic, NamesChecker, Checker
+from zope.app.security.registries.permissionregistry import permissionRegistry
+from zope.component.service \
+     import UndefinedService
+
+# I prefer the indirection (using getService and getServiceManager vs.
+# directly importing the various services)  not only because it makes
+# unit tests easier, but also because it reinforces that the services
+# should always be obtained through the
+# IPlacefulComponentArchitecture interface methods
+
+# But these services aren't placeful! And we need to get at things that
+# normal service clients don't need!   Jim
+
+
+def handler(serviceName, methodName, *args, **kwargs):
+    method=getattr(getService(None, serviceName), methodName)
+    method(*args, **kwargs)
+
+# We can't use the handler for serviceType, because serviceType needs
+# the interface service.
+from zope.app.component.globalinterfaceservice import provideInterface
+
+def checkingHandler(permission=None, *args, **kw):
+    """Check if permission is defined"""
+    if permission is not None:
+        permissionRegistry.ensurePermissionDefined(permission)
+    handler(*args, **kw)
+
+def managerHandler(methodName, *args, **kwargs):
+    method=getattr(getServiceManager(None), methodName)
+    method(*args, **kwargs)
+
+def interface(_context, interface):
+    interface = _context.resolve(interface)
+    return [
+        Action(
+          discriminator = None,
+          callable = handler,
+          args = ('Interfaces', 'provideInterface', '', interface)
+        ),
+      ]
+
+
+def adapter(_context, factory, provides, for_=None, permission=None, name=''):
+    if for_ is not None: for_ = _context.resolve(for_)
+    provides = _context.resolve(provides)
+    factory = map(_context.resolve, factory.split())
+
+    if permission is not None:
+        if permission == 'zope.Public':
+            permission = CheckerPublic
+        checker = InterfaceChecker(provides, permission)
+        factory.append(lambda c: Proxy(c, checker))
+    actions=[
+        Action(
+            discriminator = ('adapter', for_, provides, name),
+            callable = checkingHandler,
+            args = (permission, 'Adapters', 'provideAdapter',
+                    for_, provides, factory, name),
+               ),
+        Action(
+            discriminator = None,
+            callable = handler,
+            args = ('Interfaces', 'provideInterface', '', provides)
+              )
+              ]
+    if for_ is not None:
+        actions.append
+        (
+        Action(
+            discriminator = None,
+            callable = handler,
+            args = ('Interfaces', 'provideInterface', '', for_)
+              )
+         )
+
+    return actions
+
+
+def utility(_context, provides, component=None, factory=None,
+            permission=None, name=''):
+    provides = _context.resolve(provides)
+
+    if factory:
+        if component:
+            raise TypeError("Can't specify factory and component.")
+
+        component = _context.resolve(factory)()
+    else:
+        component = _context.resolve(component)
+
+    if permission is not None:
+        if permission == 'Zope.Public':
+            permission = CheckerPublic
+        checker = InterfaceChecker(provides, permission)
+
+        component = Proxy(component, checker)
+
+    return [
+        Action(
+            discriminator = ('utility', provides, name),
+            callable = checkingHandler,
+            args = (permission, 'Utilities', 'provideUtility',
+                    provides, component, name),
+            ),
+        Action(
+            discriminator = None,
+            callable = handler,
+            args = ('Interfaces', 'provideInterface',
+                    provides.__module__+'.'+provides.__name__, provides)
+              )
+        ]
+
+
+def factory(_context, component, id=None):
+    if id is None:
+        id = component
+
+    component = _context.resolve(component)
+
+    return [
+        Action(
+            discriminator = ('factory', id),
+            callable = handler,
+            args = ('Factories', 'provideFactory', id, component),
+            )
+        ]
+
+def _checker(_context, permission, allowed_interface, allowed_attributes):
+    if (not allowed_attributes) and (not allowed_interface):
+        allowed_attributes = "__call__"
+
+    if permission == 'zope.Public':
+        permission = CheckerPublic
+
+    require={}
+    for name in (allowed_attributes or '').split():
+        require[name] = permission
+    if allowed_interface:
+        for name in _context.resolve(allowed_interface).names(1):
+            require[name] = permission
+
+    checker = Checker(require.get)
+
+    return checker
+
+def resource(_context, factory, type, name, layer='default',
+             permission=None,
+             allowed_interface=None, allowed_attributes=None):
+
+    if ((allowed_attributes or allowed_interface)
+        and (not permission)):
+        raise ConfigurationError(
+            "Must use name attribute with allowed_interface or "
+            "allowed_attributes"
+            )
+
+
+    type = _context.resolve(type)
+    factory = _context.resolve(factory)
+
+
+    if permission:
+
+        checker = _checker(_context, permission,
+                           allowed_interface, allowed_attributes)
+
+        def proxyResource(request, factory=factory, checker=checker):
+            return Proxy(factory(request), checker)
+
+        factory = proxyResource
+
+    return [
+        Action(
+            discriminator = ('resource', name, type, layer),
+            callable = checkingHandler,
+            args = (permission, 'Resources','provideResource',
+                    name, type, factory, layer),
+            ),
+        Action(
+            discriminator = None,
+            callable = handler,
+            args = ('Interfaces', 'provideInterface',
+                    type.__module__+'.'+type.__name__, type)
+              )
+        ]
+
+def view(_context, factory, type, name, for_=None, layer='default',
+         permission=None, allowed_interface=None, allowed_attributes=None):
+
+    if ((allowed_attributes or allowed_interface)
+        and (not permission)):
+        raise ConfigurationError(
+            "Must use name attribute with allowed_interface or "
+            "allowed_attributes"
+            )
+
+    if for_ is not None: for_ = _context.resolve(for_)
+    type = _context.resolve(type)
+
+    factory = map(_context.resolve, factory.strip().split())
+    if not factory:
+        raise ConfigurationError("No view factory specified.")
+
+    if permission:
+
+        checker = _checker(_context, permission,
+                           allowed_interface, allowed_attributes)
+
+        def proxyView(context, request, factory=factory[-1], checker=checker):
+            return Proxy(factory(context, request), checker)
+
+        factory[-1] = proxyView
+
+    actions=[
+        Action(
+            discriminator = ('view', for_, name, type, layer),
+            callable = checkingHandler,
+            args = (permission, 'Views','provideView', for_, name,
+                    type, factory, layer),
+            ),
+        Action(
+            discriminator = None,
+            callable = handler,
+            args = ('Interfaces', 'provideInterface',
+                    type.__module__+'.'+type.__name__, type)
+            )
+            ]
+    if for_ is not None:
+        actions.append
+        (
+        Action(
+            discriminator = None,
+            callable = handler,
+            args = ('Interfaces', 'provideInterface',
+                    for_.__module__+'.'+for_.__name__,
+                    for_)
+              )
+         )
+
+    return actions
+
+def defaultView(_context, type, name, for_=None, **__kw):
+
+    if __kw:
+        actions = view(_context, type=type, name=name, for_=for_, **__kw)
+    else:
+        actions = []
+
+    if for_ is not None:
+        for_ = _context.resolve(for_)
+    type = _context.resolve(type)
+
+    actions += [
+        Action(
+        discriminator = ('defaultViewName', for_, type, name),
+        callable = handler,
+        args = ('Views','setDefaultViewName', for_, type, name),
+        ),
+        Action(
+            discriminator = None,
+            callable = handler,
+            args = ('Interfaces', 'provideInterface',
+                    type.__module__+'.'+type.__name__, type)
+            )
+               ]
+    if for_ is not None:
+        actions.append
+        (
+        Action(
+            discriminator = None,
+            callable = handler,
+            args = ('Interfaces', 'provideInterface',
+                    for_.__module__+'.'+for_.__name__, for_)
+              )
+         )
+
+    return actions
+
+def serviceType(_context, id, interface):
+    interface = _context.resolve(interface)
+    return [
+        Action(
+            discriminator = ('serviceType', id),
+            callable = managerHandler,
+            args = ('defineService', id, interface),
+            ),
+        Action(
+            discriminator = None,
+            callable = provideInterface,
+            args = (interface.__module__+'.'+interface.__name__,
+                    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.
+
+    service_manager = getServiceManager(None)
+
+    if permission:
+
+        for stype, interface in service_manager.getServiceDefinitions():
+            if stype == serviceType:
+                break
+        else:
+            raise UndefinedService(serviceType)
+
+        if permission == 'zope.Public':
+            permission = CheckerPublic
+
+        checker = InterfaceChecker(interface, permission)
+
+        try:
+            component.__Security_checker__ = checker
+        except: # too bad exceptions aren't more predictable
+            component = Proxy(component, checker)
+
+    service_manager.provideService(serviceType, component)
+
+def service(_context, serviceType, component=None, permission=None,
+            factory=None):
+    if factory:
+        if component:
+            raise TypeError("Can't specify factory and component.")
+
+        component = _context.resolve(factory)()
+    else:
+        component = _context.resolve(component)
+
+    return [
+        Action(
+            discriminator = ('service', serviceType),
+            callable = provideService,
+            args = (serviceType, component, permission),
+            )
+        ]
+
+def skin(_context, name, layers, type):
+    type = _context.resolve(type)
+    if ',' in layers:
+        raise TypeError("Commas are not allowed in layer names.")
+
+    layers = layers.strip().split()
+    actions = [
+        Action(
+            discriminator = ('skin', name, type),
+            callable = handler,
+            args = ('Skins','defineSkin',name, type, layers)
+              ),
+        Action(
+            discriminator = None,
+            callable = handler,
+            args = ('Interfaces', 'provideInterface',
+                    type.__module__+'.'+type.__name__, type)
+              )
+             ]
+    return actions


=== Zope3/src/zope/app/component/nextservice.py 1.1 => 1.2 ===
--- /dev/null	Wed Dec 25 09:13:47 2002
+++ Zope3/src/zope/app/component/nextservice.py	Wed Dec 25 09:12:45 2002
@@ -0,0 +1,78 @@
+##############################################################################
+#
+# Copyright (c) 2002 Zope Corporation and Contributors.
+# All Rights Reserved.
+#
+# This software is subject to the provisions of the Zope Public License,
+# Version 2.0 (ZPL).  A copy of the ZPL should accompany this distribution.
+# THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED
+# WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+# WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS
+# FOR A PARTICULAR PURPOSE.
+#
+##############################################################################
+"""Support for delegation among service managers
+
+$Id$
+"""
+
+from zope.component.exceptions import ComponentLookupError
+from zope.component.service import serviceManager
+from zope.proxy.context import getWrapperContainer
+from zope.proxy.introspection import removeAllProxies
+from zope.app.interfaces.services.service import IServiceManagerContainer
+from zope.app.component.hooks import getServiceManager_hook
+
+# placeful service manager convenience tools
+
+def queryNextServiceManager(context, default=None):
+    try:
+        return getNextServiceManager(context)
+    except ComponentLookupError:
+        return default
+
+def getNextService(context, name):
+    service = queryNextService(context, name)
+    if service is None:
+        raise ComponentLookupError('service', name)
+    return service
+
+def queryNextService(context, name, default=None):
+    try:
+        sm = getNextServiceManager(context)
+    except ComponentLookupError:
+        return default
+    return sm.queryService(name, default)
+
+def getNextServiceManager(context):
+    """if the context is a service manager or a placeful service, tries
+    to return the next highest service manager"""
+
+    # IMPORTANT
+    #
+    # This is not allowed to use any services to get it's job done!
+
+    # get this service manager
+    sm = getServiceManager_hook(context)
+    if sm is serviceManager:
+        raise ComponentLookupError('service manager')
+
+    # get the service manager container, which ought to be the context
+    # contaioner.
+    container = getWrapperContainer(sm)
+
+    # But we're *really* paranoid, so we'll double check.
+    while ((container is not None) and not
+           IServiceManagerContainer.isImplementedBy(
+                      removeAllProxies(container))
+           ):
+        container = getWrapperContainer(container) # we should be
+
+    # Now we need to step up so we can look for a service manager above.
+    context = getWrapperContainer(container)
+
+    # But we have to make sure we haven't got the same object..
+    while (context is not None) and (context == container):
+        context = getWrapperContainer(context)
+
+    return getServiceManager_hook(context)