2 * Copyright (c) 2013 Cisco Systems, Inc. and others. All rights reserved.
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
8 package org.opendaylight.yangtools.yang.parser.impl;
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;
25 import com.google.common.base.Splitter;
26 import com.google.common.base.Strings;
27 import com.google.common.collect.Iterables;
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;
37 import java.util.NavigableMap;
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;
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";
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";
117 * Date Format is not thread-safe so we cannot make constant from it.
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;
129 public YangParserListenerImpl(final Map<String, NavigableMap<Date, URI>> namespaceContext, final String sourcePath) {
130 this.namespaceContext = namespaceContext;
131 this.sourcePath = sourcePath;
135 * Create a new instance.
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?
141 * @param namespaceContext namespaceContext
142 * @param sourcePath sourcePath
143 * @param walker walker
145 * @return new instance of YangParserListenerImpl
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);
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);
161 moduleBuilder = new ModuleBuilder(moduleName, sourcePath);
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);
172 if (description != null && reference != null) {
177 moduleBuilder.setDescription(description);
178 moduleBuilder.setReference(reference);
182 public void exitModule_stmt(final YangParser.Module_stmtContext ctx) {
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);
194 moduleBuilder = new ModuleBuilder(moduleName, true, sourcePath);
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);
205 if (description != null && reference != null) {
210 moduleBuilder.setDescription(description);
211 moduleBuilder.setReference(reference);
215 public void exitSubmodule_stmt(final YangParser.Submodule_stmtContext ctx) {
216 exitLog("submodule");
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();
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);
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);
265 if (yangVersion == null) {
268 moduleBuilder.setYangVersion(yangVersion);
272 public void exitModule_header_stmts(final Module_header_stmtsContext ctx) {
273 exitLog("module_header");
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);
302 public void exitMeta_stmts(final YangParser.Meta_stmtsContext ctx) {
303 exitLog("meta_stmt");
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);
318 public void exitRevision_stmts(final Revision_stmtsContext ctx) {
319 exitLog("revisions");
322 private void updateRevisionForRevisionStatement(final ParseTree treeNode) {
323 final String revisionDateStr = stringFromNode(treeNode);
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));
337 } catch (final ParseException e) {
338 LOG.warn("Failed to parse revision string: {}", revisionDateStr, e);
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);
348 String importPrefix = null;
349 Date importRevision = null;
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);
358 importRevision = revisionFormat.parse(importRevisionStr);
359 } catch (final ParseException e) {
360 LOG.warn("Failed to parse import revision-date at line {}: {}", line, importRevisionStr, e);
364 moduleBuilder.addModuleImport(importName, importRevision, importPrefix);
365 LOG.trace("setting import ({}; {}; {})", importName, importRevision, importPrefix);
369 public void exitImport_stmt(final Import_stmtContext ctx) {
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);
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);
385 includeRevision = revisionFormat.parse(importRevisionStr);
386 } catch (final ParseException e) {
387 LOG.warn("Failed to parse import revision-date at line {}: {}", line, importRevisionStr, e);
391 moduleBuilder.addInclude(includeName, includeRevision);
395 public void exitInclude_stmt(final YangParser.Include_stmtContext ctx) {
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);
406 final SchemaPath targetPath = parseXPathString(augmentPath, line);
407 final AugmentationSchemaBuilder builder = moduleBuilder.addAugment(line, augmentPath, targetPath,
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));
423 moduleBuilder.enterNode(builder);
427 public void exitAugment_stmt(final YangParser.Augment_stmtContext ctx) {
428 moduleBuilder.exitNode();
429 exitLog(AUGMENT_STR);
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);
441 final ExtensionBuilder builder = moduleBuilder.addExtension(qname, line, path);
442 parseSchemaNodeArgs(ctx, builder);
444 String argument = null;
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);
454 builder.setArgument(argument);
455 builder.setYinElement(yin);
457 moduleBuilder.enterNode(builder);
461 public void exitExtension_stmt(final YangParser.Extension_stmtContext ctx) {
462 moduleBuilder.exitNode();
463 exitLog("extension", stack.removeNodeFromPath());
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);
474 final TypeDefinitionBuilder builder = moduleBuilder.addTypedef(line, typedefQName, path);
475 parseSchemaNodeArgs(ctx, builder);
476 builder.setUnits(parseUnits(ctx));
477 builder.setDefaultValue(parseDefault(ctx));
479 moduleBuilder.enterNode(builder);
483 public void exitTypedef_stmt(final YangParser.Typedef_stmtContext ctx) {
484 moduleBuilder.exitNode();
485 exitLog("typedef", stack.removeNodeFromPath());
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);
494 final QName typeQName = parseQName(typeName, line);
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);
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);
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);
525 qname = BaseTypes.IDENTITYREF_QNAME;
526 final SchemaPath path = stack.addNodeToPath(qname);
527 moduleBuilder.addIdentityrefType(line, path, getIdentityrefBase(typeBody));
530 type = parseTypeWithBody(typeName, typeBody, stack.currentSchemaPath(), moduleQName,
531 moduleBuilder.getActualNode());
532 moduleBuilder.setType(type);
533 stack.addNodeToPath(type.getQName());
537 final TypeAwareBuilder parent = (TypeAwareBuilder) moduleBuilder.getActualNode();
538 if (typeBody == null) {
539 parent.setTypeQName(typeQName);
540 moduleBuilder.markActualNodeDirty();
542 ParserListenerUtils.parseUnknownTypeWithBody(typeBody, parent, typeQName, moduleBuilder, moduleQName,
543 stack.currentSchemaPath());
545 stack.addNodeToPath(QName.create(moduleQName.getModule(), typeQName.getLocalName()));
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}
561 * QName value as String
563 * line in Yang model document where QName occur.
564 * @return transformed string qname parameter as QName structure.
566 * @throws YangParseException
568 private QName parseQName(final String qnameString, final int line) {
570 if (qnameString.indexOf(':') == -1) {
571 qname = QName.create(moduleQName, qnameString);
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);
579 final ModuleImport imp = moduleBuilder.getImport(prefix);
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.");
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()));
592 if (revision == null) {
593 revision = namespaces.lastEntry().getKey();
594 namespace = namespaces.lastEntry().getValue();
596 // FIXME: this lookup does not look right, as we will end up
598 // a qname which does not have a namespace. At any rate we
599 // should arrive at a QNameModule!
600 namespace = namespaces.get(revision);
603 final QNameModule mod = QNameModule.cachedReference(QNameModule.create(namespace, revision));
604 qname = QName.create(mod, name);
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();
616 exitLog("type", stack.removeNodeFromPath());
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);
627 final GroupingBuilder builder = moduleBuilder.addGrouping(ctx.getStart().getLine(), groupQName, path);
628 parseSchemaNodeArgs(ctx, builder);
630 moduleBuilder.enterNode(builder);
634 public void exitGrouping_stmt(final YangParser.Grouping_stmtContext ctx) {
635 moduleBuilder.exitNode();
636 exitLog("grouping", stack.removeNodeFromPath());
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);
645 final QName containerQName = QName.create(moduleQName, containerName);
646 final SchemaPath path = stack.addNodeToPath(containerQName);
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));
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);
661 moduleBuilder.enterNode(builder);
665 public void exitContainer_stmt(final Container_stmtContext ctx) {
666 moduleBuilder.exitNode();
667 exitLog("container", stack.removeNodeFromPath());
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);
676 final QName leafQName = QName.create(moduleQName, leafName);
677 final SchemaPath path = stack.addNodeToPath(leafQName);
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));
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);
694 builder.setDefaultStr(defaultStr);
695 builder.setUnits(unitsStr);
697 moduleBuilder.enterNode(builder);
701 public void exitLeaf_stmt(final YangParser.Leaf_stmtContext ctx) {
702 moduleBuilder.exitNode();
703 exitLog("leaf", stack.removeNodeFromPath());
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);
713 final UsesNodeBuilder builder = moduleBuilder.addUsesNode(line, groupingPath);
715 moduleBuilder.enterNode(builder);
719 public void exitUses_stmt(final YangParser.Uses_stmtContext ctx) {
720 moduleBuilder.exitNode();
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);
731 final SchemaPath targetPath = parseXPathString(augmentPath, line);
732 final AugmentationSchemaBuilder builder = moduleBuilder.addAugment(line, augmentPath, targetPath,
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));
748 moduleBuilder.enterNode(builder);
752 public void exitUses_augment_stmt(final YangParser.Uses_augment_stmtContext ctx) {
753 moduleBuilder.exitNode();
754 exitLog(AUGMENT_STR);
759 public void enterRefine_stmt(final YangParser.Refine_stmtContext ctx) {
760 final String refineString = stringFromNode(ctx);
761 enterLog("refine", refineString, ctx.getStart().getLine());
763 final RefineHolderImpl refine = parseRefine(ctx, moduleName);
764 moduleBuilder.addRefine(refine);
765 moduleBuilder.enterNode(refine);
769 public void exitRefine_stmt(final YangParser.Refine_stmtContext ctx) {
770 moduleBuilder.exitNode();
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);
782 final LeafListSchemaNodeBuilder builder = moduleBuilder.addLeafListNode(line, leafListQName, path);
783 moduleBuilder.enterNode(builder);
785 parseSchemaNodeArgs(ctx, builder);
786 parseConstraints(ctx, builder.getConstraints());
787 builder.setConfiguration(getConfig(ctx, builder, moduleName, ctx.getStart().getLine()));
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);
801 public void exitLeaf_list_stmt(final YangParser.Leaf_list_stmtContext ctx) {
802 moduleBuilder.exitNode();
803 exitLog("leaf-list", stack.removeNodeFromPath());
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);
812 final QName listQName = QName.create(moduleQName, listName);
813 final SchemaPath path = stack.addNodeToPath(listQName);
815 final ListSchemaNodeBuilder builder = moduleBuilder.addListNode(line, listQName, path);
816 moduleBuilder.enterNode(builder);
818 parseSchemaNodeArgs(ctx, builder);
819 parseConstraints(ctx, builder.getConstraints());
820 builder.setConfiguration(getConfig(ctx, builder, moduleName, line));
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");
839 public void exitList_stmt(final List_stmtContext ctx) {
840 moduleBuilder.exitNode();
841 exitLog("list", stack.removeNodeFromPath());
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);
850 final QName anyXmlQName = QName.create(moduleQName, anyXmlName);
851 final SchemaPath path = stack.addNodeToPath(anyXmlQName);
853 final AnyXmlBuilder builder = moduleBuilder.addAnyXml(line, anyXmlQName, path);
854 moduleBuilder.enterNode(builder);
856 parseSchemaNodeArgs(ctx, builder);
857 parseConstraints(ctx, builder.getConstraints());
858 builder.setConfiguration(getConfig(ctx, builder, moduleName, line));
862 public void exitAnyxml_stmt(final YangParser.Anyxml_stmtContext ctx) {
863 moduleBuilder.exitNode();
864 exitLog("anyxml", stack.removeNodeFromPath());
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);
873 final QName choiceQName = QName.create(moduleQName, choiceName);
874 final SchemaPath path = stack.addNodeToPath(choiceQName);
876 final ChoiceBuilder builder = moduleBuilder.addChoice(line, choiceQName, path);
877 moduleBuilder.enterNode(builder);
879 parseSchemaNodeArgs(ctx, builder);
880 parseConstraints(ctx, builder.getConstraints());
881 builder.setConfiguration(getConfig(ctx, builder, moduleName, line));
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);
895 public void exitChoice_stmt(final YangParser.Choice_stmtContext ctx) {
896 moduleBuilder.exitNode();
897 exitLog("choice", stack.removeNodeFromPath());
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);
906 final QName caseQName = QName.create(moduleQName, caseName);
907 final SchemaPath path = stack.addNodeToPath(caseQName);
909 final ChoiceCaseBuilder builder = moduleBuilder.addCase(line, caseQName, path);
910 moduleBuilder.enterNode(builder);
912 parseSchemaNodeArgs(ctx, builder);
913 parseConstraints(ctx, builder.getConstraints());
917 public void exitCase_stmt(final YangParser.Case_stmtContext ctx) {
918 moduleBuilder.exitNode();
919 exitLog("case", stack.removeNodeFromPath());
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);
928 final QName notificationQName = QName.create(moduleQName, notificationName);
929 final SchemaPath path = stack.addNodeToPath(notificationQName);
931 final NotificationBuilder builder = moduleBuilder.addNotification(line, notificationQName, path);
932 moduleBuilder.enterNode(builder);
934 parseSchemaNodeArgs(ctx, builder);
938 public void exitNotification_stmt(final YangParser.Notification_stmtContext ctx) {
939 moduleBuilder.exitNode();
940 exitLog("notification", stack.removeNodeFromPath());
945 public void enterIdentifier_stmt(final YangParser.Identifier_stmtContext ctx) {
946 handleUnknownNode(ctx.getStart().getLine(), ctx);
950 public void exitIdentifier_stmt(final YangParser.Identifier_stmtContext ctx) {
951 moduleBuilder.exitNode();
952 exitLog(UNKNOWN_NODE_STR, stack.removeNodeFromPath());
956 public void enterUnknown_statement(final YangParser.Unknown_statementContext ctx) {
957 handleUnknownNode(ctx.getStart().getLine(), ctx);
961 public void exitUnknown_statement(final YangParser.Unknown_statementContext ctx) {
962 moduleBuilder.exitNode();
963 exitLog(UNKNOWN_NODE_STR, stack.removeNodeFromPath());
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);
972 final QName rpcQName = QName.create(moduleQName, rpcName);
973 final SchemaPath path = stack.addNodeToPath(rpcQName);
975 final RpcDefinitionBuilder rpcBuilder = moduleBuilder.addRpc(line, rpcQName, path);
976 moduleBuilder.enterNode(rpcBuilder);
978 parseSchemaNodeArgs(ctx, rpcBuilder);
982 public void exitRpc_stmt(final YangParser.Rpc_stmtContext ctx) {
983 moduleBuilder.exitNode();
984 exitLog("rpc", stack.removeNodeFromPath());
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);
993 final QName rpcQName = QName.create(moduleQName, input);
994 final SchemaPath path = stack.addNodeToPath(rpcQName);
996 final ContainerSchemaNodeBuilder builder = moduleBuilder.addRpcInput(line, rpcQName, path);
997 moduleBuilder.enterNode(builder);
998 builder.setConfiguration(true);
1000 parseSchemaNodeArgs(ctx, builder);
1001 parseConstraints(ctx, builder.getConstraints());
1005 public void exitInput_stmt(final YangParser.Input_stmtContext ctx) {
1006 moduleBuilder.exitNode();
1007 exitLog("input", stack.removeNodeFromPath());
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);
1016 final QName rpcQName = QName.create(moduleQName, output);
1017 final SchemaPath path = stack.addNodeToPath(rpcQName);
1019 final ContainerSchemaNodeBuilder builder = moduleBuilder.addRpcOutput(path, rpcQName, line);
1020 moduleBuilder.enterNode(builder);
1021 builder.setConfiguration(true);
1023 parseSchemaNodeArgs(ctx, builder);
1024 parseConstraints(ctx, builder.getConstraints());
1028 public void exitOutput_stmt(final YangParser.Output_stmtContext ctx) {
1029 moduleBuilder.exitNode();
1030 exitLog("output", stack.removeNodeFromPath());
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);
1039 final QName featureQName = QName.create(moduleQName, featureName);
1040 final SchemaPath path = stack.addNodeToPath(featureQName);
1042 final FeatureBuilder featureBuilder = moduleBuilder.addFeature(line, featureQName, path);
1043 moduleBuilder.enterNode(featureBuilder);
1045 parseSchemaNodeArgs(ctx, featureBuilder);
1049 public void exitFeature_stmt(final YangParser.Feature_stmtContext ctx) {
1050 moduleBuilder.exitNode();
1051 exitLog("feature", stack.removeNodeFromPath());
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.");
1062 enterLog("deviation", targetPathStr, line);
1064 String reference = null;
1065 String deviate = null;
1067 final SchemaPath targetPath = parseXPathString(targetPathStr, line);
1068 final DeviationBuilder builder = moduleBuilder.addDeviation(line, targetPath);
1069 moduleBuilder.enterNode(builder);
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);
1085 builder.setReference(reference);
1086 builder.setDeviate(deviate);
1089 public SchemaPath parseXPathString(final String xpathString, final int line) {
1090 final boolean absolute = !xpathString.isEmpty() && xpathString.charAt(0) == '/';
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();
1097 path.add(parseQName(pathElement, line));
1099 path.add(QName.create(moduleQName, s));
1102 return SchemaPath.create(path, absolute);
1106 public void exitDeviation_stmt(final YangParser.Deviation_stmtContext ctx) {
1107 moduleBuilder.exitNode();
1108 exitLog("deviation");
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);
1117 final QName identityQName = QName.create(moduleQName, identityName);
1118 final SchemaPath path = stack.addNodeToPath(identityQName);
1120 final IdentitySchemaNodeBuilder builder = moduleBuilder.addIdentity(identityQName, line, path);
1121 moduleBuilder.enterNode(builder);
1123 parseSchemaNodeArgs(ctx, builder);
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);
1135 public void exitIdentity_stmt(final YangParser.Identity_stmtContext ctx) {
1136 moduleBuilder.exitNode();
1137 exitLog("identity", stack.removeNodeFromPath());
1140 public ModuleBuilder getModuleBuilder() {
1141 return moduleBuilder;
1144 private static void enterLog(final String p1, final String p2, final int line) {
1145 LOG.trace("entering {} {} ({})", p1, p2, line);
1148 private static void exitLog(final String p1) {
1149 LOG.trace("exiting {}", p1);
1152 private static void exitLog(final String p1, final QName p2) {
1153 LOG.trace("exiting {} {}", p1, p2.getLocalName());
1156 private static void setLog(final String p1, final String p2) {
1157 LOG.trace("setting {} {}", p1, p2);
1160 private void handleUnknownNode(final int line, final ParseTree ctx) {
1161 final String nodeParameter = stringFromNode(ctx);
1162 enterLog(UNKNOWN_NODE_STR, nodeParameter, line);
1164 final String nodeTypeStr = ctx.getChild(0).getText();
1165 final QName nodeType = parseQName(nodeTypeStr, line);
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
1175 // they are dependent!!!
1176 if (Strings.isNullOrEmpty(nodeParameter)) {
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);
1184 qname = QName.create(moduleQName, it.next());
1187 } catch (IllegalArgumentException | YangParseException ex) {
1191 final SchemaPath path = stack.addNodeToPath(qname);
1193 final UnknownSchemaNodeBuilderImpl builder = moduleBuilder.addUnknownSchemaNode(line, qname, path);
1194 builder.setNodeType(nodeType);
1195 builder.setNodeParameter(nodeParameter);
1197 parseSchemaNodeArgs(ctx, builder);
1198 moduleBuilder.enterNode(builder);