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

Source Code for Module Products.ZenRelations.RelationshipManager

  1   
  2  ########################################################################### 
  3  # 
  4  # This program is part of Zenoss Core, an open source monitoring platform. 
  5  # Copyright (C) 2007, Zenoss Inc. 
  6  # 
  7  # This program is free software; you can redistribute it and/or modify it 
  8  # under the terms of the GNU General Public License version 2 or (at your 
  9  # option) any later version as published by the Free Software Foundation. 
 10  # 
 11  # For complete information please visit: http://www.zenoss.com/oss/ 
 12  # 
 13  ########################################################################### 
 14   
 15  __doc__ = """RelationshipManager 
 16   
 17  RelationshipManager is a mix in class to manage relationships 
 18  defined by the SchemaManager.   
 19  """ 
 20   
 21  from xml.sax import saxutils 
 22   
 23  import logging 
 24  log = logging.getLogger("zen.Relations") 
 25   
 26  # Base classes for RelationshipManager 
 27  from PrimaryPathObjectManager import PrimaryPathObjectManager 
 28  from ZenPropertyManager import ZenPropertyManager 
 29   
 30  from Globals import DTMLFile 
 31  from Globals import InitializeClass 
 32  from AccessControl import ClassSecurityInfo 
 33  from Acquisition import aq_base 
 34  from App.Management import Tabs 
 35  import OFS.subscribers 
 36  import zope.interface 
 37  import zope.component 
 38   
 39  from OFS.interfaces import IItem 
 40   
 41  from RelSchema import * 
 42  from Exceptions import * 
 43   
 44  from Products.ZenUtils.Utils import unused 
 45  from Products.ZenModel.interfaces import IZenDocProvider 
 46   
 47  zenmarker = "__ZENMARKER__" 
 48   
