[Zope3-checkins] CVS: Zope3/lib/python/Zope/App/OFS/Services/ServiceManager - ConfigurationManager.py:1.2 IConfigurationManager.py:1.2 IServiceConfiguration.py:1.2 ServiceConfiguration.py:1.2 INameResolver.py:1.2 IBindingAware.py:1.5 IServiceManager.py:1.5 ServiceManager.py:1.10 configure.zcml:1.7 IServiceDirective.py:NONE ServiceDirective.py:NONE

Jim Fulton jim@zope.com
Sat, 30 Nov 2002 13:39:47 -0500


Update of /cvs-repository/Zope3/lib/python/Zope/App/OFS/Services/ServiceManager
In directory cvs.zope.org:/tmp/cvs-serv12171/lib/python/Zope/App/OFS/Services/ServiceManager

Modified Files:
	IBindingAware.py IServiceManager.py ServiceManager.py 
	configure.zcml 
Added Files:
	ConfigurationManager.py IConfigurationManager.py 
	IServiceConfiguration.py ServiceConfiguration.py 
	INameResolver.py 
Removed Files:
	IServiceDirective.py ServiceDirective.py 
Log Message:
- Updated to use new configuration framework.

- Updated PlacefulSetup to register the standard traversal adapters
  and views during setup.

- Service managers now support hierarchical module lookup.




=== Zope3/lib/python/Zope/App/OFS/Services/ServiceManager/ConfigurationManager.py 1.1 => 1.2 ===
--- /dev/null	Sat Nov 30 13:39:47 2002
+++ Zope3/lib/python/Zope/App/OFS/Services/ServiceManager/ConfigurationManager.py	Sat Nov 30 13:39:16 2002
@@ -0,0 +1,140 @@
+##############################################################################
+#
+# 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.
+# 
+##############################################################################
+"""
+$Id$
+"""
+
+__metaclass__ = type
+
+from Persistence import Persistent
+from IConfigurationManager import IConfigurationManager
+
+class ConfigurationManager(Persistent):
+    """Configuration manager
+
+    Manages configurations within a package.
+    """
+    
+    __implements__ = IConfigurationManager
+
+    def __init__(self):
+        self._data = ()
+        self._next = 0
+
+    def __getitem__(self, key):
+        "See Zope.App.OFS.Container.IContainer.IItemContainer"
+        v = self.get(key)
+        if v is None:
+            raise KeyError, key
+        return v
+
+    def get(self, key, default=None):
+        "See Interface.Common.Mapping.IReadMapping"
+        for k, v in self._data:
+            if k == key:
+                return v
+        return default
+
+    def __contains__(self, key):
+        "See Interface.Common.Mapping.IReadMapping"
+        return self.get(key) is not None
+    
+
+    def keys(self):
+        "See Interface.Common.Mapping.IEnumerableMapping"
+        return [k for k, v in self._data]
+
+    def values(self):
+        "See Interface.Common.Mapping.IEnumerableMapping"
+        return [v for k, v in self._data]
+    
+    def items(self):
+        "See Interface.Common.Mapping.IEnumerableMapping"
+        return self._data
+
+    def __len__(self):
+        "See Interface.Common.Mapping.IEnumerableMapping"
+        return len(self._data)
+
+    def setObject(self, key, object):
+        "See Zope.App.OFS.Container.IContainer.IWriteContainer"
+        self._next += 1
+        key = str(self._next)
+        self._data += ((key, object), )
+        return key
+        
+    def __delitem__(self, key):
+        "See Zope.App.OFS.Container.IContainer.IWriteContainer"
+        if key not in self:
+            raise KeyError, key
+        self._data = tuple(
+            [item
+             for item in self._data
+             if item[0] != key]
+            )
+
+    def moveTop(self, names):
+        self._data = tuple(
+            [item for item in self._data if (item[0] in names)]
+            +
+            [item for item in self._data if (item[0] not in names)]
+            )
+
+    def moveBottom(self, names):
+        self._data = tuple(
+            [item for item in self._data if (item[0] not in names)]
+            +
+            [item for item in self._data if (item[0] in names)]
+            )
+
+    def _moveUpOrDown(self, names, direction):
+        # Move each named item by one position. Note that this
+        # might require moving some unnamed objects by more than
+        # one position.
+
+        indexes = {}
+
+        # Copy named items to positions one less than they currently have
+        i = -1
+        for item in self._data:
+            i += 1
+            if item[0] in names:
+                j = max(i + direction, 0)
+                while j in indexes:
+                    j += 1
+                
+                indexes[j] = item
+
+        # Fill in the rest where there's room.
+        i = 0
+        for item in self._data:
+            if item[0] not in names:
+                while i in indexes:
+                    i += 1
+                indexes[i] = item
+
+        items = indexes.items()
+        items.sort()
+
+        self._data = tuple([item[1] for item in items])
+
+    def moveUp(self, names):
+        self._moveUpOrDown(names, -1)
+
+    def moveDown(self, names):
+        self._moveUpOrDown(names, 1)
+        
+
+
+__doc__ = ConfigurationManager.__doc__  + __doc__


