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/eplv10.html
8 package org.opendaylight.controller.yang.model.validator;
10 import java.text.DateFormat;
11 import java.text.ParseException;
12 import java.util.Date;
13 import java.util.List;
15 import java.util.regex.Matcher;
16 import java.util.regex.Pattern;
18 import org.antlr.v4.runtime.tree.ParseTree;
19 import org.opendaylight.controller.antlrv4.code.gen.YangParser.Yang_version_stmtContext;
20 import org.opendaylight.controller.yang.model.parser.impl.YangModelParserListenerImpl;
21 import org.opendaylight.controller.yang.model.parser.util.YangValidationException;
23 import com.google.common.collect.Sets;
26 * Reusable checks of basic constraints on yang statements
28 final class BasicValidations {
30 static final String SUPPORTED_YANG_VERSION = "1";
32 static void checkNotPresentBoth(ParseTree parent,
33 Class<? extends ParseTree> childType1,
34 Class<? extends ParseTree> childType2) {
35 if (BasicValidations.checkPresentChildOfTypeSafe(parent, childType1,
37 && BasicValidations.checkPresentChildOfTypeSafe(parent,
41 .f("(In (sub)module:%s) Both %s and %s statement present in %s:%s",
42 ValidationUtil.getRootParentName(parent),
44 .getSimpleStatementName(childType1),
46 .getSimpleStatementName(childType2),
48 .getSimpleStatementName(parent
50 ValidationUtil.getName(parent)));
53 static void checkOnlyPermittedValues(ParseTree ctx,
54 Set<String> permittedValues) {
55 String mandatory = ValidationUtil.getName(ctx);
56 String rootParentName = ValidationUtil.getRootParentName(ctx);
58 if (!permittedValues.contains(mandatory))
61 .f("(In (sub)module:%s) %s:%s, illegal value for %s statement, only permitted:%s",
62 rootParentName, ValidationUtil
63 .getSimpleStatementName(ctx
64 .getClass()), mandatory,
65 ValidationUtil.getSimpleStatementName(ctx
66 .getClass()), permittedValues));
69 static void checkUniquenessInNamespace(ParseTree stmt, Set<String> uniques) {
70 String name = ValidationUtil.getName(stmt);
71 String rootParentName = ValidationUtil.getRootParentName(stmt);
73 if (uniques.contains(name))
74 ValidationUtil.ex(ValidationUtil.f(
75 "(In (sub)module:%s) %s:%s not unique in (sub)module",
77 ValidationUtil.getSimpleStatementName(stmt.getClass()),
83 * Check if only one module or submodule is present in session(one yang
86 static void checkOnlyOneModulePresent(String moduleName, String globalId) {
88 ValidationUtil.ex(ValidationUtil
89 .f("Multiple (sub)modules per file"));
92 static void checkPresentYangVersion(ParseTree ctx, String moduleName) {
93 if (!checkPresentChildOfTypeSafe(ctx, Yang_version_stmtContext.class,
97 .f("Yang version statement not present in module:%s, Validating as yang version:%s",
98 moduleName, SUPPORTED_YANG_VERSION));
101 static void checkDateFormat(ParseTree stmt, DateFormat format) {
103 format.parse(ValidationUtil.getName(stmt));
104 } catch (ParseException e) {
105 String exceptionMessage = ValidationUtil
106 .f("(In (sub)module:%s) %s:%s, invalid date format expected date format is:%s",
107 ValidationUtil.getRootParentName(stmt),
108 ValidationUtil.getSimpleStatementName(stmt
109 .getClass()), ValidationUtil.getName(stmt),
110 YangModelParserListenerImpl.simpleDateFormat
111 .format(new Date()));
112 ValidationUtil.ex(exceptionMessage);
116 static Pattern identifierPattern = Pattern
117 .compile("[a-zA-Z_][a-zA-Z0-9_.-]*");
119 static void checkIdentifier(ParseTree statement) {
120 checkIdentifierInternal(statement, ValidationUtil.getName(statement));
123 static void checkIdentifierInternal(ParseTree statement, String name) {
124 if (!identifierPattern.matcher(name).matches()) {
126 String message = ValidationUtil
127 .f("%s statement identifier:%s is not in required format:%s",
128 ValidationUtil.getSimpleStatementName(statement
129 .getClass()), name, identifierPattern
131 String parent = ValidationUtil.getRootParentName(statement);
132 message = parent.equals(name) ? message : ValidationUtil.f(
133 "(In (sub)module:%s) %s", parent, message);
135 ValidationUtil.ex(message);
139 static Pattern prefixedIdentifierPattern = Pattern.compile("(.+):(.+)");
141 static void checkPrefixedIdentifier(ParseTree statement) {
142 checkPrefixedIdentifierInternal(statement,
143 ValidationUtil.getName(statement));
146 private static void checkPrefixedIdentifierInternal(ParseTree statement,
148 Matcher matcher = prefixedIdentifierPattern.matcher(id);
150 if (matcher.matches()) {
153 checkIdentifierInternal(statement, matcher.group(1));
155 checkIdentifierInternal(statement, matcher.group(2));
156 } catch (YangValidationException e) {
157 ValidationUtil.ex(ValidationUtil.f(
158 "Prefixed id:%s not in required format, details:%s",
159 id, e.getMessage()));
162 checkIdentifierInternal(statement, id);
165 static void checkSchemaNodeIdentifier(ParseTree statement) {
166 String id = ValidationUtil.getName(statement);
169 for (String oneOfId : id.split("/")) {
170 if (oneOfId.isEmpty())
172 checkPrefixedIdentifierInternal(statement, oneOfId);
174 } catch (YangValidationException e) {
175 ValidationUtil.ex(ValidationUtil.f(
176 "Schema node id:%s not in required format, details:%s", id,
181 private static interface MessageProvider {
185 static void checkPresentChildOfTypeInternal(ParseTree parent,
186 Set<Class<? extends ParseTree>> expectedChildType,
187 MessageProvider message, boolean atMostOne) {
188 if (!checkPresentChildOfTypeSafe(parent, expectedChildType, atMostOne)) {
189 String str = atMostOne ? "(Expected exactly one statement) "
190 + message.getMessage() : message.getMessage();
191 ValidationUtil.ex(str);
195 static void checkPresentChildOfType(final ParseTree parent,
196 final Class<? extends ParseTree> expectedChildType,
199 // Construct message in checkPresentChildOfTypeInternal only if
200 // validaiton fails, not in advance
201 MessageProvider message = new MessageProvider() {
204 public String getMessage() {
205 String message = ValidationUtil
206 .f("Missing %s statement in %s:%s", ValidationUtil
207 .getSimpleStatementName(expectedChildType),
208 ValidationUtil.getSimpleStatementName(parent
209 .getClass()), ValidationUtil
212 String root = ValidationUtil.getRootParentName(parent);
213 message = parent.equals(ValidationUtil
214 .getRootParentName(parent)) ? message : ValidationUtil
215 .f("(In (sub)module:%s) %s", root, message);
220 Set<Class<? extends ParseTree>> expectedChildTypeSet = Sets
222 expectedChildTypeSet.add(expectedChildType);
224 checkPresentChildOfTypeInternal(parent, expectedChildTypeSet, message,
228 static void checkPresentChildOfTypes(final ParseTree parent,
229 final Set<Class<? extends ParseTree>> expectedChildTypes,
232 // Construct message in checkPresentChildOfTypeInternal only if
233 // validaiton fails, not in advance
234 MessageProvider message = new MessageProvider() {
237 public String getMessage() {
238 StringBuilder childTypes = new StringBuilder();
239 String orStr = " OR ";
240 for (Class<? extends ParseTree> type : expectedChildTypes) {
241 childTypes.append(ValidationUtil
242 .getSimpleStatementName(type));
243 childTypes.append(orStr);
246 String message = ValidationUtil
247 .f("Missing %s statement in %s:%s", childTypes
248 .toString(), ValidationUtil
249 .getSimpleStatementName(parent.getClass()),
250 ValidationUtil.getName(parent));
252 String root = ValidationUtil.getRootParentName(parent);
253 message = parent.equals(ValidationUtil
254 .getRootParentName(parent)) ? message : ValidationUtil
255 .f("(In (sub)module:%s) %s", root, message);
261 checkPresentChildOfTypeInternal(parent, expectedChildTypes, message,
265 static boolean checkPresentChildOfTypeSafe(ParseTree parent,
266 Set<Class<? extends ParseTree>> expectedChildType, boolean atMostOne) {
268 int foundChildrenOfType = ValidationUtil.countPresentChildrenOfType(
269 parent, expectedChildType);
271 return atMostOne ? foundChildrenOfType == 1 ? true : false
272 : foundChildrenOfType != 0 ? true : false;
275 static boolean checkPresentChildOfTypeSafe(ParseTree parent,
276 Class<? extends ParseTree> expectedChildType, boolean atMostOne) {
278 int foundChildrenOfType = ValidationUtil.countPresentChildrenOfType(
279 parent, expectedChildType);
281 return atMostOne ? foundChildrenOfType == 1 ? true : false
282 : foundChildrenOfType != 0 ? true : false;
285 static List<String> getAndCheckUniqueKeys(ParseTree ctx) {
286 String key = ValidationUtil.getName(ctx);
287 ParseTree parent = ctx.getParent();
288 String rootParentName = ValidationUtil.getRootParentName(ctx);
290 List<String> keyList = ValidationUtil.listKeysFromId(key);
291 Set<String> duplicates = ValidationUtil.getDuplicates(keyList);
293 if (duplicates.size() != 0)
294 ValidationUtil.ex(ValidationUtil.f(
295 "(In (sub)module:%s) %s:%s, %s:%s contains duplicates:%s",
297 ValidationUtil.getSimpleStatementName(parent.getClass()),
298 ValidationUtil.getName(parent),
299 ValidationUtil.getSimpleStatementName(ctx.getClass()), key,