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 static java.lang.String.format;
12 import com.google.common.base.Splitter;
13 import com.google.common.collect.Sets;
15 import java.text.ParseException;
16 import java.util.Date;
18 import java.util.regex.Matcher;
19 import java.util.regex.Pattern;
21 import org.antlr.v4.runtime.ParserRuleContext;
22 import org.antlr.v4.runtime.tree.ParseTree;
23 import org.opendaylight.yangtools.antlrv4.code.gen.YangParser.Yang_version_stmtContext;
24 import org.opendaylight.yangtools.yang.common.SimpleDateFormatUtil;
25 import org.opendaylight.yangtools.yang.parser.util.YangValidationException;
28 * Reusable checks of basic constraints on yang statements
30 final class BasicValidations {
32 static final String SUPPORTED_YANG_VERSION = "1";
33 private static final Splitter SLASH_SPLITTER = Splitter.on('/').omitEmptyStrings();
34 private static final Pattern IDENTIFIER_PATTERN = Pattern.compile("[a-zA-Z_][a-zA-Z0-9_.-]*");
35 private static final Pattern PREFIX_IDENTIFIER_PATTERN = Pattern.compile("(.+):(.+)");
38 * It isn't desirable to create instance of this class.
40 private BasicValidations() {
43 static void checkNotPresentBoth(final ParseTree parent, final Class<? extends ParseTree> childType1,
44 final Class<? extends ParseTree> childType2) {
45 if (BasicValidations.checkPresentChildOfTypeSafe(parent, childType1, true)
46 && BasicValidations.checkPresentChildOfTypeSafe(parent, childType2, false)) {
47 ValidationUtil.ex(ValidationUtil.f("(In (sub)module:%s) Both %s and %s statement present in %s:%s",
48 ValidationUtil.getRootParentName(parent), ValidationUtil.getSimpleStatementName(childType1),
49 ValidationUtil.getSimpleStatementName(childType2),
50 ValidationUtil.getSimpleStatementName(parent.getClass()), ValidationUtil.getName(parent)));
54 static void checkOnlyPermittedValues(final ParseTree ctx, final Set<String> permittedValues) {
55 String mandatory = ValidationUtil.getName(ctx);
56 String rootParentName = ValidationUtil.getRootParentName(ctx);
58 if (!permittedValues.contains(mandatory)) {
59 ValidationUtil.ex(ValidationUtil.f(
60 "(In (sub)module:%s) %s:%s, illegal value for %s statement, only permitted:%s", rootParentName,
61 ValidationUtil.getSimpleStatementName(ctx.getClass()), mandatory,
62 ValidationUtil.getSimpleStatementName(ctx.getClass()), permittedValues));
66 static void checkUniquenessInNamespace(final ParseTree stmt, final Set<String> uniques) {
67 String name = ValidationUtil.getName(stmt);
68 String rootParentName = ValidationUtil.getRootParentName(stmt);
70 if (uniques.contains(name)) {
71 ValidationUtil.ex(ValidationUtil.f("(In (sub)module:%s) %s:%s not unique in (sub)module", rootParentName,
72 ValidationUtil.getSimpleStatementName(stmt.getClass()), name));
78 * Check if only one module or submodule is present in session(one yang
81 static void checkIsModuleIdNull(final String globalId) {
82 if (globalId != null) {
83 ValidationUtil.ex(ValidationUtil.f("Multiple (sub)modules per file"));
87 static void checkPresentYangVersion(final ParseTree ctx, final String moduleName) {
88 if (!checkPresentChildOfTypeSafe(ctx, Yang_version_stmtContext.class, true)) {
89 ValidationUtil.ex(ValidationUtil.f(
90 "Yang version statement not present in module:%s, Validating as yang version:%s", moduleName,
91 SUPPORTED_YANG_VERSION));
95 static void checkDateFormat(final ParseTree stmt) {
97 SimpleDateFormatUtil.getRevisionFormat().parse(ValidationUtil.getName(stmt));
98 } catch (ParseException e) {
99 String exceptionMessage = ValidationUtil.f(
100 "(In (sub)module:%s) %s:%s, invalid date format expected date format is:%s",
101 ValidationUtil.getRootParentName(stmt), ValidationUtil.getSimpleStatementName(stmt.getClass()),
102 ValidationUtil.getName(stmt), SimpleDateFormatUtil.getRevisionFormat().format(new Date()));
103 ValidationUtil.ex(exceptionMessage);
107 static void checkIdentifier(final ParseTree statement) {
108 checkIdentifierInternal(statement, ValidationUtil.getName(statement));
111 static void checkIdentifierInternal(final ParseTree statement, final String name) {
112 if (!IDENTIFIER_PATTERN.matcher(name).matches()) {
114 String message = ValidationUtil.f("%s statement identifier:%s is not in required format:%s",
115 ValidationUtil.getSimpleStatementName(statement.getClass()), name, IDENTIFIER_PATTERN.toString());
116 String parent = ValidationUtil.getRootParentName(statement);
117 message = parent.equals(name) ? message : ValidationUtil.f("(In (sub)module:%s) %s", parent, message);
119 if (statement instanceof ParserRuleContext) {
120 message = "Error on line " + ((ParserRuleContext) statement).getStart().getLine() + ": " + message;
123 ValidationUtil.ex(message);
127 static void checkPrefixedIdentifier(final ParseTree statement) {
128 checkPrefixedIdentifierInternal(statement, ValidationUtil.getName(statement));
131 private static void checkPrefixedIdentifierInternal(final ParseTree statement, final String id) {
132 Matcher matcher = PREFIX_IDENTIFIER_PATTERN.matcher(id);
134 if (matcher.matches()) {
137 checkIdentifierInternal(statement, matcher.group(1));
139 checkIdentifierInternal(statement, matcher.group(2));
140 } catch (YangValidationException e) {
141 ValidationUtil.ex(ValidationUtil.f("Prefixed id:%s not in required format, details:%s", id,
145 checkIdentifierInternal(statement, id);
149 static void checkSchemaNodeIdentifier(final ParseTree statement) {
150 String id = ValidationUtil.getName(statement);
153 for (String oneOfId : SLASH_SPLITTER.split(id)) {
154 checkPrefixedIdentifierInternal(statement, oneOfId);
156 } catch (YangValidationException e) {
157 ValidationUtil.ex(ValidationUtil.f("Schema node id:%s not in required format, details:%s", id,
162 private interface MessageProvider {
166 private static void checkPresentChildOfTypeInternal(final ParseTree parent, final Set<Class<? extends ParseTree>> expectedChildType,
167 final MessageProvider message, final boolean atMostOne) {
168 if (!checkPresentChildOfTypeSafe(parent, expectedChildType, atMostOne)) {
169 String str = atMostOne ? "(Expected exactly one statement) " + message.getMessage() : message.getMessage();
170 ValidationUtil.ex(str);
174 static void checkPresentChildOfType(final ParseTree parent, final Class<? extends ParseTree> expectedChildType,
175 final boolean atMostOne) {
177 // Construct message in checkPresentChildOfTypeInternal only if
178 // validation fails, not in advance
179 MessageProvider message = new MessageProvider() {
182 public String getMessage() {
183 String message = ValidationUtil.f("Missing %s statement in %s:%s",
184 ValidationUtil.getSimpleStatementName(expectedChildType),
185 ValidationUtil.getSimpleStatementName(parent.getClass()), ValidationUtil.getName(parent));
187 String root = ValidationUtil.getRootParentName(parent);
188 message = format("(In (sub)module:%s) %s", root, message);
193 Set<Class<? extends ParseTree>> expectedChildTypeSet = Sets.newHashSet();
194 expectedChildTypeSet.add(expectedChildType);
196 checkPresentChildOfTypeInternal(parent, expectedChildTypeSet, message, atMostOne);
201 * Implementation of interface <code>MessageProvider</code> for method
202 * {@link BasicValidations#checkPresentChildOfTypeSafe(ParseTree, Set, boolean)
203 * checkPresentChildOfTypeSafe(ParseTree, Set, boolean) * }
205 private static class MessageProviderForSetOfChildTypes implements MessageProvider {
207 private final Set<Class<? extends ParseTree>> expectedChildTypes;
208 private final ParseTree parent;
210 public MessageProviderForSetOfChildTypes(final Set<Class<? extends ParseTree>> expectedChildTypes, final ParseTree parent) {
211 this.expectedChildTypes = expectedChildTypes;
212 this.parent = parent;
216 public String getMessage() {
217 StringBuilder childTypes = new StringBuilder();
218 for (Class<? extends ParseTree> type : expectedChildTypes) {
219 childTypes.append(ValidationUtil.getSimpleStatementName(type));
220 childTypes.append(" OR ");
222 String message = ValidationUtil.f("Missing %s statement in %s:%s", childTypes.toString(),
223 ValidationUtil.getSimpleStatementName(parent.getClass()), ValidationUtil.getName(parent));
225 String root = ValidationUtil.getRootParentName(parent);
226 message = format("(In (sub)module:%s) %s", root, message);
231 static void checkPresentChildOfTypes(final ParseTree parent,
232 final Set<Class<? extends ParseTree>> expectedChildTypes, final boolean atMostOne) {
234 // Construct message in checkPresentChildOfTypeInternal only if
235 // validation fails, not in advance
236 MessageProvider message = new MessageProviderForSetOfChildTypes(expectedChildTypes, parent);
237 checkPresentChildOfTypeInternal(parent, expectedChildTypes, message, atMostOne);
240 private static boolean checkPresentChildOfTypeSafe(final ParseTree parent, final Set<Class<? extends ParseTree>> expectedChildType,
241 final boolean atMostOne) {
243 int foundChildrenOfType = ValidationUtil.countPresentChildrenOfType(parent, expectedChildType);
245 return atMostOne ? foundChildrenOfType == 1 : foundChildrenOfType != 0;
248 private static boolean checkPresentChildOfTypeSafe(final ParseTree parent, final Class<? extends ParseTree> expectedChildType,
249 final boolean atMostOne) {
251 int foundChildrenOfType = ValidationUtil.countPresentChildrenOfType(parent, expectedChildType);
253 return atMostOne ? foundChildrenOfType == 1 : foundChildrenOfType != 0;
256 static Iterable<String> getAndCheckUniqueKeys(final ParseTree ctx) {
257 String key = ValidationUtil.getName(ctx);
258 ParseTree parent = ctx.getParent();
259 String rootParentName = ValidationUtil.getRootParentName(ctx);
261 Iterable<String> keyList = ValidationUtil.listKeysFromId(key);
262 Set<String> duplicates = ValidationUtil.getDuplicates(keyList);
264 if (!duplicates.isEmpty()) {
265 ValidationUtil.ex(ValidationUtil.f("(In (sub)module:%s) %s:%s, %s:%s contains duplicates:%s",
266 rootParentName, ValidationUtil.getSimpleStatementName(parent.getClass()),
267 ValidationUtil.getName(parent), ValidationUtil.getSimpleStatementName(ctx.getClass()), key,