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