Author: jmorliaguet Date: Fri Nov 4 16:12:15 2005 New Revision: 28979 Added: z3lab/cpsskins/branches/jmo-perspectives/registry/ z3lab/cpsskins/branches/jmo-perspectives/registry/README.txt (contents, props changed) z3lab/cpsskins/branches/jmo-perspectives/registry/__init__.py (contents, props changed) z3lab/cpsskins/branches/jmo-perspectives/registry/configure.zcml (contents, props changed) z3lab/cpsskins/branches/jmo-perspectives/registry/interfaces.py (contents, props changed) z3lab/cpsskins/branches/jmo-perspectives/registry/storage.py (contents, props changed) Modified: z3lab/cpsskins/branches/jmo-perspectives/configure.zcml Log:
- saving work (current a basic container implementation of a global utility that registers ISomeItem objects.) Modified: z3lab/cpsskins/branches/jmo-perspectives/configure.zcml ============================================================================== --- z3lab/cpsskins/branches/jmo-perspectives/configure.zcml (original) +++ z3lab/cpsskins/branches/jmo-perspectives/configure.zcml Fri Nov 4 16:12:15 2005 @@ -49,7 +49,6 @@ <include package=".controllers" /> - <include package=".storage" /> <include package=".elements" /> @@ -67,4 +66,8 @@ <include package=".configuration.engines" /> + <include package=".registry" /> + + <include package=".storage" /> + </configure> Added: z3lab/cpsskins/branches/jmo-perspectives/registry/README.txt ============================================================================== --- (empty file) +++ z3lab/cpsskins/branches/jmo-perspectives/registry/README.txt Fri Nov 4 16:12:15 2005 @@ -0,0 +1,206 @@ + +$id:$ + +===================== +STORAGE-LIKE REGISTRY +===================== + +This package provides a storage that implements the component architecture's +utility-based registration mechanism to register objects. + +Description +----------- + +A storage-like registry contains objects (resources, images, portlets, ...) +that are used by the application. Objects can be stored in the ZODB or be +filesystem resources. The objects are accessed as if they were stored in a +single container, although they may be part of different registries (global / +local). + +Design goals +------------ + +The main design goal of this type of registry is to allow transparent access to +objects located in the storage independently of the way in which they have been +created (i.e. TTW or via the filesystem) or registered. + +Filesystem-based vs. persistent objects +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +Filesystem-based configurations (e.g. zope configuration system) store +information about objects on the filesystem: when the application server is +started the server stores objects in memory based on the configuration. +The objects can be modified by the application, but the modifications are lost +as soon the server is restarted. + +Unless users have access to the filesystem, the objects created in this way +can be considered as read-only resources. This poses a problem in case the +objects need to be modified by users who only work through the web. + +A solution is to create such objects as persistent content classes from the +beginning, but this make filesystem-based development difficult. + +Different patterns +~~~~~~~~~~~~~~~~~~ + +The main issue is that the patterns used when working with filesystem-based +objects and with persistent objects are quite different: + +- objects configured on the filesystem are considered by the application as + simple resources stored in a registry. They are not supposed to be + manipulated by users. + +- objects stored in the ZODB are meant to be manipulated by users but + they are difficult to access via a registry unless they are cataloged. + +The results is that different APIs get implemented based on the type of +object, and sometimes it is the entire application that supports one way of +working with objects or the other. + + +Use case 1: application developer +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +Developing an application through-the-web is not very efficient. + +Application developers will most likely take the filesystem-based configuration +approach for creating application resources (actions, skins, templates, +workflows, ...). This makes it easier to collaborate on software repositories. + + +Use case 2: site designers +~~~~~~~~~~~~~~~~~~~~~~~~~~ + +Site designers will most likely want to work directly through-the-web and +export site configurations to the filesystem when they are satisfied with the +results. + +Conflicting interests +~~~~~~~~~~~~~~~~~~~~~ + +This situation causes conflicts of interests since the developers will claim +that resources ought be stored on the filesystem and site designers will claim +that working through-the-web is a better approach. + +The result is that some of the resources in the application shared by both +developers and by site designers cannot be considered as "filesystem-only" +or as "TTW-only" resources, they have to be considered as both. + +The current pattern in Zope3 is to not support TTW development. This partly +solves the issue, but only if by "development" one really means development. + +It can be argued that site creation is not done by developers but by site +designers. If this former category of users is to be empowered, a model that +mixes filesystem-based and through-the-web "development" is needed. + +The storage described here treats filesystem-based objects as if they were +read-only objects stored in the ZODB. + + +Implementation +-------------- + +Interfaces +~~~~~~~~~~ + +Each storage implements the base IStorage interface and may also implement more +specific interfaces depending on the type of object stored:: + +class IStorage(Interface): + + def add(object, name): + """Add an object to the storage. Return the added object. + The object's name can be specified. + """ + + def remove(objects): + """Remove a list of objects from the storage.""" + + def duplicate(object): + """Duplicate an object in the storage. Return the duplicated object.""" + + def __setitem__(object): + """Set an object into the storage.""" + + def __getitem__(item): + """Get an item from the storage.""" + + def customize(object): + """Turn a filesystem object into a persistent object.""" + + def decustomize(object): + """Convert a customized object back into a filesystem object.""" + + +The storage interface is also used to identify the storage.:: + +class IMyStorage(IStorage): + + contains(ISomeTypeOfObject) + + def doSomethingSpecial(): + """Do something special with the stored objects""" + + +Registration +~~~~~~~~~~~~ + +Storages are registered in ZCML:: + +<configure + xmlns:cpsskins="http://namespaces.zope.org/cpsskins"> + + <cpsskins:storage + id="mystorage" + title="My storage" + description="A description of my storage" + factory=".mystorage.MyStorage" + interface=".mystorage.IMyStorage" + /> + +</configure> + + +Adding filessystem objects to the storage +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +When an object is registered in ZCML it is possible to specify the +storage to which it will be add. This can be done in metaconfigure.py + +instead of writing:: + + some_registry = getUtility(ISomeRegistry) + some_registry.register(name, some_object) + + +one would write: + + some_storage = queryUtility(IMyStorage) + some_storage.add(some_object) + +The object is physically stored in memory but for the application it appears as +though the object is located in the storage with other ZODB objects. + +It is the responsibility of the ZCML configuration handler to add objects +to the registry. Hence the storage is unaware of the configuration method. + +Customizing objects +~~~~~~~~~~~~~~~~~~~ + +Sometimes an object configured on the filesystem needs to become persistent +This is the equivalent of the "Customize" function in Zope2's portal skins. +A copy of the original object is created and replaces the customized object. + +Decustomizing objects +~~~~~~~~~~~~~~~~~~~~~ + +Customized objects are not destroyed, hence it is easy to reverse the +customization. + +Access +~~~~~~ + +Filesystem-based objects are to be considered as read-only, hence they should +appear as being locked or not being writable by the application. + +(...) Added: z3lab/cpsskins/branches/jmo-perspectives/registry/__init__.py ============================================================================== --- (empty file) +++ z3lab/cpsskins/branches/jmo-perspectives/registry/__init__.py Fri Nov 4 16:12:15 2005 @@ -0,0 +1,19 @@ +############################################################################## +# +# Copyright (c) 2005 Nuxeo and Contributors. +# All Rights Reserved. +# +# This software is subject to the provisions of the Zope Public License, +# Version 2.1 (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$ +""" +__docformat__ = "reStructuredText" + Added: z3lab/cpsskins/branches/jmo-perspectives/registry/configure.zcml ============================================================================== --- (empty file) +++ z3lab/cpsskins/branches/jmo-perspectives/registry/configure.zcml Fri Nov 4 16:12:15 2005 @@ -0,0 +1,48 @@ +<configure + xmlns="http://namespaces.zope.org/zope" + xmlns:browser="http://namespaces.zope.org/browser"> + + <localUtility class=".storage.Storage"> + + <require + permission="zope.ManageServices" + interface=".storage.IStorage" + /> + + </localUtility> + + <content class=".storage.SomeItem"> + + <implements + interface="zope.app.annotation.IAttributeAnnotatable" /> + + <require permission="zope.View" + interface=".storage.ISomeItem" /> + + <require permission="zope.ManageContent" + set_schema=".storage.ISomeItem" /> + + </content> + + <browser:addMenuItem + title="Some item" + description="Some item" + class=".storage.SomeItem" + permission="zope.ManageContent" + /> + + <browser:addMenuItem + title="Storage-like registry" + description="Registry" + class=".storage.Storage" + permission="zope.ManageServices" + /> + + <browser:containerViews + for=".storage.IStorage" + contents="zope.ManageContent" + index="zope.View" + add="zope.ManageContent" + /> + +</configure> Added: z3lab/cpsskins/branches/jmo-perspectives/registry/interfaces.py ============================================================================== --- (empty file) +++ z3lab/cpsskins/branches/jmo-perspectives/registry/interfaces.py Fri Nov 4 16:12:15 2005 @@ -0,0 +1,24 @@ +############################################################################## +# +# Copyright (c) 2005 Nuxeo and Contributors. +# All Rights Reserved. +# +# This software is subject to the provisions of the Zope Public License, +# Version 2.1 (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$ +""" + +__docformat__ = "reStructuredText" + +from zope.app.container.interfaces import IContainer + +class IStorage(IContainer): + """A storage-like registry.""" Added: z3lab/cpsskins/branches/jmo-perspectives/registry/storage.py ============================================================================== --- (empty file) +++ z3lab/cpsskins/branches/jmo-perspectives/registry/storage.py Fri Nov 4 16:12:15 2005 @@ -0,0 +1,83 @@ +############################################################################## +# +# Copyright (c) 2005 Nuxeo and Contributors. +# All Rights Reserved. +# +# This software is subject to the provisions of the Zope Public License, +# Version 2.1 (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$ +""" + +__docformat__ = "reStructuredText" + +from zope.component import provideUtility, queryUtility, getUtilitiesFor +from zope.app.component import queryNextUtility +from persistent import Persistent +from zope.interface import implements, Interface +from zope.app.container.contained import Contained + +from interfaces import IStorage + +class ISomeItem(Interface): + """Some storage item""" + +class SomeItem(Persistent, Contained): + implements(ISomeItem) + def __init__(self): + pass + +class Storage(Persistent, Contained): + + implements(IStorage) + + def __setitem__(self, name, object): + if not isinstance(name, basestring): + raise TypeError("The key must be an ascii or a unicode string.") + + if not name: + raise ValueError("The key must not be empty.") + + if not ISomeItem.providedBy(object): + raise TypeError( + "The object %s cannot be added to this storage" % object) + + provideUtility(component=object, provides=ISomeItem, name=name) + + object.__parent__ = self + object.__name__ = name + + def __getitem__(self, name): + object = queryUtility(ISomeItem, name) + if object is None: + raise KeyError("No such item %s." % name) + return object + + def __delitem__(self, name): + object = self[name] + + def __len__(self): + return len(self.keys()) + + def keys(self): + return list(getUtilitiesFor(ISomeItem)) + + def __iter__(self): + return iter([v for k, v in self.items()]) + + def get(self, name, default=None): + return queryUtility(ISomeItem, name, default=default) + + def items(self): + return list(getUtilitiesFor(ISomeItem)) + + def ___contains__(self, name): + return name in self.keys() + -- http://lists.nuxeo.com/mailman/listinfo/z3lab-checkins