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

Source Code for Module Products.ZenRelations.ToManyContRelationship

  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__ = """ToManyContRelationship 
 15  A to-many container relationship 
 16  """ 
 17   
 18   
 19  import logging 
 20  log = logging.getLogger("zen.Relations") 
 21   
 22  from Globals import DTMLFile 
 23  from Globals import InitializeClass 
 24  from AccessControl import ClassSecurityInfo 
 25  from Acquisition import aq_base 
 26  from OFS.ObjectManager import checkValidId, BeforeDeleteException 
 27  from ZODB.POSException import ConflictError 
 28   
 29  import OFS.subscribers 
 30  from OFS.event import ObjectWillBeAddedEvent 
 31  from OFS.event import ObjectWillBeRemovedEvent 
 32  from zope.event import notify 
 33  from zope.container.contained import ObjectAddedEvent 
 34  from zope.container.contained import ObjectRemovedEvent 
 35  from zope.container.contained import dispatchToSublocations 
 36   
 37  from BTrees.OOBTree import OOBTree 
 38   
 39  from ToManyRelationshipBase import ToManyRelationshipBase 
 40   
 41  from Products.ZenRelations.Exceptions import * 
 42   
 43  from Products.ZenUtils.Utils import unused 
 44   
45 -def manage_addToManyContRelationship(context, id, REQUEST=None):
46 """factory for ToManyRelationship""" 47 rel = ToManyContRelationship(id) 48 context._setObject(rel.id, rel) 49 if REQUEST: 50 REQUEST['RESPONSE'].redirect(context.absolute_url()+'/manage_main') 51 return rel.id
52 53 54 addToManyContRelationship = DTMLFile('dtml/addToManyContRelationship',globals()) 55 56
57 -class ToManyContRelationship(ToManyRelationshipBase):
58 """ 59 ToManyContRelationship is the ToMany side of a realtionship that 60 contains its related objects (like the normal Zope ObjectManager) 61 """ 62 63 meta_type = "ToManyContRelationship" 64 65 security = ClassSecurityInfo() 66 67
68 - def __init__(self, id):
69 """set our instance values""" 70 self.id = id 71 self._objects = OOBTree()
72 73
74 - def _safeOfObjects(self):
75 """ 76 Try to safely return ZenPack objects rather than 77 causing imports to fail. 78 """ 79 objs = [] 80 for ob in self._objects.values(): 81 try: 82 objs.append(ob.__of__(self)) 83 except AttributeError: 84 log.info("Ignoring unresolvable object '%s'", str(ob)) 85 return objs
86
87 - def __call__(self):
88 """when we are called return our related object in our aq context""" 89 return self._safeOfObjects()
90 91
92 - def __getattr__(self, name):
93 """look in the two object stores for related objects""" 94 if '_objects' in self.__dict__: 95 objects = self._objects 96 if objects.has_key(name): return objects[name] 97 raise AttributeError( "Unable to find the attribute '%s'" % name )
98 99
100 - def __hasattr__(self, name):
101 """check to see if we have an object by an id 102 this will fail if passed a short id and object is stored 103 with fullid (ie: it is related not contained) 104 use hasobject to get around this issue""" 105 return self._objects.has_key(name)
106 107
108 - def hasobject(self, obj):
109 "check to see if we have this object" 110 return self._objects.get(obj.id) == obj
111 112
113 - def addRelation(self, obj):
114 """Override base to run manage_afterAdd like ObjectManager""" 115 if self._objects.has_key(obj.getId()): 116 log.debug("obj %s already exists on %s", obj.getPrimaryId(), 117 self.getPrimaryId()) 118 119 notify(ObjectWillBeAddedEvent(obj, self, obj.getId())) 120 ToManyRelationshipBase.addRelation(self, obj) 121 obj = obj.__of__(self) 122 o = self._getOb(obj.id) 123 notify(ObjectAddedEvent(o, self, obj.getId()))
124 125
126 - def _setObject(self,id,object,roles=None,user=None,set_owner=1):
127 """ObjectManager interface to add contained object.""" 128 unused(user, roles, set_owner) 129 object.__primary_parent__ = aq_base(self) 130 self.addRelation(object) 131 return object.getId()
132 133
134 - def manage_afterAdd(self, item, container):
135 # Don't do recursion anymore, a subscriber does that. 136 pass
137 manage_afterAdd.__five_method__ = True 138
139 - def manage_afterClone(self, item):
140 # Don't do recursion anymore, a subscriber does that. 141 pass
142 manage_afterClone.__five_method__ = True 143
144 - def manage_beforeDelete(self, item, container):
145 # Don't do recursion anymore, a subscriber does that. 146 pass
147 manage_beforeDelete.__five_method__ = True 148
149 - def _add(self,obj):
150 """add an object to one side of a ToManyContRelationship. 151 """ 152 id = obj.id 153 if self._objects.has_key(id): 154 raise RelationshipExistsError 155 v=checkValidId(self, id) 156 if v is not None: id=v 157 self._objects[id] = aq_base(obj) 158 obj = aq_base(obj).__of__(self) 159 self.setCount()
160 161
162 - def _remove(self, obj=None, suppress_events=False):
163 """remove object from our side of a relationship""" 164 if obj: objs = [obj] 165 else: objs = self.objectValuesAll() 166 if not suppress_events: 167 for robj in objs: 168 notify(ObjectWillBeRemovedEvent(robj, self, robj.getId())) 169 if obj: 170 id = obj.id 171 if not self._objects.has_key(id): 172 raise ObjectNotFound( 173 "object %s not found on %s" % ( 174 obj.getPrimaryId(), self.getPrimaryId())) 175 del self._objects[id] 176 else: 177 self._objects = OOBTree() 178 self.__primary_parent__._p_changed = True 179 if not suppress_events: 180 for robj in objs: 181 notify(ObjectRemovedEvent(robj, self, robj.getId())) 182 self.setCount()
183 184
185 - def _remoteRemove(self, obj=None):
186 """remove an object from the far side of this relationship 187 if no object is passed in remove all objects""" 188 if obj: 189 if not self._objects.has_key(obj.id): 190 raise ObjectNotFound("object %s not found on %s" % ( 191 obj.getPrimaryId(), self.getPrimaryId())) 192 objs = [obj] 193 else: objs = self.objectValuesAll() 194 remoteName = self.remoteName() 195 for obj in objs: 196 rel = getattr(obj, remoteName) 197 rel._remove(self.__primary_parent__)
198 199
200 - def _getOb(self, id, default=zenmarker):
201 """look up in our local store and wrap in our aq_chain""" 202 if self._objects.has_key(id): 203 return self._objects[id].__of__(self) 204 elif default == zenmarker: 205 raise AttributeError( "Unable to find %s" % id ) 206 return default
207 208 209 security.declareProtected('View', 'objectIds')
210 - def objectIds(self, spec=None):
211 """only return contained objects""" 212 if spec: 213 if isinstance(spec,basestring): spec=[spec] 214 return [obj.id for obj in self._objects.values() \ 215 if obj.meta_type in spec] 216 return [ k for k in self._objects.keys() ]
217 objectIdsAll = objectIds 218 219 220 security.declareProtected('View', 'objectValues')
221 - def objectValues(self, spec=None):
222 """override to only return owned objects for many to many rel""" 223 if spec: 224 if isinstance(spec,basestring): spec=[spec] 225 return [ob.__of__(self) for ob in self._objects.values() \ 226 if ob.meta_type in spec] 227 return self._safeOfObjects()
228 security.declareProtected('View', 'objectValuesAll') 229 objectValuesAll = objectValues 230 231
232 - def objectValuesGen(self):
233 """Generator that returns all related objects.""" 234 for obj in self._objects.values(): 235 yield obj.__of__(self)
236 237
238 - def objectItems(self, spec=None):
239 """over ride to only return owned objects for many to many rel""" 240 if spec: 241 if isinstance(spec,basestring): spec=[spec] 242 return [(key,value.__of__(self)) \ 243 for (key,value) in self._objects.items() \ 244 if value.meta_type in spec] 245 return [(key,value.__of__(self)) \ 246 for (key,value) in self._objects.items()]
247 objectItemsAll = objectItems 248 249 250 #FIXME - need to make this work 251 # def all_meta_types(self, interfaces=None): 252 # mts = [] 253 # for mt in ToManyRelationshipBase.all_meta_types(self, interfaces): 254 # if (mt.has_key('instance') and mt['instance']): 255 # for cl in self.sub_classes: 256 # if checkClass(mt['instance'], cl): 257 # mts.append(mt) 258 # return mts 259 260
261 - def _getCopy(self, container):
262 """ 263 make new relation add copies of contained objs 264 and refs if the relation is a many to many 265 """ 266 rel = self.__class__(self.id) 267 rel.__primary_parent__ = container 268 rel = rel.__of__(container) 269 norelcopy = getattr(self, 'zNoRelationshipCopy', []) 270 if self.id in norelcopy: return rel 271 for oobj in self.objectValuesAll(): 272 cobj = oobj._getCopy(rel) 273 rel._setObject(cobj.id, cobj) 274 return rel
275
276 - def checkValidId(self, id):
277 """ 278 Is this a valid id for this container? 279 """ 280 try: 281 checkValidId(self, id) 282 except: 283 raise 284 else: 285 return True
286
287 - def exportXml(self, ofile, ignorerels=[]):
288 """Return an xml representation of a ToManyContRelationship 289 <tomanycont id='interfaces'> 290 <object id='hme0' 291 module='Products.Confmon.IpInterface' class='IpInterface'> 292 <property></property> etc.... 293 </object> 294 </tomanycont> 295 """ 296 if self.countObjects() == 0: return 297 ofile.write("<tomanycont id='%s'>\n" % self.id) 298 for obj in self.objectValues(): 299 obj.exportXml(ofile, ignorerels) 300 ofile.write("</tomanycont>\n")
301 302
303 - def checkRelation(self, repair=False):
304 """Check to make sure that relationship bidirectionality is ok. 305 """ 306 if len(self._objects): 307 log.debug("checking relation: %s", self.id) 308 else: 309 return 310 311 # look for objects that don't point back to us 312 # or who should no longer exist in the database 313 remoteName = self.remoteName() 314 parentObject = self.getPrimaryParent() 315 for obj in self._objects.values(): 316 rrel = getattr(obj, remoteName) 317 if not rrel.hasobject(parentObject): 318 log.error("remote relation %s doesn't point back to %s", 319 rrel.getPrimaryId(), self.getPrimaryId()) 320 if repair: 321 log.warn("reconnecting relation %s to relation %s", 322 rrel.getPrimaryId(),self.getPrimaryId()) 323 rrel._add(parentObject)
324 325 326 327 InitializeClass(ToManyContRelationship) 328 329
330 -class ToManyContSublocations(object):
331 """ 332 Adapter so the event dispatching can propagate to children. 333 """
334 - def __init__(self, container):
335 self.container = container
336 - def sublocations(self):
337 return (ob for ob in self.container.objectValuesAll())
338