Merge "BUG-864: decrease log level when sorting and parsing modules"
[yangtools.git] / yang / yang-parser-impl / src / main / java / org / opendaylight / yangtools / 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.yangtools.yang.parser.impl;
9
10 import static org.opendaylight.yangtools.yang.parser.util.ParserListenerUtils.checkMissingBody;
11 import static org.opendaylight.yangtools.yang.parser.util.ParserListenerUtils.createActualSchemaPath;
12 import static org.opendaylight.yangtools.yang.parser.util.ParserListenerUtils.createListKey;
13 import static org.opendaylight.yangtools.yang.parser.util.ParserListenerUtils.getConfig;
14 import static org.opendaylight.yangtools.yang.parser.util.ParserListenerUtils.getIdentityrefBase;
15 import static org.opendaylight.yangtools.yang.parser.util.ParserListenerUtils.parseConstraints;
16 import static org.opendaylight.yangtools.yang.parser.util.ParserListenerUtils.parseDefault;
17 import static org.opendaylight.yangtools.yang.parser.util.ParserListenerUtils.parseRefine;
18 import static org.opendaylight.yangtools.yang.parser.util.ParserListenerUtils.parseSchemaNodeArgs;
19 import static org.opendaylight.yangtools.yang.parser.util.ParserListenerUtils.parseStatus;
20 import static org.opendaylight.yangtools.yang.parser.util.ParserListenerUtils.parseTypeWithBody;
21 import static org.opendaylight.yangtools.yang.parser.util.ParserListenerUtils.parseUnits;
22 import static org.opendaylight.yangtools.yang.parser.util.ParserListenerUtils.parseUnknownTypeWithBody;
23 import static org.opendaylight.yangtools.yang.parser.util.ParserListenerUtils.parseUserOrdered;
24 import static org.opendaylight.yangtools.yang.parser.util.ParserListenerUtils.parseYinValue;
25 import static org.opendaylight.yangtools.yang.parser.util.ParserListenerUtils.stringFromNode;
26
27 import com.google.common.base.Strings;
28 import java.net.URI;
29 import java.text.DateFormat;
30 import java.text.ParseException;
31 import java.text.SimpleDateFormat;
32 import java.util.Date;
33 import java.util.List;
34 import java.util.Stack;
35 import org.antlr.v4.runtime.tree.ParseTree;
36 import org.opendaylight.yangtools.antlrv4.code.gen.YangParser;
37 import org.opendaylight.yangtools.antlrv4.code.gen.YangParser.Argument_stmtContext;
38 import org.opendaylight.yangtools.antlrv4.code.gen.YangParser.Base_stmtContext;
39 import org.opendaylight.yangtools.antlrv4.code.gen.YangParser.Contact_stmtContext;
40 import org.opendaylight.yangtools.antlrv4.code.gen.YangParser.Container_stmtContext;
41 import org.opendaylight.yangtools.antlrv4.code.gen.YangParser.Default_stmtContext;
42 import org.opendaylight.yangtools.antlrv4.code.gen.YangParser.Description_stmtContext;
43 import org.opendaylight.yangtools.antlrv4.code.gen.YangParser.Deviate_add_stmtContext;
44 import org.opendaylight.yangtools.antlrv4.code.gen.YangParser.Deviate_delete_stmtContext;
45 import org.opendaylight.yangtools.antlrv4.code.gen.YangParser.Deviate_not_supported_stmtContext;
46 import org.opendaylight.yangtools.antlrv4.code.gen.YangParser.Deviate_replace_stmtContext;
47 import org.opendaylight.yangtools.antlrv4.code.gen.YangParser.Import_stmtContext;
48 import org.opendaylight.yangtools.antlrv4.code.gen.YangParser.Key_stmtContext;
49 import org.opendaylight.yangtools.antlrv4.code.gen.YangParser.Leaf_list_stmtContext;
50 import org.opendaylight.yangtools.antlrv4.code.gen.YangParser.Leaf_stmtContext;
51 import org.opendaylight.yangtools.antlrv4.code.gen.YangParser.List_stmtContext;
52 import org.opendaylight.yangtools.antlrv4.code.gen.YangParser.Module_header_stmtsContext;
53 import org.opendaylight.yangtools.antlrv4.code.gen.YangParser.Namespace_stmtContext;
54 import org.opendaylight.yangtools.antlrv4.code.gen.YangParser.Ordered_by_stmtContext;
55 import org.opendaylight.yangtools.antlrv4.code.gen.YangParser.Organization_stmtContext;
56 import org.opendaylight.yangtools.antlrv4.code.gen.YangParser.Prefix_stmtContext;
57 import org.opendaylight.yangtools.antlrv4.code.gen.YangParser.Presence_stmtContext;
58 import org.opendaylight.yangtools.antlrv4.code.gen.YangParser.Reference_stmtContext;
59 import org.opendaylight.yangtools.antlrv4.code.gen.YangParser.Revision_date_stmtContext;
60 import org.opendaylight.yangtools.antlrv4.code.gen.YangParser.Revision_stmtContext;
61 import org.opendaylight.yangtools.antlrv4.code.gen.YangParser.Revision_stmtsContext;
62 import org.opendaylight.yangtools.antlrv4.code.gen.YangParser.Status_stmtContext;
63 import org.opendaylight.yangtools.antlrv4.code.gen.YangParser.Type_body_stmtsContext;
64 import org.opendaylight.yangtools.antlrv4.code.gen.YangParser.Units_stmtContext;
65 import org.opendaylight.yangtools.antlrv4.code.gen.YangParser.When_stmtContext;
66 import org.opendaylight.yangtools.antlrv4.code.gen.YangParser.Yang_version_stmtContext;
67 import org.opendaylight.yangtools.antlrv4.code.gen.YangParserBaseListener;
68 import org.opendaylight.yangtools.yang.common.QName;
69 import org.opendaylight.yangtools.yang.model.api.SchemaPath;
70 import org.opendaylight.yangtools.yang.model.api.TypeDefinition;
71 import org.opendaylight.yangtools.yang.model.util.BaseTypes;
72 import org.opendaylight.yangtools.yang.model.util.YangTypesConverter;
73 import org.opendaylight.yangtools.yang.parser.builder.api.AugmentationSchemaBuilder;
74 import org.opendaylight.yangtools.yang.parser.builder.api.Builder;
75 import org.opendaylight.yangtools.yang.parser.builder.api.GroupingBuilder;
76 import org.opendaylight.yangtools.yang.parser.builder.api.TypeDefinitionBuilder;
77 import org.opendaylight.yangtools.yang.parser.builder.api.UsesNodeBuilder;
78 import org.opendaylight.yangtools.yang.parser.builder.impl.AnyXmlBuilder;
79 import org.opendaylight.yangtools.yang.parser.builder.impl.ChoiceBuilder;
80 import org.opendaylight.yangtools.yang.parser.builder.impl.ChoiceCaseBuilder;
81 import org.opendaylight.yangtools.yang.parser.builder.impl.ContainerSchemaNodeBuilder;
82 import org.opendaylight.yangtools.yang.parser.builder.impl.DeviationBuilder;
83 import org.opendaylight.yangtools.yang.parser.builder.impl.ExtensionBuilder;
84 import org.opendaylight.yangtools.yang.parser.builder.impl.FeatureBuilder;
85 import org.opendaylight.yangtools.yang.parser.builder.impl.IdentitySchemaNodeBuilder;
86 import org.opendaylight.yangtools.yang.parser.builder.impl.LeafListSchemaNodeBuilder;
87 import org.opendaylight.yangtools.yang.parser.builder.impl.LeafSchemaNodeBuilder;
88 import org.opendaylight.yangtools.yang.parser.builder.impl.ListSchemaNodeBuilder;
89 import org.opendaylight.yangtools.yang.parser.builder.impl.ModuleBuilder;
90 import org.opendaylight.yangtools.yang.parser.builder.impl.NotificationBuilder;
91 import org.opendaylight.yangtools.yang.parser.builder.impl.RpcDefinitionBuilder;
92 import org.opendaylight.yangtools.yang.parser.builder.impl.UnionTypeBuilder;
93 import org.opendaylight.yangtools.yang.parser.builder.impl.UnknownSchemaNodeBuilder;
94 import org.opendaylight.yangtools.yang.parser.util.RefineHolder;
95 import org.slf4j.Logger;
96 import org.slf4j.LoggerFactory;
97
98 public final class YangParserListenerImpl extends YangParserBaseListener {
99     private static final Logger LOGGER = LoggerFactory.getLogger(YangParserListenerImpl.class);
100     private static final String AUGMENT_STR = "augment";
101
102     private final String sourcePath;
103     private ModuleBuilder moduleBuilder;
104     private String moduleName;
105     private URI namespace;
106     private String yangModelPrefix;
107     private Date revision = new Date(0L);
108
109     private final DateFormat SIMPLE_DATE_FORMAT = new SimpleDateFormat("yyyy-MM-dd");
110     private final Stack<Stack<QName>> actualPath = new Stack<>();
111
112     private void addNodeToPath(QName name) {
113         actualPath.peek().push(name);
114     }
115
116     private QName removeNodeFromPath() {
117         return actualPath.peek().pop();
118     }
119
120     public YangParserListenerImpl(String sourcePath) {
121         this.sourcePath = sourcePath;
122     }
123
124     @Override
125     public void enterModule_stmt(YangParser.Module_stmtContext ctx) {
126         moduleName = stringFromNode(ctx);
127         LOGGER.trace("entering module " + moduleName);
128         enterLog("module", moduleName, 0);
129         actualPath.push(new Stack<QName>());
130
131         moduleBuilder = new ModuleBuilder(moduleName, sourcePath);
132
133         String description = null;
134         String reference = null;
135         for (int i = 0; i < ctx.getChildCount(); i++) {
136             ParseTree child = ctx.getChild(i);
137             if (child instanceof Description_stmtContext) {
138                 description = stringFromNode(child);
139             } else if (child instanceof Reference_stmtContext) {
140                 reference = stringFromNode(child);
141             } else {
142                 if (description != null && reference != null) {
143                     break;
144                 }
145             }
146         }
147         moduleBuilder.setDescription(description);
148         moduleBuilder.setReference(reference);
149     }
150
151     @Override
152     public void exitModule_stmt(YangParser.Module_stmtContext ctx) {
153         exitLog("module", "");
154         actualPath.pop();
155     }
156
157     @Override public void enterSubmodule_stmt(YangParser.Submodule_stmtContext ctx) {
158         moduleName = stringFromNode(ctx);
159         LOGGER.trace("entering submodule " + moduleName);
160         enterLog("submodule", moduleName, 0);
161         actualPath.push(new Stack<QName>());
162
163         moduleBuilder = new ModuleBuilder(moduleName, true, sourcePath);
164
165         String description = null;
166         String reference = null;
167         for (int i = 0; i < ctx.getChildCount(); i++) {
168             ParseTree child = ctx.getChild(i);
169             if (child instanceof Description_stmtContext) {
170                 description = stringFromNode(child);
171             } else if (child instanceof Reference_stmtContext) {
172                 reference = stringFromNode(child);
173             } else {
174                 if (description != null && reference != null) {
175                     break;
176                 }
177             }
178         }
179         moduleBuilder.setDescription(description);
180         moduleBuilder.setReference(reference);
181     }
182
183     @Override public void exitSubmodule_stmt(YangParser.Submodule_stmtContext ctx) {
184         exitLog("submodule", "");
185         actualPath.pop();
186     }
187
188     @Override public void enterBelongs_to_stmt(YangParser.Belongs_to_stmtContext ctx) {
189         moduleBuilder.setBelongsTo(stringFromNode(ctx));
190     }
191
192     @Override
193     public void enterModule_header_stmts(Module_header_stmtsContext ctx) {
194         enterLog("module_header", "", ctx.getStart().getLine());
195         String yangVersion = null;
196         for (int i = 0; i < ctx.getChildCount(); ++i) {
197             final ParseTree treeNode = ctx.getChild(i);
198             if (treeNode instanceof Namespace_stmtContext) {
199                 final String namespaceStr = stringFromNode(treeNode);
200                 namespace = URI.create(namespaceStr);
201                 moduleBuilder.setNamespace(namespace);
202                 setLog("namespace", namespaceStr);
203             } else if (treeNode instanceof Prefix_stmtContext) {
204                 yangModelPrefix = stringFromNode(treeNode);
205                 moduleBuilder.setPrefix(yangModelPrefix);
206                 setLog("prefix", yangModelPrefix);
207             } else if (treeNode instanceof Yang_version_stmtContext) {
208                 yangVersion = stringFromNode(treeNode);
209                 setLog("yang-version", yangVersion);
210             }
211         }
212
213         if (yangVersion == null) {
214             yangVersion = "1";
215         }
216         moduleBuilder.setYangVersion(yangVersion);
217     }
218
219     @Override
220     public void exitModule_header_stmts(Module_header_stmtsContext ctx) {
221         exitLog("module_header", "");
222     }
223
224     @Override
225     public void enterMeta_stmts(YangParser.Meta_stmtsContext ctx) {
226         enterLog("meta_stmt", "", ctx.getStart().getLine());
227         for (int i = 0; i < ctx.getChildCount(); i++) {
228             ParseTree child = ctx.getChild(i);
229             if (child instanceof Organization_stmtContext) {
230                 final String organization = stringFromNode(child);
231                 moduleBuilder.setOrganization(organization);
232                 setLog("organization", organization);
233             } else if (child instanceof Contact_stmtContext) {
234                 final String contact = stringFromNode(child);
235                 moduleBuilder.setContact(contact);
236                 setLog("contact", contact);
237             } else if (child instanceof Description_stmtContext) {
238                 final String description = stringFromNode(child);
239                 moduleBuilder.setDescription(description);
240                 setLog("description", description);
241             } else if (child instanceof Reference_stmtContext) {
242                 final String reference = stringFromNode(child);
243                 moduleBuilder.setReference(reference);
244                 setLog("reference", reference);
245             }
246         }
247     }
248
249     @Override
250     public void exitMeta_stmts(YangParser.Meta_stmtsContext ctx) {
251         exitLog("meta_stmt", "");
252     }
253
254     @Override
255     public void enterRevision_stmts(Revision_stmtsContext ctx) {
256         enterLog("revisions", "", ctx.getStart().getLine());
257         for (int i = 0; i < ctx.getChildCount(); ++i) {
258             final ParseTree treeNode = ctx.getChild(i);
259             if (treeNode instanceof Revision_stmtContext) {
260                 updateRevisionForRevisionStatement(treeNode);
261             }
262         }
263     }
264
265     @Override
266     public void exitRevision_stmts(Revision_stmtsContext ctx) {
267         exitLog("revisions", "");
268     }
269
270     private void updateRevisionForRevisionStatement(final ParseTree treeNode) {
271         final String revisionDateStr = stringFromNode(treeNode);
272         try {
273             final Date revisionDate = SIMPLE_DATE_FORMAT.parse(revisionDateStr);
274             if ((revisionDate != null) && (this.revision.compareTo(revisionDate) < 0)) {
275                 this.revision = revisionDate;
276                 moduleBuilder.setRevision(this.revision);
277                 setLog("revision", this.revision.toString());
278                 for (int i = 0; i < treeNode.getChildCount(); ++i) {
279                     ParseTree child = treeNode.getChild(i);
280                     if (child instanceof Reference_stmtContext) {
281                         moduleBuilder.setReference(stringFromNode(child));
282                     }
283                 }
284             }
285         } catch (ParseException e) {
286             final String message = "Failed to parse revision string: " + revisionDateStr;
287             LOGGER.warn(message);
288         }
289     }
290
291     @Override
292     public void enterImport_stmt(Import_stmtContext ctx) {
293         final int line = ctx.getStart().getLine();
294         final String importName = stringFromNode(ctx);
295         enterLog("import", importName, line);
296
297         String importPrefix = null;
298         Date importRevision = null;
299
300         for (int i = 0; i < ctx.getChildCount(); ++i) {
301             final ParseTree treeNode = ctx.getChild(i);
302             if (treeNode instanceof Prefix_stmtContext) {
303                 importPrefix = stringFromNode(treeNode);
304             }
305             if (treeNode instanceof Revision_date_stmtContext) {
306                 String importRevisionStr = stringFromNode(treeNode);
307                 try {
308                     importRevision = SIMPLE_DATE_FORMAT.parse(importRevisionStr);
309                 } catch (ParseException e) {
310                     LOGGER.warn("Failed to parse import revision-date at line " + line + ": " + importRevisionStr);
311                 }
312             }
313         }
314         moduleBuilder.addModuleImport(importName, importRevision, importPrefix);
315         setLog("import", "(" + importName + "; " + importRevision + "; " + importPrefix + ")");
316     }
317
318     @Override
319     public void exitImport_stmt(Import_stmtContext ctx) {
320         exitLog("import", "");
321     }
322
323     @Override
324     public void enterAugment_stmt(YangParser.Augment_stmtContext ctx) {
325         final int line = ctx.getStart().getLine();
326         final String augmentPath = stringFromNode(ctx);
327         enterLog(AUGMENT_STR, augmentPath, line);
328         actualPath.push(new Stack<QName>());
329
330         AugmentationSchemaBuilder builder = moduleBuilder.addAugment(line, augmentPath);
331
332         for (int i = 0; i < ctx.getChildCount(); i++) {
333             ParseTree child = ctx.getChild(i);
334             if (child instanceof Description_stmtContext) {
335                 builder.setDescription(stringFromNode(child));
336             } else if (child instanceof Reference_stmtContext) {
337                 builder.setReference(stringFromNode(child));
338             } else if (child instanceof Status_stmtContext) {
339                 builder.setStatus(parseStatus((Status_stmtContext) child));
340             } else if (child instanceof When_stmtContext) {
341                 builder.addWhenCondition(stringFromNode(child));
342             }
343         }
344
345         moduleBuilder.enterNode(builder);
346     }
347
348     @Override
349     public void exitAugment_stmt(YangParser.Augment_stmtContext ctx) {
350         moduleBuilder.exitNode();
351         exitLog(AUGMENT_STR, "");
352         actualPath.pop();
353     }
354
355     @Override
356     public void enterExtension_stmt(YangParser.Extension_stmtContext ctx) {
357         final int line = ctx.getStart().getLine();
358         final String extName = stringFromNode(ctx);
359         enterLog("extension", extName, line);
360         QName qname = new QName(namespace, revision, yangModelPrefix, extName);
361         addNodeToPath(qname);
362         SchemaPath path = createActualSchemaPath(actualPath.peek());
363
364         ExtensionBuilder builder = moduleBuilder.addExtension(qname, line, path);
365         parseSchemaNodeArgs(ctx, builder);
366
367         String argument = null;
368         boolean yin = false;
369         for (int i = 0; i < ctx.getChildCount(); i++) {
370             ParseTree child = ctx.getChild(i);
371             if (child instanceof Argument_stmtContext) {
372                 argument = stringFromNode(child);
373                 yin = parseYinValue((Argument_stmtContext) child);
374                 break;
375             }
376         }
377         builder.setArgument(argument);
378         builder.setYinElement(yin);
379
380         moduleBuilder.enterNode(builder);
381     }
382
383     @Override
384     public void exitExtension_stmt(YangParser.Extension_stmtContext ctx) {
385         moduleBuilder.exitNode();
386         exitLog("extension", removeNodeFromPath());
387     }
388
389     @Override
390     public void enterTypedef_stmt(YangParser.Typedef_stmtContext ctx) {
391         final int line = ctx.getStart().getLine();
392         final String typedefName = stringFromNode(ctx);
393         enterLog("typedef", typedefName, line);
394         QName typedefQName = new QName(namespace, revision, yangModelPrefix, typedefName);
395         addNodeToPath(typedefQName);
396         SchemaPath path = createActualSchemaPath(actualPath.peek());
397
398         TypeDefinitionBuilder builder = moduleBuilder.addTypedef(line, typedefQName, path);
399         parseSchemaNodeArgs(ctx, builder);
400         builder.setUnits(parseUnits(ctx));
401         builder.setDefaultValue(parseDefault(ctx));
402
403         moduleBuilder.enterNode(builder);
404     }
405
406     @Override
407     public void exitTypedef_stmt(YangParser.Typedef_stmtContext ctx) {
408         moduleBuilder.exitNode();
409         exitLog("typedef", removeNodeFromPath());
410     }
411
412     @Override
413     public void enterType_stmt(YangParser.Type_stmtContext ctx) {
414         final int line = ctx.getStart().getLine();
415         final String typeName = stringFromNode(ctx);
416         enterLog("type", typeName, line);
417
418         final QName typeQName = parseQName(typeName);
419
420         TypeDefinition<?> type = null;
421         Type_body_stmtsContext typeBody = null;
422         for (int i = 0; i < ctx.getChildCount(); i++) {
423             if (ctx.getChild(i) instanceof Type_body_stmtsContext) {
424                 typeBody = (Type_body_stmtsContext) ctx.getChild(i);
425                 break;
426             }
427         }
428
429         // if this is base yang type...
430         if (YangTypesConverter.isBaseYangType(typeName)) {
431             if (typeBody == null) {
432                 // check for types which must have body
433                 checkMissingBody(typeName, moduleName, line);
434                 // if there are no constraints, just grab default base yang type
435                 type = YangTypesConverter.javaTypeForBaseYangType(typeName);
436                 addNodeToPath(type.getQName());
437                 moduleBuilder.setType(type);
438             } else {
439                 QName qname;
440                 switch (typeName) {
441                     case "union":
442                         qname = BaseTypes.constructQName("union");
443                         addNodeToPath(qname);
444                         UnionTypeBuilder unionBuilder = moduleBuilder.addUnionType(line, namespace, revision);
445                         Builder parent = moduleBuilder.getActualNode();
446                         unionBuilder.setParent(parent);
447                         moduleBuilder.enterNode(unionBuilder);
448                         break;
449                     case "identityref":
450                         qname = BaseTypes.constructQName("identityref");
451                         addNodeToPath(qname);
452                         SchemaPath path = createActualSchemaPath(actualPath.peek());
453                         moduleBuilder.addIdentityrefType(line, path, getIdentityrefBase(typeBody));
454                         break;
455                     default:
456                         type = parseTypeWithBody(typeName, typeBody, actualPath.peek(), namespace, revision,
457                                 yangModelPrefix, moduleBuilder.getActualNode());
458                         moduleBuilder.setType(type);
459                         addNodeToPath(type.getQName());
460                 }
461             }
462         } else {
463             type = parseUnknownTypeWithBody(typeQName, typeBody, actualPath.peek(), namespace, revision,
464                     yangModelPrefix, moduleBuilder.getActualNode());
465             // add parent node of this type statement to dirty nodes
466             moduleBuilder.markActualNodeDirty();
467             moduleBuilder.setType(type);
468             addNodeToPath(type.getQName());
469         }
470
471     }
472
473     private QName parseQName(String typeName) {
474         QName typeQName;
475         if (typeName.contains(":")) {
476             String[] splittedName = typeName.split(":");
477             String prefix = splittedName[0];
478             String name = splittedName[1];
479             if (prefix.equals(yangModelPrefix)) {
480                 typeQName = new QName(namespace, revision, prefix, name);
481             } else {
482                 typeQName = new QName(null, null, prefix, name);
483             }
484         } else {
485             typeQName = new QName(namespace, revision, yangModelPrefix, typeName);
486         }
487         return typeQName;
488     }
489
490     @Override
491     public void exitType_stmt(YangParser.Type_stmtContext ctx) {
492         final String typeName = stringFromNode(ctx);
493         if ("union".equals(typeName)) {
494             moduleBuilder.exitNode();
495         }
496         exitLog("type", removeNodeFromPath());
497     }
498
499     @Override
500     public void enterGrouping_stmt(YangParser.Grouping_stmtContext ctx) {
501         final int line = ctx.getStart().getLine();
502         final String groupName = stringFromNode(ctx);
503         enterLog("grouping", groupName, line);
504         QName groupQName = new QName(namespace, revision, yangModelPrefix, groupName);
505         addNodeToPath(groupQName);
506         SchemaPath path = createActualSchemaPath(actualPath.peek());
507
508         GroupingBuilder builder = moduleBuilder.addGrouping(ctx.getStart().getLine(), groupQName, path);
509         parseSchemaNodeArgs(ctx, builder);
510
511         moduleBuilder.enterNode(builder);
512     }
513
514     @Override
515     public void exitGrouping_stmt(YangParser.Grouping_stmtContext ctx) {
516         moduleBuilder.exitNode();
517         exitLog("grouping", removeNodeFromPath());
518     }
519
520     @Override
521     public void enterContainer_stmt(Container_stmtContext ctx) {
522         final int line = ctx.getStart().getLine();
523         final String containerName = stringFromNode(ctx);
524         enterLog("container", containerName, line);
525
526         QName containerQName = new QName(namespace, revision, yangModelPrefix, containerName);
527         addNodeToPath(containerQName);
528         SchemaPath path = createActualSchemaPath(actualPath.peek());
529
530         ContainerSchemaNodeBuilder builder = moduleBuilder.addContainerNode(line, containerQName, path);
531         parseSchemaNodeArgs(ctx, builder);
532         parseConstraints(ctx, builder.getConstraints());
533         builder.setConfiguration(getConfig(ctx, builder, moduleName, line));
534
535         for (int i = 0; i < ctx.getChildCount(); ++i) {
536             final ParseTree childNode = ctx.getChild(i);
537             if (childNode instanceof Presence_stmtContext) {
538                 builder.setPresence(true);
539                 break;
540             }
541         }
542
543         moduleBuilder.enterNode(builder);
544     }
545
546     @Override
547     public void exitContainer_stmt(Container_stmtContext ctx) {
548         moduleBuilder.exitNode();
549         exitLog("container", removeNodeFromPath());
550     }
551
552     @Override
553     public void enterLeaf_stmt(Leaf_stmtContext ctx) {
554         final int line = ctx.getStart().getLine();
555         final String leafName = stringFromNode(ctx);
556         enterLog("leaf", leafName, line);
557
558         QName leafQName = new QName(namespace, revision, yangModelPrefix, leafName);
559         addNodeToPath(leafQName);
560         SchemaPath path = createActualSchemaPath(actualPath.peek());
561
562         LeafSchemaNodeBuilder builder = moduleBuilder.addLeafNode(line, leafQName, path);
563         parseSchemaNodeArgs(ctx, builder);
564         parseConstraints(ctx, builder.getConstraints());
565         builder.setConfiguration(getConfig(ctx, builder, moduleName, line));
566
567         String defaultStr = null;
568         String unitsStr = null;
569         for (int i = 0; i < ctx.getChildCount(); i++) {
570             ParseTree child = ctx.getChild(i);
571             if (child instanceof Default_stmtContext) {
572                 defaultStr = stringFromNode(child);
573             } else if (child instanceof Units_stmtContext) {
574                 unitsStr = stringFromNode(child);
575             }
576         }
577         builder.setDefaultStr(defaultStr);
578         builder.setUnits(unitsStr);
579
580         moduleBuilder.enterNode(builder);
581     }
582
583     @Override
584     public void exitLeaf_stmt(YangParser.Leaf_stmtContext ctx) {
585         moduleBuilder.exitNode();
586         exitLog("leaf", removeNodeFromPath());
587     }
588
589     @Override
590     public void enterUses_stmt(YangParser.Uses_stmtContext ctx) {
591         final int line = ctx.getStart().getLine();
592         final String groupingPathStr = stringFromNode(ctx);
593         enterLog("uses", groupingPathStr, line);
594
595         UsesNodeBuilder builder = moduleBuilder.addUsesNode(line, groupingPathStr);
596
597         moduleBuilder.enterNode(builder);
598     }
599
600     @Override
601     public void exitUses_stmt(YangParser.Uses_stmtContext ctx) {
602         moduleBuilder.exitNode();
603         exitLog("uses", "");
604     }
605
606     @Override
607     public void enterUses_augment_stmt(YangParser.Uses_augment_stmtContext ctx) {
608         actualPath.push(new Stack<QName>());
609         final int line = ctx.getStart().getLine();
610         final String augmentPath = stringFromNode(ctx);
611         enterLog(AUGMENT_STR, augmentPath, line);
612
613         AugmentationSchemaBuilder builder = moduleBuilder.addAugment(line, augmentPath);
614
615         for (int i = 0; i < ctx.getChildCount(); i++) {
616             ParseTree child = ctx.getChild(i);
617             if (child instanceof Description_stmtContext) {
618                 builder.setDescription(stringFromNode(child));
619             } else if (child instanceof Reference_stmtContext) {
620                 builder.setReference(stringFromNode(child));
621             } else if (child instanceof Status_stmtContext) {
622                 builder.setStatus(parseStatus((Status_stmtContext) child));
623             } else if (child instanceof When_stmtContext) {
624                 builder.addWhenCondition(stringFromNode(child));
625             }
626         }
627
628         moduleBuilder.enterNode(builder);
629     }
630
631     @Override
632     public void exitUses_augment_stmt(YangParser.Uses_augment_stmtContext ctx) {
633         moduleBuilder.exitNode();
634         exitLog(AUGMENT_STR, "");
635         actualPath.pop();
636     }
637
638     @Override
639     public void enterRefine_stmt(YangParser.Refine_stmtContext ctx) {
640         final String refineString = stringFromNode(ctx);
641         enterLog("refine", refineString, ctx.getStart().getLine());
642
643         RefineHolder refine = parseRefine(ctx, moduleName);
644         moduleBuilder.addRefine(refine);
645         moduleBuilder.enterNode(refine);
646     }
647
648     @Override
649     public void exitRefine_stmt(YangParser.Refine_stmtContext ctx) {
650         moduleBuilder.exitNode();
651         exitLog("refine", "");
652     }
653
654     @Override
655     public void enterLeaf_list_stmt(Leaf_list_stmtContext ctx) {
656         final int line = ctx.getStart().getLine();
657         final String leafListName = stringFromNode(ctx);
658         enterLog("leaf-list", leafListName, line);
659         QName leafListQName = new QName(namespace, revision, yangModelPrefix, leafListName);
660         addNodeToPath(leafListQName);
661         SchemaPath path = createActualSchemaPath(actualPath.peek());
662
663         LeafListSchemaNodeBuilder builder = moduleBuilder.addLeafListNode(line, leafListQName, path);
664         moduleBuilder.enterNode(builder);
665
666         parseSchemaNodeArgs(ctx, builder);
667         parseConstraints(ctx, builder.getConstraints());
668         builder.setConfiguration(getConfig(ctx, builder, moduleName, ctx.getStart().getLine()));
669
670         for (int i = 0; i < ctx.getChildCount(); ++i) {
671             final ParseTree childNode = ctx.getChild(i);
672             if (childNode instanceof Ordered_by_stmtContext) {
673                 final Ordered_by_stmtContext orderedBy = (Ordered_by_stmtContext) childNode;
674                 final boolean userOrdered = parseUserOrdered(orderedBy);
675                 builder.setUserOrdered(userOrdered);
676                 break;
677             }
678         }
679     }
680
681     @Override
682     public void exitLeaf_list_stmt(YangParser.Leaf_list_stmtContext ctx) {
683         moduleBuilder.exitNode();
684         exitLog("leaf-list", removeNodeFromPath());
685     }
686
687     @Override
688     public void enterList_stmt(List_stmtContext ctx) {
689         final int line = ctx.getStart().getLine();
690         final String listName = stringFromNode(ctx);
691         enterLog("list", listName, line);
692
693         QName listQName = new QName(namespace, revision, yangModelPrefix, listName);
694         addNodeToPath(listQName);
695         SchemaPath path = createActualSchemaPath(actualPath.peek());
696
697         ListSchemaNodeBuilder builder = moduleBuilder.addListNode(line, listQName, path);
698         moduleBuilder.enterNode(builder);
699
700         parseSchemaNodeArgs(ctx, builder);
701         parseConstraints(ctx, builder.getConstraints());
702         builder.setConfiguration(getConfig(ctx, builder, moduleName, line));
703
704         for (int i = 0; i < ctx.getChildCount(); ++i) {
705             ParseTree childNode = ctx.getChild(i);
706             if (childNode instanceof Ordered_by_stmtContext) {
707                 final Ordered_by_stmtContext orderedBy = (Ordered_by_stmtContext) childNode;
708                 final boolean userOrdered = parseUserOrdered(orderedBy);
709                 builder.setUserOrdered(userOrdered);
710             } else if (childNode instanceof Key_stmtContext) {
711                 List<String> key = createListKey((Key_stmtContext) childNode);
712                 builder.setKeys(key);
713             }
714         }
715     }
716
717     @Override
718     public void exitList_stmt(List_stmtContext ctx) {
719         moduleBuilder.exitNode();
720         exitLog("list", removeNodeFromPath());
721     }
722
723     @Override
724     public void enterAnyxml_stmt(YangParser.Anyxml_stmtContext ctx) {
725         final int line = ctx.getStart().getLine();
726         final String anyXmlName = stringFromNode(ctx);
727         enterLog("anyxml", anyXmlName, line);
728
729         QName anyXmlQName = new QName(namespace, revision, yangModelPrefix, anyXmlName);
730         addNodeToPath(anyXmlQName);
731         SchemaPath path = createActualSchemaPath(actualPath.peek());
732
733         AnyXmlBuilder builder = moduleBuilder.addAnyXml(line, anyXmlQName, path);
734         moduleBuilder.enterNode(builder);
735
736         parseSchemaNodeArgs(ctx, builder);
737         parseConstraints(ctx, builder.getConstraints());
738         builder.setConfiguration(getConfig(ctx, builder, moduleName, line));
739     }
740
741     @Override
742     public void exitAnyxml_stmt(YangParser.Anyxml_stmtContext ctx) {
743         moduleBuilder.exitNode();
744         exitLog("anyxml", removeNodeFromPath());
745     }
746
747     @Override
748     public void enterChoice_stmt(YangParser.Choice_stmtContext ctx) {
749         final int line = ctx.getStart().getLine();
750         final String choiceName = stringFromNode(ctx);
751         enterLog("choice", choiceName, line);
752
753         QName choiceQName = new QName(namespace, revision, yangModelPrefix, choiceName);
754         addNodeToPath(choiceQName);
755         SchemaPath path = createActualSchemaPath(actualPath.peek());
756
757         ChoiceBuilder builder = moduleBuilder.addChoice(line, choiceQName, path);
758         moduleBuilder.enterNode(builder);
759
760         parseSchemaNodeArgs(ctx, builder);
761         parseConstraints(ctx, builder.getConstraints());
762         builder.setConfiguration(getConfig(ctx, builder, moduleName, line));
763
764         // set 'default' case
765         for (int i = 0; i < ctx.getChildCount(); i++) {
766             ParseTree child = ctx.getChild(i);
767             if (child instanceof Default_stmtContext) {
768                 String defaultCase = stringFromNode(child);
769                 builder.setDefaultCase(defaultCase);
770                 break;
771             }
772         }
773     }
774
775     @Override
776     public void exitChoice_stmt(YangParser.Choice_stmtContext ctx) {
777         moduleBuilder.exitNode();
778         exitLog("choice", removeNodeFromPath());
779     }
780
781     @Override
782     public void enterCase_stmt(YangParser.Case_stmtContext ctx) {
783         final int line = ctx.getStart().getLine();
784         final String caseName = stringFromNode(ctx);
785         enterLog("case", caseName, line);
786
787         QName caseQName = new QName(namespace, revision, yangModelPrefix, caseName);
788         addNodeToPath(caseQName);
789         SchemaPath path = createActualSchemaPath(actualPath.peek());
790
791         ChoiceCaseBuilder builder = moduleBuilder.addCase(line, caseQName, path);
792         moduleBuilder.enterNode(builder);
793
794         parseSchemaNodeArgs(ctx, builder);
795         parseConstraints(ctx, builder.getConstraints());
796     }
797
798     @Override
799     public void exitCase_stmt(YangParser.Case_stmtContext ctx) {
800         moduleBuilder.exitNode();
801         exitLog("case", removeNodeFromPath());
802     }
803
804     @Override
805     public void enterNotification_stmt(YangParser.Notification_stmtContext ctx) {
806         final int line = ctx.getStart().getLine();
807         final String notificationName = stringFromNode(ctx);
808         enterLog("notification", notificationName, line);
809
810         QName notificationQName = new QName(namespace, revision, yangModelPrefix, notificationName);
811         addNodeToPath(notificationQName);
812         SchemaPath path = createActualSchemaPath(actualPath.peek());
813
814         NotificationBuilder builder = moduleBuilder.addNotification(line, notificationQName, path);
815         moduleBuilder.enterNode(builder);
816
817         parseSchemaNodeArgs(ctx, builder);
818     }
819
820     @Override
821     public void exitNotification_stmt(YangParser.Notification_stmtContext ctx) {
822         moduleBuilder.exitNode();
823         exitLog("notification", removeNodeFromPath());
824     }
825
826     // Unknown nodes
827     @Override
828     public void enterIdentifier_stmt(YangParser.Identifier_stmtContext ctx) {
829         handleUnknownNode(ctx.getStart().getLine(), ctx);
830     }
831
832     @Override
833     public void exitIdentifier_stmt(YangParser.Identifier_stmtContext ctx) {
834         moduleBuilder.exitNode();
835         exitLog("unknown-node", removeNodeFromPath());
836     }
837
838     @Override public void enterUnknown_statement(YangParser.Unknown_statementContext ctx) {
839         handleUnknownNode(ctx.getStart().getLine(), ctx);
840     }
841
842     @Override public void exitUnknown_statement(YangParser.Unknown_statementContext ctx) {
843         moduleBuilder.exitNode();
844         exitLog("unknown-node", removeNodeFromPath());
845     }
846
847     @Override public void enterUnknown_statement2(YangParser.Unknown_statement2Context ctx) {
848         handleUnknownNode(ctx.getStart().getLine(), ctx);
849     }
850
851     @Override public void exitUnknown_statement2(YangParser.Unknown_statement2Context ctx) {
852         moduleBuilder.exitNode();
853         exitLog("unknown-node", removeNodeFromPath());
854     }
855
856     @Override public void enterUnknown_statement3(YangParser.Unknown_statement3Context ctx) {
857         handleUnknownNode(ctx.getStart().getLine(), ctx);
858     }
859
860     @Override public void exitUnknown_statement3(YangParser.Unknown_statement3Context ctx) {
861         moduleBuilder.exitNode();
862         exitLog("unknown-node", removeNodeFromPath());
863     }
864
865     @Override
866     public void enterRpc_stmt(YangParser.Rpc_stmtContext ctx) {
867         final int line = ctx.getStart().getLine();
868         final String rpcName = stringFromNode(ctx);
869         enterLog("rpc", rpcName, line);
870
871         QName rpcQName = new QName(namespace, revision, yangModelPrefix, rpcName);
872         addNodeToPath(rpcQName);
873         SchemaPath path = createActualSchemaPath(actualPath.peek());
874
875         RpcDefinitionBuilder rpcBuilder = moduleBuilder.addRpc(line, rpcQName, path);
876         moduleBuilder.enterNode(rpcBuilder);
877
878
879         parseSchemaNodeArgs(ctx, rpcBuilder);
880     }
881
882     @Override
883     public void exitRpc_stmt(YangParser.Rpc_stmtContext ctx) {
884         moduleBuilder.exitNode();
885         exitLog("rpc", removeNodeFromPath());
886     }
887
888     @Override
889     public void enterInput_stmt(YangParser.Input_stmtContext ctx) {
890         final int line = ctx.getStart().getLine();
891         final String input = "input";
892         enterLog(input, input, line);
893
894         QName rpcQName = new QName(namespace, revision, yangModelPrefix, input);
895         addNodeToPath(rpcQName);
896         SchemaPath path = createActualSchemaPath(actualPath.peek());
897
898         ContainerSchemaNodeBuilder builder = moduleBuilder.addRpcInput(line, rpcQName, path);
899         moduleBuilder.enterNode(builder);
900         builder.setConfiguration(true);
901
902         parseSchemaNodeArgs(ctx, builder);
903         parseConstraints(ctx, builder.getConstraints());
904     }
905
906     @Override
907     public void exitInput_stmt(YangParser.Input_stmtContext ctx) {
908         moduleBuilder.exitNode();
909         exitLog("input", removeNodeFromPath());
910     }
911
912     @Override
913     public void enterOutput_stmt(YangParser.Output_stmtContext ctx) {
914         final int line = ctx.getStart().getLine();
915         final String output = "output";
916         enterLog(output, output, line);
917
918         QName rpcQName = new QName(namespace, revision, yangModelPrefix, output);
919         addNodeToPath(rpcQName);
920         SchemaPath path = createActualSchemaPath(actualPath.peek());
921
922         ContainerSchemaNodeBuilder builder = moduleBuilder.addRpcOutput(path, rpcQName, line);
923         moduleBuilder.enterNode(builder);
924         builder.setConfiguration(true);
925
926         parseSchemaNodeArgs(ctx, builder);
927         parseConstraints(ctx, builder.getConstraints());
928     }
929
930     @Override
931     public void exitOutput_stmt(YangParser.Output_stmtContext ctx) {
932         moduleBuilder.exitNode();
933         exitLog("output", removeNodeFromPath());
934     }
935
936     @Override
937     public void enterFeature_stmt(YangParser.Feature_stmtContext ctx) {
938         final int line = ctx.getStart().getLine();
939         final String featureName = stringFromNode(ctx);
940         enterLog("feature", featureName, line);
941
942         QName featureQName = new QName(namespace, revision, yangModelPrefix, featureName);
943         addNodeToPath(featureQName);
944         SchemaPath path = createActualSchemaPath(actualPath.peek());
945
946         FeatureBuilder featureBuilder = moduleBuilder.addFeature(line, featureQName, path);
947         moduleBuilder.enterNode(featureBuilder);
948
949         parseSchemaNodeArgs(ctx, featureBuilder);
950     }
951
952     @Override
953     public void exitFeature_stmt(YangParser.Feature_stmtContext ctx) {
954         moduleBuilder.exitNode();
955         exitLog("feature", removeNodeFromPath());
956     }
957
958     @Override
959     public void enterDeviation_stmt(YangParser.Deviation_stmtContext ctx) {
960         final int line = ctx.getStart().getLine();
961         final String targetPath = stringFromNode(ctx);
962         enterLog("deviation", targetPath, line);
963
964         String reference = null;
965         String deviate = null;
966         DeviationBuilder builder = moduleBuilder.addDeviation(line, targetPath);
967         moduleBuilder.enterNode(builder);
968
969         for (int i = 0; i < ctx.getChildCount(); i++) {
970             ParseTree child = ctx.getChild(i);
971             if (child instanceof Reference_stmtContext) {
972                 reference = stringFromNode(child);
973             } else if (child instanceof Deviate_not_supported_stmtContext) {
974                 deviate = stringFromNode(child);
975             } else if (child instanceof Deviate_add_stmtContext) {
976                 deviate = stringFromNode(child);
977             } else if (child instanceof Deviate_replace_stmtContext) {
978                 deviate = stringFromNode(child);
979             } else if (child instanceof Deviate_delete_stmtContext) {
980                 deviate = stringFromNode(child);
981             }
982         }
983         builder.setReference(reference);
984         builder.setDeviate(deviate);
985     }
986
987     @Override
988     public void exitDeviation_stmt(YangParser.Deviation_stmtContext ctx) {
989         moduleBuilder.exitNode();
990         exitLog("deviation", "");
991     }
992
993     @Override
994     public void enterIdentity_stmt(YangParser.Identity_stmtContext ctx) {
995         final int line = ctx.getStart().getLine();
996         final String identityName = stringFromNode(ctx);
997         enterLog("identity", identityName, line);
998
999         final QName identityQName = new QName(namespace, revision, yangModelPrefix, identityName);
1000         addNodeToPath(identityQName);
1001         SchemaPath path = createActualSchemaPath(actualPath.peek());
1002
1003         IdentitySchemaNodeBuilder builder = moduleBuilder.addIdentity(identityQName, line, path);
1004         moduleBuilder.enterNode(builder);
1005
1006
1007         parseSchemaNodeArgs(ctx, builder);
1008
1009         for (int i = 0; i < ctx.getChildCount(); i++) {
1010             ParseTree child = ctx.getChild(i);
1011             if (child instanceof Base_stmtContext) {
1012                 String baseIdentityName = stringFromNode(child);
1013                 builder.setBaseIdentityName(baseIdentityName);
1014             }
1015         }
1016     }
1017
1018     @Override
1019     public void exitIdentity_stmt(YangParser.Identity_stmtContext ctx) {
1020         moduleBuilder.exitNode();
1021         exitLog("identity", removeNodeFromPath());
1022     }
1023
1024     public ModuleBuilder getModuleBuilder() {
1025         return moduleBuilder;
1026     }
1027
1028     private void enterLog(String p1, String p2, int line) {
1029         LOGGER.trace("entering {} {} ({})", p1, p2, line);
1030     }
1031
1032     private void exitLog(String p1, String p2) {
1033         LOGGER.trace("exiting {} {}", p1, p2);
1034     }
1035
1036     private void exitLog(String p1, QName p2) {
1037         LOGGER.trace("exiting {} {}", p1, p2.getLocalName());
1038     }
1039
1040     private void setLog(String p1, String p2) {
1041         LOGGER.trace("setting {} {}", p1, p2);
1042     }
1043
1044     private void handleUnknownNode(final int line, final ParseTree ctx) {
1045         final String nodeParameter = stringFromNode(ctx);
1046         enterLog("unknown-node", nodeParameter, line);
1047
1048         QName nodeType;
1049         final String nodeTypeStr = ctx.getChild(0).getText();
1050         final String[] splittedElement = nodeTypeStr.split(":");
1051         if (splittedElement.length == 1) {
1052             nodeType = new QName(namespace, revision, yangModelPrefix, splittedElement[0]);
1053         } else {
1054             nodeType = new QName(namespace, revision, splittedElement[0], splittedElement[1]);
1055         }
1056
1057         QName qname = null;
1058         try {
1059             if (!Strings.isNullOrEmpty(nodeParameter)) {
1060                 String[] splittedName = nodeParameter.split(":");
1061                 if (splittedName.length == 2) {
1062                     qname = new QName(null, null, splittedName[0], splittedName[1]);
1063                 } else {
1064                     qname = new QName(namespace, revision, yangModelPrefix, splittedName[0]);
1065                 }
1066             } else {
1067                 qname = nodeType;
1068             }
1069         } catch (IllegalArgumentException e) {
1070             qname = nodeType;
1071
1072         }
1073         addNodeToPath(qname);
1074         SchemaPath path = createActualSchemaPath(actualPath.peek());
1075
1076         UnknownSchemaNodeBuilder builder = moduleBuilder.addUnknownSchemaNode(line, qname, path);
1077         builder.setNodeType(nodeType);
1078         builder.setNodeParameter(nodeParameter);
1079
1080
1081         parseSchemaNodeArgs(ctx, builder);
1082         moduleBuilder.enterNode(builder);
1083     }
1084
1085 }