-
Notifications
You must be signed in to change notification settings - Fork 39
/
ifmap_model.py
456 lines (364 loc) · 13.7 KB
/
ifmap_model.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
#
# Copyright (c) 2013 Juniper Networks, Inc. All rights reserved.
#
import logging
import re
import textwrap
from ifmap_global import getCppType, getJavaType, getGoLangType
from ifmap_global import IsGeneratedType, CamelCase
from type_model import ComplexType, ComplexTypeLocate, MemberInfo
class AmbiguousParentType(Exception): pass
def ElementXsdType(xelement):
if xelement.schema_type:
typename = xelement.schema_type
else:
typename = xelement.getType()
if typename == xelement.getName():
return None
return typename
class IFMapObject(object):
def __init__(self, name):
self._name = name
self._xelement = None
def getName(self):
""" The data structure name (e.g. virtual-network) """
return self._name
def getJsonName(self):
name = self._name
name = name.replace('-', '_')
return name
def getCIdentifierName(self):
""" A valid C identifier name (e.g. virtual_network). """
if not self._xelement:
special_chars = [':', '-', '.']
name = self._name
for ch in special_chars:
name = name.replace(ch, '_')
return name
return self._xelement.getCleanName()
def SetSchemaElement(self, xelement):
self._xelement = xelement
def getXsdType(self):
return ElementXsdType(self._xelement)
def getElement(self):
return self._xelement
class IFMapIdentifier(IFMapObject):
""" An identifier and the list of associated properties.
"""
def __init__(self, name):
super(IFMapIdentifier, self).__init__(name)
self._cppname = CamelCase(name)
self._properties = [] # list of IFMapProperty elements
self._key_members = []
self._data_members = []
self._data_types = []
self._links = []
self._back_links = []
self._parents = None
self._children = []
self._references = []
self._back_references = []
def getCppName(self):
return self._cppname
def SetProperty(self, meta):
if meta not in self._properties:
self._properties.append(meta)
def getProperties(self):
return self._properties
def setParent(self, parent_ident, meta, is_derived):
parent_info = {'ident': parent_ident, 'meta': meta,
'derived': is_derived}
if not self._parents:
self._parents = [parent_info]
else:
self._parents.append(parent_info)
def getParents(self):
if not self._parents:
return None
return [(parent_info['ident'], parent_info['meta'],
parent_info['derived']) for parent_info in self._parents]
def getParentName(self, parent_info):
return parent_info['ident'].getName()
def getParentMetaName(self, parent_info):
return parent_info['meta'].getName()
def getChildren(self):
return self._children
def getReferences(self):
return self._references
def getBackReferences(self):
return self._back_references
def getDefaultFQName(self, parent_type = None):
if not self._parents:
if self._name == 'config-root':
return []
else:
return ['default-%s' %(self._name)]
if not parent_type and len(self._parents) > 1:
parent_names = [p['ident'].getName() for p in self._parents]
raise AmbiguousParentType('Ambiguous parents %s' %(parent_names))
if parent_type:
parent_ident = None
for parent in self._parents:
if parent['ident'].getName() == parent_type:
parent_ident = parent['ident']
break
else:
parent_ident = self._parents[0]['ident']
fq_name = parent_ident.getDefaultFQName()
fq_name.append('default-%s' %(self._name))
return fq_name
def isDerived(self, parent_ident):
return [pi['derived'] for pi in self._parents
if pi['ident'] == parent_ident][0]
def addLinkInfo(self, meta, to_ident, attrs):
link_info = (meta, to_ident, attrs)
self._links.append(link_info)
if (self.isLinkHas(link_info)):
self._children.append(to_ident)
to_ident.setParent(self, meta,
self.isLinkDerived(link_info))
elif self.isLinkRef(link_info):
self._references.append(to_ident)
def getLinksInfo(self):
return self._links
def getLink(self, link_info):
return link_info[0]
def getLinkTo(self, link_info):
return link_info[1]
def isLinkHas(self, link_info):
attrs = link_info[2]
return 'has' in attrs
def isLinkRef(self, link_info):
attrs = link_info[2]
return 'ref' in attrs
def isLinkDerived(self, link_info):
"""
Returns if the 'to' identifier is directly managed by user
or if it is result of schema transformation
"""
attrs = link_info[2]
return 'derived' in attrs
def addBackLinkInfo(self, meta, from_ident, attrs):
link_info = (meta, self, attrs)
back_link_info = (meta, from_ident, attrs)
if self.isLinkRef(link_info):
self._back_references.append(from_ident)
self._back_links.append(back_link_info)
def getBackLinksInfo(self):
return self._back_links
def getBackLink(self, back_link_info):
return back_link_info[0]
def getBackLinkFrom(self, back_link_info):
return back_link_info[1]
def getKeyMembers(self):
return self._key_members
def getDataMembers(self):
return self._data_members
def getDataTypes(self):
return self._data_types
def _BuildKeySpec(self, TypeDict, decl, typename):
""" The IFMapIdentifier primary key """
if not typename:
return decl
if typename == 'IdentityType':
decl.append(('std::string', 'name_'))
return decl
return decl
def _BuildDataMembers(self, xsdTypeDict, cTypeDict):
for mprop in self._properties:
mprop.Resolve(xsdTypeDict, cTypeDict)
if mprop._xelement.isComplex():
self._BuildProperty(xsdTypeDict, mprop)
else:
self._BuildSimpleProperty(mprop)
def _BuildProperty(self, TypeDict, meta):
name = meta.getPropertyName() + '_'
member = MemberInfo()
member.membername = name
member.xsd_object = meta._xelement
member.isComplex = True
child_data = meta.getDataMembers()
if len(child_data) == 1:
cpptype = child_data[0].ctypename
member.xsd_object = child_data[0].xsd_object
m = re.match('std::vector<(\S+)>', cpptype)
if m:
member.isSequence = True
meta._isSequence = True
dtype = m.group(1)
member.sequenceType = dtype
if IsGeneratedType(dtype):
self._data_types.append(dtype)
else:
self._data_types.append(cpptype)
else:
cpptype = meta.getCType().getName()
self._data_types.append(cpptype)
member.ctypename = cpptype
meta._memberinfo = member
self._data_members.append(member)
def _BuildSimpleProperty(self, prop):
member = MemberInfo()
member.membername = prop.getPropertyName() + '_'
member.xsd_object = prop._xelement
member.isComplex = False
member.default = prop.getDefault()
member.ctypename = getCppType(prop._xelement.getType())
prop._memberinfo = member
self._data_members.append(member)
def Resolve(self, xsdTypeDict, cTypeDict):
if not self._xelement:
logger = logging.getLogger('ifmap_model')
logger.warning('%s not found in xml schema', self.getName())
return
self._key_members = self._BuildKeySpec(xsdTypeDict, [],
self.getXsdType())
self._BuildDataMembers(xsdTypeDict, cTypeDict)
class IFMapMetadata(IFMapObject):
""" Base class for all metadata elements (properties, links)
"""
def __init__(self, name, idl_info):
super(IFMapMetadata, self).__init__(name)
self._idl_info = idl_info
def getPresence(self):
return self._idl_info[0].presence
def getOperations(self):
return self._idl_info[0].operations
def getDescription(self, width=None):
desc = self._idl_info[0].description
if width is None and isinstance(desc, basestring):
return self._idl_info[0].description
if isinstance(desc, basestring):
return textwrap.wrap(desc, width, break_long_words=False)
elif isinstance(desc, list):
desc_lines = []
for d_line in desc:
desc_lines.extend(textwrap.wrap(
d_line, width, break_long_words=False))
return desc_lines
else:
return desc
def Resolve(self, xsdTypeDict, cTypeDict):
pass
@staticmethod
def Create(name, is_property, annotation, typename):
if not is_property:
if typename:
meta = IFMapLinkAttr(name, annotation)
else:
meta = IFMapLink(name, annotation)
else:
meta = IFMapProperty(name, annotation)
return meta
class IFMapProperty(IFMapMetadata):
""" Property associated with a single identifier
"""
def __init__(self, name, idl_info):
super(IFMapProperty, self).__init__(name, idl_info)
self._parent = None
self._cppname = CamelCase(name)
self._complexType = None
self._memberinfo = None
def getParent(self):
return self._parent
def setParent(self, identifier):
self._parent = identifier
def getCppName(self):
return self._cppname
def getCType(self):
return self._complexType
def getCTypename(self):
if self._xelement.isComplex():
return self._complexType.getName()
return getCppType(self._xelement.getType())
def getJavaTypename(self):
if self._xelement.isComplex():
return self._complexType.getName()
return getJavaType(self._xelement.getType())
def getDefault(self):
if not self._xelement.isComplex():
return self._xelement.getDefault()
return None
def getGoLangTypename(self):
if self._xelement.isComplex():
return self._complexType.getName()
return getGoLangType(self._xelement.getType())
def getMemberInfo(self):
return self._memberinfo
def getDependentTypes(self):
return self._complexType._data_types
def getDataMembers(self):
return self._complexType._data_members
def getPropertyName(self):
name = self.getCIdentifierName()
if self._parent == 'all':
return name
prefix = self._parent.getCIdentifierName() + '_'
if name.startswith(prefix):
name = name[len(prefix):]
return name
def getPropertyId(self):
prop = self.getPropertyName()
return prop.upper()
def isList(self):
idl_prop = self._idl_info[0]
return idl_prop.IsList() or self._xelement.maxOccurs > 1
def isListUsingWrapper(self):
idl_prop = self._idl_info[0]
return idl_prop.IsList()
def isMap(self):
idl_prop = self._idl_info[0]
return idl_prop.IsMap() or self._xelement.maxOccurs > 1
def isMapUsingWrapper(self):
idl_prop = self._idl_info[0]
return idl_prop.IsMap()
def getMapKeyName(self):
idl_prop = self._idl_info[0]
return idl_prop.map_key_name
def Resolve(self, xsdTypeDict, cTypeDict):
xtypename = self.getXsdType()
self._complexType = ComplexTypeLocate(xsdTypeDict, cTypeDict, xtypename)
# Ensure a prop-list using wrapper for list
# has only one element in wrapper
if (self.isListUsingWrapper() and
(len(xsdTypeDict[xtypename].children) != 1)):
err_msg = 'ListProperty %s using incorrect wrapper-type %s' %(
self._name, xtypename)
raise Exception(err_msg)
class IFMapLink(IFMapMetadata):
""" Link metadata with no attributes
"""
def __init__(self, name, idl_info):
super(IFMapLink, self).__init__(name, idl_info)
def getCType(self):
return None
class IFMapLinkAttr(IFMapMetadata):
""" Link metadata with attributes
"""
def __init__(self, name, idl_info):
super(IFMapLinkAttr, self).__init__(name, idl_info)
self._cppname = CamelCase(name)
self._complexType = None
def getCppName(self):
return self._cppname
def getCType(self):
return self._complexType
def getCTypename(self):
if self._xelement.isComplex():
return self._complexType.getName()
return getCppType(self._xelement.getType())
def Resolve(self, xsdTypeDict, cTypeDict):
if self._xelement.isComplex():
self._complexType = ComplexTypeLocate(xsdTypeDict, cTypeDict,
self.getXsdType())
if not self._complexType:
logger = logging.getLogger('ifmap_model')
logger.warning('%s: type \'%s\' not found in xml schema',
self.getName(), xtypename)
def SimpleTypeWrapper(info):
assert type(info) is MemberInfo
wtype = info.ctypename
sep = wtype.rfind("::")
if sep:
wtype = wtype[sep + 2:]
return wtype.capitalize() + 'Property'