1 # Copyright (c) 2008 by Florian Friesdorf
3 # GNU Affero General Public License (AGPL)
5 # This program is free software; you can redistribute it and/or modify
6 # it under the terms of the GNU Affero General Public License as
7 # published by the Free Software Foundation; either version 3 of the
8 # License, or (at your option) any later version.
10 # This program is distributed in the hope that it will be useful,
11 # but WITHOUT ANY WARRANTY; without even the implied warranty of
12 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 # GNU Affero General Public License for more details.
15 # You should have received a copy of the GNU Affero General Public
16 # License along with this program. If not, see
17 # <http://www.gnu.org/licenses/>.
20 __author__
= "Florian Friesdorf <flo@chaoflow.net>"
21 __docformat__
= "plaintext"
23 from BTrees
import OOBTree
25 from persistent
import Persistent
26 from persistent
.list import PersistentList
28 from zope
.app
.container
.contained
import Contained
30 from zope
.component
import queryUtility
31 from zope
.component
.interfaces
import IFactory
33 from zope
.interface
import implements
35 from paula
.properties
.interfaces
import IPropertyProvider
36 from paula
.proputil
.interfaces
import IRWPropertyProviders
39 class RWPropertyProviders(Persistent
, Contained
):
40 """Utility delivering IPropertyProviders for principal ids
42 IPropertyProvider objects are generated by dynamic adapter lookup from
43 IPropertyProviderAdaptable objects, which are retrieved from an internal
44 mapping. Objects enter/leave the mapping through register/unregister.
46 Currently we do not support modification of principal id for registered
47 objects; before doing anything that modifies the prinicipal id of an object,
48 you need to unregister and reregister the object.
50 This utility could be registered globally and works outside of an
51 application server. However, the adapter lookup for IPropertyProvider
52 needs to be supported.
55 Mappings are empty, for a new utility
57 >>> ppu = RWPropertyProviders()
61 Suitable objects end up in the mapping, strings work as id
63 >>> a = Mock(id = '1')
64 >>> alsoProvides(a, IPropertyProvider)
66 >>> len(ppu._objs['1'])
68 >>> ppu._objs['1'][0] is a
71 Object with same id is appended to the same list
73 >>> b = Mock(id = '1')
74 >>> alsoProvides(b, IPropertyProvider)
76 >>> len(ppu._objs['1'])
78 >>> ppu._objs['1'][0] is a
80 >>> ppu._objs['1'][1] is b
83 Unsuitable object triggers TypeError
85 >>> c = Mock(id = '2')
86 >>> ppu.register(c) # doctest: +IGNORE_EXCEPTION_DETAIL
87 Traceback (most recent call last):
91 Object with different id enters new list
93 >>> c = Mock(id = '2')
94 >>> alsoProvides(c, IPropertyProvider)
96 >>> len(ppu._objs['2'])
98 >>> ppu._objs['2'][0] is c
101 Objects are retrieved correctly
117 in operator is working
124 list of all keys can be given
129 len() is working and contains the number of ids, we have providers for
134 implements(IRWPropertyProviders
)
139 self
._objs
= queryUtility(IFactory
, 'OOBTree', OOBTree
.OOBTree
)()
141 def __contains__(self
, id):
142 return self
.has_key(id)
144 def __getitem__(self
, id):
145 """retrieve IPropertyProvider list for principal id
147 pps
= [IPropertyProvider(x
) for x
in self
._objs
[id]]
151 return self
._objs
.__len
__()
153 def has_key(self
, id):
154 # I currently consider this a broken BTree
155 return bool(self
._objs
.has_key(id))
158 # I currently consider this a broken BTree
159 return list(self
._objs
.keys())
161 def register(self
, obj
):
162 """Register an object.
164 It is assumed that an adapter lookup for IPropertyProvider succeeds.
166 id = IPropertyProvider(obj
).id
168 objs
= self
._objs
[id]
170 self
._objs
[id] = PersistentList()
171 objs
= self
._objs
[id]
175 self
._objs
[id].append(obj
)
177 def unregister(self
, obj
):
178 """Unregister an object.
180 Fails with ValueError, if the object is not registered.
182 id = IPropertyProvider(obj
).id
183 self
._objs
[id].remove(obj
)