[Zope3-checkins] CVS: Zope3/lib/python/Zope/App/OFS/Services - Configuration.py:1.1.2.1 ConfigurationInterfaces.py:1.1.2.1 configure.zcml:1.9.6.2
Jim Fulton
jim@zope.com
Sat, 30 Nov 2002 07:44:56 -0500
Update of /cvs-repository/Zope3/lib/python/Zope/App/OFS/Services
In directory cvs.zope.org:/tmp/cvs-serv30047/lib/python/Zope/App/OFS/Services
Modified Files:
Tag: Zope3-Bangalore-TTW-Branch
configure.zcml
Added Files:
Tag: Zope3-Bangalore-TTW-Branch
Configuration.py ConfigurationInterfaces.py
Log Message:
Refactored the way TTW component registration is done. There are now
separate registry objects that abstract the machinery for registering
multiple conflicting configurations and deciding which, if any are
active. Also provided a new field and widget for the status
information.
Along the way, cleaned up and streamlined placeful testing
infrastructure a bit.
Now checking into branch. Will give file-by-file (or at least more
specific logs) when the changes are merged into the head.
=== Added File Zope3/lib/python/Zope/App/OFS/Services/Configuration.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
This module provides constant definitions for the three registration states,
Unregistered, Registered, and Active.
$Id: Configuration.py,v 1.1.2.1 2002/11/30 12:44:26 jim Exp $
"""
__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)
=== Added File Zope3/lib/python/Zope/App/OFS/Services/ConfigurationInterfaces.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.
#
##############################################################################
"""Interfaces for objects supporting configuration registration
$Id: ConfigurationInterfaces.py,v 1.1.2.1 2002/11/30 12:44:26 jim Exp $
"""
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/configure.zcml 1.9.6.1 => 1.9.6.2 ===
--- Zope3/lib/python/Zope/App/OFS/Services/configure.zcml:1.9.6.1 Wed Oct 16 11:52:24 2002
+++ Zope3/lib/python/Zope/App/OFS/Services/configure.zcml Sat Nov 30 07:44:26 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=".AdapterService" />
+<include package=".Browser" />
</zopeConfigure>