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