1
2
3
4
5
6
7
8
9
10
11
12
13
14 __doc__ = """ToManyContRelationship
15 A to-many container relationship
16 """
17
18
19 import logging
20 log = logging.getLogger("zen.Relations")
21
22 from Globals import DTMLFile
23 from Globals import InitializeClass
24 from AccessControl import ClassSecurityInfo
25 from Acquisition import aq_base
26 from OFS.ObjectManager import checkValidId, BeforeDeleteException
27 from ZODB.POSException import ConflictError
28
29 import OFS.subscribers
30 from OFS.event import ObjectWillBeAddedEvent
31 from OFS.event import ObjectWillBeRemovedEvent
32 from zope.event import notify
33 from zope.container.contained import ObjectAddedEvent
34 from zope.container.contained import ObjectRemovedEvent
35 from zope.container.contained import dispatchToSublocations
36
37 from BTrees.OOBTree import OOBTree
38
39 from ToManyRelationshipBase import ToManyRelationshipBase
40
41 from Products.ZenRelations.Exceptions import *
42
43 from Products.ZenUtils.Utils import unused
44
52
53
54 addToManyContRelationship = DTMLFile('dtml/addToManyContRelationship',globals())
55
56
58 """
59 ToManyContRelationship is the ToMany side of a realtionship that
60 contains its related objects (like the normal Zope ObjectManager)
61 """
62
63 meta_type = "ToManyContRelationship"
64
65 security = ClassSecurityInfo()
66
67
69 """set our instance values"""
70 self.id = id
71 self._objects = OOBTree()
72
73
75 """
76 Try to safely return ZenPack objects rather than
77 causing imports to fail.
78 """
79 objs = []
80 for ob in self._objects.values():
81 try:
82 objs.append(ob.__of__(self))
83 except AttributeError:
84 log.info("Ignoring unresolvable object '%s'", str(ob))
85 return objs
86
88 """when we are called return our related object in our aq context"""
89 return self._safeOfObjects()
90
91
93 """look in the two object stores for related objects"""
94 if '_objects' in self.__dict__:
95 objects = self._objects
96 if objects.has_key(name): return objects[name]
97 raise AttributeError( "Unable to find the attribute '%s'" % name )
98
99
101 """check to see if we have an object by an id
102 this will fail if passed a short id and object is stored
103 with fullid (ie: it is related not contained)
104 use hasobject to get around this issue"""
105 return self._objects.has_key(name)
106
107
109 "check to see if we have this object"
110 return self._objects.get(obj.id) == obj
111
112
124
125
126 - def _setObject(self,id,object,roles=None,user=None,set_owner=1):
127 """ObjectManager interface to add contained object."""
128 unused(user, roles, set_owner)
129 object.__primary_parent__ = aq_base(self)
130 self.addRelation(object)
131 return object.getId()
132
133
137 manage_afterAdd.__five_method__ = True
138
142 manage_afterClone.__five_method__ = True
143
147 manage_beforeDelete.__five_method__ = True
148
149 - def _add(self,obj):
160
161
162 - def _remove(self, obj=None, suppress_events=False):
163 """remove object from our side of a relationship"""
164 if obj: objs = [obj]
165 else: objs = self.objectValuesAll()
166 if not suppress_events:
167 for robj in objs:
168 notify(ObjectWillBeRemovedEvent(robj, self, robj.getId()))
169 if obj:
170 id = obj.id
171 if not self._objects.has_key(id):
172 raise ObjectNotFound(
173 "object %s not found on %s" % (
174 obj.getPrimaryId(), self.getPrimaryId()))
175 del self._objects[id]
176 else:
177 self._objects = OOBTree()
178 self.__primary_parent__._p_changed = True
179 if not suppress_events:
180 for robj in objs:
181 notify(ObjectRemovedEvent(robj, self, robj.getId()))
182 self.setCount()
183
184
198
199
201 """look up in our local store and wrap in our aq_chain"""
202 if self._objects.has_key(id):
203 return self._objects[id].__of__(self)
204 elif default == zenmarker:
205 raise AttributeError( "Unable to find %s" % id )
206 return default
207
208
209 security.declareProtected('View', 'objectIds')
211 """only return contained objects"""
212 if spec:
213 if isinstance(spec,basestring): spec=[spec]
214 return [obj.id for obj in self._objects.values() \
215 if obj.meta_type in spec]
216 return [ k for k in self._objects.keys() ]
217 objectIdsAll = objectIds
218
219
220 security.declareProtected('View', 'objectValues')
222 """override to only return owned objects for many to many rel"""
223 if spec:
224 if isinstance(spec,basestring): spec=[spec]
225 return [ob.__of__(self) for ob in self._objects.values() \
226 if ob.meta_type in spec]
227 return self._safeOfObjects()
228 security.declareProtected('View', 'objectValuesAll')
229 objectValuesAll = objectValues
230
231
233 """Generator that returns all related objects."""
234 for obj in self._objects.values():
235 yield obj.__of__(self)
236
237
239 """over ride to only return owned objects for many to many rel"""
240 if spec:
241 if isinstance(spec,basestring): spec=[spec]
242 return [(key,value.__of__(self)) \
243 for (key,value) in self._objects.items() \
244 if value.meta_type in spec]
245 return [(key,value.__of__(self)) \
246 for (key,value) in self._objects.items()]
247 objectItemsAll = objectItems
248
249
250
251
252
253
254
255
256
257
258
259
260
262 """
263 make new relation add copies of contained objs
264 and refs if the relation is a many to many
265 """
266 rel = self.__class__(self.id)
267 rel.__primary_parent__ = container
268 rel = rel.__of__(container)
269 norelcopy = getattr(self, 'zNoRelationshipCopy', [])
270 if self.id in norelcopy: return rel
271 for oobj in self.objectValuesAll():
272 cobj = oobj._getCopy(rel)
273 rel._setObject(cobj.id, cobj)
274 return rel
275
277 """
278 Is this a valid id for this container?
279 """
280 try:
281 checkValidId(self, id)
282 except:
283 raise
284 else:
285 return True
286
288 """Return an xml representation of a ToManyContRelationship
289 <tomanycont id='interfaces'>
290 <object id='hme0'
291 module='Products.Confmon.IpInterface' class='IpInterface'>
292 <property></property> etc....
293 </object>
294 </tomanycont>
295 """
296 if self.countObjects() == 0: return
297 ofile.write("<tomanycont id='%s'>\n" % self.id)
298 for obj in self.objectValues():
299 obj.exportXml(ofile, ignorerels)
300 ofile.write("</tomanycont>\n")
301
302
324
325
326
327 InitializeClass(ToManyContRelationship)
328
329
331 """
332 Adapter so the event dispatching can propagate to children.
333 """
335 self.container = container
338