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