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.controller.yang.model.parser.impl;
10 import static org.opendaylight.controller.yang.model.parser.util.YangModelBuilderUtil.*;
13 import java.text.DateFormat;
14 import java.text.ParseException;
15 import java.text.SimpleDateFormat;
16 import java.util.Collections;
17 import java.util.Date;
18 import java.util.List;
19 import java.util.Stack;
21 import org.antlr.v4.runtime.tree.ParseTree;
22 import org.opendaylight.controller.antlrv4.code.gen.YangParser;
23 import org.opendaylight.controller.antlrv4.code.gen.YangParser.Contact_stmtContext;
24 import org.opendaylight.controller.antlrv4.code.gen.YangParser.Container_stmtContext;
25 import org.opendaylight.controller.antlrv4.code.gen.YangParser.Description_stmtContext;
26 import org.opendaylight.controller.antlrv4.code.gen.YangParser.Deviate_add_stmtContext;
27 import org.opendaylight.controller.antlrv4.code.gen.YangParser.Deviate_delete_stmtContext;
28 import org.opendaylight.controller.antlrv4.code.gen.YangParser.Deviate_not_supported_stmtContext;
29 import org.opendaylight.controller.antlrv4.code.gen.YangParser.Deviate_replace_stmtContext;
30 import org.opendaylight.controller.antlrv4.code.gen.YangParser.Import_stmtContext;
31 import org.opendaylight.controller.antlrv4.code.gen.YangParser.Key_stmtContext;
32 import org.opendaylight.controller.antlrv4.code.gen.YangParser.Leaf_list_stmtContext;
33 import org.opendaylight.controller.antlrv4.code.gen.YangParser.Leaf_stmtContext;
34 import org.opendaylight.controller.antlrv4.code.gen.YangParser.List_stmtContext;
35 import org.opendaylight.controller.antlrv4.code.gen.YangParser.Module_header_stmtsContext;
36 import org.opendaylight.controller.antlrv4.code.gen.YangParser.Namespace_stmtContext;
37 import org.opendaylight.controller.antlrv4.code.gen.YangParser.Ordered_by_stmtContext;
38 import org.opendaylight.controller.antlrv4.code.gen.YangParser.Organization_stmtContext;
39 import org.opendaylight.controller.antlrv4.code.gen.YangParser.Prefix_stmtContext;
40 import org.opendaylight.controller.antlrv4.code.gen.YangParser.Presence_stmtContext;
41 import org.opendaylight.controller.antlrv4.code.gen.YangParser.Reference_stmtContext;
42 import org.opendaylight.controller.antlrv4.code.gen.YangParser.Revision_date_stmtContext;
43 import org.opendaylight.controller.antlrv4.code.gen.YangParser.Revision_stmtContext;
44 import org.opendaylight.controller.antlrv4.code.gen.YangParser.Revision_stmtsContext;
45 import org.opendaylight.controller.antlrv4.code.gen.YangParser.Status_stmtContext;
46 import org.opendaylight.controller.antlrv4.code.gen.YangParser.Type_body_stmtsContext;
47 import org.opendaylight.controller.antlrv4.code.gen.YangParser.Yang_version_stmtContext;
48 import org.opendaylight.controller.antlrv4.code.gen.YangParserBaseListener;
49 import org.opendaylight.controller.model.util.YangTypesConverter;
50 import org.opendaylight.controller.yang.common.QName;
51 import org.opendaylight.controller.yang.model.api.Status;
52 import org.opendaylight.controller.yang.model.api.TypeDefinition;
53 import org.opendaylight.controller.yang.model.parser.builder.api.AugmentationSchemaBuilder;
54 import org.opendaylight.controller.yang.model.parser.builder.api.GroupingBuilder;
55 import org.opendaylight.controller.yang.model.parser.builder.impl.ContainerSchemaNodeBuilder;
56 import org.opendaylight.controller.yang.model.parser.builder.impl.DeviationBuilder;
57 import org.opendaylight.controller.yang.model.parser.builder.impl.ExtensionBuilder;
58 import org.opendaylight.controller.yang.model.parser.builder.impl.FeatureBuilder;
59 import org.opendaylight.controller.yang.model.parser.builder.impl.LeafListSchemaNodeBuilder;
60 import org.opendaylight.controller.yang.model.parser.builder.impl.LeafSchemaNodeBuilder;
61 import org.opendaylight.controller.yang.model.parser.builder.impl.ListSchemaNodeBuilder;
62 import org.opendaylight.controller.yang.model.parser.builder.impl.ModuleBuilder;
63 import org.opendaylight.controller.yang.model.parser.builder.impl.NotificationBuilder;
64 import org.opendaylight.controller.yang.model.parser.builder.impl.RpcDefinitionBuilder;
65 import org.opendaylight.controller.yang.model.parser.builder.impl.TypedefBuilder;
66 import org.opendaylight.controller.yang.model.parser.builder.impl.UnknownSchemaNodeBuilder;
67 import org.slf4j.Logger;
68 import org.slf4j.LoggerFactory;
70 final class YangModelParserListenerImpl extends YangParserBaseListener {
72 private static final Logger logger = LoggerFactory
73 .getLogger(YangModelParserListenerImpl.class);
75 private ModuleBuilder moduleBuilder;
77 private String moduleName;
78 private URI namespace;
79 private String yangModelPrefix;
80 private Date revision;
82 private final DateFormat simpleDateFormat = new SimpleDateFormat(
84 private final Stack<String> actualPath = new Stack<String>();
88 public void enterModule_stmt(YangParser.Module_stmtContext ctx) {
89 moduleName = stringFromNode(ctx);
90 actualPath.push(moduleName);
91 moduleBuilder = new ModuleBuilder(moduleName);
93 String description = null;
94 String reference = null;
96 for (int i = 0; i < ctx.getChildCount(); i++) {
97 ParseTree child = ctx.getChild(i);
98 if (child instanceof Description_stmtContext) {
99 description = stringFromNode(child);
100 } else if (child instanceof Reference_stmtContext) {
101 reference = stringFromNode(child);
103 if (description != null && reference != null) {
108 moduleBuilder.setDescription(description);
109 moduleBuilder.setReference(reference);
113 public void exitModule_stmt(YangParser.Module_stmtContext ctx) {
114 final String moduleName = actualPath.pop();
115 logger.debug("Exiting module " + moduleName);
119 public void enterModule_header_stmts(final Module_header_stmtsContext ctx) {
120 super.enterModule_header_stmts(ctx);
122 for (int i = 0; i < ctx.getChildCount(); ++i) {
123 final ParseTree treeNode = ctx.getChild(i);
124 if (treeNode instanceof Namespace_stmtContext) {
125 final String namespaceStr = stringFromNode(treeNode);
126 namespace = URI.create(namespaceStr);
127 moduleBuilder.setNamespace(namespace);
128 } else if (treeNode instanceof Prefix_stmtContext) {
129 yangModelPrefix = stringFromNode(treeNode);
130 moduleBuilder.setPrefix(yangModelPrefix);
131 } else if (treeNode instanceof Yang_version_stmtContext) {
132 final String yangVersion = stringFromNode(treeNode);
133 moduleBuilder.setYangVersion(yangVersion);
139 public void enterMeta_stmts(YangParser.Meta_stmtsContext ctx) {
140 for (int i = 0; i < ctx.getChildCount(); i++) {
141 ParseTree child = ctx.getChild(i);
142 if (child instanceof Organization_stmtContext) {
143 final String organization = stringFromNode(child);
144 moduleBuilder.setOrganization(organization);
145 } else if (child instanceof Contact_stmtContext) {
146 final String contact = stringFromNode(child);
147 moduleBuilder.setContact(contact);
148 } else if (child instanceof Description_stmtContext) {
149 final String description = stringFromNode(child);
150 moduleBuilder.setDescription(description);
151 } else if (child instanceof Reference_stmtContext) {
152 final String reference = stringFromNode(child);
153 moduleBuilder.setReference(reference);
159 public void exitSubmodule_header_stmts(
160 YangParser.Submodule_header_stmtsContext ctx) {
161 final String submodule = actualPath.pop();
162 logger.debug("exiting submodule " + submodule);
166 public void enterRevision_stmts(Revision_stmtsContext ctx) {
167 for (int i = 0; i < ctx.getChildCount(); ++i) {
168 final ParseTree treeNode = ctx.getChild(i);
169 if (treeNode instanceof Revision_stmtContext) {
170 final String revisionDateStr = stringFromNode(treeNode);
172 revision = simpleDateFormat.parse(revisionDateStr);
173 moduleBuilder.setRevision(revision);
174 } catch (ParseException e) {
175 final String message = "Failed to parse revision string: "+ revisionDateStr;
176 logger.warn(message);
183 public void enterImport_stmt(Import_stmtContext ctx) {
184 super.enterImport_stmt(ctx);
186 final String importName = stringFromNode(ctx);
187 String importPrefix = null;
188 Date importRevision = null;
190 for (int i = 0; i < ctx.getChildCount(); ++i) {
191 final ParseTree treeNode = ctx.getChild(i);
192 if (treeNode instanceof Prefix_stmtContext) {
193 importPrefix = stringFromNode(treeNode);
195 if (treeNode instanceof Revision_date_stmtContext) {
196 String importRevisionStr = stringFromNode(treeNode);
198 importRevision = simpleDateFormat.parse(importRevisionStr);
199 } catch(ParseException e) {
200 logger.warn("Failed to parse import revision-date: "+ importRevisionStr);
204 moduleBuilder.addModuleImport(importName, importRevision, importPrefix);
208 public void enterAugment_stmt(YangParser.Augment_stmtContext ctx) {
209 final String augmentPath = stringFromNode(ctx);
210 AugmentationSchemaBuilder builder = moduleBuilder.addAugment(
211 augmentPath, getActualPath());
212 updatePath(augmentPath);
214 for (int i = 0; i < ctx.getChildCount(); i++) {
215 ParseTree child = ctx.getChild(i);
216 if (child instanceof Description_stmtContext) {
217 String desc = stringFromNode(child);
218 builder.setDescription(desc);
219 } else if (child instanceof Reference_stmtContext) {
220 String ref = stringFromNode(child);
221 builder.setReference(ref);
222 } else if (child instanceof Status_stmtContext) {
223 Status status = parseStatus((Status_stmtContext) child);
224 builder.setStatus(status);
230 public void exitAugment_stmt(YangParser.Augment_stmtContext ctx) {
231 final String augment = actualPath.pop();
232 logger.debug("exiting augment " + augment);
236 public void enterExtension_stmt(YangParser.Extension_stmtContext ctx) {
237 String argument = stringFromNode(ctx);
238 QName qname = new QName(namespace, revision, yangModelPrefix, argument);
239 ExtensionBuilder builder = moduleBuilder.addExtension(qname);
240 parseSchemaNodeArgs(ctx, builder);
244 public void enterTypedef_stmt(YangParser.Typedef_stmtContext ctx) {
245 String typedefName = stringFromNode(ctx);
246 QName typedefQName = new QName(namespace, revision, yangModelPrefix,
248 TypedefBuilder builder = moduleBuilder.addTypedef(typedefQName,
250 updatePath(typedefName);
252 builder.setPath(createActualSchemaPath(actualPath, namespace, revision,
254 parseSchemaNodeArgs(ctx, builder);
255 builder.setUnits(parseUnits(ctx));
259 public void exitTypedef_stmt(YangParser.Typedef_stmtContext ctx) {
260 final String actContainer = actualPath.pop();
261 logger.debug("exiting " + actContainer);
265 public void enterType_stmt(YangParser.Type_stmtContext ctx) {
266 String typeName = stringFromNode(ctx);
268 if (typeName.contains(":")) {
269 String[] splittedName = typeName.split(":");
270 String prefix = splittedName[0];
271 String name = splittedName[1];
272 if (prefix.equals(yangModelPrefix)) {
273 typeQName = new QName(namespace, revision, prefix, name);
275 typeQName = new QName(null, null, prefix, name);
278 typeQName = new QName(namespace, revision, yangModelPrefix,
282 TypeDefinition<?> type = null;
283 Type_body_stmtsContext typeBody = null;
284 for (int i = 0; i < ctx.getChildCount(); i++) {
285 if (ctx.getChild(i) instanceof Type_body_stmtsContext) {
286 typeBody = (Type_body_stmtsContext) ctx.getChild(i);
291 // if this is base yang type...
292 if(YangTypesConverter.isBaseYangType(typeName)) {
293 if (typeBody == null) {
294 // if there are no constraints, just grab default base yang type
295 type = YangTypesConverter.javaTypeForBaseYangType(typeName);
297 type = parseTypeBody(typeName, typeBody, actualPath, namespace, revision, yangModelPrefix);
300 type = parseUnknownTypeBody(typeQName, typeBody);
301 // mark parent node of this type statement as dirty
302 moduleBuilder.addDirtyNode(actualPath);
305 moduleBuilder.setType(type, actualPath);
306 updatePath(typeName);
310 public void exitType_stmt(YangParser.Type_stmtContext ctx) {
311 final String actContainer = actualPath.pop();
312 logger.debug("exiting " + actContainer);
316 public void enterGrouping_stmt(YangParser.Grouping_stmtContext ctx) {
317 final String groupName = stringFromNode(ctx);
318 QName groupQName = new QName(namespace, revision, yangModelPrefix,
320 GroupingBuilder groupBuilder = moduleBuilder.addGrouping(groupQName,
322 updatePath("grouping");
323 updatePath(groupName);
324 parseSchemaNodeArgs(ctx, groupBuilder);
328 public void exitGrouping_stmt(YangParser.Grouping_stmtContext ctx) {
329 String actContainer = actualPath.pop();
330 actContainer += "-" + actualPath.pop();
331 logger.debug("exiting " + actContainer);
335 public void enterContainer_stmt(Container_stmtContext ctx) {
336 super.enterContainer_stmt(ctx);
337 String containerName = stringFromNode(ctx);
338 QName containerQName = new QName(namespace, revision, yangModelPrefix,
340 ContainerSchemaNodeBuilder containerBuilder = moduleBuilder
341 .addContainerNode(containerQName, actualPath);
342 updatePath(containerName);
344 containerBuilder.setPath(createActualSchemaPath(actualPath, namespace, revision, yangModelPrefix));
345 parseSchemaNodeArgs(ctx, containerBuilder);
346 parseConstraints(ctx, containerBuilder.getConstraintsBuilder());
348 for (int i = 0; i < ctx.getChildCount(); ++i) {
349 final ParseTree childNode = ctx.getChild(i);
350 if (childNode instanceof Presence_stmtContext) {
351 containerBuilder.setPresenceContainer(true);
358 public void exitContainer_stmt(Container_stmtContext ctx) {
359 super.exitContainer_stmt(ctx);
360 final String actContainer = actualPath.pop();
361 logger.debug("exiting " + actContainer);
365 public void enterLeaf_stmt(Leaf_stmtContext ctx) {
366 super.enterLeaf_stmt(ctx);
368 final String leafName = stringFromNode(ctx);
369 QName leafQName = new QName(namespace, revision, yangModelPrefix,
371 LeafSchemaNodeBuilder leafBuilder = moduleBuilder.addLeafNode(
372 leafQName, actualPath);
373 updatePath(leafName);
375 leafBuilder.setPath(createActualSchemaPath(actualPath, namespace, revision, yangModelPrefix));
376 parseSchemaNodeArgs(ctx, leafBuilder);
377 parseConstraints(ctx, leafBuilder.getConstraintsBuilder());
381 public void exitLeaf_stmt(YangParser.Leaf_stmtContext ctx) {
382 final String actLeaf = actualPath.pop();
383 logger.debug("exiting " + actLeaf);
387 public void enterUses_stmt(YangParser.Uses_stmtContext ctx) {
388 final String groupingPathStr = stringFromNode(ctx);
389 moduleBuilder.addUsesNode(groupingPathStr, actualPath);
390 updatePath(groupingPathStr);
394 public void exitUses_stmt(YangParser.Uses_stmtContext ctx) {
395 final String actContainer = actualPath.pop();
396 logger.debug("exiting " + actContainer);
400 public void enterLeaf_list_stmt(Leaf_list_stmtContext ctx) {
401 super.enterLeaf_list_stmt(ctx);
403 final String leafListName = stringFromNode(ctx);
404 QName leafListQName = new QName(namespace, revision, yangModelPrefix,
406 LeafListSchemaNodeBuilder leafListBuilder = moduleBuilder
407 .addLeafListNode(leafListQName, actualPath);
408 updatePath(leafListName);
410 parseSchemaNodeArgs(ctx, leafListBuilder);
411 parseConstraints(ctx, leafListBuilder.getConstraintsBuilder());
413 for (int i = 0; i < ctx.getChildCount(); ++i) {
414 final ParseTree childNode = ctx.getChild(i);
415 if (childNode instanceof Ordered_by_stmtContext) {
416 final Ordered_by_stmtContext orderedBy = (Ordered_by_stmtContext) childNode;
417 final boolean userOrdered = parseUserOrdered(orderedBy);
418 leafListBuilder.setUserOrdered(userOrdered);
425 public void exitLeaf_list_stmt(YangParser.Leaf_list_stmtContext ctx) {
426 final String actContainer = actualPath.pop();
427 logger.debug("exiting " + actContainer);
431 public void enterList_stmt(List_stmtContext ctx) {
432 super.enterList_stmt(ctx);
434 final String containerName = stringFromNode(ctx);
435 QName containerQName = new QName(namespace, revision, yangModelPrefix,
437 ListSchemaNodeBuilder listBuilder = moduleBuilder.addListNode(
438 containerQName, actualPath);
439 updatePath(containerName);
441 listBuilder.setPath(createActualSchemaPath(actualPath, namespace, revision, yangModelPrefix));
442 parseSchemaNodeArgs(ctx, listBuilder);
443 parseConstraints(ctx, listBuilder.getConstraintsBuilder());
445 String keyDefinition = "";
446 for (int i = 0; i < ctx.getChildCount(); ++i) {
447 ParseTree childNode = ctx.getChild(i);
448 if (childNode instanceof Ordered_by_stmtContext) {
449 final Ordered_by_stmtContext orderedBy = (Ordered_by_stmtContext) childNode;
450 final boolean userOrdered = parseUserOrdered(orderedBy);
451 listBuilder.setUserOrdered(userOrdered);
452 } else if (childNode instanceof Key_stmtContext) {
453 keyDefinition = stringFromNode(childNode);
454 List<QName> key = createListKey(keyDefinition, namespace,
455 revision, yangModelPrefix);
456 listBuilder.setKeyDefinition(key);
462 public void exitList_stmt(List_stmtContext ctx) {
463 final String actContainer = actualPath.pop();
464 logger.debug("exiting " + actContainer);
468 public void enterNotification_stmt(YangParser.Notification_stmtContext ctx) {
469 final String notificationName = stringFromNode(ctx);
470 QName notificationQName = new QName(namespace, revision,
471 yangModelPrefix, notificationName);
472 NotificationBuilder notificationBuilder = moduleBuilder
473 .addNotification(notificationQName, actualPath);
474 updatePath(notificationName);
476 notificationBuilder.setPath(createActualSchemaPath(actualPath, namespace,
477 revision, yangModelPrefix));
478 parseSchemaNodeArgs(ctx, notificationBuilder);
482 public void exitNotification_stmt(YangParser.Notification_stmtContext ctx) {
483 final String actContainer = actualPath.pop();
484 logger.debug("exiting " + actContainer);
489 public void enterIdentifier_stmt(YangParser.Identifier_stmtContext ctx) {
490 String name = stringFromNode(ctx);
494 String[] splittedName = name.split(":");
495 if(splittedName.length == 2) {
496 qname = new QName(null, null, splittedName[0], splittedName[1]);
498 qname = new QName(namespace, revision, yangModelPrefix, splittedName[0]);
501 qname = new QName(namespace, revision, yangModelPrefix, name);
504 UnknownSchemaNodeBuilder builder = moduleBuilder.addUnknownSchemaNode(qname, getActualPath());
507 builder.setPath(createActualSchemaPath(actualPath, namespace, revision, yangModelPrefix));
508 parseSchemaNodeArgs(ctx, builder);
512 public void exitIdentifier_stmt(YangParser.Identifier_stmtContext ctx) {
513 final String actContainer = actualPath.pop();
514 logger.debug("exiting " + actContainer);
518 public void enterRpc_stmt(YangParser.Rpc_stmtContext ctx) {
519 final String rpcName = stringFromNode(ctx);
520 QName rpcQName = new QName(namespace, revision, yangModelPrefix,
522 RpcDefinitionBuilder rpcBuilder = moduleBuilder.addRpc(rpcQName,
526 rpcBuilder.setPath(createActualSchemaPath(actualPath, namespace, revision,
528 parseSchemaNodeArgs(ctx, rpcBuilder);
532 public void exitRpc_stmt(YangParser.Rpc_stmtContext ctx) {
533 final String actContainer = actualPath.pop();
534 logger.debug("exiting " + actContainer);
538 public void enterInput_stmt(YangParser.Input_stmtContext ctx) {
543 public void exitInput_stmt(YangParser.Input_stmtContext ctx) {
544 final String actContainer = actualPath.pop();
545 logger.debug("exiting " + actContainer);
549 public void enterOutput_stmt(YangParser.Output_stmtContext ctx) {
550 updatePath("output");
554 public void exitOutput_stmt(YangParser.Output_stmtContext ctx) {
555 final String actContainer = actualPath.pop();
556 logger.debug("exiting " + actContainer);
560 public void enterFeature_stmt(YangParser.Feature_stmtContext ctx) {
561 final String featureName = stringFromNode(ctx);
562 QName featureQName = new QName(namespace, revision, yangModelPrefix,
564 FeatureBuilder featureBuilder = moduleBuilder.addFeature(featureQName,
566 updatePath(featureName);
568 featureBuilder.setPath(createActualSchemaPath(actualPath, namespace,
569 revision, yangModelPrefix));
570 parseSchemaNodeArgs(ctx, featureBuilder);
574 public void exitFeature_stmt(YangParser.Feature_stmtContext ctx) {
575 final String actContainer = actualPath.pop();
576 logger.debug("exiting " + actContainer);
580 public void enterDeviation_stmt(YangParser.Deviation_stmtContext ctx) {
581 final String targetPath = stringFromNode(ctx);
582 String reference = null;
583 String deviate = null;
584 DeviationBuilder builder = moduleBuilder.addDeviation(targetPath);
585 updatePath(targetPath);
587 for (int i = 0; i < ctx.getChildCount(); i++) {
588 ParseTree child = ctx.getChild(i);
589 if (child instanceof Reference_stmtContext) {
590 reference = stringFromNode(child);
591 } else if (child instanceof Deviate_not_supported_stmtContext) {
592 deviate = stringFromNode(child);
593 } else if (child instanceof Deviate_add_stmtContext) {
594 deviate = stringFromNode(child);
595 } else if (child instanceof Deviate_replace_stmtContext) {
596 deviate = stringFromNode(child);
597 } else if (child instanceof Deviate_delete_stmtContext) {
598 deviate = stringFromNode(child);
601 builder.setReference(reference);
602 builder.setDeviate(deviate);
606 public void exitDeviation_stmt(YangParser.Deviation_stmtContext ctx) {
607 final String actContainer = actualPath.pop();
608 logger.debug("exiting " + actContainer);
612 public void enterConfig_stmt(YangParser.Config_stmtContext ctx) {
613 boolean configuration = parseConfig(ctx);
614 moduleBuilder.addConfiguration(configuration, actualPath);
617 public ModuleBuilder getModuleBuilder() {
618 return moduleBuilder;
621 private void updatePath(String containerName) {
622 actualPath.push(containerName);
625 private List<String> getActualPath() {
626 return Collections.unmodifiableList(actualPath);