=== Zope3/lib/python/Zope/App/OFS/Services/ServiceManager/IConfigurationManager.py 1.1 => 1.2 ===
--- /dev/null	Sat Nov 30 13:39:47 2002
+++ Zope3/lib/python/Zope/App/OFS/Services/ServiceManager/IConfigurationManager.py	Sat Nov 30 13:39:16 2002
@@ -0,0 +1,41 @@
+##############################################################################
+#
+# 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.
+# 
+##############################################################################
+"""
+$Id$
+"""
+
+from Zope.App.OFS.Container.IContainer  import IContainerNamesContainer
+
+class IConfigurationManager(IContainerNamesContainer):
+    """Manage Configuration Directives
+    """
+
+    def moveTop(names):
+        """Move the objects corresponding to the given names to the top
+        """
+
+    def moveUp(names):
+        """Move the objects corresponding to the given names up
+        """
+
+    def moveBottom(names):
+        """Move the objects corresponding to the given names to the bottom
+        """
+
+    def moveDown(names):
+        """Move the objects corresponding to the given names down
+        """
+
+__doc__ = IConfigurationManager.__doc__ + __doc__
+


=== Zope3/lib/python/Zope/App/OFS/Services/ServiceManager/IServiceConfiguration.py 1.1 => 1.2 ===
--- /dev/null	Sat Nov 30 13:39:47 2002
+++ Zope3/lib/python/Zope/App/OFS/Services/ServiceManager/IServiceConfiguration.py	Sat Nov 30 13:39:16 2002
@@ -0,0 +1,38 @@
+##############################################################################
+#
+# 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.
+# 
+##############################################################################
+"""
+$Id$
+"""
+
+from Interface.Attribute import Attribute
+from Zope.App.OFS.Services.ConfigurationInterfaces import IConfiguration
+
+class IServiceConfiguration(IConfiguration):
+    """Service Configuration
+
+    Service configurations are dependent on the components that they
+    configure. They register themselves as component dependents.
+    
+    """
+
+    serviceType = Attribute("The service type id")
+
+    componentPath = Attribute("The physical path to the component")
+
+    def getService(service_manager):
+        """Return the service component named in the directive.
+        """
+
+__doc__ = IServiceConfiguration.__doc__ + __doc__
+


