Logo Search packages:      
Sourcecode: zope-loginmanager version File versions

Rack.py

from DataManagers import DataManager
from SheetProviders import SheetProvider
from AttributeProviders import AttributeProvider
from Providers import LinkToParentProviders
from Globals import HTMLFile, default__class_init__, PersistentMapping
from ComputedAttribute import ComputedAttribute
from Transactions import Kept
from App.Common import absattr
from DataSkins import DataSkin
from Products.PlugIns import MakePICBase
import Products

_marker=[]

SelfKey = 'ZPatterns.Rack','Self'


























00042 class Rack(DataManager, Kept):

    """
    Basic Rack - supports sheet and attribute provider plugins, as
    well as persistent storage of any ZClass object and arbitrary
    associated data (using "slots").
    """

    # Template (i.e. abstract) methods, should be left as-is

00052     def getItem(self, key):
        """Get an item from the rack by key"""
        
        # Borrow canonicals map for per-transaction item cache
        item = self._fromCache(key,_marker)
        
        if item is _marker:
            item = self.retrieveItem(key)
            self._toCache(key,item) # XXX Should we cache non-existence?
            
        return item


00065     def newItem(self, key=None):
        """Create a new item - attempts to generate key if not supplied"""

        if key is None:
            key=getattr(self,'newKey',None)
            key=key and key()
            if key is None: return None

        return self.createItem(key)
        

    def _objectDeleting(self,client):
        DataManager._objectDeleting(self,client)
        self._delSlotFor(client)




    # Methods to be overridden in subclasses for non-ZODB storage

    loadAttrib = ''  # If not empty, attribute to use when loading an item


    def retrieveItem(self,key):

        # Retrieve an object, identified by key

        a = self.loadAttrib
        item = None

        if a:
            item = self._RawItem(key)
            if hasattr(item.aq_base, a):
                return item

        else:
            # The block below is what you want to replace
            # if you're creating a non-ZODB storage.
            # In practice, from version 0.4.0 on, there's
            # no reason to do such a thing in the first place.
            
            slot = self._readableSlot(key)

            if slot:
                item = slot[SelfKey]

                # XXX class remapping should go here??

                self = self.aq_inner
                item._setRack(self)
                item._setSlot(slot)
                return item.__of__(self.aq_parent)







    def createItem(self,key):

        # Create a new object, identified by key

        item = self.getItem(key)

        # XXX What if all items potentially exist?
        
        if item is not None:
            raise KeyError,("'%s' already exists" % key)

        item = self._RawItem(key)

        a = self.loadAttrib
        if not a:
            slot = self._writeableSlot(key)
            slot[SelfKey] = item.aq_base    # strip acquisition wrapping
            item._setSlot(slot)             # Not needed for non-ZODB storage

        item._objectCreating()
        item._objectAdding()

        self._toCache(key,item) # XXX Should we cache non-creation?
        
        return item
















    # Optionally overrideable methods for additional functionality

    #def newKey(self):
    #    """Generate a new object key"""
    #    pass    # must be defined if key autogeneration is desired
    #
    # def countItems(self): pass
    # def deleteAll(self): pass

    _initialized = 0
    
    def _setup(self):
        # set up default providers
        
        if self._initialized:
            # We must only initialize once, since _setup gets called on pastes,
            # imports, etc.
            return
            
        self._installPlugIn(
            LinkToParentProviders('SpecialistPlugIns', 
                title='Plug-ins from parent Specialist')
        )
        
        self._installPlugIn(
            SheetProvider('PersistentSheets', title='Sheets stored in Rack slots')
        )
        
        self._installPlugIn(
            AttributeProvider('PersistentAttributes',
                title='Attributes stored persistently in objects')
        )
        
        self._initialized = 1
        






    # ZClass Machinery (Optionally overrideable)

    _defaultClass = None

    def _v_itemConstructor(self):
        c = getattr(self, '_zclass', None) or self._defaultClass

        if c:
            if type(c) is type(''):
                c = self._unifiedZClassRegistry()[c][1]   #Products.meta_classes[c]
        else:
            def err(key):
                raise TypeError, "No ZClass set - please use 'Storage' tab"
            return err

        c = getattr(c,'_zclass_',c)
        self._v_itemConstructor = c
        return c

    _v_itemConstructor = ComputedAttribute(lambda s,v=ComputedAttribute(_v_itemConstructor): v)  

00227     def _RawItem(self, key):
        """
        Create an empty object of the right class
        """
        self = self.aq_inner
        item = self._v_itemConstructor(key)
        
        item._setRack(self)                 # Connect to rack
        item = item.__of__(self.aq_parent.aq_inner)  # Link to Specialist
        return item


    def _isSelected(self, name, path, klass):
        Z = self._v_itemConstructor
        Z = getattr(Z, 'aq_self', Z)
        return klass._zclass_ is Z




    # Caching

    def _v_cache(self):
        self._v_Keeper
        l = self._v_cache = {}
        return l

    _v_cache = ComputedAttribute(_v_cache)

    __per_transaction_cache_attrs__ = ('_v_cache',)

    def _fromCache(self, key, default=None):
        return self._v_cache.get(key,default)

    def _toCache(self, key, item):
        self._v_cache[key] = item
    
























    # Persistence Machinery - little need to override, but to be extended
    # for future multi-ZODB support

    storageInfo = ''    # Reserved for configuring future multi-ZODB support
    __storage = None    # This rack's storage object for sheets and/or objects

