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