=== Zope3/lib/python/Zope/App/OFS/Services/ServiceManager/ServiceConfiguration.py 1.1 => 1.2 ===
--- /dev/null	Sat Nov 30 13:39:47 2002
+++ Zope3/lib/python/Zope/App/OFS/Services/ServiceManager/ServiceConfiguration.py	Sat Nov 30 13:39:16 2002
@@ -0,0 +1,150 @@
+##############################################################################
+#
+# 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.
+# 
+##############################################################################
+"""
+$Id$
+"""
+
+__metaclass__ = type
+
+from Persistence import Persistent
+from Zope.Security.Checker import CheckerPublic, InterfaceChecker
+from Zope.Security.Proxy import Proxy
+from Zope.App.DependencyFramework.Exceptions import DependencyError
+from Zope.App.Traversing import traverse
+from IServiceConfiguration import IServiceConfiguration
+from Zope.Proxy.ProxyIntrospection import removeAllProxies
+from Zope.App.Traversing import getPhysicalRoot
+from Zope.ComponentArchitecture import getService, getServiceManager
+from Zope.App.Traversing import getPhysicalPathString
+from ServiceManager import ServiceManager
+from Zope.App.OFS.Container.IAddNotifiable import IAddNotifiable
+from Zope.App.OFS.Container.IDeleteNotifiable import IDeleteNotifiable
+from Zope.App.DependencyFramework.IDependable import IDependable
+from Zope.ComponentArchitecture import getServiceManager, getAdapter
+from Zope.ContextWrapper import ContextMethod
+from Zope.App.OFS.Services.Configuration import ConfigurationStatusProperty
+from Zope.ContextWrapper import ContextProperty
+from IBindingAware import IBindingAware
+from Zope.App.OFS.Services.ConfigurationInterfaces import Active
+from Zope.App.OFS.Services.ConfigurationInterfaces import Registered
+from Zope.App.OFS.Services.ConfigurationInterfaces import Unregistered
+
+class ServiceConfiguration(Persistent):
+    __doc__ = IServiceConfiguration.__doc__
+    
+    __implements__ = IServiceConfiguration, IAddNotifiable, IDeleteNotifiable
+
+    status = ConfigurationStatusProperty('Services')
+
+    def __init__(self, service_type, component_path, permission=None):
+        self.serviceType = service_type
+        self.componentPath = component_path
+        if permission == 'Zope.Public':
+            permission = CheckerPublic
+            
+        self.permission = permission
+
+    def __repr__(self):
+        return "service(%s, %s)" % (self.serviceType, self.componentPath)
+
+    ############################################################
+    # Implementation methods for interface
+    # Zope.App.OFS.Services.ServiceManager.IServiceConfiguration.
+
+    def getService(self):
+        service_manager = getServiceManager(self)
+        
+        service = getattr(self, '_v_service', None)
+        if service is None:
+            
+            # We have to be clever here. We need to do an honest to
+            # god unrestricted traveral, which means we have to
+            # traverse from an unproxies object. But, it's not enough
+            # for the service manager to be unproxies, because the
+            # path is an absolute path. When absolute paths are
+            # traversed, the traverser finds the physical root and
+            # traverses from there, so we need to make sure the
+            # physical root isn;t proxied.
+
+            # get the root and unproxy it.
+            root = removeAllProxies(getPhysicalRoot(service_manager))            
+            service = traverse(root, self.componentPath)
+
+            if self.permission:
+                if type(service) is Proxy:
+                    # XXX what is this?
+                    service = removeSecurityProxy(service)
+
+                interface = service_manager.getInterfaceFor(self.serviceType)
+
+                checker = InterfaceChecker(interface, self.permission)
+
+                service = Proxy(service, checker)
+
+            
+            self._v_service = service
+
+
+        return service
+
+    getService.__doc__ = IServiceConfiguration['getService'].__doc__
+
+    getService = ContextMethod(getService)
+
+    ############################################################
+
+    def activated(self):
+        service = self.getService()
+        if IBindingAware.isImplementedBy(service):
+            service.bound(self.serviceType)
+
+    activated = ContextMethod(activated)
+
+    def deactivated(self):
+        service = self.getService()
+        if IBindingAware.isImplementedBy(service):
+            service.unbound(self.serviceType)
+
+    deactivated = ContextMethod(deactivated)
+
+    def manage_afterAdd(self, configuration, container):
+        "See Zope.App.OFS.Container.IAddNotifiable"
+        sm = getServiceManager(configuration)
+        service = configuration.getService()
+        dependents = getAdapter(service, IDependable)
+        objectpath = getPhysicalPathString(configuration)
+        dependents.addDependent(objectpath)
+        
+    def manage_beforeDelete(self, configuration, container):
+        "See Zope.App.OFS.Container.IDeleteNotifiable"
+        assert self == configuration
+        service_type = self.serviceType
+        sm = getServiceManager(self)
+        service = self.getService()
+        objectstatus = self.status
+        dependents = getAdapter(service, IDependable)
+        objectpath = getPhysicalPathString(self)
+        
+        if objectstatus == Active:
+            raise DependencyError("Can't delete active configurations")
+        elif objectstatus == Registered:
+            self.status = Unregistered
+
+        dependents.removeDependent(objectpath)
+
+    manage_beforeDelete = ContextMethod(manage_beforeDelete)
+    
+__doc__ = ServiceConfiguration.__doc__  + __doc__
+
+            