00294     def storageInUse(self):
        """How many racked items have persistent storage use?"""
        return len(self.__readableStorage)

00298     def __writeableStorage(self):
        """Create new a mapping-like object for storing 'persistent' stuff and save it in self"""
        from BTree import BTree
        s = self.__readableStorage = self.__writeableStorage = BTree()
        return s
        
    __readableStorage = {}
    __writeableStorage = ComputedAttribute(__writeableStorage)
        

00308     def _migrateStorage(self,storage):
        """Move existing data to new kind of storage"""

        #if self.storageInUse():
        #    raise ValueError, "Cannot change storage with contents present"

        raise "NotImplemented", "Only self-storage is currently supported"

        # XXX self.storageInfo = storage; del self.__storage

00318     def manage_storageOptions(self):
        """Return a list of key-value pair tuples listing storage options"""
        return [('', 'Directly in this object')]

    def _getClientID(self,client):
        return absattr(client.id)





    def _readableSlotFor(self, client):
        slot = self._readableSlot(self._getClientID(client),_marker)
        if slot is not _marker: 
            client._setSlot(slot)
            return slot
        else:
            return {}

    def _writeableSlotFor(self, client):
        slot = self._writeableSlot(self._getClientID(client))
        client._setSlot(slot)
        return slot

    def _readableSlot(self, key, default={}):
        return self.__readableStorage.get(key,default)

    def _writeableSlot(self, key):
        r = self.__writeableStorage.get(key,_marker)
        if r is _marker:
            r = self.__writeableStorage[key] = PersistentMapping()
        return r


00352     def _delSlotFor(self, client):

        """Delete persistent mapping for client, if present"""

        id = self._getClientID(client)
        if self.__readableStorage.has_key(id): del self.__writeableStorage[id]
        
    def getPersistentItemIDs(self):
        return self.__readableStorage.keys()









    # Management interface

    manage_storageForm = HTMLFile('www/storageForm', globals())

00374     def manage_setStorage(self, zclass=None, storage=None, use_attrib=None, \
        load_attrib=None, REQUEST=None):

        """
        Change class of returned items, and persistent storage used
        to store them
        """

        if zclass is not None:
            if self._unifiedZClassRegistry().has_key(zclass):
                #if Products.meta_classes.has_key(zclass):
                    self._zclass = zclass
                #else:
                #    self._zclass = self._unifiedZClassRegistry()[zclass][1]
                    if self.__dict__.has_key('_v_itemConstructor'):
                         del self._v_itemConstructor
            else:
                raise NameError,("Invalid/nonexistent ZClass '%s'" % zclass)

        if storage is not None and storage != self.storageInfo:
            self._migrateStorage(storage)

        if use_attrib is not None and load_attrib is not None:
            self.loadAttrib = (use_attrib=="YES") and load_attrib or ""

        if REQUEST is not None:
            return self.manage_storageForm(self, REQUEST,
                manage_tabs_message='Updated storage settings.')









00411     def manage_pack(self,REQUEST=None):
        """Pack storage and remove unused objects"""

        if self.__readableStorage:
            w=self.__writeableStorage
            c=0
            for id in self.getPersistentItemIDs():
                if self.getItem(id) is None: del w[id]
                c=(c+1) % 1000
                if not c: get_transaction().commit(1)

        if REQUEST is not None:
            return self.manage_storageForm(self, REQUEST,
                manage_tabs_message='Pack completed.')


    manage_options_right = (
                {'label':'Storage',
                 'action':'manage_storageForm'},
    ) + DataManager.manage_options_right


    meta_type = "Rack"
    __plugin_kind__ = "Rack"
    icon = 'misc_/ZPatterns/rack'

    __ac_permissions__ = (
        ('Change Rack storage settings',
            ('manage_storageForm','manage_setStorage','manage_storageOptions',
             'manage_pack'),
        ),

        ('Access contents information',
            ('getItem','retrieveItem','storageInUse','getPersistentItemIDs'),
        ),

        ('Add Items to Racks', ('newItem','createItem','newKey'), ),
    )

default__class_init__(Rack); MakePICBase(Rack)

manage_addRackForm = HTMLFile('addRack', globals())

def manage_addRack(self, id, title='', REQUEST=None):
    """Add a Rack"""
    ob = Rack(id, title)
    return self.Destination()._installPlugIn(ob,'Added Rack.',REQUEST)


class RackMountable(DataSkin):
    meta_type="Rack-mountable"


def initialize(context):

    context.registerPlugInClass(
        Rack,
        permission = 'Add Racks',
        constructors = (manage_addRackForm,
                        manage_addRack),
        icon = 'www/rack.gif',
    )

    context.registerPIContainerBase(Rack)



Generated by  Doxygen 1.6.0   Back to index