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

Source Code for Module Products.ZenRelations.ToManyContRelationship

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