[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>