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