f0efb8394b00e71ae667f93f0f3a6e840959ea16
[dlux.git] / modules / common-yangutils-resources / src / main / resources / yangutils / services / yin-parser.services.js
1 define([], function () {
2     'use strict';
3
4     function YinParserService($http, SyncService, constants, PathUtilsService, YangUiApisService, NodeUtilsService){
5         var augmentType = 'augment';
6         var path = './assets';
7
8         var Module = function (name, revision, namespace) {
9             this._name = name;
10             this._revision = revision;
11             this._namespace = namespace;
12             this._statements = {};
13             this._roots = [];
14             this._augments = [];
15
16             this.getRoots = function () {
17                 return this._roots;
18             };
19
20             this.getImportByPrefix = function (prefix) {
21                 var importNode = null;
22
23                 if (this._statements.hasOwnProperty('import')) {
24                     importNode = this._statements.import.filter(function (importItem) {
25                         return importItem._prefix === prefix;
26                     })[0];
27                 }
28
29                 return importNode;
30             };
31
32             this.getRawAugments = function () {
33                 return this._augments;
34             };
35
36             this.getAugments = function () {
37                 var self = this;
38
39                 return this.getRawAugments().map(function (augNode) {
40                     var prefixConverter = function (prefix) {
41                             var importNode = self.getImportByPrefix(prefix);
42                             return importNode ? importNode.label : null;
43                         },
44                         getDefaultModule = function() {
45                             return null;
46                         };
47
48                     augNode.path = PathUtilsService.translate(augNode.pathString, prefixConverter, self._statements.import, getDefaultModule);
49
50                     return new Augmentation(augNode);
51                 });
52             };
53
54             this.addChild = function (node) {
55                 if (!this._statements.hasOwnProperty(node.type)) {
56                     this._statements[node.type] = [];
57                 }
58
59                 var duplicates = this._statements[node.type].filter(function (item) {
60                     return node.label === item.label && node.nodeType === item.nodeType;
61                 });
62
63                 if (duplicates && duplicates.length > 0) {
64                     console.warn('trying to add duplicate node', node, 'to module', this._statements);
65                 } else {
66                     this._statements[node.type].push(node);
67
68                     if (NodeUtilsService.isRootNode(node.type)) {
69                         this._roots.push(node);
70                     }
71
72                     if (node.type === 'augment') {
73                         this._augments.push(node);
74                     }
75                 }
76             };
77
78             this.searchNode = function (type, name) {
79                 var searchResults = null,
80                     searchedNode = null;
81
82                 if (this._statements[type]) {
83                     searchResults = this._statements[type].filter(function (node) {
84                         return name === node.label;
85                     });
86                 }
87
88                 if (searchResults && searchResults.length === 0) {
89                     //console.warn('no nodes with type', type, 'and name', name, 'found in', this);
90                 } else if (searchResults && searchResults.length > 1) {
91                     //console.warn('multiple nodes with type', type, 'and name', name, 'found in', this);
92                 } else if (searchResults && searchResults.length === 1) {
93                     searchedNode = searchResults[0];
94                 }
95
96                 return searchedNode;
97             };
98         };
99
100         var Node = function (id, name, type, module, namespace, parent, nodeType, moduleRevision) {
101             this.id = id;
102             this.label = name;
103             this.localeLabel = constants.LOCALE_PREFIX + name.toUpperCase();
104             this.type = type;
105             this.module = module;
106             this.children = [];
107             this.parent = parent;
108             this.nodeType = nodeType;
109             this.namespace = namespace;
110             this.moduleRevision = moduleRevision;
111
112             this.appendTo = function (parentNode) {
113                 parentNode.addChild(this);
114             };
115
116             this.addChild = function (node) {
117                 if (this.children.indexOf(node) === -1) {
118                     this.children.push(node);
119                     node.parent = this;
120                 }
121
122             };
123
124             this.deepCopy = function deepCopy(additionalProperties) {
125                 var copy = new Node(this.id, this.label, this.type, this.module, this.namespace, null, this.nodeType, this.moduleRevision),
126                     self = this;
127
128                 additionalProperties = (additionalProperties || []).concat(['pathString']);
129
130                 additionalProperties.forEach(function(prop) {
131                     if (prop !== 'children' && self.hasOwnProperty(prop) && copy.hasOwnProperty(prop) === false) {
132                         copy[prop] = self[prop];
133                     }
134                 });
135
136                 this.children.forEach(function (child) {
137                     var childCopy = child.deepCopy(additionalProperties);
138                     childCopy.parent = copy;
139                     copy.children.push(childCopy);
140                 });
141                 return copy;
142             };
143
144             this.getCleanCopy = function(){
145                 return new Node(this.id, this.label, this.type, this.module, this.namespace, null, this.nodeType, this.moduleRevision);
146             };
147
148             this.getChildren = function (type, name, nodeType, property) {
149                 var filteredChildren = this.children.filter(function (item) {
150                     return (name != null ? name === item.label : true) && (type != null ? type === item.type : true) && (nodeType != null ? nodeType === item.nodeType : true);
151                 });
152
153                 if (property) {
154                     return filteredChildren.filter(function (item) {
155                         return item.hasOwnProperty(property);
156                     }).map(function (item) {
157                         return item[property];
158                     });
159                 } else {
160                     return filteredChildren;
161                 }
162             };
163
164         };
165
166
167
168         var AugmentationsGroup = function(){
169             this.obj = {};
170
171             this.addAugumentation = function(augumentation){
172                 this.obj[augumentation.id] = augumentation;
173             };
174         };
175
176         var Augmentations = function(){
177             this.groups = {};
178
179             this.addGroup  = function(groupId){
180                 this.groups[groupId] = !this.groups.hasOwnProperty(groupId) ? new AugmentationsGroup() : this.groups[groupId];
181             };
182
183             this.getAugmentation = function(node, augId) {
184                 return this.groups[node.module + ':' + node.label] ? this.groups[node.module + ':' + node.label].obj[augId] : null;
185             };
186         };
187
188         var Augmentation = function (node) {
189             var self = this;
190             this.node = node;
191             this.path = (node.path ? node.path : []);
192             this.id = node.module + ':' + node.label;
193             this.expanded = true;
194             // AUGMENT FIX
195             //node.label = node.module + ':' + node.label;
196
197
198             this.toggleExpand = function () {
199                 this.expanded = !this.expanded;
200             };
201
202             this.setAugmentationGroup = function(targetNode, augumentations){
203                 var targetNodeId = targetNode.module + ':' + targetNode.label;
204                 targetNode.augmentionGroups = targetNode.augmentionGroups ? targetNode.augmentionGroups : [];
205                 targetNode.augmentionGroups.push(self.id);
206
207                 augumentations.addGroup(targetNodeId);
208                 augumentations.groups[targetNodeId].addAugumentation(self);
209             };
210
211             this.apply = function (nodeList, augumentations) {
212                 var targetNode = this.getTargetNodeToAugment(nodeList);
213
214                 if (targetNode) {
215                     this.setAugmentationGroup(targetNode, augumentations);
216
217                     this.node.children.forEach(function (child) {
218                         child.appendTo(targetNode);
219                         child.augmentationId = self.id;
220                         // AUGMENT FIX
221                         // child.children.forEach(function (moduleChild) {
222                         //     moduleChild.label = moduleChild.module + ':' + moduleChild.label;
223                         // });
224                     });
225                 } else {
226                     console.warn('can\'t find target node for augmentation ', this.getPathString());
227                 }
228             };
229
230             this.getTargetNodeToAugment = function (nodeList) {
231                 return PathUtilsService.search({children: nodeList}, this.path.slice());
232             };
233
234             this.getPathString = function () {
235                 return this.path.map(function (elem) {
236                     return elem.module + ':' + elem.name;
237                 }).join('/');
238             };
239
240         };
241
242         var parentTag = function (xml) {
243             if (xml.get(0).tagName.toLowerCase() === 'module') {
244                 return xml.get(0);
245             } else {
246                 return parentTag(xml.parent());
247             }
248         };
249
250         var parseModule = function(data, callback) {
251             var yangParser = new YangParser();
252
253             var moduleName = $($.parseXML(data).documentElement).attr('name'),
254                 moduleNamespace = $($.parseXML(data)).find('namespace').attr('uri'),
255                 moduleoduleRevision = $($.parseXML(data)).find('revision').attr('date'),
256                 moduleObj = new Module(moduleName, moduleoduleRevision, moduleNamespace);
257
258             yangParser.setCurrentModuleObj(moduleObj);
259             yangParser.parse($.parseXML(data).documentElement, moduleObj);
260
261             yangParser.sync.waitFor(function () {
262                 callback(moduleObj);
263             });
264         };
265
266         var loadStaticModule = function(name, callback, errorCbk) {
267             var yinPath = '/yang2xml/' + name + '.yang.xml';
268             $http.get(path + yinPath).success(function(data) {
269                 console.warn('cannot load '+ name + 'from controller, trying loading from static storage');
270                 parseModule(data, callback);
271             }).error(function() {
272                 console.warn('cannot load file '+ yinPath + 'from static storage');
273                 errorCbk();
274                 return null;
275             });
276         };
277
278         var parseYangMP = function parseYangMP(baseApiPath, name, rev, callback, errorCbk) {
279             var path = baseApiPath + '/' + name + '/' + rev + '/schema';
280
281             YangUiApisService.getSingleModuleInfo(path).then(
282                 function (data) {
283                     if($.parseXML(data) !== null) {
284                         parseModule(data, callback);
285                     } else {
286                         loadStaticModule(name, callback, errorCbk);
287                     }
288                 }, function () {
289                     loadStaticModule(name, callback, errorCbk);
290                 }
291             );
292         };
293
294         var parseYang = function parseYang(name, rev, callback, errorCbk) {
295             YangUiApisService.getModuleSchema(name, rev).get().then(
296                 function (data) {
297                     if($.parseXML(data) !== null) {
298                         parseModule(data, callback);
299                     } else {
300                         loadStaticModule(name, callback, errorCbk);
301                     }
302                 }, function () {
303                     loadStaticModule(name, callback, errorCbk);
304                 }
305             );
306         };
307
308         var YangParser = function () {
309             this.rootNodes = [];
310             this.nodeIndex = 0;
311             this.sync = SyncService.generateObj();
312             this.moduleObj = null;
313
314             this.setCurrentModuleObj = function (moduleObj) {
315                 this.moduleObj = moduleObj;
316             };
317
318             this.createNewNode = function (name, type, parentNode, nodeType) {
319                 var node = new Node(this.nodeIndex++, name, type, this.moduleObj._name, this.moduleObj._namespace, parentNode, nodeType, this.moduleObj._revision);
320
321                 if (parentNode) {
322                     parentNode.addChild(node);
323                 }
324
325                 return node;
326             };
327
328             this.parse = function (xml, parent) {
329                 var self = this;
330
331                 $(xml).children().each(function (_, item) {
332                     var prop = item.tagName.toLowerCase();
333                     if (self.hasOwnProperty(prop)) {
334                         self[prop](item, parent);
335                     } else {
336                         // self.parse(this, parent);
337                     }
338                 });
339             };
340
341             this.config = function(xml, parent) {
342                 var type = 'config',
343                     name = $(xml).attr('value'),
344                     nodeType = constants.NODE_ALTER,
345                     node = this.createNewNode(name, type, parent, nodeType);
346             };
347
348             this.presence = function(xml, parent) {
349                 var type = 'presence',
350                     name = $(xml).attr('value'),
351                     nodeType = constants.NODE_ALTER,
352                     node = this.createNewNode(name, type, parent, nodeType);
353             };
354
355             this.leaf = function (xml, parent) {
356                 var type = 'leaf',
357                     name = $(xml).attr('name'),
358                     nodeType = constants.NODE_UI_DISPLAY,
359                     node = this.createNewNode(name, type, parent, nodeType);
360
361                 this.parse(xml, node);
362             };
363
364             this['leaf-list'] = function (xml, parent) {
365                 var type = 'leaf-list',
366                     name = $(xml).attr('name'),
367                     nodeType = constants.NODE_UI_DISPLAY,
368                     node = this.createNewNode(name, type, parent, nodeType);
369
370                 this.parse(xml, node);
371             };
372
373             this.container = function (xml, parent) {
374                 var type = 'container',
375                     name = $(xml).attr('name'),
376                     nodeType = constants.NODE_UI_DISPLAY,
377                     node = this.createNewNode(name, type, parent, nodeType);
378
379                 this.parse(xml, node);
380             };
381
382             this.choice = function (xml, parent) {
383                 var type = 'choice',
384                     name = $(xml).attr('name'),
385                     nodeType = constants.NODE_UI_DISPLAY,
386                     node = this.createNewNode(name, type, parent, nodeType);
387
388                 this.parse(xml, node);
389             };
390
391             this.case = function (xml, parent) {
392                 var type = 'case',
393                     name = $(xml).attr('name'),
394                     nodeType = constants.NODE_UI_DISPLAY,
395                     node = this.createNewNode(name, type, parent, nodeType);
396
397                 this.parse(xml, node);
398             };
399
400             this.list = function (xml, parent) {
401                 var type = 'list',
402                     name = $(xml).attr('name'),
403                     nodeType = constants.NODE_UI_DISPLAY,
404                     node = this.createNewNode(name, type, parent, nodeType);
405
406                 this.parse(xml, node);
407             };
408
409
410             this.key = function (xml, parent) {
411                 var type = 'key',
412                     name = $(xml).attr('value'),
413                     nodeType = constants.NODE_ALTER,
414                     node = this.createNewNode(name, type, parent, nodeType);
415
416                 this.parse(xml, node);
417             };
418
419             this.description = function (xml, parent) {
420                 var type = 'description',
421                     name = $(xml).attr('text') ? $(xml).attr('text') : $(xml).children('text:first').text(),
422                     nodeType = constants.NODE_ALTER,
423                     node = this.createNewNode(name, type, parent, nodeType);
424
425                 this.parse(xml, node);
426             };
427
428             this.typedef = function (xml, parent, typedefName) {
429                 var type = 'typedef',
430                     name = $(xml).attr('name'),
431                     nodeType = constants.NODE_LINK_TARGET,
432                     node = this.createNewNode(name, type, parent, nodeType);
433
434                 this.parse(xml, node);
435             };
436
437             this.grouping = function (xml, parent, groupingName) {
438                 var type = 'grouping',
439                     name = $(xml).attr('name'),
440                     nodeType = constants.NODE_LINK_TARGET,
441                     node = this.createNewNode(name, type, parent, nodeType);
442
443                 this.parse(xml, node);
444             };
445
446             this.uses = function (xml, parent) {
447                 var type = 'uses',
448                     name = $(xml).attr('name'),
449                     nodeType = constants.NODE_LINK,
450                     node = this.createNewNode(name, type, parent, nodeType);
451
452                 this.parse(xml, node);
453             };
454
455             this.import = function (xml, parent) {
456                 var type = 'import',
457                     name = $(xml).attr('module'),
458                     nodeType = constants.NODE_ALTER,
459                     node = this.createNewNode(name, type, parent, nodeType);
460
461                 node._prefix = $(xml).children('prefix:first').attr('value');
462                 node._revisionDate = $(xml).children('revision-date:first').attr('date');
463             };
464
465             this.augment = function (xml, parent) {
466                 var type = augmentType,
467                     nodeType = constants.NODE_ALTER,
468                     augmentIndentifier = $(xml).children("ext\\:augment-identifier:first").attr("ext:identifier"),
469                     name = augmentIndentifier ? augmentIndentifier : 'augment' + (this.nodeIndex + 1).toString(),
470                     pathString = $(xml).attr('target-node'),
471                     augmentRoot = this.createNewNode(name, type, parent, nodeType);
472
473                 augmentRoot.pathString = pathString;
474                 this.parse(xml, augmentRoot);
475             };
476
477
478             this.rpc = function (xml, parent) {
479                 var type = 'rpc',
480                     name = $(xml).attr('name'),
481                     nodeType = constants.NODE_UI_DISPLAY,
482                     node = this.createNewNode(name, type, parent, nodeType);
483
484                 this.parse(xml, node);
485             };
486
487             this.input = function (xml, parent) {
488                 var type = 'input',
489                     name = 'input',
490                     nodeType = constants.NODE_UI_DISPLAY,
491                     node = this.createNewNode(name, type, parent, nodeType);
492
493                 this.parse(xml, node);
494             };
495
496             this.output = function (xml, parent) {
497                 var type = 'output',
498                     name = 'output',
499                     nodeType = constants.NODE_UI_DISPLAY,
500                     node = this.createNewNode(name, type, parent, nodeType);
501
502                 this.parse(xml, node);
503             };
504
505             this.pattern = function (xml, parent) {
506                 var type = 'pattern',
507                     name = $(xml).attr('value'),
508                     nodeType = constants.NODE_RESTRICTIONS;
509
510                 this.createNewNode(name, type, parent, nodeType);
511             };
512
513             this.range = function (xml, parent) {
514                 var type = 'range',
515                     name = $(xml).attr('value'),
516                     nodeType = constants.NODE_RESTRICTIONS;
517
518                 this.createNewNode(name, type, parent, nodeType);
519             };
520
521             this.length = function (xml, parent) {
522                 var type = 'length',
523                     name = $(xml).attr('value'),
524                     nodeType = constants.NODE_RESTRICTIONS;
525
526                 this.createNewNode(name, type, parent, nodeType);
527             };
528
529             this.enum = function (xml, parent) {
530                 var type = 'enum',
531                     name = $(xml).attr('name'),
532                     nodeType = constants.NODE_ALTER;
533
534                 this.createNewNode(name, type, parent, nodeType);
535             };
536
537             this.bit = function (xml, parent) {
538                 var type = 'bit',
539                     name = $(xml).attr('name'),
540                     nodeType = constants.NODE_ALTER,
541                     node = this.createNewNode(name, type, parent, nodeType);
542
543                 this.parse(xml, node);
544             };
545
546             this.position = function (xml, parent) {
547                 var type = 'position',
548                     name = $(xml).attr('value'),
549                     nodeType = constants.NODE_ALTER;
550
551                 this.createNewNode(name, type, parent, nodeType);
552             };
553
554             this.type = function (xml, parent) {
555                 var type = 'type',
556                     name = $(xml).attr('name'),
557                     nodeType = constants.NODE_ALTER,
558                     node = this.createNewNode(name, type, parent, nodeType);
559
560                 this.parse(xml, node);
561             };
562         };
563
564         return {
565             parseYang: parseYang,
566             parseYangMP: parseYangMP,
567             yangParser: new YangParser(),
568             Augmentations: Augmentations,
569             Module: Module,
570             __test: {
571                 path: path,
572                 parentTag: parentTag,
573                 yangParser: new YangParser(),
574                 Augmentation: Augmentation,
575                 Module: Module
576             }
577         };
578     }
579
580     YinParserService.$inject=['$http','SyncService', 'constants', 'PathUtilsService', 'YangUiApisService', 'NodeUtilsService'];
581
582     return YinParserService;
583
584 });