Package Products :: Package ZenRelations :: Module ToManyRelationship
[hide private]
[frames] | no frames]

Source Code for Module Products.ZenRelations.ToManyRelationship

  1  ########################################################################### 
  2  # 
  3  # This program is part of Zenoss Core, an open source monitoring platform. 
  4  # Copyright (C) 2007, Zenoss Inc. 
  5  # 
  6  # This program is free software; you can redistribute it and/or modify it 
  7  # under the terms of the GNU General Public License version 2 or (at your 
  8  # option) any later version as published by the Free Software Foundation. 
  9  # 
 10  # For complete information please visit: http://www.zenoss.com/oss/ 
 11  # 
 12  ########################################################################### 
 13   
 14  __doc__="""$Id: ToManyRelationship.py,v 1.48 2003/11/12 22:05:48 edahl Exp $""" 
 15   
 16  __version__ = "$Revision: 1.48 $"[11:-2] 
 17   
 18  import logging 
 19  log = logging.getLogger("zen.Relations") 
 20   
 21  from Globals import DTMLFile 
 22  from Globals import InitializeClass 
 23  from AccessControl import ClassSecurityInfo 
 24  from Acquisition import aq_base 
 25   
 26  from zExceptions import NotFound 
 27  from Products.ZenUtils.Utils import getObjByPath, unused 
 28   
 29  from ToManyRelationshipBase import ToManyRelationshipBase 
 30   
 31  from Products.ZenRelations.Exceptions import * 
 32   
 33  from persistent.list import PersistentList 
 34   
