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

Source Code for Module Products.ZenRelations.RelationshipManager

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