| /* |
| * Copyright 2016-present Open Networking Foundation |
| * |
| * 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.yms.app.ydt; |
| |
| import org.onosproject.yangutils.datamodel.YangSchemaNode; |
| import org.onosproject.yangutils.datamodel.YangSchemaNodeContextInfo; |
| import org.onosproject.yangutils.datamodel.YangSchemaNodeIdentifier; |
| import org.onosproject.yangutils.datamodel.exceptions.DataModelException; |
| import org.onosproject.yms.app.ydt.exceptions.YdtException; |
| import org.onosproject.yms.ydt.YdtContext; |
| import org.onosproject.yms.ydt.YdtContextOperationType; |
| import org.onosproject.yms.ydt.YdtExtendedInfoType; |
| import org.onosproject.yms.ydt.YdtType; |
| |
| import java.util.ArrayList; |
| import java.util.HashMap; |
| import java.util.HashSet; |
| import java.util.List; |
| import java.util.Map; |
| import java.util.Set; |
| |
| import static org.onosproject.yms.app.ydt.YdtConstants.errorMsg; |
| |
| /** |
| * Represents implementation of interfaces to build and obtain YANG data tree |
| * which is data (sub)instance representation, abstract of protocol. |
| */ |
| public abstract class YdtNode<T> implements YdtExtendedContext, Cloneable { |
| |
| // YDT formatted error string |
| private static final String FMT_NON_LIST_STR = |
| "List of key cannot be created for leaf and leaf-list %s node."; |
| private static final String FMT_VAL_N = |
| "Value cannot be set in non leaf %s node."; |
| private static final String FMT_VAL_NS = |
| "ValueSet cannot be set in non leaf-list %s node."; |
| private static final String FMT_VAL_IN = |
| "Value cannot be invoke from non leaf %s node."; |
| private static final String FMT_VAL_INS = |
| "ValueSet cannot be invoke from non leaf-list %s node"; |
| |
| // YDT error string |
| private static final String E_EXIST = "Node is already part of a tree"; |
| private static final String E_ATOMIC = |
| "Child to be added is not atomic, it already has a child"; |
| private static final String E_SIB = |
| "Child to be added is not atomic, it already has a next sibling"; |
| private static final String E_PRE = |
| "Child to be added is not atomic, it already has a previous " + |
| "sibling"; |
| private static final String E_SUPPORT = "Requested node type not supported"; |
| |
| /* |
| * Parent reference. |
| */ |
| private YdtNode parent; |
| |
| /* |
| * First child reference. |
| */ |
| private YdtNode child; |
| |
| /* |
| * Next sibling reference. |
| */ |
| private YdtNode nextSibling; |
| |
| /* |
| * Previous sibling reference. |
| */ |
| private YdtNode previousSibling; |
| |
| /* |
| * Last child reference. |
| */ |
| private YdtNode lastChild; |
| |
| /* |
| * Type of node. |
| */ |
| private final YdtType ydtType; |
| |
| /* |
| * Flag to keep the track of context switch, |
| * if set then traverse back to parent in YDT app tree else no need. |
| */ |
| private boolean isContextSwitch; |
| |
| /* |
| * YDT extended information. |
| */ |
| private T ydtExtendedInfo; |
| |
| /* |
| * YDT extended information type. |
| */ |
| private YdtExtendedInfoType ydtExtendedInfoType; |
| |
| /* |
| * Ydt map to keep the track of node added under current parent node. |
| */ |
| final Map<YangSchemaNodeIdentifier, YdtNode<T>> ydtNodeMap = |
| new HashMap<>(); |
| |
| /* |
| * Ydt map to keep the track of multi instance node added under current |
| * parent node. |
| */ |
| private final Map<YangSchemaNodeIdentifier, |
| List<YdtNode<YdtMultiInstanceNode>>> ydtMultiInsMap = |
| new HashMap<>(); |
| |
| /* |
| * Reference for data-model schema node. |
| */ |
| private YangSchemaNode yangSchemaNode; |
| |
| /* |
| * Reference for ydt node operation type. |
| */ |
| private YdtContextOperationType ydtContextOperationType; |
| |
| /* |
| * Ydt map to keep the track of application information object |
| * with respective type. |
| */ |
| private final Map<AppType, Object> ydtAppInfoMap = new HashMap<>(); |
| |
| private YdtContext clonedNode; |
| |
| /** |
| * Creates a specific type of node. |
| * |
| * @param type of YDT node |
| * @param node schema node |
| */ |
| YdtNode(YdtType type, YangSchemaNode node) { |
| ydtType = type; |
| yangSchemaNode = node; |
| } |
| |
| /** |
| * Creates a specific type of node. |
| * |
| * @param type of YDT node |
| */ |
| YdtNode(YdtType type) { |
| ydtType = type; |
| } |
| |
| /** |
| * Returns the cloned ydt node. |
| * |
| * @return clonedNode cloned ydt node |
| */ |
| public YdtContext getClonedNode() { |
| return clonedNode; |
| } |
| |
| /** |
| * Sets the cloned node. |
| * |
| * @param clonedNode cloned ydt node |
| */ |
| public void setClonedNode(YdtContext clonedNode) { |
| this.clonedNode = clonedNode; |
| } |
| |
| @Override |
| public String getName() { |
| return yangSchemaNode.getName(); |
| } |
| |
| @Override |
| public String getNamespace() { |
| return yangSchemaNode.getNameSpace().getModuleNamespace(); |
| } |
| |
| @Override |
| public String getModuleNameAsNameSpace() { |
| return yangSchemaNode.getNameSpace().getModuleName(); |
| } |
| |
| @Override |
| public <T> T getYdtContextExtendedInfo() { |
| return (T) ydtExtendedInfo; |
| } |
| |
| @Override |
| public YdtExtendedInfoType getYdtExtendedInfoType() { |
| return ydtExtendedInfoType; |
| } |
| |
| @Override |
| public YdtType getYdtType() { |
| return ydtType; |
| } |
| |
| @Override |
| public YdtNode getParent() { |
| return parent; |
| } |
| |
| @Override |
| public YdtNode getFirstChild() { |
| return child; |
| } |
| |
| @Override |
| public YdtNode getNextSibling() { |
| return nextSibling; |
| } |
| |
| public YangSchemaNode getYangSchemaNode() { |
| return yangSchemaNode; |
| } |
| |
| @Override |
| public YdtNode getLastChild() { |
| return lastChild; |
| } |
| |
| @Override |
| public Object getAppInfo(AppType appType) { |
| return ydtAppInfoMap.get(appType); |
| } |
| |
| @Override |
| public void addAppInfo(AppType appType, Object object) { |
| ydtAppInfoMap.put(appType, object); |
| } |
| |
| /** |
| * Returns child schema node context information. It is used by YMS to |
| * obtain the child schema corresponding to data node identifier. |
| * |
| * @param id represents a identifier of YANG data tree node |
| * @return YANG data node context information |
| * @throws YdtException when user requested node schema doesn't exist |
| */ |
| public YangSchemaNodeContextInfo getSchemaNodeContextInfo( |
| YangSchemaNodeIdentifier id) throws YdtException { |
| try { |
| return getYangSchemaNode().getChildSchema(id); |
| } catch (DataModelException e) { |
| throw new YdtException(e.getLocalizedMessage()); |
| } |
| } |
| |
| /** |
| * Adds the given value to the non single instance leaf node. |
| * <p> |
| * This default implementation throws an exception stating that |
| * the value cannot be added. Subclasses may override this method |
| * to provide the correct behavior for their specific implementation. |
| * |
| * @param value value in a single instance node |
| * @throws YdtException when fails to add value for non single instance |
| * leaf node |
| */ |
| public void addValue(String value) throws YdtException { |
| throw new YdtException(errorMsg(FMT_VAL_N, getName())); |
| } |
| |
| /** |
| * Creates the list of key element's of multi instance node. |
| * This will not be applicable on leaf and leaf-list node. |
| * |
| * @throws YdtException when user requested multi instance node is missing |
| * any of the key element in request or requested |
| * node is of type other then multi instance node |
| */ |
| public void createKeyNodeList() throws YdtException { |
| throw new YdtException(errorMsg(FMT_NON_LIST_STR, getName())); |
| } |
| |
| /** |
| * Adds the given value to the non single instance leaf node. |
| * <p> |
| * This default implementation throws an exception stating that |
| * the value cannot be added. Subclasses may override this method |
| * to provide the correct behavior for their specific implementation. |
| * This will be applicable in case of call from SBI so no need |
| * to validate the value. |
| * |
| * @param value value in a single instance leaf node |
| * @param isKeyLeaf true, for key leaf; false non key leaf |
| * @throws YdtException when fails to add value for non single instance |
| * leaf node |
| */ |
| public void addValueWithoutValidation(String value, boolean isKeyLeaf) |
| throws YdtException { |
| throw new YdtException(errorMsg(FMT_VAL_N, getName())); |
| } |
| |
| /** |
| * Adds the given valueSet to the non multi instance leaf node. |
| * <p> |
| * This default implementation throws an exception stating that |
| * the value cannot be added. Subclasses may override this method |
| * to provide the correct behavior for their specific implementation. |
| * |
| * @param valueSet valueSet in a multi instance leaf node |
| * @throws YdtException when fails to add value set for non multi instance |
| * leaf node |
| */ |
| public void addValueSet(Set<String> valueSet) throws YdtException { |
| throw new YdtException(errorMsg(FMT_VAL_NS, getName())); |
| } |
| |
| /** |
| * Adds the given valueSet to the non multi instance leaf node. |
| * <p> |
| * This default implementation throws an exception stating that |
| * the value cannot be added. Subclasses may override this method |
| * to provide the correct behavior for their specific implementation. |
| * This will be applicable in case of call from SBI so no need |
| * to validate the value. |
| * |
| * @param valueSet valueSet in a multi instance leaf node |
| * @throws YdtException when fails to add value set for non multi instance |
| * leaf node |
| */ |
| public void addValueSetWithoutValidation(Set<String> valueSet) |
| throws YdtException { |
| throw new YdtException(errorMsg(FMT_VAL_NS, getName())); |
| } |
| |
| /** |
| * Validates requested node allowed to have duplicate entry or not. |
| * <p> |
| * This default implementation throws an exception stating that |
| * the duplicate entry found. Subclasses may override this method |
| * to provide the correct behavior for their specific implementation. |
| * |
| * @throws YdtException when fails to process valid duplicate entry in YDT |
| */ |
| void validDuplicateEntryProcessing() throws YdtException { |
| } |
| |
| /** |
| * Returns already existing YdtNode in Ydt tree with same nodeIdentifier. |
| * |
| * @param id represents a identifier of YANG data tree node |
| * @return YDT node |
| * @throws YdtException when user requested node already part of YDT tree. |
| */ |
| public YdtNode getCollidingChild(YangSchemaNodeIdentifier id) |
| throws YdtException { |
| |
| // Find the key in YDT map for getting the colliding node. |
| YdtNode collidingChild = ydtNodeMap.get(id); |
| |
| /* |
| * If colliding child exist then process colliding node in respective |
| * YDT node type. |
| */ |
| if (collidingChild != null) { |
| collidingChild.validDuplicateEntryProcessing(); |
| return collidingChild; |
| } |
| |
| return null; |
| } |
| |
| /** |
| * Sets the parent of node. |
| * |
| * @param parent node |
| */ |
| public void setParent(YdtNode parent) { |
| this.parent = parent; |
| } |
| |
| /** |
| * Sets the first instance of a child node. |
| * |
| * @param child is only child to be set |
| */ |
| public void setChild(YdtNode child) { |
| this.child = child; |
| } |
| |
| /** |
| * Sets the next sibling of node. |
| * |
| * @param sibling YANG node |
| */ |
| public void setNextSibling(YdtNode sibling) { |
| nextSibling = sibling; |
| } |
| |
| /** |
| * Returns the previous sibling of a node. |
| * |
| * @return previous sibling of a node |
| */ |
| public YdtNode getPreviousSibling() { |
| return previousSibling; |
| } |
| |
| /** |
| * Sets the previous sibling. |
| * |
| * @param previousSibling points to predecessor sibling |
| */ |
| public void setPreviousSibling(YdtNode previousSibling) { |
| this.previousSibling = previousSibling; |
| } |
| |
| @Override |
| public String getValue() throws YdtException { |
| throw new YdtException(errorMsg(FMT_VAL_IN, getName())); |
| } |
| |
| @Override |
| public Set<String> getValueSet() throws YdtException { |
| throw new YdtException(errorMsg(FMT_VAL_INS, getName())); |
| } |
| |
| /** |
| * Sets the data-model node reference for of a given node. |
| * |
| * @param yangSchemaNode YANG data node |
| */ |
| public void setYangSchemaNode(YangSchemaNode yangSchemaNode) { |
| this.yangSchemaNode = yangSchemaNode; |
| } |
| |
| /** |
| * Sets the last instance of a child node. |
| * |
| * @param child is last child to be set |
| */ |
| public void setLastChild(YdtNode child) { |
| lastChild = child; |
| } |
| |
| |
| /** |
| * Adds a child node. |
| * The children sibling list will be sorted based on node |
| * type. This will add single child or sub-tree based on isAtomic flag. |
| * |
| * @param newChild refers to a new child to be added |
| * @param isAtomic boolean flag to maintain atomicity of the current node |
| * @throws YdtException in case of violation of any YDT rule |
| */ |
| public void addChild(YdtContext newChild, boolean isAtomic) |
| throws YdtException { |
| |
| if (!(newChild instanceof YdtNode)) { |
| throw new YdtException(errorMsg(E_SUPPORT)); |
| } |
| |
| YdtNode node = (YdtNode) newChild; |
| |
| if (node.getParent() == null) { |
| node.setParent(this); |
| } else if (!node.getParent().equals(this)) { |
| throw new YdtException(E_EXIST); |
| } |
| |
| if (node.getFirstChild() != null && isAtomic) { |
| throw new YdtException(E_ATOMIC); |
| } |
| |
| if (node.getNextSibling() != null) { |
| throw new YdtException(E_SIB); |
| } |
| |
| if (node.getPreviousSibling() != null) { |
| throw new YdtException(E_PRE); |
| } |
| |
| // If new node needs to be added as first child. |
| if (getFirstChild() == null) { |
| setChild(node); |
| setLastChild(node); |
| return; |
| } |
| |
| // If new node needs to be added as last child. |
| YdtNode curNode = getLastChild(); |
| curNode.setNextSibling(node); |
| node.setPreviousSibling(curNode); |
| setLastChild(node); |
| } |
| |
| @Override |
| public YdtContextOperationType getYdtContextOperationType() { |
| return ydtContextOperationType; |
| } |
| |
| /** |
| * Sets type of yang data tree node operation. |
| * |
| * @param opType type of yang data tree node operation |
| */ |
| public void setYdtContextOperationType(YdtContextOperationType opType) { |
| ydtContextOperationType = opType; |
| } |
| |
| /** |
| * Updates ydt maps of current context parent node. |
| * |
| * @param node ydt node for which map need to be updated |
| */ |
| void updateYdtMap(YdtNode node) { |
| |
| YangSchemaNodeIdentifier id = node.getYangSchemaNode() |
| .getYangSchemaNodeIdentifier(); |
| /* |
| * If node to be added is of type multi instance node(list) then multi |
| * instance node to be updated |
| */ |
| if (node.getYdtType() == YdtType.MULTI_INSTANCE_NODE) { |
| updateMultiInsMap(id, node); |
| } |
| |
| /* |
| * If entry for multi instance node is already there with same id then |
| * existing entry will be overwritten by the new entry. |
| */ |
| ydtNodeMap.put(id, node); |
| } |
| |
| /** |
| * Updates ydt multi instance map of current context parent node. |
| * |
| * @param id object node identifier |
| * @param node ydt node for which map need to be updated |
| */ |
| private void updateMultiInsMap(YangSchemaNodeIdentifier id, YdtNode node) { |
| |
| List<YdtNode<YdtMultiInstanceNode>> list = ydtMultiInsMap.get(id); |
| if (list == null) { |
| list = new ArrayList<>(); |
| ydtMultiInsMap.put(id, list); |
| } |
| list.add(node); |
| } |
| |
| /** |
| * Returns the flag for node if context switch. |
| * |
| * @return isContextSwitch flag of a node |
| */ |
| public boolean getAppContextSwitch() { |
| return isContextSwitch; |
| } |
| |
| /** |
| * Sets the flag to keep the track of context switch. |
| * If it is set then when YDT get traverToParent then |
| * traverse back to parent in YDT application tree. |
| */ |
| public void setAppContextSwitch() { |
| isContextSwitch = true; |
| } |
| |
| /** |
| * Validates all multi Instance nodes inside current context. |
| * |
| * @throws YdtException when fails to validate multi instance node |
| */ |
| public void validateMultiInstanceNode() throws YdtException { |
| |
| // Set for checking whether input string is unique or not. |
| Set<String> keyStringSet = new HashSet<>(); |
| |
| if (ydtMultiInsMap.size() != 0) { |
| /* |
| * Iterating over values in map and find multi instance node list |
| * only. |
| */ |
| for (List<YdtNode<YdtMultiInstanceNode>> ydtNodeList : |
| ydtMultiInsMap.values()) { |
| try { |
| ydtNodeList.get(0).validateInstances(keyStringSet, |
| ydtNodeList); |
| } catch (YdtException e) { |
| throw new YdtException(e.getLocalizedMessage()); |
| } |
| } |
| } |
| } |
| |
| /** |
| * Validates the given list of instances by verifying the allowed |
| * instance count and key element uniqueness. |
| * <p> |
| * This default implementation do nothing if requested node is of type |
| * other then multiInstanceNode. Subclasses may override this method |
| * to provide the correct behavior for their specific implementation. |
| * |
| * @param keyStringSet set to validate the key element uniqueness |
| * @param ydtNodeList list of instance's of same list |
| * @throws YdtException when user requested multi instance node instance's |
| * count doesn't fit into the allowed instance's limit |
| * or doesn't have unique key's |
| */ |
| void validateInstances(Set<String> keyStringSet, |
| List<YdtNode<YdtMultiInstanceNode>> |
| ydtNodeList) throws YdtException { |
| |
| } |
| |
| /** |
| * Clones the current node contents and create a new node. |
| * |
| * @return cloned node |
| * @throws CloneNotSupportedException clone is not supported |
| * by the referred node |
| */ |
| public YdtNode clone() throws CloneNotSupportedException { |
| YdtNode clonedNode = (YdtNode) super.clone(); |
| clonedNode.setPreviousSibling(null); |
| clonedNode.setNextSibling(null); |
| clonedNode.setParent(null); |
| clonedNode.setChild(null); |
| clonedNode.setLastChild(null); |
| return clonedNode; |
| } |
| } |