49 -def manage_addRelationshipManager(context, id, title=None, REQUEST = None):
50 """Relationship factory""" 51 rm = RelationshipManager(id) 52 context._setObject(id, rm) 53 if REQUEST: 54 REQUEST['RESPONSE'].redirect(context.absolute_url()+'/manage_main')
55 56 57 addRelationshipManager = DTMLFile('dtml/addRelationshipManager',globals()) 58 59
60 -class RelationshipManager(PrimaryPathObjectManager, ZenPropertyManager):
61 """ 62 RelationshipManger is an ObjectManager like class that can contain 63 relationships (in fact relationships can only be added to a 64 RelationshipManager). 65 66 Relationships are defined on an RM by the hash _relations. It 67 should be defined on the class so that it isn't stored in the database. 68 If there is inheritance involved remember to add the base class _relations 69 definition to the current class so that all relationships for the class 70 are defined on it. 71 72 remoteClassStr - is a string that represents the full path to the remote 73 class. Its a string because in most cases the classes 74 will be in different modules which would cause a recursive 75 import of the two modules. 76 77 _relations = ( 78 ("toonename", ToOne(ToMany, remoteClassStr, remoteName)), 79 ("tomanyname", ToMany(ToMany, remoteClassStr, remoteName)), 80 ) 81 """ 82 zope.interface.implements(IItem) 83 84 _relations = () 85 86 meta_type = 'Relationship Manager' 87 88 security = ClassSecurityInfo() 89 90 manage_options = ( 91 PrimaryPathObjectManager.manage_options + 92 ZenPropertyManager.manage_options 93 ) 94 95 manage_main=DTMLFile('dtml/RelationshipManagerMain', globals()) 96 97 # are we being deleted or moved 98 _operation = -1 99
100 - def __init__(self, id, title=None, buildRelations=True):
101 unused(title) 102 self.id = id 103 if buildRelations: self.buildRelations()
104 105
106 - def getRelationshipManagerId(self):
107 """ 108 Return our simple id if we are called from our primary path 109 else return the full primary id. 110 """ 111 if self.getPhysicalPath() == self.getPrimaryPath(): return self.id 112 return self.getPrimaryId()
113 114 115 ########################################################################## 116 # 117 # Methods for relationship management. 118 # 119 ########################################################################## 120 121
122 - def addRelation(self, name, obj):
123 """Form a bi-directional relationship.""" 124 rel = getattr(self, name, None) 125 if rel == None: 126 raise AttributeError("Relationship %s, not found" % name) 127 rel.addRelation(obj)
128 129
130 - def removeRelation(self, name, obj = None, suppress_events=False):
131 """ 132 Remove an object from a relationship. 133 If no object is passed all objects are removed. 134 """ 135 rel = getattr(self, name, None) 136 if rel == None: 137 raise AttributeError("Relationship %s, not found" % name) 138 rel.removeRelation(obj, suppress_events=suppress_events)
139 140
141 - def _setObject(self,id,object,roles=None,user=None,set_owner=1):
142 if object.meta_type in RELMETATYPES: 143 schema = self.lookupSchema(id) 144 if not schema.checkType(object): 145 raise ZenSchemaError("Relaitonship %s type %s != %s" % 146 (id, object.meta_type, schema.__class__.__name__)) 147 return PrimaryPathObjectManager._setObject(self, id, object, roles, 148 user, set_owner)
149 150 151 ########################################################################## 152 # 153 # Methods for copy management 154 # 155 ########################################################################## 156
157 - def _getCopy(self, container):
158 """ 159 Create a copy of this relationship manager. This involes copying 160 relationships and removing invalid relations (ie ones with ToOne) 161 and performing copies of any contained objects. 162 Properties are also set on the new object. 163 """ 164 id = self.id 165 if getattr(aq_base(container), id, zenmarker) is not zenmarker: 166 id = "copy_of_" + id 167 cobj = self.__class__(id, buildRelations=False) #make new instance 168 cobj = cobj.__of__(container) #give the copy container's aq chain 169 for objid, sobj in self.objectItems(): 170 #if getattr(aq_base(self), objid, None): continue 171 csobj = sobj._getCopy(cobj) 172 cobj._setObject(csobj.id, csobj) 173 for name, value in self.propertyItems(): 174 cobj._updateProperty(name, value) 175 return aq_base(cobj)
176 177
178 - def _notifyOfCopyTo(self, container, op=0):
179 """Manage copy/move/rename state for use in manage_beforeDelete.""" 180 unused(container) 181 self._operation = op # 0 == copy, 1 == move, 2 == rename
182 183
184 - def cb_isMoveable(self):
185 """Prevent move unless we are being called from our primary path.""" 186 if (self.getPhysicalPath() == self.getPrimaryPath()): 187 return PrimaryPathObjectManager.cb_isMoveable(self) 188 return 0
189 190
191 - def moveMeBetweenRels(self, srcRelationship, destRelationship):
192 """ 193 Move a relationship manager without deleting its relationships. 194 """ 195 self._operation = 1 196 srcRelationship._delObject(self.id) 197 self = aq_base(self) 198 destRelationship._setObject(self.id, self) 199 return destRelationship._getOb(self.id)
200 201 202
203 - def moveObject(self, obj, destination):
204 """ 205 Move obj from this RM to the destination RM 206 """ 207 self._operation = 1 208 self._delObject(obj.id) 209 obj = aq_base(obj) 210 destination._setObject(obj.id, obj) 211 return destination._getOb(obj.id)
212 213 214 215 ########################################################################## 216 # 217 # Functions for examining a RelationshipManager's schema 218 # 219 ########################################################################## 220 221
222 - def buildRelations(self):
223 """build our relations based on the schema defined in _relations""" 224 if not getattr(self, "_relations", False): return 225 relnames = self.getRelationshipNames() 226 for name, schema in self._relations: 227 if name not in relnames: 228 self._setObject(name, schema.createRelation(name)) 229 if name in relnames: relnames.remove(name) 230 for rname in relnames: 231 self._delObject(rname)
232 233
234 - def lookupSchema(cls, relname):
235 """ 236 Lookup the schema definition for a relationship. 237 All base classes are checked until RelationshipManager is found. 238 """ 239 for name, schema in cls._relations: 240 if name == relname: return schema 241 raise ZenSchemaError("Schema for relation %s not found on %s" % 242 (relname, cls.__name__))
243 lookupSchema = classmethod(lookupSchema) 244 245
246 - def getRelationships(self):
247 """Returns a dictionary of relationship objects keyed by their names""" 248 return self.objectValues(spec=RELMETATYPES)
249 250
251 - def getRelationshipNames(self):
252 """Return our relationship names""" 253 return self.objectIds(spec=RELMETATYPES)
254 255
256 - def checkRelations(self, repair=False):
257 """Confirm the integrity of all relations on this object""" 258 log.info("checking relations on object %s", self.getPrimaryId()) 259 for rel in self.getRelationships(): 260 rel.checkRelation(repair)
261 262 263 ########################################################################## 264 # 265 # Functions for exporting RelationshipManager to XML 266 # 267 ########################################################################## 268
269 - def exportXml(self, ofile, ignorerels=[], root=False):
270 """Return an xml based representation of a RelationshipManager 271 <object id='/Devices/Servers/Windows/dhcp160.confmon.loc' 272 module='Products.Confmon.IpInterface' class='IpInterface'> 273 <property id='name'>jim</property> 274 <toone></toone> 275 <tomany></tomany> 276 <tomanycont></tomanycont> 277 </object> 278 """ 279 modname = self.__class__.__module__ 280 classname = self.__class__.__name__ 281 id = root and self.getPrimaryId() or self.id 282 stag = "<object id='%s' module='%s' class='%s'>\n" % ( 283 id , modname, classname) 284 ofile.write(stag) 285 zendocAdapter = zope.component.queryAdapter( self, IZenDocProvider ) 286 if zendocAdapter is not None: 287 zendocAdapter.exportZendoc( ofile ) 288 self.exportXmlProperties(ofile) 289 self.exportXmlRelationships(ofile, ignorerels) 290 exportHook = getattr(aq_base(self), 'exportXmlHook', None) 291 if exportHook and callable(exportHook): 292 self.exportXmlHook(ofile, ignorerels) 293 ofile.write("</object>\n")
294 295
296 - def exportXmlProperties(self,ofile):
297 """Return an xml representation of a RelationshipManagers properties 298 <property id='name' type='type' mode='w' select_variable='selectvar'> 299 value 300 </property> 301 value will be converted to is correct python type on import 302 """ 303 for prop in self._properties: 304 if not 'id' in prop: continue 305 id = prop['id'] 306 ptype = prop['type'] 307 value = getattr(aq_base(self), id, None) # use aq_base? 308 if not value: 309 if ptype in ("string","text","password"): 310 if not id.startswith('z'): 311 continue 312 elif ptype == "lines": 313 if value is None: 314 continue 315 elif ptype not in ("int","float","boolean","long"): 316 continue 317 if ptype == "password": 318 value = '' 319 stag = [] 320 stag.append('<property') 321 for k, v in prop.items(): 322 if ptype != 'selection' and k == 'select_variable': continue 323 v = saxutils.quoteattr(str(v)) 324 stag.append('%s=%s' % (k, v)) 325 stag.append('>') 326 ofile.write(' '.join(stag)+"\n") 327 if not isinstance(value, basestring): 328 value = unicode(value) 329 elif isinstance(value, str): 330 value = value.decode('latin-1') 331 valuestr = saxutils.escape(value).encode('utf-8').strip() 332 if valuestr: 333 ofile.write(valuestr+"\n") 334 ofile.write("</property>\n")
335 336
337 - def exportXmlRelationships(self, ofile, ignorerels=[]):
338 """Return an xml representation of Relationships""" 339 for rel in self.getRelationships(): 340 if rel.id in ignorerels: continue 341 rel.exportXml(ofile, ignorerels)
342 343 344 ########################################################################## 345 # 346 # Methods called from UI code. 347 # 348 ########################################################################## 349 350 security.declareProtected('Manage Relations', 'manage_addRelation')
351 - def manage_addRelation(self, name, obj, REQUEST=None):
352 """make a relationship""" 353 self.addRelation(name, obj) 354 if REQUEST: return self.callZenScreen(REQUEST)
355 356 357 security.declareProtected('Manage Relations', 'manage_removeRelation')
358 - def manage_removeRelation(self, name, id=None, REQUEST=None):
359 """remove a relationship to be called from UI""" 360 rel = getattr(self, name, None) 361 if rel == None: 362 raise AttributeError("Relationship %s, not found" % name) 363 rel._delObject(id) 364 if REQUEST: return self.callZenScreen(REQUEST)
365 366
367 - def manage_workspace(self, REQUEST):
368 """return the workspace of the related object using its primary path""" 369 url = REQUEST['URL'] 370 myp = self.getPrimaryUrlPath() 371 if url.find(myp) > 0: 372 Tabs.manage_workspace(self, REQUEST) 373 else: 374 from zExceptions import Redirect 375 raise Redirect( myp+'/manage_workspace' )
376 377 378 379 InitializeClass(RelationshipManager) 380