[Zope3-checkins] CVS: Zope3/src/zope/app/services - error.txt:1.1.2.1 factories.py:1.3.2.1 registration.py:1.1.2.1 utility.txt:1.1.2.1 README.txt:1.4.10.1 adapter.py:1.14.2.1 auth.py:1.15.10.1 cache.py:1.9.10.1 configure.zcml:1.29.2.1 connection.py:1.11.10.1 errorr.py:1.8.18.1 event.py:1.24.4.1 field.py:1.7.18.1 folder.py:1.6.10.1 hub.py:1.10.10.1 module.py:1.2.26.1 pagefolder.py:1.5.10.1 principalannotation.py:1.5.14.1 queryfield.py:1.2.22.1 role.py:1.4.18.1 service.py:1.18.10.1 servicecontainer.py:1.2.24.1 session.py:1.9.18.1 utility.py:1.6.10.1 utility.zcml:1.3.14.1 view.py:1.18.4.1 zpt.py:1.10.10.1 configuration.py:NONE

Grégoire Weber zope@i-con.ch
Sun, 22 Jun 2003 10:23:59 -0400


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

Modified Files:
      Tag: cw-mail-branch
	README.txt adapter.py auth.py cache.py configure.zcml 
	connection.py errorr.py event.py field.py folder.py hub.py 
	module.py pagefolder.py principalannotation.py queryfield.py 
	role.py service.py servicecontainer.py session.py utility.py 
	utility.zcml view.py zpt.py 
Added Files:
      Tag: cw-mail-branch
	error.txt factories.py registration.py utility.txt 
Removed Files:
      Tag: cw-mail-branch
	configuration.py 
Log Message:
Synced up with HEAD

=== Added File Zope3/src/zope/app/services/error.txt ===
Under construction.


=== Added File Zope3/src/zope/app/services/factories.py ===
##############################################################################
#
# Copyright (c) 2003 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.
#
##############################################################################
"""A collection of factory functions for various registration classes.

See method factory() in class ComponentRegistrationAdapter in file
registration.py.

The functions here may create invalid objects; a subsequent setBody()
call to the adapter's setBody() method will make the object valid.

$Id: factories.py,v 1.3.2.1 2003/06/22 14:23:27 gregweb Exp $
"""

def CacheRegistration():
    from zope.app.services.cache import CacheRegistration
    return CacheRegistration("", "") # name, componentPath

def ConnectionRegistration():
    from zope.app.services.connection import ConnectionRegistration
    return ConnectionRegistration("", "") # name, componentPath

def ServiceRegistration():
    from zope.app.services.service import ServiceRegistration
    return ServiceRegistration("", "") # name, componentPath

def UtilityRegistration():
    from zope.app.services.utility import UtilityRegistration
    return UtilityRegistration("", None, "") # name, interface, componentPath


=== Added File Zope3/src/zope/app/services/registration.py ===
##############################################################################
#
# 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.
#
##############################################################################
"""Component registration support for services

$Id: registration.py,v 1.1.2.1 2003/06/22 14:23:27 gregweb Exp $
"""
__metaclass__ = type



from persistence import Persistent
from zope.interface import implements
from zope.app.interfaces.annotation import IAnnotations
from zope.app.interfaces.annotation import IAttributeAnnotatable
from zope.app.interfaces.container import IAddNotifiable, IDeleteNotifiable
from zope.app.interfaces.container import IZopeWriteContainer
from zope.app.interfaces.dependable import IDependable, DependencyError

from zope.app.interfaces.services.registration import IRegistrationManager
from zope.app.interfaces.services.registration import IRegistrationStack
from zope.app.interfaces.services.registration \
     import INameComponentRegistry
from zope.app.interfaces.services.registration import INamedRegistration
from zope.app.interfaces.services.registration import IRegistration
from zope.app.interfaces.services.registration \
     import INamedComponentRegistration
from zope.app.interfaces.services.registration import INameRegistry
from zope.app.interfaces.services.registration \
     import INamedComponentRegistration, IComponentRegistration
from zope.app.interfaces.services.registration import IRegistered
from zope.app.interfaces.services.registration \
     import NoRegistrationManagerError
from zope.app.interfaces.services.registration import NoLocalServiceError

from zope.app.interfaces.services.registration import UnregisteredStatus
from zope.app.interfaces.services.registration import ActiveStatus
from zope.app.interfaces.services.registration import RegisteredStatus
from zope.app.traversing import getRoot, getPath, traverse
from zope.component import getAdapter, queryAdapter
from zope.component import getServiceManager
from zope.app.context import ContextWrapper
from zope.context import ContextMethod, ContextDescriptor, getWrapperContainer
from zope.proxy import removeAllProxies
from zope.security.checker import InterfaceChecker
from zope.security.proxy import Proxy, trustedRemoveSecurityProxy
from zope.proxy import getProxiedObject

class RegistrationStatusProperty(ContextDescriptor):

    def __get__(self, inst, klass):
        if inst is None:
            return self

        registration = inst

        sm = getServiceManager(registration)
        service = sm.queryLocalService(registration.serviceType)
        # XXX The following may fail; there's a subtle bug here when
        # the returned service isn't in the same service manager as
        # the one owning the registration.
        registry = service and service.queryRegistrationsFor(registration)

        if registry:

            if registry.active() == registration:
                return ActiveStatus
            if registry.registered(registration):
                return RegisteredStatus

        return UnregisteredStatus

    def __set__(self, inst, value):
        registration = inst

        sm = getServiceManager(registration)
        service = sm.queryLocalService(registration.serviceType)

        registry = service and service.queryRegistrationsFor(registration)

        if value == UnregisteredStatus:
            if registry:
                registry.unregister(registration)

        else:
            if not service:
                raise NoLocalServiceError(
                    "This registration change cannot be performed because "
                    "there isn't a corresponding %s service defined in this "
                    "site. To proceed, first add a local %s service."
                    % (registration.serviceType, registration.serviceType))

            if registry is None:
                registry = service.createRegistrationsFor(registration)

            if value == RegisteredStatus:
                if registry.active() == registration:
                    registry.deactivate(registration)
                else:
                    registry.register(registration)

            elif value == ActiveStatus:
                if not registry.registered(registration):
                    registry.register(registration)
                registry.activate(registration)


class RegistrationStack(Persistent):

    """Registration registry implementation.

    The invariants for _data are as follows:

        (1) The last element (if any) is not None

        (2) No value occurs more than once

        (3) Each value except None is a relative path from the nearest
            service manager to an object implementing IRegistration
    """

    implements(IRegistrationStack)

    _data = ()

    def _id(self, ob):

        # Get and check relative path
        path = getPath(ob)
        prefix = "/++etc++site/"
        lpackages = path.rfind(prefix)
        if lpackages < 0:
            # XXX Backward compatability
            prefix = "/++etc++Services/"
            lpackages = path.rfind(prefix)

        if lpackages < 0:
            raise ValueError("Registration object is in an invalid location",
                             path)

        rpath = path[lpackages+len(prefix):]
        if not rpath or (".." in rpath.split("/")):
            raise ValueError("Registration object is in an invalid location",
                             path)

        return rpath

    def register(wrapped_self, registration):
        cid = wrapped_self._id(registration)

        if wrapped_self._data:
            if cid in wrapped_self._data:
                return # already registered
        else:
            # Nothing registered. Need to stick None in front so that nothing
            # is active.
            wrapped_self._data = (None, )

        wrapped_self._data += (cid, )
    register = ContextMethod(register)

    def unregister(wrapped_self, registration):
        cid = wrapped_self._id(registration)

        data = wrapped_self._data
        if data:
            if data[0] == cid:
                # Tell it that it is no longer active
                registration.deactivated()

            # Remove it from our data
            data = tuple([item for item in data if item != cid])

            # Check for trailing None
            if data and data[-1] is None:
                data = data[:-1]

            if data and data[0] is not None:
                # Activate the newly active component
                sm = getServiceManager(wrapped_self)
                new = traverse(sm, data[0])
                new.activated()

            # Write data back
            wrapped_self._data = data
    unregister = ContextMethod(unregister)

    def registered(wrapped_self, registration):
        cid = wrapped_self._id(registration)
        return cid in wrapped_self._data
    registered = ContextMethod(registered)

    def activate(wrapped_self, registration):
        if registration is None:
            cid = None
        else:
            cid = wrapped_self._id(registration)
        data = wrapped_self._data

        if cid is None and not data:
            return # already in the state we want

        if cid is None or cid in data:

            if data[0] == cid:
                return # already active

            if data[0] is not None:
                # Deactivate the currently active component
                sm = getServiceManager(wrapped_self)
                old = traverse(sm, data[0])
                old.deactivated()

            # Insert it in front, removing it from back
            data = (cid, ) + tuple([item for item in data if item != cid])

            # Check for trailing None
            if data[-1] == None:
                data = data[:-1]

            # Write data back
            wrapped_self._data = data

            if registration is not None:
                # Tell it that it is now active
                registration.activated()

        else:
            raise ValueError(
                "Registration to be activated is not registered",
                registration)
    activate = ContextMethod(activate)

    def deactivate(wrapped_self, registration):
        cid = wrapped_self._id(registration)
        data = wrapped_self._data

        if cid not in data:
            raise ValueError(
                "Registration to be deactivated is not registered",
                registration)

        if data[0] != cid:
            return # already inactive

        # Tell it that it is no longer active
        registration.deactivated()

        if None not in data:
            # Append None
            data += (None,)

        # Move it to the end
        data = data[1:] + data[:1]

        if data[0] is not None:
            # Activate the newly active component
            sm = getServiceManager(wrapped_self)
            new = traverse(sm, data[0])
            new.activated()

        # Write data back
        wrapped_self._data = data
    deactivate = ContextMethod(deactivate)

    def active(wrapped_self):
        if wrapped_self._data:
            path = wrapped_self._data[0]
            if path is not None:
                # Make sure we can traverse to it.
                sm = getServiceManager(wrapped_self)
                registration = traverse(sm, path)
                return registration

        return None
    active = ContextMethod(active)

    def __nonzero__(self):
        return bool(self._data)

    def info(wrapped_self, keep_dummy=False):
        sm = getServiceManager(wrapped_self)

        data = wrapped_self._data
        if not data and keep_dummy:
            data += (None,)

        result = [{'id': path or "",
                   'active': False,
                   'registration': (path and traverse(sm, path))
                  }
                  for path in data if path or keep_dummy
                 ]

        if keep_dummy or (result and result[0]['registration'] is not None):
            result[0]['active'] = True

        return result
    info = ContextMethod(info)


class SimpleRegistration(Persistent):
    """Registration objects that just contain registration data

    Classes that derive from this must make sure they implement
    IDeleteNotifiable either by implementing
    implementedBy(SimpleRegistration) or explicitly implementing
    IDeleteNotifiable.
    """

    implements(IRegistration, IDeleteNotifiable,
                      # We are including this here because we want all of the
                      # subclasses to get it and we don't really need to be
                      # flexible about the policy here. At least we don't
                      # *think* we do. :)
                      IAttributeAnnotatable,
                      )

    # Methods from IRegistration

    def activated(self):
        pass

    def deactivated(self):
        pass

    def usageSummary(self):
        return self.__class__.__name__

    def implementationSummary(self):
        return ""

    # Methods from IDeleteNotifiable

    def beforeDeleteHook(self, registration, container):
        "See IDeleteNotifiable"

        objectstatus = registration.status

        if objectstatus == ActiveStatus:
            try:
                objectpath = getPath(registration)
            except: # XXX
                objectpath = str(registration)
            raise DependencyError("Can't delete active registration (%s)"
                                  % objectpath)
        elif objectstatus == RegisteredStatus:
            registration.status = UnregisteredStatus


class NamedRegistration(SimpleRegistration):
    """Named registration
    """

    implements(INamedRegistration)

    def __init__(self, name):
        self.name = name

    def usageSummary(self):
        return "%s %s" % (self.name, self.__class__.__name__)


class ComponentRegistration(SimpleRegistration):
    """Component registration.

    Subclasses should define a getInterface() method returning the interface
    of the component.
    """

    # SimpleRegistration implements IDeleteNotifiable, so we don't need
    # it below.
    implements(IComponentRegistration, IAddNotifiable)

    def __init__(self, component_path, permission=None):
        self.componentPath = component_path
        if permission == 'zope.Public':
            permission = CheckerPublic
        self.permission = permission

    def implementationSummary(self):
        return self.componentPath

    def getComponent(wrapped_self):
        service_manager = getServiceManager(wrapped_self)

        # The user of the registration object may not have permission
        # to traverse to the component.  Yet they should be able to
        # get it by calling getComponent() on a registration object
        # for which they do have permission.  What they get will be
        # wrapped in a security proxy of course.  Hence:

        # We have to be clever here. We need to do an honest to
        # god unrestricted traveral, which means we have to
        # traverse from an unproxied object. But, it's not enough
        # for the service manager to be unproxied, 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.

        path = wrapped_self.componentPath
        # Get the root and unproxy it
        root = removeAllProxies(getRoot(service_manager))
        if path.startswith("/"):
            # Absolute path
            component = traverse(root, path)
        else:
            # Relative path.
            # XXX We do a strange little dance because we want the
            #     context to inherit the unproxied root, and this is
            #     the only way to keep it.
            ancestor = getWrapperContainer(getWrapperContainer(wrapped_self))
            ancestor = traverse(root, getPath(ancestor))
            component = traverse(ancestor, path)

        if wrapped_self.permission:
            if type(component) is Proxy:
                # There should be at most one security Proxy around an object.
                # So, if we're going to add a new security proxy, we need to
                # remove any existing one.
                component = trustedRemoveSecurityProxy(component)

            interface = wrapped_self.getInterface()

            checker = InterfaceChecker(interface, wrapped_self.permission)

            component = Proxy(component, checker)

        return component
    getComponent = ContextMethod(getComponent)

    def afterAddHook(self, registration, container):
        "See IAddNotifiable"
        component = registration.getComponent()
        dependents = getAdapter(component, IDependable)
        objectpath = getPath(registration)
        dependents.addDependent(objectpath)
        # Also update usage, if supported
        adapter = queryAdapter(component, IRegistered)
        if adapter is not None:
            adapter.addUsage(getPath(registration))

    def beforeDeleteHook(self, registration, container):
        "See IDeleteNotifiable"
        super(ComponentRegistration, self).beforeDeleteHook(registration,
                                                             container)
        component = registration.getComponent()
        dependents = getAdapter(component, IDependable)
        objectpath = getPath(registration)
        dependents.removeDependent(objectpath)
        # Also update usage, if supported
        adapter = queryAdapter(component, IRegistered)
        if adapter is not None:
            adapter.removeUsage(getPath(registration))

class NamedComponentRegistration(NamedRegistration, ComponentRegistration):
    """Registrations for named components.

    This configures components that live in folders, by name.
    """
    implements(INamedComponentRegistration)

    def __init__(self, name, component_path, permission=None):
        NamedRegistration.__init__(self, name)
        ComponentRegistration.__init__(self, component_path, permission)


class NameRegistry:
    """Mixin for implementing INameRegistry
    """
    implements(INameRegistry)

    def __init__(self, *args, **kw):
        self._bindings = {}
        super(NameRegistry, self).__init__(*args, **kw)

    def queryRegistrationsFor(wrapped_self, cfg, default=None):
        """See IRegistry"""
        return wrapped_self.queryRegistrations(cfg.name, default)
    queryRegistrationsFor = ContextMethod(queryRegistrationsFor)

    def queryRegistrations(wrapped_self, name, default=None):
        """See INameRegistry"""
        registry = wrapped_self._bindings.get(name, default)
        return ContextWrapper(registry, wrapped_self)
    queryRegistrations = ContextMethod(queryRegistrations)

    def createRegistrationsFor(wrapped_self, cfg):
        """See IRegistry"""
        return wrapped_self.createRegistrations(cfg.name)
    createRegistrationsFor = ContextMethod(createRegistrationsFor)

    def createRegistrations(wrapped_self, name):
        """See INameRegistry"""
        try:
            registry = wrapped_self._bindings[name]
        except KeyError:
            wrapped_self._bindings[name] = registry = RegistrationStack()
            wrapped_self._p_changed = 1
        return ContextWrapper(registry, wrapped_self)
    createRegistrations = ContextMethod(createRegistrations)

    def listRegistrationNames(wrapped_self):
        """See INameRegistry"""
        return filter(wrapped_self._bindings.get,
                      wrapped_self._bindings.keys())


