blob: 5ad6133a3e6b4678274ca0960ecf33b1263a5bdf [file] [log] [blame]
/*
* Copyright 2016-present Open Networking Laboratory
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.onosproject.yangutils.parser.impl.parserutils;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Date;
import java.util.Iterator;
import java.util.LinkedList;
import java.util.List;
import java.util.regex.Pattern;
import org.antlr.v4.runtime.ParserRuleContext;
import org.onosproject.yangutils.datamodel.YangAtomicPath;
import org.onosproject.yangutils.datamodel.YangLeafRef;
import org.onosproject.yangutils.datamodel.YangNodeIdentifier;
import org.onosproject.yangutils.datamodel.YangPathPredicate;
import org.onosproject.yangutils.datamodel.YangRelativePath;
import org.onosproject.yangutils.datamodel.utils.YangConstructType;
import org.onosproject.yangutils.parser.antlrgencode.GeneratedYangParser;
import org.onosproject.yangutils.parser.exceptions.ParserException;
import static org.onosproject.yangutils.datamodel.YangPathArgType.ABSOLUTE_PATH;
import static org.onosproject.yangutils.datamodel.YangPathArgType.RELATIVE_PATH;
import static org.onosproject.yangutils.datamodel.YangPathOperator.EQUALTO;
import static org.onosproject.yangutils.utils.UtilConstants.ADD;
import static org.onosproject.yangutils.utils.UtilConstants.ANCESTOR_ACCESSOR;
import static org.onosproject.yangutils.utils.UtilConstants.ANCESTOR_ACCESSOR_IN_PATH;
import static org.onosproject.yangutils.utils.UtilConstants.CARET;
import static org.onosproject.yangutils.utils.UtilConstants.CHAR_OF_CLOSE_SQUARE_BRACKET;
import static org.onosproject.yangutils.utils.UtilConstants.CHAR_OF_OPEN_SQUARE_BRACKET;
import static org.onosproject.yangutils.utils.UtilConstants.CHAR_OF_SLASH;
import static org.onosproject.yangutils.utils.UtilConstants.CLOSE_PARENTHESIS;
import static org.onosproject.yangutils.utils.UtilConstants.COLON;
import static org.onosproject.yangutils.utils.UtilConstants.CURRENT;
import static org.onosproject.yangutils.utils.UtilConstants.EMPTY_STRING;
import static org.onosproject.yangutils.utils.UtilConstants.FALSE;
import static org.onosproject.yangutils.utils.UtilConstants.OPEN_SQUARE_BRACKET;
import static org.onosproject.yangutils.utils.UtilConstants.QUOTES;
import static org.onosproject.yangutils.utils.UtilConstants.SLASH;
import static org.onosproject.yangutils.utils.UtilConstants.SLASH_FOR_STRING;
import static org.onosproject.yangutils.utils.UtilConstants.TRUE;
import static org.onosproject.yangutils.utils.UtilConstants.YANG_FILE_ERROR;
/**
* Represents an utility for listener.
*/
public final class ListenerUtil {
private static final Pattern IDENTIFIER_PATTERN = Pattern.compile("[a-zA-Z_][a-zA-Z0-9_.-]*");
private static final String DATE_PATTERN = "[0-9]{4}-([0-9]{2}|[0-9])-([0-9]{2}|[0-9])";
private static final String NON_NEGATIVE_INTEGER_PATTERN = "[0-9]+";
private static final Pattern INTEGER_PATTERN = Pattern.compile("[-][0-9]+|[0-9]+");
private static final Pattern PATH_PREDICATE_PATTERN = Pattern.compile("\\[(.*?)\\]");
private static final String XML = "xml";
private static final String ONE = "1";
private static final int IDENTIFIER_LENGTH = 64;
private static final String DATE_FORMAT = "yyyy-MM-dd";
/**
* Creates a new listener util.
*/
private ListenerUtil() {
}
/**
* Removes doubles quotes and concatenates if string has plus symbol.
*
* @param yangStringData string from yang file
* @return concatenated string after removing double quotes
*/
public static String removeQuotesAndHandleConcat(String yangStringData) {
yangStringData = yangStringData.replace("\"", EMPTY_STRING);
String[] tmpData = yangStringData.split(Pattern.quote(ADD));
StringBuilder builder = new StringBuilder();
for (String yangString : tmpData) {
builder.append(yangString);
}
return builder.toString();
}
/**
* Validates identifier and returns concatenated string if string contains plus symbol.
*
* @param identifier string from yang file
* @param yangConstruct yang construct for creating error message
* @param ctx yang construct's context to get the line number and character position
* @return concatenated string after removing double quotes
*/
public static String getValidIdentifier(String identifier, YangConstructType yangConstruct, ParserRuleContext ctx) {
String identifierString = removeQuotesAndHandleConcat(identifier);
ParserException parserException;
if (identifierString.length() > IDENTIFIER_LENGTH) {
parserException = new ParserException("YANG file error : " +
YangConstructType.getYangConstructType(yangConstruct) + " name " + identifierString + " is " +
"greater than 64 characters.");
} else if (!IDENTIFIER_PATTERN.matcher(identifierString).matches()) {
parserException = new ParserException("YANG file error : " +
YangConstructType.getYangConstructType(yangConstruct) + " name " + identifierString + " is not " +
"valid.");
} else if (identifierString.toLowerCase().startsWith(XML)) {
parserException = new ParserException("YANG file error : " +
YangConstructType.getYangConstructType(yangConstruct) + " identifier " + identifierString +
" must not start with (('X'|'x') ('M'|'m') ('L'|'l')).");
} else {
return identifierString;
}
parserException.setLine(ctx.getStart().getLine());
parserException.setCharPosition(ctx.getStart().getCharPositionInLine());
throw parserException;
}
/**
* Validates identifier and returns concatenated string if string contains plus symbol.
*
* @param identifier string from yang file
* @param yangConstruct yang construct for creating error message
* @param ctx yang construct's context to get the line number and character position
* @param yangLeafRef instance of leafref where the path argument has to be set
* @return concatenated string after removing double quotes
*/
public static String getValidIdentifierForLeafref(String identifier, YangConstructType yangConstruct,
ParserRuleContext ctx, YangLeafRef yangLeafRef) {
String identifierString = removeQuotesAndHandleConcat(identifier);
ParserException parserException;
if (identifierString.length() > IDENTIFIER_LENGTH) {
parserException = new ParserException("YANG file error : " + " identifier " + identifierString + " in " +
YangConstructType.getYangConstructType(yangConstruct) + " " + yangLeafRef.getPath() + " is " +
"greater than 64 characters.");
} else if (!IDENTIFIER_PATTERN.matcher(identifierString).matches()) {
parserException = new ParserException("YANG file error : " + " identifier " + identifierString + " in " +
YangConstructType.getYangConstructType(yangConstruct) + " " + yangLeafRef.getPath() + " is not " +
"valid.");
} else if (identifierString.toLowerCase().startsWith(XML)) {
parserException = new ParserException("YANG file error : " + " identifier " + identifierString + " in " +
YangConstructType.getYangConstructType(yangConstruct) + " " + yangLeafRef.getPath() +
" must not start with (('X'|'x') ('M'|'m') ('L'|'l')).");
} else {
return identifierString;
}
parserException.setLine(ctx.getStart().getLine());
parserException.setCharPosition(ctx.getStart().getCharPositionInLine());
throw parserException;
}
/**
* Validates the revision date.
*
* @param dateToValidate input revision date
* @return validation result, true for success, false for failure
*/
public static boolean isDateValid(String dateToValidate) {
if (dateToValidate == null || !dateToValidate.matches(DATE_PATTERN)) {
return false;
}
SimpleDateFormat sdf = new SimpleDateFormat(DATE_FORMAT);
sdf.setLenient(false);
try {
//if not valid, it will throw ParseException
sdf.parse(dateToValidate);
} catch (ParseException e) {
return false;
}
return true;
}
/**
* Validates YANG version.
*
* @param ctx version context object of the grammar rule
* @return valid version
*/
public static byte getValidVersion(GeneratedYangParser.YangVersionStatementContext ctx) {
String value = removeQuotesAndHandleConcat(ctx.version().getText());
if (!value.equals(ONE)) {
ParserException parserException = new ParserException("YANG file error: Input version not supported");
parserException.setLine(ctx.getStart().getLine());
parserException.setCharPosition(ctx.getStart().getCharPositionInLine());
throw parserException;
}
return Byte.valueOf(value);
}
/**
* Validates non negative integer value.
*
* @param integerValue integer to be validated
* @param yangConstruct yang construct for creating error message
* @param ctx context object of the grammar rule
* @return valid non negative integer value
*/
public static int getValidNonNegativeIntegerValue(String integerValue, YangConstructType yangConstruct,
ParserRuleContext ctx) {
String value = removeQuotesAndHandleConcat(integerValue);
if (!value.matches(NON_NEGATIVE_INTEGER_PATTERN)) {
ParserException parserException = new ParserException("YANG file error : " +
YangConstructType.getYangConstructType(yangConstruct) + " value " + value + " is not " +
"valid.");
parserException.setLine(ctx.getStart().getLine());
parserException.setCharPosition(ctx.getStart().getCharPositionInLine());
throw parserException;
}
int valueInInteger;
try {
valueInInteger = Integer.parseInt(value);
} catch (NumberFormatException e) {
ParserException parserException = new ParserException("YANG file error : " +
YangConstructType.getYangConstructType(yangConstruct) + " value " + value + " is not " +
"valid.");
parserException.setLine(ctx.getStart().getLine());
parserException.setCharPosition(ctx.getStart().getCharPositionInLine());
throw parserException;
}
return valueInInteger;
}
/**
* Validates integer value.
*
* @param integerValue integer to be validated
* @param yangConstruct yang construct for creating error message
* @param ctx context object of the grammar rule
* @return valid integer value
*/
public static int getValidIntegerValue(String integerValue, YangConstructType yangConstruct,
ParserRuleContext ctx) {
String value = removeQuotesAndHandleConcat(integerValue);
if (!INTEGER_PATTERN.matcher(value).matches()) {
ParserException parserException = new ParserException("YANG file error : " +
YangConstructType.getYangConstructType(yangConstruct) + " value " + value + " is not " +
"valid.");
parserException.setLine(ctx.getStart().getLine());
parserException.setCharPosition(ctx.getStart().getCharPositionInLine());
throw parserException;
}
int valueInInteger;
try {
valueInInteger = Integer.parseInt(value);
} catch (NumberFormatException e) {
ParserException parserException = new ParserException("YANG file error : " +
YangConstructType.getYangConstructType(yangConstruct) + " value " + value + " is not " +
"valid.");
parserException.setLine(ctx.getStart().getLine());
parserException.setCharPosition(ctx.getStart().getCharPositionInLine());
throw parserException;
}
return valueInInteger;
}
/**
* Validates boolean value.
*
* @param booleanValue value to be validated
* @param yangConstruct yang construct for creating error message
* @param ctx context object of the grammar rule
* @return boolean value either true or false
*/
public static boolean getValidBooleanValue(String booleanValue, YangConstructType yangConstruct,
ParserRuleContext ctx) {
String value = removeQuotesAndHandleConcat(booleanValue);
if (value.equals(TRUE)) {
return true;
} else if (value.equals(FALSE)) {
return false;
} else {
ParserException parserException = new ParserException("YANG file error : " +
YangConstructType.getYangConstructType(yangConstruct) + " value " + value + " is not " +
"valid.");
parserException.setLine(ctx.getStart().getLine());
parserException.setCharPosition(ctx.getStart().getCharPositionInLine());
throw parserException;
}
}
/**
* Returns current date and makes it in usable format for revision.
*
* @return usable current date format for revision
*/
public static Date getCurrentDateForRevision() {
SimpleDateFormat dateFormat = new SimpleDateFormat(DATE_FORMAT);
Date date = new Date();
String dateInString = dateFormat.format(date);
try {
//if not valid, it will throw ParseException
Date now = dateFormat.parse(dateInString);
return date;
} catch (ParseException e) {
ParserException parserException = new ParserException("YANG file error: Input date is not correct");
throw parserException;
}
}
/**
* Checks and return valid node identifier.
*
* @param nodeIdentifierString string from yang file
* @param yangConstruct yang construct for creating error message
* @param ctx yang construct's context to get the line number and character position
* @return valid node identifier
*/
public static YangNodeIdentifier getValidNodeIdentifier(String nodeIdentifierString,
YangConstructType yangConstruct, ParserRuleContext ctx) {
String tmpIdentifierString = removeQuotesAndHandleConcat(nodeIdentifierString);
String[] tmpData = tmpIdentifierString.split(Pattern.quote(COLON));
if (tmpData.length == 1) {
YangNodeIdentifier nodeIdentifier = new YangNodeIdentifier();
nodeIdentifier.setName(getValidIdentifier(tmpData[0], yangConstruct, ctx));
return nodeIdentifier;
} else if (tmpData.length == 2) {
YangNodeIdentifier nodeIdentifier = new YangNodeIdentifier();
nodeIdentifier.setPrefix(getValidIdentifier(tmpData[0], yangConstruct, ctx));
nodeIdentifier.setName(getValidIdentifier(tmpData[1], yangConstruct, ctx));
return nodeIdentifier;
} else {
ParserException parserException = new ParserException("YANG file error : " +
YangConstructType.getYangConstructType(yangConstruct) + " name " + nodeIdentifierString +
" is not valid.");
parserException.setLine(ctx.getStart().getLine());
parserException.setCharPosition(ctx.getStart().getCharPositionInLine());
throw parserException;
}
}
/**
* Checks and return valid node identifier specific to nodes in leafref path.
*
* @param nodeIdentifierString string from yang file
* @param yangConstruct yang construct for creating error message
* @param ctx yang construct's context to get the line number and character position
* @param yangLeafRef instance of leafref where the path argument has to be set
* @return valid node identifier
*/
public static YangNodeIdentifier getValidNodeIdentifierForLeafref(String nodeIdentifierString,
YangConstructType yangConstruct, ParserRuleContext ctx, YangLeafRef yangLeafRef) {
String tmpIdentifierString = removeQuotesAndHandleConcat(nodeIdentifierString);
String[] tmpData = tmpIdentifierString.split(Pattern.quote(COLON));
if (tmpData.length == 1) {
YangNodeIdentifier nodeIdentifier = new YangNodeIdentifier();
nodeIdentifier.setName(getValidIdentifierForLeafref(tmpData[0], yangConstruct, ctx, yangLeafRef));
return nodeIdentifier;
} else if (tmpData.length == 2) {
YangNodeIdentifier nodeIdentifier = new YangNodeIdentifier();
nodeIdentifier.setPrefix(getValidIdentifierForLeafref(tmpData[0], yangConstruct, ctx, yangLeafRef));
nodeIdentifier.setName(getValidIdentifierForLeafref(tmpData[1], yangConstruct, ctx, yangLeafRef));
return nodeIdentifier;
} else {
ParserException parserException = new ParserException("YANG file error : " +
YangConstructType.getYangConstructType(yangConstruct) + yangLeafRef.getPath() +
" is not valid.");
parserException.setLine(ctx.getStart().getLine());
parserException.setCharPosition(ctx.getStart().getCharPositionInLine());
throw parserException;
}
}
/**
* Validates the path argument. It can be either absolute or relative path.
*
* @param pathString the path string from the path type
* @param yangConstruct yang construct for creating error message
* @param ctx yang construct's context to get the line number and character position
* @param yangLeafRef instance of leafref where the path argument has to be set
*/
public static void validatePathArgument(String pathString, YangConstructType yangConstruct,
ParserRuleContext ctx, YangLeafRef yangLeafRef) {
String completePathString = removeQuotesAndHandleConcat(pathString);
yangLeafRef.setPath(completePathString);
if (completePathString.startsWith(SLASH)) {
yangLeafRef.setPathType(ABSOLUTE_PATH);
List<YangAtomicPath> yangAtomicPathListList = validateAbsolutePath(completePathString, yangConstruct, ctx,
yangLeafRef);
yangLeafRef.setAtomicPath(yangAtomicPathListList);
} else if (completePathString.startsWith(ANCESTOR_ACCESSOR)) {
yangLeafRef.setPathType(RELATIVE_PATH);
validateRelativePath(completePathString, yangConstruct, ctx, yangLeafRef);
} else {
ParserException parserException = new ParserException("YANG file error : " +
YangConstructType.getYangConstructType(yangConstruct) + yangLeafRef.getPath() +
" does not follow valid path syntax");
parserException.setLine(ctx.getStart().getLine());
parserException.setCharPosition(ctx.getStart().getCharPositionInLine());
throw parserException;
}
}
/**
* Validates the relative path.
*
* @param completePathString the path string of relative path
* @param yangConstruct yang construct for creating error message
* @param ctx yang construct's context to get the line number and character position
* @param yangLeafRef instance of leafref where the path argument has to be set
*/
private static void validateRelativePath(String completePathString, YangConstructType yangConstruct,
ParserRuleContext ctx, YangLeafRef yangLeafRef) {
YangRelativePath relativePath = new YangRelativePath();
int numberOfAncestors = 0;
while (completePathString.startsWith(ANCESTOR_ACCESSOR_IN_PATH)) {
completePathString = completePathString.replaceFirst(ANCESTOR_ACCESSOR_IN_PATH, EMPTY_STRING);
numberOfAncestors = numberOfAncestors + 1;
}
if (completePathString == null || completePathString.length() == 0) {
ParserException parserException = new ParserException("YANG file error : "
+ YangConstructType.getYangConstructType(yangConstruct) + yangLeafRef.getPath() +
" does not follow valid path syntax");
parserException.setLine(ctx.getStart().getLine());
parserException.setCharPosition(ctx.getStart().getCharPositionInLine());
throw parserException;
}
relativePath.setAncestorNodeCount(numberOfAncestors);
List<YangAtomicPath> atomicPath = validateAbsolutePath(SLASH_FOR_STRING + completePathString,
yangConstruct,
ctx, yangLeafRef);
relativePath.setAtomicPathList(atomicPath);
yangLeafRef.setRelativePath(relativePath);
}
/**
* Validates the absolute path.
*
* @param completePathString the path string of absolute path
* @param yangConstruct yang construct for creating error message
* @param ctx yang construct's context to get the line number and character position
* @param yangLeafRef instance of leafref where the path argument has to be set
* @return list of object of node in absolute path
*/
private static List<YangAtomicPath> validateAbsolutePath(String completePathString,
YangConstructType yangConstruct, ParserRuleContext ctx, YangLeafRef yangLeafRef) {
List<YangAtomicPath> absolutePathList = new LinkedList<>();
YangPathPredicate yangPathPredicate = new YangPathPredicate();
YangNodeIdentifier yangNodeIdentifier;
while (completePathString != null) {
String path = completePathString.replaceFirst(SLASH_FOR_STRING, EMPTY_STRING);
if (path == null || path.length() == 0) {
ParserException parserException = new ParserException("YANG file error : "
+ YangConstructType.getYangConstructType(yangConstruct) + " " + yangLeafRef.getPath() +
" does not follow valid path syntax");
parserException.setLine(ctx.getStart().getLine());
parserException.setCharPosition(ctx.getStart().getCharPositionInLine());
throw parserException;
}
String matchedPathPredicate;
String nodeIdentifier;
String[] differentiate = new String[2];
int forNodeIdentifier = path.indexOf(CHAR_OF_SLASH);
int forPathPredicate = path.indexOf(CHAR_OF_OPEN_SQUARE_BRACKET);
// Checks if path predicate is present for the node.
if ((forPathPredicate < forNodeIdentifier) && (forPathPredicate != -1)) {
List<String> pathPredicate = new ArrayList<>();
matchedPathPredicate = matchForPathPredicate(path);
if (matchedPathPredicate == null || matchedPathPredicate.length() == 0) {
ParserException parserException = new ParserException("YANG file error : "
+ YangConstructType.getYangConstructType(yangConstruct) + " " + yangLeafRef.getPath() +
" does not follow valid path syntax");
parserException.setLine(ctx.getStart().getLine());
parserException.setCharPosition(ctx.getStart().getCharPositionInLine());
throw parserException;
}
int indexOfMatchedFirstOpenBrace = path.indexOf(CHAR_OF_OPEN_SQUARE_BRACKET);
differentiate[0] = path.substring(0, indexOfMatchedFirstOpenBrace);
differentiate[1] = path.substring(indexOfMatchedFirstOpenBrace);
pathPredicate.add(matchedPathPredicate);
nodeIdentifier = differentiate[0];
// Starts adding all path predicates of a node into the list.
if (!differentiate[1].isEmpty()) {
while (differentiate[1].startsWith(OPEN_SQUARE_BRACKET)) {
matchedPathPredicate = matchForPathPredicate(differentiate[1]);
if (matchedPathPredicate == null || matchedPathPredicate.length() == 0) {
ParserException parserException = new ParserException(
"YANG file error : " + YangConstructType.getYangConstructType(yangConstruct) + " "
+ yangLeafRef.getPath() +
" does not follow valid path syntax");
parserException.setLine(ctx.getStart().getLine());
parserException.setCharPosition(ctx.getStart().getCharPositionInLine());
throw parserException;
}
pathPredicate.add(matchedPathPredicate);
differentiate[1] = differentiate[1].substring(matchedPathPredicate.length());
}
}
List<YangPathPredicate> pathPredicateList = validatePathPredicate(pathPredicate, yangConstruct, ctx,
yangPathPredicate, yangLeafRef);
YangAtomicPath atomicPath = new YangAtomicPath();
yangNodeIdentifier = getValidNodeIdentifierForLeafref(nodeIdentifier, yangConstruct, ctx, yangLeafRef);
atomicPath.setNodeIdentifier(yangNodeIdentifier);
atomicPath.setPathPredicatesList(pathPredicateList);
absolutePathList.add(atomicPath);
} else {
if (path.contains(SLASH_FOR_STRING)) {
nodeIdentifier = path.substring(0, path.indexOf(CHAR_OF_SLASH));
differentiate[1] = path.substring(path.indexOf(CHAR_OF_SLASH));
} else {
nodeIdentifier = path;
differentiate[1] = null;
}
yangNodeIdentifier = getValidNodeIdentifierForLeafref(nodeIdentifier, yangConstruct, ctx, yangLeafRef);
YangAtomicPath atomicPath = new YangAtomicPath();
atomicPath.setNodeIdentifier(yangNodeIdentifier);
atomicPath.setPathPredicatesList(null);
absolutePathList.add(atomicPath);
}
if (differentiate[1] == null || differentiate[1].length() == 0) {
completePathString = null;
} else {
completePathString = differentiate[1];
}
}
return absolutePathList;
}
/**
* Validates path predicate in the absolute path's node.
*
* @param pathPredicate list of path predicates in the node of absolute path
* @param yangConstruct yang construct for creating error message
* @param ctx yang construct's context to get the line number and character position
* @param yangPathPredicate instance of path predicate where it has to be set
* @param yangLeafRef instance of leafref where the path argument has to be set
* @return list of object of path predicates in absolute path's node
*/
private static List<YangPathPredicate> validatePathPredicate(List<String> pathPredicate,
YangConstructType yangConstruct, ParserRuleContext ctx, YangPathPredicate yangPathPredicate,
YangLeafRef yangLeafRef) {
Iterator<String> pathPredicateString = pathPredicate.iterator();
List<String> pathEqualityExpression = new ArrayList<>();
while (pathPredicateString.hasNext()) {
String pathPredicateForNode = pathPredicateString.next();
pathPredicateForNode = (pathPredicateForNode.substring(1)).trim();
pathPredicateForNode = pathPredicateForNode.substring(0,
pathPredicateForNode.indexOf(CHAR_OF_CLOSE_SQUARE_BRACKET));
pathEqualityExpression.add(pathPredicateForNode);
}
List<YangPathPredicate> validatedPathPredicateList = validatePathEqualityExpression(pathEqualityExpression,
yangConstruct, ctx, yangPathPredicate, yangLeafRef);
return validatedPathPredicateList;
}
/**
* Validates the path equality expression.
*
* @param pathEqualityExpression list of path equality expression in the path predicates of the node
* @param yangConstruct yang construct for creating error message
* @param ctx yang construct's context to get the line number and character position
* @param yangPathPredicate instance of path predicate where it has to be set
* @param yangLeafRef instance of leafref where the path argument has to be set
* @return list of object of path predicates in absolute path's node
*/
private static List<YangPathPredicate> validatePathEqualityExpression(List<String> pathEqualityExpression,
YangConstructType yangConstruct, ParserRuleContext ctx, YangPathPredicate yangPathPredicate,
YangLeafRef yangLeafRef) {
Iterator<String> pathEqualityExpressionString = pathEqualityExpression.iterator();
List<YangPathPredicate> yangPathPredicateList = new ArrayList<>();
while (pathEqualityExpressionString.hasNext()) {
String pathEqualityExpressionForNode = pathEqualityExpressionString.next();
String[] pathEqualityExpressionArray = pathEqualityExpressionForNode.split("[=]");
YangNodeIdentifier yangNodeIdentifierForPredicate;
YangRelativePath yangRelativePath;
yangNodeIdentifierForPredicate = getValidNodeIdentifierForLeafref(pathEqualityExpressionArray[0].trim(),
yangConstruct, ctx, yangLeafRef);
yangRelativePath = validatePathKeyExpression(pathEqualityExpressionArray[1].trim(), yangConstruct, ctx,
yangLeafRef);
yangPathPredicate.setNodeIdentifier(yangNodeIdentifierForPredicate);
yangPathPredicate.setPathOperator(EQUALTO);
yangPathPredicate.setRightRelativePath(yangRelativePath);
yangPathPredicateList.add(yangPathPredicate);
}
return yangPathPredicateList;
}
/**
* Validate the path key expression.
*
* @param rightRelativePath relative path in the path predicate
* @param yangConstruct yang construct for creating error message
* @param ctx yang construct's context to get the line number and character position
* @param yangLeafRef instance of leafref where the path argument has to be set
* @return object of right relative path in path predicate
*/
private static YangRelativePath validatePathKeyExpression(String rightRelativePath,
YangConstructType yangConstruct, ParserRuleContext ctx, YangLeafRef yangLeafRef) {
YangRelativePath yangRelativePath = new YangRelativePath();
String[] relativePath = rightRelativePath.split(SLASH_FOR_STRING);
List<String> rightAbsolutePath = new ArrayList<>();
int accessAncestor = 0;
for (String path : relativePath) {
if (path.trim().equals(ANCESTOR_ACCESSOR)) {
accessAncestor = accessAncestor + 1;
} else {
rightAbsolutePath.add(path);
}
}
List<YangAtomicPath> atomicPathInRelativePath = validateRelativePathKeyExpression(rightAbsolutePath,
yangConstruct, ctx, yangLeafRef);
yangRelativePath.setAtomicPathList(atomicPathInRelativePath);
yangRelativePath.setAncestorNodeCount(accessAncestor);
return yangRelativePath;
}
/**
* Validates the relative path key expression.
*
* @param rightAbsolutePath absolute path nodes present in the relative path
* @param yangConstruct yang construct for creating error message
* @param ctx yang construct's context to get the line number and character position
* @param yangLeafRef instance of leafref where the path argument has to be set
* @return list of object of absolute path nodes present in the relative path
*/
private static List<YangAtomicPath> validateRelativePathKeyExpression(List<String> rightAbsolutePath,
YangConstructType yangConstruct, ParserRuleContext ctx, YangLeafRef yangLeafRef) {
List<YangAtomicPath> atomicPathList = new ArrayList<>();
YangNodeIdentifier yangNodeIdentifier;
Iterator<String> nodes = rightAbsolutePath.iterator();
String currentInvocationFunction = nodes.next();
currentInvocationFunction = currentInvocationFunction.trim();
String[] currentFunction = currentInvocationFunction.split("[(]");
if (!(currentFunction[0].trim().equals(CURRENT)) || !(currentFunction[1].trim().equals(CLOSE_PARENTHESIS))) {
ParserException parserException = new ParserException("YANG file error : "
+ YangConstructType.getYangConstructType(yangConstruct) + " " + yangLeafRef.getPath() +
" does not follow valid path syntax");
parserException.setLine(ctx.getStart().getLine());
parserException.setCharPosition(ctx.getStart().getCharPositionInLine());
throw parserException;
}
while (nodes.hasNext()) {
YangAtomicPath atomicPath = new YangAtomicPath();
String node = nodes.next();
yangNodeIdentifier = getValidNodeIdentifierForLeafref(node.trim(), yangConstruct, ctx, yangLeafRef);
atomicPath.setNodeIdentifier(yangNodeIdentifier);
atomicPathList.add(atomicPath);
}
return atomicPathList;
}
/**
* Validates the match for first path predicate in a given string.
*
* @param matchRequiredString string for which match has to be done
* @return the matched string
*/
private static String matchForPathPredicate(String matchRequiredString) {
String matchedString = null;
java.util.regex.Matcher matcher = PATH_PREDICATE_PATTERN.matcher(matchRequiredString);
if (matcher.find()) {
matchedString = matcher.group(0);
}
return matchedString;
}
/**
* Checks and return valid absolute schema node id.
*
* @param argumentString string from yang file
* @param yangConstructType yang construct for creating error message
* @param ctx yang construct's context to get the line number and character position
* @return target nodes list of absolute schema node id
*/
public static List<YangAtomicPath> getValidAbsoluteSchemaNodeId(String argumentString,
YangConstructType yangConstructType, ParserRuleContext ctx) {
List<YangAtomicPath> targetNodes = new ArrayList<>();
YangNodeIdentifier yangNodeIdentifier;
String tmpSchemaNodeId = removeQuotesAndHandleConcat(argumentString);
// absolute-schema-nodeid = 1*("/" node-identifier)
if (!tmpSchemaNodeId.startsWith(SLASH)) {
ParserException parserException = new ParserException("YANG file error : " +
YangConstructType.getYangConstructType(yangConstructType) + " name " + argumentString +
"is not valid");
parserException.setLine(ctx.getStart().getLine());
parserException.setCharPosition(ctx.getStart().getCharPositionInLine());
throw parserException;
}
String[] tmpData = tmpSchemaNodeId.replaceFirst(CARET + SLASH, EMPTY_STRING).split(SLASH);
for (String nodeIdentifiers : tmpData) {
yangNodeIdentifier = getValidNodeIdentifier(nodeIdentifiers, yangConstructType, ctx);
YangAtomicPath yangAbsPath = new YangAtomicPath();
yangAbsPath.setNodeIdentifier(yangNodeIdentifier);
targetNodes.add(yangAbsPath);
}
return targetNodes;
}
/**
* Throws parser exception for unsupported YANG constructs.
*
* @param yangConstructType yang construct for creating error message
* @param ctx yang construct's context to get the line number and character position
* @param errorInfo error information
*/
public static void handleUnsupportedYangConstruct(YangConstructType yangConstructType,
ParserRuleContext ctx, String errorInfo) {
ParserException parserException = new ParserException(YANG_FILE_ERROR
+ QUOTES + YangConstructType.getYangConstructType(yangConstructType) + QUOTES
+ errorInfo);
parserException.setLine(ctx.getStart().getLine());
parserException.setCharPosition(ctx.getStart().getCharPositionInLine());
throw parserException;
}
/**
* Returns date and makes it in usable format for revision.
*
* @param dateInString date argument string from yang file
* @param ctx yang construct's context to get the line number and character position
* @return date format for revision
*/
public static Date getValidDateFromString(String dateInString, ParserRuleContext ctx) {
String dateArgument = removeQuotesAndHandleConcat(dateInString);
if (dateArgument == null || !dateArgument.matches(DATE_PATTERN)) {
ParserException parserException = new ParserException("YANG file error: Input date is not correct");
parserException.setLine(ctx.getStart().getLine());
parserException.setCharPosition(ctx.getStart().getCharPositionInLine());
throw parserException;
}
SimpleDateFormat sdf = new SimpleDateFormat(DATE_FORMAT);
sdf.setLenient(false);
try {
//if not valid, it will throw ParseException
Date date = sdf.parse(dateArgument);
return date;
} catch (ParseException e) {
ParserException parserException = new ParserException("YANG file error: Input date is not correct");
parserException.setLine(ctx.getStart().getLine());
parserException.setCharPosition(ctx.getStart().getCharPositionInLine());
throw parserException;
}
}
}