[Zope3-checkins] CVS: Zope3/lib/python/Zope/App/OFS/Services - Configuration.py:1.2 ConfigurationInterfaces.py:1.2 IConfigureFor.py:1.2 RegistrationState.py:1.2 configure.zcml:1.15
Jim Fulton
jim@zope.com
Sat, 30 Nov 2002 13:36:25 -0500
Update of /cvs-repository/Zope3/lib/python/Zope/App/OFS/Services
In directory cvs.zope.org:/tmp/cvs-serv11713/lib/python/Zope/App/OFS/Services
Modified Files:
configure.zcml
Added Files:
Configuration.py ConfigurationInterfaces.py IConfigureFor.py
RegistrationState.py
Log Message:
Added a framework for managing configuration registration. This should
make it much easier to implement configurable services.
=== Zope3/lib/python/Zope/App/OFS/Services/Configuration.py 1.1 => 1.2 ===
--- /dev/null Sat Nov 30 13:36:25 2002
+++ Zope3/lib/python/Zope/App/OFS/Services/Configuration.py Sat Nov 30 13:35:55 2002
@@ -0,0 +1,240 @@
+##############################################################################
+#
+# 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
+
+This module provides constant definitions for the three registration states,
+Unregistered, Registered, and Active.
+
+$Id$
+"""
+__metaclass__ = type
+
+from Persistence import Persistent
+from ConfigurationInterfaces import IConfigurationRegistry
+from Zope.Schema import Text
+from Zope.ComponentArchitecture import getService, getServiceManager
+from Zope.App.Traversing import getPhysicalPathString, traverse
+from Zope.App.OFS.Services.ConfigurationInterfaces \
+ import Unregistered, Registered, Active
+from Zope.Proxy.ContextWrapper import ContextWrapper
+from Zope.ContextWrapper import ContextMethod
+
+class ConfigurationStatusProperty:
+
+ __Zope_ContextWrapper_contextful_get__ = True
+ __Zope_ContextWrapper_contextful_set__ = True
+
+ def __init__(self, service):
+ self.service = service
+
+ def __get__(self, inst, klass):
+ if inst is None:
+ return self
+
+ configuration = inst
+ service = getService(configuration, self.service)
+ registry = service.queryConfigurationsFor(configuration)
+
+ if registry:
+
+ if registry.active() == configuration:
+ return Active
+ if registry.registered(configuration):
+ return Registered
+
+ return Unregistered
+
+ def __set__(self, inst, value):
+ configuration = inst
+ service = getService(configuration, self.service)
+ registry = service.queryConfigurationsFor(configuration)
+
+ if value == Unregistered:
+ if registry:
+ registry.unregister(configuration)
+
+ else:
+
+ if registry is None:
+ registry = service.createConfigurationsFor(configuration)
+
+ if value == Registered:
+ if registry.active() == configuration:
+ registry.deactivate(configuration)
+ else:
+ registry.register(configuration)
+
+ elif value == Active:
+ if not registry.registered(configuration):
+ registry.register(configuration)
+ registry.activate(configuration)
+
+
+
+class ConfigurationRegistry(Persistent):
+
+ __implements__ = IConfigurationRegistry
+
+ _data = ()
+
+ def _id(self, ob):
+
+ # Get and check relative path
+ prefix = "/++etc++Services/Packages/"
+ path = getPhysicalPathString(ob)
+ lpackages = path.rfind(prefix)
+ if lpackages < 0:
+ raise ValueError("Configuration object is in an invalid location",
+ path)
+
+ rpath = path[lpackages+len(prefix):]
+ if not rpath or (".." in rpath.split("/")):
+ raise ValueError("Configuration object is in an invalid location",
+ path)
+
+ return rpath
+
+ _id = ContextMethod(_id)
+
+ def register(self, configuration):
+ cid = self._id(configuration)
+
+ if self._data:
+ if cid in self._data:
+ return # already registered
+ else:
+ # Nothing registered. Need to stick None in front so that nothing
+ # is active.
+ self._data = (None, )
+
+ self._data += (cid, )
+
+ register = ContextMethod(register)
+
+ def unregister(self, configuration):
+ cid = self._id(configuration)
+
+ data = self._data
+ if data:
+ if data[0] == cid:
+ # It's active, we need to switch in None
+ data = (None, ) + data[1:]
+
+ # we need to notify it that it's inactive.
+ configuration.deactivated()
+
+ else:
+ data = tuple([item for item in data if item != cid])
+
+ # Check for empty registry
+ if len(data) == 1 and data[0] is None:
+ data = ()
+
+ self._data = data
+
+ unregister = ContextMethod(unregister)
+
+ def registered(self, configuration):
+ cid = self._id(configuration)
+ return cid in self._data
+
+ registered = ContextMethod(registered)
+
+ def activate(self, configuration):
+ cid = self._id(configuration)
+ data = self._data
+
+ if cid in data:
+
+ if data[0] == cid:
+ return # already active
+
+ if data[0] is None:
+ # Remove leading None marker
+ data = data[1:]
+ else:
+ # We need to deactivate the currently active component
+ sm = getServiceManager(self)
+ old = traverse(sm, 'Packages/'+data[0])
+ old.deactivated()
+
+
+ self._data = (cid, ) + tuple(
+ [item for item in data if item != cid]
+ )
+
+ configuration.activated()
+
+ else:
+ raise ValueError(
+ "Configuration to be activated is not regsistered",
+ configuration)
+
+ activate = ContextMethod(activate)
+
+ def deactivate(self, configuration):
+ cid = self._id(configuration)
+
+ if cid in self._data:
+
+ if self._data[0] != cid:
+ return # already inactive
+
+ # Just stick None on the front
+ self._data = (None, ) + self._data
+
+ configuration.deactivated()
+
+ else:
+ raise ValueError(
+ "Configuration to be deactivated is not regsistered",
+ configuration)
+
+ deactivate = ContextMethod(deactivate)
+
+ def active(self):
+ if self._data:
+ path = self._data[0]
+ if path is not None:
+ # Make sure we can traverse to it.
+ sm = getServiceManager(self)
+ configuration = traverse(sm, 'Packages/'+path)
+ return configuration
+
+ return None
+
+ active = ContextMethod(active)
+
+ def __nonzero__(self):
+ return bool(self._data)
+
+ def info(self):
+ sm = getServiceManager(self)
+
+ result = [{'id': path,
+ 'active': False,
+ 'configuration': (path and traverse(sm, 'Packages/'+path))
+ }
+ for path in self._data
+ ]
+
+ if result:
+ if result[0]['configuration'] is None:
+ del result[0]
+ else:
+ result[0]['active'] = True
+
+ return result
+
+ info = ContextMethod(info)
=== Zope3/lib/python/Zope/App/OFS/Services/ConfigurationInterfaces.py 1.1 => 1.2 ===
--- /dev/null Sat Nov 30 13:36:25 2002
+++ Zope3/lib/python/Zope/App/OFS/Services/ConfigurationInterfaces.py Sat Nov 30 13:35:55 2002
@@ -0,0 +1,176 @@
+##############################################################################
+#
+# 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.
+#
+##############################################################################
+"""Interfaces for objects supporting configuration registration
+
+$Id$
+"""
+
+from Interface import Interface
+from Zope.Schema import Text, TextLine
+from Zope.Schema.IField import ITextLine
+
+Unregistered = u'Unregistered'
+Registered = u'Registered'
+Active = u'Active'
+
+class IConfigurationStatus(ITextLine):
+ """The registration status of a configuration
+ """
+
+class ConfigurationStatus(TextLine):
+ __implements__ = IConfigurationStatus
+ allowed_values = Unregistered, Registered, Active
+
+class IConfigurationSummary(Interface):
+ """Configuration summary data
+ """
+
+ title = TextLine(title = u"Title",
+ description = u"Descriptive title",
+ required = True)
+
+ status = ConfigurationStatus(title = u"Configuration status")
+
+class IConfiguration(IConfigurationSummary):
+ """Configuration object
+
+ A configuration object represents a specific configuration
+ decision, such as registering an adapter or defining a permission.
+
+ In addition to the attributes or methods defined here,
+ configuration objecvts will include additional attributes
+ identifying how they should be used. For example, a service
+ configuration will provide a service type. An adapter
+ configuration will specify a used-for interface and a provided
+ interface.
+ """
+
+ description = Text(title = u"Description",
+ description = u"Detailed description",
+ )
+
+ def activated():
+ """Method called when a configuration is made active
+ """
+
+ def deactivated():
+ """Method called when a configuration is made inactive
+ """
+
+
+class IConfigurationRegistry(Interface):
+ """A registry of configurations for a set of parameters
+
+ A service will have a regsitry containing configuration registries
+ for specific parameters. For example, an adapter service will have
+ a configuration registry for each given used-for and provided
+ interface.
+
+ """
+
+ def register(configuration):
+ """Register the given configuration
+
+ Do nothing if the configuration is already registered.
+ """
+
+ def unregister(configuration):
+ """Unregister the given configuration
+
+ Do nothing if the configuration is not registered.
+ """
+
+ def registered(configuration):
+ """Is the configuration registered
+
+ Return a boolean indicating whether the configuration has been
+ registered.
+
+ """
+
+ def activate(configuration):
+ """Make the configuration active.
+
+ The activated method is called on the configuration.
+
+ Raises a ValueError if the given configuration is not registered.
+ """
+
+ def deactivate(configuration):
+ """Make the configuration inactive.
+
+ Id the configuration is active, the deactivated method is called
+ on the configuration.
+
+ Raises a ValueError if the given configuration is not registered.
+
+ The call has no effect if the configuration is registered but
+ not active.
+ """
+
+ def active():
+ """Return the active configuration, if any
+
+ Otherwise, returns None.
+ """
+
+ def info():
+ """Return a sequence of configuration information
+
+ The sequence items are mapping objects with keys:
+
+ id -- A string that can be used to uniquely identify the
+ configuration
+
+ active -- A boolean indicating whether the configuration is
+ active
+
+ configuration -- The configuration object.
+ """
+
+ def __nonzero__(self):
+ """The registry is true if it is non-empty
+ """
+
+class IConfigurable(Interface):
+
+ def queryConfigurationsFor(configuration):
+ """Return an IConfigurationRegistry for the configuration
+
+ Data on the configuration is used to decide which regsitry to
+ return. For example, a service manager will use the
+ configuration serviceType attribute to decide which regsitry
+ to return.
+
+ Typically, an object that implements this method will also
+ implement a method named queryConfigurations, which takes
+ arguments for each of the parameters needed to specify a set
+ of configurations.
+
+ """
+
+ def createConfigurationsFor(configuration):
+ """Create and return an IConfigurationRegistry for the configuration
+
+ Data on the configuration is used to decide which regsitry to
+ create. For example, a service manager will use the
+ configuration serviceType attribute to decide which regsitry
+ to create.
+
+ Typically, an object that implements this method will also
+ implement a method named createConfigurations, which takes
+ arguments for each of the parameters needed to specify a set
+ of configurations.
+
+ """
=== Zope3/lib/python/Zope/App/OFS/Services/IConfigureFor.py 1.1 => 1.2 ===
--- /dev/null Sat Nov 30 13:36:25 2002
+++ Zope3/lib/python/Zope/App/OFS/Services/IConfigureFor.py Sat Nov 30 13:35:55 2002
@@ -0,0 +1,38 @@
+##############################################################################
+#
+# Copyright (c) 2001, 2002 Zope Corporation and Contributors.
+# All Rights Reserved.
+#
+# This software is subject to the provisions of the Zope Public License,
+# Version 2.0 (ZPL). A copy of the ZPL should accompany this distribution.
+# THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED
+# WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+# WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS
+# FOR A PARTICULAR PURPOSE.
+#
+##############################################################################
+"""
+
+$Id$
+"""
+
+from Interface import Interface
+
+class IConfigureFor(Interface):
+ """Services that configure component for interfaces
+
+ This interface is used to find out if there is configuration for a given
+ interface.
+
+ Services that implements this interface must provide a view named "ConfigurationFor"
+ that displays the configuration for a given interface. For browser views the interface
+ will be given in a form variable named "forInterface".
+ """
+ def hasConfigurationFor(interface):
+ """Check for configuration information
+
+ Return a Boolean indicating wether there is configuration information for
+ the given interface.
+ """
+
+
=== Zope3/lib/python/Zope/App/OFS/Services/RegistrationState.py 1.1 => 1.2 ===
--- /dev/null Sat Nov 30 13:36:25 2002
+++ Zope3/lib/python/Zope/App/OFS/Services/RegistrationState.py Sat Nov 30 13:35:55 2002
@@ -0,0 +1,24 @@
+##############################################################################
+#
+# 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.
+#
+##############################################################################
+"""Standard registration states
+
+This module provides constant definitions for the three registration states,
+Unregistered, Registered, and Active.
+
+$Id$
+"""
+
+Unregistered = 'Unregistered'
+Registered = 'Registered'
+Active = 'Active'
=== Zope3/lib/python/Zope/App/OFS/Services/configure.zcml 1.14 => 1.15 ===
--- Zope3/lib/python/Zope/App/OFS/Services/configure.zcml:1.14 Tue Oct 29 22:47:45 2002
+++ Zope3/lib/python/Zope/App/OFS/Services/configure.zcml Sat Nov 30 13:35:55 2002
@@ -1,4 +1,13 @@
-<zopeConfigure xmlns='http://namespaces.zope.org/zope'>
+<zopeConfigure
+ xmlns='http://namespaces.zope.org/zope'
+ xmlns:browser="http://namespaces.zope.org/browser"
+ >
+
+<content class=".Configuration.ConfigurationRegistry">
+ <require permission="Zope.ManageServices"
+ interface=".ConfigurationInterfaces.IConfigurationRegistry"
+ />
+</content>
<include package=".ServiceManager" />
<include package=".AuthenticationService" />
@@ -9,5 +18,6 @@
<include package=".CachingService" />
<include package=".ObjectHub" />
<include package=".ErrorReportingService" />
+<include package=".Browser" />
</zopeConfigure>