class NameComponentRegistry(NameRegistry):
    """Mixin for implementing INameComponentRegistry
    """
    implements(INameComponentRegistry)

    def queryActiveComponent(wrapped_self, name, default=None):
        """See INameComponentRegistry"""
        registry = wrapped_self.queryRegistrations(name)
        if registry:
            registration = registry.active()
            if registration is not None:
                return registration.getComponent()
        return default
    queryActiveComponent = ContextMethod(queryActiveComponent)


from zope.app.dependable import PathSetAnnotation

class Registered(PathSetAnnotation):
    """An adapter from IRegisterable to IRegistered.

    This class is the only place that knows how 'Registered'
    data is represented.
    """

    implements(IRegistered)

    # We want to use this key:
    #   key = "zope.app.services.registration.Registered"
    # But we have existing annotations with the following key, so we'll keep
    # it. :( 
    key = "zope.app.services.configuration.UseConfiguration"

    addUsage = PathSetAnnotation.addPath
    removeUsage = PathSetAnnotation.removePath
    usages = PathSetAnnotation.getPaths


class RegistrationManager(Persistent):
    """Registration manager

    Manages registrations within a package.
    """

    implements(IRegistrationManager, IDeleteNotifiable)

    def __init__(self):
        self._data = ()
        self._next = 0

    def __getitem__(self, key):
        "See IItemContainer"
        v = self.get(key)
        if v is None:
            raise KeyError, key
        return v

    def get(self, key, default=None):
        "See IReadMapping"
        for k, v in self._data:
            if k == key:
                return v
        return default

    def __contains__(self, key):
        "See IReadMapping"
        return self.get(key) is not None


    def keys(self):
        "See IEnumerableMapping"
        return [k for k, v in self._data]

    def __iter__(self):
        return iter(self.keys())

    def values(self):
        "See IEnumerableMapping"
        return [v for k, v in self._data]

    def items(self):
        "See IEnumerableMapping"
        return self._data

    def __len__(self):
        "See IEnumerableMapping"
        return len(self._data)

    def setObject(self, key, object):
        "See IWriteContainer"
        self._next += 1
        if key:
            if key in self:
                raise DuplicationError("key is already registered", key)
            try:
                n = int(key)
            except ValueError:
                pass
            else:
                if n > self._next:
                    self._next = n
        else:
            key = str(self._next)
            while key in self:
                self._next += 1
                key = str(self._next)
        self._data += ((key, object), )
        return key

    def __delitem__(self, key):
        "See 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)

    def beforeDeleteHook(self, object, container):
        assert object == self
        container = getAdapter(object, IZopeWriteContainer)
        for k, v in self._data:
            del container[k]


class RegistrationManagerContainer(object):
    """Mix-in to implement IRegistrationManagerContainer
    """

    def __init__(self):
        super(RegistrationManagerContainer, self).__init__()
        self.setObject('RegistrationManager', RegistrationManager())

    def __delitem__(self, name):
        """Delete an item, but not if it's the last registration manager
        """
        item = self[name]
        if IRegistrationManager.isImplementedBy(item):
            # Check to make sure it's not the last one
            if len([i for i in self.values()
                    if IRegistrationManager.isImplementedBy(i)]) < 2:
                raise NoRegistrationManagerError(
                    "Can't delete the last registration manager")
        super(RegistrationManagerContainer, self).__delitem__(name)

    def getRegistrationManager(self):
        """Get a registration manager
        """
        # Get the registration manager for this folder
        for name in self:
            item = self[name]
            if IRegistrationManager.isImplementedBy(item):
                # We found one. Get it in context
                return ContextWrapper(item, self, name=name)
        else:
            raise NoRegistrationManagerError(
                "Couldn't find an registration manager")
    getRegistrationManager = ContextMethod(getRegistrationManager)


from zope.xmlpickle import dumps, loads
from zope.app.interfaces.fssync import IObjectFile
from zope.app.fssync.classes import ObjectEntryAdapter

class ComponentRegistrationAdapter(ObjectEntryAdapter):

    """Fssync adapter for ComponentRegistration objects and subclasses.

    This is fairly generic -- it should apply to most subclasses of
    ComponentRegistration.  But in order for it to work for a
    specific subclass (say, UtilityRegistration), you have to (a) add
    an entry to configure.zcml, like this:

        <fssync:adapter
            class=".utility.UtilityRegistration"
            factory=".registration.ComponentRegistrationAdapter"
            />

    and (b) add a function to factories.py, like this:

        def UtilityRegistration():
            from zope.app.services.utility import UtilityRegistration
            return UtilityRegistration("", None, "")

    The file representation of a registration object is an XML pickle
    for a modified version of the instance dict.  In this version of
    the instance dict, the __annotations__ attribute is omitted,
    because annotations are already stored on the filesystem in a
    different way (in @@Zope/Annotations/<file>).
    """

    implements(IObjectFile)

    def factory(self):
        """See IObjectEntry."""
        name = self.context.__class__.__name__
        return "zope.app.services.factories." + name

    def getBody(self):
        """See IObjectEntry."""
        obj = removeAllProxies(self.context)
        ivars = {}
        ivars.update(obj.__getstate__())
        aname = "__annotations__"
        if aname in ivars:
            del ivars[aname]
        return dumps(ivars)

    def setBody(self, body):
        """See IObjectEntry."""
        obj = removeAllProxies(self.context)
        ivars = loads(body)
        obj.__setstate__(ivars)



# XXX Pickle backward compatability
ConfigurationRegistry = RegistrationStack
ConfigurationManager = RegistrationManager
import sys
sys.modules['zope.app.services.registrationmanager'
            ] = sys.modules['zope.app.services.registration']
sys.modules['zope.app.services.configuration'
            ] = sys.modules['zope.app.services.registration']


=== Added File Zope3/src/zope/app/services/utility.txt ===
==================================================
Creating Local Services: The Local Utility Service
==================================================

:Author: Jim Fulton
:Version: $Revision: 1.1.2.1 $

.. contents::

This document describes how to implement a common type of local
service.  We'll walk through an example step by step.  We'll implement
a local utility service.  A utility service must implement the
interface ``zope.component.interfaces.IUtilityService``.

Step 1. Create a minimal service
--------------------------------

Create a minimal service that delagates everything to the
service above it, in the file ``utility.py``::

  from persistence import Persistent
  from zope.component.exceptions import ComponentLookupError
  from zope.context import ContextMethod
  from zope.app.component.nextservice import getNextService
  from zope.component.interfaces import IUtilityService
  from zope.app.interfaces.services.interfaces import ISimpleService
  from zope.interface import implements

  class LocalUtilityService(Persistent):

      implements(IUtilityService, ISimpleService)

      def getUtility(self, interface, name=''):
          utility = self.queryUtility(interface, name=name)
          if utility is None:
              raise ComponentLookupError("utility", interface, name)
          return utility
      getUtility = ContextMethod(getUtility)

      def queryUtility(self, interface, default=None, name=''):
          next = getNextService(self, "Utilities")
          return next.queryUtility(interface, default, name)
      queryUtility = ContextMethod(queryUtility)

The local service subclasses ``Persistent`` to provide support for
transparent persistent in the ZODB.

