28095b5ef75331bd5c128f82692da619b396272b
[controller.git] / opendaylight / sal / yang-prototype / code-generator / yang-model-parser-impl / src / main / java / org / opendaylight / controller / yang / parser / impl / YangParserListenerImpl.java
1 /*
2  * Copyright (c) 2013 Cisco Systems, Inc. and others.  All rights reserved.
3  *
4  * This program and the accompanying materials are made available under the
5  * terms of the Eclipse Public License v1.0 which accompanies this distribution,
6  * and is available at http://www.eclipse.org/legal/epl-v10.html
7  */
8 package org.opendaylight.controller.yang.parser.impl;
9
10 import static org.opendaylight.controller.yang.parser.util.YangModelBuilderUtil.*;
11
12 import java.net.URI;
13 import java.text.DateFormat;
14 import java.text.ParseException;
15 import java.text.SimpleDateFormat;
16 import java.util.ArrayList;
17 import java.util.Date;
18 import java.util.List;
19 import java.util.Stack;
20
21 import org.antlr.v4.runtime.tree.ParseTree;
22 import org.opendaylight.controller.antlrv4.code.gen.*;
23 import org.opendaylight.controller.antlrv4.code.gen.YangParser.Argument_stmtContext;
24 import org.opendaylight.controller.antlrv4.code.gen.YangParser.Base_stmtContext;
25 import org.opendaylight.controller.antlrv4.code.gen.YangParser.Contact_stmtContext;
26 import org.opendaylight.controller.antlrv4.code.gen.YangParser.Container_stmtContext;
27 import org.opendaylight.controller.antlrv4.code.gen.YangParser.Default_stmtContext;
28 import org.opendaylight.controller.antlrv4.code.gen.YangParser.Description_stmtContext;
29 import org.opendaylight.controller.antlrv4.code.gen.YangParser.Deviate_add_stmtContext;
30 import org.opendaylight.controller.antlrv4.code.gen.YangParser.Deviate_delete_stmtContext;
31 import org.opendaylight.controller.antlrv4.code.gen.YangParser.Deviate_not_supported_stmtContext;
32 import org.opendaylight.controller.antlrv4.code.gen.YangParser.Deviate_replace_stmtContext;
33 import org.opendaylight.controller.antlrv4.code.gen.YangParser.Import_stmtContext;
34 import org.opendaylight.controller.antlrv4.code.gen.YangParser.Key_stmtContext;
35 import org.opendaylight.controller.antlrv4.code.gen.YangParser.Leaf_list_stmtContext;
36 import org.opendaylight.controller.antlrv4.code.gen.YangParser.Leaf_stmtContext;
37 import org.opendaylight.controller.antlrv4.code.gen.YangParser.List_stmtContext;
38 import org.opendaylight.controller.antlrv4.code.gen.YangParser.Module_header_stmtsContext;
39 import org.opendaylight.controller.antlrv4.code.gen.YangParser.Namespace_stmtContext;
40 import org.opendaylight.controller.antlrv4.code.gen.YangParser.Ordered_by_stmtContext;
41 import org.opendaylight.controller.antlrv4.code.gen.YangParser.Organization_stmtContext;
42 import org.opendaylight.controller.antlrv4.code.gen.YangParser.Prefix_stmtContext;
43 import org.opendaylight.controller.antlrv4.code.gen.YangParser.Presence_stmtContext;
44 import org.opendaylight.controller.antlrv4.code.gen.YangParser.Reference_stmtContext;
45 import org.opendaylight.controller.antlrv4.code.gen.YangParser.Revision_date_stmtContext;
46 import org.opendaylight.controller.antlrv4.code.gen.YangParser.Revision_stmtContext;
47 import org.opendaylight.controller.antlrv4.code.gen.YangParser.Revision_stmtsContext;
48 import org.opendaylight.controller.antlrv4.code.gen.YangParser.Status_stmtContext;
49 import org.opendaylight.controller.antlrv4.code.gen.YangParser.Type_body_stmtsContext;
50 import org.opendaylight.controller.antlrv4.code.gen.YangParser.Units_stmtContext;
51 import org.opendaylight.controller.antlrv4.code.gen.YangParser.When_stmtContext;
52 import org.opendaylight.controller.antlrv4.code.gen.YangParser.Yang_version_stmtContext;
53 import org.opendaylight.controller.yang.common.QName;
54 import org.opendaylight.controller.yang.model.api.SchemaPath;
55 import org.opendaylight.controller.yang.model.api.Status;
56 import org.opendaylight.controller.yang.model.api.TypeDefinition;
57 import org.opendaylight.controller.yang.model.util.YangTypesConverter;
58 import org.opendaylight.controller.yang.parser.builder.api.AugmentationSchemaBuilder;
59 import org.opendaylight.controller.yang.parser.builder.api.GroupingBuilder;
60 import org.opendaylight.controller.yang.parser.builder.api.TypeDefinitionBuilder;
61 import org.opendaylight.controller.yang.parser.builder.api.UsesNodeBuilder;
62 import org.opendaylight.controller.yang.parser.builder.impl.AnyXmlBuilder;
63 import org.opendaylight.controller.yang.parser.builder.impl.ChoiceBuilder;
64 import org.opendaylight.controller.yang.parser.builder.impl.ChoiceCaseBuilder;
65 import org.opendaylight.controller.yang.parser.builder.impl.ContainerSchemaNodeBuilder;
66 import org.opendaylight.controller.yang.parser.builder.impl.DeviationBuilder;
67 import org.opendaylight.controller.yang.parser.builder.impl.ExtensionBuilder;
68 import org.opendaylight.controller.yang.parser.builder.impl.FeatureBuilder;
69 import org.opendaylight.controller.yang.parser.builder.impl.IdentitySchemaNodeBuilder;
70 import org.opendaylight.controller.yang.parser.builder.impl.LeafListSchemaNodeBuilder;
71 import org.opendaylight.controller.yang.parser.builder.impl.LeafSchemaNodeBuilder;
72 import org.opendaylight.controller.yang.parser.builder.impl.ListSchemaNodeBuilder;
73 import org.opendaylight.controller.yang.parser.builder.impl.ModuleBuilder;
74 import org.opendaylight.controller.yang.parser.builder.impl.NotificationBuilder;
75 import org.opendaylight.controller.yang.parser.builder.impl.RpcDefinitionBuilder;
76 import org.opendaylight.controller.yang.parser.builder.impl.UnionTypeBuilder;
77 import org.opendaylight.controller.yang.parser.builder.impl.UnknownSchemaNodeBuilder;
78 import org.opendaylight.controller.yang.parser.util.RefineHolder;
79 import org.slf4j.Logger;
80 import org.slf4j.LoggerFactory;
81
82 public final class YangParserListenerImpl extends YangParserBaseListener {
83     private static final Logger logger = LoggerFactory.getLogger(YangParserListenerImpl.class);
84
85     private ModuleBuilder moduleBuilder;
86     private String moduleName;
87     private URI namespace;
88     private String yangModelPrefix;
89     private Date revision = new Date(0L);
90
91     public final static DateFormat simpleDateFormat = new SimpleDateFormat("yyyy-MM-dd");
92     private final Stack<String> actualPath = new Stack<String>();
93
94     @Override
95     public void enterModule_stmt(YangParser.Module_stmtContext ctx) {
96         moduleName = stringFromNode(ctx);
97         actualPath.push(moduleName);
98         moduleBuilder = new ModuleBuilder(moduleName);
99
100         String description = null;
101         String reference = null;
102
103         for (int i = 0; i < ctx.getChildCount(); i++) {
104             ParseTree child = ctx.getChild(i);
105             if (child instanceof Description_stmtContext) {
106                 description = stringFromNode(child);
107             } else if (child instanceof Reference_stmtContext) {
108                 reference = stringFromNode(child);
109             } else {
110                 if (description != null && reference != null) {
111                     break;
112                 }
113             }
114         }
115         moduleBuilder.setDescription(description);
116         moduleBuilder.setReference(reference);
117     }
118
119     @Override
120     public void exitModule_stmt(YangParser.Module_stmtContext ctx) {
121         final String moduleName = actualPath.pop();
122         logger.debug("Exiting module " + moduleName);
123     }
124
125     @Override
126     public void enterModule_header_stmts(final Module_header_stmtsContext ctx) {
127         super.enterModule_header_stmts(ctx);
128
129         String yangVersion = null;
130         for (int i = 0; i < ctx.getChildCount(); ++i) {
131             final ParseTree treeNode = ctx.getChild(i);
132             if (treeNode instanceof Namespace_stmtContext) {
133                 final String namespaceStr = stringFromNode(treeNode);
134                 namespace = URI.create(namespaceStr);
135                 moduleBuilder.setNamespace(namespace);
136             } else if (treeNode instanceof Prefix_stmtContext) {
137                 yangModelPrefix = stringFromNode(treeNode);
138                 moduleBuilder.setPrefix(yangModelPrefix);
139             } else if (treeNode instanceof Yang_version_stmtContext) {
140                 yangVersion = stringFromNode(treeNode);
141             }
142         }
143
144         if (yangVersion == null) {
145             yangVersion = "1";
146         }
147         moduleBuilder.setYangVersion(yangVersion);
148     }
149
150     @Override
151     public void enterMeta_stmts(YangParser.Meta_stmtsContext ctx) {
152         for (int i = 0; i < ctx.getChildCount(); i++) {
153             ParseTree child = ctx.getChild(i);
154             if (child instanceof Organization_stmtContext) {
155                 final String organization = stringFromNode(child);
156                 moduleBuilder.setOrganization(organization);
157             } else if (child instanceof Contact_stmtContext) {
158                 final String contact = stringFromNode(child);
159                 moduleBuilder.setContact(contact);
160             } else if (child instanceof Description_stmtContext) {
161                 final String description = stringFromNode(child);
162                 moduleBuilder.setDescription(description);
163             } else if (child instanceof Reference_stmtContext) {
164                 final String reference = stringFromNode(child);
165                 moduleBuilder.setReference(reference);
166             }
167         }
168     }
169
170     @Override
171     public void exitSubmodule_header_stmts(YangParser.Submodule_header_stmtsContext ctx) {
172         final String submodule = actualPath.pop();
173         logger.debug("exiting submodule " + submodule);
174     }
175
176     @Override
177     public void enterRevision_stmts(Revision_stmtsContext ctx) {
178         if (ctx != null) {
179             for (int i = 0; i < ctx.getChildCount(); ++i) {
180                 final ParseTree treeNode = ctx.getChild(i);
181                 if (treeNode instanceof Revision_stmtContext) {
182                     updateRevisionForRevisionStatement(treeNode);
183                 }
184             }
185         }
186     }
187
188     private void updateRevisionForRevisionStatement(final ParseTree treeNode) {
189         final String revisionDateStr = stringFromNode(treeNode);
190         try {
191             final Date revision = simpleDateFormat.parse(revisionDateStr);
192             if ((revision != null) && (this.revision.compareTo(revision) < 0)) {
193                 this.revision = revision;
194                 moduleBuilder.setRevision(this.revision);
195                 for (int i = 0; i < treeNode.getChildCount(); ++i) {
196                     ParseTree child = treeNode.getChild(i);
197                     if (child instanceof Reference_stmtContext) {
198                         moduleBuilder.setReference(stringFromNode(child));
199                     }
200                 }
201             }
202         } catch (ParseException e) {
203             final String message = "Failed to parse revision string: " + revisionDateStr;
204             logger.warn(message);
205         }
206     }
207
208     @Override
209     public void enterImport_stmt(Import_stmtContext ctx) {
210         final String importName = stringFromNode(ctx);
211         String importPrefix = null;
212         Date importRevision = null;
213
214         for (int i = 0; i < ctx.getChildCount(); ++i) {
215             final ParseTree treeNode = ctx.getChild(i);
216             if (treeNode instanceof Prefix_stmtContext) {
217                 importPrefix = stringFromNode(treeNode);
218             }
219             if (treeNode instanceof Revision_date_stmtContext) {
220                 String importRevisionStr = stringFromNode(treeNode);
221                 try {
222                     importRevision = simpleDateFormat.parse(importRevisionStr);
223                 } catch (ParseException e) {
224                     logger.warn("Failed to parse import revision-date: " + importRevisionStr);
225                 }
226             }
227         }
228         moduleBuilder.addModuleImport(importName, importRevision, importPrefix);
229     }
230
231     @Override
232     public void enterAugment_stmt(YangParser.Augment_stmtContext ctx) {
233         final String augmentPath = stringFromNode(ctx);
234         AugmentationSchemaBuilder builder = moduleBuilder.addAugment(augmentPath, actualPath, ctx.getStart().getLine());
235         moduleBuilder.enterNode(builder);
236         updatePath(augmentPath);
237
238         for (int i = 0; i < ctx.getChildCount(); i++) {
239             ParseTree child = ctx.getChild(i);
240             if (child instanceof Description_stmtContext) {
241                 String desc = stringFromNode(child);
242                 builder.setDescription(desc);
243             } else if (child instanceof Reference_stmtContext) {
244                 String ref = stringFromNode(child);
245                 builder.setReference(ref);
246             } else if (child instanceof Status_stmtContext) {
247                 Status status = parseStatus((Status_stmtContext) child);
248                 builder.setStatus(status);
249             } else if (child instanceof When_stmtContext) {
250                 String when = stringFromNode(child);
251                 builder.addWhenCondition(when);
252             }
253         }
254     }
255
256     @Override
257     public void exitAugment_stmt(YangParser.Augment_stmtContext ctx) {
258         final String augment = actualPath.pop();
259         logger.debug("exiting augment " + augment);
260         moduleBuilder.exitNode();
261     }
262
263     @Override
264     public void enterExtension_stmt(YangParser.Extension_stmtContext ctx) {
265         final String extName = stringFromNode(ctx);
266         QName qname = new QName(namespace, revision, yangModelPrefix, extName);
267         ExtensionBuilder builder = moduleBuilder.addExtension(qname, ctx.getStart().getLine());
268         parseSchemaNodeArgs(ctx, builder);
269
270         String argument = null;
271         boolean yin = false;
272         for (int i = 0; i < ctx.getChildCount(); i++) {
273             ParseTree child = ctx.getChild(i);
274             if (child instanceof Argument_stmtContext) {
275                 argument = stringFromNode(child);
276                 yin = parseYinValue((Argument_stmtContext) child);
277                 break;
278             }
279         }
280         builder.setArgument(argument);
281         builder.setYinElement(yin);
282     }
283
284     @Override
285     public void enterTypedef_stmt(YangParser.Typedef_stmtContext ctx) {
286         final String typedefName = stringFromNode(ctx);
287         QName typedefQName = new QName(namespace, revision, yangModelPrefix, typedefName);
288         TypeDefinitionBuilder builder = moduleBuilder.addTypedef(typedefQName, actualPath, ctx.getStart().getLine());
289         moduleBuilder.enterNode(builder);
290         updatePath(typedefName);
291
292         builder.setPath(createActualSchemaPath(actualPath, namespace, revision, yangModelPrefix));
293         parseSchemaNodeArgs(ctx, builder);
294         builder.setUnits(parseUnits(ctx));
295     }
296
297     @Override
298     public void exitTypedef_stmt(YangParser.Typedef_stmtContext ctx) {
299         final String actContainer = actualPath.pop();
300         logger.debug("exiting " + actContainer);
301         moduleBuilder.exitNode();
302     }
303
304     @Override
305     public void enterType_stmt(YangParser.Type_stmtContext ctx) {
306         final String typeName = stringFromNode(ctx);
307         final int line = ctx.getStart().getLine();
308         final QName typeQName = parseQName(typeName);
309
310         TypeDefinition<?> type = null;
311         Type_body_stmtsContext typeBody = null;
312         for (int i = 0; i < ctx.getChildCount(); i++) {
313             if (ctx.getChild(i) instanceof Type_body_stmtsContext) {
314                 typeBody = (Type_body_stmtsContext) ctx.getChild(i);
315                 break;
316             }
317         }
318
319         // if this is base yang type...
320         if (YangTypesConverter.isBaseYangType(typeName)) {
321             if (typeBody == null) {
322                 // check for types which must have body
323                 checkMissingBody(typeName, moduleName, line);
324                 // if there are no constraints, just grab default base yang type
325                 type = YangTypesConverter.javaTypeForBaseYangType(actualPath, namespace, revision, typeName);
326                 moduleBuilder.setType(type, actualPath);
327             } else {
328                 if ("union".equals(typeName)) {
329                     List<String> typePath = new ArrayList<String>(actualPath);
330                     typePath.add(typeName);
331                     SchemaPath p = createActualSchemaPath(typePath, namespace, revision, yangModelPrefix);
332                     UnionTypeBuilder unionBuilder = moduleBuilder.addUnionType(actualPath, namespace, revision, line);
333                     moduleBuilder.enterNode(unionBuilder);
334                     unionBuilder.setPath(p);
335                 } else if ("identityref".equals(typeName)) {
336                     SchemaPath path = createActualSchemaPath(actualPath, namespace, revision, yangModelPrefix);
337                     moduleBuilder.addIdentityrefType(getIdentityrefBase(typeBody), actualPath, path, line);
338                 } else {
339                     type = parseTypeWithBody(moduleName, typeName, typeBody, actualPath, namespace, revision,
340                             yangModelPrefix, moduleBuilder.getActualNode());
341                     moduleBuilder.setType(type, actualPath);
342                 }
343             }
344         } else {
345             type = parseUnknownTypeWithBody(typeQName, typeBody, actualPath, namespace, revision, yangModelPrefix,
346                     moduleBuilder.getActualNode());
347             // add parent node of this type statement to dirty nodes
348             moduleBuilder.addDirtyNode(actualPath);
349             moduleBuilder.setType(type, actualPath);
350         }
351
352         updatePath(typeName);
353     }
354
355     private QName parseQName(String typeName) {
356         QName typeQName;
357         if (typeName.contains(":")) {
358             String[] splittedName = typeName.split(":");
359             String prefix = splittedName[0];
360             String name = splittedName[1];
361             if (prefix.equals(yangModelPrefix)) {
362                 typeQName = new QName(namespace, revision, prefix, name);
363             } else {
364                 typeQName = new QName(null, null, prefix, name);
365             }
366         } else {
367             typeQName = new QName(namespace, revision, yangModelPrefix, typeName);
368         }
369         return typeQName;
370     }
371
372     @Override
373     public void exitType_stmt(YangParser.Type_stmtContext ctx) {
374         final String actContainer = actualPath.pop();
375         logger.debug("exiting " + actContainer);
376
377         final String typeName = stringFromNode(ctx);
378         if ("union".equals(typeName)) {
379             moduleBuilder.exitNode();
380         }
381     }
382
383     @Override
384     public void enterGrouping_stmt(YangParser.Grouping_stmtContext ctx) {
385         final String groupName = stringFromNode(ctx);
386         QName groupQName = new QName(namespace, revision, yangModelPrefix, groupName);
387         GroupingBuilder builder = moduleBuilder.addGrouping(groupQName, actualPath, ctx.getStart().getLine());
388         moduleBuilder.enterNode(builder);
389         updatePath(groupName);
390         builder.setPath(createActualSchemaPath(actualPath, namespace, revision, yangModelPrefix));
391         parseSchemaNodeArgs(ctx, builder);
392     }
393
394     @Override
395     public void exitGrouping_stmt(YangParser.Grouping_stmtContext ctx) {
396         String actContainer = actualPath.pop();
397         logger.debug("exiting " + actContainer);
398         moduleBuilder.exitNode();
399     }
400
401     @Override
402     public void enterContainer_stmt(Container_stmtContext ctx) {
403         final int line = ctx.getStart().getLine();
404         final String containerName = stringFromNode(ctx);
405         QName containerQName = new QName(namespace, revision, yangModelPrefix, containerName);
406
407         SchemaPath path = createActualSchemaPath(actualPath, namespace, revision, yangModelPrefix, containerName);
408
409         ContainerSchemaNodeBuilder builder = moduleBuilder.addContainerNode(path, containerQName, actualPath, line);
410         moduleBuilder.enterNode(builder);
411         updatePath(containerName);
412
413         parseSchemaNodeArgs(ctx, builder);
414         parseConstraints(ctx, builder.getConstraints());
415         builder.setConfiguration(getConfig(ctx, moduleBuilder.getActualParent(), moduleName, line));
416
417         for (int i = 0; i < ctx.getChildCount(); ++i) {
418             final ParseTree childNode = ctx.getChild(i);
419             if (childNode instanceof Presence_stmtContext) {
420                 builder.setPresence(true);
421                 break;
422             }
423         }
424     }
425
426     @Override
427     public void exitContainer_stmt(Container_stmtContext ctx) {
428         final String actContainer = actualPath.pop();
429         logger.debug("exiting " + actContainer);
430         moduleBuilder.exitNode();
431     }
432
433     @Override
434     public void enterLeaf_stmt(Leaf_stmtContext ctx) {
435         final String leafName = stringFromNode(ctx);
436         QName leafQName = new QName(namespace, revision, yangModelPrefix, leafName);
437         SchemaPath schemaPath = createActualSchemaPath(actualPath, namespace, revision, yangModelPrefix, leafName);
438
439         LeafSchemaNodeBuilder builder = moduleBuilder.addLeafNode(schemaPath, leafQName, actualPath, ctx.getStart().getLine());
440         moduleBuilder.enterNode(builder);
441         updatePath(leafName);
442
443         parseSchemaNodeArgs(ctx, builder);
444         parseConstraints(ctx, builder.getConstraints());
445         builder.setConfiguration(getConfig(ctx, moduleBuilder.getActualParent(), moduleName, ctx.getStart().getLine()));
446
447         String defaultStr = null;
448         String unitsStr = null;
449         for (int i = 0; i < ctx.getChildCount(); i++) {
450             ParseTree child = ctx.getChild(i);
451             if (child instanceof Default_stmtContext) {
452                 defaultStr = stringFromNode(child);
453             } else if (child instanceof Units_stmtContext) {
454                 unitsStr = stringFromNode(child);
455             }
456         }
457         builder.setDefaultStr(defaultStr);
458         builder.setUnits(unitsStr);
459     }
460
461     @Override
462     public void exitLeaf_stmt(YangParser.Leaf_stmtContext ctx) {
463         final String actLeaf = actualPath.pop();
464         logger.debug("exiting " + actLeaf);
465         moduleBuilder.exitNode();
466     }
467
468     @Override
469     public void enterUses_stmt(YangParser.Uses_stmtContext ctx) {
470         final String groupingPathStr = stringFromNode(ctx);
471         UsesNodeBuilder builder = moduleBuilder.addUsesNode(groupingPathStr, actualPath, ctx.getStart().getLine());
472
473         moduleBuilder.enterNode(builder);
474         updatePath(groupingPathStr);
475     }
476
477     @Override
478     public void exitUses_stmt(YangParser.Uses_stmtContext ctx) {
479         final String actContainer = actualPath.pop();
480         logger.debug("exiting " + actContainer);
481         moduleBuilder.exitNode();
482     }
483
484     @Override
485     public void enterRefine_stmt(YangParser.Refine_stmtContext ctx) {
486         String refineString = stringFromNode(ctx);
487         RefineHolder refine = parseRefine(ctx);
488         moduleBuilder.addRefine(refine, actualPath);
489         moduleBuilder.enterNode(refine);
490         updatePath(refineString);
491     }
492
493     @Override
494     public void exitRefine_stmt(YangParser.Refine_stmtContext ctx) {
495         final String actContainer = actualPath.pop();
496         logger.debug("exiting " + actContainer);
497         moduleBuilder.exitNode();
498     }
499
500     @Override
501     public void enterLeaf_list_stmt(Leaf_list_stmtContext ctx) {
502         final String leafListName = stringFromNode(ctx);
503         QName leafListQName = new QName(namespace, revision, yangModelPrefix, leafListName);
504         SchemaPath schemaPath = createActualSchemaPath(actualPath, namespace, revision, yangModelPrefix, leafListName);
505
506         LeafListSchemaNodeBuilder builder = moduleBuilder.addLeafListNode(schemaPath, leafListQName, actualPath, ctx.getStart()
507                 .getLine());
508         moduleBuilder.enterNode(builder);
509         updatePath(leafListName);
510
511         parseSchemaNodeArgs(ctx, builder);
512         parseConstraints(ctx, builder.getConstraints());
513         builder.setConfiguration(getConfig(ctx, moduleBuilder.getActualParent(), moduleName, ctx.getStart().getLine()));
514
515         for (int i = 0; i < ctx.getChildCount(); ++i) {
516             final ParseTree childNode = ctx.getChild(i);
517             if (childNode instanceof Ordered_by_stmtContext) {
518                 final Ordered_by_stmtContext orderedBy = (Ordered_by_stmtContext) childNode;
519                 final boolean userOrdered = parseUserOrdered(orderedBy);
520                 builder.setUserOrdered(userOrdered);
521                 break;
522             }
523         }
524     }
525
526     @Override
527     public void exitLeaf_list_stmt(YangParser.Leaf_list_stmtContext ctx) {
528         final String actContainer = actualPath.pop();
529         logger.debug("exiting " + actContainer);
530         moduleBuilder.exitNode();
531     }
532
533     @Override
534     public void enterList_stmt(List_stmtContext ctx) {
535         final String listName = stringFromNode(ctx);
536         QName listQName = new QName(namespace, revision, yangModelPrefix, listName);
537         SchemaPath schemaPath = createActualSchemaPath(actualPath, namespace, revision, yangModelPrefix, listName);
538
539         ListSchemaNodeBuilder builder = moduleBuilder.addListNode(schemaPath, listQName, actualPath, ctx.getStart().getLine());
540         moduleBuilder.enterNode(builder);
541         updatePath(listName);
542
543         parseSchemaNodeArgs(ctx, builder);
544         parseConstraints(ctx, builder.getConstraints());
545         builder.setConfiguration(getConfig(ctx, moduleBuilder.getActualParent(), moduleName, ctx.getStart().getLine()));
546
547         String keyDefinition = "";
548         for (int i = 0; i < ctx.getChildCount(); ++i) {
549             ParseTree childNode = ctx.getChild(i);
550             if (childNode instanceof Ordered_by_stmtContext) {
551                 final Ordered_by_stmtContext orderedBy = (Ordered_by_stmtContext) childNode;
552                 final boolean userOrdered = parseUserOrdered(orderedBy);
553                 builder.setUserOrdered(userOrdered);
554             } else if (childNode instanceof Key_stmtContext) {
555                 keyDefinition = stringFromNode(childNode);
556                 List<QName> key = createListKey(keyDefinition, namespace, revision, yangModelPrefix);
557                 builder.setKeyDefinition(key);
558             }
559         }
560     }
561
562     @Override
563     public void exitList_stmt(List_stmtContext ctx) {
564         final String actContainer = actualPath.pop();
565         logger.debug("exiting " + actContainer);
566         moduleBuilder.exitNode();
567     }
568
569     @Override
570     public void enterAnyxml_stmt(YangParser.Anyxml_stmtContext ctx) {
571         final String anyXmlName = stringFromNode(ctx);
572         QName anyXmlQName = new QName(namespace, revision, yangModelPrefix, anyXmlName);
573         SchemaPath schemaPath = createActualSchemaPath(actualPath, namespace, revision, yangModelPrefix, anyXmlName);
574
575         AnyXmlBuilder builder = moduleBuilder.addAnyXml(schemaPath, anyXmlQName, actualPath, ctx.getStart().getLine());
576         moduleBuilder.enterNode(builder);
577         updatePath(anyXmlName);
578
579         parseSchemaNodeArgs(ctx, builder);
580         parseConstraints(ctx, builder.getConstraints());
581         builder.setConfiguration(getConfig(ctx, moduleBuilder.getActualParent(), moduleName, ctx.getStart().getLine()));
582     }
583
584     @Override
585     public void exitAnyxml_stmt(YangParser.Anyxml_stmtContext ctx) {
586         final String actContainer = actualPath.pop();
587         logger.debug("exiting " + actContainer);
588         moduleBuilder.exitNode();
589     }
590
591     @Override
592     public void enterChoice_stmt(YangParser.Choice_stmtContext ctx) {
593         final String choiceName = stringFromNode(ctx);
594         QName choiceQName = new QName(namespace, revision, yangModelPrefix, choiceName);
595         ChoiceBuilder builder = moduleBuilder.addChoice(choiceQName, actualPath, ctx.getStart().getLine());
596         moduleBuilder.enterNode(builder);
597
598         updatePath(choiceName);
599         builder.setPath(createActualSchemaPath(actualPath, namespace, revision, yangModelPrefix));
600         parseSchemaNodeArgs(ctx, builder);
601         parseConstraints(ctx, builder.getConstraints());
602         builder.setConfiguration(getConfig(ctx, moduleBuilder.getActualParent(), moduleName, ctx.getStart().getLine()));
603
604         // set 'default' case
605         for (int i = 0; i < ctx.getChildCount(); i++) {
606             ParseTree child = ctx.getChild(i);
607             if (child instanceof Default_stmtContext) {
608                 String defaultCase = stringFromNode(child);
609                 builder.setDefaultCase(defaultCase);
610                 break;
611             }
612         }
613     }
614
615     @Override
616     public void exitChoice_stmt(YangParser.Choice_stmtContext ctx) {
617         final String actContainer = actualPath.pop();
618         logger.debug("exiting " + actContainer);
619         moduleBuilder.exitNode();
620     }
621
622     @Override
623     public void enterCase_stmt(YangParser.Case_stmtContext ctx) {
624         final String caseName = stringFromNode(ctx);
625         QName choiceQName = new QName(namespace, revision, yangModelPrefix, caseName);
626         ChoiceCaseBuilder builder = moduleBuilder.addCase(choiceQName, actualPath, ctx.getStart().getLine());
627         moduleBuilder.enterNode(builder);
628
629         updatePath(caseName);
630         builder.setPath(createActualSchemaPath(actualPath, namespace, revision, yangModelPrefix));
631         parseSchemaNodeArgs(ctx, builder);
632         parseConstraints(ctx, builder.getConstraints());
633     }
634
635     @Override
636     public void exitCase_stmt(YangParser.Case_stmtContext ctx) {
637         final String actContainer = actualPath.pop();
638         logger.debug("exiting " + actContainer);
639         moduleBuilder.exitNode();
640     }
641
642     @Override
643     public void enterNotification_stmt(YangParser.Notification_stmtContext ctx) {
644         final String notificationName = stringFromNode(ctx);
645         QName notificationQName = new QName(namespace, revision, yangModelPrefix, notificationName);
646         NotificationBuilder builder = moduleBuilder.addNotification(notificationQName, actualPath, ctx.getStart()
647                 .getLine());
648         moduleBuilder.enterNode(builder);
649         updatePath(notificationName);
650
651         builder.setPath(createActualSchemaPath(actualPath, namespace, revision, yangModelPrefix));
652         parseSchemaNodeArgs(ctx, builder);
653     }
654
655     @Override
656     public void exitNotification_stmt(YangParser.Notification_stmtContext ctx) {
657         final String actContainer = actualPath.pop();
658         logger.debug("exiting " + actContainer);
659         moduleBuilder.exitNode();
660     }
661
662     // Unknown types
663     @Override
664     public void enterIdentifier_stmt(YangParser.Identifier_stmtContext ctx) {
665         final String nodeParameter = stringFromNode(ctx);
666         QName nodeType = null;
667
668         final String nodeTypeStr = ctx.getChild(0).getText();
669         final String[] splittedElement = nodeTypeStr.split(":");
670         if (splittedElement.length == 1) {
671             nodeType = new QName(null, null, yangModelPrefix, splittedElement[0]);
672         } else {
673             nodeType = new QName(null, null, splittedElement[0], splittedElement[1]);
674         }
675
676         QName qname;
677         if (nodeParameter != null) {
678             String[] splittedName = nodeParameter.split(":");
679             if (splittedName.length == 2) {
680                 qname = new QName(null, null, splittedName[0], splittedName[1]);
681             } else {
682                 qname = new QName(namespace, revision, yangModelPrefix, splittedName[0]);
683             }
684         } else {
685             qname = new QName(namespace, revision, yangModelPrefix, nodeParameter);
686         }
687
688         UnknownSchemaNodeBuilder builder = moduleBuilder.addUnknownSchemaNode(qname, actualPath, ctx.getStart()
689                 .getLine());
690         builder.setNodeType(nodeType);
691         builder.setNodeParameter(nodeParameter);
692         updatePath(nodeParameter);
693         builder.setPath(createActualSchemaPath(actualPath, namespace, revision, yangModelPrefix));
694         parseSchemaNodeArgs(ctx, builder);
695         moduleBuilder.enterNode(builder);
696     }
697
698     @Override
699     public void exitIdentifier_stmt(YangParser.Identifier_stmtContext ctx) {
700         final String actContainer = actualPath.pop();
701         logger.debug("exiting " + actContainer);
702         moduleBuilder.exitNode();
703     }
704
705     @Override
706     public void enterRpc_stmt(YangParser.Rpc_stmtContext ctx) {
707         final String rpcName = stringFromNode(ctx);
708         QName rpcQName = new QName(namespace, revision, yangModelPrefix, rpcName);
709         RpcDefinitionBuilder rpcBuilder = moduleBuilder.addRpc(rpcQName, actualPath, ctx.getStart().getLine());
710         moduleBuilder.enterNode(rpcBuilder);
711         updatePath(rpcName);
712
713         rpcBuilder.setPath(createActualSchemaPath(actualPath, namespace, revision, yangModelPrefix));
714         parseSchemaNodeArgs(ctx, rpcBuilder);
715     }
716
717     @Override
718     public void exitRpc_stmt(YangParser.Rpc_stmtContext ctx) {
719         final String actContainer = actualPath.pop();
720         logger.debug("exiting " + actContainer);
721         moduleBuilder.exitNode();
722     }
723
724     @Override
725     public void enterInput_stmt(YangParser.Input_stmtContext ctx) {
726         final String input = "input";
727         QName rpcQName = new QName(namespace, revision, yangModelPrefix, input);
728         SchemaPath path = createActualSchemaPath(actualPath, namespace, revision, yangModelPrefix, input);
729
730         ContainerSchemaNodeBuilder builder = moduleBuilder.addRpcInput(path, rpcQName, ctx.getStart().getLine());
731         moduleBuilder.enterNode(builder);
732         updatePath(input);
733
734         parseSchemaNodeArgs(ctx, builder);
735         parseConstraints(ctx, builder.getConstraints());
736     }
737
738     @Override
739     public void exitInput_stmt(YangParser.Input_stmtContext ctx) {
740         final String actContainer = actualPath.pop();
741         logger.debug("exiting " + actContainer);
742         moduleBuilder.exitNode();
743     }
744
745     @Override
746     public void enterOutput_stmt(YangParser.Output_stmtContext ctx) {
747         final String output = "output";
748         QName rpcQName = new QName(namespace, revision, yangModelPrefix, output);
749         SchemaPath path = createActualSchemaPath(actualPath, namespace, revision, yangModelPrefix, output);
750
751         ContainerSchemaNodeBuilder builder = moduleBuilder.addRpcOutput(path, rpcQName, ctx.getStart().getLine());
752         moduleBuilder.enterNode(builder);
753         updatePath(output);
754
755         parseSchemaNodeArgs(ctx, builder);
756         parseConstraints(ctx, builder.getConstraints());
757     }
758
759     @Override
760     public void exitOutput_stmt(YangParser.Output_stmtContext ctx) {
761         final String actContainer = actualPath.pop();
762         logger.debug("exiting " + actContainer);
763         moduleBuilder.exitNode();
764     }
765
766     @Override
767     public void enterFeature_stmt(YangParser.Feature_stmtContext ctx) {
768         final String featureName = stringFromNode(ctx);
769         QName featureQName = new QName(namespace, revision, yangModelPrefix, featureName);
770         FeatureBuilder featureBuilder = moduleBuilder.addFeature(featureQName, actualPath, ctx.getStart().getLine());
771         moduleBuilder.enterNode(featureBuilder);
772         updatePath(featureName);
773
774         featureBuilder.setPath(createActualSchemaPath(actualPath, namespace, revision, yangModelPrefix));
775         parseSchemaNodeArgs(ctx, featureBuilder);
776     }
777
778     @Override
779     public void exitFeature_stmt(YangParser.Feature_stmtContext ctx) {
780         final String actContainer = actualPath.pop();
781         logger.debug("exiting " + actContainer);
782         moduleBuilder.exitNode();
783     }
784
785     @Override
786     public void enterDeviation_stmt(YangParser.Deviation_stmtContext ctx) {
787         final String targetPath = stringFromNode(ctx);
788         String reference = null;
789         String deviate = null;
790         DeviationBuilder builder = moduleBuilder.addDeviation(targetPath, actualPath, ctx.getStart().getLine());
791         moduleBuilder.enterNode(builder);
792         updatePath(targetPath);
793
794         for (int i = 0; i < ctx.getChildCount(); i++) {
795             ParseTree child = ctx.getChild(i);
796             if (child instanceof Reference_stmtContext) {
797                 reference = stringFromNode(child);
798             } else if (child instanceof Deviate_not_supported_stmtContext) {
799                 deviate = stringFromNode(child);
800             } else if (child instanceof Deviate_add_stmtContext) {
801                 deviate = stringFromNode(child);
802             } else if (child instanceof Deviate_replace_stmtContext) {
803                 deviate = stringFromNode(child);
804             } else if (child instanceof Deviate_delete_stmtContext) {
805                 deviate = stringFromNode(child);
806             }
807         }
808         builder.setReference(reference);
809         builder.setDeviate(deviate);
810     }
811
812     @Override
813     public void exitDeviation_stmt(YangParser.Deviation_stmtContext ctx) {
814         final String actContainer = actualPath.pop();
815         logger.debug("exiting " + actContainer);
816         moduleBuilder.exitNode();
817     }
818
819     @Override
820     public void enterIdentity_stmt(YangParser.Identity_stmtContext ctx) {
821         final String identityName = stringFromNode(ctx);
822         final QName identityQName = new QName(namespace, revision, yangModelPrefix, identityName);
823         IdentitySchemaNodeBuilder builder = moduleBuilder.addIdentity(identityQName, actualPath, ctx.getStart()
824                 .getLine());
825         moduleBuilder.enterNode(builder);
826         updatePath(identityName);
827
828         builder.setPath(createActualSchemaPath(actualPath, namespace, revision, yangModelPrefix));
829         parseSchemaNodeArgs(ctx, builder);
830
831         for (int i = 0; i < ctx.getChildCount(); i++) {
832             ParseTree child = ctx.getChild(i);
833             if (child instanceof Base_stmtContext) {
834                 String baseIdentityName = stringFromNode(child);
835                 builder.setBaseIdentityName(baseIdentityName);
836             }
837         }
838     }
839
840     @Override
841     public void exitIdentity_stmt(YangParser.Identity_stmtContext ctx) {
842         final String actContainer = actualPath.pop();
843         logger.debug("exiting " + actContainer);
844         moduleBuilder.exitNode();
845     }
846
847     public ModuleBuilder getModuleBuilder() {
848         return moduleBuilder;
849     }
850
851     private void updatePath(String containerName) {
852         actualPath.push(containerName);
853     }
854
855 }