| /* |
| * 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; |
| } |
| } |
| } |