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.yangtools.yang.parser.impl;
10 import static java.lang.String.format;
12 import com.google.common.collect.Sets;
13 import java.text.ParseException;
14 import java.util.Date;
15 import java.util.List;
17 import java.util.regex.Matcher;
18 import java.util.regex.Pattern;
19 import org.antlr.v4.runtime.ParserRuleContext;
20 import org.antlr.v4.runtime.tree.ParseTree;
21 import org.opendaylight.yangtools.antlrv4.code.gen.YangParser.Yang_version_stmtContext;
22 import org.opendaylight.yangtools.yang.common.SimpleDateFormatUtil;
23 import org.opendaylight.yangtools.yang.parser.util.YangValidationException;
26 * Reusable checks of basic constraints on yang statements
28 final class BasicValidations {
30 static final String SUPPORTED_YANG_VERSION = "1";
33 * It isn't desirable to create instance of this class.
35 private BasicValidations() {
38 static void checkNotPresentBoth(final ParseTree parent, final Class<? extends ParseTree> childType1,
39 final Class<? extends ParseTree> childType2) {
40 if (BasicValidations.checkPresentChildOfTypeSafe(parent, childType1, true)
41 && BasicValidations.checkPresentChildOfTypeSafe(parent, childType2, false)) {
42 ValidationUtil.ex(ValidationUtil.f("(In (sub)module:%s) Both %s and %s statement present in %s:%s",
43 ValidationUtil.getRootParentName(parent), ValidationUtil.getSimpleStatementName(childType1),
44 ValidationUtil.getSimpleStatementName(childType2),
45 ValidationUtil.getSimpleStatementName(parent.getClass()), ValidationUtil.getName(parent)));
49 static void checkOnlyPermittedValues(final ParseTree ctx, final Set<String> permittedValues) {
50 String mandatory = ValidationUtil.getName(ctx);
51 String rootParentName = ValidationUtil.getRootParentName(ctx);
53 if (!permittedValues.contains(mandatory)) {
54 ValidationUtil.ex(ValidationUtil.f(
55 "(In (sub)module:%s) %s:%s, illegal value for %s statement, only permitted:%s", rootParentName,
56 ValidationUtil.getSimpleStatementName(ctx.getClass()), mandatory,
57 ValidationUtil.getSimpleStatementName(ctx.getClass()), permittedValues));
61 static void checkUniquenessInNamespace(final ParseTree stmt, final Set<String> uniques) {
62 String name = ValidationUtil.getName(stmt);
63 String rootParentName = ValidationUtil.getRootParentName(stmt);
65 if (uniques.contains(name)) {
66 ValidationUtil.ex(ValidationUtil.f("(In (sub)module:%s) %s:%s not unique in (sub)module", rootParentName,
67 ValidationUtil.getSimpleStatementName(stmt.getClass()), name));
73 * Check if only one module or submodule is present in session(one yang
76 static void checkIsModuleIdNull(final String globalId) {
77 if (globalId != null) {
78 ValidationUtil.ex(ValidationUtil.f("Multiple (sub)modules per file"));
82 static void checkPresentYangVersion(final ParseTree ctx, final String moduleName) {
83 if (!checkPresentChildOfTypeSafe(ctx, Yang_version_stmtContext.class, true)) {
84 ValidationUtil.ex(ValidationUtil.f(
85 "Yang version statement not present in module:%s, Validating as yang version:%s", moduleName,
86 SUPPORTED_YANG_VERSION));
90 static void checkDateFormat(final ParseTree stmt) {
92 SimpleDateFormatUtil.getRevisionFormat().parse(ValidationUtil.getName(stmt));
93 } catch (ParseException e) {
94 String exceptionMessage = ValidationUtil.f(
95 "(In (sub)module:%s) %s:%s, invalid date format expected date format is:%s",
96 ValidationUtil.getRootParentName(stmt), ValidationUtil.getSimpleStatementName(stmt.getClass()),
97 ValidationUtil.getName(stmt), SimpleDateFormatUtil.getRevisionFormat().format(new Date()));
98 ValidationUtil.ex(exceptionMessage);
102 private static final Pattern identifierPattern = Pattern.compile("[a-zA-Z_][a-zA-Z0-9_.-]*");
104 static void checkIdentifier(final ParseTree statement) {
105 checkIdentifierInternal(statement, ValidationUtil.getName(statement));
108 static void checkIdentifierInternal(final ParseTree statement, final String name) {
109 if (!identifierPattern.matcher(name).matches()) {
111 String message = ValidationUtil.f("%s statement identifier:%s is not in required format:%s",
112 ValidationUtil.getSimpleStatementName(statement.getClass()), name, identifierPattern.toString());
113 String parent = ValidationUtil.getRootParentName(statement);
114 message = parent.equals(name) ? message : ValidationUtil.f("(In (sub)module:%s) %s", parent, message);
116 if (statement instanceof ParserRuleContext) {
117 message = "Error on line " + ((ParserRuleContext) statement).getStart().getLine() + ": " + message;
120 ValidationUtil.ex(message);
124 private static final Pattern prefixedIdentifierPattern = Pattern.compile("(.+):(.+)");
126 static void checkPrefixedIdentifier(final ParseTree statement) {
127 checkPrefixedIdentifierInternal(statement, ValidationUtil.getName(statement));
130 private static void checkPrefixedIdentifierInternal(final ParseTree statement, final String id) {
131 Matcher matcher = prefixedIdentifierPattern.matcher(id);
133 if (matcher.matches()) {
136 checkIdentifierInternal(statement, matcher.group(1));
138 checkIdentifierInternal(statement, matcher.group(2));
139 } catch (YangValidationException e) {
140 ValidationUtil.ex(ValidationUtil.f("Prefixed id:%s not in required format, details:%s", id,
144 checkIdentifierInternal(statement, id);
148 static void checkSchemaNodeIdentifier(final ParseTree statement) {
149 String id = ValidationUtil.getName(statement);
152 for (String oneOfId : id.split("/")) {
153 if (oneOfId.isEmpty()) {
156 checkPrefixedIdentifierInternal(statement, oneOfId);
158 } catch (YangValidationException e) {
159 ValidationUtil.ex(ValidationUtil.f("Schema node id:%s not in required format, details:%s", id,
164 private interface MessageProvider {
168 private static void checkPresentChildOfTypeInternal(final ParseTree parent, final Set<Class<? extends ParseTree>> expectedChildType,
169 final MessageProvider message, final boolean atMostOne) {
170 if (!checkPresentChildOfTypeSafe(parent, expectedChildType, atMostOne)) {
171 String str = atMostOne ? "(Expected exactly one statement) " + message.getMessage() : message.getMessage();
172 ValidationUtil.ex(str);
176 static void checkPresentChildOfType(final ParseTree parent, final Class<? extends ParseTree> expectedChildType,
177 final boolean atMostOne) {
179 // Construct message in checkPresentChildOfTypeInternal only if
180 // validation fails, not in advance
181 MessageProvider message = new MessageProvider() {
184 public String getMessage() {
185 String message = ValidationUtil.f("Missing %s statement in %s:%s",
186 ValidationUtil.getSimpleStatementName(expectedChildType),
187 ValidationUtil.getSimpleStatementName(parent.getClass()), ValidationUtil.getName(parent));
189 String root = ValidationUtil.getRootParentName(parent);
190 message = format("(In (sub)module:%s) %s", root, message);
195 Set<Class<? extends ParseTree>> expectedChildTypeSet = Sets.newHashSet();
196 expectedChildTypeSet.add(expectedChildType);
198 checkPresentChildOfTypeInternal(parent, expectedChildTypeSet, message, atMostOne);
203 * Implementation of interface <code>MessageProvider</code> for method
204 * {@link BasicValidations#checkPresentChildOfTypeSafe(ParseTree, Set, boolean)
205 * checkPresentChildOfTypeSafe(ParseTree, Set, boolean) * }
207 private static class MessageProviderForSetOfChildTypes implements MessageProvider {
209 private final Set<Class<? extends ParseTree>> expectedChildTypes;
210 private final ParseTree parent;
212 public MessageProviderForSetOfChildTypes(final Set<Class<? extends ParseTree>> expectedChildTypes, final ParseTree parent) {
213 this.expectedChildTypes = expectedChildTypes;
214 this.parent = parent;
218 public String getMessage() {
219 StringBuilder childTypes = new StringBuilder();
220 String orStr = " OR ";
221 for (Class<? extends ParseTree> type : expectedChildTypes) {
222 childTypes.append(ValidationUtil.getSimpleStatementName(type));
223 childTypes.append(orStr);
225 String message = ValidationUtil.f("Missing %s statement in %s:%s", childTypes.toString(),
226 ValidationUtil.getSimpleStatementName(parent.getClass()), ValidationUtil.getName(parent));
228 String root = ValidationUtil.getRootParentName(parent);
229 message = format("(In (sub)module:%s) %s", root, message);
234 static void checkPresentChildOfTypes(final ParseTree parent,
235 final Set<Class<? extends ParseTree>> expectedChildTypes, final boolean atMostOne) {
237 // Construct message in checkPresentChildOfTypeInternal only if
238 // validation fails, not in advance
239 MessageProvider message = new MessageProviderForSetOfChildTypes(expectedChildTypes, parent);
240 checkPresentChildOfTypeInternal(parent, expectedChildTypes, message, atMostOne);
243 private static boolean checkPresentChildOfTypeSafe(final ParseTree parent, final Set<Class<? extends ParseTree>> expectedChildType,
244 final boolean atMostOne) {
246 int foundChildrenOfType = ValidationUtil.countPresentChildrenOfType(parent, expectedChildType);
248 return atMostOne ? foundChildrenOfType == 1 : foundChildrenOfType != 0;
251 private static boolean checkPresentChildOfTypeSafe(final ParseTree parent, final Class<? extends ParseTree> expectedChildType,
252 final boolean atMostOne) {
254 int foundChildrenOfType = ValidationUtil.countPresentChildrenOfType(parent, expectedChildType);
256 return atMostOne ? foundChildrenOfType == 1 : foundChildrenOfType != 0;
259 static List<String> getAndCheckUniqueKeys(final ParseTree ctx) {
260 String key = ValidationUtil.getName(ctx);
261 ParseTree parent = ctx.getParent();
262 String rootParentName = ValidationUtil.getRootParentName(ctx);
264 List<String> keyList = ValidationUtil.listKeysFromId(key);
265 Set<String> duplicates = ValidationUtil.getDuplicates(keyList);
267 if (duplicates.size() != 0) {
268 ValidationUtil.ex(ValidationUtil.f("(In (sub)module:%s) %s:%s, %s:%s contains duplicates:%s",
269 rootParentName, ValidationUtil.getSimpleStatementName(parent.getClass()),
270 ValidationUtil.getName(parent), ValidationUtil.getSimpleStatementName(ctx.getClass()), key,