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.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.ParserRuleContext;
19 import org.antlr.v4.runtime.tree.ParseTree;
20 import org.opendaylight.controller.antlrv4.code.gen.YangParser.Yang_version_stmtContext;
21 import org.opendaylight.controller.yang.parser.impl.YangParserListenerImpl;
22 import org.opendaylight.controller.yang.parser.util.YangValidationException;
24 import com.google.common.collect.Sets;
27 * Reusable checks of basic constraints on yang statements
29 final class BasicValidations {
31 static final String SUPPORTED_YANG_VERSION = "1";
33 static void checkNotPresentBoth(ParseTree parent,
34 Class<? extends ParseTree> childType1,
35 Class<? extends ParseTree> childType2) {
36 if (BasicValidations.checkPresentChildOfTypeSafe(parent, childType1,
38 && BasicValidations.checkPresentChildOfTypeSafe(parent,
42 .f("(In (sub)module:%s) Both %s and %s statement present in %s:%s",
43 ValidationUtil.getRootParentName(parent),
45 .getSimpleStatementName(childType1),
47 .getSimpleStatementName(childType2),
49 .getSimpleStatementName(parent
51 ValidationUtil.getName(parent)));
54 static void checkOnlyPermittedValues(ParseTree ctx,
55 Set<String> permittedValues) {
56 String mandatory = ValidationUtil.getName(ctx);
57 String rootParentName = ValidationUtil.getRootParentName(ctx);
59 if (!permittedValues.contains(mandatory))
62 .f("(In (sub)module:%s) %s:%s, illegal value for %s statement, only permitted:%s",
63 rootParentName, ValidationUtil
64 .getSimpleStatementName(ctx
65 .getClass()), mandatory,
66 ValidationUtil.getSimpleStatementName(ctx
67 .getClass()), permittedValues));
70 static void checkUniquenessInNamespace(ParseTree stmt, Set<String> uniques) {
71 String name = ValidationUtil.getName(stmt);
72 String rootParentName = ValidationUtil.getRootParentName(stmt);
74 if (uniques.contains(name))
75 ValidationUtil.ex(ValidationUtil.f(
76 "(In (sub)module:%s) %s:%s not unique in (sub)module",
78 ValidationUtil.getSimpleStatementName(stmt.getClass()),
84 * Check if only one module or submodule is present in session(one yang
87 static void checkOnlyOneModulePresent(String moduleName, String globalId) {
89 ValidationUtil.ex(ValidationUtil
90 .f("Multiple (sub)modules per file"));
93 static void checkPresentYangVersion(ParseTree ctx, String moduleName) {
94 if (!checkPresentChildOfTypeSafe(ctx, Yang_version_stmtContext.class,
98 .f("Yang version statement not present in module:%s, Validating as yang version:%s",
99 moduleName, SUPPORTED_YANG_VERSION));
102 static void checkDateFormat(ParseTree stmt, DateFormat format) {
104 format.parse(ValidationUtil.getName(stmt));
105 } catch (ParseException e) {
106 String exceptionMessage = ValidationUtil
107 .f("(In (sub)module:%s) %s:%s, invalid date format expected date format is:%s",
108 ValidationUtil.getRootParentName(stmt),
109 ValidationUtil.getSimpleStatementName(stmt
110 .getClass()), ValidationUtil.getName(stmt),
111 YangParserListenerImpl.simpleDateFormat
112 .format(new Date()));
113 ValidationUtil.ex(exceptionMessage);
117 static Pattern identifierPattern = Pattern
118 .compile("[a-zA-Z_][a-zA-Z0-9_.-]*");
120 static void checkIdentifier(ParseTree statement) {
121 checkIdentifierInternal(statement, ValidationUtil.getName(statement));
124 static void checkIdentifierInternal(ParseTree statement, String name) {
125 if (!identifierPattern.matcher(name).matches()) {
127 String message = ValidationUtil
128 .f("%s statement identifier:%s is not in required format:%s",
129 ValidationUtil.getSimpleStatementName(statement
130 .getClass()), name, identifierPattern
132 String parent = ValidationUtil.getRootParentName(statement);
133 message = parent.equals(name) ? message : ValidationUtil.f(
134 "(In (sub)module:%s) %s", parent, message);
136 if(statement instanceof ParserRuleContext) {
137 message = "Error on line "+ ((ParserRuleContext)statement).getStart().getLine() + ": "+ message;
140 ValidationUtil.ex(message);
144 static Pattern prefixedIdentifierPattern = Pattern.compile("(.+):(.+)");
146 static void checkPrefixedIdentifier(ParseTree statement) {
147 checkPrefixedIdentifierInternal(statement,
148 ValidationUtil.getName(statement));
151 private static void checkPrefixedIdentifierInternal(ParseTree statement,
153 Matcher matcher = prefixedIdentifierPattern.matcher(id);
155 if (matcher.matches()) {
158 checkIdentifierInternal(statement, matcher.group(1));
160 checkIdentifierInternal(statement, matcher.group(2));
161 } catch (YangValidationException e) {
162 ValidationUtil.ex(ValidationUtil.f(
163 "Prefixed id:%s not in required format, details:%s",
164 id, e.getMessage()));
167 checkIdentifierInternal(statement, id);
170 static void checkSchemaNodeIdentifier(ParseTree statement) {
171 String id = ValidationUtil.getName(statement);
174 for (String oneOfId : id.split("/")) {
175 if (oneOfId.isEmpty())
177 checkPrefixedIdentifierInternal(statement, oneOfId);
179 } catch (YangValidationException e) {
180 ValidationUtil.ex(ValidationUtil.f(
181 "Schema node id:%s not in required format, details:%s", id,
186 private static interface MessageProvider {
190 static void checkPresentChildOfTypeInternal(ParseTree parent,
191 Set<Class<? extends ParseTree>> expectedChildType,
192 MessageProvider message, boolean atMostOne) {
193 if (!checkPresentChildOfTypeSafe(parent, expectedChildType, atMostOne)) {
194 String str = atMostOne ? "(Expected exactly one statement) "
195 + message.getMessage() : message.getMessage();
196 ValidationUtil.ex(str);
200 static void checkPresentChildOfType(final ParseTree parent,
201 final Class<? extends ParseTree> expectedChildType,
204 // Construct message in checkPresentChildOfTypeInternal only if
205 // validaiton fails, not in advance
206 MessageProvider message = new MessageProvider() {
209 public String getMessage() {
210 String message = ValidationUtil
211 .f("Missing %s statement in %s:%s", ValidationUtil
212 .getSimpleStatementName(expectedChildType),
213 ValidationUtil.getSimpleStatementName(parent
214 .getClass()), ValidationUtil
217 String root = ValidationUtil.getRootParentName(parent);
218 message = parent.equals(ValidationUtil
219 .getRootParentName(parent)) ? message : ValidationUtil
220 .f("(In (sub)module:%s) %s", root, message);
225 Set<Class<? extends ParseTree>> expectedChildTypeSet = Sets
227 expectedChildTypeSet.add(expectedChildType);
229 checkPresentChildOfTypeInternal(parent, expectedChildTypeSet, message,
233 static void checkPresentChildOfTypes(final ParseTree parent,
234 final Set<Class<? extends ParseTree>> expectedChildTypes,
237 // Construct message in checkPresentChildOfTypeInternal only if
238 // validaiton fails, not in advance
239 MessageProvider message = new MessageProvider() {
242 public String getMessage() {
243 StringBuilder childTypes = new StringBuilder();
244 String orStr = " OR ";
245 for (Class<? extends ParseTree> type : expectedChildTypes) {
246 childTypes.append(ValidationUtil
247 .getSimpleStatementName(type));
248 childTypes.append(orStr);
251 String message = ValidationUtil
252 .f("Missing %s statement in %s:%s", childTypes
253 .toString(), ValidationUtil
254 .getSimpleStatementName(parent.getClass()),
255 ValidationUtil.getName(parent));
257 String root = ValidationUtil.getRootParentName(parent);
258 message = parent.equals(ValidationUtil
259 .getRootParentName(parent)) ? message : ValidationUtil
260 .f("(In (sub)module:%s) %s", root, message);
266 checkPresentChildOfTypeInternal(parent, expectedChildTypes, message,
270 static boolean checkPresentChildOfTypeSafe(ParseTree parent,
271 Set<Class<? extends ParseTree>> expectedChildType, boolean atMostOne) {
273 int foundChildrenOfType = ValidationUtil.countPresentChildrenOfType(
274 parent, expectedChildType);
276 return atMostOne ? foundChildrenOfType == 1 ? true : false
277 : foundChildrenOfType != 0 ? true : false;
280 static boolean checkPresentChildOfTypeSafe(ParseTree parent,
281 Class<? extends ParseTree> expectedChildType, boolean atMostOne) {
283 int foundChildrenOfType = ValidationUtil.countPresentChildrenOfType(
284 parent, expectedChildType);
286 return atMostOne ? foundChildrenOfType == 1 ? true : false
287 : foundChildrenOfType != 0 ? true : false;
290 static List<String> getAndCheckUniqueKeys(ParseTree ctx) {
291 String key = ValidationUtil.getName(ctx);
292 ParseTree parent = ctx.getParent();
293 String rootParentName = ValidationUtil.getRootParentName(ctx);
295 List<String> keyList = ValidationUtil.listKeysFromId(key);
296 Set<String> duplicates = ValidationUtil.getDuplicates(keyList);
298 if (duplicates.size() != 0)
299 ValidationUtil.ex(ValidationUtil.f(
300 "(In (sub)module:%s) %s:%s, %s:%s contains duplicates:%s",
302 ValidationUtil.getSimpleStatementName(parent.getClass()),
303 ValidationUtil.getName(parent),
304 ValidationUtil.getSimpleStatementName(ctx.getClass()), key,