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.validator;
11 import java.net.URISyntaxException;
14 import org.antlr.v4.runtime.tree.ParseTree;
15 import org.opendaylight.yangtools.antlrv4.code.gen.*;
16 import org.opendaylight.yangtools.antlrv4.code.gen.YangParser.Anyxml_stmtContext;
17 import org.opendaylight.yangtools.antlrv4.code.gen.YangParser.Argument_stmtContext;
18 import org.opendaylight.yangtools.antlrv4.code.gen.YangParser.Augment_stmtContext;
19 import org.opendaylight.yangtools.antlrv4.code.gen.YangParser.Base_stmtContext;
20 import org.opendaylight.yangtools.antlrv4.code.gen.YangParser.Belongs_to_stmtContext;
21 import org.opendaylight.yangtools.antlrv4.code.gen.YangParser.Case_stmtContext;
22 import org.opendaylight.yangtools.antlrv4.code.gen.YangParser.Choice_stmtContext;
23 import org.opendaylight.yangtools.antlrv4.code.gen.YangParser.Config_argContext;
24 import org.opendaylight.yangtools.antlrv4.code.gen.YangParser.Container_stmtContext;
25 import org.opendaylight.yangtools.antlrv4.code.gen.YangParser.Default_stmtContext;
26 import org.opendaylight.yangtools.antlrv4.code.gen.YangParser.Deviate_add_stmtContext;
27 import org.opendaylight.yangtools.antlrv4.code.gen.YangParser.Deviation_stmtContext;
28 import org.opendaylight.yangtools.antlrv4.code.gen.YangParser.Extension_stmtContext;
29 import org.opendaylight.yangtools.antlrv4.code.gen.YangParser.Feature_stmtContext;
30 import org.opendaylight.yangtools.antlrv4.code.gen.YangParser.Grouping_stmtContext;
31 import org.opendaylight.yangtools.antlrv4.code.gen.YangParser.Identity_stmtContext;
32 import org.opendaylight.yangtools.antlrv4.code.gen.YangParser.If_feature_stmtContext;
33 import org.opendaylight.yangtools.antlrv4.code.gen.YangParser.Import_stmtContext;
34 import org.opendaylight.yangtools.antlrv4.code.gen.YangParser.Include_stmtContext;
35 import org.opendaylight.yangtools.antlrv4.code.gen.YangParser.Key_stmtContext;
36 import org.opendaylight.yangtools.antlrv4.code.gen.YangParser.Leaf_list_stmtContext;
37 import org.opendaylight.yangtools.antlrv4.code.gen.YangParser.Leaf_stmtContext;
38 import org.opendaylight.yangtools.antlrv4.code.gen.YangParser.List_stmtContext;
39 import org.opendaylight.yangtools.antlrv4.code.gen.YangParser.Mandatory_argContext;
40 import org.opendaylight.yangtools.antlrv4.code.gen.YangParser.Mandatory_stmtContext;
41 import org.opendaylight.yangtools.antlrv4.code.gen.YangParser.Module_header_stmtsContext;
42 import org.opendaylight.yangtools.antlrv4.code.gen.YangParser.Module_stmtContext;
43 import org.opendaylight.yangtools.antlrv4.code.gen.YangParser.Namespace_stmtContext;
44 import org.opendaylight.yangtools.antlrv4.code.gen.YangParser.Notification_stmtContext;
45 import org.opendaylight.yangtools.antlrv4.code.gen.YangParser.Ordered_by_argContext;
46 import org.opendaylight.yangtools.antlrv4.code.gen.YangParser.Prefix_stmtContext;
47 import org.opendaylight.yangtools.antlrv4.code.gen.YangParser.Refine_stmtContext;
48 import org.opendaylight.yangtools.antlrv4.code.gen.YangParser.Revision_date_stmtContext;
49 import org.opendaylight.yangtools.antlrv4.code.gen.YangParser.Revision_stmtContext;
50 import org.opendaylight.yangtools.antlrv4.code.gen.YangParser.Rpc_stmtContext;
51 import org.opendaylight.yangtools.antlrv4.code.gen.YangParser.Status_argContext;
52 import org.opendaylight.yangtools.antlrv4.code.gen.YangParser.Submodule_header_stmtsContext;
53 import org.opendaylight.yangtools.antlrv4.code.gen.YangParser.Submodule_stmtContext;
54 import org.opendaylight.yangtools.antlrv4.code.gen.YangParser.Type_stmtContext;
55 import org.opendaylight.yangtools.antlrv4.code.gen.YangParser.Typedef_stmtContext;
56 import org.opendaylight.yangtools.antlrv4.code.gen.YangParser.Unique_stmtContext;
57 import org.opendaylight.yangtools.antlrv4.code.gen.YangParser.Uses_stmtContext;
58 import org.opendaylight.yangtools.antlrv4.code.gen.YangParser.Yin_element_argContext;
59 import org.opendaylight.yangtools.yang.parser.impl.YangParserListenerImpl;
60 import org.slf4j.Logger;
61 import org.slf4j.LoggerFactory;
63 import com.google.common.collect.Sets;
66 * Validation listener that validates yang statements according to RFC-6020.
67 * This validator expects only one module or submodule per file and performs
68 * only basic validation where context from all yang models is not present.
70 final class YangModelBasicValidationListener extends YangParserBaseListener {
72 private static final Logger LOGGER = LoggerFactory.getLogger(YangModelBasicValidationListener.class);
74 private final Set<String> uniquePrefixes;
75 private final Set<String> uniqueImports;
76 private final Set<String> uniqueIncludes;
78 private String globalModuleId;
80 YangModelBasicValidationListener() {
82 uniquePrefixes = Sets.newHashSet();
83 uniqueImports = Sets.newHashSet();
84 uniqueIncludes = Sets.newHashSet();
90 * <li>Identifier is in required format</li>
91 * <li>Header statements present(mandatory prefix and namespace statements
93 * <li>Only one module or submodule per file</li>
97 public void enterModule_stmt(Module_stmtContext ctx) {
99 BasicValidations.checkIdentifier(ctx);
101 BasicValidations.checkPresentChildOfType(ctx, Module_header_stmtsContext.class, true);
103 String moduleName = ValidationUtil.getName(ctx);
104 BasicValidations.checkOnlyOneModulePresent(moduleName, globalModuleId);
105 globalModuleId = moduleName;
111 * <li>Identifier is in required format</li>
112 * <li>Header statements present(mandatory belongs-to statement is in
114 * <li>Only one module or submodule per file</li>
118 public void enterSubmodule_stmt(Submodule_stmtContext ctx) {
120 BasicValidations.checkIdentifier(ctx);
122 BasicValidations.checkPresentChildOfType(ctx, Submodule_header_stmtsContext.class, true);
124 String submoduleName = ValidationUtil.getName(ctx);
125 BasicValidations.checkOnlyOneModulePresent(submoduleName, globalModuleId);
126 globalModuleId = submoduleName;
133 * <li>One Belongs-to statement present</li>
137 public void enterSubmodule_header_stmts(Submodule_header_stmtsContext ctx) {
138 BasicValidations.checkPresentChildOfType(ctx, Belongs_to_stmtContext.class, true);
140 // check Yang version present, if not log
142 BasicValidations.checkPresentYangVersion(ctx, ValidationUtil.getRootParentName(ctx));
143 } catch (Exception e) {
144 LOGGER.debug(e.getMessage());
151 * <li>One Namespace statement present</li>
152 * <li>One Prefix statement present</li>
156 public void enterModule_header_stmts(Module_header_stmtsContext ctx) {
157 String moduleName = ValidationUtil.getRootParentName(ctx);
159 BasicValidations.checkPresentChildOfType(ctx, Namespace_stmtContext.class, true);
160 BasicValidations.checkPresentChildOfType(ctx, Prefix_stmtContext.class, true);
162 // check Yang version present, if not log
164 BasicValidations.checkPresentYangVersion(ctx, moduleName);
165 } catch (Exception e) {
166 LOGGER.debug(e.getMessage());
173 * <li>Date is in valid format</li>
177 public void enterRevision_stmt(Revision_stmtContext ctx) {
178 BasicValidations.checkDateFormat(ctx, YangParserListenerImpl.SIMPLE_DATE_FORMAT);
185 * <li>Identifier is in required format</li>
186 * <li>One Prefix statement child</li>
190 public void enterBelongs_to_stmt(Belongs_to_stmtContext ctx) {
191 BasicValidations.checkIdentifier(ctx);
193 BasicValidations.checkPresentChildOfType(ctx, Prefix_stmtContext.class, true);
199 * <li>Namespace string can be parsed as URI</li>
203 public void enterNamespace_stmt(Namespace_stmtContext ctx) {
204 String namespaceName = ValidationUtil.getName(ctx);
205 String rootParentName = ValidationUtil.getRootParentName(ctx);
208 new URI(namespaceName);
209 } catch (URISyntaxException e) {
210 ValidationUtil.ex(ValidationUtil.f("(In module:%s) Namespace:%s cannot be parsed as URI", rootParentName,
218 * <li>Identifier is in required format</li>
219 * <li>Every import(identified by identifier) within a module/submodule is
220 * present only once</li>
221 * <li>One prefix statement child</li>
225 public void enterImport_stmt(Import_stmtContext ctx) {
227 BasicValidations.checkIdentifier(ctx);
229 BasicValidations.checkUniquenessInNamespace(ctx, uniqueImports);
231 BasicValidations.checkPresentChildOfType(ctx, Prefix_stmtContext.class, true);
238 * <li>Date is in valid format</li>
242 public void enterRevision_date_stmt(Revision_date_stmtContext ctx) {
243 BasicValidations.checkDateFormat(ctx, YangParserListenerImpl.SIMPLE_DATE_FORMAT);
249 * <li>Identifier is in required format</li>
250 * <li>Every include(identified by identifier) within a module/submodule is
251 * present only once</li>
255 public void enterInclude_stmt(Include_stmtContext ctx) {
257 BasicValidations.checkIdentifier(ctx);
259 BasicValidations.checkUniquenessInNamespace(ctx, uniqueIncludes);
265 * <li>Yang-version is specified as 1</li>
269 public void enterYang_version_stmt(YangParser.Yang_version_stmtContext ctx) {
270 String version = ValidationUtil.getName(ctx);
271 String rootParentName = ValidationUtil.getRootParentName(ctx);
272 if (!version.equals(BasicValidations.SUPPORTED_YANG_VERSION)) {
273 ValidationUtil.ex(ValidationUtil.f("(In (sub)module:%s) Unsupported yang version:%s, supported version:%s",
274 rootParentName, version, BasicValidations.SUPPORTED_YANG_VERSION));
281 * <li>Identifier is in required format</li>
282 * <li>Every prefix(identified by identifier) within a module/submodule is
283 * presented only once</li>
287 public void enterPrefix_stmt(Prefix_stmtContext ctx) {
289 BasicValidations.checkIdentifier(ctx);
291 BasicValidations.checkUniquenessInNamespace(ctx, uniquePrefixes);
297 * <li>Identifier is in required format</li>
298 * <li>One type statement child</li>
302 public void enterTypedef_stmt(Typedef_stmtContext ctx) {
304 BasicValidations.checkIdentifier(ctx);
306 BasicValidations.checkPresentChildOfType(ctx, Type_stmtContext.class, true);
312 * <li>(Prefix):Identifier is in required format</li>
316 public void enterType_stmt(Type_stmtContext ctx) {
317 BasicValidations.checkPrefixedIdentifier(ctx);
323 * <li>Identifier is in required format</li>
327 public void enterContainer_stmt(Container_stmtContext ctx) {
328 BasicValidations.checkIdentifier(ctx);
334 * <li>Identifier is in required format</li>
335 * <li>One type statement child</li>
336 * <li>Default statement must not be present if mandatory statement is</li>
340 public void enterLeaf_stmt(Leaf_stmtContext ctx) {
341 BasicValidations.checkIdentifier(ctx);
343 BasicValidations.checkPresentChildOfType(ctx, Type_stmtContext.class, true);
345 BasicValidations.checkNotPresentBoth(ctx, Mandatory_stmtContext.class, Default_stmtContext.class);
351 * <li>Identifier is in required format</li>
352 * <li>One type statement child</li>
356 public void enterLeaf_list_stmt(Leaf_list_stmtContext ctx) {
358 BasicValidations.checkIdentifier(ctx);
360 BasicValidations.checkPresentChildOfType(ctx, Type_stmtContext.class, true);
363 private static final Set<String> PERMITTED_ORDER_BY_ARGS = Sets.newHashSet("system", "user");
368 * <li>Value must be one of: system, user</li>
372 public void enterOrdered_by_arg(Ordered_by_argContext ctx) {
373 BasicValidations.checkOnlyPermittedValues(ctx, PERMITTED_ORDER_BY_ARGS);
379 * <li>Identifier is in required format</li>
383 public void enterList_stmt(List_stmtContext ctx) {
384 BasicValidations.checkIdentifier(ctx);
385 // TODO check: "if config==true then key must be present" could be
392 * <li>No duplicate keys</li>
396 public void enterKey_stmt(Key_stmtContext ctx) {
397 BasicValidations.getAndCheckUniqueKeys(ctx);
403 * <liNo duplicate uniques</li>
407 public void enterUnique_stmt(Unique_stmtContext ctx) {
408 BasicValidations.getAndCheckUniqueKeys(ctx);
414 * <li>Identifier is in required format</li>
415 * <li>Default statement must not be present if mandatory statement is</li>
419 public void enterChoice_stmt(Choice_stmtContext ctx) {
420 BasicValidations.checkIdentifier(ctx);
422 BasicValidations.checkNotPresentBoth(ctx, Mandatory_stmtContext.class, Default_stmtContext.class);
429 * <li>Identifier is in required format</li>
433 public void enterCase_stmt(Case_stmtContext ctx) {
434 BasicValidations.checkIdentifier(ctx);
437 private static final Set<String> PERMITTED_BOOLEAN_ARGS = Sets.newHashSet("true", "false");
442 * <li>Value must be one of: true, false</li>
446 public void enterMandatory_arg(Mandatory_argContext ctx) {
447 BasicValidations.checkOnlyPermittedValues(ctx, PERMITTED_BOOLEAN_ARGS);
453 * <li>Identifier is in required format</li>
457 public void enterAnyxml_stmt(Anyxml_stmtContext ctx) {
458 BasicValidations.checkIdentifier(ctx);
464 * <li>Identifier is in required format</li>
468 public void enterGrouping_stmt(Grouping_stmtContext ctx) {
469 BasicValidations.checkIdentifier(ctx);
475 * <li>(Prefix):Identifier is in required format</li>
479 public void enterUses_stmt(Uses_stmtContext ctx) {
480 BasicValidations.checkPrefixedIdentifier(ctx);
486 * <li>Identifier is in required format</li>
490 public void enterRefine_stmt(Refine_stmtContext ctx) {
491 BasicValidations.checkIdentifier(ctx);
497 * <li>Identifier is in required format</li>
501 public void enterRpc_stmt(Rpc_stmtContext ctx) {
502 BasicValidations.checkIdentifier(ctx);
508 * <li>Identifier is in required format</li>
512 public void enterNotification_stmt(Notification_stmtContext ctx) {
513 BasicValidations.checkIdentifier(ctx);
519 * <li>Schema Node Identifier is in required format</li>
523 public void enterAugment_stmt(Augment_stmtContext ctx) {
524 BasicValidations.checkSchemaNodeIdentifier(ctx);
530 * <li>Identifier is in required format</li>
534 public void enterIdentity_stmt(Identity_stmtContext ctx) {
535 BasicValidations.checkIdentifier(ctx);
541 * <li>(Prefix):Identifier is in required format</li>
545 public void enterBase_stmt(Base_stmtContext ctx) {
546 BasicValidations.checkPrefixedIdentifier(ctx);
553 * <li>Value must be one of: true, false</li>
557 public void enterYin_element_arg(Yin_element_argContext ctx) {
558 BasicValidations.checkOnlyPermittedValues(ctx, PERMITTED_BOOLEAN_ARGS);
564 * <li>Identifier is in required format</li>
568 public void enterExtension_stmt(Extension_stmtContext ctx) {
569 BasicValidations.checkIdentifier(ctx);
575 * <li>Identifier is in required format</li>
579 public void enterArgument_stmt(Argument_stmtContext ctx) {
580 BasicValidations.checkIdentifier(ctx);
586 * <li>Identifier is in required format</li>
590 public void enterFeature_stmt(Feature_stmtContext ctx) {
591 BasicValidations.checkIdentifier(ctx);
598 * <li>(Prefix):Identifier is in required format</li>
602 public void enterIf_feature_stmt(If_feature_stmtContext ctx) {
603 BasicValidations.checkPrefixedIdentifier(ctx);
609 * <li>Schema Node Identifier is in required format</li>
610 * <li>At least one deviate-* statement child</li>
614 public void enterDeviation_stmt(Deviation_stmtContext ctx) {
615 BasicValidations.checkSchemaNodeIdentifier(ctx);
617 Set<Class<? extends ParseTree>> types = Sets.newHashSet();
618 types.add(Deviate_add_stmtContext.class);
619 types.add(Deviate_add_stmtContext.class);
620 BasicValidations.checkPresentChildOfTypes(ctx, types, false);
626 * <li>Value must be one of: true, false</li>
630 public void enterConfig_arg(Config_argContext ctx) {
631 BasicValidations.checkOnlyPermittedValues(ctx, PERMITTED_BOOLEAN_ARGS);
634 private static final Set<String> PERMITTED_STATUS_ARGS = Sets.newHashSet("current", "deprecated", "obsolete");
639 * <li>Value must be one of: "current", "deprecated", "obsolete"</li>
643 public void enterStatus_arg(Status_argContext ctx) {
644 BasicValidations.checkOnlyPermittedValues(ctx, PERMITTED_STATUS_ARGS);