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