| /* |
| * Copyright 2016 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.datamodel; |
| |
| import java.util.Stack; |
| import org.onosproject.yangutils.datamodel.exceptions.DataModelException; |
| |
| /** |
| * Resolution object which will be resolved by linker. |
| */ |
| public class YangResolutionInfo<T> { |
| |
| // Prefix associated with the linking. |
| private String prefix; |
| |
| // Parsable node for which resolution is to be performed. |
| private T entityToResolve; |
| |
| // Holder of the YANG construct for which resolution has to be carried out. |
| private YangNode holderOfEntityToResolve; |
| |
| // Error Line number. |
| private int lineNumber; |
| |
| // Error character position. |
| private int charPosition; |
| |
| // Status of resolution. |
| private boolean isResolved; |
| |
| /* |
| * Stack for type/uses is maintained for hierarchical references, this |
| * is used during resolution. |
| */ |
| private Stack<T> partialResolvedStack; |
| |
| // Flag to indicate whether more references are detected. |
| private boolean isMoreReferenceDetected; |
| |
| // Module/Sub-module prefix. |
| private String resolutionInfoRootNodePrefix; |
| |
| /** |
| * Create a resolution information object. |
| */ |
| private YangResolutionInfo() { |
| |
| } |
| |
| /** |
| * Creates a resolution information object with all the inputs. |
| * |
| * @param dataNode current parsable data node |
| * @param resolutionType type of resolution whether grouping/typedef |
| * @param holderNode parent YANG node |
| * @param prefix imported module prefix |
| * @param lineNumber error line number |
| * @param charPositionInLine error character position in line |
| */ |
| public YangResolutionInfo(T dataNode, ResolutionType resolutionType, |
| YangNode holderNode, String prefix, int lineNumber, |
| int charPositionInLine) { |
| this.setHolderOfEntityToResolve(holderNode); |
| this.setEntityToResolve(dataNode); |
| this.setPrefix(prefix); |
| this.setLineNumber(lineNumber); |
| this.setCharPosition(charPositionInLine); |
| setPartialResolvedStack(new Stack<T>()); |
| } |
| |
| /** |
| * Creates a resolution information object with all the inputs except prefix. |
| * |
| * @param dataNode current parsable data node |
| * @param resolutionType type of resolution whether grouping/typedef |
| * @param holderNode parent YANG node |
| * @param lineNumber error line number |
| * @param charPositionInLine error character position in line |
| */ |
| public YangResolutionInfo(T dataNode, ResolutionType resolutionType, |
| YangNode holderNode, int lineNumber, |
| int charPositionInLine) { |
| this.setHolderOfEntityToResolve(holderNode); |
| this.setEntityToResolve(dataNode); |
| this.setLineNumber(lineNumber); |
| this.setCharPosition(charPositionInLine); |
| } |
| |
| /** |
| * Resolve linking with all the ancestors node for a resolution info. |
| * |
| * @param resolutionInfoNodePrefix module/sub-module prefix |
| * @throws DataModelException DataModelException a violation of data model rules |
| */ |
| public void resolveLinkingForResolutionInfo(String resolutionInfoNodePrefix) throws DataModelException { |
| |
| this.resolutionInfoRootNodePrefix = resolutionInfoNodePrefix; |
| |
| // Current node to resolve, it can be a YANG type or YANG uses. |
| T entityToResolve = getEntityToResolve(); |
| |
| // Check if linking is already done |
| if (entityToResolve instanceof Resolvable) { |
| Resolvable resolvable = (Resolvable) entityToResolve; |
| if (resolvable.getResolvableStatus() == ResolvableStatus.RESOLVED || |
| resolvable.getResolvableStatus() == ResolvableStatus.PARTIALLY_RESOLVED) { |
| return; |
| } |
| } else { |
| throw new DataModelException("Data Model Exception: Entity to resolved is other than type/uses"); |
| } |
| |
| // Push the initial YANG type to the stack. |
| getPartialResolvedStack().push(entityToResolve); |
| |
| // Get holder of entity to resolve |
| YangNode curNode = getHolderOfEntityToResolve(); |
| |
| resolveLinkingWithAncestors(curNode); |
| } |
| |
| /** |
| * Resolves linking with ancestors. |
| * |
| * @param curNode current node for which ancestors to be checked |
| * @throws DataModelException a violation of data model rules |
| */ |
| private void resolveLinkingWithAncestors(YangNode curNode) throws DataModelException { |
| |
| while (curNode != null) { |
| YangNode node = curNode.getChild(); |
| if (resolveLinkingForNodesChildAndSibling(node, curNode)) { |
| return; |
| } |
| curNode = curNode.getParent(); |
| } |
| |
| // If curNode is null, it indicates an error condition in YANG file. |
| DataModelException dataModelException = new DataModelException("YANG file error: Unable to find base " + |
| "typedef/grouping for given type/uses"); |
| dataModelException.setLine(getLineNumber()); |
| dataModelException.setCharPosition(getCharPosition()); |
| throw dataModelException; |
| } |
| |
| /** |
| * Resolves linking for a node child and siblings. |
| * |
| * @param node current node |
| * @param parentNode parent node of current node |
| * @return flag to indicate whether resolution is done |
| * @throws DataModelException |
| */ |
| private boolean resolveLinkingForNodesChildAndSibling(YangNode node, YangNode parentNode) |
| throws DataModelException { |
| while ((node != null)) { |
| isMoreReferenceDetected = false; |
| // Check if node is of type, typedef or grouping |
| if (isNodeOfResolveType(node)) { |
| if (resolveLinkingForNode(node, parentNode)) { |
| return true; |
| } |
| } |
| if (isMoreReferenceDetected) { |
| /* |
| * If more reference are present, tree traversal must start |
| * from first child again, to check the availability of |
| * typedef/grouping. |
| */ |
| node = parentNode.getChild(); |
| } else { |
| node = node.getNextSibling(); |
| } |
| } |
| return false; |
| } |
| |
| /** |
| * Resolves linking for a node. |
| * |
| * @param node current node |
| * @param parentNode parent node of current node |
| * @return flag to indicate whether resolution is done |
| * @throws DataModelException a violation of data model rules |
| */ |
| private boolean resolveLinkingForNode(YangNode node, YangNode parentNode) throws |
| DataModelException { |
| /* |
| * Check if name of node name matches with the entity name |
| * under resolution. |
| */ |
| if (isNodeNameSameAsResolutionInfoName(node)) { |
| // Add reference of entity to the node under resolution. |
| addReferredEntityLink(node); |
| // Check if referred entity has further reference to uses/type. |
| if (!(isMoreReferencePresent(node))) { |
| // Resolve all the entities in stack. |
| resolveStackAndAddToStack(node); |
| return true; |
| } else { |
| // Add referred type/uses to the stack. |
| addToPartialResolvedStack(node); |
| /* |
| * Check whether referred type is resolved, partially resolved |
| * or unresolved. |
| */ |
| if (isReferenceFullyResolved()) { |
| // Resolve the stack which is complete. |
| resolveCompleteStack(); |
| return true; |
| } else if (isReferencePartiallyResolved()) { |
| /* |
| * Update the resolution type to partially resolved for all |
| * type/uses in stack |
| */ |
| updateResolutionTypeToPartial(); |
| return true; |
| } else { |
| /* |
| * Check if prefix is present to find that the derived |
| * reference is for intra file or inter file, if it's |
| * inter-file return and stop further processing. |
| */ |
| if (isExternalPrefixPresent(node)) { |
| /* |
| * Update the resolution type to partially resolved for all |
| * type/uses in stack |
| */ |
| updateResolutionTypeToPartial(); |
| return true; |
| } else { |
| /* |
| * If prefix is not present it indicates intra-file |
| * dependency in this case set the node back to first |
| * child, as referred entity may appear in any order |
| * and continue with the resolution. |
| */ |
| isMoreReferenceDetected = true; |
| return false; |
| } |
| } |
| } |
| } |
| return false; |
| } |
| |
| /** |
| * Update resolution type to partial for all type/uses in stack. |
| * |
| * @throws DataModelException a violation of data model rules |
| */ |
| private void updateResolutionTypeToPartial() throws DataModelException { |
| // For all entries in stack calls for the resolution in type/uses. |
| for (T entity:getPartialResolvedStack()) { |
| if (!(entity instanceof Resolvable)) { |
| throw new DataModelException("Data Model Exception: Entity to resolved is other than type/uses"); |
| } |
| if (((Resolvable) entity).getResolvableStatus() == ResolvableStatus.UNRESOLVED) { |
| // Set the resolution status in inside the type/uses. |
| ((Resolvable) entity).setResolvableStatus(ResolvableStatus.PARTIALLY_RESOLVED); |
| } |
| } |
| } |
| |
| /** |
| * Add referred type/uses to the stack and resolve the stack. |
| * |
| * @param node typedef/grouping node |
| * @throws DataModelException a violation of data model rules |
| */ |
| private void resolveStackAndAddToStack(YangNode node) throws DataModelException { |
| if (getEntityToResolve() instanceof YangType) { |
| // Add to the stack only for YANG typedef. |
| getPartialResolvedStack().push((T) ((YangTypeDef) node).getDataType()); |
| } |
| // Don't add to stack in case of YANG grouping. |
| |
| // Resolve the complete stack. |
| resolveCompleteStack(); |
| } |
| |
| /** |
| * Check if the referred type/uses is partially resolved. |
| * |
| * @return true if reference is partially resolved, otherwise false |
| */ |
| private boolean isReferencePartiallyResolved() { |
| if (getPartialResolvedStack().peek() instanceof YangType) { |
| /* |
| * Checks if type is partially resolved. |
| */ |
| if (((YangType) getPartialResolvedStack().peek()).getResolvableStatus() == |
| ResolvableStatus.PARTIALLY_RESOLVED) { |
| return true; |
| } |
| } else if (getPartialResolvedStack().peek() instanceof YangUses) { |
| if (((YangUses) getPartialResolvedStack().peek()).getResolvableStatus() == |
| ResolvableStatus.PARTIALLY_RESOLVED) { |
| return true; |
| } |
| } |
| return false; |
| } |
| |
| /** |
| * Check if the referred type/uses is resolved. |
| * |
| * @return true if reference is resolved, otherwise false |
| */ |
| private boolean isReferenceFullyResolved() { |
| if (getPartialResolvedStack().peek() instanceof YangType) { |
| /* |
| * Checks if type is partially resolved. |
| */ |
| if (((YangType) getPartialResolvedStack().peek()).getResolvableStatus() == |
| ResolvableStatus.RESOLVED) { |
| return true; |
| } |
| } else if (getPartialResolvedStack().peek() instanceof YangUses) { |
| if (((YangUses) getPartialResolvedStack().peek()).getResolvableStatus() == |
| ResolvableStatus.RESOLVED) { |
| return true; |
| } |
| } |
| return false; |
| } |
| |
| /** |
| * Check if node is of resolve type i.e. of type typedef or grouping. |
| * |
| * @param node typedef/grouping node |
| * @return true if node is of resolve type otherwise false |
| * @throws DataModelException a violation of data model rules |
| */ |
| private boolean isNodeOfResolveType(YangNode node) throws DataModelException { |
| if (getPartialResolvedStack().peek() instanceof YangType && entityToResolve instanceof YangType) { |
| if (node instanceof YangTypeDef) { |
| return true; |
| } |
| } else if (getPartialResolvedStack().peek() instanceof YangUses && entityToResolve instanceof YangUses) { |
| if (node instanceof YangGrouping) { |
| return true; |
| } |
| } else { |
| throw new DataModelException("Data Model Exception: Entity to resolved is other than type/uses"); |
| } |
| return false; |
| } |
| |
| |
| /** |
| * Check if node name is same as name in resolution info, i.e. name of |
| * typedef/grouping is same as name of type/uses. |
| * |
| * @param node typedef/grouping node |
| * @return true if node name is same as name in resolution info, otherwise |
| * false |
| * @throws DataModelException a violation of data model rules |
| */ |
| private boolean isNodeNameSameAsResolutionInfoName(YangNode node) throws DataModelException { |
| if (getPartialResolvedStack().peek() instanceof YangType) { |
| if (node.getName().equals(((YangType<?>) getPartialResolvedStack().peek()).getDataTypeName())) { |
| return true; |
| } |
| } else if (getPartialResolvedStack().peek() instanceof YangUses) { |
| if (node.getName().equals(((YangUses) getPartialResolvedStack().peek()).getName())) { |
| return true; |
| } |
| } else { |
| throw new DataModelException("Data Model Exception: Entity to resolved is other than type/uses"); |
| } |
| return false; |
| } |
| |
| /** |
| * Add reference of grouping/typedef in uses/type. |
| * |
| * @param node grouping/typedef node |
| * @throws DataModelException a violation of data model rules |
| */ |
| private void addReferredEntityLink(YangNode node) throws DataModelException { |
| if (getPartialResolvedStack().peek() instanceof YangType) { |
| YangDerivedInfo<?> derivedInfo = (YangDerivedInfo<?>) ((YangType<?>) getPartialResolvedStack().peek()) |
| .getDataTypeExtendedInfo(); |
| derivedInfo.setReferredTypeDef((YangTypeDef) node); |
| } else if (getPartialResolvedStack().peek() instanceof YangUses) { |
| ((YangUses) getPartialResolvedStack().peek()).setRefGroup((YangGrouping) node); |
| } else { |
| throw new DataModelException("Data Model Exception: Entity to resolved is other than type/uses"); |
| } |
| } |
| |
| /** |
| * Checks if typedef/grouping has further reference to type/typedef. |
| * |
| * @param node grouping/typedef node |
| * @return true if referred entity is resolved, otherwise false |
| * @throws DataModelException a violation of data model rules |
| */ |
| private boolean isMoreReferencePresent(YangNode node) throws DataModelException { |
| if (getEntityToResolve() instanceof YangType) { |
| /* |
| * Checks if typedef type is built-in type |
| */ |
| if ((((YangTypeDef) node).getDataType().getDataType() != YangDataTypes.DERIVED)) { |
| return false; |
| } |
| } else if (getEntityToResolve() instanceof YangUses) { |
| /* |
| * Search if the grouping has any uses child, if so return false, |
| * else return true. |
| */ |
| if (getUsesInGrouping(node) == null) { |
| return false; |
| } |
| } else { |
| throw new DataModelException("Data Model Exception: Entity to resolved is other than type/uses"); |
| } |
| return true; |
| } |
| |
| /** |
| * Return if there is any uses in grouping. |
| * |
| * @param node grouping/typedef node |
| * @return if there is any uses in grouping, otherwise return null |
| */ |
| private YangUses getUsesInGrouping(YangNode node) { |
| YangNode curNode = ((YangGrouping) node).getChild(); |
| while (curNode != null) { |
| if (curNode instanceof YangUses) { |
| break; |
| } |
| curNode = curNode.getNextSibling(); |
| } |
| return (YangUses) curNode; |
| } |
| |
| /** |
| * Resolve the complete stack. |
| * |
| * @throws DataModelException a violation of data model rules |
| */ |
| private void resolveCompleteStack() throws DataModelException { |
| // For all entries in stack calls for the resolution in type/uses. |
| for (T entity:getPartialResolvedStack()) { |
| if (!(entity instanceof Resolvable)) { |
| throw new DataModelException("Data Model Exception: Entity to resolved is other than type/uses"); |
| } |
| ((Resolvable) entity).resolve(); |
| // Set the resolution status in inside the type/uses. |
| ((Resolvable) entity).setResolvableStatus(ResolvableStatus.RESOLVED); |
| } |
| /* |
| * Set the resolution status in resolution info present in resolution |
| * list. |
| */ |
| setIsResolved(true); |
| } |
| |
| /** |
| * Add to partial resolved stack. |
| * |
| * @param node grouping/typedef node |
| * @throws DataModelException a violation of data model rules |
| */ |
| private void addToPartialResolvedStack(YangNode node) throws DataModelException { |
| if (getPartialResolvedStack().peek() instanceof YangType) { |
| // Add to the stack only for YANG typedef. |
| getPartialResolvedStack().push((T) ((YangTypeDef) node).getDataType()); |
| } else if (getPartialResolvedStack().peek() instanceof YangUses) { |
| getPartialResolvedStack().push((T) getUsesInGrouping(node)); |
| } else { |
| throw new DataModelException("Data Model Exception: Entity to resolved is other than type/uses"); |
| } |
| } |
| |
| /** |
| * Check if prefix is associated with type/uses. |
| * |
| * @param node typedef/grouping node |
| * @return true if prefix is present, otherwise false |
| * @throws DataModelException a violation of data model rules |
| */ |
| private boolean isExternalPrefixPresent(YangNode node) throws DataModelException { |
| if (getEntityToResolve() instanceof YangType) { |
| if (((YangTypeDef) node).getDataType().getPrefix() != null && |
| (!((YangTypeDef) node).getDataType().getPrefix().equals(resolutionInfoRootNodePrefix))) { |
| return true; |
| } |
| } else if (getEntityToResolve() instanceof YangUses) { |
| if (getUsesInGrouping(node).getPrefix() != null) { |
| return true; |
| } |
| } else { |
| throw new DataModelException("Data Model Exception: Entity to resolved is other than type/uses"); |
| } |
| return false; |
| } |
| |
| /** |
| * Returns prefix of imported module. |
| * |
| * @return prefix of imported module |
| */ |
| public String getPrefix() { |
| return prefix; |
| } |
| |
| /** |
| * Set prefix of imported module. |
| * |
| * @param prefix of imported module |
| */ |
| public void setPrefix(String prefix) { |
| this.prefix = prefix; |
| } |
| |
| /** |
| * Returns parsable entity which is to be resolved. |
| * |
| * @return parsable entity which is to be resolved |
| */ |
| public T getEntityToResolve() { |
| return entityToResolve; |
| } |
| |
| /** |
| * Set parsable entity to be resolved. |
| * |
| * @param entityToResolve YANG entity to be resolved |
| */ |
| public void setEntityToResolve(T entityToResolve) { |
| this.entityToResolve = entityToResolve; |
| } |
| |
| /** |
| * Returns parent YANG node holder for the entity to be resolved. |
| * |
| * @return parent YANG node holder |
| */ |
| public YangNode getHolderOfEntityToResolve() { |
| return holderOfEntityToResolve; |
| } |
| |
| /** |
| * Set parent YANG node holder for the entity to be resolved. |
| * |
| * @param holderOfEntityToResolve parent YANG node holder |
| */ |
| public void setHolderOfEntityToResolve(YangNode holderOfEntityToResolve) { |
| this.holderOfEntityToResolve = holderOfEntityToResolve; |
| } |
| |
| /** |
| * Returns error position. |
| * |
| * @return error position |
| */ |
| public int getCharPosition() { |
| return charPosition; |
| } |
| |
| /** |
| * Set error position. |
| * |
| * @param charPosition position of error |
| */ |
| public void setCharPosition(int charPosition) { |
| this.charPosition = charPosition; |
| } |
| |
| /** |
| * Returns error character position in line. |
| * |
| * @return error character position in line |
| */ |
| public int getLineNumber() { |
| return lineNumber; |
| } |
| |
| /** |
| * Set error character position in line. |
| * |
| * @param lineNumber error character position in line |
| */ |
| public void setLineNumber(int lineNumber) { |
| this.lineNumber = lineNumber; |
| } |
| |
| /** |
| * Returns status of resolution. |
| * |
| * @return resolution status |
| */ |
| public boolean isResolved() { |
| return isResolved; |
| } |
| |
| /** |
| * Set status of resolution. |
| * |
| * @param isResolved resolution status |
| */ |
| public void setIsResolved(boolean isResolved) { |
| this.isResolved = isResolved; |
| } |
| |
| /** |
| * Returns stack of YANG type with partially resolved YANG construct hierarchy. |
| * |
| * @return partial resolved YANG construct stack |
| */ |
| public Stack<T> getPartialResolvedStack() { |
| return partialResolvedStack; |
| } |
| |
| /** |
| * Set stack of YANG type with partially resolved YANG construct hierarchy. |
| * |
| * @param partialResolvedStack partial resolved YANG construct stack |
| */ |
| public void setPartialResolvedStack(Stack<T> partialResolvedStack) { |
| this.partialResolvedStack = partialResolvedStack; |
| } |
| } |