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;
12 import java.net.URISyntaxException;
13 import java.util.HashSet;
15 import org.antlr.v4.runtime.tree.ParseTree;
16 import org.opendaylight.yangtools.antlrv4.code.gen.YangParser;
17 import org.opendaylight.yangtools.antlrv4.code.gen.YangParser.Anyxml_stmtContext;
18 import org.opendaylight.yangtools.antlrv4.code.gen.YangParser.Argument_stmtContext;
19 import org.opendaylight.yangtools.antlrv4.code.gen.YangParser.Augment_stmtContext;
20 import org.opendaylight.yangtools.antlrv4.code.gen.YangParser.Base_stmtContext;
21 import org.opendaylight.yangtools.antlrv4.code.gen.YangParser.Belongs_to_stmtContext;
22 import org.opendaylight.yangtools.antlrv4.code.gen.YangParser.Case_stmtContext;
23 import org.opendaylight.yangtools.antlrv4.code.gen.YangParser.Choice_stmtContext;
24 import org.opendaylight.yangtools.antlrv4.code.gen.YangParser.Config_argContext;
25 import org.opendaylight.yangtools.antlrv4.code.gen.YangParser.Container_stmtContext;
26 import org.opendaylight.yangtools.antlrv4.code.gen.YangParser.Default_stmtContext;
27 import org.opendaylight.yangtools.antlrv4.code.gen.YangParser.Deviate_add_stmtContext;
28 import org.opendaylight.yangtools.antlrv4.code.gen.YangParser.Deviation_stmtContext;
29 import org.opendaylight.yangtools.antlrv4.code.gen.YangParser.Extension_stmtContext;
30 import org.opendaylight.yangtools.antlrv4.code.gen.YangParser.Feature_stmtContext;
31 import org.opendaylight.yangtools.antlrv4.code.gen.YangParser.Grouping_stmtContext;
32 import org.opendaylight.yangtools.antlrv4.code.gen.YangParser.Identity_stmtContext;
33 import org.opendaylight.yangtools.antlrv4.code.gen.YangParser.If_feature_stmtContext;
34 import org.opendaylight.yangtools.antlrv4.code.gen.YangParser.Import_stmtContext;
35 import org.opendaylight.yangtools.antlrv4.code.gen.YangParser.Include_stmtContext;
36 import org.opendaylight.yangtools.antlrv4.code.gen.YangParser.Key_stmtContext;
37 import org.opendaylight.yangtools.antlrv4.code.gen.YangParser.Leaf_list_stmtContext;
38 import org.opendaylight.yangtools.antlrv4.code.gen.YangParser.Leaf_stmtContext;
39 import org.opendaylight.yangtools.antlrv4.code.gen.YangParser.List_stmtContext;
40 import org.opendaylight.yangtools.antlrv4.code.gen.YangParser.Mandatory_argContext;
41 import org.opendaylight.yangtools.antlrv4.code.gen.YangParser.Mandatory_stmtContext;
42 import org.opendaylight.yangtools.antlrv4.code.gen.YangParser.Module_header_stmtsContext;
43 import org.opendaylight.yangtools.antlrv4.code.gen.YangParser.Module_stmtContext;
44 import org.opendaylight.yangtools.antlrv4.code.gen.YangParser.Namespace_stmtContext;
45 import org.opendaylight.yangtools.antlrv4.code.gen.YangParser.Notification_stmtContext;
46 import org.opendaylight.yangtools.antlrv4.code.gen.YangParser.Ordered_by_argContext;
47 import org.opendaylight.yangtools.antlrv4.code.gen.YangParser.Prefix_stmtContext;
48 import org.opendaylight.yangtools.antlrv4.code.gen.YangParser.Refine_stmtContext;
49 import org.opendaylight.yangtools.antlrv4.code.gen.YangParser.Revision_date_stmtContext;
50 import org.opendaylight.yangtools.antlrv4.code.gen.YangParser.Revision_stmtContext;
51 import org.opendaylight.yangtools.antlrv4.code.gen.YangParser.Rpc_stmtContext;
52 import org.opendaylight.yangtools.antlrv4.code.gen.YangParser.Status_argContext;
53 import org.opendaylight.yangtools.antlrv4.code.gen.YangParser.Submodule_header_stmtsContext;
54 import org.opendaylight.yangtools.antlrv4.code.gen.YangParser.Submodule_stmtContext;
55 import org.opendaylight.yangtools.antlrv4.code.gen.YangParser.Type_stmtContext;
56 import org.opendaylight.yangtools.antlrv4.code.gen.YangParser.Typedef_stmtContext;
57 import org.opendaylight.yangtools.antlrv4.code.gen.YangParser.Unique_stmtContext;
58 import org.opendaylight.yangtools.antlrv4.code.gen.YangParser.Uses_stmtContext;
59 import org.opendaylight.yangtools.antlrv4.code.gen.YangParser.Yin_element_argContext;
60 import org.opendaylight.yangtools.antlrv4.code.gen.YangParserBaseListener;
61 import org.slf4j.Logger;
62 import org.slf4j.LoggerFactory;
65 * Validation listener that validates yang statements according to RFC-6020.
66 * This validator expects only one module or submodule per file and performs
67 * only basic validation where context from all yang models is not present.
69 final class YangModelBasicValidationListener extends YangParserBaseListener {
70 private static final Logger LOGGER = LoggerFactory.getLogger(YangModelBasicValidationListener.class);
71 private final Set<String> uniquePrefixes = new HashSet<>();
72 private final Set<String> uniqueImports = new HashSet<>();
73 private final Set<String> uniqueIncludes = new HashSet<>();
75 private String globalModuleId;
80 * <li>Identifier is in required format</li>
81 * <li>Header statements present(mandatory prefix and namespace statements
83 * <li>Only one module or submodule per file</li>
87 public void enterModule_stmt(final Module_stmtContext ctx) {
89 BasicValidations.checkIdentifier(ctx);
91 BasicValidations.checkPresentChildOfType(ctx, Module_header_stmtsContext.class, true);
93 String moduleName = ValidationUtil.getName(ctx);
94 BasicValidations.checkIsModuleIdNull(globalModuleId);
95 globalModuleId = moduleName;
101 * <li>Identifier is in required format</li>
102 * <li>Header statements present(mandatory belongs-to statement is in
104 * <li>Only one module or submodule per file</li>
108 public void enterSubmodule_stmt(final Submodule_stmtContext ctx) {
110 BasicValidations.checkIdentifier(ctx);
112 BasicValidations.checkPresentChildOfType(ctx, Submodule_header_stmtsContext.class, true);
114 String submoduleName = ValidationUtil.getName(ctx);
115 BasicValidations.checkIsModuleIdNull(globalModuleId);
116 globalModuleId = submoduleName;
123 * <li>One Belongs-to statement present</li>
127 public void enterSubmodule_header_stmts(final Submodule_header_stmtsContext ctx) {
128 BasicValidations.checkPresentChildOfType(ctx, Belongs_to_stmtContext.class, true);
130 // check Yang version present, if not log
132 BasicValidations.checkPresentYangVersion(ctx, ValidationUtil.getRootParentName(ctx));
133 } catch (Exception e) {
134 LOGGER.debug(e.getMessage());
141 * <li>One Namespace statement present</li>
142 * <li>One Prefix statement present</li>
146 public void enterModule_header_stmts(final Module_header_stmtsContext ctx) {
147 String moduleName = ValidationUtil.getRootParentName(ctx);
149 BasicValidations.checkPresentChildOfType(ctx, Namespace_stmtContext.class, true);
150 BasicValidations.checkPresentChildOfType(ctx, Prefix_stmtContext.class, true);
152 // check Yang version present, if not log
154 BasicValidations.checkPresentYangVersion(ctx, moduleName);
155 } catch (Exception e) {
156 LOGGER.debug(e.getMessage());
163 * <li>Date is in valid format</li>
167 public void enterRevision_stmt(final Revision_stmtContext ctx) {
168 BasicValidations.checkDateFormat(ctx);
175 * <li>Identifier is in required format</li>
176 * <li>One Prefix statement child</li>
180 public void enterBelongs_to_stmt(final Belongs_to_stmtContext ctx) {
181 BasicValidations.checkIdentifier(ctx);
183 BasicValidations.checkPresentChildOfType(ctx, Prefix_stmtContext.class, true);
189 * <li>Namespace string can be parsed as URI</li>
193 public void enterNamespace_stmt(final Namespace_stmtContext ctx) {
194 String namespaceName = ValidationUtil.getName(ctx);
195 String rootParentName = ValidationUtil.getRootParentName(ctx);
198 new URI(namespaceName);
199 } catch (URISyntaxException e) {
200 ValidationUtil.ex(ValidationUtil.f("(In module:%s) Namespace:%s cannot be parsed as URI", rootParentName,
208 * <li>Identifier is in required format</li>
209 * <li>Every import(identified by identifier) within a module/submodule is
210 * present only once</li>
211 * <li>One prefix statement child</li>
215 public void enterImport_stmt(final Import_stmtContext ctx) {
217 BasicValidations.checkIdentifier(ctx);
219 BasicValidations.checkUniquenessInNamespace(ctx, uniqueImports);
221 BasicValidations.checkPresentChildOfType(ctx, Prefix_stmtContext.class, true);
228 * <li>Date is in valid format</li>
232 public void enterRevision_date_stmt(final Revision_date_stmtContext ctx) {
233 BasicValidations.checkDateFormat(ctx);
239 * <li>Identifier is in required format</li>
240 * <li>Every include(identified by identifier) within a module/submodule is
241 * present only once</li>
245 public void enterInclude_stmt(final Include_stmtContext ctx) {
247 BasicValidations.checkIdentifier(ctx);
249 BasicValidations.checkUniquenessInNamespace(ctx, uniqueIncludes);
255 * <li>Yang-version is specified as 1</li>
259 public void enterYang_version_stmt(final YangParser.Yang_version_stmtContext ctx) {
260 String version = ValidationUtil.getName(ctx);
261 String rootParentName = ValidationUtil.getRootParentName(ctx);
262 if (!version.equals(BasicValidations.SUPPORTED_YANG_VERSION)) {
263 ValidationUtil.ex(ValidationUtil.f("(In (sub)module:%s) Unsupported yang version:%s, supported version:%s",
264 rootParentName, version, BasicValidations.SUPPORTED_YANG_VERSION));
271 * <li>Identifier is in required format</li>
272 * <li>Every prefix(identified by identifier) within a module/submodule is
273 * presented only once</li>
277 public void enterPrefix_stmt(final Prefix_stmtContext ctx) {
279 BasicValidations.checkIdentifier(ctx);
281 BasicValidations.checkUniquenessInNamespace(ctx, uniquePrefixes);
287 * <li>Identifier is in required format</li>
288 * <li>One type statement child</li>
292 public void enterTypedef_stmt(final Typedef_stmtContext ctx) {
294 BasicValidations.checkIdentifier(ctx);
296 BasicValidations.checkPresentChildOfType(ctx, Type_stmtContext.class, true);
302 * <li>(Prefix):Identifier is in required format</li>
306 public void enterType_stmt(final Type_stmtContext ctx) {
307 BasicValidations.checkPrefixedIdentifier(ctx);
313 * <li>Identifier is in required format</li>
317 public void enterContainer_stmt(final Container_stmtContext ctx) {
318 BasicValidations.checkIdentifier(ctx);
324 * <li>Identifier is in required format</li>
325 * <li>One type statement child</li>
326 * <li>Default statement must not be present if mandatory statement is</li>
330 public void enterLeaf_stmt(final Leaf_stmtContext ctx) {
331 BasicValidations.checkIdentifier(ctx);
333 BasicValidations.checkPresentChildOfType(ctx, Type_stmtContext.class, true);
335 BasicValidations.checkNotPresentBoth(ctx, Mandatory_stmtContext.class, Default_stmtContext.class);
341 * <li>Identifier is in required format</li>
342 * <li>One type statement child</li>
346 public void enterLeaf_list_stmt(final Leaf_list_stmtContext ctx) {
348 BasicValidations.checkIdentifier(ctx);
350 BasicValidations.checkPresentChildOfType(ctx, Type_stmtContext.class, true);
353 private static final Set<String> PERMITTED_ORDER_BY_ARGS = Sets.newHashSet("system", "user");
358 * <li>Value must be one of: system, user</li>
362 public void enterOrdered_by_arg(final Ordered_by_argContext ctx) {
363 BasicValidations.checkOnlyPermittedValues(ctx, PERMITTED_ORDER_BY_ARGS);
369 * <li>Identifier is in required format</li>
373 public void enterList_stmt(final List_stmtContext ctx) {
374 BasicValidations.checkIdentifier(ctx);
375 // TODO check: "if config==true then key must be present" could be
382 * <li>No duplicate keys</li>
386 public void enterKey_stmt(final Key_stmtContext ctx) {
387 BasicValidations.getAndCheckUniqueKeys(ctx);
393 * <liNo duplicate uniques</li>
397 public void enterUnique_stmt(final Unique_stmtContext ctx) {
398 BasicValidations.getAndCheckUniqueKeys(ctx);
404 * <li>Identifier is in required format</li>
405 * <li>Default statement must not be present if mandatory statement is</li>
409 public void enterChoice_stmt(final Choice_stmtContext ctx) {
410 BasicValidations.checkIdentifier(ctx);
412 BasicValidations.checkNotPresentBoth(ctx, Mandatory_stmtContext.class, Default_stmtContext.class);
419 * <li>Identifier is in required format</li>
423 public void enterCase_stmt(final Case_stmtContext ctx) {
424 BasicValidations.checkIdentifier(ctx);
427 private static final Set<String> PERMITTED_BOOLEAN_ARGS = Sets.newHashSet("true", "false");
432 * <li>Value must be one of: true, false</li>
436 public void enterMandatory_arg(final Mandatory_argContext ctx) {
437 BasicValidations.checkOnlyPermittedValues(ctx, PERMITTED_BOOLEAN_ARGS);
443 * <li>Identifier is in required format</li>
447 public void enterAnyxml_stmt(final Anyxml_stmtContext ctx) {
448 BasicValidations.checkIdentifier(ctx);
454 * <li>Identifier is in required format</li>
458 public void enterGrouping_stmt(final Grouping_stmtContext ctx) {
459 BasicValidations.checkIdentifier(ctx);
465 * <li>(Prefix):Identifier is in required format</li>
469 public void enterUses_stmt(final Uses_stmtContext ctx) {
470 BasicValidations.checkPrefixedIdentifier(ctx);
476 * <li>Identifier is in required format</li>
480 public void enterRefine_stmt(final Refine_stmtContext ctx) {
481 BasicValidations.checkSchemaNodeIdentifier(ctx);
487 * <li>Identifier is in required format</li>
491 public void enterRpc_stmt(final Rpc_stmtContext ctx) {
492 BasicValidations.checkIdentifier(ctx);
498 * <li>Identifier is in required format</li>
502 public void enterNotification_stmt(final Notification_stmtContext ctx) {
503 BasicValidations.checkIdentifier(ctx);
509 * <li>Schema Node Identifier is in required format</li>
513 public void enterAugment_stmt(final Augment_stmtContext ctx) {
514 BasicValidations.checkSchemaNodeIdentifier(ctx);
520 * <li>Identifier is in required format</li>
524 public void enterIdentity_stmt(final Identity_stmtContext ctx) {
525 BasicValidations.checkIdentifier(ctx);
531 * <li>(Prefix):Identifier is in required format</li>
535 public void enterBase_stmt(final Base_stmtContext ctx) {
536 BasicValidations.checkPrefixedIdentifier(ctx);
543 * <li>Value must be one of: true, false</li>
547 public void enterYin_element_arg(final Yin_element_argContext ctx) {
548 BasicValidations.checkOnlyPermittedValues(ctx, PERMITTED_BOOLEAN_ARGS);
554 * <li>Identifier is in required format</li>
558 public void enterExtension_stmt(final Extension_stmtContext ctx) {
559 BasicValidations.checkIdentifier(ctx);
565 * <li>Identifier is in required format</li>
569 public void enterArgument_stmt(final Argument_stmtContext ctx) {
570 BasicValidations.checkIdentifier(ctx);
576 * <li>Identifier is in required format</li>
580 public void enterFeature_stmt(final Feature_stmtContext ctx) {
581 BasicValidations.checkIdentifier(ctx);
588 * <li>(Prefix):Identifier is in required format</li>
592 public void enterIf_feature_stmt(final If_feature_stmtContext ctx) {
593 BasicValidations.checkPrefixedIdentifier(ctx);
599 * <li>Schema Node Identifier is in required format</li>
600 * <li>At least one deviate-* statement child</li>
604 public void enterDeviation_stmt(final Deviation_stmtContext ctx) {
605 BasicValidations.checkSchemaNodeIdentifier(ctx);
607 Set<Class<? extends ParseTree>> types = Sets.newHashSet();
608 types.add(Deviate_add_stmtContext.class);
609 types.add(Deviate_add_stmtContext.class);
610 BasicValidations.checkPresentChildOfTypes(ctx, types, false);
616 * <li>Value must be one of: true, false</li>
620 public void enterConfig_arg(final Config_argContext ctx) {
621 BasicValidations.checkOnlyPermittedValues(ctx, PERMITTED_BOOLEAN_ARGS);
624 private static final Set<String> PERMITTED_STATUS_ARGS = Sets.newHashSet("current", "deprecated", "obsolete");
629 * <li>Value must be one of: "current", "deprecated", "obsolete"</li>
633 public void enterStatus_arg(final Status_argContext ctx) {
634 BasicValidations.checkOnlyPermittedValues(ctx, PERMITTED_STATUS_ARGS);