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;
24 import com.google.common.base.Splitter;
25 import com.google.common.base.Strings;
26 import com.google.common.collect.Iterables;
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;
36 import java.util.NavigableMap;
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;
106 * @deprecated Pre-Beryllium implementation, scheduled for removal.
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";
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";
120 * Date Format is not thread-safe so we cannot make constant from it.
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;
132 public YangParserListenerImpl(final Map<String, NavigableMap<Date, URI>> namespaceContext, final String sourcePath) {
133 this.namespaceContext = namespaceContext;
134 this.sourcePath = sourcePath;
138 * Create a new instance.
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?
144 * @param namespaceContext namespaceContext
145 * @param sourcePath sourcePath
146 * @param walker walker
148 * @return new instance of YangParserListenerImpl
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);
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);
164 moduleBuilder = new ModuleBuilder(moduleName, sourcePath);
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);
175 if (description != null && reference != null) {
180 moduleBuilder.setDescription(description);
181 moduleBuilder.setReference(reference);
185 public void exitModule_stmt(final YangParser.Module_stmtContext ctx) {
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);
197 moduleBuilder = new ModuleBuilder(moduleName, true, sourcePath);
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);
208 if (description != null && reference != null) {
213 moduleBuilder.setDescription(description);
214 moduleBuilder.setReference(reference);
218 public void exitSubmodule_stmt(final YangParser.Submodule_stmtContext ctx) {
219 exitLog("submodule");
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();
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);
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);
268 if (yangVersion == null) {
271 moduleBuilder.setYangVersion(yangVersion);
275 public void exitModule_header_stmts(final Module_header_stmtsContext ctx) {
276 exitLog("module_header");
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);
305 public void exitMeta_stmts(final YangParser.Meta_stmtsContext ctx) {
306 exitLog("meta_stmt");
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);
321 public void exitRevision_stmts(final Revision_stmtsContext ctx) {
322 exitLog("revisions");
325 private void updateRevisionForRevisionStatement(final ParseTree treeNode) {
326 final String revisionDateStr = stringFromNode(treeNode);
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));
340 } catch (final ParseException e) {
341 LOG.warn("Failed to parse revision string: {}", revisionDateStr, e);
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);
351 String importPrefix = null;
352 Date importRevision = null;
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);
361 importRevision = revisionFormat.parse(importRevisionStr);
362 } catch (final ParseException e) {
363 LOG.warn("Failed to parse import revision-date at line {}: {}", line, importRevisionStr, e);
367 moduleBuilder.addModuleImport(importName, importRevision, importPrefix);
368 LOG.trace("setting import ({}; {}; {})", importName, importRevision, importPrefix);
372 public void exitImport_stmt(final Import_stmtContext ctx) {
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);
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);
388 includeRevision = revisionFormat.parse(importRevisionStr);
389 } catch (final ParseException e) {
390 LOG.warn("Failed to parse import revision-date at line {}: {}", line, importRevisionStr, e);
394 moduleBuilder.addInclude(includeName, includeRevision);
398 public void exitInclude_stmt(final YangParser.Include_stmtContext ctx) {
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);
409 final SchemaPath targetPath = parseXPathString(augmentPath, line);
410 final AugmentationSchemaBuilder builder = moduleBuilder.addAugment(line, augmentPath, targetPath,
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));
426 moduleBuilder.enterNode(builder);
430 public void exitAugment_stmt(final YangParser.Augment_stmtContext ctx) {
431 moduleBuilder.exitNode();
432 exitLog(AUGMENT_STR);
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);
444 final ExtensionBuilder builder = moduleBuilder.addExtension(qname, line, path);
445 parseSchemaNodeArgs(ctx, builder);
447 String argument = null;
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);
457 builder.setArgument(argument);
458 builder.setYinElement(yin);
460 moduleBuilder.enterNode(builder);
464 public void exitExtension_stmt(final YangParser.Extension_stmtContext ctx) {
465 moduleBuilder.exitNode();
466 exitLog("extension", stack.removeNodeFromPath());
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);
477 final TypeDefinitionBuilder builder = moduleBuilder.addTypedef(line, typedefQName, path);
478 parseSchemaNodeArgs(ctx, builder);
479 builder.setUnits(parseUnits(ctx));
480 builder.setDefaultValue(parseDefault(ctx));
482 moduleBuilder.enterNode(builder);
486 public void exitTypedef_stmt(final YangParser.Typedef_stmtContext ctx) {
487 moduleBuilder.exitNode();
488 exitLog("typedef", stack.removeNodeFromPath());
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);
497 final QName typeQName = parseQName(typeName, line);
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);
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);
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);
528 qname = BaseTypes.IDENTITYREF_QNAME;
529 final SchemaPath path = stack.addNodeToPath(qname);
530 moduleBuilder.addIdentityrefType(line, path, getIdentityrefBase(typeBody));
533 type = parseTypeWithBody(typeName, typeBody, stack.currentSchemaPath(), moduleQName,
534 moduleBuilder.getActualNode());
535 moduleBuilder.setType(type);
536 stack.addNodeToPath(type.getQName());
540 final TypeAwareBuilder parent = (TypeAwareBuilder) moduleBuilder.getActualNode();
541 if (typeBody == null) {
542 parent.setTypeQName(typeQName);
543 moduleBuilder.markActualNodeDirty();
545 ParserListenerUtils.parseUnknownTypeWithBody(typeBody, parent, typeQName, moduleBuilder, moduleQName,
546 stack.currentSchemaPath());
548 stack.addNodeToPath(QName.create(moduleQName.getModule(), typeQName.getLocalName()));
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}
564 * QName value as String
566 * line in Yang model document where QName occur.
567 * @return transformed string qname parameter as QName structure.
569 * @throws YangParseException
571 private QName parseQName(final String qnameString, final int line) {
573 if (qnameString.indexOf(':') == -1) {
574 qname = QName.create(moduleQName, qnameString);
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);
582 final ModuleImport imp = moduleBuilder.getImport(prefix);
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.");
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()));
595 if (revision == null) {
596 revision = namespaces.lastEntry().getKey();
597 namespace = namespaces.lastEntry().getValue();
599 // FIXME: this lookup does not look right, as we will end up
601 // a qname which does not have a namespace. At any rate we
602 // should arrive at a QNameModule!
603 namespace = namespaces.get(revision);
606 final QNameModule mod = QNameModule.create(namespace, revision).intern();
607 qname = QName.create(mod, name);
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();
619 exitLog("type", stack.removeNodeFromPath());
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);
630 final GroupingBuilder builder = moduleBuilder.addGrouping(ctx.getStart().getLine(), groupQName, path);
631 parseSchemaNodeArgs(ctx, builder);
633 moduleBuilder.enterNode(builder);
637 public void exitGrouping_stmt(final YangParser.Grouping_stmtContext ctx) {
638 moduleBuilder.exitNode();
639 exitLog("grouping", stack.removeNodeFromPath());
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);
648 final QName containerQName = QName.create(moduleQName, containerName);
649 final SchemaPath path = stack.addNodeToPath(containerQName);
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));
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);
664 moduleBuilder.enterNode(builder);
668 public void exitContainer_stmt(final Container_stmtContext ctx) {
669 moduleBuilder.exitNode();
670 exitLog("container", stack.removeNodeFromPath());
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);
679 final QName leafQName = QName.create(moduleQName, leafName);
680 final SchemaPath path = stack.addNodeToPath(leafQName);
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));
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);
697 builder.setDefaultStr(defaultStr);
698 builder.setUnits(unitsStr);
700 moduleBuilder.enterNode(builder);
704 public void exitLeaf_stmt(final YangParser.Leaf_stmtContext ctx) {
705 moduleBuilder.exitNode();
706 exitLog("leaf", stack.removeNodeFromPath());
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);
716 final UsesNodeBuilder builder = moduleBuilder.addUsesNode(line, groupingPath);
718 moduleBuilder.enterNode(builder);
722 public void exitUses_stmt(final YangParser.Uses_stmtContext ctx) {
723 moduleBuilder.exitNode();
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);
734 final SchemaPath targetPath = parseXPathString(augmentPath, line);
735 final AugmentationSchemaBuilder builder = moduleBuilder.addAugment(line, augmentPath, targetPath,
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));
751 moduleBuilder.enterNode(builder);
755 public void exitUses_augment_stmt(final YangParser.Uses_augment_stmtContext ctx) {
756 moduleBuilder.exitNode();
757 exitLog(AUGMENT_STR);
762 public void enterRefine_stmt(final YangParser.Refine_stmtContext ctx) {
763 final String refineString = stringFromNode(ctx);
764 enterLog("refine", refineString, ctx.getStart().getLine());
766 final RefineHolderImpl refine = parseRefine(ctx, moduleName);
767 moduleBuilder.addRefine(refine);
768 moduleBuilder.enterNode(refine);
772 public void exitRefine_stmt(final YangParser.Refine_stmtContext ctx) {
773 moduleBuilder.exitNode();
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);
785 final LeafListSchemaNodeBuilder builder = moduleBuilder.addLeafListNode(line, leafListQName, path);
786 moduleBuilder.enterNode(builder);
788 parseSchemaNodeArgs(ctx, builder);
789 parseConstraints(ctx, builder.getConstraints());
790 builder.setConfiguration(getConfig(ctx, builder, moduleName, ctx.getStart().getLine()));
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);
804 public void exitLeaf_list_stmt(final YangParser.Leaf_list_stmtContext ctx) {
805 moduleBuilder.exitNode();
806 exitLog("leaf-list", stack.removeNodeFromPath());
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);
815 final QName listQName = QName.create(moduleQName, listName);
816 final SchemaPath path = stack.addNodeToPath(listQName);
818 final ListSchemaNodeBuilder builder = moduleBuilder.addListNode(line, listQName, path);
819 moduleBuilder.enterNode(builder);
821 parseSchemaNodeArgs(ctx, builder);
822 parseConstraints(ctx, builder.getConstraints());
823 builder.setConfiguration(getConfig(ctx, builder, moduleName, line));
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");
842 public void exitList_stmt(final List_stmtContext ctx) {
843 moduleBuilder.exitNode();
844 exitLog("list", stack.removeNodeFromPath());
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);
853 final QName anyXmlQName = QName.create(moduleQName, anyXmlName);
854 final SchemaPath path = stack.addNodeToPath(anyXmlQName);
856 final AnyXmlBuilder builder = moduleBuilder.addAnyXml(line, anyXmlQName, path);
857 moduleBuilder.enterNode(builder);
859 parseSchemaNodeArgs(ctx, builder);
860 parseConstraints(ctx, builder.getConstraints());
861 builder.setConfiguration(getConfig(ctx, builder, moduleName, line));
865 public void exitAnyxml_stmt(final YangParser.Anyxml_stmtContext ctx) {
866 moduleBuilder.exitNode();
867 exitLog("anyxml", stack.removeNodeFromPath());
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);
876 final QName choiceQName = QName.create(moduleQName, choiceName);
877 final SchemaPath path = stack.addNodeToPath(choiceQName);
879 final ChoiceBuilder builder = moduleBuilder.addChoice(line, choiceQName, path);
880 moduleBuilder.enterNode(builder);
882 parseSchemaNodeArgs(ctx, builder);
883 parseConstraints(ctx, builder.getConstraints());
884 builder.setConfiguration(getConfig(ctx, builder, moduleName, line));
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);
898 public void exitChoice_stmt(final YangParser.Choice_stmtContext ctx) {
899 moduleBuilder.exitNode();
900 exitLog("choice", stack.removeNodeFromPath());
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);
909 final QName caseQName = QName.create(moduleQName, caseName);
910 final SchemaPath path = stack.addNodeToPath(caseQName);
912 final ChoiceCaseBuilder builder = moduleBuilder.addCase(line, caseQName, path);
913 moduleBuilder.enterNode(builder);
915 parseSchemaNodeArgs(ctx, builder);
916 parseConstraints(ctx, builder.getConstraints());
920 public void exitCase_stmt(final YangParser.Case_stmtContext ctx) {
921 moduleBuilder.exitNode();
922 exitLog("case", stack.removeNodeFromPath());
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);
931 final QName notificationQName = QName.create(moduleQName, notificationName);
932 final SchemaPath path = stack.addNodeToPath(notificationQName);
934 final NotificationBuilder builder = moduleBuilder.addNotification(line, notificationQName, path);
935 moduleBuilder.enterNode(builder);
937 parseSchemaNodeArgs(ctx, builder);
941 public void exitNotification_stmt(final YangParser.Notification_stmtContext ctx) {
942 moduleBuilder.exitNode();
943 exitLog("notification", stack.removeNodeFromPath());
948 public void enterIdentifier_stmt(final YangParser.Identifier_stmtContext ctx) {
949 handleUnknownNode(ctx.getStart().getLine(), ctx);
953 public void exitIdentifier_stmt(final YangParser.Identifier_stmtContext ctx) {
954 moduleBuilder.exitNode();
955 exitLog(UNKNOWN_NODE_STR, stack.removeNodeFromPath());
959 public void enterUnknown_statement(final YangParser.Unknown_statementContext ctx) {
960 handleUnknownNode(ctx.getStart().getLine(), ctx);
964 public void exitUnknown_statement(final YangParser.Unknown_statementContext ctx) {
965 moduleBuilder.exitNode();
966 exitLog(UNKNOWN_NODE_STR, stack.removeNodeFromPath());
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);
975 final QName rpcQName = QName.create(moduleQName, rpcName);
976 final SchemaPath path = stack.addNodeToPath(rpcQName);
978 final RpcDefinitionBuilder rpcBuilder = moduleBuilder.addRpc(line, rpcQName, path);
979 moduleBuilder.enterNode(rpcBuilder);
981 parseSchemaNodeArgs(ctx, rpcBuilder);
985 public void exitRpc_stmt(final YangParser.Rpc_stmtContext ctx) {
986 moduleBuilder.exitNode();
987 exitLog("rpc", stack.removeNodeFromPath());
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);
996 final QName rpcQName = QName.create(moduleQName, input);
997 final SchemaPath path = stack.addNodeToPath(rpcQName);
999 final ContainerSchemaNodeBuilder builder = moduleBuilder.addRpcInput(line, rpcQName, path);
1000 moduleBuilder.enterNode(builder);
1001 builder.setConfiguration(true);
1003 parseSchemaNodeArgs(ctx, builder);
1004 parseConstraints(ctx, builder.getConstraints());
1008 public void exitInput_stmt(final YangParser.Input_stmtContext ctx) {
1009 moduleBuilder.exitNode();
1010 exitLog("input", stack.removeNodeFromPath());
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);
1019 final QName rpcQName = QName.create(moduleQName, output);
1020 final SchemaPath path = stack.addNodeToPath(rpcQName);
1022 final ContainerSchemaNodeBuilder builder = moduleBuilder.addRpcOutput(path, rpcQName, line);
1023 moduleBuilder.enterNode(builder);
1024 builder.setConfiguration(true);
1026 parseSchemaNodeArgs(ctx, builder);
1027 parseConstraints(ctx, builder.getConstraints());
1031 public void exitOutput_stmt(final YangParser.Output_stmtContext ctx) {
1032 moduleBuilder.exitNode();
1033 exitLog("output", stack.removeNodeFromPath());
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);
1042 final QName featureQName = QName.create(moduleQName, featureName);
1043 final SchemaPath path = stack.addNodeToPath(featureQName);
1045 final FeatureBuilder featureBuilder = moduleBuilder.addFeature(line, featureQName, path);
1046 moduleBuilder.enterNode(featureBuilder);
1048 parseSchemaNodeArgs(ctx, featureBuilder);
1052 public void exitFeature_stmt(final YangParser.Feature_stmtContext ctx) {
1053 moduleBuilder.exitNode();
1054 exitLog("feature", stack.removeNodeFromPath());
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.");
1065 enterLog("deviation", targetPathStr, line);
1067 String reference = null;
1068 String deviate = null;
1070 final SchemaPath targetPath = parseXPathString(targetPathStr, line);
1071 final DeviationBuilder builder = moduleBuilder.addDeviation(line, targetPath);
1072 moduleBuilder.enterNode(builder);
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);
1088 builder.setReference(reference);
1089 builder.setDeviate(deviate);
1092 public SchemaPath parseXPathString(final String xpathString, final int line) {
1093 final boolean absolute = !xpathString.isEmpty() && xpathString.charAt(0) == '/';
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();
1100 path.add(parseQName(pathElement, line));
1102 path.add(QName.create(moduleQName, s));
1105 return SchemaPath.create(path, absolute);
1109 public void exitDeviation_stmt(final YangParser.Deviation_stmtContext ctx) {
1110 moduleBuilder.exitNode();
1111 exitLog("deviation");
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);
1120 final QName identityQName = QName.create(moduleQName, identityName);
1121 final SchemaPath path = stack.addNodeToPath(identityQName);
1123 final IdentitySchemaNodeBuilder builder = moduleBuilder.addIdentity(identityQName, line, path);
1124 moduleBuilder.enterNode(builder);
1126 parseSchemaNodeArgs(ctx, builder);
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);
1138 public void exitIdentity_stmt(final YangParser.Identity_stmtContext ctx) {
1139 moduleBuilder.exitNode();
1140 exitLog("identity", stack.removeNodeFromPath());
1143 public ModuleBuilder getModuleBuilder() {
1144 return moduleBuilder;
1147 private static void enterLog(final String p1, final String p2, final int line) {
1148 LOG.trace("entering {} {} ({})", p1, p2, line);
1151 private static void exitLog(final String p1) {
1152 LOG.trace("exiting {}", p1);
1155 private static void exitLog(final String p1, final QName p2) {
1156 LOG.trace("exiting {} {}", p1, p2.getLocalName());
1159 private static void setLog(final String p1, final String p2) {
1160 LOG.trace("setting {} {}", p1, p2);
1163 private void handleUnknownNode(final int line, final ParseTree ctx) {
1164 final String nodeParameter = stringFromNode(ctx);
1165 enterLog(UNKNOWN_NODE_STR, nodeParameter, line);
1167 final String nodeTypeStr = ctx.getChild(0).getText();
1168 final QName nodeType = parseQName(nodeTypeStr, line);
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
1178 // they are dependent!!!
1179 if (Strings.isNullOrEmpty(nodeParameter)) {
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);
1187 qname = QName.create(moduleQName, it.next());
1190 } catch (IllegalArgumentException | YangParseException ex) {
1194 final SchemaPath path = stack.addNodeToPath(qname);
1196 final UnknownSchemaNodeBuilderImpl builder = moduleBuilder.addUnknownSchemaNode(line, qname, path);
1197 builder.setNodeType(nodeType);
1198 builder.setNodeParameter(nodeParameter);
1200 parseSchemaNodeArgs(ctx, builder);
1201 moduleBuilder.enterNode(builder);