[Zope3-checkins] CVS: Zope3/src/zope/app/services - utility.py:1.2 utility.zcml:1.2 README.txt:1.2 configure.zcml:1.21
Jim Fulton
jim@zope.com
Fri, 21 Mar 2003 16:02:20 -0500
Update of /cvs-repository/Zope3/src/zope/app/services
In directory cvs.zope.org:/tmp/cvs-serv18855/src/zope/app/services
Modified Files:
configure.zcml
Added Files:
utility.py utility.zcml README.txt
Log Message:
Added a partial utility service implementation.
This *still* needs tests. Yes, I'm breaking the rules. But some folks
are waiting on this. Tests will come soon.
=== Zope3/src/zope/app/services/utility.py 1.1 => 1.2 ===
--- /dev/null Fri Mar 21 16:02:20 2003
+++ Zope3/src/zope/app/services/utility.py Fri Mar 21 16:02:19 2003
@@ -0,0 +1,151 @@
+##############################################################################
+# 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.
+##############################################################################
+"""Local utility service implementation.
+
+Besides being functional, this module also serves as an example of
+creating a local service; see README.txt.
+
+$Id$
+"""
+
+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.service import ISimpleService
+from zope.app.interfaces.services.utility import IUtilityConfiguration
+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.configuration import SimpleConfiguration
+from zope.component.exceptions import ComponentLookupError
+from zope.component import getAdapter
+from zope.component.interfaces import IUtilityService
+from zope.interface.implementor import ImplementorRegistry
+from zope.proxy.context import ContextAware
+from zope.proxy.context import ContextWrapper
+from zope.proxy.introspection import removeAllProxies
+from zope.app.interfaces.services.configuration import IUseConfiguration
+from zope.app.traversing import getPath
+
+class LocalUtilityService(Persistent, ContextAware):
+
+ __implements__ = IUtilityService, IConfigurable, ISimpleService
+
+ def __init__(self):
+ self._utilities = PersistentDict()
+
+ 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=''):
+ registry = self.queryConfigurations(name, interface)
+ if registry is not None:
+ configuration = registry.active()
+ if configuration is not None:
+ return configuration.getComponent()
+
+ next = getNextService(self, "Utilities")
+ return next.queryUtility(interface, default, name)
+
+ def queryConfigurationsFor(self, configuration, default=None):
+ return self.queryConfigurations(configuration.name,
+ configuration.interface,
+ default)
+
+ def queryConfigurations(self, name, interface, default=None):
+ utilities = self._utilities.get(name)
+ if utilities is None:
+ return default
+ registry = utilities.getRegistered(interface)
+ if registry is None:
+ return default
+
+ return ContextWrapper(registry, self)
+
+ def createConfigurationsFor(self, configuration):
+ return self.createConfigurations(configuration.name,
+ configuration.interface)
+
+ def createConfigurations(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)
+
+ return ContextWrapper(registry, self)
+
+
+class UtilityConfiguration(ComponentConfiguration):
+ """Utility component configuration for persistent components
+
+ This configuration configures persistent components in packages to
+ be utilities.
+
+ """
+
+ status = ConfigurationStatusProperty('Utilities')
+
+ __implements__ = (IUtilityConfiguration,
+ ComponentConfiguration.__implements__)
+
+ def __init__(self, name, interface, component_path, permission=None):
+ ComponentConfiguration.__init__(self, component_path, permission)
+ self.name = name
+ self.interface = interface
+
+ def usageSummary(self):
+ # Override IConfiguration.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
+ # permission; it needs the interface to create a security
+ # proxy for the interface with the given permission.
+ return self.interface
+
+ # The following hooks are called only if we implement
+ # IAddNotifiable and IDeleteNotifiable.
+
+ def afterAddHook(self, configuration, container):
+ """Hook method will call after an object is added to container.
+
+ Defined in IAddNotifiable.
+ """
+ super(UtilityConfiguration, self).afterAddHook(configuration,
+ container)
+ utility = configuration.getComponent()
+ adapter = getAdapter(utility, IUseConfiguration)
+ adapter.addUsage(getPath(configuration))
+
+ def beforeDeleteHook(self, configuration, container):
+ """Hook method will call before object is removed from container.
+
+ Defined in IDeleteNotifiable.
+ """
+ utility = configuration.getComponent()
+ adapter = getAdapter(utility, IUseConfiguration)
+ adapter.removeUsage(getPath(configuration))
+ super(UtilityConfiguration, self).beforeDeleteHook(configuration,
+ container)
+
=== Zope3/src/zope/app/services/utility.zcml 1.1 => 1.2 ===
--- /dev/null Fri Mar 21 16:02:20 2003
+++ Zope3/src/zope/app/services/utility.zcml Fri Mar 21 16:02:19 2003
@@ -0,0 +1,26 @@
+<zopeConfigure xmlns='http://namespaces.zope.org/zope'>
+
+<content class=".utility.LocalUtilityService">
+ <factory
+ id="zope.app.services.UtilityService"
+ permission="zope.ManageServices"
+ />
+</content>
+
+<content class=".utility.UtilityConfiguration">
+ <require
+ permission="zope.ManageServices"
+ interface="zope.app.interfaces.services.utility.IUtilityConfiguration"
+ set_schema="zope.app.interfaces.services.utility.IUtilityConfiguration"
+ />
+ <require
+ permission="zope.ManageServices"
+ interface="zope.app.interfaces.container.IAddNotifiable"
+ />
+ <require
+ permission="zope.ManageServices"
+ interface="zope.app.interfaces.container.IDeleteNotifiable"
+ />
+ </content>
+
+</zopeConfigure>
=== Zope3/src/zope/app/services/README.txt 1.1 => 1.2 === (418/518 lines abridged)
--- /dev/null Fri Mar 21 16:02:20 2003
+++ Zope3/src/zope/app/services/README.txt Fri Mar 21 16:02:19 2003
@@ -0,0 +1,515 @@
+==============
+Local Services
+==============
+
+: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.
+
+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.
+
+A few words on the difference between local and global services:
+
+- Local services (usually) exist in the ZODB; global services don't.
+
+- Local services apply to a specific part of the object hierarchy;
+ global services (as their name suggests) don't.
+
+- Local services are (usually) created and configured through the ZMI;
+ global services are created and configured by ZCML directives.
+
+- Local services are expected to collaborate with services "above"
+ 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``::
+
[-=- -=- -=- 418 lines omitted -=- -=- -=-]
+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.
+
+ 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
+
+
+
+
+
+
+
+
+
+
+
+---------------------------------------------------------------
+
+.. [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/configure.zcml 1.20 => 1.21 ===
--- Zope3/src/zope/app/services/configure.zcml:1.20 Tue Mar 18 16:02:22 2003
+++ Zope3/src/zope/app/services/configure.zcml Fri Mar 21 16:02:19 2003
@@ -260,7 +260,7 @@
<!-- Configuration Manager -->
- <content class="zope.app.services.configurationmanager.ConfigurationManager">
+ <content class="zope.app.services.configuration.ConfigurationManager">
<factory
id = "zope.app.services.ConfigurationManager"
permission = "zope.ManageServices"
@@ -270,15 +270,11 @@
interface="zope.app.interfaces.container.IReadContainer" />
<require
permission="zope.ManageServices"
- interface="zope.app.interfaces.container.IWriteContainer" />
- <require
- permission="zope.ManageServices"
- interface=
- "zope.app.interfaces.services.configurationmanager.IOrderedContainer"
- />
- <require
- permission="zope.ManageServices"
- interface="zope.app.interfaces.container.IDeleteNotifiable"
+ interface="
+ zope.app.interfaces.container.IWriteContainer
+ zope.app.interfaces.services.configuration.IOrderedContainer
+ zope.app.interfaces.container.IDeleteNotifiable
+ "
/>
<implements
interface="zope.app.interfaces.annotation.IAttributeAnnotatable"
@@ -468,5 +464,8 @@
id='Subscription'
interface='zope.app.interfaces.services.event.ISubscriptionService'
/>
+
+<!-- Utility Service --> <include file="utility.zcml" />
+
</zopeConfigure>