1
2
3
4
5
6
7
8
9
10
11
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 import types
27
28
29 from PrimaryPathObjectManager import PrimaryPathObjectManager
30 from ZenPropertyManager import ZenPropertyManager
31
32 from Globals import DTMLFile
33 from Globals import InitializeClass
34 from AccessControl import ClassSecurityInfo
35 from Acquisition import aq_base
36 from App.Management import Tabs
37 import OFS.subscribers
38 import zope.interface
39 import zope.component
40
41 from OFS.interfaces import IItem
42
43 from RelSchema import *
44 from Exceptions import *
45
46 from Products.ZenUtils.Utils import unused
47 from Products.ZenModel.interfaces import IZenDocProvider
48
49 zenmarker = "__ZENMARKER__"
50
57
58
59 addRelationshipManager = DTMLFile('dtml/addRelationshipManager',globals())
60
61
63 """
64 RelationshipManger is an ObjectManager like class that can contain
65 relationships (in fact relationships can only be added to a
66 RelationshipManager).
67
68 Relationships are defined on an RM by the hash _relations. It
69 should be defined on the class so that it isn't stored in the database.
70 If there is inheritance involved remember to add the base class _relations
71 definition to the current class so that all relationships for the class
72 are defined on it.
73
74 remoteClassStr - is a string that represents the full path to the remote
75 class. Its a string because in most cases the classes
76 will be in different modules which would cause a recursive
77 import of the two modules.
78
79 _relations = (
80 ("toonename", ToOne(ToMany, remoteClassStr, remoteName)),
81 ("tomanyname", ToMany(ToMany, remoteClassStr, remoteName)),
82 )
83 """
84 zope.interface.implements(IItem)
85
86 _relations = ()
87
88 meta_type = 'Relationship Manager'
89
90 security = ClassSecurityInfo()
91
92 manage_options = (
93 PrimaryPathObjectManager.manage_options +
94 ZenPropertyManager.manage_options
95 )
96
97 manage_main=DTMLFile('dtml/RelationshipManagerMain', globals())
98
99
100 _operation = -1
101
102 - def __init__(self, id, title=None, buildRelations=True):
106
107
109 """
110 Return our simple id if we are called from our primary path
111 else return the full primary id.
112 """
113 if self.getPhysicalPath() == self.getPrimaryPath(): return self.id
114 return self.getPrimaryId()
115
116
117
118
119
120
121
122
123
125 """Form a bi-directional relationship."""
126 rel = getattr(self, name, None)
127 if rel == None:
128 raise AttributeError("Relationship %s, not found" % name)
129 rel.addRelation(obj)
130
131
133 """
134 Remove an object from a relationship.
135 If no object is passed all objects are removed.
136 """
137 rel = getattr(self, name, None)
138 if rel == None:
139 raise AttributeError("Relationship %s, not found" % name)
140 rel.removeRelation(obj, suppress_events=suppress_events)
141
142
143 - def _setObject(self,id,object,roles=None,user=None,set_owner=1):
151
152
153
154
155
156
157
158
160 """
161 Create a copy of this relationship manager. This involes copying
162 relationships and removing invalid relations (ie ones with ToOne)
163 and performing copies of any contained objects.
164 Properties are also set on the new object.
165 """
166 id = self.id
167 if getattr(aq_base(container), id, zenmarker) is not zenmarker:
168 id = "copy_of_" + id
169 cobj = self.__class__(id, buildRelations=False)
170 cobj = cobj.__of__(container)
171 for objid, sobj in self.objectItems():
172
173 csobj = sobj._getCopy(cobj)
174 cobj._setObject(csobj.id, csobj)
175 for name, value in self.propertyItems():
176 cobj._updateProperty(name, value)
177 return aq_base(cobj)
178
179
181 """Manage copy/move/rename state for use in manage_beforeDelete."""
182 unused(container)
183 self._operation = op
184
185
191
192
194 """
195 Move a relationship manager without deleting its relationships.
196 """
197 self._operation = 1
198 srcRelationship._delObject(self.id)
199 self = aq_base(self)
200 destRelationship._setObject(self.id, self)
201 return destRelationship._getOb(self.id)
202
203
204
206 """
207 Move obj from this RM to the destination RM
208 """
209 self._operation = 1
210 self._delObject(obj.id)
211 obj = aq_base(obj)
212 destination._setObject(obj.id, obj)
213 return destination._getOb(obj.id)
214
215
216
217
218
219
220
221
222
223
234
235
237 """
238 Lookup the schema definition for a relationship.
239 All base classes are checked until RelationshipManager is found.
240 """
241 for name, schema in cls._relations:
242 if name == relname: return schema
243 raise ZenSchemaError("Schema for relation %s not found on %s" %
244 (relname, cls.__name__))
245 lookupSchema = classmethod(lookupSchema)
246
247
249 """Returns a dictionary of relationship objects keyed by their names"""
250 return self.objectValues(spec=RELMETATYPES)
251
252
256
257
263
264
265
266
267
268
269
270
271 - def exportXml(self, ofile, ignorerels=[], root=False):
272 """Return an xml based representation of a RelationshipManager
273 <object id='/Devices/Servers/Windows/dhcp160.confmon.loc'
274 module='Products.Confmon.IpInterface' class='IpInterface'>
275 <property id='name'>jim</property>
276 <toone></toone>
277 <tomany></tomany>
278 <tomanycont></tomanycont>
279 </object>
280 """
281 modname = self.__class__.__module__
282 classname = self.__class__.__name__
283 id = root and self.getPrimaryId() or self.id
284 stag = "<object id='%s' module='%s' class='%s'>\n" % (
285 id , modname, classname)
286 ofile.write(stag)
287 zendocAdapter = zope.component.queryAdapter( self, IZenDocProvider )
288 if zendocAdapter is not None:
289 zendocAdapter.exportZendoc( ofile )
290 self.exportXmlProperties(ofile)
291 self.exportXmlRelationships(ofile, ignorerels)
292 exportHook = getattr(aq_base(self), 'exportXmlHook', None)
293 if exportHook and callable(exportHook):
294 self.exportXmlHook(ofile, ignorerels)
295 ofile.write("</object>\n")
296
297
299 """Return an xml representation of a RelationshipManagers properties
300 <property id='name' type='type' mode='w' select_variable='selectvar'>
301 value
302 </property>
303 value will be converted to is correct python type on import
304 """
305 for prop in self._properties:
306 if not prop.has_key('id'): continue
307 id = prop['id']
308 ptype = prop['type']
309 value = getattr(aq_base(self), id, None)
310 if not value and ptype not in ("int","float","boolean"): continue
311 stag = []
312 stag.append('<property')
313 for k, v in prop.items():
314 if ptype != 'selection' and k == 'select_variable': continue
315 v = saxutils.quoteattr(str(v))
316 stag.append('%s=%s' % (k, v))
317 stag.append('>')
318 ofile.write(' '.join(stag)+"\n")
319 if type(value) not in types.StringTypes:
320 value = unicode(value)
321 elif type(value) == types.StringType:
322 value = value.decode('latin-1')
323 ofile.write(saxutils.escape(value).encode('utf-8')+"\n")
324 ofile.write("</property>\n")
325
326
328 """Return an xml representation of Relationships"""
329 for rel in self.getRelationships():
330 if rel.id in ignorerels: continue
331 rel.exportXml(ofile, ignorerels)
332
333
334
335
336
337
338
339
340 security.declareProtected('Manage Relations', 'manage_addRelation')
345
346
347 security.declareProtected('Manage Relations', 'manage_removeRelation')
349 """remove a relationship to be called from UI"""
350 rel = getattr(self, name, None)
351 if rel == None:
352 raise AttributeError("Relationship %s, not found" % name)
353 rel._delObject(id)
354 if REQUEST: return self.callZenScreen(REQUEST)
355
356
358 """return the workspace of the related object using its primary path"""
359 url = REQUEST['URL']
360 myp = self.getPrimaryUrlPath()
361 if url.find(myp) > 0:
362 Tabs.manage_workspace(self, REQUEST)
363 else:
364 from zExceptions import Redirect
365 raise Redirect( myp+'/manage_workspace' )
366
367
368
369 InitializeClass(RelationshipManager)
370