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
73 .getLogger(YangModelBasicValidationListener.class);
75 private final Set<String> uniquePrefixes;
76 private final Set<String> uniqueImports;
77 private final Set<String> uniqueIncludes;
79 private String globalModuleId;
81 YangModelBasicValidationListener() {
83 uniquePrefixes = Sets.newHashSet();
84 uniqueImports = Sets.newHashSet();
85 uniqueIncludes = Sets.newHashSet();
91 * <li>Identifier is in required format</li>
92 * <li>Header statements present(mandatory prefix and namespace statements
94 * <li>Only one module or submodule per file</li>
98 public void enterModule_stmt(Module_stmtContext ctx) {
100 BasicValidations.checkIdentifier(ctx);
102 BasicValidations.checkPresentChildOfType(ctx,
103 Module_header_stmtsContext.class, true);
105 String moduleName = ValidationUtil.getName(ctx);
106 BasicValidations.checkOnlyOneModulePresent(moduleName, globalModuleId);
107 globalModuleId = moduleName;
113 * <li>Identifier is in required format</li>
114 * <li>Header statements present(mandatory belongs-to statement is in
116 * <li>Only one module or submodule per file</li>
120 public void enterSubmodule_stmt(Submodule_stmtContext ctx) {
122 BasicValidations.checkIdentifier(ctx);
124 BasicValidations.checkPresentChildOfType(ctx,
125 Submodule_header_stmtsContext.class, true);
127 String submoduleName = ValidationUtil.getName(ctx);
128 BasicValidations.checkOnlyOneModulePresent(submoduleName,
130 globalModuleId = submoduleName;
137 * <li>One Belongs-to statement present</li>
141 public void enterSubmodule_header_stmts(Submodule_header_stmtsContext ctx) {
142 BasicValidations.checkPresentChildOfType(ctx,
143 Belongs_to_stmtContext.class, true);
145 // check Yang version present, if not log
147 BasicValidations.checkPresentYangVersion(ctx,
148 ValidationUtil.getRootParentName(ctx));
149 } catch (Exception e) {
150 logger.debug(e.getMessage());
157 * <li>One Namespace statement present</li>
158 * <li>One Prefix statement present</li>
162 public void enterModule_header_stmts(Module_header_stmtsContext ctx) {
163 String moduleName = ValidationUtil.getRootParentName(ctx);
165 BasicValidations.checkPresentChildOfType(ctx,
166 Namespace_stmtContext.class, true);
167 BasicValidations.checkPresentChildOfType(ctx, Prefix_stmtContext.class,
170 // check Yang version present, if not log
172 BasicValidations.checkPresentYangVersion(ctx, moduleName);
173 } catch (Exception e) {
174 logger.debug(e.getMessage());
181 * <li>Date is in valid format</li>
185 public void enterRevision_stmt(Revision_stmtContext ctx) {
186 BasicValidations.checkDateFormat(ctx,
187 YangParserListenerImpl.simpleDateFormat);
194 * <li>Identifier is in required format</li>
195 * <li>One Prefix statement child</li>
199 public void enterBelongs_to_stmt(Belongs_to_stmtContext ctx) {
200 BasicValidations.checkIdentifier(ctx);
202 BasicValidations.checkPresentChildOfType(ctx, Prefix_stmtContext.class,
209 * <li>Namespace string can be parsed as URI</li>
213 public void enterNamespace_stmt(Namespace_stmtContext ctx) {
214 String namespaceName = ValidationUtil.getName(ctx);
215 String rootParentName = ValidationUtil.getRootParentName(ctx);
218 new URI(namespaceName);
219 } catch (URISyntaxException e) {
220 ValidationUtil.ex(ValidationUtil.f(
221 "(In module:%s) Namespace:%s cannot be parsed as URI",
222 rootParentName, namespaceName));
229 * <li>Identifier is in required format</li>
230 * <li>Every import(identified by identifier) within a module/submodule is
231 * present only once</li>
232 * <li>One prefix statement child</li>
236 public void enterImport_stmt(Import_stmtContext ctx) {
238 BasicValidations.checkIdentifier(ctx);
240 BasicValidations.checkUniquenessInNamespace(ctx, uniqueImports);
242 BasicValidations.checkPresentChildOfType(ctx, Prefix_stmtContext.class,
250 * <li>Date is in valid format</li>
254 public void enterRevision_date_stmt(Revision_date_stmtContext ctx) {
255 BasicValidations.checkDateFormat(ctx,
256 YangParserListenerImpl.simpleDateFormat);
262 * <li>Identifier is in required format</li>
263 * <li>Every include(identified by identifier) within a module/submodule is
264 * present only once</li>
268 public void enterInclude_stmt(Include_stmtContext ctx) {
270 BasicValidations.checkIdentifier(ctx);
272 BasicValidations.checkUniquenessInNamespace(ctx, uniqueIncludes);
278 * <li>Yang-version is specified as 1</li>
282 public void enterYang_version_stmt(YangParser.Yang_version_stmtContext ctx) {
283 String version = ValidationUtil.getName(ctx);
284 String rootParentName = ValidationUtil.getRootParentName(ctx);
285 if (!version.equals(BasicValidations.SUPPORTED_YANG_VERSION)) {
288 .f("(In (sub)module:%s) Unsupported yang version:%s, supported version:%s",
289 rootParentName, version,
290 BasicValidations.SUPPORTED_YANG_VERSION));
297 * <li>Identifier is in required format</li>
298 * <li>Every prefix(identified by identifier) within a module/submodule is
299 * presented only once</li>
303 public void enterPrefix_stmt(Prefix_stmtContext ctx) {
305 BasicValidations.checkIdentifier(ctx);
307 BasicValidations.checkUniquenessInNamespace(ctx, uniquePrefixes);
313 * <li>Identifier is in required format</li>
314 * <li>One type statement child</li>
318 public void enterTypedef_stmt(Typedef_stmtContext ctx) {
320 BasicValidations.checkIdentifier(ctx);
322 BasicValidations.checkPresentChildOfType(ctx, Type_stmtContext.class,
329 * <li>(Prefix):Identifier is in required format</li>
333 public void enterType_stmt(Type_stmtContext ctx) {
334 BasicValidations.checkPrefixedIdentifier(ctx);
340 * <li>Identifier is in required format</li>
344 public void enterContainer_stmt(Container_stmtContext ctx) {
345 BasicValidations.checkIdentifier(ctx);
351 * <li>Identifier is in required format</li>
352 * <li>One type statement child</li>
353 * <li>Default statement must not be present if mandatory statement is</li>
357 public void enterLeaf_stmt(Leaf_stmtContext ctx) {
358 BasicValidations.checkIdentifier(ctx);
360 BasicValidations.checkPresentChildOfType(ctx, Type_stmtContext.class,
363 BasicValidations.checkNotPresentBoth(ctx, Mandatory_stmtContext.class,
364 Default_stmtContext.class);
370 * <li>Identifier is in required format</li>
371 * <li>One type statement child</li>
375 public void enterLeaf_list_stmt(Leaf_list_stmtContext ctx) {
377 BasicValidations.checkIdentifier(ctx);
379 BasicValidations.checkPresentChildOfType(ctx, Type_stmtContext.class,
383 private static final Set<String> permittedOrderByArgs = Sets.newHashSet(
389 * <li>Value must be one of: system, user</li>
393 public void enterOrdered_by_arg(Ordered_by_argContext ctx) {
394 BasicValidations.checkOnlyPermittedValues(ctx, permittedOrderByArgs);
400 * <li>Identifier is in required format</li>
404 public void enterList_stmt(List_stmtContext ctx) {
405 BasicValidations.checkIdentifier(ctx);
406 // TODO check: "if config==true then key must be present" could be
413 * <li>No duplicate keys</li>
417 public void enterKey_stmt(Key_stmtContext ctx) {
418 BasicValidations.getAndCheckUniqueKeys(ctx);
424 * <liNo duplicate uniques</li>
428 public void enterUnique_stmt(Unique_stmtContext ctx) {
429 BasicValidations.getAndCheckUniqueKeys(ctx);
435 * <li>Identifier is in required format</li>
436 * <li>Default statement must not be present if mandatory statement is</li>
440 public void enterChoice_stmt(Choice_stmtContext ctx) {
441 BasicValidations.checkIdentifier(ctx);
443 BasicValidations.checkNotPresentBoth(ctx, Mandatory_stmtContext.class,
444 Default_stmtContext.class);
451 * <li>Identifier is in required format</li>
455 public void enterCase_stmt(Case_stmtContext ctx) {
456 BasicValidations.checkIdentifier(ctx);
459 private static final Set<String> permittedBooleanArgs = Sets.newHashSet(
465 * <li>Value must be one of: true, false</li>
469 public void enterMandatory_arg(Mandatory_argContext ctx) {
470 BasicValidations.checkOnlyPermittedValues(ctx, permittedBooleanArgs);
476 * <li>Identifier is in required format</li>
480 public void enterAnyxml_stmt(Anyxml_stmtContext ctx) {
481 BasicValidations.checkIdentifier(ctx);
487 * <li>Identifier is in required format</li>
491 public void enterGrouping_stmt(Grouping_stmtContext ctx) {
492 BasicValidations.checkIdentifier(ctx);
498 * <li>(Prefix):Identifier is in required format</li>
502 public void enterUses_stmt(Uses_stmtContext ctx) {
503 BasicValidations.checkPrefixedIdentifier(ctx);
509 * <li>Identifier is in required format</li>
513 public void enterRefine_stmt(Refine_stmtContext ctx) {
514 BasicValidations.checkIdentifier(ctx);
520 * <li>Identifier is in required format</li>
524 public void enterRpc_stmt(Rpc_stmtContext ctx) {
525 BasicValidations.checkIdentifier(ctx);
531 * <li>Identifier is in required format</li>
535 public void enterNotification_stmt(Notification_stmtContext ctx) {
536 BasicValidations.checkIdentifier(ctx);
542 * <li>Schema Node Identifier is in required format</li>
546 public void enterAugment_stmt(Augment_stmtContext ctx) {
547 BasicValidations.checkSchemaNodeIdentifier(ctx);
553 * <li>Identifier is in required format</li>
557 public void enterIdentity_stmt(Identity_stmtContext ctx) {
558 BasicValidations.checkIdentifier(ctx);
564 * <li>(Prefix):Identifier is in required format</li>
568 public void enterBase_stmt(Base_stmtContext ctx) {
569 BasicValidations.checkPrefixedIdentifier(ctx);
576 * <li>Value must be one of: true, false</li>
580 public void enterYin_element_arg(Yin_element_argContext ctx) {
581 BasicValidations.checkOnlyPermittedValues(ctx, permittedBooleanArgs);
587 * <li>Identifier is in required format</li>
591 public void enterExtension_stmt(Extension_stmtContext ctx) {
592 BasicValidations.checkIdentifier(ctx);
598 * <li>Identifier is in required format</li>
602 public void enterArgument_stmt(Argument_stmtContext ctx) {
603 BasicValidations.checkIdentifier(ctx);
609 * <li>Identifier is in required format</li>
613 public void enterFeature_stmt(Feature_stmtContext ctx) {
614 BasicValidations.checkIdentifier(ctx);
621 * <li>(Prefix):Identifier is in required format</li>
625 public void enterIf_feature_stmt(If_feature_stmtContext ctx) {
626 BasicValidations.checkPrefixedIdentifier(ctx);
632 * <li>Schema Node Identifier is in required format</li>
633 * <li>At least one deviate-* statement child</li>
637 public void enterDeviation_stmt(Deviation_stmtContext ctx) {
638 BasicValidations.checkSchemaNodeIdentifier(ctx);
640 Set<Class<? extends ParseTree>> types = Sets.newHashSet();
641 types.add(Deviate_add_stmtContext.class);
642 types.add(Deviate_add_stmtContext.class);
643 BasicValidations.checkPresentChildOfTypes(ctx, types, false);
649 * <li>Value must be one of: true, false</li>
653 public void enterConfig_arg(Config_argContext ctx) {
654 BasicValidations.checkOnlyPermittedValues(ctx, permittedBooleanArgs);
657 private static final Set<String> permittedStatusArgs = Sets.newHashSet(
658 "current", "deprecated", "obsolete");
663 * <li>Value must be one of: "current", "deprecated", "obsolete"</li>
667 public void enterStatus_arg(Status_argContext ctx) {
668 BasicValidations.checkOnlyPermittedValues(ctx, permittedStatusArgs);