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.app.container.contained import ObjectAddedEvent
34 from zope.app.container.contained import ObjectRemovedEvent
35 from zope.app.container.contained import ContainerModifiedEvent
36 from zope.app.container.contained import dispatchToSublocations
37
38 from BTrees.OOBTree import OOBTree
39
40 from ToManyRelationshipBase import ToManyRelationshipBase
41
42 from Products.ZenRelations.Exceptions import *
43
44 from Products.ZenUtils.Utils import unused
45
53
54
55 addToManyContRelationship = DTMLFile('dtml/addToManyContRelationship',globals())
56
57
59 """
60 ToManyContRelationship is the ToMany side of a realtionship that
61 contains its related objects (like the normal Zope ObjectManager)
62 """
63
64 meta_type = "ToManyContRelationship"
65
66 security = ClassSecurityInfo()
67
68
70 """set our instance values"""
71 self.id = id
72 self._objects = OOBTree()
73
74
76 """
77 Try to safely return ZenPack objects rather than
78 causing imports to fail.
79 """
80 objs = []
81 for ob in self._objects.values():
82 try:
83 objs.append(ob.__of__(self))
84 except AttributeError:
85 log.info("Ignoring unresolvable object '%s'", str(ob))
86 return objs
87
89 """when we are called return our related object in our aq context"""
90 return self._safeOfObjects()
91
92
94 """look in the two object stores for related objects"""
95 if self.__dict__.has_key("_objects"):
96 objects = self.__dict__['_objects']
97 if objects.has_key(name): return objects[name]
98 raise AttributeError( "Unable to find the attribute '%s'" % name )
99
100
102 """check to see if we have an object by an id
103 this will fail if passed a short id and object is stored
104 with fullid (ie: it is related not contained)
105 use hasobject to get around this issue"""
106 return self._objects.has_key(name)
107
108
110 "check to see if we have this object"
111 return self._objects.get(obj.id) == obj
112
113
121
122
123 - def _setObject(self,id,object,roles=None,user=None,set_owner=1):
129
130
134 manage_afterAdd.__five_method__ = True
135
139 manage_afterClone.__five_method__ = True
140
144 manage_beforeDelete.__five_method__ = True
145
146 - def _add(self,obj):
147 """add an object to one side of a ToManyContRelationship.
148 """
149 id = obj.id
150 if self._objects.has_key(id):
151 raise RelationshipExistsError
152 v=checkValidId(self, id)
153 if v is not None: id=v
154 self._objects[id] = aq_base(obj)
155 obj = aq_base(obj).__of__(self)
156
157
158 - def _remove(self, obj=None, suppress_events=False):
159 """remove object from our side of a relationship"""
160 if obj: objs = [obj]
161 else: objs = self.objectValuesAll()
162 if not suppress_events:
163 for robj in objs:
164 notify(ObjectWillBeRemovedEvent(robj, self, robj.getId()))
165 if obj:
166 id = obj.id
167 if not self._objects.has_key(id):
168 raise ObjectNotFound(
169 "object %s not found on %s" % (
170 obj.getPrimaryId(), self.getPrimaryId()))
171 del self._objects[id]
172 else:
173 self._objects = OOBTree()
174 self.__primary_parent__._p_changed = True
175 if not suppress_events:
176 for robj in objs:
177 notify(ObjectRemovedEvent(robj, self, robj.getId()))
178 notify(ContainerModifiedEvent(self))
179
180
194
195
197 """look up in our local store and wrap in our aq_chain"""
198 if self._objects.has_key(id):
199 return self._objects[id].__of__(self)
200 elif default == zenmarker:
201 raise AttributeError( "Unable to find %s" % id )
202 return default
203
204
205 security.declareProtected('View', 'objectIds')
207 """only return contained objects"""
208 if spec:
209 if type(spec)==type('s'): spec=[spec]
210 return [obj.id for obj in self._objects.values() \
211 if obj.meta_type in spec]
212 return [ k for k in self._objects.keys() ]
213 objectIdsAll = objectIds
214
215
216 security.declareProtected('View', 'objectValues')
218 """override to only return owned objects for many to many rel"""
219 if spec:
220 if type(spec)==type('s'): spec=[spec]
221 return [ob.__of__(self) for ob in self._objects.values() \
222 if ob.meta_type in spec]
223 return self._safeOfObjects()
224 security.declareProtected('View', 'objectValuesAll')
225 objectValuesAll = objectValues
226
227
229 """Generator that returns all related objects."""
230 for obj in self._objects.values():
231 yield obj.__of__(self)
232
233
235 """over ride to only return owned objects for many to many rel"""
236 if spec:
237 if type(spec)==type('s'): spec=[spec]
238 return [(key,value.__of__(self)) \
239 for (key,value) in self._objects.items() \
240 if value.meta_type in spec]
241 return [(key,value.__of__(self)) \
242 for (key,value) in self._objects.items()]
243 objectItemsAll = objectItems
244
245
246
247
248
249
250
251
252
253
254
255
256
258 """
259 make new relation add copies of contained objs
260 and refs if the relation is a many to many
261 """
262 rel = self.__class__(self.id)
263 rel.__primary_parent__ = container
264 rel = rel.__of__(container)
265 norelcopy = getattr(self, 'zNoRelationshipCopy', [])
266 if self.id in norelcopy: return rel
267 for oobj in self.objectValuesAll():
268 cobj = oobj._getCopy(rel)
269 rel._setObject(cobj.id, cobj)
270 return rel
271
273 """
274 Is this a valid id for this container?
275 """
276 try:
277 checkValidId(self, id)
278 except:
279 raise
280 else:
281 return True
282
284 """Return an xml representation of a ToManyContRelationship
285 <tomanycont id='interfaces'>
286 <object id='hme0'
287 module='Products.Confmon.IpInterface' class='IpInterface'>
288 <property></property> etc....
289 </object>
290 </tomanycont>
291 """
292 if self.countObjects() == 0: return
293 ofile.write("<tomanycont id='%s'>\n" % self.id)
294 for obj in self.objectValues():
295 obj.exportXml(ofile, ignorerels)
296 ofile.write("</tomanycont>\n")
297
298
299 InitializeClass(ToManyContRelationship)
300
301
303 """
304 Adapter so the event dispatching can propagate to children.
305 """
307 self.container = container
310