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 com.google.common.collect.Sets;
13 import java.net.URISyntaxException;
14 import java.util.HashSet;
17 import org.antlr.v4.runtime.tree.ParseTree;
18 import org.opendaylight.yangtools.antlrv4.code.gen.YangParser;
19 import org.opendaylight.yangtools.antlrv4.code.gen.YangParser.Anyxml_stmtContext;
20 import org.opendaylight.yangtools.antlrv4.code.gen.YangParser.Argument_stmtContext;
21 import org.opendaylight.yangtools.antlrv4.code.gen.YangParser.Augment_stmtContext;
22 import org.opendaylight.yangtools.antlrv4.code.gen.YangParser.Base_stmtContext;
23 import org.opendaylight.yangtools.antlrv4.code.gen.YangParser.Belongs_to_stmtContext;
24 import org.opendaylight.yangtools.antlrv4.code.gen.YangParser.Case_stmtContext;
25 import org.opendaylight.yangtools.antlrv4.code.gen.YangParser.Choice_stmtContext;
26 import org.opendaylight.yangtools.antlrv4.code.gen.YangParser.Config_argContext;
27 import org.opendaylight.yangtools.antlrv4.code.gen.YangParser.Container_stmtContext;
28 import org.opendaylight.yangtools.antlrv4.code.gen.YangParser.Default_stmtContext;
29 import org.opendaylight.yangtools.antlrv4.code.gen.YangParser.Deviate_add_stmtContext;
30 import org.opendaylight.yangtools.antlrv4.code.gen.YangParser.Deviation_stmtContext;
31 import org.opendaylight.yangtools.antlrv4.code.gen.YangParser.Extension_stmtContext;
32 import org.opendaylight.yangtools.antlrv4.code.gen.YangParser.Feature_stmtContext;
33 import org.opendaylight.yangtools.antlrv4.code.gen.YangParser.Grouping_stmtContext;
34 import org.opendaylight.yangtools.antlrv4.code.gen.YangParser.Identity_stmtContext;
35 import org.opendaylight.yangtools.antlrv4.code.gen.YangParser.If_feature_stmtContext;
36 import org.opendaylight.yangtools.antlrv4.code.gen.YangParser.Import_stmtContext;
37 import org.opendaylight.yangtools.antlrv4.code.gen.YangParser.Include_stmtContext;
38 import org.opendaylight.yangtools.antlrv4.code.gen.YangParser.Key_stmtContext;
39 import org.opendaylight.yangtools.antlrv4.code.gen.YangParser.Leaf_list_stmtContext;
40 import org.opendaylight.yangtools.antlrv4.code.gen.YangParser.Leaf_stmtContext;
41 import org.opendaylight.yangtools.antlrv4.code.gen.YangParser.List_stmtContext;
42 import org.opendaylight.yangtools.antlrv4.code.gen.YangParser.Mandatory_argContext;
43 import org.opendaylight.yangtools.antlrv4.code.gen.YangParser.Mandatory_stmtContext;
44 import org.opendaylight.yangtools.antlrv4.code.gen.YangParser.Module_header_stmtsContext;
45 import org.opendaylight.yangtools.antlrv4.code.gen.YangParser.Module_stmtContext;
46 import org.opendaylight.yangtools.antlrv4.code.gen.YangParser.Namespace_stmtContext;
47 import org.opendaylight.yangtools.antlrv4.code.gen.YangParser.Notification_stmtContext;
48 import org.opendaylight.yangtools.antlrv4.code.gen.YangParser.Ordered_by_argContext;
49 import org.opendaylight.yangtools.antlrv4.code.gen.YangParser.Prefix_stmtContext;
50 import org.opendaylight.yangtools.antlrv4.code.gen.YangParser.Refine_stmtContext;
51 import org.opendaylight.yangtools.antlrv4.code.gen.YangParser.Revision_date_stmtContext;
52 import org.opendaylight.yangtools.antlrv4.code.gen.YangParser.Revision_stmtContext;
53 import org.opendaylight.yangtools.antlrv4.code.gen.YangParser.Rpc_stmtContext;
54 import org.opendaylight.yangtools.antlrv4.code.gen.YangParser.Status_argContext;
55 import org.opendaylight.yangtools.antlrv4.code.gen.YangParser.Submodule_header_stmtsContext;
56 import org.opendaylight.yangtools.antlrv4.code.gen.YangParser.Submodule_stmtContext;
57 import org.opendaylight.yangtools.antlrv4.code.gen.YangParser.Type_stmtContext;
58 import org.opendaylight.yangtools.antlrv4.code.gen.YangParser.Typedef_stmtContext;
59 import org.opendaylight.yangtools.antlrv4.code.gen.YangParser.Unique_stmtContext;
60 import org.opendaylight.yangtools.antlrv4.code.gen.YangParser.Uses_stmtContext;
61 import org.opendaylight.yangtools.antlrv4.code.gen.YangParser.Yin_element_argContext;
62 import org.opendaylight.yangtools.antlrv4.code.gen.YangParserBaseListener;
63 import org.slf4j.Logger;
64 import org.slf4j.LoggerFactory;
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 public final class YangModelBasicValidationListener extends YangParserBaseListener {
72 private static final Logger LOGGER = LoggerFactory.getLogger(YangModelBasicValidationListener.class);
73 private final Set<String> uniquePrefixes = new HashSet<>();
74 private final Set<String> uniqueImports = new HashSet<>();
75 private final Set<String> uniqueIncludes = new HashSet<>();
77 private String globalModuleId;
82 * <li>Identifier is in required format</li>
83 * <li>Header statements present(mandatory prefix and namespace statements
85 * <li>Only one module or submodule per file</li>
89 public void enterModule_stmt(final Module_stmtContext ctx) {
91 BasicValidations.checkIdentifier(ctx);
93 BasicValidations.checkPresentChildOfType(ctx, Module_header_stmtsContext.class, true);
95 String moduleName = ValidationUtil.getName(ctx);
96 BasicValidations.checkIsModuleIdNull(globalModuleId);
97 globalModuleId = moduleName;
103 * <li>Identifier is in required format</li>
104 * <li>Header statements present(mandatory belongs-to statement is in
106 * <li>Only one module or submodule per file</li>
110 public void enterSubmodule_stmt(final Submodule_stmtContext ctx) {
112 BasicValidations.checkIdentifier(ctx);
114 BasicValidations.checkPresentChildOfType(ctx, Submodule_header_stmtsContext.class, true);
116 String submoduleName = ValidationUtil.getName(ctx);
117 BasicValidations.checkIsModuleIdNull(globalModuleId);
118 globalModuleId = submoduleName;
125 * <li>One Belongs-to statement present</li>
129 public void enterSubmodule_header_stmts(final Submodule_header_stmtsContext ctx) {
130 BasicValidations.checkPresentChildOfType(ctx, Belongs_to_stmtContext.class, true);
132 // check Yang version present, if not log
134 BasicValidations.checkPresentYangVersion(ctx, ValidationUtil.getRootParentName(ctx));
135 } catch (Exception e) {
136 LOGGER.debug(e.getMessage());
143 * <li>One Namespace statement present</li>
144 * <li>One Prefix statement present</li>
148 public void enterModule_header_stmts(final Module_header_stmtsContext ctx) {
149 String moduleName = ValidationUtil.getRootParentName(ctx);
151 BasicValidations.checkPresentChildOfType(ctx, Namespace_stmtContext.class, true);
152 BasicValidations.checkPresentChildOfType(ctx, Prefix_stmtContext.class, true);
154 // check Yang version present, if not log
156 BasicValidations.checkPresentYangVersion(ctx, moduleName);
157 } catch (Exception e) {
158 LOGGER.debug(e.getMessage());
165 * <li>Date is in valid format</li>
169 public void enterRevision_stmt(final Revision_stmtContext ctx) {
170 BasicValidations.checkDateFormat(ctx);
177 * <li>Identifier is in required format</li>
178 * <li>One Prefix statement child</li>
182 public void enterBelongs_to_stmt(final Belongs_to_stmtContext ctx) {
183 BasicValidations.checkIdentifier(ctx);
185 BasicValidations.checkPresentChildOfType(ctx, Prefix_stmtContext.class, true);
191 * <li>Namespace string can be parsed as URI</li>
195 public void enterNamespace_stmt(final Namespace_stmtContext ctx) {
196 String namespaceName = ValidationUtil.getName(ctx);
197 String rootParentName = ValidationUtil.getRootParentName(ctx);
200 new URI(namespaceName);
201 } catch (URISyntaxException e) {
202 ValidationUtil.ex(ValidationUtil.f("(In module:%s) Namespace:%s cannot be parsed as URI", rootParentName,
210 * <li>Identifier is in required format</li>
211 * <li>Every import(identified by identifier) within a module/submodule is
212 * present only once</li>
213 * <li>One prefix statement child</li>
217 public void enterImport_stmt(final Import_stmtContext ctx) {
219 BasicValidations.checkIdentifier(ctx);
221 BasicValidations.checkUniquenessInNamespace(ctx, uniqueImports);
223 BasicValidations.checkPresentChildOfType(ctx, Prefix_stmtContext.class, true);
230 * <li>Date is in valid format</li>
234 public void enterRevision_date_stmt(final Revision_date_stmtContext ctx) {
235 BasicValidations.checkDateFormat(ctx);
241 * <li>Identifier is in required format</li>
242 * <li>Every include(identified by identifier) within a module/submodule is
243 * present only once</li>
247 public void enterInclude_stmt(final Include_stmtContext ctx) {
249 BasicValidations.checkIdentifier(ctx);
251 BasicValidations.checkUniquenessInNamespace(ctx, uniqueIncludes);
257 * <li>Yang-version is specified as 1</li>
261 public void enterYang_version_stmt(final YangParser.Yang_version_stmtContext ctx) {
262 String version = ValidationUtil.getName(ctx);
263 String rootParentName = ValidationUtil.getRootParentName(ctx);
264 if (!version.equals(BasicValidations.SUPPORTED_YANG_VERSION)) {
265 ValidationUtil.ex(ValidationUtil.f("(In (sub)module:%s) Unsupported yang version:%s, supported version:%s",
266 rootParentName, version, BasicValidations.SUPPORTED_YANG_VERSION));
273 * <li>Identifier is in required format</li>
274 * <li>Every prefix(identified by identifier) within a module/submodule is
275 * presented only once</li>
279 public void enterPrefix_stmt(final Prefix_stmtContext ctx) {
281 BasicValidations.checkIdentifier(ctx);
283 BasicValidations.checkUniquenessInNamespace(ctx, uniquePrefixes);
289 * <li>Identifier is in required format</li>
290 * <li>One type statement child</li>
294 public void enterTypedef_stmt(final Typedef_stmtContext ctx) {
296 BasicValidations.checkIdentifier(ctx);
298 BasicValidations.checkPresentChildOfType(ctx, Type_stmtContext.class, true);
304 * <li>(Prefix):Identifier is in required format</li>
308 public void enterType_stmt(final Type_stmtContext ctx) {
309 BasicValidations.checkPrefixedIdentifier(ctx);
315 * <li>Identifier is in required format</li>
319 public void enterContainer_stmt(final Container_stmtContext ctx) {
320 BasicValidations.checkIdentifier(ctx);
326 * <li>Identifier is in required format</li>
327 * <li>One type statement child</li>
328 * <li>Default statement must not be present if mandatory statement is</li>
332 public void enterLeaf_stmt(final Leaf_stmtContext ctx) {
333 BasicValidations.checkIdentifier(ctx);
335 BasicValidations.checkPresentChildOfType(ctx, Type_stmtContext.class, true);
337 BasicValidations.checkNotPresentBoth(ctx, Mandatory_stmtContext.class, Default_stmtContext.class);
343 * <li>Identifier is in required format</li>
344 * <li>One type statement child</li>
348 public void enterLeaf_list_stmt(final Leaf_list_stmtContext ctx) {
350 BasicValidations.checkIdentifier(ctx);
352 BasicValidations.checkPresentChildOfType(ctx, Type_stmtContext.class, true);
355 private static final Set<String> PERMITTED_ORDER_BY_ARGS = Sets.newHashSet("system", "user");
360 * <li>Value must be one of: system, user</li>
364 public void enterOrdered_by_arg(final Ordered_by_argContext ctx) {
365 BasicValidations.checkOnlyPermittedValues(ctx, PERMITTED_ORDER_BY_ARGS);
371 * <li>Identifier is in required format</li>
375 public void enterList_stmt(final List_stmtContext ctx) {
376 BasicValidations.checkIdentifier(ctx);
377 // TODO check: "if config==true then key must be present" could be
384 * <li>No duplicate keys</li>
388 public void enterKey_stmt(final Key_stmtContext ctx) {
389 BasicValidations.getAndCheckUniqueKeys(ctx);
395 * <li>No duplicate uniques</li>
399 public void enterUnique_stmt(final Unique_stmtContext ctx) {
400 BasicValidations.getAndCheckUniqueKeys(ctx);
406 * <li>Identifier is in required format</li>
407 * <li>Default statement must not be present if mandatory statement is</li>
411 public void enterChoice_stmt(final Choice_stmtContext ctx) {
412 BasicValidations.checkIdentifier(ctx);
414 BasicValidations.checkNotPresentBoth(ctx, Mandatory_stmtContext.class, Default_stmtContext.class);
421 * <li>Identifier is in required format</li>
425 public void enterCase_stmt(final Case_stmtContext ctx) {
426 BasicValidations.checkIdentifier(ctx);
429 private static final Set<String> PERMITTED_BOOLEAN_ARGS = Sets.newHashSet("true", "false");
434 * <li>Value must be one of: true, false</li>
438 public void enterMandatory_arg(final Mandatory_argContext ctx) {
439 BasicValidations.checkOnlyPermittedValues(ctx, PERMITTED_BOOLEAN_ARGS);
445 * <li>Identifier is in required format</li>
449 public void enterAnyxml_stmt(final Anyxml_stmtContext ctx) {
450 BasicValidations.checkIdentifier(ctx);
456 * <li>Identifier is in required format</li>
460 public void enterGrouping_stmt(final Grouping_stmtContext ctx) {
461 BasicValidations.checkIdentifier(ctx);
467 * <li>(Prefix):Identifier is in required format</li>
471 public void enterUses_stmt(final Uses_stmtContext ctx) {
472 BasicValidations.checkPrefixedIdentifier(ctx);
478 * <li>Identifier is in required format</li>
482 public void enterRefine_stmt(final Refine_stmtContext ctx) {
483 BasicValidations.checkSchemaNodeIdentifier(ctx);
489 * <li>Identifier is in required format</li>
493 public void enterRpc_stmt(final Rpc_stmtContext ctx) {
494 BasicValidations.checkIdentifier(ctx);
500 * <li>Identifier is in required format</li>
504 public void enterNotification_stmt(final Notification_stmtContext ctx) {
505 BasicValidations.checkIdentifier(ctx);
511 * <li>Schema Node Identifier is in required format</li>
515 public void enterAugment_stmt(final Augment_stmtContext ctx) {
516 BasicValidations.checkSchemaNodeIdentifier(ctx);
522 * <li>Identifier is in required format</li>
526 public void enterIdentity_stmt(final Identity_stmtContext ctx) {
527 BasicValidations.checkIdentifier(ctx);
533 * <li>(Prefix):Identifier is in required format</li>
537 public void enterBase_stmt(final Base_stmtContext ctx) {
538 BasicValidations.checkPrefixedIdentifier(ctx);
545 * <li>Value must be one of: true, false</li>
549 public void enterYin_element_arg(final Yin_element_argContext ctx) {
550 BasicValidations.checkOnlyPermittedValues(ctx, PERMITTED_BOOLEAN_ARGS);
556 * <li>Identifier is in required format</li>
560 public void enterExtension_stmt(final Extension_stmtContext ctx) {
561 BasicValidations.checkIdentifier(ctx);
567 * <li>Identifier is in required format</li>
571 public void enterArgument_stmt(final Argument_stmtContext ctx) {
572 BasicValidations.checkIdentifier(ctx);
578 * <li>Identifier is in required format</li>
582 public void enterFeature_stmt(final Feature_stmtContext ctx) {
583 BasicValidations.checkIdentifier(ctx);
590 * <li>(Prefix):Identifier is in required format</li>
594 public void enterIf_feature_stmt(final If_feature_stmtContext ctx) {
595 BasicValidations.checkPrefixedIdentifier(ctx);
601 * <li>Schema Node Identifier is in required format</li>
602 * <li>At least one deviate-* statement child</li>
606 public void enterDeviation_stmt(final Deviation_stmtContext ctx) {
607 BasicValidations.checkSchemaNodeIdentifier(ctx);
609 Set<Class<? extends ParseTree>> types = Sets.newHashSet();
610 types.add(Deviate_add_stmtContext.class);
611 types.add(Deviate_add_stmtContext.class);
612 BasicValidations.checkPresentChildOfTypes(ctx, types, false);
618 * <li>Value must be one of: true, false</li>
622 public void enterConfig_arg(final Config_argContext ctx) {
623 BasicValidations.checkOnlyPermittedValues(ctx, PERMITTED_BOOLEAN_ARGS);
626 private static final Set<String> PERMITTED_STATUS_ARGS = Sets.newHashSet("current", "deprecated", "obsolete");
631 * <li>Value must be one of: "current", "deprecated", "obsolete"</li>
635 public void enterStatus_arg(final Status_argContext ctx) {
636 BasicValidations.checkOnlyPermittedValues(ctx, PERMITTED_STATUS_ARGS);