The local service uses the `ContextMethod`` function to convert it's
methods to be context methods.  Context methods are called with "self"
arguments that are context wrapped.  This is needed if the methods or
properties are going to call APIs that need acquisition context.

The ``getUtility`` method simply delegates to ``queryUtility``.  The
``queryUtility`` method delegates to the next utility service using
``getNextService``.  (Both methods are specified by the
``IUtilityService`` interface.)

The function ``getNextService`` looks up the next service above the
current service.  It takes a location and a service name.  We use it
to get the interface service defined above our service, which may be
the global service, and delegate to it.

In addition to implementing ``IUtilityService``, the local service
implements ``ISimpleService``.  A Local service must implement
``zope.app.interfaces.services.interfaces.ILocalService`` and a local
service must be annotatable.  ``ISimpleService`` simply extends
``ILocalService`` and ``IAttributeAnnotatable``.

I created the service in the ``utility`` module in this package (the
file ``utility.py``).  This package is already pretty large.  To avoid
a really large zcml file, I've started giving each service its own
zcml file.  So I also created an ``utility.zcml`` file::

  <zopeConfigure xmlns="http://namespaces.zope.org/zope">

  <content class=".utility.LocalUtilityService">
    <factory
        id="zope.app.services.UtilityService"
        permission="zope.ManageServices"
        />
  </content>

  </zopeConfigure>

and I added an include to the package configuration file::

  <!-- Utility Service --> <include file="utility.zcml" />

To make it possible to add the utility service, I need to add an entry to
the ``add_service`` browser menu.  The ``add_component`` menu is the menu
used by site folders for adding objects.  To do this, I need to add a
browser menu configuration.  Eventually, the local interface will
have a number of views, so I create a package, ``utility``, for
it in ``zope/app/browser/services``.  [1]_ In that
package, I put a configuration that defines the needed browser menu
item::

   <zopeConfigure xmlns="http://namespaces.zope.org/browser">

   <menuItem
         for="zope.app.interfaces.container.IAdding"
         menu="add_service"
         action="zope.app.services.UtilityService"
         title="Utility Service"
         permission="zope.ManageServices"
         />

   </zopeConfigure>

and I added an include to the configuration file in
zope.app.browser.services::

   <!-- Utility Service --> <include package=".utility" />

With this in place, I can add a local service that does nothing but
delegate to a service above it.  (To actually create a utility service
instance, I have to go to the service manager and use its ``Add
service`` action.  The service manager is reached from the root folder
by using the ``Manage local services`` action.)


Step 2. Providing functionality
-------------------------------

Now it's time to add some functionality.  A utility service keeps
track of utility components by name and interface.  It allows
components to be registered and then looked up later.

We'll start by updating the utility service to support registrations.
The updated local utility service implementation can be found in
zope/app/services/utility.py.

First, we'll pick a data structure.  We'll use a persistent dictionary
mapping utility names to implementor registries.  An implementor
registry implements a mapping from interfaces to objects; it's not
quite the same as a mapping because it understands subclassing
relationships between the interfaces used as keys.  In this case, the
implementor registries themselves map interfaces to
RegistrationStacks::

  { utility_name -> { interface -> stack } }


We also need to implement
zope.app.interfaces.services.registration.IRegistry.  This defines two
methods, ``queryRegistrationsFor`` and ``createRegistrationsFor``.

A ``queryRegistrationsFor`` method is added to implement
``IRegistry``.  It takes a registration object and returns the
corresponding registration registry.  The registration object is
used to provide an abstract way to represent registration parameters.
Typically, the registration parameters are extracted and a more
concrete method is called.  In the local utility service, we extract
the utility name and interface and call ``queryRegistrations`` with
the name and interface.

Similarly, we add a ``createRegistrationsFor`` method that takes a
registration object holding registration parameters and creates a
registration registry for the parameters (if none already exists).
If we don't have a implementor registry for a utility name, we create
one and add it.  When we create the implementor registry, we pass a
``PersistentDict`` for it to use to store registration data.  This
assures that updates are made persistently.  If there isn't implementor
data for the given interface, we create a registration registry and
register it for the interface.

Finally, we modify ``queryUtility`` to use registered utility
registrations.  We try to get a registration registery by calling
``queryRegistrations``.  If we get one, we call its ``active``
method to get the active registration, if any.  Finally, we call
``getComponent`` on the active registration to get the actual
component.  We leave it up to the registration object to take care of
actually finding and returning the component.

We need to provide utility registration objects.  The
utility registration objects need to manage several bits of
information:

- name

- interface

- permission

- The location of the actual component.

The registration objects provide access to the component through the
getComponent method.

To create the registration class, we'll start by defining a
registration schema in
``zope/app/interfaces/services/utility.py``.  The schema should extend
``zope.app.interfaces.services.registration.IRegistration``.
There's a more specific interface,
``zope.app.interfaces.services.registration.IComponentRegistration``
that is much closer to what we need.  (XXX Add footnote explaining why
we can't use INamedComponentRegistration in this example.)
We extend this interface as IUtilityRegistration, which adds a name
field (which is required but may be empty -- note the subtle
difference, because the empty string is still used as part of the
lookup key) and an interface field.  We also override the
componentPath field to make it read-only (this is for the UI
definition).

A ``UtilityRegistration`` class is added to the ``utility`` module in
``zope/app/services`` that implements the registration interface.  We
can subclass ComponentRegistration, which does much of the work.  Note
that registration component includes two methods, defined in
``IRegistration``, giving summary information used by several
predefined views.  See the interface for a description of these methods.

We need to provide user interfaces for:

- The utility service, 

- The utility registrations, and for 

- Registered utilities

Utility service user interface
==============================

The utility service needs a view for showing what utilities have been
registered. 

MORE DOCUMENTATION TO FOLLOW

Utility registration user interface
===================================

We need two views for registration objects:

- an add view, and 

- an edit view

The registration add view will be created using a schema-driven add
form::

  <addform
      label="New Utility Registration"
      for="zope.app.interfaces.services.utility.ILocalUtility"
      name="addRegistration.html"
      schema="zope.app.interfaces.services.utility.IUtilityRegistration"
      class=".AddRegistration"
      permission="zope.ManageServices"
      content_factory="zope.app.services.utility.UtilityRegistration"
      arguments="name interface componentPath"
      set_after_add="status"
      fields="name interface componentPath permission status"
      />

The add form is named ``addRegistration.html``.  This is a standard
name that a number of other views expect to be defined.  The form is
registered for ``ILocalUtility``.  ``ILocalUtility`` is a marker
interface thgat extends ``IRegisterable``.  We'll require that all
local utilities implement this view.  Utility components should also
implement IAttributeAnnotatable, unless they want to provide a
different way to store annotations.

Notice that there's no template!  The <addform> directive creates the
form for us using a generic template, zope/app/browser/form/add.pt,
and information about the specific fields to be displayed extracted
from the schema.  We do specify a class name: the AddRegistration
class.  This class needs some explanation.

The <addform> directive uses the AddRegistration class as a mix-in
class.  It may override various methods to customize the add form; the
set of methods that can be customized is described by the
``zope.app.interfaces.browser.form.IAddFormCustomization`` interface.
In this particular case, we must override ``add`` and ``nextURL``
because their default implementations only work when the add form is a
view on an `IAdding` view.  That is the normal way to use add forms, but
here we don't do that; this particular add form is a view on a local
utility component.  Our ``AddRegistration`` class subclasses
``zope.app.browser.services.registration.AddComponentRegistration``,
which provides the implementations of ``add`` and ``nextURL`` that we
need. The ``add`` method defined in ``AddComponentRegistration`` finds
the congiguration manager in the current folder and adds the new
registration object to it.

The AddRegistration class defines a class attribute::

    interface_widget = CustomWidget(UtilityInterfaceWidget)

This tells the forms machinery to use a a custom widget for the
interface field. The custom widget we use is a specialized interface
widget that allows the user to select from the non-trivial interfaces
implemented by the component being configured.

The edit view looks similar to the add view, but its definition
is simpler, because it isn't deviating quite as much from a standard
edit view::

  <editform
      name="index.html"
      menu="zmi_views" title="Edit"
      schema="zope.app.interfaces.services.utility.IUtilityRegistration"
      label="Utility Registration"
      permission="zope.ManageServices"
      fields="name interface componentPath permission status"
      />

This is a view on IUtilityRegistration, which is typical for an edit
view.  The good news is that it has no template *or* class!  The
<editform> directive lets us specifiy all the customization we need:

- ``name=``: The view name.  This is the last component of the URL for
  the view.

- ``menu=``, ``title=``: Menu information: "zmi_views" means that this
  view is one of the "tabs" for this type of object, the title
  argument gives the text in the tab.

- ``schema=``: The interface used as the schema.  The field
  definitions in this interface define which attributes are displayed
  in the form, and how.

- ``label=``: The label, used as the title text in the view.

- ``permission=``: A permission needed to access the view.

- ``fields=``: A list of fields to be displayed in the form.  This is
  used here to force the order in which the fields are displayed.  It
  can also be used to display only a subset of the fields present in
  the schema.

And that's all there is to the edit view.  Some observable differences
between the edit view and the add view:

- The add view lets you specify the name or the interface; the edit
  view displays these fields read-only.

- When you submit the add view, you are redirected to the
  registration manager; the edit view takes you back to itself.


User interface for registered utilities
=======================================

In general, for registerable components, we want to do
the registration through the components themselves.  That is, the site
admin should be able to walk up to a component and add or change a
registration for it.  The most common case is actually that a site
manager creates a component and configures it right away.  (This is
the same common case that is used for creating and configuring
services.)  There's a standard view registered for all IRegisterable
components that provides the ability to view and change the
registrations for a component. 

IRegisterable is a marker interface that extends IAnnotatable.
Annotations are used to record the registrations for a component.

---------------------------------------------------------------

.. [1] Of course, I initially forgot to include a nearly empty
   ``__init__.py`` file and had to add one later.


=== Zope3/src/zope/app/services/README.txt 1.4 => 1.4.10.1 ===
--- Zope3/src/zope/app/services/README.txt:1.4	Thu May  1 14:59:30 2003
+++ Zope3/src/zope/app/services/README.txt	Sun Jun 22 10:23:26 2003
@@ -5,20 +5,17 @@
 :Author: Jim Fulton
 :Version: $Revision$
 
-.. contents::
-
 This package includes implementations of several local services.
 It also contains infrastructure for implementing local services.
 
-This document describes how to implement local services.  It's not
-too difficult, but there can be a lot of details that are hard to
-remember.
+Implementing lolcal services is not too difficult, but there can be a
+lot of details that are hard to remember.
 
 A service is a component that implements a specific interface *and*
 that has the responsibility to collaborate with services above it.
 Local services are stored in the Zope object database, so they also
 need to be persistent.  Finally, many local services support modular
-configuration through configuration objects.
+registration through registration objects.
 
 A few words on the difference between local and global services:
 
@@ -34,124 +31,22 @@
   them in the object hierarchy, or with the global service; global
   services by definition have nothing "above" them.
 
-Let's walk through an example step by step.  We'll implement a
-local utility service.  A utility service must implement the
-interface ``zope.component.interfaces.IUtilityService``.
-
-
-Step 1. Create a minimal service
---------------------------------
-
-Create a minimal service that delagates everything to the
-service above it, in the file ``utility.py``::
-
-  from persistence import Persistent
-  from zope.component.exceptions import ComponentLookupError
-  from zope.proxy.context import ContextAware
-  from zope.app.component.nextservice import getNextService
-  from zope.component.interfaces import IUtilityService
-  from zope.app.interfaces.services.interfaces import ISimpleService
-
-  class LocalUtilityService(Persistent, ContextAware):
-
-      __implements__ = IUtilityService, ISimpleService
-
-      def getUtility(self, interface, name=''):
-          utility = self.queryUtility(interface, name=name)
-          if utility is None:
-              raise ComponentLookupError("utility", interface, name)
-          return utility
-
-      def queryUtility(self, interface, default=None, name=''):
-          next = getNextService(self, "Utilities")
-          return next.queryUtility(interface, default, name)
-
-The local service subclasses two classes:
-
-``Persistent``
-  Provides support for transparent persistent in the ZODB.
-
-``ContextAware``
-  Causes all of the methods or properties defined in
-  the class (or base classes) to be bound to context-wrapped
-  instances.  This is needed if the methods or properties are going to
-  call APIs that need acquisition context.  We could convert each of
-  the methods to context methods individually, but it's easier to just
-  mix-in context aware.
-
-The ``getUtility`` method simply delegates to ``queryUtility``.  The
-``queryUtility`` method delegates to the next utility service using
-``getNextService``.  (Both methods are specified by the
-``IUtilityService`` interface.)
-
-The function ``getNextService`` looks up the next service above the
-current service.  It takes a location and a service name.  We use it
-to get the interface service defined above our service, which may be
-the global service, and delegate to it.
-
-I created the service in the ``utility`` module in this package (the
-file ``utility.py``).  This package is already pretty large.  To avoid
-a really large zcml file, I've started giving each service its own
-zcml file.  So I also created an ``utility.zcml`` file::
-
-  <zopeConfigure xmlns="http://namespaces.zope.org/zope">
-
-  <content class=".utility.LocalUtilityService">
-    <factory
-        id="zope.app.services.UtilityService"
-        permission="zope.ManageServices"
-        />
-  </content>
-
-  </zopeConfigure>
-
-and I added an include to the package configuration file::
-
-  <!-- Utility Service --> <include file="utility.zcml" />
-
-To make it possible to add the utility service, I need to add an entry to
-the ``add_component`` browser menu.  The ``add_component`` menu is the menu
-used by site folders for adding objects.  To do this, I need to add a
-browser menu configuration.  Eventually, the local interface will
-have a number of views, so I create a package, ``utility``, for
-it in ``zope/app/browser/services``.  [1]_ In that
-package, I put a configuration that defines the needed browser menu
-item::
-
-   <zopeConfigure xmlns="http://namespaces.zope.org/browser">
-
-   <menuItem
-         for="zope.app.interfaces.container.IAdding"
-         menu="add_service"
-         action="zope.app.services.UtilityService"
-         title="Utility Service"
-         permission="zope.ManageServices"
-         />
-
-   </zopeConfigure>
-
-and I added an include to the configuration file in
-zope.app.browser.services::
-
-   <!-- Utility Service --> <include package=".utility" />
-
-With this in place, I can add a local service that does nothing but
-delegate to a service above it.  (To actually create a utility service
-instance, I have to go to the service manager and use its ``Add
-service`` action.  The service manager is reached from the root folder
-by using the ``Manage local services`` action.)
-
-
-Step 2. Providing functionality
--------------------------------
-
-Now it's time to add some functionality.  A utility service keeps
-track of utility components by name and interface.  It allows
-components to be registered and then looked up later.
-
-An important feature of component registration services, like the
-utility service, is that they support multiple conflicting
-registrations.  At most one of the registrations is active.  A site
+  (Note that it's up to the service to decide what form the
+  collaboration will take.  An exceptable form of collaboration is to
+  not collaborate at all.
+
+Registration
+------------
+
+Many services act as component registries.  Their primary job is to
+allow components to be looked up based on parameters such as names,
+interfaces or both. Examples of component registries include the
+adapter service, the view service, the service service, and the
+utility service.
+
+An important feature of component registration services is that they
+support multiple conflicting registrations for the same registration
+parameters.  At most one of the registrations is active.  A site
 developer can switch between alternate components by simply changing
 which one is active.
 
@@ -160,358 +55,68 @@
 it.  The new version is active.  The site developer then finds a
 bug in the new version.  Because the old utility is still registered,
 the site developer can easily switch back to it by making it active.
+In fact, the site manager only needs to inactivate the new version and
+the old version becomes active again.
 
-Utilities can be provided in two ways:
-
-- As persistent objects in (site-management) folders.
+To support this registration flexibility, Zope provides a registration
+framework:
 
-- As module global objects.  (A variation is to point to a class
-  that can be called without arguments to create a utility.)
+- Registration objects manage registration parameters and other data.
+  They also provide access to registered components. In some cases,
+  such as adapters and views, they are responsible for constructing
+  components on the fly.
+
+- Registration managers support management of registration objects
+  in folders.  Each folder has a registration manager containing all
+  of the registration objects for that folder.
 
-We'd like to avoid making the utility service have to deal with
-these variations directly.
-
-We want to make it possible for folders to provide configurations
-that can be reused in different sites.
-
-To support the configuration flexibility described above, Zope
-provides a configuration framework:
-
-- Configuration registry objects manage multiple configurations for
-  the same configuration parameters (at most one of which is active at
+- RegistrationStack objects manage multiple registrations for
+  the same registration parameters (at most one of which is active at
   any given time).  For example, in the case of a utility service
-  these would be configurations for the same interface and name.
-
-- Configuration objects provide configuration data.
+  these would be registrations for the same interface and name.
 
-- Configuration managers support management of configuration objects
-  in folders.
+There are two kinds of registrations:
 
-We'll start by updating the utility service to support configurations.
-The updated local utility service implementation can be found in
-zope/app/services/utility.py.
-
-First, we'll pick a data structure.  We'll use a persistent dictionary
-mapping utility names to implementor registries.  An implementor
-registry implements a mapping from interfaces to objects; it's not
-quite the same as a mapping because it understands subclassing
-relationships between the interfaces used as keys.  In this case, the
-implementor registries themselves map interfaces to configuration
-registries.
-
-We also need to implement
-zope.app.interfaces.services.configuration.IConfigurable.  This
-defines two methods, ``queryConfigurationsFor`` and
-``createConfigurationsFor``.
-
-A ``queryConfigurationsFor`` method is added to implement
-``IConfigurable``.  It takes a configuration object and returns the
-corresponding configuration registry.  The configuration object is
-used to provide an abstract way to represent configuration parameters.
-Typically, the configuration parameters are extracted and a more
-concrete method is called.  In the local utility service, we extract
-the utility name and interface and call ``queryConfigurations`` with
-the name and interface.
-
-Similarly, we add a ``createConfigurationsFor`` method that takes a
-configuration object holding configuration parameters and creates a
-configuration registry for the parameters (if none already exists).
-If we don't have a implementor registry for a utility name, we create
-one and add it.  When we create the implementor registry, we pass a
-``PersistentDict`` for it to use to store registration data.  This
-assures that updates are made persistently.  If there isn't implementor
-data for the given interface, we create a configuration registry and
-register it for the interface.
-
-Finally, we modify ``queryUtility`` to use registered utility
-configurations.  We try to get a configuration registery by calling
-``queryConfigurations``.  If we get one, we call its ``active``
-method to get the active configuration, if any.  Finally, we call
-``getComponent`` on the active configuration to get the actual
-component.  We leave it up to the configuration object to take care of
-actually finding and returning the component.
-
-Our local utility service is now complete, except for a user
-interface.  We need to provide utility configuration objects.  The
-utility configuration objects need to manage several bits of
-information:
-
-- name
-
-- interface
-
-- permission
-
-- The location of the actual component.
-
-We'll start by creating a configuration class for utility components
-stored in folders.  Somewhat different approaches are taken for
-configuring components contained in folders and objects contained in
-modules.  Objects contained in folders provide a configurations view
-that shows the configurations for the object and lets you add
-configurations.  When we add these objects, we typically add
-configurations at the same time.
-
-To create the configuration class, we'll start by defining a
-configuration schema in
-``zope/app/interfaces/services/utility.py``.  The schema should extend
-``zope.app.interfaces.services.configuration.IConfiguration``.
-There's a more specific interface,
-``zope.app.interfaces.services.configuration.IComponentConfiguration``
-that is much closer to what we need.  (XXX Add footnote explaining why
-we can't use INamedComponentConfiguration in this example.)
-We extend this interface as IUtilityConfiguration, which adds a name
-field (which is required but may be empty -- note the subtle
-difference, because the empty string is still used as part of the
-lookup key) and an interface field.  We also override the
-componentPath field to make it read-only (this is for the UI
-definition).
-
-A ``UtilityConfiguration`` class is added to the ``utility`` module in
-``zope/app/services`` that implements the configuration interface.
-We can subclass ComponentConfiguration, which does much of the work.
-
-
-For utility components stored in folders, we want to do the
-configuration through the components themselves.  That is, the site
-admin should be able to walk up to a component that implements a
-utility and add or change a utility configuration for it.  The most
-common case is actually that a site manager creates a utility
-component and configures it right away.  (This is the same common case
-that is used for creating and configuring services.)
-
-There's a view on utility components for managing their
-configurations; similar to the corresponding view on service
-components, it shows a list of all configurations for the component,
-and a link to add a new one.
-
-To implement this view, we need to keep track of the
-configuration objects for given utility components.  The reference
-from a configuration object to the component it configures is
-contained in the configuration object itself.  In order to find the
-configurations pertaining to a component, we have to implement back
-pointers somehow.  Requiring each component to keep track of these
-back pointers would be impractical; fortunately there's a general
-mechanism that we can use.
-
-The general mechanism is called "annotations".  See
-zope/app/interfaces/annotation.py for the full scoop.  The short
-version: by adapting an object to IAnnotations, we get a mapping-like
-interface that allows us to store arbitrary named data for the object.
-In the most common implemenation variant (see
-zope/app/attributeannotations.py), all annotation data is stored in a
-dictionary which itself is stored as the attribute __annotations__.
-Because we don't want to stomp on a component's attributes (even if
-they have a __funky__ name) without its permission, a component must
-declare that it implements IAttributeAnnotatable; the implementation
-is registered as an adapter from this interface to IAnnotations.
-
-To store the configuration back pointers on components, we use an
-annotation named "zope.app.services.configuration.UseConfiguration".
-(By convention, annotation keys should contain the full dotted name of
-the module or class that uses them.)  By adapting a component to
-IUseConfiguration, we get an interface defining methods ``addUsage``,
-``removeUsage`` and ``usages``, which provide access to the back
-pointers.
-
-We also need to provide two summary lines for the configuration
-manager.  These summary lines are returned by two methods that are
-(questionably, but conveniently) defined in the IConfiguration
-interface: usageSummary() and implementationSummary().  We override
-usageSummary() to return a string of the form "<interface> utility
-[named <name>]"; we inherit implementationSummary() from the
-ComponentConfiguration base class, which returns the component
-pathname as a string.  These two lines are used in the configuration
-manager's default view, which lists all the configurations it knows
-about; the first line is a a link to an edit view for configuration
-object.
-
-We're now ready to write view code.  We will create three views:
-
-- A "Configurations" view for utility components.
-
-- An "add configuration" view to configure a utility.
-
-- An "edit configuration" view to change a utility's configuration.
-
-
-The first view we create is the "Configurations" view for utility
-components.  This is very similar to the Configurations view for
-service components, and for several other components that are handled
-by the configuration manager.  The view is a "tab" on any object that
-implements ILocalUtility; the view name is useConfigurations.html and
-the tab label is "Configurations".  All this is expressed by the ZCML
-for the view, in zope/app/browser/services/utility/configure.zcml::
-
-  <page
-      for="zope.app.interfaces.services.utility.ILocalUtility"
-      name="useConfiguration.html"
-      template="useconfiguration.pt"
-      class=".useconfiguration.UseConfiguration"
-      permission="zope.ManageServices"
-      menu="zmi_views" title="Configurations"
-      />
-
-We won't show the template (useconfiguration.pt) here; it renders a
-bulleted list giving links to the configurations (each linking to the
-edit view for the configuration object), and a link to add a new
-configuration.
-
-The information for the bulleted list is computed by the
-UseConfiguration class in the file useconfiguration.py, which we also
-won't show here.  As described earlier, it adapts the component to
-IUseConfiguration and gets the back pointers to configuration objects
-from the adapter's usages() method.  For each configuration object it
-returns enough information to render the utility's interface, name,
-activity status, and URL.
-
-
-The second view we create is the add view for utility configurations.
-Here's the ZCML::
-
-  <addform
-      for="zope.app.interfaces.services.utility.ILocalUtility"
-      name="addConfiguration.html"
-      schema="zope.app.interfaces.services.utility.IUtilityConfiguration"
-      class=".useconfiguration.AddConfiguration"
-      permission="zope.ManageServices"
-      content_factory="zope.app.services.utility.UtilityConfiguration"
-      arguments="name interface componentPath"
-      set_after_add="status"
-      fields="name interface componentPath permission status"
-      />
-
-(XXX Maybe briefly explain each attribute, like we do below for
-<editform>?)
-
-Notice that there's no template!  The <addform> directive creates the
-form for us using a generic template, zope/app/browser/form/add.pt,
-and information about the specific fields to be displayed extracted
-from the schema.  We do specify a class name: the AddConfiguration
-class.  This class needs some explanation.
-
-The ``for=`` attribute says that this view applies to all objects that
-implement the ILocalUtility interface.  All utility components should
-implement this interface in order to be configurable as a utility.
-This interface extends IUseConfigurable, which is required so that a
-utility component can keep track of the back pointers to configuration
-objects that reference it, as was discussed above.  Utility components
-should also implement IAttributeAnnotatable, unless they want to
-provide a different way to store annotations.
-
-The <addform> directive uses the AddConfiguration class as a mix-in
-class.  It may override various methods to customize the add form; the
-set of methods that can be customized is given by the
-``zope.app.interfaces.browser.form.IAddFormCustomization class``.  In this
-particular case, we must override ``add`` and ``nextURL`` because their
-default implementations only work when the add form is a view on an
-IAdding view.  That is the normal way to use add forms, but here we
-don't do that; this particular add form is a view on a local utility
-component.  Our ``AddConfiguration`` class subclasses
-``zope.app.browser.services.configuration.AddComponentConfiguration``,
-which provides the implementations of ``add`` and ``nextURL`` that we
-need. The ``add`` method defined in ``AddComponentConfiguration``
-finds the congiguration manager in the current folder and adds the new
-configuration object to it.
-
-
-The AddConfiguration class defines a class attribute::
-
-    interface = CustomWidget(UtilityInterfaceWidget)
-
-This tells the forms machinery to use a a custom widget for the
-interface field. The custom widget we use is a specialized interface
-widget that allows the user to select from the non-trivial interfaces
-implemented by the component being configured.
-
-The third view we create is the edit view for utility configuration
-objects.  This view looks similar to the add view, but its definition
-is simpler, because it isn't deviating quite as much from a standard
-edit view::
-
-  <editform
-      name="index.html"
-      menu="zmi_views" title="Edit"
-      schema="zope.app.interfaces.services.utility.IUtilityConfiguration"
-      label="Utility Configuration"
-      permission="zope.ManageServices"
-      fields="name interface componentPath permission status"
-      />
-
-This is a view on IUtilityConfiguration, which is typical for an edit
-view.  The good news is that it has no template *or* class!  The
-<editform> directive lets us specifiy all the customization we need:
-
-- ``name=``: The view name.  This is the last component of the URL for
-  the view.
-
-- ``menu=``, ``title=``: Menu information: "zmi_views" means that this
-  view is one of the "tabs" for this type of object, the title
-  argument gives the text in the tab.
-
-- ``schema=``: The interface used as the schema.  The field
-  definitions in this interface define which attributes are displayed
-  in the form, and how.
-
-- ``label=``: The label, used as the title text in the view.
-
-- ``permission=``: A permission needed to access the view.
-
-- ``fields=``: A list of fields to be displayed in the form.  This is
-  used here to force the order in which the fields are displayed.  It
-  can also be used to display only a subset of the fields present in
-  the schema.
-
-And that's all there is to the edit view.  Some observable differences
-between the edit view and the add view:
-
-- The add view lets you specify the name or the interface; the edit
-  view displays these fields read-only.
-
-- When you submit the add view, you are redirected to the
-  configuration manager; the edit view takes you back to itself.
-
-
-
-To do:
-
-  Describe the demo utility
-
-  Need a UI for browsing registered utilities in the utility service.
-  (Done, need to describe it.)
-
-  XXX We decided not to do this after all:
-  Configuration of module globals
-
-    - Need the configuration object class that keeps track of:
-
-      o name
-
-      o interface
-
-      o dotted name
-
-      o permission
-
-    - Add view for the configuration
-
-    - Edit view for the configuration
-
-    - Summary view of the configuration in a configuration registry
-
-    - Summary view of the configuration in a configuration manager
+- Local-object registrations register objects in site-management
+  folders, such as service instances, utility instances, database
+  connections, caches, and templates.  
 
+  Local objects are named using a path.
 
+  Local-object registrations are primarily managed through the objects
+  that they register. The objects have a "Registrations" tab that
+  allows the registrations (usually 1) for the objects to be managed.
 
+  Local-object registrations can also be browsed and edited in the
+  registration manager for the folder containing the registered
+  components. 
 
+- Module-global registrations register objects stored in
+  modules. Objects in modules aren't managable directly, so we can't
+  manage their registrations trough them.  (The state of an object
+  stored in a module must be respresented soley by the module source.)
+  
+  Module-global objects are named using dotted names.
 
+  Module-global registrations are added, browsed and edited in
+  registration mananagers.  
 
+Implementation of services that support registration is substantially
+more difficult that implementation of non-registry services.
 
+Examples
+--------
 
+Implementation of local services is described through examples.
 
+- The error reporting service is among the simplest examples because
+  error reporting services don't support registration and don't
+  delegate requests to services above.
 
+  See error.txt
 
----------------------------------------------------------------
+- The utility service is an example of a service that supports
+  local-object registration. It also provides a simple example of a
+  service that delegates to services above it.
 
-.. [1] Of course, I initially forgot to include a nearly empty
-   ``__init__.py`` file and had to add one later.
+  See utility.txt.


=== Zope3/src/zope/app/services/adapter.py 1.14 => 1.14.2.1 ===
--- Zope3/src/zope/app/services/adapter.py:1.14	Wed May 21 16:30:04 2003
+++ Zope3/src/zope/app/services/adapter.py	Sun Jun 22 10:23:26 2003
@@ -21,20 +21,21 @@
 from zope.interface.adapter import AdapterRegistry
 from persistence import Persistent
 from persistence.dict import PersistentDict
+from zope.interface import implements
 from zope.component.interfaces import IAdapterService
 from zope.component.exceptions import ComponentLookupError
 from zope.component import getServiceManager
 from zope.app.services.servicenames import Adapters
-from zope.app.interfaces.services.configuration import IConfigurable
-from zope.app.services.configuration import ConfigurationRegistry
-from zope.app.services.configuration import SimpleConfiguration
-from zope.proxy.context import ContextWrapper
-from zope.proxy.context import ContextMethod
-from zope.app.services.configuration import ConfigurationStatusProperty
+from zope.app.interfaces.services.registration import IRegistry
+from zope.app.services.registration import RegistrationStack
+from zope.app.services.registration import SimpleRegistration
+from zope.app.context import ContextWrapper
+from zope.context import ContextMethod
+from zope.app.services.registration import RegistrationStatusProperty
 from zope.app.component.nextservice import getNextService
 from zope.app.interfaces.services.service import ISimpleService
 
-from zope.app.interfaces.services.adapter import IAdapterConfiguration
+from zope.app.interfaces.services.adapter import IAdapterRegistration
 
 class PersistentAdapterRegistry(Persistent, AdapterRegistry):
 
@@ -44,22 +45,22 @@
 
 class AdapterService(Persistent):
 
-    __implements__ = IAdapterService, IConfigurable, ISimpleService
+    implements(IAdapterService, IRegistry, ISimpleService)
 
     def __init__(self):
         self._byName = PersistentDict()
 
-    def queryConfigurationsFor(self, configuration, default=None):
-        "See IConfigurable"
+    def queryRegistrationsFor(self, registration, default=None):
+        "See IRegistry"
         # XXX Need to add named adapter support
-        return self.queryConfigurations(
-            configuration.forInterface, configuration.providedInterface,
-            configuration.adapterName,
+        return self.queryRegistrations(
+            registration.forInterface, registration.providedInterface,
+            registration.adapterName,
             default)
 
-    queryConfigurationsFor = ContextMethod(queryConfigurationsFor)
+    queryRegistrationsFor = ContextMethod(queryRegistrationsFor)
 
-    def queryConfigurations(self,
+    def queryRegistrations(self,
                             forInterface, providedInterface, adapterName,
                             default=None):
 
@@ -73,18 +74,18 @@
 
         return ContextWrapper(registry, self)
 
-    queryConfigurations = ContextMethod(queryConfigurations)
+    queryRegistrations = ContextMethod(queryRegistrations)
 
-    def createConfigurationsFor(self, configuration):
-        "See IConfigurable"
+    def createRegistrationsFor(self, registration):
+        "See IRegistry"
         # XXX Need to add named adapter support
-        return self.createConfigurations(
-            configuration.forInterface, configuration.providedInterface,
-            configuration.adapterName)
+        return self.createRegistrations(
+            registration.forInterface, registration.providedInterface,
+            registration.adapterName)
 
-    createConfigurationsFor = ContextMethod(createConfigurationsFor)
+    createRegistrationsFor = ContextMethod(createRegistrationsFor)
 
-    def createConfigurations(self, forInterface, providedInterface, name):
+    def createRegistrations(self, forInterface, providedInterface, name):
 
         adapters = self._byName.get(name)
         if adapters is None:
@@ -93,12 +94,12 @@
 
         registry = adapters.getRegistered(forInterface, providedInterface)
         if registry is None:
-            registry = ConfigurationRegistry()
+            registry = RegistrationStack()
             adapters.register(forInterface, providedInterface, registry)
 
         return ContextWrapper(registry, self)
 
-    createConfigurations = ContextMethod(createConfigurations)
+    createRegistrations = ContextMethod(createRegistrations)
 
     def getAdapter(self, object, interface, name=''):
         "See IAdapterService"
@@ -186,11 +187,13 @@
         return adapters.getRegisteredMatching(for_interfaces,
                                               provided_interfaces)
 
-class AdapterConfiguration(SimpleConfiguration):
+class AdapterRegistration(SimpleRegistration):
 
-    __implements__ = IAdapterConfiguration, SimpleConfiguration.__implements__
+    implements(IAdapterRegistration)
 
-    status = ConfigurationStatusProperty(Adapters)
+    serviceType = Adapters
+
+    status = RegistrationStatusProperty()
 
     # XXX These should be positional arguments, except that forInterface
     #     isn't passed in if it is omitted. To fix this, we need a
@@ -216,3 +219,6 @@
         return factory(object)
 
     getAdapter = ContextMethod(getAdapter)
+
+# XXX Pickle backward compatability
+AdapterConfiguration = AdapterRegistration


=== Zope3/src/zope/app/services/auth.py 1.15 => 1.15.10.1 ===
--- Zope3/src/zope/app/services/auth.py:1.15	Thu May  1 15:35:34 2003
+++ Zope3/src/zope/app/services/auth.py	Sun Jun 22 10:23:26 2003
@@ -30,11 +30,12 @@
 
 from zope.app.interfaces.services.auth import IAnnotatableUser
 
-from zope.proxy.introspection import removeAllProxies
+from zope.proxy import removeAllProxies
 from zope.app.attributeannotations import AttributeAnnotations
 from zope.app.component.nextservice import getNextService
-from zope.proxy.context import ContextMethod
+from zope.context import ContextMethod
 from zope.app.interfaces.services.service import ISimpleService
+from zope.interface import implements
 
 
 class DuplicateLogin(Exception):
@@ -46,7 +47,7 @@
 
 class AuthenticationService(Persistent):
 
-    __implements__ = IAuthenticationService, IContainer, ISimpleService
+    implements(IAuthenticationService, IContainer, ISimpleService)
 
     def __init__(self):
         self._usersbylogin = OOBTree()
@@ -124,6 +125,7 @@
             raise ValueError(key)
         self._usersbyid[key] = object
         self._usersbylogin[object.getLogin()] = object
+        return key
 
     def __delitem__(self, key):
         'See IWriteContainer'
@@ -159,11 +161,10 @@
         return key in self._usersbyid
 
 
-
 class User(Persistent):
     """A persistent implementation of the IUser interface """
 
-    __implements__ =  IAnnotatableUser
+    implements(IAnnotatableUser)
 
     def __init__(self, id, title, description, login, pw):
         self.__id = id


=== Zope3/src/zope/app/services/cache.py 1.9 => 1.9.10.1 ===
--- Zope3/src/zope/app/services/cache.py:1.9	Thu May  1 15:35:34 2003
+++ Zope3/src/zope/app/services/cache.py	Sun Jun 22 10:23:27 2003
@@ -17,33 +17,29 @@
 """
 
 from persistence import Persistent
-
-from zope.component import getService
-from zope.proxy.context import ContextMethod
-
 from zope.app.component.nextservice import queryNextService
 from zope.app.interfaces.cache.cache import ICache, ICachingService
 from zope.app.interfaces.event import IObjectModifiedEvent
-from zope.app.interfaces.services.cache import ICacheConfiguration
-from zope.app.interfaces.services.configuration \
-     import INameComponentConfigurable
+from zope.app.interfaces.services.cache import ICacheRegistration
+from zope.app.interfaces.services.registration import INameComponentRegistry
 from zope.app.interfaces.services.event import IEventChannel
 from zope.app.interfaces.services.service import ISimpleService
-from zope.app.services.configuration import ConfigurationStatusProperty
-from zope.app.services.configuration import NameComponentConfigurable
-from zope.app.services.configuration import NamedComponentConfiguration
+from zope.app.services.registration import RegistrationStatusProperty
+from zope.app.services.registration import NameComponentRegistry
+from zope.app.services.registration import NamedComponentRegistration
 from zope.app.services.event import ServiceSubscriberEventChannel
+from zope.component import getService
+from zope.context import ContextMethod
+from zope.interface import implements
 
 class ILocalCachingService(ICachingService, IEventChannel,
-                           INameComponentConfigurable):
+                           INameComponentRegistry):
     """TTW manageable caching service"""
 
 
-class CachingService(ServiceSubscriberEventChannel, NameComponentConfigurable):
+class CachingService(ServiceSubscriberEventChannel, NameComponentRegistry):
 
-    __implements__ = (ILocalCachingService,
-                      ISimpleService,
-                      ServiceSubscriberEventChannel.__implements__)
+    implements(ILocalCachingService, ISimpleService)
 
     _subscribeToServiceInterface = IObjectModifiedEvent
 
@@ -52,9 +48,13 @@
         #     __init__ with respect to calling
         #     super(ClassName, self).__init__(*args, **kw), then we can
         #     replace the following with just a call to super.
+        # XXX Disagree.  __init__ doesn't always have the same signature,
+        #     hence cllaborative super doesn't apply to __init__, at least
+        #     not in general.  (It may work by convention for Fields.)
+        #     --Guido
         Persistent.__init__(self)
         ServiceSubscriberEventChannel.__init__(self)
-        NameComponentConfigurable.__init__(self)
+        NameComponentRegistry.__init__(self)
 
     def getCache(wrapped_self, name):
         'See ICachingService'
@@ -78,8 +78,8 @@
     def getAvailableCaches(wrapped_self):
         'See ICachingService'
         caches = {}
-        for name in wrapped_self.listConfigurationNames():
-            registry = wrapped_self.queryConfigurations(name)
+        for name in wrapped_self.listRegistrationNames():
+            registry = wrapped_self.queryRegistrations(name)
             if registry.active() is not None:
                 caches[name] = 0
         service = queryNextService(wrapped_self, "Caching")
@@ -90,19 +90,17 @@
     getAvailableCaches = ContextMethod(getAvailableCaches)
 
 
-class CacheConfiguration(NamedComponentConfiguration):
+class CacheRegistration(NamedComponentRegistration):
 
-    __doc__ = ICacheConfiguration.__doc__
+    __doc__ = ICacheRegistration.__doc__
 
-    __implements__ = (ICacheConfiguration,
-                      NamedComponentConfiguration.__implements__)
+    implements(ICacheRegistration)
 
-    status = ConfigurationStatusProperty('Caching')
+    serviceType = 'Caching'
 
-    label = "Cache"
+    status = RegistrationStatusProperty()
 
-    def __init__(self, *args, **kw):
-        super(CacheConfiguration, self).__init__(*args, **kw)
+    label = "Cache"
 
     def activated(wrapped_self):
         cache = wrapped_self.getComponent()
@@ -119,3 +117,7 @@
 
     def getInterface(self):
         return ICache
+
+
+# XXX Pickle backward compatability
+CacheConfiguration = CacheRegistration


=== Zope3/src/zope/app/services/configure.zcml 1.29 => 1.29.2.1 ===
--- Zope3/src/zope/app/services/configure.zcml:1.29	Thu May 15 17:30:44 2003
+++ Zope3/src/zope/app/services/configure.zcml	Sun Jun 22 10:23:27 2003
@@ -3,13 +3,13 @@
     xmlns:fssync='http://namespaces.zope.org/fssync'
     >
 
-<!-- Configuration registries -->
+<!-- Registration registries -->
 
-<content class="zope.app.services.configuration.ConfigurationRegistry">
+<content class="zope.app.services.registration.RegistrationStack">
   <require
       permission="zope.ManageServices"
       interface=
-      "zope.app.interfaces.services.configuration.IConfigurationRegistry"
+      "zope.app.interfaces.services.registration.IRegistrationStack"
       />
 </content>
 
@@ -22,16 +22,16 @@
       />
   <require
       permission="zope.ManageServices"
-      interface="zope.app.interfaces.services.configuration.IConfigurable"
+      interface="zope.app.interfaces.services.registration.IRegistry"
       attributes="getRegisteredMatching"
       />
 </content>
 
-<content class="zope.app.services.adapter.AdapterConfiguration">
+<content class="zope.app.services.adapter.AdapterRegistration">
   <require
       permission="zope.ManageServices"
-      interface="zope.app.interfaces.services.adapter.IAdapterConfiguration"
-      set_schema="zope.app.interfaces.services.configuration.IConfiguration"
+      interface="zope.app.interfaces.services.adapter.IAdapterRegistration"
+      set_schema="zope.app.interfaces.services.registration.IRegistration"
       />
   <require
       permission="zope.ManageServices"
@@ -48,16 +48,16 @@
       />
   <require
       permission="zope.ManageServices"
-      interface="zope.app.interfaces.services.configuration.IConfigurable"
+      interface="zope.app.interfaces.services.registration.IRegistry"
       attributes="getRegisteredMatching"
       />
 </content>
 
-<content class="zope.app.services.view.ViewConfiguration">
+<content class="zope.app.services.view.ViewRegistration">
   <require
       permission="zope.ManageServices"
-      interface="zope.app.interfaces.services.view.IViewConfiguration"
-      set_schema="zope.app.interfaces.services.configuration.IConfiguration"
+      interface="zope.app.interfaces.services.view.IViewRegistration"
+      set_schema="zope.app.interfaces.services.registration.IRegistration"
       />
   <require
       permission="zope.ManageServices"
@@ -65,11 +65,11 @@
       />
 </content>
 
-<content class="zope.app.services.view.PageConfiguration">
+<content class="zope.app.services.view.PageRegistration">
   <require
       permission="zope.ManageServices"
-      interface="zope.app.interfaces.services.view.IPageConfiguration"
-      set_schema="zope.app.interfaces.services.view.IPageConfiguration"
+      interface="zope.app.interfaces.services.view.IPageRegistration"
+      set_schema="zope.app.interfaces.services.view.IPageRegistration"
       />
   <require
       permission="zope.ManageServices"
@@ -122,9 +122,9 @@
   />
 
 <adapter
-  for="zope.app.interfaces.services.configuration.IUseConfigurable"
-  provides="zope.app.interfaces.services.configuration.IUseConfiguration"
-  factory="zope.app.services.configuration.UseConfiguration"
+  for="zope.app.interfaces.services.registration.IRegisterable"
+  provides="zope.app.interfaces.services.registration.IRegistered"
+  factory="zope.app.services.registration.Registered"
   />
 
 <!-- Role Templates -->
@@ -177,20 +177,20 @@
       <require
           permission="zope.View"
           interface="zope.app.interfaces.cache.cache.ICachingService"
-          attributes="queryConfigurations queryConfigurationsFor
-                      listConfigurationNames" />
+          attributes="queryRegistrations queryRegistrationsFor
+                      listRegistrationNames" />
       <require
           permission="zope.ManageServices"
           interface="zope.app.interfaces.container.IContainer" />
     </content>
 
-  <content class="zope.app.services.cache.CacheConfiguration">
+  <content class="zope.app.services.cache.CacheRegistration">
     <require
         permission="zope.ManageServices"
-        interface="zope.app.interfaces.services.cache.ICacheConfiguration"
+        interface="zope.app.interfaces.services.cache.ICacheRegistration"
         set_attributes="name componentPath permission"
         set_schema=
-            "zope.app.interfaces.services.configuration.IConfiguration" />
+            "zope.app.interfaces.services.registration.IRegistration" />
     <require
         permission="zope.ManageServices"
         interface="zope.app.interfaces.container.IAddNotifiable" />
@@ -213,13 +213,13 @@
         interface="zope.app.interfaces.annotation.IAttributeAnnotatable" />
     </content>
 
-  <content class="zope.app.services.service.ServiceConfiguration">
+  <content class="zope.app.services.service.ServiceRegistration">
     <require
         permission="zope.ManageServices"
-        interface="zope.app.interfaces.services.service.IServiceConfiguration"
+        interface="zope.app.interfaces.services.service.IServiceRegistration"
         set_attributes="serviceType componentPath permission"
         set_schema=
-            "zope.app.interfaces.services.configuration.IConfiguration"
+            "zope.app.interfaces.services.registration.IRegistration"
         />
     <require
         permission="zope.ManageServices"
@@ -250,26 +250,27 @@
     </content>
 
   <content class="zope.app.services.folder.SiteManagementFolder">
+    <factory permission="zope.ManageServices" />
     <require
         permission="zope.View"
         interface="zope.app.interfaces.container.IReadContainer" />
     <require
         permission="zope.ManageServices"
         interface="zope.app.interfaces.container.IWriteContainer"
-        attributes="getConfigurationManager" 
+        attributes="getRegistrationManager" 
         />
     <implements
         interface="zope.app.interfaces.annotation.IAttributeAnnotatable" />
 
     </content>
 
-<!-- Configuration Manager -->
+<!-- Registration Manager -->
 
-  <content class="zope.app.services.configuration.ConfigurationManager">
+  <content class="zope.app.services.registration.RegistrationManager">
     <factory
-        id = "zope.app.services.ConfigurationManager"
+        id = "zope.app.services.RegistrationManager"
         permission = "zope.ManageServices"
-        title = "Configuration Manager" />
+        title = "Registration Manager" />
     <require
         permission="zope.View"
         interface="zope.app.interfaces.container.IReadContainer" />
@@ -277,7 +278,7 @@
         permission="zope.ManageServices"
         interface="
         zope.app.interfaces.container.IWriteContainer
-        zope.app.interfaces.services.configuration.IOrderedContainer
+        zope.app.interfaces.services.registration.IOrderedContainer
         zope.app.interfaces.container.IDeleteNotifiable
         " 
         />
@@ -293,6 +294,10 @@
         permission="zope.ManageCode"
         interface="zodb.code.interfaces.IPersistentModuleManager"
         />
+    <require
+        permission="zope.ManageCode"
+        attributes="beforeDeleteHook"
+        />
     <implements
         interface="zope.app.interfaces.annotation.IAttributeAnnotatable"
         />
@@ -314,12 +319,18 @@
         interface="zope.app.interfaces.container.IWriteContainer
                    zope.app.interfaces.services.pagefolder.IPageFolderInfo"
         set_schema="zope.app.interfaces.services.pagefolder.IPageFolderInfo"
-        attributes="configured getConfigurationManager" 
+        attributes="configured getRegistrationManager" 
         />
     <implements
         interface="zope.app.interfaces.annotation.IAttributeAnnotatable" />
     </content>
 
+    <adapter
+        for="zope.app.interfaces.services.pagefolder.IPageFolder"
+        provides="zope.app.interfaces.context.IZopeContextWrapper"
+        factory="zope.app.services.pagefolder.PageFolderContextDecorator"
+        />
+
 <!-- Connection Service -->
 
   <content class="zope.app.services.connection.ConnectionService">
@@ -330,17 +341,17 @@
     <require
         permission="zope.View"
         interface="zope.app.interfaces.rdb.IConnectionService"
-        attributes="queryConfigurations queryConfigurationsFor
-                    listConfigurationNames" />
+        attributes="queryRegistrations queryRegistrationsFor
+                    listRegistrationNames" />
     </content>
 
-  <content class="zope.app.services.connection.ConnectionConfiguration">
+  <content class="zope.app.services.connection.ConnectionRegistration">
     <require
         permission="zope.ManageServices"
         interface=
-        "zope.app.interfaces.services.connection.IConnectionConfiguration"
+        "zope.app.interfaces.services.connection.IConnectionRegistration"
         set_attributes="name componentPath"
-        set_schema="zope.app.interfaces.services.view.IPageConfiguration"
+        set_schema="zope.app.interfaces.services.view.IPageRegistration"
         />
     <require
         permission="zope.ManageServices"
@@ -477,7 +488,7 @@
 <!-- Filesystem synchronization support -->
 
 <fssync:adapter
-    class=".configuration.ConfigurationManager"
+    class=".registration.RegistrationManager"
     factory="zope.app.content.fssync.DirectoryAdapter"
     />
 
@@ -488,7 +499,65 @@
 
 <fssync:adapter
     class=".service.ServiceManager"
-    factory="zope.app.content.fssync.DirectoryAdapter"
+    factory=".service.ServiceManagerAdapter"
+    />
+
+<fssync:adapter
+    class=".pagefolder.PageFolder"
+    factory=".pagefolder.PageFolderAdapter"
+    />
+
+<fssync:adapter
+    class=".zpt.ZPTTemplate"
+    factory=".zpt.ZPTPageAdapter"
+    />
+
+<fssync:adapter
+    class=".module.Manager"
+    factory=".module.ModuleAdapter"
+    />
+
+<fssync:adapter
+    class=".cache.CacheRegistration"
+    factory=".registration.ComponentRegistrationAdapter"
     />
+
+<fssync:adapter
+    class=".connection.ConnectionRegistration"
+    factory=".registration.ComponentRegistrationAdapter"
+    />
+
+<fssync:adapter
+    class=".service.ServiceRegistration"
+    factory=".registration.ComponentRegistrationAdapter"
+    />
+
+<fssync:adapter
+    class=".utility.UtilityRegistration"
+    factory=".registration.ComponentRegistrationAdapter"
+    />
+
+<adapter 
+  for="zope.app.interfaces.services.service.IServiceManager"
+  provides="zope.app.interfaces.file.IDirectoryFactory"
+  factory=".folder.SMFolderFactory"
+  permission="zope.ManageContent"
+  />
+
+<adapter 
+  for="zope.app.interfaces.services.folder.ISiteManagementFolder"
+  provides="zope.app.interfaces.file.IDirectoryFactory"
+  factory=".pagefolder.PageFolderFactory"
+  permission="zope.ManageContent"
+  />
+
+<adapter 
+  for="zope.app.interfaces.services.folder.ISiteManagementFolder"
+  provides="zope.app.interfaces.file.IFileFactory"
+  name=".py"
+  factory=".module.ModuleFactory"
+  permission="zope.ManageContent"
+  />
+
 
 </zopeConfigure>


=== Zope3/src/zope/app/services/connection.py 1.11 => 1.11.10.1 ===
--- Zope3/src/zope/app/services/connection.py:1.11	Thu May  1 15:35:34 2003
+++ Zope3/src/zope/app/services/connection.py	Sun Jun 22 10:23:27 2003
@@ -16,20 +16,21 @@
 """
 
 from persistence import Persistent
-from zope.proxy.context import ContextMethod
+from zope.context import ContextMethod
 
 from zope.app.interfaces.rdb import IZopeDatabaseAdapter
 from zope.app.interfaces.services.connection import ILocalConnectionService
 from zope.app.interfaces.services.service import ISimpleService
 
 from zope.app.component.nextservice import queryNextService
-from zope.app.services.configuration import NameComponentConfigurable
+from zope.app.services.registration import NameComponentRegistry
+from zope.interface import implements
 
-class ConnectionService(Persistent, NameComponentConfigurable):
+class ConnectionService(Persistent, NameComponentRegistry):
 
     __doc__ = ILocalConnectionService.__doc__
 
-    __implements__ = ILocalConnectionService, ISimpleService
+    implements(ILocalConnectionService, ISimpleService)
 
     def getConnection(self, name):
         'See IConnectionService'
@@ -55,8 +56,8 @@
     def getAvailableConnections(self):
         'See IConnectionService'
         connections = {}
-        for name in self.listConfigurationNames():
-            registry = self.queryConfigurations(name)
+        for name in self.listRegistrationNames():
+            registry = self.queryRegistrations(name)
             if registry.active() is not None:
                 connections[name] = 0
         service = queryNextService(self, "SQLDatabaseConnections")
@@ -72,20 +73,25 @@
     getAvailableConnections = ContextMethod(getAvailableConnections)
 
 
-from zope.app.interfaces.services.connection import IConnectionConfiguration
-from zope.app.services.configuration import NamedComponentConfiguration
-from zope.app.services.configuration import ConfigurationStatusProperty
+from zope.app.interfaces.services.connection import IConnectionRegistration
+from zope.app.services.registration import NamedComponentRegistration
+from zope.app.services.registration import RegistrationStatusProperty
 
-class ConnectionConfiguration(NamedComponentConfiguration):
+class ConnectionRegistration(NamedComponentRegistration):
 
-    __doc__ = IConnectionConfiguration.__doc__
+    __doc__ = IConnectionRegistration.__doc__
 
-    __implements__ = (IConnectionConfiguration,
-                      NamedComponentConfiguration.__implements__)
+    implements(IConnectionRegistration)
 
-    status = ConfigurationStatusProperty('SQLDatabaseConnections')
+    serviceType = 'SQLDatabaseConnections'
+
+    status = RegistrationStatusProperty()
 
     label = "Connection"
 
     def getInterface(self):
         return IZopeDatabaseAdapter
+
+
+# XXX Pickle backward compatability
+ConnectionConfiguration = ConnectionRegistration


=== Zope3/src/zope/app/services/errorr.py 1.8 => 1.8.18.1 ===
--- Zope3/src/zope/app/services/errorr.py:1.8	Tue Mar 11 11:11:22 2003
+++ Zope3/src/zope/app/services/errorr.py	Sun Jun 22 10:23:27 2003
@@ -24,9 +24,10 @@
 from types import StringTypes
 import logging
 from zope.exceptions.exceptionformatter import format_exception
-from zope.proxy.context import ContextMethod
+from zope.context import ContextMethod
 from zope.app.interfaces.services.error import IErrorReportingService
 from zope.app.interfaces.services.service import ISimpleService
+from zope.interface import implements
 
 
 #Restrict the rate at which errors are sent to the Event Log
@@ -49,7 +50,7 @@
 class ErrorReportingService(Persistent):
     """Error Reporting Service
     """
-    __implements__ = IErrorReportingService, ISimpleService
+    implements(IErrorReportingService, ISimpleService)
 
     keep_entries = 20
     copy_to_zlog = 0


=== Zope3/src/zope/app/services/event.py 1.24 => 1.24.4.1 ===
--- Zope3/src/zope/app/services/event.py:1.24	Mon May 12 12:31:50 2003
+++ Zope3/src/zope/app/services/event.py	Sun Jun 22 10:23:27 2003
@@ -31,8 +31,9 @@
 from zope.app.services.servicenames import EventSubscription
 from zope.app.component.nextservice import getNextService, queryNextService
 
-from zope.proxy.context import ContextMethod, ContextSuper
-from zope.proxy.introspection import removeAllProxies
+from zope.context import ContextMethod, ContextSuper
+from zope.proxy import removeAllProxies
+from zope.interface import implements
 
 from zope.app.event.subs import Subscribable, SubscriptionTracker
 
@@ -61,11 +62,12 @@
     return getSubscriptionService(context).unsubscribe(
         subscriber, event_type, filter)
 
-def unsubscribeAll(subscriber, event_type=IEvent, context=None):
+def unsubscribeAll(subscriber, event_type=IEvent, context=None,
+                   local_only=False):
     if context is None and not isinstance(subscriber, (int, str, unicode)):
         context = subscriber
     return getSubscriptionService(context).unsubscribeAll(
-        subscriber, event_type)
+        subscriber, event_type, local_only=local_only)
 
 def iterSubscriptions(subscriber=None, event_type=None, local_only=False,
                       context=None):
@@ -77,7 +79,7 @@
 
 class EventChannel(Subscribable):
 
-    __implements__ = IEventChannel
+    implements(IEventChannel)
 
     # needs __init__ from zope.app.event.subs.Subscribable
 
@@ -139,11 +141,7 @@
     event service when bound, and unsubscribe when unbound.
     """
 
-    __implements__ = (
-        EventChannel.__implements__,
-        SubscriptionTracker.__implements__,
-        IBindingAware
-        )
+    implements(IBindingAware)
 
     def __init__(self):
         SubscriptionTracker.__init__(self)
@@ -210,16 +208,35 @@
         # unsubscribe all subscriptions
         hubIds = clean_self._hubIds
         unsubscribeAll = wrapped_self.unsubscribeAll
+
+        # XXX Temporary hack to make unsubscriptions local in scope when
+        #     this mix-in is used as part of a subscriptions service.
+        #     The dependences of these mixins need to be documented and
+        #     reevaluated.
+        if ISubscriptionService.isImplementedBy(wrapped_self):
+            real_unsubscribeAll = unsubscribeAll
+            unsubscribeAll = lambda x: real_unsubscribeAll(x, local_only=True)
+
         try:
             clean_self._v_ssecunbinding = True
             while hubIds:
                 hubId = iter(hubIds).next()
-                unsubscribeAll(hubId, local_only=True)
+                # XXX This code path needs a unit test!
+                #     This code is also wrong.
+                #     The call to unsubscribeAll assumes that whatever class
+                #     mixes this class in provides an unsubscribeAll method
+                #     that correctly uses the self._subscribeToServiceName
+                #     to decide what it should be unsubscribing from.
+                #     This could be any service that implements
+                #     ISubscriptionService
+                unsubscribeAll(hubId)
 
             paths = clean_self._paths
             while paths:
                 path = iter(paths).next()
-                unsubscribeAll(path, local_only=True)
+                # XXX This code path needs a unit test!
+                #     Also, see comment above.
+                unsubscribeAll(path)
         finally:
             del clean_self._v_ssecunbinding
 
@@ -241,8 +258,6 @@
       those of the next higher service.
     """
 
-    __implements__ = Subscribable.__implements__
-
     _serviceName = None # should be replaced; usually done in "bound"
                         # method of a subclass that is IBindingAware
 
@@ -318,13 +333,7 @@
 
 class EventService(ServiceSubscriberEventChannel, ServiceSubscribable):
 
-    __implements__ = (
-        IEventService,
-        ISubscriptionService,
-        ISimpleService,
-        ServiceSubscribable.__implements__,
-        ServiceSubscriberEventChannel.__implements__
-        )
+    implements(IEventService, ISubscriptionService, ISimpleService)
 
     def __init__(self):
         ServiceSubscriberEventChannel.__init__(self)


=== Zope3/src/zope/app/services/field.py 1.7 => 1.7.18.1 ===
--- Zope3/src/zope/app/services/field.py:1.7	Thu Mar 13 12:10:37 2003
+++ Zope3/src/zope/app/services/field.py	Sun Jun 22 10:23:27 2003
@@ -25,10 +25,11 @@
 from zope.app.interfaces.services.field import IComponentLocation
 from zope.component import getServiceManager, getAdapter
 from zope.app.interfaces.services.module import IModuleService
+from zope.interface import implements
 
 class ComponentPath(Field):
 
-    __implements__ = IComponentPath
+    implements(IComponentPath)
 
     _type = unicode
 
@@ -52,7 +53,7 @@
 
 class ComponentLocation(Field):
 
-    __implements__ = IComponentLocation
+    implements(IComponentLocation)
 
     _type = unicode
 


=== Zope3/src/zope/app/services/folder.py 1.6 => 1.6.10.1 ===
--- Zope3/src/zope/app/services/folder.py:1.6	Thu May  1 15:35:34 2003
+++ Zope3/src/zope/app/services/folder.py	Sun Jun 22 10:23:27 2003
@@ -11,7 +11,7 @@
 # FOR A PARTICULAR PURPOSE.
 #
 ##############################################################################
-"""A package contains components and component configurations.
+"""A package contains components and component registrations.
 
 $Id$
 """
@@ -23,16 +23,19 @@
 from zope.app.interfaces.services.folder import ISiteManagementFolders
 from zope.app.interfaces.services.folder import ISiteManagementFolder
 from zope.app.interfaces.services.service import IComponentManager
-from zope.app.services.configuration import ConfigurationManagerContainer
+from zope.app.interfaces.file import IDirectoryFactory
+from zope.app.services.registration import RegistrationManagerContainer
 from zope.app.traversing import getPath
-from zope.proxy.context import ContextMethod, ContextWrapper
+from zope.app.context import ContextWrapper
+from zope.context import ContextMethod
+from zope.interface import implements
 
-class SiteManagementFolder(ConfigurationManagerContainer, BTreeContainer):
-    __implements__ = ISiteManagementFolder
+class SiteManagementFolder(RegistrationManagerContainer, BTreeContainer):
+    implements(ISiteManagementFolder)
 
 
 class SiteManagementFolders(BTreeContainer):
-    __implements__ = ISiteManagementFolders
+    implements(ISiteManagementFolders)
 
     def __init__(self):
         super(SiteManagementFolders, self).__init__()
@@ -69,6 +72,16 @@
         if not ISiteManagementFolder.isImplementedBy(obj):
             raise TypeError("Can only add packages")
         return super(SiteManagementFolders, self).setObject(name, obj)
+
+class SMFolderFactory(object):
+
+    implements(IDirectoryFactory)
+
+    def __init__(self, context):
+        self.context = context
+
+    def __call__(self, name):
+        return SiteManagementFolder()
 
 # XXX Backward compatability. This is needed to support old pickles.
 Package = SiteManagementFolder


=== Zope3/src/zope/app/services/hub.py 1.10 => 1.10.10.1 ===
--- Zope3/src/zope/app/services/hub.py:1.10	Thu May  1 15:35:34 2003
+++ Zope3/src/zope/app/services/hub.py	Sun Jun 22 10:23:27 2003
@@ -29,8 +29,8 @@
 
 from zope.component import getAdapter
 from zope.exceptions import NotFoundError
-from zope.proxy.context import ContextMethod
-from zope.proxy.introspection import removeAllProxies
+from zope.context import ContextMethod
+from zope.proxy import removeAllProxies
 
 from zope.app.interfaces.traversing import ITraverser
 from zope.app.interfaces.event import IObjectRemovedEvent, IObjectEvent
@@ -45,6 +45,7 @@
 from zope.app.interfaces.services.hub import IObjectRemovedHubEvent
 from zope.app.interfaces.traversing import ITraverser
 from zope.app.interfaces.services.service import ISimpleService
+from zope.interface import implements
 
 class HubEvent:
     """Convenient mix-in for HubEvents"""
@@ -83,7 +84,7 @@
 class ObjectRegisteredHubEvent(HubEvent):
     """A hubid has been freshly created and mapped against an object."""
 
-    __implements__ = IObjectRegisteredHubEvent
+    implements(IObjectRegisteredHubEvent)
 
 
 class ObjectUnregisteredHubEvent:
@@ -103,7 +104,7 @@
         self.__object = object
         self.location = location
 
-    __implements__ = IObjectUnregisteredHubEvent
+    implements(IObjectUnregisteredHubEvent)
 
     def __getObject(self):
         obj = self.__object
@@ -118,7 +119,7 @@
 class ObjectModifiedHubEvent(HubEvent):
     """An object with a hubid has been modified."""
 
-    __implements__ = IObjectModifiedHubEvent
+    implements(IObjectModifiedHubEvent)
 
 
 class ObjectMovedHubEvent(HubEvent):
@@ -129,13 +130,13 @@
         self.fromLocation = fromLocation
         HubEvent.__init__(self, hub, hubid, location, object)
 
-    __implements__ = IObjectMovedHubEvent
+    implements(IObjectMovedHubEvent)
 
 
 class ObjectRemovedHubEvent(ObjectUnregisteredHubEvent):
     """An object with a hubid has been removed."""
 
-    __implements__ = IObjectRemovedHubEvent
+    implements(IObjectRemovedHubEvent)
     # ...which is a subclass of IObjectUnregisteredHubEvent
 
     hub = None
@@ -171,10 +172,7 @@
     # concerned, and if it doesn't know how to do something, it won't
     # ask anything else to try.  Everything else is YAGNI for now.
 
-    __implements__ = (
-        IObjectHub,
-        ISimpleService,
-        ServiceSubscriberEventChannel.__implements__)
+    implements(IObjectHub, ISimpleService)
 
     def __init__(self):
         ServiceSubscriberEventChannel.__init__(self)
@@ -277,11 +275,6 @@
             path = getPath(path_or_object)
 
         pathslash = canonicalSlash(path)
-
-        # XXX This check should be done by canonicalPath, but Albert is still
-        #     refactoring that. So, I'll do it here for now.
-        if not pathslash.startswith(u'/'):
-            raise ValueError('Path must be absolute, not relative:', path)
 
         path_to_hubid = clean_self.__path_to_hubid
         if path_to_hubid.has_key(pathslash):


=== Zope3/src/zope/app/services/module.py 1.2 => 1.2.26.1 ===
--- Zope3/src/zope/app/services/module.py:1.2	Wed Dec 25 09:13:19 2002
+++ Zope3/src/zope/app/services/module.py	Sun Jun 22 10:23:27 2003
@@ -19,43 +19,66 @@
 from persistence import Persistent
 from zodb.code.module import PersistentModuleManager
 from zodb.code.interfaces import IPersistentModuleManager
+from zodb.code.interfaces import IPersistentModuleImportRegistry
+from zodb.code.interfaces import IPersistentModuleUpdateRegistry
 
 from zope.component import getServiceManager
-from zope.proxy.context import ContextMethod
+from zope.context import ContextMethod
 
-class Registry:
+from zope.interface import implements
 
-    # The registry is found via context, but the PersistentModuleManager
-    # doesn't know about context.  To make it behave contextually, this
-    # Registry class collaborates with Manager to delegate to the
-    # registry found via context.
+from zope.app.fssync.classes import ObjectEntryAdapter, AttrMapping
+from zope.app.interfaces.fssync import IObjectFile
+from zope.app.interfaces.file import IFileFactory
+from zope.app.interfaces.container import IDeleteNotifiable
+from zope.app.context import ContextWrapper
+
+
+class Registry(Persistent):
+
+    # This is a wrapper around the module service, which is actually
+    # the service manager.  The service manager is found via context,
+    # but the PersistentModuleManager doesn't know about context.  To
+    # make it behave contextually, this Registry class collaborates
+    # with the Manager class below to delegate to the registry found
+    # via context.
+
+    implements(IPersistentModuleImportRegistry,
+               IPersistentModuleUpdateRegistry)
 
     def __init__(self):
-        self._v_manager = None
+        self._v_module_service = None
+
+    def setModuleService(self, ms):
+        # This method is called by methods of Manager below
+        self._v_module_service = ms
 
-    def setManager(self, ctx):
-        self._v_manager = ctx
+    # The next three methods are called by the persistent module manager
 
     def findModule(self, name):
-        return self._v_manager.findModule(name)
+        return self._v_module_service.findModule(name)
 
     def setModule(self, name, module):
-        return self._v_manager.setModule(name, module)
+        return self._v_module_service.setModule(name, module)
 
     def delModule(self, name):
-        return self._v_manager.delModule(name)
+        return self._v_module_service.delModule(name)
+
+    def __getstate__(self):
+        # So pickling this object doesn't include the module service
+        return {}
 
 class Manager(Persistent):
 
-    __implements__ = IPersistentModuleManager
+    implements(IPersistentModuleManager, IDeleteNotifiable)
 
     # The registry for the manager is the ServiceManager.
     # The association between this manager and the registry
     # is static, but the static association can't be stored
     # explicitly in Zope.
 
-    # XXX There is no locking, but every call to setManager() for a
-    # particular instance should have the same manager argument.
+    # XXX There is no locking, but every call to setModuleService()
+    # for a particular instance should have the same manager argument.
 
     # XXX It would be nice if the lookup via getServiceManager()
     # occurred less often.  Best would be to do it only when the
@@ -66,16 +89,16 @@
         self._manager = PersistentModuleManager(self._registry)
 
     def new(self, name, source):
-        self._registry.setManager(getServiceManager(self))
+        self._registry.setModuleService(getServiceManager(self))
         self._manager.new(name, source)
 
     def update(self, source):
-        self._registry.setManager(getServiceManager(self))
+        self._registry.setModuleService(getServiceManager(self))
         self._manager.update(source)
 
-    def remove(self, source):
-        self._registry.setManager(getServiceManager(self))
-        self._manager.remove(source)
+    def remove(self):
+        self._registry.setModuleService(getServiceManager(self))
+        self._manager.remove()
 
     new = ContextMethod(new)
     update = ContextMethod(update)
@@ -83,3 +106,37 @@
 
     name = property(lambda self: self._manager.name)
     source = property(lambda self: self._manager.source)
+
+    def beforeDeleteHook(self, obj, container):
+        obj.remove()
+    beforeDeleteHook = ContextMethod(beforeDeleteHook)
+
+
+class ModuleAdapter(ObjectEntryAdapter):
+
+    implements(IObjectFile)
+
+    def getBody(self):
+        return self.context.source
+
+    def setBody(self, source):
+        self.context.update(source)
+
+    def extra(self):
+        return AttrMapping(self.context, ("name",))
+
+
+class ModuleFactory(object):
+
+    implements(IFileFactory)
+
+    def __init__(self, context):
+        self.context = context
+
+    def __call__(self, name, content_type, data):
+        assert name.endswith(".py")
+        name = name[:-3]
+        m = Manager()
+        m = ContextWrapper(m, self.context)
+        m.new(name, data)
+        return m


=== Zope3/src/zope/app/services/pagefolder.py 1.5 => 1.5.10.1 ===
--- Zope3/src/zope/app/services/pagefolder.py:1.5	Thu May  1 15:35:34 2003
+++ Zope3/src/zope/app/services/pagefolder.py	Sun Jun 22 10:23:27 2003
@@ -13,7 +13,7 @@
 ##############################################################################
 """Page Folders
 
-Page folders support easy creation and configuration of page views
+Page folders support easy creation and registration of page views
 using folders of templates.
 
 $Id$
@@ -21,20 +21,26 @@
 __metaclass__ = type
 
 from zope.app.container.btree import BTreeContainer
+from zope.app.container.zopecontainer import ZopeContainerDecorator
 from zope.app.interfaces.services.view import IZPTTemplate
 from zope.publisher.interfaces.browser import IBrowserPresentation
 from zope.app.traversing import getPath
-from zope.proxy.context import getItem, ContextMethod
-from zope.app.interfaces.services.configuration import Active
-from zope.app.services.configuration import ConfigurationManagerContainer
-from zope.proxy.introspection import removeAllProxies
-from zope.app.services.view import PageConfiguration
+from zope.app.context import getItem
+from zope.context import ContextMethod
+from zope.app.interfaces.services.registration import ActiveStatus
+from zope.app.services.registration import RegistrationManagerContainer
+from zope.proxy import removeAllProxies
+from zope.app.services.view import PageRegistration
 from zope.app.interfaces.services.pagefolder import IPageFolder
-from zope.app.interfaces.services.configuration import IConfigurationManager
+from zope.app.interfaces.services.registration import IRegistrationManager
+from zope.app.interfaces.file import IDirectoryFactory
+from zope.app.fssync.classes import ObjectEntryAdapter, AttrMapping
+from zope.app.interfaces.fssync import IObjectDirectory
+from zope.interface import implements
 
-class PageFolder(ConfigurationManagerContainer, BTreeContainer):
+class PageFolder(RegistrationManagerContainer, BTreeContainer):
 
-    __implements__ = IPageFolder
+    implements(IPageFolder)
 
     presentationType = IBrowserPresentation
     layer = "default"
@@ -45,45 +51,76 @@
     template = None
 
     def setObject(self, name, object):
-        if IConfigurationManager.isImplementedBy(object):
-            # We allow configuration managers as well as templates
+        if (IRegistrationManager.isImplementedBy(object) or
+            IZPTTemplate.isImplementedBy(object)):
             return super(PageFolder, self).setObject(name, object)
-
-        if not IZPTTemplate.isImplementedBy(object):
+        else:
             raise TypeError("Can only add templates", object)
 
-        # super() does not work on a context wrapped instance
-        base = removeAllProxies(self)
-
-        name = super(PageFolder, base).setObject(name, object)
-        template = getItem(self, name)
-        template = getPath(template)
-        config = PageConfiguration(
-            forInterface=self.forInterface,
-            viewName=name,
-            permission=self.permission,
-            class_=self.factoryName,
-            template=template,
-            layer=self.layer,
-            )
-        configure = self.getConfigurationManager()
-        id = configure.setObject('', config)
-        config = getItem(configure, id)
-        config.status = Active
-        return name
-
-    setObject = ContextMethod(setObject)
-
     def configured(self):
         return (hasattr(self, 'permission')
                 and hasattr(self, 'forInterface')
                 )
 
     def activated(self):
-        "See IConfiguration"
+        "See IRegistration"
 
     def deactivated(self):
-        "See IConfiguration"
+        "See IRegistration"
+
+
+_attrNames = (
+    'factoryName',
+    'forInterface',
+    'layer',
+    'permission',
+    )
+
+class PageFolderAdapter(ObjectEntryAdapter):
+    """ObjectFile adapter for PageFolder objects."""
+
+    implements(IObjectDirectory)
+
+    def contents(self):
+        return self.context.items()
+
+    def extra(self):
+        return AttrMapping(self.context, _attrNames)
+
+
+class PageFolderFactory:
+
+    implements(IDirectoryFactory)
+
+    def __init__(self, context):
+        self.context = context
+
+    def __call__(self, name):
+        return PageFolder()
+
+class PageFolderContextDecorator(ZopeContainerDecorator):
+
+    def setObject(self, name, object):
+        name = super(PageFolderContextDecorator, self).setObject(name, object)
+
+        # If a template is added, we need to configure it too.
+        if IZPTTemplate.isImplementedBy(object):
+            template = getItem(self, name)
+            template = getPath(template)
+            config = PageRegistration(
+                forInterface=self.forInterface,
+                viewName=name,
+                permission=self.permission,
+                class_=self.factoryName,
+                template=template,
+                layer=self.layer,
+                )
+            configure = self.getRegistrationManager()
+            id = configure.setObject('', config)
+            config = getItem(configure, id)
+            config.status = ActiveStatus
+        return name
+
 
 # XXX Backward compatibility. This is needed to support old pickles.
 ViewPackage = PageFolder


=== Zope3/src/zope/app/services/principalannotation.py 1.5 => 1.5.14.1 ===
--- Zope3/src/zope/app/services/principalannotation.py:1.5	Tue Apr  8 13:43:43 2003
+++ Zope3/src/zope/app/services/principalannotation.py	Sun Jun 22 10:23:27 2003
@@ -20,14 +20,17 @@
 
 # Zope3 imports
 from persistence import Persistent
+from persistence.dict import PersistentDict
 from zodb.btrees.OOBTree import OOBTree
-from zope.app.component.nextservice import getNextService
-from zope.proxy.context import ContextMethod
-from zope.proxy.context import ContextWrapper
+from zope.app.component.nextservice import queryNextService
+from zope.context import ContextMethod
+from zope.app.context import ContextWrapper
 from zope.app.interfaces.annotation import IAnnotations
+from zope.interface import implements
 
 # Sibling imports
-from zope.app.interfaces.services.principalannotation import IPrincipalAnnotationService
+from zope.app.interfaces.services.principalannotation \
+     import IPrincipalAnnotationService
 from zope.app.interfaces.services.service import ISimpleService
 
 class PrincipalAnnotationService(Persistent):
@@ -36,8 +39,7 @@
     The service ID is 'PrincipalAnnotation'.
     """
 
-    __implements__ = (IPrincipalAnnotationService, Persistent.__implements__,
-                      ISimpleService)
+    implements(IPrincipalAnnotationService, ISimpleService)
 
     def __init__(self):
         self.annotations = OOBTree()
@@ -45,54 +47,76 @@
 
     # implementation of IPrincipalAnnotationService
 
-    def getAnnotation(self, principalId):
+    def getAnnotations(self, principal):
         """Return object implementing IAnnotations for the given principal.
 
         If there is no IAnnotations it will be created and then returned.
         """
-        if not self.annotations.has_key(principalId):
-            self.annotations[principalId] = Annotations(principalId)
-        return ContextWrapper(self.annotations[principalId], self, name=principalId)
 
-    getAnnotation = ContextMethod(getAnnotation)
+        return self.getAnnotationsById(principal.getId())
+    getAnnotations = ContextMethod(getAnnotations)
 
-    def hasAnnotation(self, principalId):
+    def getAnnotationsById(self, principalId):
+        """Return object implementing IAnnotations for the given principal.
+
+        If there is no IAnnotations it will be created and then returned.
+        """
+
+        annotations = self.annotations.get(principalId)
+        if annotations is None:
+            annotations = Annotations(principalId, store=self.annotations)
+
+        return ContextWrapper(annotations, self, name=principalId)
+
+    getAnnotationsById = ContextMethod(getAnnotationsById)
+
+    def hasAnnotations(self, principal):
         """Return boolean indicating if given principal has IAnnotations."""
-        return self.annotations.has_key(principalId)
+        return principal.getId() in self.annotations
 
 
 class Annotations(Persistent):
     """Stores annotations."""
 
-    __implements__ = IAnnotations, Persistent.__implements__
+    implements(IAnnotations)
 
-    def __init__(self, principalId):
+    def __init__(self, principalId, store=None):
         self.principalId = principalId
-        self.data = OOBTree()
+        self.data = PersistentDict() # We don't really expect that many
+
+        # _v_store is used to remember a mapping object that we should
+        # be saved in if we ever change
+        self._v_store = store
 
     def __getitem__(wrapped_self, key):
         try:
             return wrapped_self.data[key]
         except KeyError:
             # We failed locally: delegate to a higher-level service.
-            service = getNextService(wrapped_self, 'PrincipalAnnotation')
-            if service:
-                return service.getAnnotation(wrapped_self.principalId)[key]
+            service = queryNextService(wrapped_self, 'PrincipalAnnotation')
+            if service is not None:
+                annotations = service.getAnnotationsById(
+                    wrapped_self.principalId)
+                return annotations[key]
             raise
 
     __getitem__ = ContextMethod(__getitem__)
 
     def __setitem__(self, key, value):
+
+        if getattr(self, '_v_store', None) is not None:
+            # _v_store is used to remember a mapping object that we should
+            # be saved in if we ever change
+            self._v_store[self.principalId] = self
+            del self._v_store
+
         self.data[key] = value
 
     def __delitem__(self, key):
         del self.data[key]
 
     def get(self, key, default=None):
-        try:
-            return self.data[key]
-        except KeyError:
-            return default
+        return self.data.get(key, default)
 
 
 class AnnotationsForPrincipal(object):
@@ -105,4 +129,4 @@
         self.service = service
 
     def __call__(self, principal):
-        return self.service.getAnnotation(principal.getId())
+        return self.service.getAnnotationsById(principal.getId())


=== Zope3/src/zope/app/services/queryfield.py 1.2 => 1.2.22.1 ===
--- Zope3/src/zope/app/services/queryfield.py:1.2	Tue Feb 11 10:59:56 2003
+++ Zope3/src/zope/app/services/queryfield.py	Sun Jun 22 10:23:27 2003
@@ -19,7 +19,7 @@
 from zope.schema import Tuple
 from zope.schema.interfaces import ValidationError
 from zope.component import getAdapter
-from zope.interface.implements import implements
+from zope.interface import classImplements
 # See end of file for further imports
 
 class QueryProcessorsField(Tuple):
@@ -48,5 +48,5 @@
 from zope.app.interfaces.services.query import IQueryProcessorsField
 from zope.app.interfaces.services.query import IQueryProcessable
 from zope.app.interfaces.services.query import IQueryProcessor
-implements(QueryProcessorsField, IQueryProcessorsField)
+classImplements(QueryProcessorsField, IQueryProcessorsField)
 


=== Zope3/src/zope/app/services/role.py 1.4 => 1.4.18.1 ===
--- Zope3/src/zope/app/services/role.py:1.4	Tue Mar 11 11:11:22 2003
+++ Zope3/src/zope/app/services/role.py	Sun Jun 22 10:23:27 2003
@@ -22,9 +22,10 @@
 from zope.app.container.btree import BTreeContainer
 from zope.app.interfaces.security import IRoleService
 from zope.app.interfaces.container import IContainer
-from zope.proxy.context import ContextMethod
+from zope.context import ContextMethod
 from zope.app.component.nextservice import getNextService
 from zope.app.interfaces.services.service import ISimpleService
+from zope.interface import implements
 
 class Role(Role, Persistent):
     "Persistent Role"
@@ -34,7 +35,7 @@
 
 class RoleService(BTreeContainer):
 
-    __implements__ = ILocalRoleService, ISimpleService
+    implements(ILocalRoleService, ISimpleService)
 
     def getRole(wrapped_self, rid):
         '''See interface IRoleService'''


=== Zope3/src/zope/app/services/service.py 1.18 => 1.18.10.1 ===
--- Zope3/src/zope/app/services/service.py:1.18	Thu May  1 15:35:34 2003
+++ Zope3/src/zope/app/services/service.py	Sun Jun 22 10:23:27 2003
@@ -31,12 +31,14 @@
 from zodb.code.module import PersistentModule
 from zodb.code.module import PersistentModuleRegistry
 
+from zope.interface import implements
+
 from zope.component import getServiceManager
 from zope.component.exceptions import ComponentLookupError
 
-from zope.proxy.context import ContextMethod
-from zope.proxy.context import ContextWrapper
-from zope.proxy.introspection import removeAllProxies
+from zope.context import ContextMethod
+from zope.app.context import ContextWrapper
+from zope.proxy import removeAllProxies
 
 from zope.app.component.nextservice import getNextService
 from zope.app.component.nextservice import getNextServiceManager
@@ -44,30 +46,28 @@
 from zope.app.interfaces.container import IContainer
 from zope.app.interfaces.services.service import IBindingAware
 from zope.app.interfaces.services.module import IModuleService
-from zope.app.interfaces.services.service import IServiceConfiguration
+from zope.app.interfaces.services.service import IServiceRegistration
 from zope.app.interfaces.services.service import IServiceManager
 
-# XXX This makes no sense?
+# Declare a tuple of all types we consider to be modules
+# (used as 2nd argument to isinstance() in method resolve() below)
 ModuleType = type(IModuleService), PersistentModule
 
-from zope.app.services.configuration import ConfigurationStatusProperty
-from zope.app.services.configuration import NameComponentConfigurable
-from zope.app.services.configuration import NamedComponentConfiguration
+from zope.app.services.registration import RegistrationStatusProperty
+from zope.app.services.registration import NameComponentRegistry
+from zope.app.services.registration import NamedComponentRegistration
 from zope.app.services.folder import SiteManagementFolders
 from zope.app.interfaces.services.service import ILocalService
 
 from zope.app.traversing import getPath
 
-class ServiceManager(PersistentModuleRegistry, NameComponentConfigurable):
+class ServiceManager(PersistentModuleRegistry, NameComponentRegistry):
 
-    __implements__ = (IServiceManager, IContainer,
-                      PersistentModuleRegistry.__implements__,
-                      NameComponentConfigurable.__implements__,
-                      IModuleService)
+    implements(IServiceManager, IContainer, IModuleService)
 
     def __init__(self):
-        super(ServiceManager, self).__init__()
-        NameComponentConfigurable.__init__(self)
+        PersistentModuleRegistry.__init__(self)
+        NameComponentRegistry.__init__(self)
         self.Packages = SiteManagementFolders()
 
     def getServiceDefinitions(wrapped_self):
@@ -231,6 +231,9 @@
     def setObject(self, name, value):
         return self.Packages.setObject(name, value)
 
+    def __delitem__(self, key):
+        return self.Packages.__delitem__(key)
+
     def findModule(wrapped_self, name):
         # override to pass call up to next service manager
         mod = super(ServiceManager,
@@ -292,19 +295,20 @@
     resolve = ContextMethod(resolve)
 
 
-class ServiceConfiguration(NamedComponentConfiguration):
+class ServiceRegistration(NamedComponentRegistration):
+
+    __doc__ = IServiceRegistration.__doc__
 
-    __doc__ = IServiceConfiguration.__doc__
+    implements(IServiceRegistration)
 
-    __implements__ = (IServiceConfiguration,
-                      NamedComponentConfiguration.__implements__)
+    serviceType = 'Services'
 
-    status = ConfigurationStatusProperty('Services')
+    status = RegistrationStatusProperty()
 
     label = "Service"
 
     def __init__(self, name, path, context=None):
-        super(ServiceConfiguration, self).__init__(name, path)
+        super(ServiceRegistration, self).__init__(name, path)
         if context is not None:
             # Check that the object implements stuff we need
             wrapped_self = ContextWrapper(self, context)
@@ -336,3 +340,23 @@
 
     def usageSummary(self):
         return self.name + " Service"
+
+
+# XXX Pickle backward compatability
+ServiceConfiguration = ServiceRegistration
+
+# Fssync stuff
+
+from zope.app.fssync.classes import AttrMapping
+from zope.app.content.fssync import DirectoryAdapter
+
+_smattrs = (
+    '_modules',                         # PersistentModuleRegistry
+    '_bindings',                        # NameComponentRegistry
+)
+
+class ServiceManagerAdapter(DirectoryAdapter):
+
+    def extra(self):
+        obj = removeAllProxies(self.context)
+        return AttrMapping(obj, _smattrs)


=== Zope3/src/zope/app/services/servicecontainer.py 1.2 => 1.2.24.1 ===
--- Zope3/src/zope/app/services/servicecontainer.py:1.2	Tue Feb  4 05:30:07 2003
+++ Zope3/src/zope/app/services/servicecontainer.py	Sun Jun 22 10:23:27 2003
@@ -11,38 +11,45 @@
 # FOR A PARTICULAR PURPOSE.
 #
 ##############################################################################
+"""ServiceManagerContainer implementation.
+
+$Id$
+"""
 
 from zope.component.exceptions import ComponentLookupError
-from zope.app.interfaces.services.service import IServiceManagerContainer  
+from zope.app.interfaces.services.service import IServiceManagerContainer
 from zope.component.interfaces import IServiceService
+from zope.interface import implements
 
 class ServiceManagerContainer:
 
-    __implements__ =  IServiceManagerContainer
+    """Implement access to the service manager (++etc++site).
+
+    This is a mix-in that implements the IServiceManagerContainer
+    interface; for example, it is used by the Folder implementation.
+    """
+
+    implements(IServiceManagerContainer)
+
+    __sm = None
 
     def hasServiceManager(self):
-        '''See interface IReadServiceManagerContainer'''
-        return hasattr(self, '_ServiceManagerContainer__sm')
+        return self.__sm is not None
 
     def getServiceManager(self):
-        '''See interface IReadServiceManagerContainer'''
-
-        try:
+        if self.__sm is not None:
             return self.__sm
-        except AttributeError:
+        else:
             raise ComponentLookupError('no service manager defined')
 
     def queryServiceManager(self, default=None):
-        '''See interface IReadServiceManagerContainer'''
-
-        return getattr(self, '_ServiceManagerContainer__sm', default)
+        if self.__sm is not None:
+            return self.__sm
+        else:
+            return default
 
     def setServiceManager(self, sm):
-        '''See interface IWriteServiceManagerContainer'''
-
         if IServiceService.isImplementedBy(sm):
             self.__sm = sm
         else:
             raise ValueError('setServiceManager requires an IServiceService')
-
-


=== Zope3/src/zope/app/services/session.py 1.9 => 1.9.18.1 ===
--- Zope3/src/zope/app/services/session.py:1.9	Tue Mar 11 11:11:22 2003
+++ Zope3/src/zope/app/services/session.py	Sun Jun 22 10:23:27 2003
@@ -26,6 +26,7 @@
 from persistence.dict import PersistentDict
 from zope.server.http.http_date import build_http_date
 from zope.component import getService
+from zope.interface import implements
 
 # Sibling imports
 from zope.app.interfaces.services.session import ISessionService
@@ -43,8 +44,7 @@
 class CookieSessionService(Persistent):
     """Session service implemented using cookies."""
 
-    __implements__ = (Persistent.__implements__, ISessionService,
-                      IConfigureSessionService, ISimpleService)
+    implements(ISessionService, IConfigureSessionService, ISimpleService)
 
     def __init__(self):
         self.dataManagers = PersistentDict()


=== Zope3/src/zope/app/services/utility.py 1.6 => 1.6.10.1 ===
--- Zope3/src/zope/app/services/utility.py:1.6	Thu May  1 15:35:34 2003
+++ Zope3/src/zope/app/services/utility.py	Sun Jun 22 10:23:27 2003
@@ -17,24 +17,25 @@
 $Id$
 """
 
+from zope.interface import implements
 from persistence.dict import PersistentDict
 from persistence import Persistent
 from zope.app.component.nextservice import getNextService
-from zope.app.interfaces.services.configuration import IConfigurable
+from zope.app.interfaces.services.registration import IRegistry
 from zope.app.interfaces.services.service import ISimpleService
-from zope.app.interfaces.services.utility import IUtilityConfiguration
+from zope.app.interfaces.services.utility import IUtilityRegistration
 from zope.app.interfaces.services.utility import ILocalUtilityService
-from zope.app.services.configuration import ConfigurationRegistry
-from zope.app.services.configuration import ConfigurationStatusProperty
-from zope.app.services.configuration import ComponentConfiguration
+from zope.app.services.registration import RegistrationStack
+from zope.app.services.registration import RegistrationStatusProperty
+from zope.app.services.registration import ComponentRegistration
 from zope.component.exceptions import ComponentLookupError
 from zope.interface.implementor import ImplementorRegistry
-from zope.proxy.context import ContextAware
-from zope.proxy.context import ContextWrapper
+from zope.context import ContextMethod
+from zope.app.context import ContextWrapper
 
-class LocalUtilityService(Persistent, ContextAware):
+class LocalUtilityService(Persistent):
 
-    __implements__ = ILocalUtilityService, IConfigurable, ISimpleService
+    implements(ILocalUtilityService, IRegistry, ISimpleService)
 
     def __init__(self):
         self._utilities = PersistentDict()
@@ -44,48 +45,55 @@
         if utility is None:
             raise ComponentLookupError("utility", interface, name)
         return utility
+    getUtility = ContextMethod(getUtility)
 
     def queryUtility(self, interface, default=None, name=''):
-        registry = self.queryConfigurations(name, interface)
-        if registry is not None:
-            configuration = registry.active()
-            if configuration is not None:
-                return configuration.getComponent()
+        stack = self.queryRegistrations(name, interface)
+        if stack is not None:
+            registration = stack.active()
+            if registration is not None:
+                return registration.getComponent()
 
         next = getNextService(self, "Utilities")
         return next.queryUtility(interface, default, name)
+    queryUtility = ContextMethod(queryUtility)
 
-    def queryConfigurationsFor(self, configuration, default=None):
-        return self.queryConfigurations(configuration.name,
-                                        configuration.interface,
+    def queryRegistrationsFor(self, registration, default=None):
+        return self.queryRegistrations(registration.name,
+                                        registration.interface,
                                         default)
+    queryRegistrationsFor = ContextMethod(queryRegistrationsFor)
 
-    def queryConfigurations(self, name, interface, default=None):
+    def queryRegistrations(self, name, interface, default=None):
         utilities = self._utilities.get(name)
         if utilities is None:
             return default
-        registry = utilities.getRegistered(interface)
-        if registry is None:
+        stack = utilities.getRegistered(interface)
+        if stack is None:
             return default
 
-        return ContextWrapper(registry, self)
+        return ContextWrapper(stack, self)
+    queryRegistrations = ContextMethod(queryRegistrations)
 
-    def createConfigurationsFor(self, configuration):
-        return self.createConfigurations(configuration.name,
-                                         configuration.interface)
+    def createRegistrationsFor(self, registration):
+        return self.createRegistrations(registration.name,
+                                         registration.interface)
 
-    def createConfigurations(self, name, interface):
+    createRegistrationsFor = ContextMethod(createRegistrationsFor)
+
+    def createRegistrations(self, name, interface):
         utilities = self._utilities.get(name)
         if utilities is None:
             utilities = ImplementorRegistry(PersistentDict())
             self._utilities[name] = utilities
 
-        registry = utilities.getRegistered(interface)
-        if registry is None:
-            registry = ConfigurationRegistry()
-            utilities.register(interface, registry)
+        stack = utilities.getRegistered(interface)
+        if stack is None:
+            stack = RegistrationStack()
+            utilities.register(interface, stack)
 
-        return ContextWrapper(registry, self)
+        return ContextWrapper(stack, self)
+    createRegistrations = ContextMethod(createRegistrations)
 
     def getRegisteredMatching(self):
         L = []
@@ -95,36 +103,42 @@
                     continue
                 L.append((iface, name, ContextWrapper(cr, self)))
         return L
+    getRegisteredMatching = ContextMethod(getRegisteredMatching)
 
 
-class UtilityConfiguration(ComponentConfiguration):
-    """Utility component configuration for persistent components
+class UtilityRegistration(ComponentRegistration):
+    """Utility component registration for persistent components
 
-    This configuration configures persistent components in packages to
+    This registration configures persistent components in packages to
     be utilities.
 
     """
 
-    status = ConfigurationStatusProperty('Utilities')
+    serviceType = 'Utilities'
+
+    status = RegistrationStatusProperty()
 
-    __implements__ = (IUtilityConfiguration,
-                      ComponentConfiguration.__implements__)
+    implements(IUtilityRegistration)
 
     def __init__(self, name, interface, component_path, permission=None):
-        ComponentConfiguration.__init__(self, component_path, permission)
+        ComponentRegistration.__init__(self, component_path, permission)
         self.name = name
         self.interface = interface
 
     def usageSummary(self):
-        # Override IConfiguration.usageSummary()
+        # Override IRegistration.usageSummary()
         s = "%s utility" % self.interface.__name__
         if self.name:
             s += " named %s" % self.name
         return s
 
     def getInterface(self):
-        # ComponentConfiguration calls this when you specify a
+        # ComponentRegistration calls this when you specify a
         # permission; it needs the interface to create a security
         # proxy for the interface with the given permission.
         # XXX Smells like a dead chicken to me.
         return self.interface
+
+
+# XXX Pickle backward compatability
+UtilityConfiguration = UtilityRegistration


=== Zope3/src/zope/app/services/utility.zcml 1.3 => 1.3.14.1 ===
--- Zope3/src/zope/app/services/utility.zcml:1.3	Thu Apr  3 17:05:34 2003
+++ Zope3/src/zope/app/services/utility.zcml	Sun Jun 22 10:23:27 2003
@@ -7,17 +7,17 @@
       />
   <require
     permission="zope.ManageServices"
-    attributes="getRegisteredMatching queryConfigurations"
+    attributes="getRegisteredMatching queryRegistrations"
     />
 </content>
 
-<content class=".utility.UtilityConfiguration">
+<content class=".utility.UtilityRegistration">
   <require
     permission="zope.ManageServices"
-    interface="zope.app.interfaces.services.utility.IUtilityConfiguration
+    interface="zope.app.interfaces.services.utility.IUtilityRegistration
                zope.app.interfaces.container.IAddNotifiable
                zope.app.interfaces.container.IDeleteNotifiable"
-    set_schema="zope.app.interfaces.services.utility.IUtilityConfiguration"
+    set_schema="zope.app.interfaces.services.utility.IUtilityRegistration"
     />
  </content>
 


=== Zope3/src/zope/app/services/view.py 1.18 => 1.18.4.1 ===
--- Zope3/src/zope/app/services/view.py:1.18	Tue May  6 07:18:54 2003
+++ Zope3/src/zope/app/services/view.py	Sun Jun 22 10:23:27 2003
@@ -24,44 +24,45 @@
 from zope.component.interfaces import IViewService
 from zope.component.exceptions import ComponentLookupError
 from zope.component import getServiceManager
-from zope.app.interfaces.services.configuration import IConfigurable
-from zope.app.services.configuration import ConfigurationRegistry
-from zope.app.services.configuration import SimpleConfiguration
-from zope.proxy.context import ContextWrapper
-from zope.proxy.context import ContextMethod
-from zope.app.services.configuration import ConfigurationStatusProperty
+from zope.app.interfaces.services.registration import IRegistry
+from zope.app.services.registration import RegistrationStack
+from zope.app.services.registration import SimpleRegistration
+from zope.app.context import ContextWrapper
+from zope.context import ContextMethod
+from zope.app.services.registration import RegistrationStatusProperty
 from zope.app.component.nextservice import getNextService
 from zope.component import getSkin
+from zope.interface import implements
 
 from zope.security.checker import NamesChecker, ProxyFactory
 
-from zope.proxy.introspection import removeAllProxies
+from zope.proxy import removeAllProxies
 from zope.app.traversing import getRoot, traverse
 from zope.exceptions import NotFoundError
 
-from zope.app.interfaces.services.view import IViewConfiguration
-from zope.app.interfaces.services.view import IPageConfiguration
+from zope.app.interfaces.services.view import IViewRegistration
+from zope.app.interfaces.services.view import IPageRegistration
 from zope.app.services.adapter import PersistentAdapterRegistry
 from zope.configuration.exceptions import ConfigurationError
 from zope.app.interfaces.services.service import ISimpleService
 
 class ViewService(Persistent):
 
-    __implements__ = IViewService, IConfigurable, ISimpleService
+    implements(IViewService, IRegistry, ISimpleService)
 
     def __init__(self):
         self._layers = PersistentDict()
 
-    def queryConfigurationsFor(self, configuration, default=None):
-        "See IConfigurable"
-        return self.queryConfigurations(
-            configuration.viewName, configuration.layer,
-            configuration.forInterface, configuration.presentationType,
+    def queryRegistrationsFor(self, registration, default=None):
+        "See IRegistry"
+        return self.queryRegistrations(
+            registration.viewName, registration.layer,
+            registration.forInterface, registration.presentationType,
             default)
 
-    queryConfigurationsFor = ContextMethod(queryConfigurationsFor)
+    queryRegistrationsFor = ContextMethod(queryRegistrationsFor)
 
-    def queryConfigurations(self, name, layer,
+    def queryRegistrations(self, name, layer,
                             forInterface, presentationType, default=None):
 
         names = self._layers.get(layer)
@@ -80,17 +81,17 @@
 
         return ContextWrapper(registry, self)
 
-    queryConfigurations = ContextMethod(queryConfigurations)
+    queryRegistrations = ContextMethod(queryRegistrations)
 
-    def createConfigurationsFor(self, configuration):
-        "See IConfigurable"
-        return self.createConfigurations(
-            configuration.viewName, configuration.layer,
-            configuration.forInterface, configuration.presentationType)
+    def createRegistrationsFor(self, registration):
+        "See IRegistry"
+        return self.createRegistrations(
+            registration.viewName, registration.layer,
+            registration.forInterface, registration.presentationType)
 
-    createConfigurationsFor = ContextMethod(createConfigurationsFor)
+    createRegistrationsFor = ContextMethod(createRegistrationsFor)
 
-    def createConfigurations(self,
+    def createRegistrations(self,
                              viewName, layer, forInterface, presentationType):
 
         names = self._layers.get(layer)
@@ -107,12 +108,12 @@
             forInterface, presentationType)
 
         if registry is None:
-            registry = ConfigurationRegistry()
+            registry = RegistrationStack()
             adapter_registry.register(forInterface, presentationType, registry)
 
         return ContextWrapper(registry, self)
 
-    createConfigurations = ContextMethod(createConfigurations)
+    createRegistrations = ContextMethod(createRegistrations)
 
     def getView(self, object, name, request):
         view = self.queryView(object, name, request)
@@ -214,11 +215,13 @@
 
         return result
 
-class ViewConfiguration(SimpleConfiguration):
+class ViewRegistration(SimpleRegistration):
 
-    __implements__ = IViewConfiguration, SimpleConfiguration.__implements__
+    implements(IViewRegistration)
 
-    status = ConfigurationStatusProperty('Views')
+    serviceType = 'Views'
+
+    status = RegistrationStatusProperty()
 
     _what = "View" # For usageSummary(); subclass may override
 
@@ -247,9 +250,9 @@
             s = "%s in layer %s" % (s, self.layer)
         return s
 
-class PageConfiguration(ViewConfiguration):
+class PageRegistration(ViewRegistration):
 
-    __implements__ = IPageConfiguration, ViewConfiguration.__implements__
+    implements(IPageRegistration)
 
     # We only care about browser pages
     presentationType = IBrowserPresentation
@@ -261,7 +264,7 @@
                  class_=None, template=None, attribute=None,
                  layer='default'):
 
-        super(PageConfiguration, self).__init__(
+        super(PageRegistration, self).__init__(
             forInterface, viewName, self.presentationType,
             class_, permission, layer)
 
@@ -286,19 +289,19 @@
     def validate(self):
         if self.template and self.attribute:
             raise ConfigurationError(
-                "PageConfiguration for %s view name %s: "
+                "PageRegistration for %s view name %s: "
                 "Cannot have both 'template' and 'attribute' at the same time." %
                 (self.forInterface, self.viewName))
 
         if not self.template and not self.attribute:
             raise ConfigurationError(
-                "PageConfiguration for %s view name %s: "
+                "PageRegistration for %s view name %s: "
                 "Should have a 'template' or 'attribute' attribute." %
                 (self.forInterface, self.viewName))
 
         if not self.class_ and self.attribute:
             raise ConfigurationError(
-                "PageConfiguration for %s view name %s: "
+                "PageRegistration for %s view name %s: "
                 "Cannot have an 'attribute' without a 'class_'." %
                 (self.forInterface, self.viewName))
 
@@ -332,7 +335,6 @@
 
     getView = ContextMethod(getView)
 
-
 class DefaultClass:
 
     def __init__(self, context, request):
@@ -349,3 +351,8 @@
         if not template_usage:
             kw["template_usage"] = template_usage
         return self.template.render(self.view, *args, **kw)
+
+
+# XXX Pickle backward compatability
+PageConfiguration = PageRegistration
+ViewConfiguration = ViewRegistration


=== Zope3/src/zope/app/services/zpt.py 1.10 => 1.10.10.1 ===
--- Zope3/src/zope/app/services/zpt.py:1.10	Thu May  1 15:35:34 2003
+++ Zope3/src/zope/app/services/zpt.py	Sun Jun 22 10:23:27 2003
@@ -19,16 +19,19 @@
 
 from persistence import Persistent
 
+from zope.interface import implements
 from zope.security.proxy import ProxyFactory
 from zope.pagetemplate.pagetemplate import PageTemplate
 from zope.app.pagetemplate.engine import AppPT
 from zope.app.interfaces.services.view import IZPTTemplate
 from zope.app.interfaces.index.text import ISearchableText
 from zope.app.interfaces.file import IReadFile, IWriteFile, IFileFactory
+from zope.app.fssync.classes import ObjectEntryAdapter, AttrMapping
+from zope.app.interfaces.fssync import IObjectFile
 
 class ZPTTemplate(AppPT, PageTemplate, Persistent):
 
-    __implements__ = IZPTTemplate
+    implements(IZPTTemplate)
 
     contentType = 'text/html'
     expand = False
@@ -71,7 +74,7 @@
 tag = re.compile(r"<[^>]+>")
 class SearchableText:
 
-    __implements__ = ISearchableText
+    implements(ISearchableText)
     __used_for__ = IZPTTemplate
 
     def __init__(self, page):
@@ -95,7 +98,7 @@
 
 class ReadFile:
 
-    __implements__ = IReadFile
+    implements(IReadFile)
 
     def __init__(self, context):
         self.context = context
@@ -105,11 +108,11 @@
 
     def size(self):
         return len(self.context.source)
-        
+
 
 class WriteFile:
 
-    __implements__ = IWriteFile
+    implements(IWriteFile)
 
     def __init__(self, context):
         self.context = context
@@ -120,7 +123,7 @@
 
 class ZPTFactory:
 
-    __implements__ = IFileFactory
+    implements(IFileFactory)
 
     def __init__(self, context):
         self.context = context
@@ -129,3 +132,21 @@
         r = ZPTTemplate()
         r.source = data
         return r
+
+
+class ZPTPageAdapter(ObjectEntryAdapter):
+    """ObjectFile adapter for ZPTTemplate objects."""
+
+    implements(IObjectFile)
+
+    def getBody(self):
+        return self.context.source
+
+    def setBody(self, data):
+        # Convert the data to Unicode, since that's what ZPTTemplate
+        # wants; it's normally read from a file so it'll be bytes.
+        # XXX This will die if it's not ASCII.  Guess encoding???
+        self.context.source = unicode(data)
+
+    def extra(self):
+        return AttrMapping(self.context, ('contentType', 'expand'))

=== Removed File Zope3/src/zope/app/services/configuration.py ===