[ONOS-4063 to 68] Intra YANG file Linking Implementation and Intra YANG file Linking Framework
Change-Id: I06e602c351ab54178bf90b8676af71a70e42371f
diff --git a/utils/yangutils/src/main/java/org/onosproject/yangutils/datamodel/YangResolutionInfo.java b/utils/yangutils/src/main/java/org/onosproject/yangutils/datamodel/YangResolutionInfo.java
new file mode 100644
index 0000000..de65bb4
--- /dev/null
+++ b/utils/yangutils/src/main/java/org/onosproject/yangutils/datamodel/YangResolutionInfo.java
@@ -0,0 +1,640 @@
+/*
+ * 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;
+ }
+}