blob: 614c260dda24b7efbc999c0f01a72407e3b160c8 [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.linker.impl;
import org.onosproject.yangutils.datamodel.YangAugment;
import org.onosproject.yangutils.datamodel.YangAugmentableNode;
import org.onosproject.yangutils.datamodel.YangAugmentedInfo;
import org.onosproject.yangutils.datamodel.YangCase;
import org.onosproject.yangutils.datamodel.YangChoice;
import org.onosproject.yangutils.datamodel.YangLeaf;
import org.onosproject.yangutils.datamodel.YangLeafList;
import org.onosproject.yangutils.datamodel.YangLeafRef;
import org.onosproject.yangutils.datamodel.YangLeavesHolder;
import org.onosproject.yangutils.datamodel.YangNode;
import org.onosproject.yangutils.datamodel.YangNodeIdentifier;
import org.onosproject.yangutils.datamodel.utils.YangConstructType;
import org.onosproject.yangutils.linker.exceptions.LinkerException;
import java.util.ArrayList;
import java.util.List;
import java.util.regex.Pattern;
import static org.onosproject.yangutils.utils.UtilConstants.COLON;
import static org.onosproject.yangutils.utils.UtilConstants.EMPTY_STRING;
import static org.onosproject.yangutils.utils.UtilConstants.SLASH_FOR_STRING;
/**
* Represent utilities for YANG linker.
*/
public final class YangLinkerUtils {
private YangLinkerUtils() {
}
private static final int IDENTIFIER_LENGTH = 64;
private static final Pattern IDENTIFIER_PATTERN = Pattern.compile("[a-zA-Z_][a-zA-Z0-9_.-]*");
private static final String XML = "xml";
/**
* Detects collision between target nodes leaf/leaf-list or child node with augmented leaf/leaf-list or child node.
*
* @param targetNode target node
* @param augment augment node
*/
private static void detectCollision(YangNode targetNode, YangAugment augment) {
YangNode targetNodesChild = targetNode.getChild();
YangNode augmentsChild = augment.getChild();
YangLeavesHolder augmentsLeavesHolder = augment;
if (targetNode instanceof YangChoice) {
if (augmentsLeavesHolder.getListOfLeaf() != null
|| augmentsLeavesHolder.getListOfLeafList() != null) {
throw new LinkerException("target node " + targetNode.getName()
+ "is a instance of choice. it can " +
"only be augmented with leaf using a case node.");
}
} else {
YangLeavesHolder targetNodesLeavesHolder = (YangLeavesHolder) targetNode;
YangNode parent = targetNode;
if (targetNode instanceof YangAugment) {
parent = targetNode.getParent();
} else {
while (parent.getParent() != null) {
parent = parent.getParent();
}
}
if (augmentsLeavesHolder.getListOfLeaf() != null && augmentsLeavesHolder.getListOfLeaf().size() != 0
&& targetNodesLeavesHolder.getListOfLeaf() != null) {
for (YangLeaf leaf : augmentsLeavesHolder.getListOfLeaf()) {
for (YangLeaf targetLeaf : targetNodesLeavesHolder.getListOfLeaf()) {
if (targetLeaf.getName().equals(leaf.getName())) {
throw new LinkerException("target node " + targetNode.getName()
+ " contains augmented leaf " + leaf.getName() + " in module "
+ parent.getName());
}
}
}
} else if (augmentsLeavesHolder.getListOfLeafList() != null
&& augmentsLeavesHolder.getListOfLeafList().size() != 0
&& targetNodesLeavesHolder.getListOfLeafList() != null) {
for (YangLeafList leafList : augmentsLeavesHolder.getListOfLeafList()) {
for (YangLeafList targetLeafList : targetNodesLeavesHolder.getListOfLeafList()) {
if (targetLeafList.getName().equals(leafList.getName())) {
throw new LinkerException("target node " + targetNode.getName()
+ " contains augmented leaf-list" + leafList.getName() + " in module "
+ parent.getName());
}
}
}
} else {
while (augmentsChild != null) {
while (targetNodesChild != null) {
if (targetNodesChild.getName().equals(augmentsChild.getName())) {
throw new LinkerException("target node " + targetNode.getName()
+ " contains augmented child node" + augmentsChild.getName() + " in module "
+ parent.getName());
}
targetNodesChild = targetNodesChild.getNextSibling();
}
augmentsChild = augmentsChild.getNextSibling();
}
}
}
}
/**
* Detects collision between target nodes and its all leaf/leaf-list or child node with augmented leaf/leaf-list or
* child node.
*
* @param targetNode target node
* @param augment augment node
*/
public static void detectCollisionForAugmentedNode(YangNode targetNode, YangAugment augment) {
// Detect collision for target node and augment node.
detectCollision(targetNode, augment);
List<YangAugmentedInfo> yangAugmentedInfo = ((YangAugmentableNode) targetNode).getAugmentedInfoList();
// Detect collision for target augment node and current augment node.
for (YangAugmentedInfo info : yangAugmentedInfo) {
detectCollision((YangAugment) info, augment);
}
}
/**
* Returns list of path names that are needed from augment.
*
* @param augment instance of YANG augment
* @param remainingAncestors ancestor count to move in augment path
* @return list of path names needed in leafref
*/
public static List<String> getPathWithAugment(YangAugment augment, int remainingAncestors) {
String augmentName = augment.getName();
List<String> listOfPathName = new ArrayList<>();
if (augmentName.contains(SLASH_FOR_STRING)) {
String[] augmentNodeNames = augmentName.split(SLASH_FOR_STRING);
for (String valueInAugment : augmentNodeNames) {
if (valueInAugment != null && valueInAugment != EMPTY_STRING && !valueInAugment.isEmpty()) {
listOfPathName.add(valueInAugment);
}
}
}
for (int countOfAncestor = 0; countOfAncestor < remainingAncestors; countOfAncestor++) {
listOfPathName.remove(listOfPathName.size() - 1);
}
return listOfPathName;
}
/**
* Skips the invalid nodes which cannot have data from YANG.
*
* @param currentParent current parent node reference
* @param leafref instance of YANG leafref
* @return parent node which can hold data
* @throws LinkerException a violation of linker rules
*/
public static YangNode skipInvalidDataNodes(YangNode currentParent, YangLeafRef leafref) throws LinkerException {
while (currentParent instanceof YangChoice || currentParent instanceof YangCase) {
if (currentParent.getParent() == null) {
throw new LinkerException("YANG file error: The target node, in the leafref path " +
leafref.getPath() + ", is invalid.");
}
currentParent = currentParent.getParent();
}
return currentParent;
}
/**
* Checks and return valid node identifier.
*
* @param nodeIdentifierString string from yang file
* @param yangConstruct yang construct for creating error message
* @return valid node identifier
*/
public static YangNodeIdentifier getValidNodeIdentifier(String nodeIdentifierString,
YangConstructType yangConstruct) {
String[] tmpData = nodeIdentifierString.split(Pattern.quote(COLON));
if (tmpData.length == 1) {
YangNodeIdentifier nodeIdentifier = new YangNodeIdentifier();
nodeIdentifier.setName(getValidIdentifier(tmpData[0], yangConstruct));
return nodeIdentifier;
} else if (tmpData.length == 2) {
YangNodeIdentifier nodeIdentifier = new YangNodeIdentifier();
nodeIdentifier.setPrefix(getValidIdentifier(tmpData[0], yangConstruct));
nodeIdentifier.setName(getValidIdentifier(tmpData[1], yangConstruct));
return nodeIdentifier;
} else {
throw new LinkerException("YANG file error : " +
YangConstructType.getYangConstructType(yangConstruct) + " name " + nodeIdentifierString +
" is not valid.");
}
}
/**
* 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=
* @return concatenated string after removing double quotes
*/
public static String getValidIdentifier(String identifier, YangConstructType yangConstruct) {
if (identifier.length() > IDENTIFIER_LENGTH) {
throw new LinkerException("YANG file error : " +
YangConstructType.getYangConstructType(yangConstruct) + " name " + identifier + " is " +
"greater than 64 characters.");
} else if (!IDENTIFIER_PATTERN.matcher(identifier).matches()) {
throw new LinkerException("YANG file error : " +
YangConstructType.getYangConstructType(yangConstruct) + " name " + identifier + " is not " +
"valid.");
} else if (identifier.toLowerCase().startsWith(XML)) {
throw new LinkerException("YANG file error : " +
YangConstructType.getYangConstructType(yangConstruct) + " identifier " + identifier +
" must not start with (('X'|'x') ('M'|'m') ('L'|'l')).");
} else {
return identifier;
}
}
}