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.validator;
11 import java.net.URISyntaxException;
14 import org.antlr.v4.runtime.tree.ParseTree;
15 import org.opendaylight.controller.antlrv4.code.gen.YangParser;
16 import org.opendaylight.controller.antlrv4.code.gen.YangParser.Anyxml_stmtContext;
17 import org.opendaylight.controller.antlrv4.code.gen.YangParser.Argument_stmtContext;
18 import org.opendaylight.controller.antlrv4.code.gen.YangParser.Augment_stmtContext;
19 import org.opendaylight.controller.antlrv4.code.gen.YangParser.Base_stmtContext;
20 import org.opendaylight.controller.antlrv4.code.gen.YangParser.Belongs_to_stmtContext;
21 import org.opendaylight.controller.antlrv4.code.gen.YangParser.Case_stmtContext;
22 import org.opendaylight.controller.antlrv4.code.gen.YangParser.Choice_stmtContext;
23 import org.opendaylight.controller.antlrv4.code.gen.YangParser.Config_argContext;
24 import org.opendaylight.controller.antlrv4.code.gen.YangParser.Container_stmtContext;
25 import org.opendaylight.controller.antlrv4.code.gen.YangParser.Default_stmtContext;
26 import org.opendaylight.controller.antlrv4.code.gen.YangParser.Deviate_add_stmtContext;
27 import org.opendaylight.controller.antlrv4.code.gen.YangParser.Deviation_stmtContext;
28 import org.opendaylight.controller.antlrv4.code.gen.YangParser.Extension_stmtContext;
29 import org.opendaylight.controller.antlrv4.code.gen.YangParser.Feature_stmtContext;
30 import org.opendaylight.controller.antlrv4.code.gen.YangParser.Grouping_stmtContext;
31 import org.opendaylight.controller.antlrv4.code.gen.YangParser.Identity_stmtContext;
32 import org.opendaylight.controller.antlrv4.code.gen.YangParser.If_feature_stmtContext;
33 import org.opendaylight.controller.antlrv4.code.gen.YangParser.Import_stmtContext;
34 import org.opendaylight.controller.antlrv4.code.gen.YangParser.Include_stmtContext;
35 import org.opendaylight.controller.antlrv4.code.gen.YangParser.Key_stmtContext;
36 import org.opendaylight.controller.antlrv4.code.gen.YangParser.Leaf_list_stmtContext;
37 import org.opendaylight.controller.antlrv4.code.gen.YangParser.Leaf_stmtContext;
38 import org.opendaylight.controller.antlrv4.code.gen.YangParser.List_stmtContext;
39 import org.opendaylight.controller.antlrv4.code.gen.YangParser.Mandatory_argContext;
40 import org.opendaylight.controller.antlrv4.code.gen.YangParser.Mandatory_stmtContext;
41 import org.opendaylight.controller.antlrv4.code.gen.YangParser.Module_header_stmtsContext;
42 import org.opendaylight.controller.antlrv4.code.gen.YangParser.Module_stmtContext;
43 import org.opendaylight.controller.antlrv4.code.gen.YangParser.Namespace_stmtContext;
44 import org.opendaylight.controller.antlrv4.code.gen.YangParser.Notification_stmtContext;
45 import org.opendaylight.controller.antlrv4.code.gen.YangParser.Ordered_by_argContext;
46 import org.opendaylight.controller.antlrv4.code.gen.YangParser.Prefix_stmtContext;
47 import org.opendaylight.controller.antlrv4.code.gen.YangParser.Refine_stmtContext;
48 import org.opendaylight.controller.antlrv4.code.gen.YangParser.Revision_date_stmtContext;
49 import org.opendaylight.controller.antlrv4.code.gen.YangParser.Revision_stmtContext;
50 import org.opendaylight.controller.antlrv4.code.gen.YangParser.Rpc_stmtContext;
51 import org.opendaylight.controller.antlrv4.code.gen.YangParser.Status_argContext;
52 import org.opendaylight.controller.antlrv4.code.gen.YangParser.Submodule_header_stmtsContext;
53 import org.opendaylight.controller.antlrv4.code.gen.YangParser.Submodule_stmtContext;
54 import org.opendaylight.controller.antlrv4.code.gen.YangParser.Type_stmtContext;
55 import org.opendaylight.controller.antlrv4.code.gen.YangParser.Typedef_stmtContext;
56 import org.opendaylight.controller.antlrv4.code.gen.YangParser.Unique_stmtContext;
57 import org.opendaylight.controller.antlrv4.code.gen.YangParser.Uses_stmtContext;
58 import org.opendaylight.controller.antlrv4.code.gen.YangParser.Yin_element_argContext;
59 import org.opendaylight.controller.antlrv4.code.gen.YangParserBaseListener;
60 import org.opendaylight.controller.yang.parser.impl.YangParserListenerImpl;
61 import org.slf4j.Logger;
62 import org.slf4j.LoggerFactory;
64 import com.google.common.collect.Sets;
67 * Validation listener that validates yang statements according to RFC-6020.
68 * This validator expects only one module or submodule per file and performs
69 * only basic validation where context from all yang models is not present.
71 final class YangModelBasicValidationListener extends YangParserBaseListener {
73 private static final Logger logger = LoggerFactory
74 .getLogger(YangModelBasicValidationListener.class);
76 private final Set<String> uniquePrefixes;
77 private final Set<String> uniqueImports;
78 private final Set<String> uniqueIncludes;
80 private String globalModuleId;
82 YangModelBasicValidationListener() {
84 uniquePrefixes = Sets.newHashSet();
85 uniqueImports = Sets.newHashSet();
86 uniqueIncludes = Sets.newHashSet();
92 * <li>Identifier is in required format</li>
93 * <li>Header statements present(mandatory prefix and namespace statements
95 * <li>Only one module or submodule per file</li>
99 public void enterModule_stmt(Module_stmtContext ctx) {
101 BasicValidations.checkIdentifier(ctx);
103 BasicValidations.checkPresentChildOfType(ctx,
104 Module_header_stmtsContext.class, true);
106 String moduleName = ValidationUtil.getName(ctx);
107 BasicValidations.checkOnlyOneModulePresent(moduleName, globalModuleId);
108 globalModuleId = moduleName;
114 * <li>Identifier is in required format</li>
115 * <li>Header statements present(mandatory belongs-to statement is in
117 * <li>Only one module or submodule per file</li>
121 public void enterSubmodule_stmt(Submodule_stmtContext ctx) {
123 BasicValidations.checkIdentifier(ctx);
125 BasicValidations.checkPresentChildOfType(ctx,
126 Submodule_header_stmtsContext.class, true);
128 String submoduleName = ValidationUtil.getName(ctx);
129 BasicValidations.checkOnlyOneModulePresent(submoduleName,
131 globalModuleId = submoduleName;
138 * <li>One Belongs-to statement present</li>
142 public void enterSubmodule_header_stmts(Submodule_header_stmtsContext ctx) {
143 BasicValidations.checkPresentChildOfType(ctx,
144 Belongs_to_stmtContext.class, true);
146 // check Yang version present, if not log
148 BasicValidations.checkPresentYangVersion(ctx,
149 ValidationUtil.getRootParentName(ctx));
150 } catch (Exception e) {
151 logger.debug(e.getMessage());
158 * <li>One Namespace statement present</li>
159 * <li>One Prefix statement present</li>
163 public void enterModule_header_stmts(Module_header_stmtsContext ctx) {
164 String moduleName = ValidationUtil.getRootParentName(ctx);
166 BasicValidations.checkPresentChildOfType(ctx,
167 Namespace_stmtContext.class, true);
168 BasicValidations.checkPresentChildOfType(ctx, Prefix_stmtContext.class,
171 // check Yang version present, if not log
173 BasicValidations.checkPresentYangVersion(ctx, moduleName);
174 } catch (Exception e) {
175 logger.debug(e.getMessage());
182 * <li>Date is in valid format</li>
186 public void enterRevision_stmt(Revision_stmtContext ctx) {
187 BasicValidations.checkDateFormat(ctx,
188 YangParserListenerImpl.simpleDateFormat);
195 * <li>Identifier is in required format</li>
196 * <li>One Prefix statement child</li>
200 public void enterBelongs_to_stmt(Belongs_to_stmtContext ctx) {
201 BasicValidations.checkIdentifier(ctx);
203 BasicValidations.checkPresentChildOfType(ctx, Prefix_stmtContext.class,
210 * <li>Namespace string can be parsed as URI</li>
214 public void enterNamespace_stmt(Namespace_stmtContext ctx) {
215 String namespaceName = ValidationUtil.getName(ctx);
216 String rootParentName = ValidationUtil.getRootParentName(ctx);
219 new URI(namespaceName);
220 } catch (URISyntaxException e) {
221 ValidationUtil.ex(ValidationUtil.f(
222 "(In module:%s) Namespace:%s cannot be parsed as URI",
223 rootParentName, namespaceName));
230 * <li>Identifier is in required format</li>
231 * <li>Every import(identified by identifier) within a module/submodule is
232 * present only once</li>
233 * <li>One prefix statement child</li>
237 public void enterImport_stmt(Import_stmtContext ctx) {
239 BasicValidations.checkIdentifier(ctx);
241 BasicValidations.checkUniquenessInNamespace(ctx, uniqueImports);
243 BasicValidations.checkPresentChildOfType(ctx, Prefix_stmtContext.class,
251 * <li>Date is in valid format</li>
255 public void enterRevision_date_stmt(Revision_date_stmtContext ctx) {
256 BasicValidations.checkDateFormat(ctx,
257 YangParserListenerImpl.simpleDateFormat);
263 * <li>Identifier is in required format</li>
264 * <li>Every include(identified by identifier) within a module/submodule is
265 * present only once</li>
269 public void enterInclude_stmt(Include_stmtContext ctx) {
271 BasicValidations.checkIdentifier(ctx);
273 BasicValidations.checkUniquenessInNamespace(ctx, uniqueIncludes);
279 * <li>Yang-version is specified as 1</li>
283 public void enterYang_version_stmt(YangParser.Yang_version_stmtContext ctx) {
284 String version = ValidationUtil.getName(ctx);
285 String rootParentName = ValidationUtil.getRootParentName(ctx);
286 if (!version.equals(BasicValidations.SUPPORTED_YANG_VERSION)) {
289 .f("(In (sub)module:%s) Unsupported yang version:%s, supported version:%s",
290 rootParentName, version,
291 BasicValidations.SUPPORTED_YANG_VERSION));
298 * <li>Identifier is in required format</li>
299 * <li>Every prefix(identified by identifier) within a module/submodule is
300 * presented only once</li>
304 public void enterPrefix_stmt(Prefix_stmtContext ctx) {
306 BasicValidations.checkIdentifier(ctx);
308 BasicValidations.checkUniquenessInNamespace(ctx, uniquePrefixes);
314 * <li>Identifier is in required format</li>
315 * <li>One type statement child</li>
319 public void enterTypedef_stmt(Typedef_stmtContext ctx) {
321 BasicValidations.checkIdentifier(ctx);
323 BasicValidations.checkPresentChildOfType(ctx, Type_stmtContext.class,
330 * <li>(Prefix):Identifier is in required format</li>
334 public void enterType_stmt(Type_stmtContext ctx) {
335 BasicValidations.checkPrefixedIdentifier(ctx);
341 * <li>Identifier is in required format</li>
345 public void enterContainer_stmt(Container_stmtContext ctx) {
346 BasicValidations.checkIdentifier(ctx);
352 * <li>Identifier is in required format</li>
353 * <li>One type statement child</li>
354 * <li>Default statement must not be present if mandatory statement is</li>
358 public void enterLeaf_stmt(Leaf_stmtContext ctx) {
359 BasicValidations.checkIdentifier(ctx);
361 BasicValidations.checkPresentChildOfType(ctx, Type_stmtContext.class,
364 BasicValidations.checkNotPresentBoth(ctx, Mandatory_stmtContext.class,
365 Default_stmtContext.class);
371 * <li>Identifier is in required format</li>
372 * <li>One type statement child</li>
376 public void enterLeaf_list_stmt(Leaf_list_stmtContext ctx) {
378 BasicValidations.checkIdentifier(ctx);
380 BasicValidations.checkPresentChildOfType(ctx, Type_stmtContext.class,
384 private static final Set<String> permittedOrderByArgs = Sets.newHashSet(
390 * <li>Value must be one of: system, user</li>
394 public void enterOrdered_by_arg(Ordered_by_argContext ctx) {
395 BasicValidations.checkOnlyPermittedValues(ctx, permittedOrderByArgs);
401 * <li>Identifier is in required format</li>
405 public void enterList_stmt(List_stmtContext ctx) {
406 BasicValidations.checkIdentifier(ctx);
407 // TODO check: "if config==true then key must be present" could be
414 * <li>No duplicate keys</li>
418 public void enterKey_stmt(Key_stmtContext ctx) {
419 BasicValidations.getAndCheckUniqueKeys(ctx);
425 * <liNo duplicate uniques</li>
429 public void enterUnique_stmt(Unique_stmtContext ctx) {
430 BasicValidations.getAndCheckUniqueKeys(ctx);
436 * <li>Identifier is in required format</li>
437 * <li>Default statement must not be present if mandatory statement is</li>
441 public void enterChoice_stmt(Choice_stmtContext ctx) {
442 BasicValidations.checkIdentifier(ctx);
444 BasicValidations.checkNotPresentBoth(ctx, Mandatory_stmtContext.class,
445 Default_stmtContext.class);
452 * <li>Identifier is in required format</li>
456 public void enterCase_stmt(Case_stmtContext ctx) {
457 BasicValidations.checkIdentifier(ctx);
460 private static final Set<String> permittedBooleanArgs = Sets.newHashSet(
466 * <li>Value must be one of: true, false</li>
470 public void enterMandatory_arg(Mandatory_argContext ctx) {
471 BasicValidations.checkOnlyPermittedValues(ctx, permittedBooleanArgs);
477 * <li>Identifier is in required format</li>
481 public void enterAnyxml_stmt(Anyxml_stmtContext ctx) {
482 BasicValidations.checkIdentifier(ctx);
488 * <li>Identifier is in required format</li>
492 public void enterGrouping_stmt(Grouping_stmtContext ctx) {
493 BasicValidations.checkIdentifier(ctx);
499 * <li>(Prefix):Identifier is in required format</li>
503 public void enterUses_stmt(Uses_stmtContext ctx) {
504 BasicValidations.checkPrefixedIdentifier(ctx);
510 * <li>Identifier is in required format</li>
514 public void enterRefine_stmt(Refine_stmtContext ctx) {
515 BasicValidations.checkIdentifier(ctx);
521 * <li>Identifier is in required format</li>
525 public void enterRpc_stmt(Rpc_stmtContext ctx) {
526 BasicValidations.checkIdentifier(ctx);
532 * <li>Identifier is in required format</li>
536 public void enterNotification_stmt(Notification_stmtContext ctx) {
537 BasicValidations.checkIdentifier(ctx);
543 * <li>Schema Node Identifier is in required format</li>
547 public void enterAugment_stmt(Augment_stmtContext ctx) {
548 BasicValidations.checkSchemaNodeIdentifier(ctx);
554 * <li>Identifier is in required format</li>
558 public void enterIdentity_stmt(Identity_stmtContext ctx) {
559 BasicValidations.checkIdentifier(ctx);
565 * <li>(Prefix):Identifier is in required format</li>
569 public void enterBase_stmt(Base_stmtContext ctx) {
570 BasicValidations.checkPrefixedIdentifier(ctx);
577 * <li>Value must be one of: true, false</li>
581 public void enterYin_element_arg(Yin_element_argContext ctx) {
582 BasicValidations.checkOnlyPermittedValues(ctx, permittedBooleanArgs);
588 * <li>Identifier is in required format</li>
592 public void enterExtension_stmt(Extension_stmtContext ctx) {
593 BasicValidations.checkIdentifier(ctx);
599 * <li>Identifier is in required format</li>
603 public void enterArgument_stmt(Argument_stmtContext ctx) {
604 BasicValidations.checkIdentifier(ctx);
610 * <li>Identifier is in required format</li>
614 public void enterFeature_stmt(Feature_stmtContext ctx) {
615 BasicValidations.checkIdentifier(ctx);
622 * <li>(Prefix):Identifier is in required format</li>
626 public void enterIf_feature_stmt(If_feature_stmtContext ctx) {
627 BasicValidations.checkPrefixedIdentifier(ctx);
633 * <li>Schema Node Identifier is in required format</li>
634 * <li>At least one deviate-* statement child</li>
638 public void enterDeviation_stmt(Deviation_stmtContext ctx) {
639 BasicValidations.checkSchemaNodeIdentifier(ctx);
641 Set<Class<? extends ParseTree>> types = Sets.newHashSet();
642 types.add(Deviate_add_stmtContext.class);
643 types.add(Deviate_add_stmtContext.class);
644 BasicValidations.checkPresentChildOfTypes(ctx, types, false);
650 * <li>Value must be one of: true, false</li>
654 public void enterConfig_arg(Config_argContext ctx) {
655 BasicValidations.checkOnlyPermittedValues(ctx, permittedBooleanArgs);
658 private static final Set<String> permittedStatusArgs = Sets.newHashSet(
659 "current", "deprecated", "obsolete");
664 * <li>Value must be one of: "current", "deprecated", "obsolete"</li>
668 public void enterStatus_arg(Status_argContext ctx) {
669 BasicValidations.checkOnlyPermittedValues(ctx, permittedStatusArgs);