=== Zope3/lib/python/Zope/App/OFS/Services/ServiceManager/INameResolver.py 1.1 => 1.2 ===
--- /dev/null	Sat Nov 30 13:39:47 2002
+++ Zope3/lib/python/Zope/App/OFS/Services/ServiceManager/INameResolver.py	Sat Nov 30 13:39:17 2002
@@ -0,0 +1,31 @@
+##############################################################################
+#
+# 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.
+# 
+##############################################################################
+"""
+$Id$
+"""
+
+from Interface import Interface
+
+class INameResolver(Interface):
+    """Objects that can resolve dotted names to objects
+    """
+
+    def resolve(dotted_name):
+        """Resolve the given dotted name to a module global variable.
+
+        If the name ends with a trailing dot, the last name segment
+        may be repeated.
+        """
+
+__doc__ = INameResolver.__doc__ + __doc__


=== Zope3/lib/python/Zope/App/OFS/Services/ServiceManager/IBindingAware.py 1.4 => 1.5 ===
--- Zope3/lib/python/Zope/App/OFS/Services/ServiceManager/IBindingAware.py:1.4	Mon Nov 11 03:36:08 2002
+++ Zope3/lib/python/Zope/App/OFS/Services/ServiceManager/IBindingAware.py	Sat Nov 30 13:39:16 2002
@@ -22,14 +22,14 @@
 class IBindingAware(Interface):
     
     def bound(name):
-        """
+        """Inform a service components that it's providing a service
 
         Called when an immediately-containing service manager binds
         this object to perform the named service.
         """
     
     def unbound(name):
-        """
+        """Inform a service components that it's no longer providing a service
 
         Called when an immediately-containing service manager unbinds
         this object from performing the named service.


=== Zope3/lib/python/Zope/App/OFS/Services/ServiceManager/IServiceManager.py 1.4 => 1.5 ===
--- Zope3/lib/python/Zope/App/OFS/Services/ServiceManager/IServiceManager.py:1.4	Thu Jul 11 14:21:32 2002
+++ Zope3/lib/python/Zope/App/OFS/Services/ServiceManager/IServiceManager.py	Sat Nov 30 13:39:16 2002
@@ -16,12 +16,11 @@
 $Id$
 """
 from Zope.ComponentArchitecture.IServiceService import IServiceService
-
+from Zope.App.OFS.Services.ConfigurationInterfaces import IConfigurable
 from IComponentManager import IComponentManager
-
 from Interface.Attribute import Attribute
 
-class IServiceManager(IServiceService, IComponentManager):
+class IServiceManager(IServiceService, IComponentManager, IConfigurable):
     """Service Managers act as containers for Services.
     
     If a Service Manager is asked for a service, it checks for those it
@@ -33,39 +32,12 @@
 
     Packages = Attribute("""Package container""")
     
-
-    def bindService(service_directive):
-        """Provide a service implementation.
-
-        If the named object implements IBindingAware, the wrapped object is
-        notified as per that interface.
+    def queryConfigurations(service_type):
+        """Return an IConfigurationRegistry for a service type
         """
 
-    def addService(service_directive):
-        """Add a registered service, but displace another active component
-
-        Register a service component, but don't make it active of
-        there is already a registered component providing the service.
-
-        """
-
-    def unbindService(service_directive):
-        """No longer provide a service implementation.
-
-        If the named object implements IBindingAware, the wrapped object is
-        notified as per that interface.
-        """
-
-    def disableService(service_type):
-        """Make the service type inactive in this service manager.
-
-        This doesn't unbind any services, but makes them all inactive.
-        """
-
-    def enableService(service_type, index):
-        """Make the service type inactive in this service manager.
-
-        This doesn't unbind any services, but makes them all inactive.
+    def createConfigurationsFor(configuration):
+        """Create and return an IConfigurationRegistry a service type
         """
 
     def getBoundService(name):
@@ -73,11 +45,10 @@
 
         Get the component currently bound to the named Service in this
         ServiceService.   Does not search context.
-        """
 
-    def getDirectives(service_type):
-        """Get the directives registered for a service
+        None is returned if the named service isn't bound locally.
         """
 
     def getBoundServiceTypes():
         """Get a sequence of the bound service types"""
+


