d7394e62291db2ca98e6be896cc551a4b800e08e
[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                     type = parseTypeBody(typeName, typeBody, actualPath,
360                             namespace, revision, yangModelPrefix);
361                     moduleBuilder.setType(type, actualPath);
362                 }
363             }
364         } else {
365             type = parseUnknownTypeBody(typeQName, typeBody);
366             // mark parent node of this type statement as dirty
367             moduleBuilder.addDirtyNode(actualPath);
368             moduleBuilder.setType(type, actualPath);
369         }
370
371         updatePath(typeName);
372     }
373
374     private QName parseQName(String typeName) {
375         QName typeQName;
376         if (typeName.contains(":")) {
377             String[] splittedName = typeName.split(":");
378             String prefix = splittedName[0];
379             String name = splittedName[1];
380             if (prefix.equals(yangModelPrefix)) {
381                 typeQName = new QName(namespace, revision, prefix, name);
382             } else {
383                 typeQName = new QName(null, null, prefix, name);
384             }
385         } else {
386             typeQName = new QName(namespace, revision, yangModelPrefix,
387                     typeName);
388         }
389         return typeQName;
390     }
391
392     @Override
393     public void exitType_stmt(YangParser.Type_stmtContext ctx) {
394         final String actContainer = actualPath.pop();
395         logger.debug("exiting " + actContainer);
396
397         final String typeName = stringFromNode(ctx);
398         if ("union".equals(typeName)) {
399             moduleBuilder.exitNode();
400         }
401     }
402
403     @Override
404     public void enterGrouping_stmt(YangParser.Grouping_stmtContext ctx) {
405         final String groupName = stringFromNode(ctx);
406         QName groupQName = new QName(namespace, revision, yangModelPrefix,
407                 groupName);
408         GroupingBuilder builder = moduleBuilder.addGrouping(groupQName,
409                 actualPath, ctx.getStart().getLine());
410         moduleBuilder.enterNode(builder);
411         updatePath("grouping");
412         updatePath(groupName);
413         parseSchemaNodeArgs(ctx, builder);
414     }
415
416     @Override
417     public void exitGrouping_stmt(YangParser.Grouping_stmtContext ctx) {
418         String actContainer = actualPath.pop();
419         actContainer += "-" + actualPath.pop();
420         logger.debug("exiting " + actContainer);
421         moduleBuilder.exitNode();
422     }
423
424     @Override
425     public void enterContainer_stmt(Container_stmtContext ctx) {
426         final String containerName = stringFromNode(ctx);
427         QName containerQName = new QName(namespace, revision, yangModelPrefix,
428                 containerName);
429         ContainerSchemaNodeBuilder builder = moduleBuilder.addContainerNode(
430                 containerQName, actualPath, ctx.getStart().getLine());
431         moduleBuilder.enterNode(builder);
432         updatePath(containerName);
433
434         builder.setPath(createActualSchemaPath(actualPath, namespace, revision,
435                 yangModelPrefix));
436         parseSchemaNodeArgs(ctx, builder);
437         parseConstraints(ctx, builder.getConstraints());
438
439         for (int i = 0; i < ctx.getChildCount(); ++i) {
440             final ParseTree childNode = ctx.getChild(i);
441             if (childNode instanceof Presence_stmtContext) {
442                 builder.setPresence(true);
443                 break;
444             }
445         }
446     }
447
448     @Override
449     public void exitContainer_stmt(Container_stmtContext ctx) {
450         final String actContainer = actualPath.pop();
451         logger.debug("exiting " + actContainer);
452         moduleBuilder.exitNode();
453     }
454
455     @Override
456     public void enterLeaf_stmt(Leaf_stmtContext ctx) {
457         final String leafName = stringFromNode(ctx);
458         QName leafQName = new QName(namespace, revision, yangModelPrefix,
459                 leafName);
460         LeafSchemaNodeBuilder builder = moduleBuilder.addLeafNode(leafQName,
461                 actualPath, ctx.getStart().getLine());
462         moduleBuilder.enterNode(builder);
463         updatePath(leafName);
464
465         builder.setPath(createActualSchemaPath(actualPath, namespace, revision,
466                 yangModelPrefix));
467         parseSchemaNodeArgs(ctx, builder);
468         parseConstraints(ctx, builder.getConstraints());
469
470         String defaultStr = null;
471         String unitsStr = null;
472         for (int i = 0; i < ctx.getChildCount(); i++) {
473             ParseTree child = ctx.getChild(i);
474             if (child instanceof Default_stmtContext) {
475                 defaultStr = stringFromNode(child);
476             } else if (child instanceof Units_stmtContext) {
477                 unitsStr = stringFromNode(child);
478             }
479         }
480         builder.setDefaultStr(defaultStr);
481         builder.setUnits(unitsStr);
482     }
483
484     @Override
485     public void exitLeaf_stmt(YangParser.Leaf_stmtContext ctx) {
486         final String actLeaf = actualPath.pop();
487         logger.debug("exiting " + actLeaf);
488         moduleBuilder.exitNode();
489     }
490
491     @Override
492     public void enterUses_stmt(YangParser.Uses_stmtContext ctx) {
493         final String groupingPathStr = stringFromNode(ctx);
494         UsesNodeBuilder builder = moduleBuilder.addUsesNode(groupingPathStr,
495                 actualPath, ctx.getStart().getLine());
496         moduleBuilder.enterNode(builder);
497         updatePath(groupingPathStr);
498     }
499
500     @Override
501     public void exitUses_stmt(YangParser.Uses_stmtContext ctx) {
502         final String actContainer = actualPath.pop();
503         logger.debug("exiting " + actContainer);
504         moduleBuilder.exitNode();
505     }
506
507     @Override
508     public void enterRefine_stmt(YangParser.Refine_stmtContext ctx) {
509         String refineString = stringFromNode(ctx);
510         RefineHolder refine = parseRefine(ctx);
511         moduleBuilder.addRefine(refine, actualPath);
512         moduleBuilder.enterNode(refine);
513         updatePath(refineString);
514     }
515
516     @Override
517     public void exitRefine_stmt(YangParser.Refine_stmtContext ctx) {
518         final String actContainer = actualPath.pop();
519         logger.debug("exiting " + actContainer);
520         moduleBuilder.exitNode();
521     }
522
523     @Override
524     public void enterLeaf_list_stmt(Leaf_list_stmtContext ctx) {
525         final String leafListName = stringFromNode(ctx);
526         QName leafListQName = new QName(namespace, revision, yangModelPrefix,
527                 leafListName);
528         LeafListSchemaNodeBuilder builder = moduleBuilder.addLeafListNode(
529                 leafListQName, actualPath, ctx.getStart().getLine());
530         moduleBuilder.enterNode(builder);
531         updatePath(leafListName);
532
533         builder.setPath(createActualSchemaPath(actualPath, namespace, revision,
534                 yangModelPrefix));
535         parseSchemaNodeArgs(ctx, builder);
536         parseConstraints(ctx, builder.getConstraints());
537
538         for (int i = 0; i < ctx.getChildCount(); ++i) {
539             final ParseTree childNode = ctx.getChild(i);
540             if (childNode instanceof Ordered_by_stmtContext) {
541                 final Ordered_by_stmtContext orderedBy = (Ordered_by_stmtContext) childNode;
542                 final boolean userOrdered = parseUserOrdered(orderedBy);
543                 builder.setUserOrdered(userOrdered);
544                 break;
545             }
546         }
547     }
548
549     @Override
550     public void exitLeaf_list_stmt(YangParser.Leaf_list_stmtContext ctx) {
551         final String actContainer = actualPath.pop();
552         logger.debug("exiting " + actContainer);
553         moduleBuilder.exitNode();
554     }
555
556     @Override
557     public void enterList_stmt(List_stmtContext ctx) {
558         final String containerName = stringFromNode(ctx);
559         QName containerQName = new QName(namespace, revision, yangModelPrefix,
560                 containerName);
561         ListSchemaNodeBuilder builder = moduleBuilder.addListNode(
562                 containerQName, actualPath, ctx.getStart().getLine());
563         moduleBuilder.enterNode(builder);
564         updatePath(containerName);
565
566         builder.setPath(createActualSchemaPath(actualPath, namespace, revision,
567                 yangModelPrefix));
568         parseSchemaNodeArgs(ctx, builder);
569         parseConstraints(ctx, builder.getConstraints());
570
571         String keyDefinition = "";
572         for (int i = 0; i < ctx.getChildCount(); ++i) {
573             ParseTree childNode = ctx.getChild(i);
574             if (childNode instanceof Ordered_by_stmtContext) {
575                 final Ordered_by_stmtContext orderedBy = (Ordered_by_stmtContext) childNode;
576                 final boolean userOrdered = parseUserOrdered(orderedBy);
577                 builder.setUserOrdered(userOrdered);
578             } else if (childNode instanceof Key_stmtContext) {
579                 keyDefinition = stringFromNode(childNode);
580                 List<QName> key = createListKey(keyDefinition, namespace,
581                         revision, yangModelPrefix);
582                 builder.setKeyDefinition(key);
583             }
584         }
585     }
586
587     @Override
588     public void exitList_stmt(List_stmtContext ctx) {
589         final String actContainer = actualPath.pop();
590         logger.debug("exiting " + actContainer);
591         moduleBuilder.exitNode();
592     }
593
594     @Override
595     public void enterAnyxml_stmt(YangParser.Anyxml_stmtContext ctx) {
596         final String anyXmlName = stringFromNode(ctx);
597         QName anyXmlQName = new QName(namespace, revision, yangModelPrefix,
598                 anyXmlName);
599         AnyXmlBuilder builder = moduleBuilder.addAnyXml(anyXmlQName,
600                 actualPath, ctx.getStart().getLine());
601         moduleBuilder.enterNode(builder);
602         updatePath(anyXmlName);
603
604         builder.setPath(createActualSchemaPath(actualPath, namespace, revision,
605                 yangModelPrefix));
606         parseSchemaNodeArgs(ctx, builder);
607         parseConstraints(ctx, builder.getConstraints());
608     }
609
610     @Override
611     public void exitAnyxml_stmt(YangParser.Anyxml_stmtContext ctx) {
612         final String actContainer = actualPath.pop();
613         logger.debug("exiting " + actContainer);
614         moduleBuilder.exitNode();
615     }
616
617     @Override
618     public void enterChoice_stmt(YangParser.Choice_stmtContext ctx) {
619         final String choiceName = stringFromNode(ctx);
620         QName choiceQName = new QName(namespace, revision, yangModelPrefix,
621                 choiceName);
622         ChoiceBuilder builder = moduleBuilder.addChoice(choiceQName,
623                 actualPath, ctx.getStart().getLine());
624         moduleBuilder.enterNode(builder);
625
626         updatePath(choiceName);
627         builder.setPath(createActualSchemaPath(actualPath, namespace, revision,
628                 yangModelPrefix));
629         parseSchemaNodeArgs(ctx, builder);
630         parseConstraints(ctx, builder.getConstraints());
631
632         // set 'default' case
633         for (int i = 0; i < ctx.getChildCount(); i++) {
634             ParseTree child = ctx.getChild(i);
635             if (child instanceof Default_stmtContext) {
636                 String defaultCase = stringFromNode(child);
637                 builder.setDefaultCase(defaultCase);
638                 break;
639             }
640         }
641     }
642
643     @Override
644     public void exitChoice_stmt(YangParser.Choice_stmtContext ctx) {
645         final String actContainer = actualPath.pop();
646         logger.debug("exiting " + actContainer);
647         moduleBuilder.exitNode();
648     }
649
650     @Override
651     public void enterCase_stmt(YangParser.Case_stmtContext ctx) {
652         final String caseName = stringFromNode(ctx);
653         QName choiceQName = new QName(namespace, revision, yangModelPrefix,
654                 caseName);
655         ChoiceCaseBuilder builder = moduleBuilder.addCase(choiceQName,
656                 actualPath, ctx.getStart().getLine());
657         moduleBuilder.enterNode(builder);
658
659         updatePath(caseName);
660         builder.setPath(createActualSchemaPath(actualPath, namespace, revision,
661                 yangModelPrefix));
662         parseSchemaNodeArgs(ctx, builder);
663         parseConstraints(ctx, builder.getConstraints());
664     }
665
666     @Override
667     public void exitCase_stmt(YangParser.Case_stmtContext ctx) {
668         final String actContainer = actualPath.pop();
669         logger.debug("exiting " + actContainer);
670         moduleBuilder.exitNode();
671     }
672
673     @Override
674     public void enterNotification_stmt(YangParser.Notification_stmtContext ctx) {
675         final String notificationName = stringFromNode(ctx);
676         QName notificationQName = new QName(namespace, revision,
677                 yangModelPrefix, notificationName);
678         NotificationBuilder builder = moduleBuilder.addNotification(
679                 notificationQName, actualPath, ctx.getStart().getLine());
680         moduleBuilder.enterNode(builder);
681         updatePath(notificationName);
682
683         builder.setPath(createActualSchemaPath(actualPath, namespace, revision,
684                 yangModelPrefix));
685         parseSchemaNodeArgs(ctx, builder);
686     }
687
688     @Override
689     public void exitNotification_stmt(YangParser.Notification_stmtContext ctx) {
690         final String actContainer = actualPath.pop();
691         logger.debug("exiting " + actContainer);
692         moduleBuilder.exitNode();
693     }
694
695     // Unknown types
696     @Override
697     public void enterIdentifier_stmt(YangParser.Identifier_stmtContext ctx) {
698         final String nodeParameter = stringFromNode(ctx);
699         QName nodeType = null;
700
701         final String nodeTypeStr = ctx.getChild(0).getText();
702         final String[] splittedElement = nodeTypeStr.split(":");
703         if (splittedElement.length == 1) {
704             nodeType = new QName(null, null, yangModelPrefix,
705                     splittedElement[0]);
706         } else {
707             nodeType = new QName(null, null, splittedElement[0],
708                     splittedElement[1]);
709         }
710
711         QName qname;
712         if (nodeParameter != null) {
713             String[] splittedName = nodeParameter.split(":");
714             if (splittedName.length == 2) {
715                 qname = new QName(null, null, splittedName[0], splittedName[1]);
716             } else {
717                 qname = new QName(namespace, revision, yangModelPrefix,
718                         splittedName[0]);
719             }
720         } else {
721             qname = new QName(namespace, revision, yangModelPrefix,
722                     nodeParameter);
723         }
724
725         UnknownSchemaNodeBuilder builder = moduleBuilder.addUnknownSchemaNode(
726                 qname, actualPath, ctx.getStart().getLine());
727         builder.setNodeType(nodeType);
728         builder.setNodeParameter(nodeParameter);
729         updatePath(nodeParameter);
730         builder.setPath(createActualSchemaPath(actualPath, namespace, revision,
731                 yangModelPrefix));
732         parseSchemaNodeArgs(ctx, builder);
733         moduleBuilder.enterNode(builder);
734     }
735
736     @Override
737     public void exitIdentifier_stmt(YangParser.Identifier_stmtContext ctx) {
738         final String actContainer = actualPath.pop();
739         logger.debug("exiting " + actContainer);
740         moduleBuilder.exitNode();
741     }
742
743     @Override
744     public void enterRpc_stmt(YangParser.Rpc_stmtContext ctx) {
745         final String rpcName = stringFromNode(ctx);
746         QName rpcQName = new QName(namespace, revision, yangModelPrefix,
747                 rpcName);
748         RpcDefinitionBuilder rpcBuilder = moduleBuilder.addRpc(rpcQName,
749                 actualPath, ctx.getStart().getLine());
750         moduleBuilder.enterNode(rpcBuilder);
751         updatePath(rpcName);
752
753         rpcBuilder.setPath(createActualSchemaPath(actualPath, namespace,
754                 revision, yangModelPrefix));
755         parseSchemaNodeArgs(ctx, rpcBuilder);
756     }
757
758     @Override
759     public void exitRpc_stmt(YangParser.Rpc_stmtContext ctx) {
760         final String actContainer = actualPath.pop();
761         logger.debug("exiting " + actContainer);
762         moduleBuilder.exitNode();
763     }
764
765     @Override
766     public void enterInput_stmt(YangParser.Input_stmtContext ctx) {
767         final String input = "input";
768         QName rpcQName = new QName(namespace, revision, yangModelPrefix, input);
769         ContainerSchemaNodeBuilder builder = moduleBuilder.addRpcInput(
770                 rpcQName, ctx.getStart().getLine());
771         moduleBuilder.enterNode(builder);
772         updatePath(input);
773
774         builder.setPath(createActualSchemaPath(actualPath, namespace, revision,
775                 yangModelPrefix));
776         parseSchemaNodeArgs(ctx, builder);
777         parseConstraints(ctx, builder.getConstraints());
778     }
779
780     @Override
781     public void exitInput_stmt(YangParser.Input_stmtContext ctx) {
782         final String actContainer = actualPath.pop();
783         logger.debug("exiting " + actContainer);
784         moduleBuilder.exitNode();
785     }
786
787     @Override
788     public void enterOutput_stmt(YangParser.Output_stmtContext ctx) {
789         final String output = "output";
790         QName rpcQName = new QName(namespace, revision, yangModelPrefix, output);
791         ContainerSchemaNodeBuilder builder = moduleBuilder.addRpcOutput(
792                 rpcQName, ctx.getStart().getLine());
793         moduleBuilder.enterNode(builder);
794         updatePath(output);
795
796         builder.setPath(createActualSchemaPath(actualPath, namespace, revision,
797                 yangModelPrefix));
798         parseSchemaNodeArgs(ctx, builder);
799         parseConstraints(ctx, builder.getConstraints());
800     }
801
802     @Override
803     public void exitOutput_stmt(YangParser.Output_stmtContext ctx) {
804         final String actContainer = actualPath.pop();
805         logger.debug("exiting " + actContainer);
806         moduleBuilder.exitNode();
807     }
808
809     @Override
810     public void enterFeature_stmt(YangParser.Feature_stmtContext ctx) {
811         final String featureName = stringFromNode(ctx);
812         QName featureQName = new QName(namespace, revision, yangModelPrefix,
813                 featureName);
814         FeatureBuilder featureBuilder = moduleBuilder.addFeature(featureQName,
815                 actualPath, ctx.getStart().getLine());
816         moduleBuilder.enterNode(featureBuilder);
817         updatePath(featureName);
818
819         featureBuilder.setPath(createActualSchemaPath(actualPath, namespace,
820                 revision, yangModelPrefix));
821         parseSchemaNodeArgs(ctx, featureBuilder);
822     }
823
824     @Override
825     public void exitFeature_stmt(YangParser.Feature_stmtContext ctx) {
826         final String actContainer = actualPath.pop();
827         logger.debug("exiting " + actContainer);
828         moduleBuilder.exitNode();
829     }
830
831     @Override
832     public void enterDeviation_stmt(YangParser.Deviation_stmtContext ctx) {
833         final String targetPath = stringFromNode(ctx);
834         String reference = null;
835         String deviate = null;
836         DeviationBuilder builder = moduleBuilder.addDeviation(targetPath,
837                 actualPath, ctx.getStart().getLine());
838         moduleBuilder.enterNode(builder);
839         updatePath(targetPath);
840
841         for (int i = 0; i < ctx.getChildCount(); i++) {
842             ParseTree child = ctx.getChild(i);
843             if (child instanceof Reference_stmtContext) {
844                 reference = stringFromNode(child);
845             } else if (child instanceof Deviate_not_supported_stmtContext) {
846                 deviate = stringFromNode(child);
847             } else if (child instanceof Deviate_add_stmtContext) {
848                 deviate = stringFromNode(child);
849             } else if (child instanceof Deviate_replace_stmtContext) {
850                 deviate = stringFromNode(child);
851             } else if (child instanceof Deviate_delete_stmtContext) {
852                 deviate = stringFromNode(child);
853             }
854         }
855         builder.setReference(reference);
856         builder.setDeviate(deviate);
857     }
858
859     @Override
860     public void exitDeviation_stmt(YangParser.Deviation_stmtContext ctx) {
861         final String actContainer = actualPath.pop();
862         logger.debug("exiting " + actContainer);
863         moduleBuilder.exitNode();
864     }
865
866     @Override
867     public void enterConfig_stmt(YangParser.Config_stmtContext ctx) {
868         boolean configuration = parseConfig(ctx);
869         moduleBuilder.addConfiguration(configuration, actualPath, ctx
870                 .getStart().getLine());
871     }
872
873     @Override
874     public void enterIdentity_stmt(YangParser.Identity_stmtContext ctx) {
875         final String identityName = stringFromNode(ctx);
876         final QName identityQName = new QName(namespace, revision,
877                 yangModelPrefix, identityName);
878         IdentitySchemaNodeBuilder builder = moduleBuilder.addIdentity(
879                 identityQName, actualPath, ctx.getStart().getLine());
880         moduleBuilder.enterNode(builder);
881         updatePath(identityName);
882
883         builder.setPath(createActualSchemaPath(actualPath, namespace, revision,
884                 yangModelPrefix));
885         parseSchemaNodeArgs(ctx, builder);
886
887         for (int i = 0; i < ctx.getChildCount(); i++) {
888             ParseTree child = ctx.getChild(i);
889             if (child instanceof Base_stmtContext) {
890                 String baseIdentityName = stringFromNode(child);
891                 builder.setBaseIdentityName(baseIdentityName);
892             }
893         }
894     }
895
896     @Override
897     public void exitIdentity_stmt(YangParser.Identity_stmtContext ctx) {
898         final String actContainer = actualPath.pop();
899         logger.debug("exiting " + actContainer);
900         moduleBuilder.exitNode();
901     }
902
903     public ModuleBuilder getModuleBuilder() {
904         return moduleBuilder;
905     }
906
907     private void updatePath(String containerName) {
908         actualPath.push(containerName);
909     }
910
911 }