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

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