35 -def manage_addToManyRelationship(context, id, REQUEST=None):
36 """factory for ToManyRelationship""" 37 rel = ToManyRelationship(id) 38 context._setObject(rel.id, rel) 39 if REQUEST: 40 REQUEST['RESPONSE'].redirect(context.absolute_url()+'/manage_main') 41 return rel.id
42 43 44 addToManyRelationship = DTMLFile('dtml/addToManyRelationship',globals()) 45 46
47 -class ToManyRelationship(ToManyRelationshipBase):
48 """ 49 ToManyRelationship manages the ToMany side of a bi-directional relation 50 between to objects. It does not return values for any of the object* 51 calls defined on ObjectManager so that Zope can still work with its 52 containment assumptions. It provides object*All calles that return 53 its object in the same way that ObjectManager does. 54 55 Related references are maintained in a list. 56 """ 57 58 __pychecker__='no-override' 59 60 meta_type = "ToManyRelationship" 61 62 security = ClassSecurityInfo() 63
64 - def __init__(self, id):
65 """ToManyRelationships use an array to store related objects""" 66 self.id = id 67 self._objects = PersistentList() 68 self._count = 0
69
70 - def __call__(self):
71 """when we are called return our related object in our aq context""" 72 return self.objectValuesAll()
73
74 - def hasobject(self, obj):
75 "check to see if we have this object" 76 try: 77 idx = self._objects.index(obj) 78 return self._objects[idx] 79 except ValueError: 80 return None
81 82
83 - def manage_pasteObjects(self, cb_copy_data=None, REQUEST=None):
84 """ToManyRelationships link instead of pasting""" 85 return self.manage_linkObjects(cb_copy_data=cb_copy_data, 86 REQUEST=REQUEST)
87 88
89 - def _add(self,obj):
90 """add an object to one side of this toMany relationship""" 91 if obj in self._objects: raise RelationshipExistsError 92 self._objects.append(aq_base(obj)) 93 self.__primary_parent__._p_changed = True 94 self.setCount()
95 96
97 - def _remove(self, obj=None, suppress_events=False):
98 """remove object from our side of a relationship""" 99 if obj: 100 try: 101 self._objects.remove(obj) 102 except ValueError: 103 raise ObjectNotFound( 104 "object %s not found on relation %s" % ( 105 obj.getPrimaryId(), self.getPrimaryId())) 106 else: 107 self._objects = PersistentList() 108 self.__primary_parent__._p_changed = True 109 self.setCount()
110 111
112 - def _remoteRemove(self, obj=None):
113 """remove an object from the far side of this relationship 114 if no object is passed in remove all objects""" 115 if obj: 116 if obj not in self._objects: 117 raise ObjectNotFound("object %s not found on relation %s" % ( 118 obj.getPrimaryId(), self.getPrimaryId())) 119 objs = [obj] 120 else: objs = self.objectValuesAll() 121 remoteName = self.remoteName() 122 for obj in objs: 123 rel = getattr(obj, remoteName) 124 rel._remove(self.__primary_parent__)
125 126
127 - def _setObject(self,id,object,roles=None,user=None,set_owner=1):
128 """Set and object onto a ToMany by calling addRelation""" 129 unused(id, roles, user, set_owner) 130 self.addRelation(object)
131 132
133 - def _delObject(self, id, dp=1, suppress_events=False):
134 """ 135 Delete object by its absolute id (ie /zport/dmd/bla/bla) 136 (this is sent out in the object*All API) 137 """ 138 obj = getObjByPath(self, id) 139 self.removeRelation(obj, suppress_events=suppress_events)
140 141
142 - def _getOb(self, id, default=zenmarker):
143 """ 144 Return object based on its primaryId. plain id will not work!!! 145 """ 146 objs = filter(lambda x: x.getPrimaryId() == id, self._objects) 147 if len(objs) == 1: return objs[0].__of__(self) 148 if default != zenmarker: return default 149 raise AttributeError(id)
150 151
152 - def objectIdsAll(self):
153 """ 154 Return object ids as their absolute primaryId. 155 """ 156 return [obj.getPrimaryId() for obj in self._objects]
157 158
159 - def objectIds(self, spec=None):
160 """ 161 ToManyRelationship doesn't publish objectIds to prevent 162 zope recursion problems. 163 """ 164 unused(spec) 165 return []
166 167 168 security.declareProtected('View', 'objectValuesAll')
169 - def objectValuesAll(self):
170 """return all related object values""" 171 return list(self.objectValuesGen())
172 173
174 - def objectValuesGen(self):
175 """Generator that returns all related objects.""" 176 rname = self.remoteName() 177 parobj = self.getPrimaryParent() 178 for obj in self._objects: 179 # Disabling relationship checking code. 180 # http://dev.zenoss.org/trac/ticket/5391 181 #if self.checkObjectRelation(obj, rname, parobj, True): 182 # continue 183 yield obj.__of__(self)
184 185
186 - def objectValues(self, spec=None):
187 """ 188 ToManyRelationship doesn't publish objectValues to prevent 189 zope recursion problems. 190 """ 191 unused(spec) 192 return []
193 194
195 - def objectItemsAll(self):
196 """ 197 Return object items where key is primaryId. 198 """ 199 objs = [] 200 for obj in self._objects: 201 objs.append((obj.getPrimaryId(), obj)) 202 return objs
203 204
205 - def objectItems(self, spec=None):
206 """ 207 ToManyRelationship doesn't publish objectItems to prevent 208 zope recursion problems. 209 """ 210 unused(spec) 211 return []
212 213
214 - def _getCopy(self, container):
215 """ 216 create copy and link remote objects if remote side is TO_MANY 217 """ 218 rel = self.__class__(self.id) 219 rel.__primary_parent__ = container 220 rel = rel.__of__(container) 221 norelcopy = getattr(self, 'zNoRelationshipCopy', []) 222 if self.id in norelcopy: return rel 223 if self.remoteTypeName() == "ToMany": 224 for robj in self.objectValuesAll(): 225 rel.addRelation(robj) 226 return rel
227 228
229 - def exportXml(self,ofile,ignorerels=[]):
230 """Return an xml representation of a ToManyRelationship 231 <tomany id='interfaces'> 232 <link>/Systems/OOL/Mail</link> 233 </tomany> 234 """ 235 if self.countObjects() == 0: return 236 ofile.write("<tomany id='%s'>\n" % self.id) 237 for id in self.objectIdsAll(): 238 ofile.write("<link objid='%s'/>\n" % id) 239 ofile.write("</tomany>\n")
240 241
242 - def all_meta_types(self, interfaces=None):
243 """Return empty list not allowed to add objects to a ToManyRelation""" 244 return []
245 246
247 - def convertToPersistentList(self):
248 self._objects = PersistentList(self._objects) 249 self.setCount()
250 251
252 - def checkObjectRelation(self, obj, remoteName, parentObject, repair):
253 deleted = False 254 try: 255 ppath = obj.getPrimaryPath() 256 getObjByPath(self, ppath) 257 except (KeyError, NotFound): 258 log.error("object %s in relation %s has been deleted " \ 259 "from its primary path", 260 obj.getPrimaryId(), self.getPrimaryId()) 261 if repair: 262 log.warn("removing object %s from relation %s", 263 obj.getPrimaryId(), self.getPrimaryId()) 264 self._objects.remove(obj) 265 self.__primary_parent__._p_changed = True 266 deleted = True 267 268 if not deleted: 269 rrel = getattr(obj, remoteName) 270 if not rrel.hasobject(parentObject): 271 log.error("remote relation %s doesn't point back to %s", 272 rrel.getPrimaryId(), self.getPrimaryId()) 273 if repair: 274 log.warn("reconnecting relation %s to relation %s", 275 rrel.getPrimaryId(),self.getPrimaryId()) 276 rrel._add(parentObject) 277 return deleted
278 279
280 - def checkRelation(self, repair=False):
281 """Check to make sure that relationship bidirectionality is ok. 282 """ 283 if len(self._objects): 284 log.debug("checking relation: %s", self.id) 285 286 # look for objects that don't point back to us 287 # or who should no longer exist in the database 288 rname = self.remoteName() 289 parobj = self.getPrimaryParent() 290 for obj in self._objects: 291 self.checkObjectRelation(obj, rname, parobj, repair) 292 293 # find duplicate objects 294 keycount = {} 295 for obj in self._objects: 296 key = obj.getPrimaryId() 297 c = keycount.setdefault(key, 0) 298 c += 1 299 keycount[key] = c 300 # Remove duplicate objects or objects that don't exist 301 for key, val in keycount.items(): 302 if val > 1: 303 log.critical("obj:%s rel:%s dup found obj:%s count:%s", 304 self.getPrimaryId(), self.id, key, val) 305 if repair: 306 log.critical("repair key %s", key) 307 self._objects = [ o for o in self._objects \ 308 if o.getPrimaryId() != key ] 309 try: 310 obj = self.getObjByPath(key) 311 self._objects.append(obj) 312 except KeyError: 313 log.critical("obj %s not found in database", key)
314 315 316 InitializeClass(ToManyRelationship) 317