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