1
2
3
4
5
6
7
8
9
10
11 __doc__="""$Id: ToManyRelationship.py,v 1.48 2003/11/12 22:05:48 edahl Exp $"""
12
13 __version__ = "$Revision: 1.48 $"[11:-2]
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
24 from zExceptions import NotFound
25 from Products.ZenUtils.Utils import getObjByPath, unused
26 from Products.ZenUtils.tbdetail import log_tb
27
28 from ToManyRelationshipBase import ToManyRelationshipBase
29
30 from Products.ZenRelations.Exceptions import *
31
32 from persistent.list import PersistentList
33
41
42
43 addToManyRelationship = DTMLFile('dtml/addToManyRelationship',globals())
44
45
47 """
48 ToManyRelationship manages the ToMany side of a bi-directional relation
49 between to objects. It does not return values for any of the object*
50 calls defined on ObjectManager so that Zope can still work with its
51 containment assumptions. It provides object*All calles that return
52 its object in the same way that ObjectManager does.
53
54 Related references are maintained in a list.
55 """
56
57 __pychecker__='no-override'
58
59 meta_type = "ToManyRelationship"
60
61 security = ClassSecurityInfo()
62
64 """ToManyRelationships use an array to store related objects"""
65 self.id = id
66 self._objects = PersistentList()
67 self._count = 0
68
70 """when we are called return our related object in our aq context"""
71 return self.objectValuesAll()
72
74 "check to see if we have this object"
75 try:
76 idx = self._objects.index(obj)
77 return self._objects[idx]
78 except ValueError:
79 return None
80
81
86
87
89 """add an object to one side of this toMany relationship"""
90 if obj in self._objects: raise RelationshipExistsError
91 self._objects.append(aq_base(obj))
92 self.__primary_parent__._p_changed = True
93 self.setCount()
94
95
96 - def _remove(self, obj=None, suppress_events=False):
97 """remove object from our side of a relationship"""
98 if obj:
99 try:
100 self._objects.remove(obj)
101 except ValueError:
102 raise ObjectNotFound(
103 "object %s not found on relation %s" % (
104 obj.getPrimaryId(), self.getPrimaryId()))
105 else:
106 self._objects = PersistentList()
107 self.__primary_parent__._p_changed = True
108 self.setCount()
109
110
128
129
130 - def _setObject(self,id,object,roles=None,user=None,set_owner=1):
131 """Set and object onto a ToMany by calling addRelation"""
132 unused(id, roles, user, set_owner)
133 self.addRelation(object)
134
135
136 - def _delObject(self, id, dp=1, suppress_events=False):
137 """
138 Delete object by its absolute id (ie /zport/dmd/bla/bla)
139 (this is sent out in the object*All API)
140 """
141 obj = getObjByPath(self, id)
142 self.removeRelation(obj, suppress_events=suppress_events)
143
144
146 """
147 Return object based on its primaryId. plain id will not work!!!
148 """
149 objs = filter(lambda x: x.getPrimaryId() == id, self._objects)
150 if len(objs) == 1: return objs[0].__of__(self)
151 if default != zenmarker: return default
152 raise AttributeError(id)
153
154
156 """
157 Return object ids as their absolute primaryId.
158 """
159 return [obj.getPrimaryId() for obj in self._objects]
160
161
163 """
164 ToManyRelationship doesn't publish objectIds to prevent
165 zope recursion problems.
166 """
167 unused(spec)
168 return []
169
170
171 security.declareProtected('View', 'objectValuesAll')
175
176
178 """Generator that returns all related objects."""
179 rname = self.remoteName()
180 parobj = self.getPrimaryParent()
181 for obj in self._objects:
182
183
184
185
186 yield obj.__of__(self)
187
188
190 """
191 ToManyRelationship doesn't publish objectValues to prevent
192 zope recursion problems.
193 """
194 unused(spec)
195 return []
196
197
199 """
200 Return object items where key is primaryId.
201 """
202 objs = []
203 for obj in self._objects:
204 objs.append((obj.getPrimaryId(), obj))
205 return objs
206
207
209 """
210 ToManyRelationship doesn't publish objectItems to prevent
211 zope recursion problems.
212 """
213 unused(spec)
214 return []
215
216
218 """
219 create copy and link remote objects if remote side is TO_MANY
220 """
221 rel = self.__class__(self.id)
222 rel.__primary_parent__ = container
223 rel = rel.__of__(container)
224 norelcopy = getattr(self, 'zNoRelationshipCopy', [])
225 if self.id in norelcopy: return rel
226 if self.remoteTypeName() == "ToMany":
227 for robj in self.objectValuesAll():
228 rel.addRelation(robj)
229 return rel
230
231
233 """Return an xml representation of a ToManyRelationship
234 <tomany id='interfaces'>
235 <link>/Systems/OOL/Mail</link>
236 </tomany>
237 """
238 if self.countObjects() == 0: return
239 ofile.write("<tomany id='%s'>\n" % self.id)
240 for id in self.objectIdsAll():
241 ofile.write("<link objid='%s'/>\n" % id)
242 ofile.write("</tomany>\n")
243
244
248
249
251 self._objects = PersistentList(self._objects)
252 self.setCount()
253
254
256 deleted = False
257 try:
258 ppath = obj.getPrimaryPath()
259 getObjByPath(self, ppath)
260 except (KeyError, NotFound):
261 log.error("object %s in relation %s has been deleted " \
262 "from its primary path",
263 obj.getPrimaryId(), self.getPrimaryId())
264 if repair:
265 log.warn("removing object %s from relation %s",
266 obj.getPrimaryId(), self.getPrimaryId())
267 self._objects.remove(obj)
268 self.__primary_parent__._p_changed = True
269 deleted = True
270
271 if not deleted:
272 rrel = getattr(obj, remoteName)
273 if not rrel.hasobject(parentObject):
274 log.error("remote relation %s doesn't point back to %s",
275 rrel.getPrimaryId(), self.getPrimaryId())
276 if repair:
277 log.warn("reconnecting relation %s to relation %s",
278 rrel.getPrimaryId(),self.getPrimaryId())
279 rrel._add(parentObject)
280 return deleted
281
282
284 """Check to make sure that relationship bidirectionality is ok.
285 """
286 if len(self._objects):
287 log.debug("checking relation: %s", self.id)
288
289
290
291 rname = self.remoteName()
292 parobj = self.getPrimaryParent()
293 for obj in self._objects:
294 self.checkObjectRelation(obj, rname, parobj, repair)
295
296
297 keycount = {}
298 for obj in self._objects:
299 key = obj.getPrimaryId()
300 c = keycount.setdefault(key, 0)
301 c += 1
302 keycount[key] = c
303
304 for key, val in keycount.items():
305 if val > 1:
306 log.critical("obj:%s rel:%s dup found obj:%s count:%s",
307 self.getPrimaryId(), self.id, key, val)
308 if repair:
309 log.critical("repair key %s", key)
310 self._objects = [ o for o in self._objects \
311 if o.getPrimaryId() != key ]
312 try:
313 obj = self.getObjByPath(key)
314 self._objects.append(obj)
315 except KeyError:
316 log.critical("obj %s not found in database", key)
317
318
319 InitializeClass(ToManyRelationship)
320