=== Zope3/lib/python/Zope/App/OFS/Services/ServiceManager/ServiceManager.py 1.9 => 1.10 ===
--- Zope3/lib/python/Zope/App/OFS/Services/ServiceManager/ServiceManager.py:1.9	Tue Nov 19 14:10:07 2002
+++ Zope3/lib/python/Zope/App/OFS/Services/ServiceManager/ServiceManager.py	Sat Nov 30 13:39:17 2002
@@ -20,6 +20,8 @@
 $Id$
 """
 
+import sys
+
 from Zope.Exceptions import NotFoundError, ZopeError
 
 from Zope.App.ComponentArchitecture.IServiceManagerContainer \
@@ -38,29 +40,34 @@
 from Zope.App.OFS.Container.BTreeContainer import BTreeContainer
 from Zope.Proxy.ProxyIntrospection import removeAllProxies
 
-from IBindingAware import IBindingAware
 from Packages import Packages
-from Package import Package
 from IServiceManager import IServiceManager
 
+from Zope.App.OFS.Services.Configuration import ConfigurationRegistry
+
 from Persistence.Module import PersistentModuleRegistry
+from Persistence.Module import PersistentModuleRegistry, PersistentModule
+from INameResolver import INameResolver
+
+ModuleType = type(INameResolver)
+ModuleType = ModuleType, PersistentModule
+
 
 class ServiceManager(PersistentModuleRegistry):
 
     __implements__ = (IServiceManager, ISimpleReadContainer,
-                      PersistentModuleRegistry.__implements__)
+                      PersistentModuleRegistry.__implements__,
+                      INameResolver)
 
     def __init__(self):
         super(ServiceManager, self).__init__()
+
         self.__bindings = {}
         # Bindings is of the form:
         #
-        # {service_type -> [directives]}
-        #
-        # Where the first directive is always the active directive.
+        # {service_type -> ConfigurationRegistry}
 
         self.Packages = Packages()
-        self.Packages.setObject('default', Package())
 
 
     def getServiceDefinitions(self):
@@ -88,31 +95,32 @@
 
     def getService(self, name):
         "See Zope.ComponentArchitecture.IServiceService.IServiceService"
-        
-        service = self.__bindings.get(name)
 
-        if service:
-            service = service[0] # Get the active service directive
-            if service is not None: # not disabled
-                service = service.getService(self) # get the service
-                return service
+        # This is rather tricky. Normally, getting a service requires
+        # the use of other services, like the adapter service.  We
+        # need to be careful not to get into an infinate recursion by
+        # getting out getService to be called while looking up
+        # services, so we'll
+
+        if name == 'Services':
+            return self # We are the service service
+
+        if not getattr(self, '_v_calling', 0):
+            
+            self._v_calling = 1
+            try:
+                service = self.getBoundService(name)
+                if service:
+                    return service
+                    
+            finally:
+                self._v_calling = 0
 
         return getNextService(self, name)
 
     getService = ContextMethod(getService)
 
 
-    def getBoundService(self, name):
-        "See Zope.App.OFS.Services.ServiceManager.IServiceManager."
-
-        service = self.__bindings.get(name)
-        if service:
-            service = service[0] # Get the active service directive
-            service = service.getService(self) # get the service
-            return service
-
-        return None
-
     def getInterfaceFor(self, service_type):
         "See Zope.ComponentArchitecture.IServiceService.IServiceService"
         for type, interface in self.getServiceDefinitions():
@@ -123,141 +131,50 @@
 
     getInterfaceFor = ContextMethod(getInterfaceFor)
 
-    def disableService(self, service_type):
-        "See Zope.App.OFS.Services.ServiceManager.IServiceManager."
-        directives = self.__bindings.get(service_type)
-        if directives and directives[0] is not None:
-            service = directives[0].getService(self)
-            aware_service = queryAdapter(service, IBindingAware)
-            if aware_service is not None:
-                aware_service.unbound(service_type)
-            directives.insert(0, None)
-            self._p_changed = 1
-    
-    disableService = ContextMethod(disableService)
-
-    def enableService(self, service_type, index):
-        "See Zope.App.OFS.Services.ServiceManager.IServiceManager."
-        self._disableFirstBeforeEnable(service_type)
-
-        directives = self.__bindings.get(service_type)
-        directive = directives[index]
-        del directives[index]
-        directives.insert(0, directive)
+    def queryConfigurationsFor(self, configuration, default=None):
+        return self.queryConfigurations(configuration.serviceType, default)
 
-        self._p_changed = 1
-
-        service = directive.getService(self)
-        aware_service = queryAdapter(service, IBindingAware)
-        if aware_service is not None:
-            aware_service.bound(service_type)
-    
-    enableService = ContextMethod(enableService)
-
-
-    def _disableFirstBeforeEnable(self, service_type):
-        # Disable the first (active) service or remove the
-        # disabled marker prior to enabling a service.
-        directives = self.__bindings.get(service_type)
-
-        if directives:
-            if directives[0] is None:
-                # remove deactivation marker
-                del directives[0]
-            else:
-                
-                old_service = queryAdapter(
-                    directives[0].getService(self), IBindingAware)
-                if old_service is not None:
-                    # unbind old service, if necessary
-                    old_service.unbound(service_type)
-    
-    _disableFirstBeforeEnable = ContextMethod(
-        _disableFirstBeforeEnable)
+    queryConfigurationsFor = ContextMethod(queryConfigurationsFor)
 
-    def bindService(self, directive):
-        "See "
-        "Zope.App.OFS.Services.ServiceManager.IServiceManager.IServiceManager"
-        service = directive.getService(self)
-        service_type = directive.service_type
+    def queryConfigurations(self, service_type, default=None):
+        registry = self.__bindings.get(service_type, default)
+        return ContextWrapper(registry, self)
 
-        interface = self.getInterfaceFor(service_type)
+    queryConfigurations = ContextMethod(queryConfigurations)
         
-        if not interface.isImplementedBy(service):
-            raise InvalidService(service_type, directive, interface)
 
-        self._disableFirstBeforeEnable(service_type)
+    def createConfigurationsFor(self, configuration):
+        return self.createConfigurations(configuration.serviceType)
 
-        bindings = self.__bindings
-        if service_type not in bindings:
-            bindings[service_type] = [directive]
-        else:
-            directives = bindings[service_type]
-            directives.insert(0, directive)
+    createConfigurationsFor = ContextMethod(createConfigurationsFor)
 
+    def createConfigurations(self, service_type):
+        registry = ConfigurationRegistry()
+        self.__bindings[service_type] = registry
         self._p_changed = 1
-        
-        aware_service = queryAdapter(service, IBindingAware)
-        if aware_service is not None:
-            aware_service.bound(service_type)
-
-    bindService = ContextMethod(bindService)
-
-    def addService(self, directive):
-        "See "
-        "Zope.App.OFS.Services.ServiceManager.IServiceManager.IServiceManager"
-        service = directive.getService(self)
-        service_type = directive.service_type
-
-        interface = self.getInterfaceFor(service_type)
-        
-        if not interface.isImplementedBy(service):
-            raise InvalidService(service_type, directive, interface)
+        return registry
 
-        bindings = self.__bindings
-        if service_type not in bindings:
-            bindings[service_type] = []
-        bindings[service_type].append(directive)
+    createConfigurations = ContextMethod(createConfigurations)
 
-        self._p_changed = 1
-                
-        if len(bindings) == 1:
-            aware_service = queryAdapter(service, IBindingAware)
-            if aware_service is not None:
-                aware_service.bound(service_type)
-
-    addService = ContextMethod(addService)
-    
-    def unbindService(self, directive):
-        "See Zope.App.OFS.Services.ServiceManager.IServiceManager.IServiceManager"
-        service = directive.getService(self) # must be before unwrapping self
-        self = removeAllProxies(self)  
-        service_type = directive.service_type
-
-        directives = self.__bindings[service_type]
-        if directive not in directives:
-            raise KeyError(directive)
-        
-        aware_service = queryAdapter(service, IBindingAware)
-        if aware_service is not None:
-            aware_service.unbound(service_type)
+    def getBoundService(self, name):
+        "See Zope.App.OFS.Services.ServiceManager.IServiceManager."
 
-        self.__bindings[service_type] = [d for d in directives
-                                         if d != directive]
+        registry = self.queryConfigurations(name)
+        if registry:
+            configuration = registry.active()
+            if configuration is not None:
+                service = configuration.getService()
+                return service
+            
+        return None
 
-        self._p_changed = 1
-    
-    unbindService = ContextMethod(unbindService)
+    getBoundService = ContextMethod(getBoundService)
 
-    def getDirectives(self, service_type):
+    def getBoundServiceTypes(self):
         "See "
         "Zope.App.OFS.Services.ServiceManager.IServiceManager.IServiceManager"
-        return self.__bindings[service_type]
-
-    def getBoundServiceTypes(self):
-        "See Zope.App.OFS.Services.ServiceManager.IServiceManager.IServiceManager"
-        return  self.__bindings.keys()
         
+        return  self.__bindings.keys()
 
     ############################################################
     # Implementation methods for interface
@@ -306,7 +223,7 @@
 
     def findModule(self, name):
         # override to pass call up to next service manager 
-        mod = super(ServiceManager, self).findModule(name)
+        mod = super(ServiceManager, removeAllProxies(self)).findModule(name)
         if mod is not None:
             return mod
         
@@ -319,3 +236,50 @@
             # direct way to ask if sm is the global service manager.
             return None
         return findModule(name)
+
+    findModule = ContextMethod(findModule)
+
+    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
+
+    __import = ContextMethod(__import)
+
+    def resolve(self, name):
+        
+        name = name.strip()
+
+        if name.endswith('.') or name.endswith('+'):
+            name = name[:-1]
+            repeat = 1
+        else:
+            repeat = 0
+
+        names=name.split('.')
+        last=names[-1]
+        mod='.'.join(names[:-1])
+
+        if not mod:
+            return self.__import(name)
+
+        while 1:
+            m = self.__import(mod)
+            try:
+                a=getattr(m, last)
+            except AttributeError:
+                if not repeat:
+                    return self.__import(name)
+
+            else:
+                if not repeat or (not isinstance(a, ModuleType)):
+                    return a
+            mod += '.' + last
+
+    resolve = ContextMethod(resolve)
+


=== Zope3/lib/python/Zope/App/OFS/Services/ServiceManager/configure.zcml 1.6 => 1.7 ===
--- Zope3/lib/python/Zope/App/OFS/Services/ServiceManager/configure.zcml:1.6	Wed Oct  2 18:18:01 2002
+++ Zope3/lib/python/Zope/App/OFS/Services/ServiceManager/configure.zcml	Sat Nov 30 13:39:17 2002
@@ -10,6 +10,7 @@
     <require
         permission="Zope.ManageServices"
         interface="Zope.App.OFS.Services.ServiceManager.IServiceManager." />
+    <implements interface="Zope.App.OFS.Annotation.IAttributeAnnotatable." />
   </content>
 
   <content class=".Packages.">
@@ -22,6 +23,7 @@
     <require
         permission="Zope.ManageServices"
         interface=".IComponentManager." />
+
   </content>
 
   <content class=".Package.">
@@ -31,22 +33,52 @@
     <require
         permission="Zope.ManageServices"
         interface="Zope.App.OFS.Container.IContainer.IWriteContainer" />
+
+  </content>
+
+   <content class=".ConfigurationManager.">
+    <require
+        permission="Zope.View"
+        interface="Zope.App.OFS.Container.IContainer.IReadContainer" />
+    <require
+        permission="Zope.ManageServices"
+        interface="Zope.App.OFS.Container.IContainer.IWriteContainer" />
+    <require
+        permission="Zope.ManageServices"
+    	attributes="arrange_object remove_objects" />
+    <factory 
+        id = "Zope.App.OFS.Services.ServiceManager.ConfigurationManager" 
+	permission = "Zope.ManageServices"
+	title = "Configuration Manager" />
   </content>
 
   <content class=".Module.Manager.">
     <require 
         permission="Zope.ManageCode"
 	interface="Persistence.IPersistentModuleManager." />
+    <implements interface="Zope.App.OFS.Annotation.IAttributeAnnotatable." />
    </content>
 
-  <content class=".ServiceDirective.">
+
+  <content class=".ServiceConfiguration.">
     <require
         permission="Zope.ManageServices"
-        interface=".IServiceDirective." />
-  </content>
-
-
+        interface=".IServiceConfiguration."
+        set_attributes="serviceType componentPath"
+        set_schema=
+            "Zope.App.OFS.Services.ConfigurationInterfaces.IConfiguration"
+        />
+    <require
+        permission="Zope.ManageServices"
+        interface="Zope.App.OFS.Container.IAddNotifiable."
+        />
+    <require
+        permission="Zope.ManageServices"
+        interface="Zope.App.OFS.Container.IDeleteNotifiable."
+        />
 
-  <include package="Zope.App.OFS.Services.ServiceManager.Views" />
+  </content>
+  
+  <include package="Zope.App.OFS.Services.ServiceManager.Browser" />
 
 </zopeConfigure>

=== Removed File Zope3/lib/python/Zope/App/OFS/Services/ServiceManager/IServiceDirective.py ===

=== Removed File Zope3/lib/python/Zope/App/OFS/Services/ServiceManager/ServiceDirective.py ===