[ONOS-5785] Refactor code into new folder structure
Change-Id: I115d5af1cd7bfbde71a3092973fe160ec1d9bae5
diff --git a/compiler/base/linker/pom.xml b/compiler/base/linker/pom.xml
new file mode 100644
index 0000000..7cd5222
--- /dev/null
+++ b/compiler/base/linker/pom.xml
@@ -0,0 +1,74 @@
+<!--
+ ~ 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.
+ -->
+<project xmlns="http://maven.apache.org/POM/4.0.0"
+ xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+ xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
+ <modelVersion>4.0.0</modelVersion>
+
+ <parent>
+ <groupId>org.onosproject</groupId>
+ <artifactId>onos-yang-compiler-base</artifactId>
+ <version>1.12-SNAPSHOT</version>
+ </parent>
+
+ <artifactId>onos-yang-compiler-linker</artifactId>
+ <packaging>jar</packaging>
+
+ <dependencies>
+ <dependency>
+ <groupId>org.onosproject</groupId>
+ <artifactId>onos-yang-compiler-datamodel</artifactId>
+ <version>${project.version}</version>
+ </dependency>
+ <dependency>
+ <groupId>org.onosproject</groupId>
+ <artifactId>onos-yang-compiler-utils</artifactId>
+ <version>${project.version}</version>
+ </dependency>
+ <dependency>
+ <groupId>org.onosproject</groupId>
+ <artifactId>onos-yang-compiler-translator</artifactId>
+ <version>${project.version}</version>
+ </dependency>
+ <dependency>
+ <groupId>junit</groupId>
+ <artifactId>junit</artifactId>
+ <version>4.8.2</version>
+ <scope>test</scope>
+ </dependency>
+ </dependencies>
+
+ <build>
+ <plugins>
+ <plugin>
+ <groupId>org.apache.maven.plugins</groupId>
+ <artifactId>maven-jar-plugin</artifactId>
+ <version>3.0.2</version>
+ <configuration>
+ <skipIfEmpty>true</skipIfEmpty>
+ </configuration>
+ <executions>
+ <execution>
+ <id>default</id>
+ <goals>
+ <goal>test-jar</goal>
+ </goals>
+ </execution>
+ </executions>
+ </plugin>
+ </plugins>
+ </build>
+</project>
diff --git a/compiler/base/linker/src/main/java/org/onosproject/yang/compiler/linker/YangLinker.java b/compiler/base/linker/src/main/java/org/onosproject/yang/compiler/linker/YangLinker.java
new file mode 100644
index 0000000..b82e21e
--- /dev/null
+++ b/compiler/base/linker/src/main/java/org/onosproject/yang/compiler/linker/YangLinker.java
@@ -0,0 +1,35 @@
+/*
+ * 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.yang.compiler.linker;
+
+import org.onosproject.yang.compiler.datamodel.YangNode;
+
+import java.util.Set;
+
+/**
+ * Abstraction of entity which provides linking service of YANG files.
+ */
+public interface YangLinker {
+
+ /**
+ * Resolve the import and include dependencies for a given resolution
+ * information.
+ *
+ * @param yangNodeSet set of all dependent YANG nodes
+ */
+ void resolveDependencies(Set<YangNode> yangNodeSet);
+}
diff --git a/compiler/base/linker/src/main/java/org/onosproject/yang/compiler/linker/YangLinkingPhase.java b/compiler/base/linker/src/main/java/org/onosproject/yang/compiler/linker/YangLinkingPhase.java
new file mode 100644
index 0000000..bd7ecea
--- /dev/null
+++ b/compiler/base/linker/src/main/java/org/onosproject/yang/compiler/linker/YangLinkingPhase.java
@@ -0,0 +1,34 @@
+/*
+ * 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.yang.compiler.linker;
+
+/**
+ * Represents the phase of YANG file reference linking.
+ */
+public enum YangLinkingPhase {
+
+ /**
+ * Linking the reference within the files.
+ */
+ INTRA_FILE,
+
+ /**
+ * Linking the reference across the files.
+ */
+ INTER_FILE
+
+}
diff --git a/compiler/base/linker/src/main/java/org/onosproject/yang/compiler/linker/exceptions/LinkerException.java b/compiler/base/linker/src/main/java/org/onosproject/yang/compiler/linker/exceptions/LinkerException.java
new file mode 100644
index 0000000..9bc3e5b
--- /dev/null
+++ b/compiler/base/linker/src/main/java/org/onosproject/yang/compiler/linker/exceptions/LinkerException.java
@@ -0,0 +1,117 @@
+/*
+ * 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.yang.compiler.linker.exceptions;
+
+/**
+ * Represents base class for exceptions in linker operations.
+ */
+public class LinkerException extends RuntimeException {
+
+ private static final long serialVersionUID = 20160211L;
+ private transient int lineNumber;
+ private transient int charPositionInLine;
+ private transient String fileName;
+
+ /**
+ * Creates a new linker exception.
+ */
+ public LinkerException() {
+ super();
+ }
+
+ /**
+ * Creates a new linker exception with given message.
+ *
+ * @param message the detail of exception in string
+ */
+ public LinkerException(String message) {
+ super(message);
+ }
+
+ /**
+ * Creates a new linker exception from given message and cause.
+ *
+ * @param message the detail of exception in string
+ * @param cause underlying cause of the error
+ */
+ public LinkerException(final String message, final Throwable cause) {
+ super(message, cause);
+ }
+
+ /**
+ * Creates a new linker exception from cause.
+ *
+ * @param cause underlying cause of the error
+ */
+ public LinkerException(final Throwable cause) {
+ super(cause);
+ }
+
+ /**
+ * Returns line number of the exception.
+ *
+ * @return line number of the exception
+ */
+ public int getLineNumber() {
+ return this.lineNumber;
+ }
+
+ /**
+ * Returns YANG file name of the exception.
+ *
+ * @return YANG file name of the exception
+ */
+ public String getFileName() {
+ return this.fileName;
+ }
+
+ /**
+ * Returns position of the exception.
+ *
+ * @return position of the exception
+ */
+ public int getCharPositionInLine() {
+ return this.charPositionInLine;
+ }
+
+ /**
+ * Sets line number of YANG file.
+ *
+ * @param line line number of YANG file
+ */
+ public void setLine(int line) {
+ this.lineNumber = line;
+ }
+
+ /**
+ * Sets position of exception.
+ *
+ * @param charPosition position of exception
+ */
+ public void setCharPosition(int charPosition) {
+ this.charPositionInLine = charPosition;
+ }
+
+ /**
+ * Sets file name in parser exception.
+ *
+ * @param fileName YANG file name
+ */
+ public void setFileName(String fileName) {
+ this.fileName = fileName;
+ }
+}
diff --git a/compiler/base/linker/src/main/java/org/onosproject/yang/compiler/linker/exceptions/package-info.java b/compiler/base/linker/src/main/java/org/onosproject/yang/compiler/linker/exceptions/package-info.java
new file mode 100644
index 0000000..a3de887
--- /dev/null
+++ b/compiler/base/linker/src/main/java/org/onosproject/yang/compiler/linker/exceptions/package-info.java
@@ -0,0 +1,20 @@
+/*
+ * 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.
+ */
+
+/**
+ * Custom linker exceptions.
+ */
+package org.onosproject.yang.compiler.linker.exceptions;
diff --git a/compiler/base/linker/src/main/java/org/onosproject/yang/compiler/linker/impl/PrefixResolverType.java b/compiler/base/linker/src/main/java/org/onosproject/yang/compiler/linker/impl/PrefixResolverType.java
new file mode 100644
index 0000000..a7896b7
--- /dev/null
+++ b/compiler/base/linker/src/main/java/org/onosproject/yang/compiler/linker/impl/PrefixResolverType.java
@@ -0,0 +1,48 @@
+/*
+ * 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.yang.compiler.linker.impl;
+
+/**
+ * Enum for prefix resolver type when augment has come in path.
+ */
+enum PrefixResolverType {
+
+ /**
+ * When prefix changes from inter file to intra file.
+ */
+ INTER_TO_INTRA,
+
+ /**
+ * When prefix changes from intra file to inter file.
+ */
+ INTRA_TO_INTER,
+
+ /**
+ * When prefix changes from one inter file to other inter file.
+ */
+ INTER_TO_INTER,
+
+ /**
+ * When no prefix change occurs.
+ */
+ NO_PREFIX_CHANGE_FOR_INTRA,
+
+ /**
+ * When no prefix change occurs.
+ */
+ NO_PREFIX_CHANGE_FOR_INTER
+}
diff --git a/compiler/base/linker/src/main/java/org/onosproject/yang/compiler/linker/impl/XpathLinkingTypes.java b/compiler/base/linker/src/main/java/org/onosproject/yang/compiler/linker/impl/XpathLinkingTypes.java
new file mode 100644
index 0000000..a4345cf
--- /dev/null
+++ b/compiler/base/linker/src/main/java/org/onosproject/yang/compiler/linker/impl/XpathLinkingTypes.java
@@ -0,0 +1,31 @@
+/*
+ * 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.yang.compiler.linker.impl;
+
+/**
+ * Represents x path linking types.
+ */
+public enum XpathLinkingTypes {
+
+ // Augment path linking.
+ AUGMENT_LINKING,
+
+ // Leaf ref path linking.
+ LEAF_REF_LINKING,
+
+ // Compiler annotation linking.
+ COMPILER_ANNOTATION_LINKING
+}
diff --git a/compiler/base/linker/src/main/java/org/onosproject/yang/compiler/linker/impl/YangLinkerManager.java b/compiler/base/linker/src/main/java/org/onosproject/yang/compiler/linker/impl/YangLinkerManager.java
new file mode 100644
index 0000000..61528be
--- /dev/null
+++ b/compiler/base/linker/src/main/java/org/onosproject/yang/compiler/linker/impl/YangLinkerManager.java
@@ -0,0 +1,215 @@
+/*
+ * 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.yang.compiler.linker.impl;
+
+import org.onosproject.yang.compiler.datamodel.YangNode;
+import org.onosproject.yang.compiler.datamodel.YangReferenceResolver;
+import org.onosproject.yang.compiler.datamodel.YangSubModule;
+import org.onosproject.yang.compiler.datamodel.exceptions.DataModelException;
+import org.onosproject.yang.compiler.linker.YangLinker;
+import org.onosproject.yang.compiler.linker.exceptions.LinkerException;
+
+import java.util.HashSet;
+import java.util.LinkedList;
+import java.util.List;
+import java.util.Set;
+
+import static java.util.Collections.sort;
+import static org.onosproject.yang.compiler.datamodel.ResolvableType.YANG_AUGMENT;
+import static org.onosproject.yang.compiler.datamodel.ResolvableType.YANG_BASE;
+import static org.onosproject.yang.compiler.datamodel.ResolvableType.YANG_COMPILER_ANNOTATION;
+import static org.onosproject.yang.compiler.datamodel.ResolvableType.YANG_DERIVED_DATA_TYPE;
+import static org.onosproject.yang.compiler.datamodel.ResolvableType.YANG_IDENTITYREF;
+import static org.onosproject.yang.compiler.datamodel.ResolvableType.YANG_IF_FEATURE;
+import static org.onosproject.yang.compiler.datamodel.ResolvableType.YANG_LEAFREF;
+import static org.onosproject.yang.compiler.datamodel.ResolvableType.YANG_USES;
+import static org.onosproject.yang.compiler.linker.impl.YangLinkerUtils.updateFilePriority;
+import static org.onosproject.yang.compiler.utils.UtilConstants.NEW_LINE;
+
+/**
+ * Representation of entity which provides linking service of YANG files.
+ */
+public class YangLinkerManager
+ implements YangLinker {
+
+ /*
+ * Set of all the YANG nodes, corresponding to the YANG files parsed by
+ * parser.
+ */
+ private Set<YangNode> yangNodeSet = new HashSet<>();
+
+ /**
+ * Returns set of YANG node.
+ *
+ * @return set of YANG node
+ */
+ public Set<YangNode> getYangNodeSet() {
+ return yangNodeSet;
+ }
+
+ /**
+ * Creates YANG nodes set.
+ *
+ * @param yangNodeSet YANG node information set
+ */
+ public void createYangNodeSet(Set<YangNode> yangNodeSet) {
+ getYangNodeSet().addAll(yangNodeSet);
+ }
+
+ @Override
+ public void resolveDependencies(Set<YangNode> yangNodeSet) {
+
+ // Create YANG node set.
+ createYangNodeSet(yangNodeSet);
+
+ // Carry out linking of sub module with module.
+ linkSubModulesToParentModule(yangNodeSet);
+
+ // Add references to import list.
+ addRefToYangFilesImportList(yangNodeSet);
+
+ // Add reference to include list.
+ addRefToYangFilesIncludeList(yangNodeSet);
+
+ // Update the priority for all the files.
+ updateFilePriority(yangNodeSet);
+
+ // TODO check for circular import/include.
+
+ // Carry out inter-file linking.
+ processInterFileLinking(yangNodeSet);
+ }
+
+ /**
+ * Resolves sub-module linking by linking sub module with parent module.
+ *
+ * @param yangNodeSet set of YANG files info
+ * @throws LinkerException fails to link sub-module to parent module
+ */
+ public void linkSubModulesToParentModule(Set<YangNode> yangNodeSet)
+ throws LinkerException {
+ for (YangNode yangNode : yangNodeSet) {
+ if (yangNode instanceof YangSubModule) {
+ try {
+ ((YangSubModule) yangNode).linkWithModule(getYangNodeSet());
+ } catch (DataModelException e) {
+ String errorInfo = "Error in file: " + yangNode.getName() + " in " +
+ yangNode.getFileName() + " at " +
+ "line: " + e.getLineNumber() + " at position: " + e.getCharPositionInLine() + NEW_LINE
+ + e.getLocalizedMessage();
+ throw new LinkerException(errorInfo);
+ // TODO add file path in exception message in util manager.
+ }
+ }
+ }
+ }
+
+ /**
+ * Adds imported node information to the import list.
+ *
+ * @param yangNodeSet set of YANG files info
+ * @throws LinkerException fails to find imported module
+ */
+ public void addRefToYangFilesImportList(Set<YangNode> yangNodeSet)
+ throws LinkerException {
+ for (YangNode yangNode : yangNodeSet) {
+ if (yangNode instanceof YangReferenceResolver) {
+ try {
+ ((YangReferenceResolver) yangNode).addReferencesToImportList(getYangNodeSet());
+ } catch (DataModelException e) {
+ String errorInfo = "Error in file: " + yangNode.getName() + " in " +
+ yangNode.getFileName() + " at " +
+ "line: " + e.getLineNumber() + " at position: " + e.getCharPositionInLine() + NEW_LINE
+ + e.getLocalizedMessage();
+ throw new LinkerException(errorInfo);
+ // TODO add file path in exception message in util manager.
+ }
+ }
+ }
+ }
+
+ /**
+ * Adds included node information to the include list.
+ *
+ * @param yangNodeSet set of YANG files info
+ * @throws LinkerException fails to find included sub-module
+ */
+ public void addRefToYangFilesIncludeList(Set<YangNode> yangNodeSet)
+ throws LinkerException {
+ for (YangNode yangNode : yangNodeSet) {
+ if (yangNode instanceof YangReferenceResolver) {
+ try {
+ ((YangReferenceResolver) yangNode).addReferencesToIncludeList(getYangNodeSet());
+ } catch (DataModelException e) {
+ String errorInfo = "Error in file: " + yangNode.getName() + " in " +
+ yangNode.getFileName() + " at " +
+ "line: " + e.getLineNumber() + " at position: " + e.getCharPositionInLine() + NEW_LINE
+ + e.getLocalizedMessage();
+ throw new LinkerException(errorInfo);
+ // TODO add file path in exception message in util manager.
+ }
+ }
+ }
+ }
+
+ /**
+ * Processes inter file linking for type and uses.
+ *
+ * @param yangNodeSet set of YANG files info
+ * @throws LinkerException a violation in linker execution
+ */
+ public void processInterFileLinking(Set<YangNode> yangNodeSet)
+ throws LinkerException {
+ List<YangNode> yangNodeSortedList = new LinkedList<>();
+ yangNodeSortedList.addAll(yangNodeSet);
+ sort(yangNodeSortedList);
+ for (YangNode yangNode : yangNodeSortedList) {
+ try {
+ ((YangReferenceResolver) yangNode)
+ .resolveInterFileLinking(YANG_IF_FEATURE);
+ ((YangReferenceResolver) yangNode)
+ .resolveInterFileLinking(YANG_USES);
+ ((YangReferenceResolver) yangNode)
+ .resolveInterFileLinking(YANG_AUGMENT);
+ ((YangReferenceResolver) yangNode)
+ .resolveInterFileLinking(YANG_DERIVED_DATA_TYPE);
+ ((YangReferenceResolver) yangNode)
+ .resolveInterFileLinking(YANG_BASE);
+ ((YangReferenceResolver) yangNode)
+ .resolveInterFileLinking(YANG_IDENTITYREF);
+ ((YangReferenceResolver) yangNode)
+ .resolveInterFileLinking(YANG_LEAFREF);
+ ((YangReferenceResolver) yangNode)
+ .resolveInterFileLinking(YANG_COMPILER_ANNOTATION);
+ } catch (DataModelException e) {
+ String errorInfo = "Error in file: " + yangNode.getName() + " in " +
+ yangNode.getFileName() + " at " +
+ "line: " + e.getLineNumber() + " at position: " + e.getCharPositionInLine() + NEW_LINE
+ + e.getLocalizedMessage();
+ throw new LinkerException(errorInfo);
+ // TODO add file path in exception message in util manager.
+ } catch (LinkerException e) {
+ String errorInfo = "Error in file: " + yangNode.getName() + " in " +
+ yangNode.getFileName() + " at " +
+ "line: " + e.getLineNumber() + " at position: " + e.getCharPositionInLine() + NEW_LINE
+ + e.getLocalizedMessage();
+ throw new LinkerException(errorInfo);
+ // TODO add file path in exception message in util manager.
+ }
+ }
+ }
+}
diff --git a/compiler/base/linker/src/main/java/org/onosproject/yang/compiler/linker/impl/YangLinkerUtils.java b/compiler/base/linker/src/main/java/org/onosproject/yang/compiler/linker/impl/YangLinkerUtils.java
new file mode 100644
index 0000000..7783328
--- /dev/null
+++ b/compiler/base/linker/src/main/java/org/onosproject/yang/compiler/linker/impl/YangLinkerUtils.java
@@ -0,0 +1,934 @@
+/*
+ * 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.yang.compiler.linker.impl;
+
+import org.onosproject.yang.compiler.datamodel.TraversalType;
+import org.onosproject.yang.compiler.datamodel.YangAtomicPath;
+import org.onosproject.yang.compiler.datamodel.YangAugment;
+import org.onosproject.yang.compiler.datamodel.YangAugmentableNode;
+import org.onosproject.yang.compiler.datamodel.YangBase;
+import org.onosproject.yang.compiler.datamodel.YangCase;
+import org.onosproject.yang.compiler.datamodel.YangChoice;
+import org.onosproject.yang.compiler.datamodel.YangGrouping;
+import org.onosproject.yang.compiler.datamodel.YangIdentityRef;
+import org.onosproject.yang.compiler.datamodel.YangIfFeature;
+import org.onosproject.yang.compiler.datamodel.YangImport;
+import org.onosproject.yang.compiler.datamodel.YangInclude;
+import org.onosproject.yang.compiler.datamodel.YangLeaf;
+import org.onosproject.yang.compiler.datamodel.YangLeafList;
+import org.onosproject.yang.compiler.datamodel.YangLeafRef;
+import org.onosproject.yang.compiler.datamodel.YangLeavesHolder;
+import org.onosproject.yang.compiler.datamodel.YangList;
+import org.onosproject.yang.compiler.datamodel.YangNode;
+import org.onosproject.yang.compiler.datamodel.YangNodeIdentifier;
+import org.onosproject.yang.compiler.datamodel.YangPathPredicate;
+import org.onosproject.yang.compiler.datamodel.YangReferenceResolver;
+import org.onosproject.yang.compiler.datamodel.YangRelativePath;
+import org.onosproject.yang.compiler.datamodel.YangType;
+import org.onosproject.yang.compiler.datamodel.YangTypeDef;
+import org.onosproject.yang.compiler.datamodel.YangUses;
+import org.onosproject.yang.compiler.datamodel.exceptions.DataModelException;
+import org.onosproject.yang.compiler.datamodel.utils.YangConstructType;
+import org.onosproject.yang.compiler.linker.exceptions.LinkerException;
+import org.onosproject.yang.compiler.translator.exception.TranslatorException;
+
+import java.util.ArrayList;
+import java.util.Iterator;
+import java.util.LinkedHashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+import java.util.regex.Pattern;
+
+import static org.onosproject.yang.compiler.datamodel.TraversalType.CHILD;
+import static org.onosproject.yang.compiler.datamodel.TraversalType.PARENT;
+import static org.onosproject.yang.compiler.datamodel.TraversalType.ROOT;
+import static org.onosproject.yang.compiler.datamodel.TraversalType.SIBILING;
+import static org.onosproject.yang.compiler.datamodel.exceptions.ErrorMessages.COLLISION_DETECTION;
+import static org.onosproject.yang.compiler.datamodel.exceptions.ErrorMessages.FAILED_TO_ADD_CASE;
+import static org.onosproject.yang.compiler.datamodel.exceptions.ErrorMessages.TARGET_NODE;
+import static org.onosproject.yang.compiler.datamodel.exceptions.ErrorMessages.TARGET_NODE_LEAF_INFO;
+import static org.onosproject.yang.compiler.datamodel.exceptions.ErrorMessages.getErrorMsg;
+import static org.onosproject.yang.compiler.datamodel.exceptions.ErrorMessages.getErrorMsgCollision;
+import static org.onosproject.yang.compiler.datamodel.utils.DataModelUtils.addResolutionInfo;
+import static org.onosproject.yang.compiler.datamodel.utils.GeneratedLanguage.JAVA_GENERATION;
+import static org.onosproject.yang.compiler.datamodel.utils.ResolvableStatus.RESOLVED;
+import static org.onosproject.yang.compiler.datamodel.utils.YangConstructType.getYangConstructType;
+import static org.onosproject.yang.compiler.datamodel.utils.builtindatatype.YangDataTypes.DERIVED;
+import static org.onosproject.yang.compiler.datamodel.utils.builtindatatype.YangDataTypes.IDENTITYREF;
+import static org.onosproject.yang.compiler.translator.tojava.YangDataModelFactory.getYangCaseNode;
+import static org.onosproject.yang.compiler.utils.UtilConstants.BASE_LINKER_ERROR;
+import static org.onosproject.yang.compiler.utils.UtilConstants.COLON;
+import static org.onosproject.yang.compiler.utils.UtilConstants.COMMA;
+import static org.onosproject.yang.compiler.utils.UtilConstants.EMPTY_STRING;
+import static org.onosproject.yang.compiler.utils.UtilConstants.FEATURE_LINKER_ERROR;
+import static org.onosproject.yang.compiler.utils.UtilConstants.GROUPING_LINKER_ERROR;
+import static org.onosproject.yang.compiler.utils.UtilConstants.IDENTITYREF_LINKER_ERROR;
+import static org.onosproject.yang.compiler.utils.UtilConstants.INVALID_TREE;
+import static org.onosproject.yang.compiler.utils.UtilConstants.IS_INVALID;
+import static org.onosproject.yang.compiler.utils.UtilConstants.LEAFREF_ERROR;
+import static org.onosproject.yang.compiler.utils.UtilConstants.LEAFREF_LINKER_ERROR;
+import static org.onosproject.yang.compiler.utils.UtilConstants.TYPEDEF_LINKER_ERROR;
+
+/**
+ * Represent utilities for YANG linker.
+ */
+public final class 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";
+ private static final String INVALID_PATH_PRE =
+ "YANG file error: The path predicate of the leafref has an " +
+ "invalid path in ";
+ private static final String EMPTY_PATH_LIST_ERR =
+ "YANG file error : The atomic path list cannot be empty of the " +
+ "leafref in the path ";
+ private static final String TGT_LEAF_ERR =
+ "YANG file error: There is no leaf/leaf-list in YANG node as " +
+ "mentioned in the path predicate of the leafref path ";
+ private static final String LEAF_REF_LIST_ERR =
+ "YANG file error: Path predicates are only applicable for YANG " +
+ "list. The leafref path has path predicate for non-list " +
+ "node in the path ";
+
+ // No instantiation.
+ private YangLinkerUtils() {
+ }
+
+ /**
+ * 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();
+ if (targetNode instanceof YangChoice) {
+ addCaseNodeToChoiceTarget(augment);
+ } else {
+ detectCollisionInLeaveHolders(targetNode, augment);
+ while (augmentsChild != null) {
+ detectCollisionInChildNodes(targetNodesChild, augmentsChild);
+ augmentsChild = augmentsChild.getNextSibling();
+ }
+ }
+ }
+
+ /*Detects collision between leaves/leaf-lists*/
+ private static void detectCollisionInLeaveHolders(YangNode targetNode, YangAugment augment) {
+ YangLeavesHolder targetNodesLeavesHolder = (YangLeavesHolder) targetNode;
+ if (augment.getListOfLeaf() != null && augment.getListOfLeaf().isEmpty() &&
+ targetNodesLeavesHolder.getListOfLeaf() != null) {
+ for (YangLeaf leaf : augment.getListOfLeaf()) {
+ for (YangLeaf targetLeaf : targetNodesLeavesHolder.getListOfLeaf()) {
+ detectCollision(targetLeaf.getName(), leaf.getName(),
+ leaf.getLineNumber(),
+ leaf.getCharPosition(),
+ leaf.getFileName(), TARGET_NODE_LEAF_INFO);
+ }
+ }
+ }
+ if (augment.getListOfLeafList() != null &&
+ augment.getListOfLeafList().isEmpty() &&
+ targetNodesLeavesHolder.getListOfLeafList() != null) {
+ for (YangLeafList leafList : augment.getListOfLeafList()) {
+ for (YangLeafList targetLeafList : targetNodesLeavesHolder.getListOfLeafList()) {
+ detectCollision(targetLeafList.getName(), leafList.getName(),
+ leafList.getLineNumber(),
+ leafList.getCharPosition(),
+ leafList.getFileName(), TARGET_NODE_LEAF_INFO);
+ }
+ }
+ }
+ }
+
+
+ private static void detectCollision(String first, String second,
+ int line, int position, String
+ fileName, String type) {
+ if (first.equals(second)) {
+ throw new LinkerException(getErrorMsgCollision(
+ COLLISION_DETECTION, second, line, position, type,
+ fileName));
+ }
+ }
+
+ /*Detects collision for child nodes.*/
+ private static void detectCollisionInChildNodes(YangNode targetNodesChild,
+ YangNode augmentsChild) {
+ while (augmentsChild != null) {
+ while (targetNodesChild != null) {
+ if (targetNodesChild.getName().equals(augmentsChild.getName())) {
+ detectCollision(targetNodesChild.getName(), augmentsChild.getName(),
+ augmentsChild.getLineNumber(),
+ augmentsChild.getCharPosition(),
+ augmentsChild.getFileName(), TARGET_NODE);
+ }
+ targetNodesChild = targetNodesChild.getNextSibling();
+ }
+ augmentsChild = augmentsChild.getNextSibling();
+ }
+ }
+
+ /**
+ * Adds a case node in augment when augmenting a choice node.
+ *
+ * @param augment augment node
+ */
+ private static void addCaseNodeToChoiceTarget(YangAugment augment) {
+ try {
+ YangNode child = augment.getChild();
+ List<YangNode> childNodes = new ArrayList<>();
+ List<YangNode> caseNodes = new ArrayList<>();
+ while (child != null) {
+ if (!(child instanceof YangCase)) {
+ childNodes.add(child);
+ } else {
+ caseNodes.add(child);
+ }
+ child = child.getNextSibling();
+ }
+ augment.setChild(null);
+
+ for (YangNode node : childNodes) {
+ Map<YangNode, List<YangNode>> map = new LinkedHashMap<>();
+ node.setNextSibling(null);
+ node.setPreviousSibling(null);
+ node.setParent(null);
+ YangCase javaCase = getYangCaseNode(JAVA_GENERATION);
+ javaCase.setName(node.getName());
+ //Break the tree to from a new tree.
+ traverseAndBreak(node, map);
+ augment.addChild(javaCase);
+ node.setParent(javaCase);
+ javaCase.addChild(node);
+ //Connect each node to its correct parent again.
+ connectTree(map);
+ }
+
+ for (YangNode node : caseNodes) {
+ Map<YangNode, List<YangNode>> map = new LinkedHashMap<>();
+ node.setNextSibling(null);
+ node.setPreviousSibling(null);
+ node.setParent(null);
+ //Break the tree to from a new tree.
+ traverseAndBreak(node, map);
+ augment.addChild(node);
+ node.setParent(augment);
+ //Connect each node to its correct parent again.
+ connectTree(map);
+ }
+ if (augment.getListOfLeaf() != null) {
+ for (YangLeaf leaf : augment.getListOfLeaf()) {
+ YangCase javaCase = getYangCaseNode(JAVA_GENERATION);
+ javaCase.setName(leaf.getName());
+ javaCase.addLeaf(leaf);
+ augment.addChild(javaCase);
+ }
+ augment.getListOfLeaf().clear();
+ }
+ if (augment.getListOfLeafList() != null) {
+ for (YangLeafList leafList : augment.getListOfLeafList()) {
+ YangCase javaCase = getYangCaseNode(JAVA_GENERATION);
+ javaCase.setName(leafList.getName());
+ javaCase.addLeafList(leafList);
+ augment.addChild(javaCase);
+ }
+ augment.getListOfLeafList().clear();
+ }
+ } catch (DataModelException e) {
+ throw new TranslatorException(
+ getErrorMsg(FAILED_TO_ADD_CASE, augment.getName(),
+ augment.getLineNumber(), augment.getCharPosition(),
+ augment.getFileName()));
+ }
+ }
+
+ private static void connectTree(Map<YangNode, List<YangNode>> map)
+ throws DataModelException {
+ ArrayList<YangNode> keys = new ArrayList<>(map.keySet());
+ int size = keys.size();
+ for (int i = size - 1; i >= 0; i--) {
+ YangNode curNode = keys.get(i);
+ List<YangNode> nodes = map.get(curNode);
+ if (nodes != null) {
+ for (YangNode node : nodes) {
+ curNode.addChild(node);
+ }
+ }
+ }
+ map.clear();
+ }
+
+ private static void processHierarchyChild(YangNode node,
+ Map<YangNode, List<YangNode>> map) {
+ YangNode child = node.getChild();
+ if (child != null) {
+ List<YangNode> nodes = new ArrayList<>();
+ while (child != null) {
+ nodes.add(child);
+ child.setParent(null);
+ child = child.getNextSibling();
+ if (child != null) {
+ child.getPreviousSibling().setNextSibling(null);
+ child.setPreviousSibling(null);
+ }
+ }
+ map.put(node, nodes);
+ }
+ node.setChild(null);
+ }
+
+ private static void traverseAndBreak(YangNode rootNode,
+ Map<YangNode, List<YangNode>> map) {
+
+ YangNode curNode = rootNode;
+ TraversalType curTraversal = ROOT;
+ while (curNode != null) {
+ if (curTraversal != PARENT && curNode.getChild() != null) {
+ curTraversal = CHILD;
+ curNode = curNode.getChild();
+ } else if (curNode.getNextSibling() != null) {
+ curTraversal = SIBILING;
+ curNode = curNode.getNextSibling();
+ } else {
+ curTraversal = PARENT;
+ curNode = curNode.getParent();
+ if (curNode != null) {
+ processHierarchyChild(curNode, map);
+ }
+ }
+ }
+ }
+
+ /**
+ * Returns error messages.
+ *
+ * @param resolvable resolvable entity
+ * @return error message
+ */
+ static String getErrorInfoForLinker(Object resolvable) {
+ if (resolvable instanceof YangType) {
+ return TYPEDEF_LINKER_ERROR;
+ }
+ if (resolvable instanceof YangUses) {
+ return GROUPING_LINKER_ERROR;
+ }
+ if (resolvable instanceof YangIfFeature) {
+ return FEATURE_LINKER_ERROR;
+ }
+ if (resolvable instanceof YangBase) {
+ return BASE_LINKER_ERROR;
+ }
+ if (resolvable instanceof YangIdentityRef) {
+ return IDENTITYREF_LINKER_ERROR;
+ }
+ return LEAFREF_LINKER_ERROR;
+ }
+
+ /**
+ * Returns leafref's error message.
+ *
+ * @param leafref leaf ref
+ * @return error message
+ */
+ static String getLeafRefErrorInfo(YangLeafRef leafref) {
+ return getErrorMsg(
+ LEAFREF_ERROR + leafref.getPath() + COMMA + IS_INVALID, EMPTY_STRING,
+ leafref.getLineNumber(), leafref.getCharPosition(), leafref
+ .getFileName());
+ }
+
+ /**
+ * 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
+ */
+ static void detectCollisionForAugmentedNode(YangNode targetNode, YangAugment augment) {
+ // Detect collision for target node and augment node.
+ detectCollision(targetNode, augment);
+ List<YangAugment> yangAugmentedInfo = ((YangAugmentableNode) targetNode).getAugmentedInfoList();
+ // Detect collision for target augment node and current augment node.
+ for (YangAugment info : yangAugmentedInfo) {
+ detectCollision(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
+ */
+ static List<String> getPathWithAugment(YangAugment augment, int remainingAncestors) {
+ List<String> listOfPathName = new ArrayList<>();
+ for (YangAtomicPath atomicPath : augment.getTargetNode()) {
+ if (atomicPath.getNodeIdentifier().getPrefix() != null &&
+ !atomicPath.getNodeIdentifier().getPrefix().equals(EMPTY_STRING)) {
+ listOfPathName.add(atomicPath.getNodeIdentifier().getPrefix()
+ + COLON + atomicPath.getNodeIdentifier().getName());
+ } else {
+ listOfPathName.add(atomicPath.getNodeIdentifier().getName());
+ }
+ }
+ 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 curParent current parent
+ * @param leafRef YANG leaf-ref
+ * @return parent node which can hold data
+ * @throws LinkerException if linker rules are violated
+ */
+ public static YangNode skipInvalidDataNodes(YangNode curParent,
+ YangLeafRef leafRef)
+ throws LinkerException {
+
+ YangNode node = curParent;
+ while (node instanceof YangChoice ||
+ node instanceof YangCase) {
+
+ if (node.getParent() == null) {
+ throw new LinkerException(getLeafRefErrorInfo(leafRef));
+ }
+ node = node.getParent();
+ }
+ return node;
+ }
+
+ /**
+ * Checks and return valid node identifier.
+ *
+ * @param nodeIdentifierString string from yang file
+ * @param yangConstruct yang construct for creating error message
+ * @return valid node identifier
+ */
+ 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 : " +
+ 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 : " +
+ getYangConstructType(yangConstruct) + " name " + identifier + " is " +
+ "greater than 64 characters.");
+ } else if (!IDENTIFIER_PATTERN.matcher(identifier).matches()) {
+ throw new LinkerException("YANG file error : " +
+ getYangConstructType(yangConstruct) + " name " + identifier + " is not " +
+ "valid.");
+ } else if (identifier.toLowerCase().startsWith(XML)) {
+ throw new LinkerException("YANG file error : " +
+ getYangConstructType(yangConstruct) + " identifier " + identifier +
+ " must not start with (('X'|'x') ('M'|'m') ('L'|'l')).");
+ } else {
+ return identifier;
+ }
+ }
+
+ /**
+ * Updates the priority for all the input files.
+ *
+ * @param yangNodeSet set of YANG files info
+ */
+ public static void updateFilePriority(Set<YangNode> yangNodeSet) {
+ for (YangNode yangNode : yangNodeSet) {
+ updateFilePriorityOfNode(yangNode);
+ }
+ }
+
+ /**
+ * Updates priority of the node.
+ *
+ * @param yangNode YANG node information
+ */
+ private static void updateFilePriorityOfNode(YangNode yangNode) {
+ int curNodePriority = yangNode.getPriority();
+ if (yangNode instanceof YangReferenceResolver) {
+ List<YangImport> yangImportList = ((YangReferenceResolver) yangNode).getImportList();
+ Iterator<YangImport> importInfoIterator = yangImportList.iterator();
+ // Run through the imported list to update priority.
+ while (importInfoIterator.hasNext()) {
+ YangImport yangImport = importInfoIterator.next();
+ YangNode importedNode = yangImport.getImportedNode();
+ if (curNodePriority >= importedNode.getPriority()) {
+ importedNode.setPriority(curNodePriority + 1);
+ updateFilePriorityOfNode(importedNode);
+ }
+ }
+
+ List<YangInclude> yangIncludeList = ((YangReferenceResolver) yangNode).getIncludeList();
+ Iterator<YangInclude> includeInfoIterator = yangIncludeList.iterator();
+ // Run through the imported list to update priority.
+ while (includeInfoIterator.hasNext()) {
+ YangInclude yangInclude = includeInfoIterator.next();
+ YangNode includedNode = yangInclude.getIncludedNode();
+ if (curNodePriority >= includedNode.getPriority()) {
+ includedNode.setPriority(curNodePriority + 1);
+ updateFilePriorityOfNode(includedNode);
+ }
+ }
+ }
+ }
+
+ /**
+ * Add the unresolved data under the root leve grouping to be resolved, since it will be used in interfile uses.
+ *
+ * @param referenceResolver module / sub-module
+ */
+ public static void resolveGroupingInDefinationScope(YangReferenceResolver referenceResolver) {
+ YangNode potentialInterFileGrouping = ((YangNode) referenceResolver).getChild();
+
+ while (potentialInterFileGrouping != null) {
+ if (potentialInterFileGrouping instanceof YangGrouping) {
+ addGroupingResolvableEntitiesToResolutionList((YangGrouping) potentialInterFileGrouping);
+ }
+
+ potentialInterFileGrouping = potentialInterFileGrouping.getNextSibling();
+ }
+ }
+
+ /**
+ * Add the interfile grouping resolvable entities to reesolution list.
+ *
+ * @param interFileGrouping interfile grouping
+ */
+ private static void addGroupingResolvableEntitiesToResolutionList(YangGrouping interFileGrouping) {
+ YangNode curNode = interFileGrouping;
+ TraversalType curTraversal = ROOT;
+ addResolvableLeavesToResolutionList((YangLeavesHolder) curNode);
+ curTraversal = CHILD;
+ curNode = interFileGrouping.getChild();
+ if (curNode == null) {
+ return;
+ }
+ while (curNode != interFileGrouping) {
+ if (curTraversal != PARENT) {
+ if (curNode instanceof YangGrouping || curNode instanceof YangUses) {
+ if (curNode.getNextSibling() != null) {
+ curTraversal = SIBILING;
+ curNode = curNode.getNextSibling();
+ } else {
+ curTraversal = PARENT;
+ curNode = curNode.getParent();
+ }
+ continue;
+ }
+
+ if (curNode instanceof YangLeavesHolder) {
+ addResolvableLeavesToResolutionList((YangLeavesHolder) curNode);
+ } else if (curNode instanceof YangTypeDef) {
+ List<YangType<?>> typeList = ((YangTypeDef) curNode).getTypeList();
+ if (!typeList.isEmpty()) {
+ YangType<?> type = typeList.get(0);
+ if (type.getDataType() == DERIVED) {
+ if (type.getResolvableStatus() != RESOLVED) {
+
+ type.setTypeForInterFileGroupingResolution(true);
+
+ // Add resolution information to the list
+ YangResolutionInfoImpl resolutionInfo =
+ new YangResolutionInfoImpl<YangType>(type, curNode, type.getLineNumber(),
+ type.getCharPosition());
+ try {
+ addResolutionInfo(resolutionInfo);
+ } catch (DataModelException e) {
+ String errorInfo = "Error in file: " + curNode.getName() + " in " +
+ curNode.getFileName() + " at " +
+ "line: " + e.getLineNumber() +
+ " at position: " + e.getCharPositionInLine()
+ + e.getLocalizedMessage();
+ throw new LinkerException("Failed to add type info in grouping to resolution "
+ + errorInfo);
+ }
+ }
+ }
+ }
+ }
+ }
+ if (curTraversal != PARENT && curNode.getChild() != null) {
+ curTraversal = CHILD;
+ curNode = curNode.getChild();
+ } else if (curNode.getNextSibling() != null) {
+
+ curTraversal = SIBILING;
+ curNode = curNode.getNextSibling();
+ } else {
+ curTraversal = PARENT;
+ curNode = curNode.getParent();
+ }
+ }
+ }
+
+ /**
+ * Add resolvable leaves type info to resolution list.
+ *
+ * @param leavesHolder leaves holder node
+ */
+ private static void addResolvableLeavesToResolutionList(YangLeavesHolder leavesHolder) {
+ if (leavesHolder.getListOfLeaf() != null && !leavesHolder.getListOfLeaf().isEmpty()) {
+ for (YangLeaf leaf : leavesHolder.getListOfLeaf()) {
+ YangType type = leaf.getDataType();
+ if (type.getDataType() == DERIVED) {
+
+ type.setTypeForInterFileGroupingResolution(true);
+
+ // Add resolution information to the list
+ YangResolutionInfoImpl resolutionInfo =
+ new YangResolutionInfoImpl<>(type, (YangNode) leavesHolder,
+ type.getLineNumber(), type.getCharPosition());
+ try {
+ addResolutionInfo(resolutionInfo);
+ } catch (DataModelException e) {
+ throw new LinkerException("Failed to add leaf type info in grouping, to resolution ");
+ }
+ } else if (type.getDataType() == IDENTITYREF) {
+ YangIdentityRef identityRef = (YangIdentityRef) type.getDataTypeExtendedInfo();
+
+ identityRef.setIdentityForInterFileGroupingResolution(true);
+
+ // Add resolution information to the list
+ YangResolutionInfoImpl resolutionInfo =
+ new YangResolutionInfoImpl<YangIdentityRef>(identityRef, (YangNode) leavesHolder,
+ identityRef.getLineNumber(), identityRef.getCharPosition());
+ try {
+ addResolutionInfo(resolutionInfo);
+ } catch (DataModelException e) {
+ throw new LinkerException("Failed to add leaf identity ref info in grouping, to resolution ");
+ }
+ }
+ }
+ }
+
+ if (leavesHolder.getListOfLeafList() != null && !leavesHolder.getListOfLeafList().isEmpty()) {
+ for (YangLeafList leafList : leavesHolder.getListOfLeafList()) {
+ YangType type = leafList.getDataType();
+ if (type.getDataType() == DERIVED) {
+
+ type.setTypeForInterFileGroupingResolution(true);
+
+ // Add resolution information to the list
+ YangResolutionInfoImpl resolutionInfo =
+ new YangResolutionInfoImpl<YangType>(type, (YangNode) leavesHolder,
+ type.getLineNumber(), type.getCharPosition());
+ try {
+ addResolutionInfo(resolutionInfo);
+ } catch (DataModelException e) {
+ throw new LinkerException("Failed to add leaf type info in grouping, to resolution ");
+ }
+ } else if (type.getDataType() == IDENTITYREF) {
+ YangIdentityRef identityRef = (YangIdentityRef) type.getDataTypeExtendedInfo();
+
+ identityRef.setIdentityForInterFileGroupingResolution(true);
+ // Add resolution information to the list
+ YangResolutionInfoImpl resolutionInfo =
+ new YangResolutionInfoImpl<YangIdentityRef>(identityRef, (YangNode) leavesHolder,
+ identityRef.getLineNumber(), identityRef.getCharPosition());
+ try {
+ addResolutionInfo(resolutionInfo);
+ } catch (DataModelException e) {
+ throw new LinkerException("Failed to add leaf identity ref info in grouping, to resolution ");
+ }
+ }
+ }
+ }
+ }
+
+ /**
+ * Fills the path predicates of the leaf-ref with right axis node and
+ * left axis node, after linking the nodes.
+ *
+ * @param leafRef YANG leaf-ref
+ * @throws DataModelException if there is a data model error
+ */
+ public static void fillPathPredicates(YangLeafRef<?> leafRef)
+ throws DataModelException {
+
+ List<YangAtomicPath> atomics = leafRef.getAtomicPath();
+ if (atomics != null) {
+ for (YangAtomicPath atom : atomics) {
+ List<YangPathPredicate> predicates =
+ atom.getPathPredicatesList();
+
+ if (predicates != null) {
+ for (YangPathPredicate predicate : predicates) {
+ setLeftAxisNode(leafRef, atom, predicate);
+ setRightAxisNode(leafRef, predicate);
+ }
+ }
+ }
+ }
+ }
+
+ /**
+ * Sets the left axis node in the YANG path predicate after finding it
+ * under the YANG list node.
+ *
+ * @param leafRef YANG leaf-ref
+ * @param atom atomic path content
+ * @param predicate predicate in the atomic path
+ * @throws DataModelException if there is a data model error
+ */
+ private static void setLeftAxisNode(YangLeafRef<?> leafRef,
+ YangAtomicPath atom,
+ YangPathPredicate predicate)
+ throws DataModelException {
+ YangNode resolvedNode = atom.getResolvedNode();
+ if (!(resolvedNode instanceof YangList)) {
+ throw getDataModelExc(LEAF_REF_LIST_ERR, leafRef);
+ }
+
+ YangNodeIdentifier leftAxisName = predicate.getNodeId();
+ Object target = getTarget(leftAxisName, resolvedNode, leafRef);
+ predicate.setLeftAxisNode(target);
+ }
+
+ /**
+ * Returns the target leaf/leaf-list from the provided YANG node.
+ *
+ * @param leftAxisName name of node
+ * @param node node having target
+ * @param leafRef YANG leaf-ref
+ * @return target leaf/leaf-list
+ * @throws DataModelException if there is a data model error
+ */
+ private static Object getTarget(YangNodeIdentifier leftAxisName,
+ YangNode node, YangLeafRef leafRef)
+ throws DataModelException {
+
+ YangLeaf leaf = getLeaf(leftAxisName, (YangLeavesHolder) node);
+ if (leaf != null) {
+ return leaf;
+ }
+ YangLeafList leafList = getLeafList(leftAxisName,
+ (YangLeavesHolder) node);
+ if (leafList == null) {
+ throw getDataModelExc(TGT_LEAF_ERR, leafRef);
+ }
+ return leafList;
+ }
+
+ /**
+ * Returns the leaf by searching it in the node by the leaf name. Returns
+ * null when the name doesn't match.
+ *
+ * @param name leaf name
+ * @param holder holder of leaf
+ * @return YANG leaf
+ */
+ private static YangLeaf getLeaf(YangNodeIdentifier name,
+ YangLeavesHolder holder) {
+
+ List<YangLeaf> listOfLeaf = holder.getListOfLeaf();
+ if (listOfLeaf != null) {
+ for (YangLeaf yangLeaf : listOfLeaf) {
+ if (yangLeaf.getName().equals(name.getName())) {
+ return yangLeaf;
+ }
+ }
+ }
+ return null;
+ }
+
+ /**
+ * Returns the leaf-list by searching it in the node by the leaf-list name.
+ * Returns null when the name doesn't match.
+ *
+ * @param name leaf-list name
+ * @param holder holder of leaf-list
+ * @return YANG leaf-list
+ */
+ private static YangLeafList getLeafList(YangNodeIdentifier name,
+ YangLeavesHolder holder) {
+
+ List<YangLeafList> listOfLeafList = holder.getListOfLeafList();
+ if (listOfLeafList != null) {
+ for (YangLeafList yangLeafList : listOfLeafList) {
+ if (yangLeafList.getName().equals(name.getName())) {
+ return yangLeafList;
+ }
+ }
+ }
+ return null;
+ }
+
+ /**
+ * Returns the root node from which the path with the atomic node names
+ * has to be traversed through. With the ancestor count the nodes are
+ * moved upward.
+ *
+ * @param count ancestor count
+ * @param node current leaf-ref parent
+ * @param leafRef YANG leaf-ref
+ * @return root node from ancestor count
+ * @throws DataModelException if there is a data model error
+ */
+ private static YangNode getRootNode(int count, YangNode node,
+ YangLeafRef leafRef)
+ throws DataModelException {
+
+ YangNode curParent = node;
+ int curCount = 0;
+ while (curCount < count) {
+ curCount = curCount + 1;
+ if (curCount != 1) {
+ if (curParent.getParent() == null) {
+ throw getDataModelExc(INVALID_TREE, leafRef);
+ }
+ curParent = curParent.getParent();
+ }
+ curParent = skipInvalidDataNodes(curParent, leafRef);
+ if (curParent instanceof YangAugment) {
+ YangAugment augment = (YangAugment) curParent;
+ curParent = augment.getAugmentedNode();
+ curCount = curCount + 1;
+ }
+ }
+ return curParent;
+ }
+
+ /**
+ * Returns the last node by traversing through the atomic node id by
+ * leaving the last target leaf/leaf-list.
+ *
+ * @param curNode current node
+ * @param relPath relative path
+ * @param leafRef YANG leaf-ref
+ * @return last YANG node
+ * @throws DataModelException if there is a data model error
+ */
+ private static Object getLastNode(YangNode curNode,
+ YangRelativePath relPath,
+ YangLeafRef leafRef)
+ throws DataModelException {
+
+ YangNode node = curNode;
+ List<YangAtomicPath> atomics = new ArrayList<>();
+ atomics.addAll(relPath.getAtomicPathList());
+
+ if (atomics.isEmpty()) {
+ throw getDataModelExc(EMPTY_PATH_LIST_ERR, leafRef);
+ }
+
+ YangAtomicPath pathTgt = atomics.get(atomics.size() - 1);
+ if (atomics.size() == 1) {
+ return getTarget(pathTgt.getNodeIdentifier(), node, leafRef);
+ }
+
+ atomics.remove(atomics.size() - 1);
+ for (YangAtomicPath atomicPath : atomics) {
+ node = getNode(node.getChild(), atomicPath.getNodeIdentifier());
+ if (node == null) {
+ throw getDataModelExc(INVALID_PATH_PRE, leafRef);
+ }
+ }
+ return getTarget(pathTgt.getNodeIdentifier(), node, leafRef);
+ }
+
+ /**
+ * Returns the node from the parent node by matching it with the atomic
+ * name. If no child node matches the name then it returns null.
+ *
+ * @param curNode current node
+ * @param identifier atomic name
+ * @return node to be traversed
+ */
+ private static YangNode getNode(YangNode curNode,
+ YangNodeIdentifier identifier) {
+ YangNode node = curNode;
+ while (node != null) {
+ if (node.getName().equals(identifier.getName())) {
+ return node;
+ }
+ node = node.getNextSibling();
+ }
+ return null;
+ }
+
+ /**
+ * Sets the right axis node in the YANG path predicate after finding it
+ * from the relative path.
+ *
+ * @param leafRef YANG leaf-ref
+ * @param predicate YANG path predicate
+ * @throws DataModelException if there is a data model error
+ */
+ private static void setRightAxisNode(YangLeafRef leafRef,
+ YangPathPredicate predicate)
+ throws DataModelException {
+
+ YangNode parentNode = leafRef.getParentNode();
+ YangRelativePath relPath = predicate.getRelPath();
+ int ancestor = relPath.getAncestorNodeCount();
+
+ YangNode rootNode = getRootNode(ancestor, parentNode, leafRef);
+ Object target = getLastNode(rootNode, relPath, leafRef);
+ if (target == null) {
+ throw getDataModelExc(INVALID_PATH_PRE, leafRef);
+ }
+ predicate.setRightAxisNode(target);
+ }
+
+ /**
+ * Returns data model error messages for leaf-ref with the path.
+ *
+ * @param msg error message
+ * @param leafRef YANG leaf-ref
+ * @return data model exception
+ */
+ private static DataModelException getDataModelExc(String msg,
+ YangLeafRef leafRef) {
+ DataModelException exc = new DataModelException(
+ msg + leafRef.getPath());
+ exc.setCharPosition(leafRef.getCharPosition());
+ exc.setLine(leafRef.getLineNumber());
+ return exc;
+ }
+}
diff --git a/compiler/base/linker/src/main/java/org/onosproject/yang/compiler/linker/impl/YangResolutionInfoImpl.java b/compiler/base/linker/src/main/java/org/onosproject/yang/compiler/linker/impl/YangResolutionInfoImpl.java
new file mode 100644
index 0000000..3c1542c
--- /dev/null
+++ b/compiler/base/linker/src/main/java/org/onosproject/yang/compiler/linker/impl/YangResolutionInfoImpl.java
@@ -0,0 +1,1623 @@
+/*
+ * 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.yang.compiler.linker.impl;
+
+import org.onosproject.yang.compiler.datamodel.DefaultLocationInfo;
+import org.onosproject.yang.compiler.datamodel.Resolvable;
+import org.onosproject.yang.compiler.datamodel.RpcNotificationContainer;
+import org.onosproject.yang.compiler.datamodel.TraversalType;
+import org.onosproject.yang.compiler.datamodel.YangAtomicPath;
+import org.onosproject.yang.compiler.datamodel.YangAugment;
+import org.onosproject.yang.compiler.datamodel.YangAugmentableNode;
+import org.onosproject.yang.compiler.datamodel.YangBase;
+import org.onosproject.yang.compiler.datamodel.YangCompilerAnnotation;
+import org.onosproject.yang.compiler.datamodel.YangDerivedInfo;
+import org.onosproject.yang.compiler.datamodel.YangEntityToResolveInfoImpl;
+import org.onosproject.yang.compiler.datamodel.YangFeature;
+import org.onosproject.yang.compiler.datamodel.YangFeatureHolder;
+import org.onosproject.yang.compiler.datamodel.YangGrouping;
+import org.onosproject.yang.compiler.datamodel.YangIdentity;
+import org.onosproject.yang.compiler.datamodel.YangIdentityRef;
+import org.onosproject.yang.compiler.datamodel.YangIfFeature;
+import org.onosproject.yang.compiler.datamodel.YangImport;
+import org.onosproject.yang.compiler.datamodel.YangInclude;
+import org.onosproject.yang.compiler.datamodel.YangInput;
+import org.onosproject.yang.compiler.datamodel.YangLeaf;
+import org.onosproject.yang.compiler.datamodel.YangLeafList;
+import org.onosproject.yang.compiler.datamodel.YangLeafRef;
+import org.onosproject.yang.compiler.datamodel.YangList;
+import org.onosproject.yang.compiler.datamodel.YangNode;
+import org.onosproject.yang.compiler.datamodel.YangNodeIdentifier;
+import org.onosproject.yang.compiler.datamodel.YangReferenceResolver;
+import org.onosproject.yang.compiler.datamodel.YangRelativePath;
+import org.onosproject.yang.compiler.datamodel.YangResolutionInfo;
+import org.onosproject.yang.compiler.datamodel.YangType;
+import org.onosproject.yang.compiler.datamodel.YangTypeDef;
+import org.onosproject.yang.compiler.datamodel.YangUses;
+import org.onosproject.yang.compiler.datamodel.YangXPathResolver;
+import org.onosproject.yang.compiler.datamodel.exceptions.DataModelException;
+import org.onosproject.yang.compiler.datamodel.utils.ResolvableStatus;
+import org.onosproject.yang.compiler.datamodel.utils.builtindatatype.YangDataTypes;
+import org.onosproject.yang.compiler.linker.exceptions.LinkerException;
+
+import java.io.Serializable;
+import java.util.Iterator;
+import java.util.LinkedList;
+import java.util.List;
+import java.util.Stack;
+
+import static org.onosproject.yang.compiler.datamodel.ResolvableType.YANG_LEAFREF;
+import static org.onosproject.yang.compiler.datamodel.TraversalType.CHILD;
+import static org.onosproject.yang.compiler.datamodel.TraversalType.PARENT;
+import static org.onosproject.yang.compiler.datamodel.TraversalType.ROOT;
+import static org.onosproject.yang.compiler.datamodel.TraversalType.SIBILING;
+import static org.onosproject.yang.compiler.datamodel.YangPathArgType.ABSOLUTE_PATH;
+import static org.onosproject.yang.compiler.datamodel.YangPathArgType.RELATIVE_PATH;
+import static org.onosproject.yang.compiler.datamodel.exceptions.ErrorMessages.getErrorMsg;
+import static org.onosproject.yang.compiler.datamodel.utils.DataModelUtils.addResolutionInfo;
+import static org.onosproject.yang.compiler.datamodel.utils.ResolvableStatus.INTER_FILE_LINKED;
+import static org.onosproject.yang.compiler.datamodel.utils.ResolvableStatus.INTRA_FILE_RESOLVED;
+import static org.onosproject.yang.compiler.datamodel.utils.ResolvableStatus.LINKED;
+import static org.onosproject.yang.compiler.datamodel.utils.ResolvableStatus.RESOLVED;
+import static org.onosproject.yang.compiler.datamodel.utils.ResolvableStatus.UNDEFINED;
+import static org.onosproject.yang.compiler.datamodel.utils.ResolvableStatus.UNRESOLVED;
+import static org.onosproject.yang.compiler.datamodel.utils.YangConstructType.PATH_DATA;
+import static org.onosproject.yang.compiler.linker.impl.XpathLinkingTypes.AUGMENT_LINKING;
+import static org.onosproject.yang.compiler.linker.impl.XpathLinkingTypes.LEAF_REF_LINKING;
+import static org.onosproject.yang.compiler.linker.impl.YangLinkerUtils.detectCollisionForAugmentedNode;
+import static org.onosproject.yang.compiler.linker.impl.YangLinkerUtils.fillPathPredicates;
+import static org.onosproject.yang.compiler.linker.impl.YangLinkerUtils.getErrorInfoForLinker;
+import static org.onosproject.yang.compiler.linker.impl.YangLinkerUtils.getLeafRefErrorInfo;
+import static org.onosproject.yang.compiler.linker.impl.YangLinkerUtils.getPathWithAugment;
+import static org.onosproject.yang.compiler.linker.impl.YangLinkerUtils.getValidNodeIdentifier;
+import static org.onosproject.yang.compiler.linker.impl.YangLinkerUtils.skipInvalidDataNodes;
+import static org.onosproject.yang.compiler.utils.UtilConstants.EMPTY_STRING;
+import static org.onosproject.yang.compiler.utils.UtilConstants.FAILED_TO_FIND_ANNOTATION;
+import static org.onosproject.yang.compiler.utils.UtilConstants.FAILED_TO_FIND_LEAD_INFO_HOLDER;
+import static org.onosproject.yang.compiler.utils.UtilConstants.FAILED_TO_LINK;
+import static org.onosproject.yang.compiler.utils.UtilConstants.INVALID_ENTITY;
+import static org.onosproject.yang.compiler.utils.UtilConstants.INVALID_LINKER_STATE;
+import static org.onosproject.yang.compiler.utils.UtilConstants.INVALID_RESOLVED_ENTITY;
+import static org.onosproject.yang.compiler.utils.UtilConstants.INVALID_TARGET;
+import static org.onosproject.yang.compiler.utils.UtilConstants.INVALID_TREE;
+import static org.onosproject.yang.compiler.utils.UtilConstants.LEAFREF;
+import static org.onosproject.yang.compiler.utils.UtilConstants.LINKER_ERROR;
+import static org.onosproject.yang.compiler.utils.UtilConstants.SLASH_FOR_STRING;
+import static org.onosproject.yang.compiler.utils.UtilConstants.UNRESOLVABLE;
+
+/**
+ * Represents implementation of resolution object which will be resolved by
+ * linker.
+ *
+ * @param <T> type of resolution entity uses / type
+ */
+public class YangResolutionInfoImpl<T> extends DefaultLocationInfo
+ implements YangResolutionInfo<T>, Serializable {
+
+ private static final long serialVersionUID = 806201658L;
+
+ /**
+ * Information about the entity that needs to be resolved.
+ */
+ private YangEntityToResolveInfoImpl<T> entityToResolveInfo;
+
+ /**
+ * Current module/sub-module reference, will be used in inter-file/
+ * inter-jar scenario to get the import/include list.
+ */
+ private YangReferenceResolver curRefResolver;
+
+ /**
+ * Stack for type/uses is maintained for hierarchical references, this is
+ * used during resolution.
+ */
+ private Stack<YangEntityToResolveInfoImpl<T>> partialResolvedStack;
+
+ /**
+ * It is private to ensure the overloaded method be invoked to create an
+ * object.
+ */
+ @SuppressWarnings("unused")
+ private YangResolutionInfoImpl() {
+ }
+
+ /**
+ * Creates a resolution information object with all the inputs.
+ *
+ * @param dataNode current parsable data node
+ * @param holderNode parent YANG node
+ * @param lineNumber error line number
+ * @param charPositionInLine error character position in line
+ */
+ public YangResolutionInfoImpl(T dataNode, YangNode holderNode, int lineNumber,
+ int charPositionInLine) {
+ entityToResolveInfo = new YangEntityToResolveInfoImpl<>();
+ entityToResolveInfo.setEntityToResolve(dataNode);
+ entityToResolveInfo.setHolderOfEntityToResolve(holderNode);
+ setLineNumber(lineNumber);
+ setCharPosition(charPositionInLine);
+ partialResolvedStack = new Stack<>();
+ }
+
+ @Override
+ public void resolveLinkingForResolutionInfo(YangReferenceResolver dataModelRootNode)
+ throws DataModelException {
+
+ curRefResolver = dataModelRootNode;
+ /*
+ * Current node to resolve, it can be a YANG type, YANG uses or YANG if-feature or
+ * YANG leafref or YANG base or YANG identityref.
+ */
+ T entityToResolve = entityToResolveInfo.getEntityToResolve();
+
+ // Check if linking is already done
+ if (entityToResolve instanceof Resolvable) {
+ Resolvable resolvable = (Resolvable) entityToResolve;
+ if (resolvable.getResolvableStatus() == RESOLVED) {
+ /*
+ * entity is already resolved, so nothing to do
+ */
+ return;
+ }
+ } else {
+ throw new DataModelException(LINKER_ERROR);
+ }
+ // Push the initial entity to resolve in stack.
+ addInPartialResolvedStack(entityToResolveInfo);
+ linkAndResolvePartialResolvedStack();
+ addDerivedRefTypeToRefTypeResolutionList();
+ }
+
+ /**
+ * Resolves linking with ancestors.
+ *
+ * @throws DataModelException a violation of data model rules
+ */
+ private void linkAndResolvePartialResolvedStack()
+ throws DataModelException {
+
+ while (!partialResolvedStack.isEmpty()) {
+ /*
+ * Current node to resolve, it can be a YANG type or YANG uses or
+ * YANG if-feature or YANG leafref or YANG base or YANG identityref.
+ */
+ T entityToResolve = getCurEntityToResolveFromStack();
+ if (!(entityToResolve instanceof Resolvable)) {
+ throw new DataModelException(LINKER_ERROR);
+ }
+ // Check if linking is already done
+ Resolvable resolvable = (Resolvable) entityToResolve;
+ switch (resolvable.getResolvableStatus()) {
+ case RESOLVED:
+ /*
+ * If the entity is already resolved in the stack, then pop
+ * it and continue with the remaining stack elements to
+ * resolve
+ */
+ partialResolvedStack.pop();
+ break;
+
+ case LINKED:
+ /*
+ * If the top of the stack is already linked then resolve
+ * the references and pop the entity and continue with
+ * remaining stack elements to resolve.
+ */
+ resolveTopOfStack();
+ partialResolvedStack.pop();
+ break;
+
+ case INTRA_FILE_RESOLVED:
+ /*
+ * Pop the top of the stack.
+ */
+ partialResolvedStack.pop();
+ break;
+
+ case UNRESOLVED:
+ linkTopOfStackReferenceUpdateStack();
+
+ if (resolvable.getResolvableStatus() == UNRESOLVED) {
+ // If current entity is still not resolved, then
+ // linking/resolution has failed.
+ DataModelException ex =
+ new DataModelException
+ (getErrorInfoForLinker(resolvable));
+ ex.setLine(getLineNumber());
+ ex.setCharPosition(getCharPosition());
+ throw ex;
+ }
+ break;
+
+ default:
+ throw new DataModelException(INVALID_LINKER_STATE);
+ }
+ }
+ }
+
+ /**
+ * Adds leaf-ref to the resolution list, with different context if
+ * leaf-ref is defined under derived type. Leaf-ref must be resolved from
+ * where the typedef is referenced.
+ */
+ private void addDerivedRefTypeToRefTypeResolutionList()
+ throws DataModelException {
+
+ YangNode refNode = entityToResolveInfo.getHolderOfEntityToResolve();
+ YangDerivedInfo info = getValidResolvableType();
+
+ if (info == null) {
+ return;
+ }
+
+ YangType<T> type =
+ (YangType<T>) entityToResolveInfo.getEntityToResolve();
+
+ T extType = (T) info.getReferredTypeDef().getTypeDefBaseType()
+ .getDataTypeExtendedInfo();
+
+ while (extType instanceof YangDerivedInfo) {
+ info = (YangDerivedInfo) extType;
+ extType = (T) info.getReferredTypeDef().getTypeDefBaseType()
+ .getDataTypeExtendedInfo();
+ }
+ /*
+ * Backup the leaf-ref info from derived type and deletes the derived
+ * type info. Copies the backed up leaf-ref data to the actual type in
+ * replacement of derived type. Adds to the resolution list in this
+ * context.
+ */
+ addRefTypeInfo(extType, type, refNode);
+ }
+
+ /**
+ * Returns the derived info if the holder is typedef, the entity is type
+ * and the effective type is leaf-ref; null otherwise.
+ *
+ * @return derived info
+ */
+ private YangDerivedInfo<?> getValidResolvableType() {
+
+ YangNode refNode = entityToResolveInfo.getHolderOfEntityToResolve();
+ T entity = entityToResolveInfo.getEntityToResolve();
+
+ if (!(refNode instanceof YangTypeDef) && entity instanceof YangType) {
+ YangType<?> type = (YangType) entity;
+ YangDerivedInfo<?> info =
+ (YangDerivedInfo) type.getDataTypeExtendedInfo();
+ YangDataTypes dataType = info.getEffectiveBuiltInType();
+ if ((type.getResolvableStatus() == RESOLVED) &&
+ (dataType == YangDataTypes.LEAFREF)) {
+ return info;
+ }
+ }
+ return null;
+ }
+
+ /**
+ * Adds resolvable type (leaf-ref) info to resolution list.
+ *
+ * @param extType resolvable type
+ * @param type YANG type
+ * @param holder holder node
+ * @throws DataModelException if there is a data model error
+ */
+ private void addRefTypeInfo(T extType, YangType<T> type, YangNode holder)
+ throws DataModelException {
+
+ type.resetYangType();
+ type.setResolvableStatus(RESOLVED);
+ type.setDataType(YangDataTypes.LEAFREF);
+ type.setDataTypeName(LEAFREF);
+ type.setDataTypeExtendedInfo(extType);
+
+ YangLeafRef leafRef = (YangLeafRef) extType;
+ (leafRef).setResolvableStatus(UNRESOLVED);
+ leafRef.setParentNode(holder);
+
+ YangResolutionInfoImpl info = new YangResolutionInfoImpl<>(
+ leafRef, holder, getLineNumber(), getCharPosition());
+ curRefResolver.addToResolutionList(info, YANG_LEAFREF);
+ curRefResolver.resolveSelfFileLinking(YANG_LEAFREF);
+ }
+
+ /**
+ * Resolves the current entity in the stack.
+ */
+ private void resolveTopOfStack()
+ throws DataModelException {
+ T entity = getCurEntityToResolveFromStack();
+ List<T> entityToResolve = (List<T>) ((Resolvable) entity).resolve();
+ if (entityToResolve != null && !entityToResolve.isEmpty()) {
+ for (T anEntityToResolve : entityToResolve) {
+ addUnresolvedEntitiesToResolutionList(anEntityToResolve);
+ }
+ }
+ if (((Resolvable) entity).getResolvableStatus() != INTRA_FILE_RESOLVED &&
+ ((Resolvable) entity).getResolvableStatus() != UNDEFINED) {
+ // Sets the resolution status in inside the type/uses/if-feature/leafref.
+ ((Resolvable) entity).setResolvableStatus(RESOLVED);
+ }
+ }
+
+ /**
+ * Adds the unresolved entities to the resolution list.
+ *
+ * @param entityToResolve entity to resolve
+ * @throws DataModelException a violation of data model rules
+ */
+ private void addUnresolvedEntitiesToResolutionList(T entityToResolve)
+ throws DataModelException {
+ if (entityToResolve instanceof YangEntityToResolveInfoImpl) {
+ YangEntityToResolveInfoImpl entityToResolveInfo
+ = (YangEntityToResolveInfoImpl) entityToResolve;
+ if (entityToResolveInfo.getEntityToResolve() instanceof YangLeafRef) {
+ YangLeafRef leafref = (YangLeafRef) entityToResolveInfo
+ .getEntityToResolve();
+ YangNode parentNodeOfLeafref = entityToResolveInfo
+ .getHolderOfEntityToResolve();
+ leafref.setParentNode(parentNodeOfLeafref);
+ if (leafref.getResolvableStatus() == UNRESOLVED) {
+ leafref.setResolvableStatus(INTRA_FILE_RESOLVED);
+ }
+ }
+
+ // Add resolution information to the list.
+ YangResolutionInfoImpl resolutionInfoImpl = new YangResolutionInfoImpl<>(
+ entityToResolveInfo.getEntityToResolve(),
+ entityToResolveInfo.getHolderOfEntityToResolve(),
+ entityToResolveInfo.getLineNumber(),
+ entityToResolveInfo.getCharPosition());
+ addResolutionInfo(resolutionInfoImpl);
+ }
+ }
+
+ /**
+ * Resolves linking for a node child and siblings.
+ *
+ * @throws DataModelException data model error
+ */
+ private void linkTopOfStackReferenceUpdateStack()
+ throws DataModelException {
+ T entity = getCurEntityToResolveFromStack();
+ if (entity instanceof YangLeafRef) {
+ ((Resolvable) entity).setResolvableStatus(INTRA_FILE_RESOLVED);
+ return;
+ }
+ /*
+ * Check if self file reference is there, this will not check for the
+ * scenario when prefix is not present and type/uses is present in
+ * sub-module from include list.
+ */
+ if (!isCandidateForSelfFileReference()) {
+ ((Resolvable) entity).setResolvableStatus(INTRA_FILE_RESOLVED);
+ return;
+ }
+
+ /*
+ * Try to resolve the top of the stack and update partial resolved stack
+ * if there is recursive references
+ */
+ YangNode ancestorRefNode = partialResolvedStack.peek()
+ .getHolderOfEntityToResolve();
+
+ if (entity instanceof YangIfFeature) {
+ resolveSelfFileLinkingForIfFeature(ancestorRefNode);
+ return;
+ }
+ if (entity instanceof YangIdentityRef || entity instanceof YangBase) {
+ resolveSelfFileLinkingForBaseAndIdentityref();
+ return;
+ }
+ YangType type = null;
+ if (entity instanceof YangType) {
+ type = (YangType) entity;
+ }
+ /*
+ * Traverse up in the ancestor tree to check if the referred node is
+ * defined
+ */
+ while (ancestorRefNode != null) {
+ /*
+ * Check for the referred node defined in a ancestor scope
+ */
+ YangNode curRefNode = ancestorRefNode.getChild();
+ if (isReferredNodeInSiblingListProcessed(curRefNode)) {
+ return;
+ }
+ ancestorRefNode = ancestorRefNode.getParent();
+ if (type != null && ancestorRefNode != null) {
+ if (ancestorRefNode.getParent() == null) {
+ type.setTypeNotResolvedTillRootNode(true);
+ }
+ }
+ }
+
+ /*
+ * In case prefix is not present or it's self prefix it's a candidate for inter-file
+ * resolution via include list.
+ */
+ if (getRefPrefix() == null ||
+ getRefPrefix().contentEquals(curRefResolver.getPrefix())) {
+ ((Resolvable) entity).setResolvableStatus(INTRA_FILE_RESOLVED);
+ }
+ }
+
+ /**
+ * Resolves self file linking for base/identityref.
+ *
+ * @throws DataModelException a violation of data model rules
+ */
+ private void resolveSelfFileLinkingForBaseAndIdentityref()
+ throws DataModelException {
+
+ boolean refIdentity = false;
+ String nodeName = null;
+ T entity = getCurEntityToResolveFromStack();
+ if (entity instanceof YangIdentityRef) {
+ nodeName = ((YangIdentityRef) entity).getName();
+ } else if (entity instanceof YangBase) {
+ nodeName = ((YangBase) entity).getBaseIdentifier().getName();
+ }
+ if (curRefResolver instanceof RpcNotificationContainer) {
+ // Sends list of nodes for finding the target identity.
+ refIdentity = isIdentityReferenceFound(nodeName, (YangNode) curRefResolver);
+ }
+ if (refIdentity) {
+ return;
+ }
+
+ /*
+ * In case prefix is not present or it's self prefix it's a candidate for inter-file
+ * resolution via include list.
+ */
+ if (getRefPrefix() == null || getRefPrefix()
+ .contentEquals(curRefResolver.getPrefix())) {
+ ((Resolvable) entity).setResolvableStatus(INTRA_FILE_RESOLVED);
+ }
+ }
+
+ /**
+ * Resolves self file linking for if-feature.
+ *
+ * @param ancestorRefNode if-feature holder node
+ * @throws DataModelException DataModelException a violation of data model
+ * rules
+ */
+ private void resolveSelfFileLinkingForIfFeature(YangNode ancestorRefNode)
+ throws DataModelException {
+
+ YangFeatureHolder featureHolder = getFeatureHolder(ancestorRefNode);
+ YangNode curRefNode = (YangNode) featureHolder;
+ if (isReferredNode(curRefNode)) {
+
+ // Adds reference link of entity to the node under resolution.
+ addReferredEntityLink(curRefNode, LINKED);
+
+ /*
+ * resolve the reference and update the partial resolution stack
+ * with any further recursive references
+ */
+ addUnresolvedRecursiveReferenceToStack(curRefNode);
+ return;
+ }
+
+ /*
+ * In case prefix is not present or it's self prefix it's a candidate for inter-file
+ * resolution via include list.
+ */
+ if (getRefPrefix() == null || getRefPrefix()
+ .contentEquals(curRefResolver.getPrefix())) {
+ ((Resolvable) getCurEntityToResolveFromStack())
+ .setResolvableStatus(INTRA_FILE_RESOLVED);
+ }
+ }
+
+ /**
+ * Returns the status of the referred identity found for base/identityref.
+ *
+ * @param nodeName the name of the base node
+ * identifier/identityref node identifier
+ * @param ancestorRefNode the parent node of base/identityref
+ * @return status of referred base/identityref
+ * @throws DataModelException a violation of data model rules
+ */
+ private boolean isIdentityReferenceFound(String nodeName, YangNode ancestorRefNode)
+ throws DataModelException {
+
+ // When child is not present return.
+ if (ancestorRefNode.getChild() == null) {
+ return false;
+ }
+
+ ancestorRefNode = ancestorRefNode.getChild();
+
+ // Checks all the siblings under the node and returns the matched node.
+ YangNode nodeFound = isReferredNodeInSiblingProcessedForIdentity(ancestorRefNode,
+ nodeName);
+
+ if (nodeFound != null) {
+ // Adds reference link of entity to the node under resolution.
+ addReferredEntityLink(nodeFound, LINKED);
+
+ /*
+ * resolve the reference and update the partial resolution stack with any further recursive references
+ */
+ addUnresolvedRecursiveReferenceToStack(nodeFound);
+ return true;
+ }
+
+ return false;
+ }
+
+ /**
+ * Adds the unresolved constructs to stack which has to be resolved for leafref.
+ *
+ * @param leavesInfo YANG leaf or leaf list which holds the type
+ * @param ancestorRefNode holder of the YANG leaf or leaf list
+ */
+ private void addUnResolvedLeafRefTypeToStack(T leavesInfo, YangNode ancestorRefNode) {
+
+ YangType refType;
+ T extendedInfo;
+ if (leavesInfo instanceof YangLeaf) {
+ YangLeaf leaf = (YangLeaf) leavesInfo;
+ refType = leaf.getDataType();
+ } else {
+ YangLeafList leafList = (YangLeafList) leavesInfo;
+ refType = leafList.getDataType();
+ }
+ extendedInfo = (T) refType.getDataTypeExtendedInfo();
+ addUnResolvedTypeDataToStack(refType, ancestorRefNode, extendedInfo);
+ }
+
+ //Adds unresolved type info to stack.
+ private void addUnResolvedTypeDataToStack(YangType refType, YangNode
+ ancestorRefNode, T extendedInfo) {
+ YangEntityToResolveInfoImpl<YangLeafRef<?>> unResolvedLeafRef =
+ new YangEntityToResolveInfoImpl<>();
+ YangEntityToResolveInfoImpl<YangType<?>> unResolvedTypeDef =
+ new YangEntityToResolveInfoImpl<>();
+ if (refType.getDataType() == YangDataTypes.LEAFREF) {
+ unResolvedLeafRef.setEntityToResolve((YangLeafRef<?>) extendedInfo);
+ unResolvedLeafRef.setHolderOfEntityToResolve(ancestorRefNode);
+ addInPartialResolvedStack((YangEntityToResolveInfoImpl<T>) unResolvedLeafRef);
+ } else if (refType.getDataType() == YangDataTypes.DERIVED) {
+ unResolvedTypeDef.setEntityToResolve(refType);
+ unResolvedTypeDef.setHolderOfEntityToResolve(ancestorRefNode);
+ addInPartialResolvedStack((YangEntityToResolveInfoImpl<T>) unResolvedTypeDef);
+ }
+ }
+
+ /**
+ * Returns feature holder(module/sub-module node) .
+ *
+ * @param ancestorRefNode if-feature holder node
+ */
+ private YangFeatureHolder getFeatureHolder(YangNode ancestorRefNode) {
+ while (ancestorRefNode != null) {
+ if (ancestorRefNode instanceof YangFeatureHolder) {
+ return (YangFeatureHolder) ancestorRefNode;
+ }
+ ancestorRefNode = ancestorRefNode.getParent();
+ }
+ return null;
+ }
+
+ /**
+ * Checks if the reference in self file or in external file.
+ *
+ * @return true if self file reference, false otherwise
+ * @throws DataModelException a violation of data model rules
+ */
+ private boolean isCandidateForSelfFileReference()
+ throws DataModelException {
+ String prefix = getRefPrefix();
+ return prefix == null || prefix.contentEquals(curRefResolver.getPrefix());
+ }
+
+ /**
+ * Checks for the referred parent node for the base/identity.
+ *
+ * @param refNode potential referred node
+ * @return the referred parent node of base/identity.
+ * @throws DataModelException data model errors
+ */
+ private YangNode isReferredNodeInSiblingProcessedForIdentity(YangNode refNode,
+ String refName)
+ throws DataModelException {
+
+ while (refNode != null) {
+ if (refNode instanceof YangIdentity) {
+ // Check if the potential referred node is the actual referred node
+ if (isReferredNodeForIdentity(refNode, refName)) {
+ return refNode;
+ }
+ }
+ refNode = refNode.getNextSibling();
+ }
+ return null;
+ }
+
+ /**
+ * Checks if the current reference node name and the name in the base/identityref base are equal.
+ *
+ * @param curRefNode the node where the reference is pointed
+ * @param name name of the base in the base/identityref base
+ * @return status of the match between the name
+ * @throws DataModelException a violation of data model rules
+ */
+ private boolean isReferredNodeForIdentity(YangNode curRefNode, String name)
+ throws DataModelException {
+ T entity = getCurEntityToResolveFromStack();
+ if (entity instanceof YangIdentityRef || entity instanceof YangBase) {
+
+ //Check if name of node name matches with the current reference node.
+ return curRefNode.getName().contentEquals(name);
+ } else {
+ throw new DataModelException(getErrorMsg(
+ INVALID_ENTITY, curRefNode.getName(), curRefNode.getLineNumber(),
+ curRefNode.getCharPosition(), curRefNode.getFileName()));
+ }
+ }
+
+ /**
+ * Checks for the referred node defined in a ancestor scope.
+ *
+ * @param refNode potential referred node
+ * @return status of resolution and updating the partial resolved stack with
+ * the any recursive references
+ * @throws DataModelException a violation of data model rules
+ */
+ private boolean isReferredNodeInSiblingListProcessed(YangNode refNode)
+ throws DataModelException {
+ while (refNode != null) {
+
+ // Check if the potential referred node is the actual referred node
+ if (isReferredNode(refNode)) {
+
+ // Adds reference link of entity to the node under resolution.
+ addReferredEntityLink(refNode, LINKED);
+
+ /*
+ * resolve the reference and update the partial resolution stack
+ * with any further recursive references
+ */
+ addUnresolvedRecursiveReferenceToStack(refNode);
+
+ /*
+ * return true, since the reference is linked and any recursive
+ * unresolved references is added to the stack
+ */
+ return true;
+ }
+
+ refNode = refNode.getNextSibling();
+ }
+ return false;
+ }
+
+ /**
+ * Checks if the potential referred node is the actual referred node.
+ *
+ * @param refNode typedef/grouping node
+ * @return true if node is of resolve type otherwise false
+ * @throws DataModelException a violation of data model rules
+ */
+ private boolean isReferredNode(YangNode refNode)
+ throws DataModelException {
+ T entity = getCurEntityToResolveFromStack();
+ if (entity instanceof YangType) {
+ if (refNode instanceof YangTypeDef) {
+ return isNodeNameSameAsResolutionInfoName(refNode);
+ }
+ } else if (entity instanceof YangUses) {
+ if (refNode instanceof YangGrouping) {
+ return isNodeNameSameAsResolutionInfoName(refNode);
+ }
+ } else if (entity instanceof YangIfFeature) {
+ if (refNode instanceof YangFeatureHolder) {
+ return isNodeNameSameAsResolutionInfoName(refNode);
+ }
+ } else if (entity instanceof YangBase || entity instanceof YangIdentityRef) {
+ if (refNode instanceof YangIdentity) {
+ return isNodeNameSameAsResolutionInfoName(refNode);
+ }
+ } else {
+ throw new DataModelException(getErrorMsg(
+ LINKER_ERROR, refNode.getName(), refNode.getLineNumber(),
+ refNode.getCharPosition(), refNode.getFileName()));
+ }
+ return false;
+ }
+
+ /**
+ * Checks 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 {
+ T entity = getCurEntityToResolveFromStack();
+ if (entity instanceof YangType) {
+ return node.getName().contentEquals(((YangType<?>) entity)
+ .getDataTypeName());
+ }
+ if (entity instanceof YangUses) {
+ return node.getName().contentEquals(((YangUses) entity).getName());
+ }
+ if (entity instanceof YangIfFeature) {
+ return isFeatureDefinedInNode(node);
+ }
+ if (entity instanceof YangBase) {
+ return node.getName().contentEquals(((
+ YangBase) entity).getBaseIdentifier().getName());
+ }
+ if (entity instanceof YangIdentityRef) {
+ return node.getName().contentEquals(((YangIdentityRef) entity).getName());
+ }
+ throw new DataModelException(getErrorMsg(
+ INVALID_RESOLVED_ENTITY, node.getName(), node.getLineNumber(),
+ node.getCharPosition(), node.getFileName()));
+ }
+
+ private boolean isFeatureDefinedInNode(YangNode node) {
+ T entity = getCurEntityToResolveFromStack();
+ YangNodeIdentifier ifFeature = ((YangIfFeature) entity).getName();
+ List<YangFeature> featureList = ((YangFeatureHolder) node).getFeatureList();
+ if (featureList != null && !featureList.isEmpty()) {
+ Iterator<YangFeature> iterator = featureList.iterator();
+ while (iterator.hasNext()) {
+ YangFeature feature = iterator.next();
+ if (ifFeature.getName().equals(feature.getName())) {
+ ((YangIfFeature) entity).setReferredFeature(feature);
+ ((YangIfFeature) entity).setReferredFeatureHolder(node);
+ return true;
+ }
+ }
+ }
+ return false;
+ }
+
+ /**
+ * Adds reference of grouping/typedef in uses/type.
+ *
+ * @param refNode grouping/typedef node being referred
+ * @param linkedStatus linked status if success.
+ * @throws DataModelException a violation of data model rules
+ */
+ private void addReferredEntityLink(YangNode refNode, ResolvableStatus linkedStatus)
+ throws DataModelException {
+ T entity = getCurEntityToResolveFromStack();
+ if (entity instanceof YangType) {
+ YangDerivedInfo<?> derivedInfo = (YangDerivedInfo<?>) ((
+ YangType<?>) entity).getDataTypeExtendedInfo();
+ derivedInfo.setReferredTypeDef((YangTypeDef) refNode);
+ } else if (entity instanceof YangUses) {
+ ((YangUses) entity).setRefGroup((YangGrouping) refNode);
+ } else if (entity instanceof YangBase) {
+ ((YangBase) entity).setReferredIdentity((YangIdentity) refNode);
+ } else if (entity instanceof YangIdentityRef) {
+ ((YangIdentityRef) entity).setReferredIdentity((YangIdentity) refNode);
+ } else if (!(entity instanceof YangIfFeature) &&
+ !(entity instanceof YangLeafRef)) {
+ throw new DataModelException(getErrorMsg(
+ LINKER_ERROR, refNode.getName(), refNode.getLineNumber(),
+ refNode.getCharPosition(), refNode.getFileName()));
+ }
+ // Sets the resolution status in inside the type/uses.
+ ((Resolvable) entity).setResolvableStatus(linkedStatus);
+ }
+
+ /**
+ * Checks if type/grouping has further reference to typedef/ unresolved
+ * uses. Add it to the partial resolve stack and return the status of
+ * addition to stack.
+ *
+ * @param refNode grouping/typedef node
+ * @throws DataModelException a violation of data model rules
+ */
+ private void addUnresolvedRecursiveReferenceToStack(YangNode refNode)
+ throws DataModelException {
+ T entity = getCurEntityToResolveFromStack();
+ if (entity instanceof YangType) {
+
+ //Checks if typedef type is derived
+ if (((YangTypeDef) refNode).getTypeDefBaseType()
+ .getDataType() == YangDataTypes.DERIVED) {
+ addEntityToStack((T) ((YangTypeDef) refNode).getTypeDefBaseType(),
+ refNode);
+ }
+ } else if (entity instanceof YangUses) {
+ /*
+ * Search if the grouping has any un resolved uses child, if so
+ * return true, else return false.
+ */
+ addUnResolvedUsesToStack(refNode);
+ } else if (entity instanceof YangIfFeature) {
+ addUnResolvedIfFeatureToStack(refNode);
+ } else if (entity instanceof YangLeafRef) {
+ // do nothing , referred node is already set
+ throw new DataModelException(getErrorMsg(
+ INVALID_RESOLVED_ENTITY, refNode.getName(), refNode.getLineNumber(),
+ refNode.getCharPosition(), refNode.getFileName()));
+ } else if (entity instanceof YangBase || entity instanceof YangIdentityRef) {
+
+ //Search if the identity has any un resolved base, if so return true, else return false.
+ addUnResolvedBaseToStack(refNode);
+ } else {
+ throw new DataModelException(getErrorMsg(
+ LINKER_ERROR, refNode.getName(), refNode.getLineNumber(),
+ refNode.getCharPosition(), refNode.getFileName()));
+ }
+ }
+
+ /**
+ * Returns if there is any unresolved uses in grouping.
+ *
+ * @param node grouping/typedef node
+ */
+ private void addUnResolvedUsesToStack(YangNode node) {
+
+ //Search the grouping node's children for presence of uses node.
+ TraversalType curTraversal = ROOT;
+ YangNode curNode = node.getChild();
+ while (curNode != null) {
+ if (curNode.getName().equals(node.getName())) {
+ // if we have traversed all the child nodes, then exit from loop
+ return;
+ }
+
+ // if child nodes has uses, then add it to resolution stack
+ if (curNode instanceof YangUses) {
+ addEntityToStack((T) curNode, node);
+ }
+
+ // Traversing all the child nodes of grouping
+ if (curTraversal != PARENT && curNode.getChild() != null) {
+ curTraversal = CHILD;
+ curNode = curNode.getChild();
+ } else if (curNode.getNextSibling() != null) {
+ curTraversal = SIBILING;
+ curNode = curNode.getNextSibling();
+ } else {
+ curTraversal = PARENT;
+ curNode = curNode.getParent();
+ }
+ }
+ }
+
+ /**
+ * Returns if there is any unresolved if-feature in feature.
+ *
+ * @param node module/submodule node
+ */
+ private void addUnResolvedIfFeatureToStack(YangNode node) {
+ YangFeature refFeature = ((YangIfFeature) getCurEntityToResolveFromStack())
+ .getReferredFeature();
+ List<YangIfFeature> ifFeatureList = refFeature.getIfFeatureList();
+ if (ifFeatureList != null && !ifFeatureList.isEmpty()) {
+ Iterator<YangIfFeature> ifFeatureIterator = ifFeatureList.iterator();
+ while (ifFeatureIterator.hasNext()) {
+ addEntityToStack((T) ifFeatureIterator.next(), node);
+ }
+ }
+ }
+
+ /**
+ * Returns if there is any unresolved base in identity.
+ *
+ * @param node module/submodule node
+ */
+ private void addUnResolvedBaseToStack(YangNode node) {
+
+ YangIdentity curNode = (YangIdentity) node;
+ if (curNode.getBaseNode() != null) {
+ if (curNode.getBaseNode().getResolvableStatus() != RESOLVED) {
+ addEntityToStack((T) curNode.getBaseNode(), node);
+ }
+ }
+ }
+
+ private void addEntityToStack(T entity, YangNode holder) {
+ YangEntityToResolveInfoImpl<T> unResolvedEntityInfo =
+ new YangEntityToResolveInfoImpl<>();
+ unResolvedEntityInfo.setEntityToResolve(entity);
+ unResolvedEntityInfo.setHolderOfEntityToResolve(holder);
+ addInPartialResolvedStack(unResolvedEntityInfo);
+ }
+
+ /**
+ * Sets stack of YANG type with partially resolved YANG construct hierarchy.
+ *
+ * @param partialResolvedInfo partial resolved YANG construct stack
+ */
+ private void addInPartialResolvedStack(YangEntityToResolveInfoImpl<T> partialResolvedInfo) {
+ partialResolvedStack.push(partialResolvedInfo);
+ }
+
+ /**
+ * Retrieves the next entity in the stack that needs to be resolved. It is
+ * assumed that the caller ensures that the stack is not empty.
+ *
+ * @return next entity in the stack that needs to be resolved
+ */
+ private T getCurEntityToResolveFromStack() {
+ return partialResolvedStack.peek().getEntityToResolve();
+ }
+
+ @Override
+ public YangEntityToResolveInfoImpl<T> getEntityToResolveInfo() {
+ return entityToResolveInfo;
+ }
+
+ @Override
+ public void linkInterFile(YangReferenceResolver dataModelRootNode)
+ throws DataModelException {
+
+ curRefResolver = dataModelRootNode;
+
+ // Current node to resolve, it can be a YANG type or YANG uses.
+ T entityToResolve = entityToResolveInfo.getEntityToResolve();
+
+ // Check if linking is already done
+ if (entityToResolve instanceof Resolvable) {
+ Resolvable resolvable = (Resolvable) entityToResolve;
+ if (resolvable.getResolvableStatus() == RESOLVED) {
+ return;
+ }
+ } else {
+ throw new DataModelException(UNRESOLVABLE);
+ }
+
+ if (entityToResolve instanceof YangXPathResolver &&
+ !(entityToResolve instanceof YangLeafRef)) {
+ //Process x-path linking.
+ processXPathLinking(entityToResolve, dataModelRootNode);
+ } else {
+ // Push the initial entity to resolve in stack.
+ addInPartialResolvedStack(entityToResolveInfo);
+ // Inter file linking and resolution.
+ linkInterFileAndResolve();
+ addDerivedRefTypeToRefTypeResolutionList();
+ }
+ }
+
+ /**
+ * Process x-path linking for augment and leaf-ref.
+ *
+ * @param entityToResolve entity to resolve
+ * @param root root node
+ * @throws DataModelException if there is a data model error
+ */
+ private void processXPathLinking(T entityToResolve,
+ YangReferenceResolver root)
+ throws DataModelException {
+
+ YangXpathLinker<T> xPathLinker = new YangXpathLinker<T>();
+
+ if (entityToResolve instanceof YangAugment) {
+ YangNode targetNode;
+ YangAugment augment = (YangAugment) entityToResolve;
+ targetNode = xPathLinker
+ .processXpathLinking(augment.getTargetNode(), (YangNode)
+ root, AUGMENT_LINKING);
+ if (targetNode != null) {
+ if (targetNode instanceof YangAugmentableNode) {
+ detectCollisionForAugmentedNode(targetNode, augment);
+ ((YangAugmentableNode) targetNode).addAugmentation(augment);
+ augment.setAugmentedNode(targetNode);
+ setAugmentedFlagInAncestors(targetNode);
+ Resolvable resolvable = (Resolvable) entityToResolve;
+ resolvable.setResolvableStatus(RESOLVED);
+ if (targetNode instanceof YangInput) {
+ xPathLinker.addInModuleIfInput(augment, (YangNode) root);
+ }
+ } else {
+ throw new LinkerException(getErrorMsg(
+ INVALID_TARGET + targetNode.getNodeType(),
+ augment.getName(), augment.getLineNumber(),
+ augment.getCharPosition(), augment.getFileName()));
+ }
+ } else {
+ throw new LinkerException(getErrorMsg(
+ FAILED_TO_LINK, augment.getName(), augment
+ .getLineNumber(), augment.getCharPosition(),
+ augment.getFileName()));
+ }
+ } else if (entityToResolve instanceof YangCompilerAnnotation) {
+ YangNode targetNode;
+ YangCompilerAnnotation ca = (YangCompilerAnnotation) entityToResolve;
+ targetNode = xPathLinker.processXpathLinking(ca.getAtomicPathList(),
+ (YangNode) root,
+ AUGMENT_LINKING);
+ if (targetNode != null) {
+ if (targetNode instanceof YangList) {
+ ((YangList) targetNode).setCompilerAnnotation(
+ (YangCompilerAnnotation) entityToResolve);
+ Resolvable resolvable = (Resolvable) entityToResolve;
+ resolvable.setResolvableStatus(RESOLVED);
+ } else {
+ throw new LinkerException(getErrorMsg(
+ INVALID_TARGET + targetNode.getNodeType(), ca.getPath(),
+ ca.getLineNumber(), ca.getCharPosition(), ca.getFileName()));
+ }
+ } else {
+ throw new LinkerException(getErrorMsg(
+ FAILED_TO_FIND_ANNOTATION, ca.getPath(), ca.getLineNumber(),
+ ca.getCharPosition(), ca.getFileName()));
+ }
+ } else if (entityToResolve instanceof YangLeafRef) {
+ YangLeafRef leafRef = (YangLeafRef) entityToResolve;
+ Object target = xPathLinker.processLeafRefXpathLinking(
+ leafRef.getAtomicPath(), (YangNode) root, leafRef, LEAF_REF_LINKING);
+ if (target != null) {
+ YangLeaf leaf;
+ YangLeafList leafList;
+ leafRef.setReferredLeafOrLeafList(target);
+ if (target instanceof YangLeaf) {
+ leaf = (YangLeaf) target;
+ leafRef.setResolvableStatus(INTER_FILE_LINKED);
+ addUnResolvedLeafRefTypeToStack((T) leaf, entityToResolveInfo
+ .getHolderOfEntityToResolve());
+ } else {
+ leafList = (YangLeafList) target;
+ leafRef.setResolvableStatus(INTER_FILE_LINKED);
+ addUnResolvedLeafRefTypeToStack(
+ (T) leafList, entityToResolveInfo.getHolderOfEntityToResolve());
+ }
+ fillPathPredicates(leafRef);
+ } else {
+ LinkerException ex = new LinkerException(
+ FAILED_TO_FIND_LEAD_INFO_HOLDER + leafRef.getPath());
+ ex.setCharPosition(leafRef.getCharPosition());
+ ex.setLine(leafRef.getLineNumber());
+ ex.setFileName(leafRef.getFileName());
+ throw ex;
+ }
+ }
+ }
+
+ /**
+ * Returns the referenced prefix of entity under resolution.
+ *
+ * @return referenced prefix of entity under resolution
+ * @throws DataModelException a violation in data model rule
+ */
+ private String getRefPrefix()
+ throws DataModelException {
+ T entity = getCurEntityToResolveFromStack();
+ if (entity instanceof YangType) {
+ return ((YangType<?>) entity).getPrefix();
+ }
+ if (entity instanceof YangUses) {
+ return ((YangUses) entity).getPrefix();
+ }
+ if (entity instanceof YangIfFeature) {
+ return ((YangIfFeature) entity).getPrefix();
+ }
+ if (entity instanceof YangBase) {
+ return ((YangBase) entity).getBaseIdentifier()
+ .getPrefix();
+ }
+ if (entity instanceof YangIdentityRef) {
+ return ((YangIdentityRef) entity).getPrefix();
+ }
+ throw new DataModelException(LINKER_ERROR);
+ }
+
+ /**
+ * Performs inter file linking and resolution.
+ *
+ * @throws DataModelException a violation in data model rule
+ */
+ private void linkInterFileAndResolve()
+ throws DataModelException {
+
+ while (!partialResolvedStack.isEmpty()) {
+
+ // Current node to resolve, it can be a YANG type or YANG uses.
+ T entityToResolve = getCurEntityToResolveFromStack();
+ // Check if linking is already done
+ if (entityToResolve instanceof Resolvable) {
+
+ Resolvable resolvable = (Resolvable) entityToResolve;
+ switch (resolvable.getResolvableStatus()) {
+ case RESOLVED:
+ /*
+ * If the entity is already resolved in the stack, then pop
+ * it and continue with the remaining stack elements to
+ * resolve
+ */
+ partialResolvedStack.pop();
+ break;
+
+ case INTER_FILE_LINKED:
+ /*
+ * If the top of the stack is already linked then resolve
+ * the references and pop the entity and continue with
+ * remaining stack elements to resolve
+ */
+ resolveTopOfStack();
+ partialResolvedStack.pop();
+ break;
+
+ case INTRA_FILE_RESOLVED:
+ /*
+ * If the top of the stack is intra file resolved then check
+ * if top of stack is linked, if not link it using
+ * import/include list and push the linked referred entity
+ * to the stack, otherwise only push it to the stack.
+ */
+ linkInterFileTopOfStackRefUpdateStack();
+ break;
+
+ case UNDEFINED:
+ /*
+ * In case of if-feature resolution, if referred "feature" is not
+ * defined then the resolvable status will be undefined.
+ */
+ partialResolvedStack.pop();
+ break;
+
+ default:
+ throw new DataModelException(INVALID_LINKER_STATE);
+ }
+ } else {
+ throw new DataModelException(INVALID_RESOLVED_ENTITY);
+ }
+ }
+ }
+
+ /**
+ * Links the top of the stack if it's inter-file and update stack.
+ *
+ * @throws DataModelException data model error
+ */
+ private void linkInterFileTopOfStackRefUpdateStack()
+ throws DataModelException {
+ T entity = getCurEntityToResolveFromStack();
+ if (entity instanceof YangLeafRef) {
+ // When leafref path comes with relative path, it will be converted to absolute path.
+ setAbsolutePathFromRelativePathInLeafref(entity);
+ processXPathLinking(entity, curRefResolver);
+ return;
+ }
+ /*
+ * Obtain the referred node of top of stack entity under resolution
+ */
+ T refNode = getRefNode();
+
+ /*
+ * Check for null for scenario when it's not linked and inter-file
+ * linking is required.
+ */
+ if (refNode == null) {
+
+ /*
+ * Check if prefix is null or not, to identify whether to search in
+ * import list or include list.
+ */
+ if (getRefPrefix() != null && !getRefPrefix()
+ .contentEquals(curRefResolver.getPrefix())) {
+ if (resolveWithImport()) {
+ return;
+ }
+ } else {
+ if (resolveWithInclude()) {
+ return;
+ }
+ }
+
+ if (entity instanceof YangIfFeature) {
+ ((YangIfFeature) entity).setResolvableStatus(UNDEFINED);
+ return;
+ }
+ // If current entity is still not resolved, then
+ // linking/resolution has failed.
+
+ DataModelException ex = new DataModelException(
+ getErrorInfoForLinker(entity));
+ ex.setLine(getLineNumber());
+ ex.setCharPosition(getCharPosition());
+ throw ex;
+ } else {
+ ((Resolvable) entity).setResolvableStatus(INTER_FILE_LINKED);
+ addUnresolvedRecursiveReferenceToStack((YangNode) refNode);
+ }
+ }
+
+ /**
+ * Sets the leafref with absolute path from the relative path.
+ *
+ * @param resolutionInfo information about the YANG construct which has to be resolved
+ * @throws DataModelException a violation of data model rules
+ */
+ private void setAbsolutePathFromRelativePathInLeafref(T resolutionInfo)
+ throws DataModelException {
+ if (resolutionInfo instanceof YangLeafRef) {
+
+ YangNode leafParent = ((YangLeafRef) resolutionInfo)
+ .getParentNode();
+ YangLeafRef leafref = (YangLeafRef) resolutionInfo;
+
+ // Checks if the leafref has relative path in it.
+ if (leafref.getPathType() == RELATIVE_PATH) {
+ YangRelativePath relativePath = leafref.getRelativePath();
+ List<YangAtomicPath> absoluteInRelative = relativePath.getAtomicPathList();
+ int ancestorCount = relativePath.getAncestorNodeCount();
+
+ // Gets the root node from the ancestor count.
+ T nodeOrAugmentList =
+ getRootNodeWithAncestorCountForLeafref(ancestorCount, leafParent,
+ leafref);
+ if (nodeOrAugmentList instanceof YangNode) {
+ StringBuilder name = new StringBuilder();
+ StringBuilder prefix = new StringBuilder();
+ YangNode rootNode = (YangNode) nodeOrAugmentList;
+ // Forms a new absolute path from the relative path
+ while (!(rootNode instanceof YangReferenceResolver)) {
+ name.append(rootNode.getName());
+ prefix.append(SLASH_FOR_STRING).append(name.reverse());
+ name.delete(0, name.length());
+ rootNode = rootNode.getParent();
+ if (rootNode == null) {
+ throw new DataModelException(INVALID_TREE);
+ }
+ }
+ prefix.reverse();
+ fillAbsolutePathValuesInLeafref(leafref, prefix.toString(),
+ absoluteInRelative);
+ } else {
+ List<String> listOfAugment = (List<String>) nodeOrAugmentList;
+ Iterator<String> listOfAugmentIterator = listOfAugment.listIterator();
+ StringBuilder augment = new StringBuilder(EMPTY_STRING);
+ while (listOfAugmentIterator.hasNext()) {
+ augment.append(SLASH_FOR_STRING)
+ .append(listOfAugmentIterator.next());
+ }
+ fillAbsolutePathValuesInLeafref(leafref, augment.toString(),
+ absoluteInRelative);
+ }
+ }
+ }
+ }
+
+ /**
+ * Fills the absolute path values in the leafref from relative path.
+ *
+ * @param leafref instance of YANG leafref
+ * @param path path name which has to be prefixed to relative path
+ * @param relative atomic paths in relative
+ * @throws DataModelException a violation of data model rules
+ */
+ private void fillAbsolutePathValuesInLeafref(YangLeafRef leafref, String path,
+ List<YangAtomicPath> relative)
+ throws DataModelException {
+ leafref.setPathType(ABSOLUTE_PATH);
+ String[] pathName = new String[0];
+ if (path != null && !path.equals(EMPTY_STRING)) {
+ pathName = path.split(SLASH_FOR_STRING);
+ }
+ List<YangAtomicPath> finalListForAbsolute = new LinkedList<>();
+ for (String value : pathName) {
+ if (value != null && !value.isEmpty() && !value.equals(EMPTY_STRING)) {
+ YangNodeIdentifier nodeId = getValidNodeIdentifier(value, PATH_DATA);
+ YangAtomicPath atomicPath = new YangAtomicPath();
+ atomicPath.setNodeIdentifier(nodeId);
+ finalListForAbsolute.add(atomicPath);
+ }
+ }
+ if (relative != null && !relative.isEmpty()) {
+ Iterator<YangAtomicPath> pathIt = relative.listIterator();
+ while (pathIt.hasNext()) {
+ YangAtomicPath yangAtomicPath = pathIt.next();
+ finalListForAbsolute.add(yangAtomicPath);
+ }
+ leafref.setAtomicPath(finalListForAbsolute);
+ } else {
+ DataModelException ex = new DataModelException(getLeafRefErrorInfo(leafref));
+ ex.setCharPosition(leafref.getCharPosition());
+ ex.setLine(leafref.getLineNumber());
+ ex.setFileName(leafref.getFileName());
+ throw ex;
+ }
+ }
+
+ /**
+ * Returns the root parent with respect to the ancestor count from leafref.
+ *
+ * @param ancestorCount count of node where parent node can be reached
+ * @param curParent current parent node
+ * @param leafref instance of YANG leafref
+ * @return node where the ancestor count stops or augment path name list
+ * @throws DataModelException a violation of data model rules
+ */
+ private T getRootNodeWithAncestorCountForLeafref(
+ int ancestorCount, YangNode curParent, YangLeafRef leafref)
+ throws DataModelException {
+
+ int curParentCount = 1;
+ curParent = skipInvalidDataNodes(curParent, leafref);
+ if (curParent instanceof YangAugment) {
+ YangAugment augment = (YangAugment) curParent;
+ List<String> valueInAugment = getPathWithAugment(augment,
+ ancestorCount - curParentCount);
+ return (T) valueInAugment;
+ } else {
+ while (curParentCount < ancestorCount) {
+ YangNode currentSkippedParent = skipInvalidDataNodes(curParent, leafref);
+ if (currentSkippedParent == curParent) {
+ if (curParent.getParent() == null) {
+ throw new DataModelException(getLeafRefErrorInfo(leafref));
+ }
+ curParent = curParent.getParent();
+ } else {
+ curParent = currentSkippedParent;
+ continue;
+ }
+ curParentCount = curParentCount + 1;
+ if (curParent instanceof YangAugment) {
+ YangAugment augment = (YangAugment) curParent;
+ List<String> valueInAugment = getPathWithAugment(
+ augment, ancestorCount - curParentCount);
+ return (T) valueInAugment;
+ }
+ }
+ }
+ return (T) curParent;
+ }
+
+ /**
+ * Finds and resolves with include list.
+ *
+ * @return true if resolved, false otherwise
+ * @throws DataModelException a violation in data model rule
+ */
+ private boolean resolveWithInclude() throws DataModelException {
+ /*
+ * Run through all the nodes in include list and search for referred
+ * typedef/grouping at the root level.
+ */
+ for (YangInclude yangInclude : curRefResolver.getIncludeList()) {
+ YangNode linkedNode = getLinkedNode(yangInclude.getIncludedNode());
+ if (linkedNode != null) {
+ return addUnResolvedRefToStack(linkedNode);
+ }
+ }
+ // If referred node can't be found return false.
+ return false;
+ }
+
+ /**
+ * Finds and resolves with import list.
+ *
+ * @return true if resolved, false otherwise
+ * @throws DataModelException a violation in data model rule
+ */
+ private boolean resolveWithImport() throws DataModelException {
+
+ // Run through import list to find the referred typedef/grouping.
+ for (YangImport yangImport : curRefResolver.getImportList()) {
+ /*
+ * Match the prefix attached to entity under resolution with the
+ * imported/included module/sub-module's prefix. If found, search
+ * for the referred typedef/grouping at the root level.
+ */
+ if (yangImport.getPrefixId().contentEquals(getRefPrefix())) {
+ YangNode linkedNode = getLinkedNode(yangImport.getImportedNode());
+ if (linkedNode != null) {
+ return addUnResolvedRefToStack(linkedNode);
+ }
+ /*
+ * If referred node can't be found at root level break for loop,
+ * and return false.
+ */
+ break;
+ }
+ }
+ // If referred node can't be found return false.
+ return false;
+ }
+
+ //Add unresolved constructs to stack.
+ private boolean addUnResolvedRefToStack(YangNode linkedNode)
+ throws DataModelException {
+ // Add the link to external entity.
+ addReferredEntityLink(linkedNode, INTER_FILE_LINKED);
+
+ // Add the type/uses of referred typedef/grouping to the stack.
+ addUnresolvedRecursiveReferenceToStack(linkedNode);
+ return true;
+ }
+
+ //Returns linked node from entity of stack.
+ private YangNode getLinkedNode(YangNode node) {
+ T entity = getCurEntityToResolveFromStack();
+ if (entity instanceof YangType) {
+ return findRefTypedef(node);
+ }
+ if (entity instanceof YangUses) {
+ return findRefGrouping(node);
+ }
+ if (entity instanceof YangIfFeature) {
+ return findRefFeature(node);
+ }
+ if (entity instanceof YangBase) {
+ return findRefIdentity(node);
+ }
+ if (entity instanceof YangIdentityRef) {
+ return findRefIdentityRef(node);
+ }
+ return null;
+ }
+
+ /**
+ * Returns referred typedef/grouping node.
+ *
+ * @return referred typedef/grouping node
+ * @throws DataModelException a violation in data model rule
+ */
+ private T getRefNode() throws DataModelException {
+ T entity = getCurEntityToResolveFromStack();
+ if (entity instanceof YangType) {
+ YangDerivedInfo<?> derivedInfo = (YangDerivedInfo<?>)
+ ((YangType<?>) entity).getDataTypeExtendedInfo();
+ return (T) derivedInfo.getReferredTypeDef();
+ }
+ if (entity instanceof YangUses) {
+ return (T) ((YangUses) entity).getRefGroup();
+ }
+ if (entity instanceof YangIfFeature) {
+ return (T) ((YangIfFeature) entity).getReferredFeatureHolder();
+ }
+ if (entity instanceof YangLeafRef) {
+ return (T) ((YangLeafRef) entity).getReferredLeafOrLeafList();
+ }
+ if (entity instanceof YangBase) {
+ return (T) ((YangBase) entity).getReferredIdentity();
+ }
+ if (entity instanceof YangIdentityRef) {
+ return (T) ((YangIdentityRef) entity).getReferredIdentity();
+ }
+ throw new DataModelException(LINKER_ERROR);
+ }
+
+ /**
+ * Finds the referred grouping node at the root level of imported/included node.
+ *
+ * @param refNode module/sub-module node
+ * @return referred grouping
+ */
+ private YangNode findRefGrouping(YangNode refNode) {
+ YangNode tmpNode = refNode.getChild();
+ while (tmpNode != null) {
+ if (tmpNode instanceof YangGrouping) {
+ if (tmpNode.getName()
+ .equals(((YangUses) getCurEntityToResolveFromStack())
+ .getName())) {
+ return tmpNode;
+ }
+ }
+ tmpNode = tmpNode.getNextSibling();
+ }
+ return null;
+ }
+
+ /**
+ * Finds the referred feature node at the root level of imported/included node.
+ *
+ * @param refNode module/sub-module node
+ * @return referred feature
+ */
+ private YangNode findRefFeature(YangNode refNode) {
+ T entity = getCurEntityToResolveFromStack();
+ YangNodeIdentifier ifFeature = ((YangIfFeature) entity).getName();
+ List<YangFeature> featureList = ((YangFeatureHolder) refNode)
+ .getFeatureList();
+ if (featureList != null && !featureList.isEmpty()) {
+ for (YangFeature feature : featureList) {
+ if (ifFeature.getName().equals(feature.getName())) {
+ ((YangIfFeature) entity).setReferredFeature(feature);
+ return refNode;
+ }
+ }
+ }
+ return null;
+ }
+
+ /**
+ * Finds the referred typedef node at the root level of imported/included node.
+ *
+ * @param refNode module/sub-module node
+ * @return referred typedef
+ */
+ private YangNode findRefTypedef(YangNode refNode) {
+ YangNode tmpNode = refNode.getChild();
+ while (tmpNode != null) {
+ if (tmpNode instanceof YangTypeDef) {
+ if (tmpNode.getName()
+ .equals(((YangType) getCurEntityToResolveFromStack())
+ .getDataTypeName())) {
+ return tmpNode;
+ }
+ }
+ tmpNode = tmpNode.getNextSibling();
+ }
+ return null;
+ }
+
+ /**
+ * Finds the referred identity node at the root level of imported/included node.
+ *
+ * @param refNode module/sub-module node
+ * @return referred identity
+ */
+ private YangNode findRefIdentity(YangNode refNode) {
+ YangNode tmpNode = refNode.getChild();
+ while (tmpNode != null) {
+ if (tmpNode instanceof YangIdentity) {
+ if (tmpNode.getName()
+ .equals(((YangBase) getCurEntityToResolveFromStack())
+ .getBaseIdentifier().getName())) {
+ return tmpNode;
+ }
+ }
+ tmpNode = tmpNode.getNextSibling();
+ }
+ return null;
+ }
+
+ /**
+ * Finds the referred identity node at the root level of imported/included node.
+ *
+ * @param refNode module/sub-module node
+ * @return referred identity
+ */
+ private YangNode findRefIdentityRef(YangNode refNode) {
+ YangNode tmpNode = refNode.getChild();
+ while (tmpNode != null) {
+ if (tmpNode instanceof YangIdentity) {
+ if (tmpNode.getName()
+ .equals(((YangIdentityRef) getCurEntityToResolveFromStack())
+ .getBaseIdentity().getName())) {
+ return tmpNode;
+ }
+ }
+ tmpNode = tmpNode.getNextSibling();
+ }
+ return null;
+ }
+
+ /**
+ * Sets descendant node augmented flag in ancestors.
+ *
+ * @param targetNode augmented YANG node
+ */
+ private void setAugmentedFlagInAncestors(YangNode targetNode) {
+ targetNode = targetNode.getParent();
+ while (targetNode != null) {
+ targetNode.setDescendantNodeAugmented(true);
+ targetNode = targetNode.getParent();
+ }
+ }
+}
\ No newline at end of file
diff --git a/compiler/base/linker/src/main/java/org/onosproject/yang/compiler/linker/impl/YangXpathLinker.java b/compiler/base/linker/src/main/java/org/onosproject/yang/compiler/linker/impl/YangXpathLinker.java
new file mode 100644
index 0000000..02d1beb
--- /dev/null
+++ b/compiler/base/linker/src/main/java/org/onosproject/yang/compiler/linker/impl/YangXpathLinker.java
@@ -0,0 +1,774 @@
+/*
+ * 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.yang.compiler.linker.impl;
+
+import org.onosproject.yang.compiler.datamodel.LeafRefInvalidHolder;
+import org.onosproject.yang.compiler.datamodel.RpcNotificationContainer;
+import org.onosproject.yang.compiler.datamodel.YangAtomicPath;
+import org.onosproject.yang.compiler.datamodel.YangAugment;
+import org.onosproject.yang.compiler.datamodel.YangGrouping;
+import org.onosproject.yang.compiler.datamodel.YangImport;
+import org.onosproject.yang.compiler.datamodel.YangInclude;
+import org.onosproject.yang.compiler.datamodel.YangInput;
+import org.onosproject.yang.compiler.datamodel.YangLeaf;
+import org.onosproject.yang.compiler.datamodel.YangLeafList;
+import org.onosproject.yang.compiler.datamodel.YangLeafRef;
+import org.onosproject.yang.compiler.datamodel.YangLeavesHolder;
+import org.onosproject.yang.compiler.datamodel.YangModule;
+import org.onosproject.yang.compiler.datamodel.YangNode;
+import org.onosproject.yang.compiler.datamodel.YangNodeIdentifier;
+import org.onosproject.yang.compiler.datamodel.YangOutput;
+import org.onosproject.yang.compiler.datamodel.YangSubModule;
+import org.onosproject.yang.compiler.datamodel.YangUses;
+import org.onosproject.yang.compiler.linker.exceptions.LinkerException;
+
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Map;
+import java.util.Stack;
+
+import static org.onosproject.yang.compiler.datamodel.exceptions.ErrorMessages.getErrorMsg;
+import static org.onosproject.yang.compiler.linker.impl.PrefixResolverType.INTER_TO_INTER;
+import static org.onosproject.yang.compiler.linker.impl.PrefixResolverType.INTER_TO_INTRA;
+import static org.onosproject.yang.compiler.linker.impl.PrefixResolverType.INTRA_TO_INTER;
+import static org.onosproject.yang.compiler.linker.impl.PrefixResolverType.NO_PREFIX_CHANGE_FOR_INTER;
+import static org.onosproject.yang.compiler.linker.impl.PrefixResolverType.NO_PREFIX_CHANGE_FOR_INTRA;
+import static org.onosproject.yang.compiler.linker.impl.XpathLinkingTypes.AUGMENT_LINKING;
+import static org.onosproject.yang.compiler.utils.UtilConstants.COLON;
+import static org.onosproject.yang.compiler.utils.UtilConstants.ERROR_MSG_FOR_AUGMENT_LINKING;
+import static org.onosproject.yang.compiler.utils.UtilConstants.FAILED_TO_FIND_LEAD_INFO_HOLDER;
+import static org.onosproject.yang.compiler.utils.UtilConstants.INPUT;
+import static org.onosproject.yang.compiler.utils.UtilConstants.IS_INVALID;
+import static org.onosproject.yang.compiler.utils.UtilConstants.LEAFREF_ERROR;
+import static org.onosproject.yang.compiler.utils.UtilConstants.LEAF_HOLDER_ERROR;
+import static org.onosproject.yang.compiler.utils.UtilConstants.OUTPUT;
+import static org.onosproject.yang.compiler.utils.UtilConstants.SLASH_FOR_STRING;
+
+/**
+ * Represents x-path linking.
+ *
+ * @param <T> x-path linking can be done for target node or for target leaf/leaf-list
+ */
+public class YangXpathLinker<T> {
+
+ private List<YangAtomicPath> absPaths;
+ private YangNode rootNode;
+ private Map<YangAtomicPath, PrefixResolverType> prefixResolverTypes;
+ private String curPrefix;
+ private String constructsParentsPrefix;
+ private XpathLinkingTypes linkingType;
+
+ /**
+ * Creates an instance of x-path linker.
+ */
+ public YangXpathLinker() {
+ absPaths = new ArrayList<>();
+ }
+
+ /**
+ * Returns list of augment nodes.
+ *
+ * @param node root node
+ * @return list of augment nodes
+ */
+ public List<YangAugment> getListOfYangAugment(YangNode node) {
+ node = node.getChild();
+ List<YangAugment> augments = new ArrayList<>();
+ while (node != null) {
+ if (node instanceof YangAugment) {
+ augments.add((YangAugment) node);
+ }
+ node = node.getNextSibling();
+ }
+ return augments;
+ }
+
+ /**
+ * Process absolute node path for target leaf.
+ *
+ * @param atomicPaths atomic path node list
+ * @param root root node
+ * @param leafref instance of YANG leafref
+ * @param curLinking x path linking type
+ * @return linked target node
+ */
+ T processLeafRefXpathLinking(List<YangAtomicPath> atomicPaths, YangNode root,
+ YangLeafRef leafref, XpathLinkingTypes curLinking) {
+
+ YangNode targetNode;
+ rootNode = root;
+ prefixResolverTypes = new HashMap<>();
+ linkingType = curLinking;
+ parsePrefixResolverList(atomicPaths);
+ YangAtomicPath leafRefPath = atomicPaths.get(atomicPaths.size() - 1);
+
+ // When leaf-ref path contains only one absolute path.
+ if (atomicPaths.size() == 1) {
+ targetNode = getTargetNodeWhenPathSizeIsOne(atomicPaths);
+ } else {
+ for (YangAtomicPath atomicPath : atomicPaths) {
+ if (atomicPath != leafRefPath) {
+ absPaths.add(atomicPath);
+ }
+ }
+ targetNode = parseData(root);
+ }
+ if (targetNode == null) {
+ targetNode = searchInSubModule(root);
+ }
+
+ // Invalid path presence in the node list is checked.
+ validateInvalidNodesInThePath(leafref);
+
+ if (targetNode != null) {
+ YangLeaf targetLeaf = searchReferredLeaf(targetNode, leafRefPath
+ .getNodeIdentifier().getName());
+ if (targetLeaf == null) {
+ YangLeafList targetLeafList = searchReferredLeafList(
+ targetNode, leafRefPath.getNodeIdentifier().getName());
+ if (targetLeafList != null) {
+ return (T) targetLeafList;
+ } else {
+ LinkerException ex = new LinkerException(
+ FAILED_TO_FIND_LEAD_INFO_HOLDER + leafref.getPath());
+ ex.setCharPosition(leafref.getCharPosition());
+ ex.setLine(leafref.getLineNumber());
+ ex.setFileName(leafref.getFileName());
+ throw ex;
+ }
+ }
+ return (T) targetLeaf;
+ }
+ return null;
+ }
+
+ /**
+ * Validates the nodes in the path for any invalid node.
+ *
+ * @param leafref instance of YANG leafref
+ */
+ private void validateInvalidNodesInThePath(YangLeafRef leafref) {
+ for (YangAtomicPath absolutePath : (Iterable<YangAtomicPath>) leafref
+ .getAtomicPath()) {
+ YangNode nodeInPath = absolutePath.getResolvedNode();
+
+ if (nodeInPath instanceof LeafRefInvalidHolder) {
+ LinkerException ex = new LinkerException(
+ LEAFREF_ERROR + leafref.getPath() + IS_INVALID);
+ ex.setCharPosition(leafref.getCharPosition());
+ ex.setLine(leafref.getLineNumber());
+ ex.setFileName(leafref.getFileName());
+ throw ex;
+ }
+ }
+ }
+
+ /**
+ * Returns target node when leaf-ref has only one absolute path in list.
+ *
+ * @param paths absolute paths
+ * @return target node
+ */
+ private YangNode getTargetNodeWhenPathSizeIsOne(List<YangAtomicPath> paths) {
+ if (paths.get(0).getNodeIdentifier().getPrefix() != null
+ && !paths.get(0).getNodeIdentifier().getPrefix().equals
+ (getRootsPrefix(rootNode))) {
+ return getImportedNode(rootNode, paths.get(0).getNodeIdentifier());
+ }
+ return rootNode;
+ }
+
+ /**
+ * Process absolute node path linking for augment.
+ *
+ * @param paths absolute path node list
+ * @param root root node
+ * @param curLinking x path linker type
+ * @return linked target node
+ */
+ public YangNode processXpathLinking(List<YangAtomicPath> paths,
+ YangNode root, XpathLinkingTypes curLinking) {
+ absPaths = paths;
+ rootNode = root;
+ prefixResolverTypes = new HashMap<>();
+ linkingType = curLinking;
+ parsePrefixResolverList(paths);
+ YangNode targetNode = parseData(root);
+ if (targetNode == null) {
+ targetNode = searchInSubModule(root);
+ }
+ return targetNode;
+ }
+
+ /**
+ * Searches for the referred leaf in target node.
+ *
+ * @param targetNode target node
+ * @param leafName leaf name
+ * @return target leaf
+ */
+ private YangLeaf searchReferredLeaf(YangNode targetNode, String leafName) {
+ if (!(targetNode instanceof YangLeavesHolder)) {
+ throw new LinkerException(getErrorMsg(
+ LEAF_HOLDER_ERROR, targetNode.getName(), targetNode
+ .getLineNumber(), targetNode.getCharPosition(),
+ targetNode.getFileName()));
+ }
+ YangLeavesHolder holder = (YangLeavesHolder) targetNode;
+ List<YangLeaf> leaves = holder.getListOfLeaf();
+ if (leaves != null && !leaves.isEmpty()) {
+ for (YangLeaf leaf : leaves) {
+ if (leaf.getName().equals(leafName)) {
+ return leaf;
+ }
+ }
+ }
+ return null;
+ }
+
+ /**
+ * Searches for the referred leaf-list in target node.
+ *
+ * @param targetNode target node
+ * @param name leaf-list name
+ * @return target leaf-list
+ */
+ private YangLeafList searchReferredLeafList(YangNode targetNode, String name) {
+ if (!(targetNode instanceof YangLeavesHolder)) {
+ throw new LinkerException(getErrorMsg(
+ LEAF_HOLDER_ERROR, targetNode.getName(), targetNode
+ .getLineNumber(), targetNode.getCharPosition(),
+ targetNode.getFileName()));
+ }
+ YangLeavesHolder holder = (YangLeavesHolder) targetNode;
+ List<YangLeafList> leavesList = holder.getListOfLeafList();
+ if (leavesList != null && !leavesList.isEmpty()) {
+ for (YangLeafList leafList : leavesList) {
+ if (leafList.getName().equals(name)) {
+ return leafList;
+ }
+ }
+ }
+ return null;
+ }
+
+ /**
+ * Process linking using for node identifier for inter/intra file.
+ *
+ * @param root root node
+ * @return linked target node
+ */
+ private YangNode parseData(YangNode root) {
+ String rootPrefix = getRootsPrefix(root);
+ constructsParentsPrefix = rootPrefix;
+ Iterator<YangAtomicPath> pathIterator = absPaths.iterator();
+ YangAtomicPath path = pathIterator.next();
+ if (path.getNodeIdentifier().getPrefix() != null
+ && !path.getNodeIdentifier().getPrefix().equals(rootPrefix)) {
+ return parsePath(getImportedNode(root, path.getNodeIdentifier()));
+ } else {
+ return parsePath(root);
+ }
+ }
+
+ /**
+ * Process linking of target node in root node.
+ *
+ * @param root root node
+ * @return linked target node
+ */
+ private YangNode parsePath(YangNode root) {
+
+ YangNode tempNode = root;
+ Stack<YangNode> linkerStack = new Stack<>();
+ Iterator<YangAtomicPath> pathIterator = absPaths.iterator();
+ YangAtomicPath tempPath = pathIterator.next();
+ YangNodeIdentifier nodeId;
+ curPrefix = tempPath.getNodeIdentifier().getPrefix();
+ int index = 0;
+ YangNode tempAugment;
+ do {
+ nodeId = tempPath.getNodeIdentifier();
+ if (tempPath.getNodeIdentifier().getPrefix() == null) {
+ tempAugment = resolveIntraFileAugment(tempPath, root);
+ } else {
+ tempAugment = resolveInterFileAugment(tempPath, root);
+ }
+ if (tempAugment != null) {
+ linkerStack.push(tempNode);
+ tempNode = tempAugment;
+ }
+
+ tempNode = searchTargetNode(tempNode, nodeId);
+
+ if (tempNode == null && !linkerStack.isEmpty()) {
+ tempNode = linkerStack.peek();
+ linkerStack.pop();
+ tempNode = searchTargetNode(tempNode, nodeId);
+ }
+
+ if (tempNode != null) {
+ tempPath.setResolvedNode(tempNode);
+ validateTempPathNode(tempNode);
+ }
+
+ if (index == absPaths.size() - 1) {
+ break;
+ }
+ tempPath = pathIterator.next();
+ index++;
+ } while (validate(tempNode, index));
+ return tempNode;
+ }
+
+ /**
+ * Validates temp path nodes for augment linking.
+ *
+ * @param node temp path node
+ */
+ private void validateTempPathNode(YangNode node) {
+
+ if (linkingType != AUGMENT_LINKING) {
+ return;
+ }
+ if (node instanceof YangGrouping) {
+ LinkerException ex = new LinkerException(
+ ERROR_MSG_FOR_AUGMENT_LINKING +
+ getAugmentNodeIdentifier(
+ absPaths.get(absPaths.size() - 1).getNodeIdentifier(),
+ absPaths,
+ rootNode));
+ ex.setFileName(rootNode.getFileName());
+ throw ex;
+ }
+ }
+
+ /**
+ * Resolves intra file augment linking.
+ *
+ * @param tempPath temporary absolute path
+ * @param root root node
+ * @return linked target node
+ */
+ private YangNode resolveIntraFileAugment(YangAtomicPath tempPath, YangNode root) {
+ YangNode tempAugment;
+ if (curPrefix != tempPath.getNodeIdentifier().getPrefix()) {
+ root = getIncludedNode(rootNode, tempPath.getNodeIdentifier().getName());
+ if (root == null) {
+ root = getIncludedNode(rootNode, getAugmentNodeIdentifier(
+ tempPath.getNodeIdentifier(), absPaths, rootNode));
+ if (root == null) {
+ root = rootNode;
+ }
+ }
+ } else {
+ if (curPrefix != null) {
+ root = getImportedNode(root, tempPath.getNodeIdentifier());
+ }
+ }
+
+ curPrefix = tempPath.getNodeIdentifier().getPrefix();
+ tempAugment = getAugment(tempPath.getNodeIdentifier(), root, absPaths);
+ if (tempAugment == null) {
+ tempAugment = getAugment(tempPath.getNodeIdentifier(), rootNode,
+ absPaths);
+ }
+ return tempAugment;
+ }
+
+ /**
+ * Resolves inter file augment linking.
+ *
+ * @param tempPath temporary absolute path
+ * @param root root node
+ * @return linked target node
+ */
+ private YangNode resolveInterFileAugment(YangAtomicPath tempPath, YangNode root) {
+
+ YangNode tempAugment;
+ if (!tempPath.getNodeIdentifier().getPrefix().equals(curPrefix)) {
+ curPrefix = tempPath.getNodeIdentifier().getPrefix();
+ root = getImportedNode(rootNode, tempPath.getNodeIdentifier());
+ }
+ tempAugment = getAugment(tempPath.getNodeIdentifier(), root, absPaths);
+ if (tempAugment == null) {
+ return resolveInterToInterFileAugment(root);
+ }
+ return tempAugment;
+ }
+
+ /**
+ * Resolves augment when prefix changed from inter file to inter file.
+ * it may be possible that the prefix used in imported module is different the
+ * given list of node identifiers.
+ *
+ * @param root root node
+ * @return target node
+ */
+ private YangNode resolveInterToInterFileAugment(YangNode root) {
+ List<YangAugment> augments = getListOfYangAugment(root);
+ int index;
+ List<YangAtomicPath> paths = new ArrayList<>();
+ for (YangAugment augment : augments) {
+ index = 0;
+
+ for (YangAtomicPath path : augment.getTargetNode()) {
+
+ if (!searchForAugmentInImportedNode(path.getNodeIdentifier(), index)) {
+ paths.clear();
+ break;
+ }
+ paths.add(path);
+ index++;
+ }
+ if (!paths.isEmpty() && paths.size() == absPaths.size() - 1) {
+ return augment;
+ } else {
+ paths.clear();
+ }
+ }
+ return null;
+ }
+
+ /**
+ * Searches for the augment node in imported module when prefix has changed from
+ * inter file to inter file.
+ *
+ * @param nodeId node id
+ * @param index index
+ * @return true if found
+ */
+ private boolean searchForAugmentInImportedNode(YangNodeIdentifier nodeId,
+ int index) {
+ if (index == absPaths.size()) {
+ return false;
+ }
+ YangNodeIdentifier tempNodeId = absPaths.get(index).getNodeIdentifier();
+ return nodeId.getName().equals(tempNodeId.getName());
+ }
+
+ /**
+ * Returns augment node.
+ *
+ * @param tempNodeId temporary absolute path id
+ * @param root root node
+ * @return linked target node
+ */
+ private YangNode getAugment(YangNodeIdentifier tempNodeId, YangNode root,
+ List<YangAtomicPath> absPaths) {
+ String augmentName = getAugmentNodeIdentifier(tempNodeId, absPaths, root);
+ if (augmentName != null) {
+ return searchAugmentNode(root, augmentName);
+ }
+ return null;
+ }
+
+ /**
+ * Process linking using import list.
+ *
+ * @param root root node
+ * @param nodeId node identifier
+ * @return linked target node
+ */
+ private YangNode getImportedNode(YangNode root, YangNodeIdentifier nodeId) {
+
+ List<YangImport> importList;
+
+ if (root instanceof YangModule) {
+ importList = ((YangModule) root).getImportList();
+ } else {
+ importList = ((YangSubModule) root).getImportList();
+ }
+
+ for (YangImport imported : importList) {
+ if (imported.getPrefixId().equals(nodeId.getPrefix())) {
+ return imported.getImportedNode();
+ }
+ }
+
+ if (nodeId.getName() != null && nodeId.getPrefix()
+ .equals(constructsParentsPrefix)) {
+ return rootNode;
+ }
+ return root;
+ }
+
+ /**
+ * Searches in sub-module node.
+ *
+ * @param root root node
+ * @return target linked node
+ */
+ private YangNode searchInSubModule(YangNode root) {
+ List<YangInclude> includeList;
+ YangNode tempNode;
+ if (root instanceof YangModule) {
+ includeList = ((YangModule) root).getIncludeList();
+ } else {
+ includeList = ((YangSubModule) root).getIncludeList();
+ }
+
+ for (YangInclude included : includeList) {
+ tempNode = parseData(included.getIncludedNode());
+ if (tempNode != null) {
+ return tempNode;
+ }
+ }
+ return null;
+ }
+
+ /**
+ * Process linking using include list.
+ *
+ * @param root root node
+ * @param tempPathName temporary path node name
+ * @return linked target node
+ */
+ private YangNode getIncludedNode(YangNode root, String tempPathName) {
+
+ List<YangInclude> includeList;
+
+ if (root instanceof YangModule) {
+ includeList = ((YangModule) root).getIncludeList();
+ } else {
+ includeList = ((YangSubModule) root).getIncludeList();
+ }
+
+ for (YangInclude included : includeList) {
+ if (verifyChildNode(included.getIncludedNode(), tempPathName)) {
+ return included.getIncludedNode();
+ }
+ }
+
+ return null;
+ }
+
+ /**
+ * Verifies for child nodes in sub module.
+ *
+ * @param node submodule node
+ * @param name name of child node
+ * @return true if child node found
+ */
+ private boolean verifyChildNode(YangNode node, String name) {
+ node = node.getChild();
+ while (node != null) {
+ if (node.getName().equals(name)) {
+ return true;
+ }
+ node = node.getNextSibling();
+ }
+ return false;
+ }
+
+
+ /**
+ * Returns augment's node id.
+ *
+ * @param nodeId node identifier
+ * @param absPaths absolute paths
+ * @param root root node
+ * @return augment's node id
+ */
+ private String getAugmentNodeIdentifier(
+ YangNodeIdentifier nodeId, List<YangAtomicPath> absPaths, YangNode root) {
+ Iterator<YangAtomicPath> nodeIdIterator = absPaths.iterator();
+ YangAtomicPath tempNodeId;
+ StringBuilder builder = new StringBuilder();
+ String name;
+ String prefix;
+ String id;
+ PrefixResolverType type;
+ while (nodeIdIterator.hasNext()) {
+ tempNodeId = nodeIdIterator.next();
+ name = tempNodeId.getNodeIdentifier().getName();
+ prefix = tempNodeId.getNodeIdentifier().getPrefix();
+ if (!tempNodeId.getNodeIdentifier().equals(nodeId)) {
+ type = prefixResolverTypes.get(tempNodeId);
+ switch (type) {
+ case INTER_TO_INTRA:
+ id = SLASH_FOR_STRING + name;
+ break;
+ case INTRA_TO_INTER:
+ if (!getRootsPrefix(root).equals(prefix)) {
+ id = SLASH_FOR_STRING + prefix + COLON + name;
+ } else {
+ id = SLASH_FOR_STRING + name;
+ }
+ break;
+ case INTER_TO_INTER:
+ id = SLASH_FOR_STRING + prefix + COLON + name;
+ break;
+ case NO_PREFIX_CHANGE_FOR_INTRA:
+ id = SLASH_FOR_STRING + name;
+ break;
+ case NO_PREFIX_CHANGE_FOR_INTER:
+ if (!getRootsPrefix(root).equals(prefix)) {
+ id = SLASH_FOR_STRING + prefix + COLON + name;
+ } else {
+ id = SLASH_FOR_STRING + name;
+ }
+ break;
+ default:
+ id = SLASH_FOR_STRING + name;
+ break;
+ }
+ builder.append(id);
+ } else {
+ return builder.toString();
+ }
+ }
+ return null;
+ }
+
+ /**
+ * Searches augment node in root node by name of the augment. For intra
+ * file augment, target augment name without prefix is taken and checked.
+ *
+ * @param root root node
+ * @param augName current augment name
+ * @return target augment node
+ */
+ private YangNode searchAugmentNode(YangNode root, String augName) {
+ YangNode node = root;
+ node = node.getChild();
+ while (node != null) {
+ if (node instanceof YangAugment) {
+ String name = ((YangAugment) node).getPrefixRemovedName();
+ if (node.getName().equals(augName) || name.equals(augName)) {
+ return node;
+ }
+ }
+ node = node.getNextSibling();
+ }
+ return null;
+ }
+
+ /**
+ * Validates for target node if target node found or not.
+ *
+ * @param tempNode temporary node
+ * @param index current index of list
+ * @return false if target node found
+ */
+ private boolean validate(YangNode tempNode, int index) {
+
+ int size = absPaths.size();
+ if (tempNode != null && index != size) {
+ return true;
+ } else if (tempNode != null) {
+ return false;
+ // this is your target node.
+ } else if (index != size) {
+ return true;
+ // this could be in submodule as well.
+ }
+ return false;
+ }
+
+ /**
+ * Searches target node in root node.
+ *
+ * @param node root node
+ * @param curNodeId YANG node identifier
+ * @return linked target node
+ */
+ private YangNode searchTargetNode(YangNode node, YangNodeIdentifier curNodeId) {
+
+ if (node != null) {
+ node = node.getChild();
+ }
+ while (node != null) {
+ if (node instanceof YangInput) {
+ if (curNodeId.getName().equalsIgnoreCase(INPUT)) {
+ return node;
+ }
+ } else if (node instanceof YangOutput) {
+ if (curNodeId.getName().equalsIgnoreCase(OUTPUT)) {
+ return node;
+ }
+ }
+ if (node.getName().equals(curNodeId.getName()) &&
+ !(node instanceof YangUses)) {
+ return node;
+ }
+ node = node.getNextSibling();
+ }
+ return null;
+ }
+
+ /**
+ * Returns root prefix.
+ *
+ * @param root root node
+ * @return root prefix
+ */
+ private String getRootsPrefix(YangNode root) {
+ if (root instanceof YangModule) {
+ return ((YangModule) root).getPrefix();
+ } else {
+ return ((YangSubModule) root).getPrefix();
+ }
+ }
+
+ /**
+ * Resolves prefix and provides prefix resolver list.
+ *
+ * @param absolutePaths absolute paths
+ */
+ private void parsePrefixResolverList(List<YangAtomicPath> absolutePaths) {
+ Iterator<YangAtomicPath> pathIterator = absolutePaths.iterator();
+ YangAtomicPath absPath;
+ String prePrefix;
+ String curPrefix = null;
+ while (pathIterator.hasNext()) {
+ prePrefix = curPrefix;
+ absPath = pathIterator.next();
+ curPrefix = absPath.getNodeIdentifier().getPrefix();
+ if (curPrefix != null) {
+ if (!curPrefix.equals(prePrefix)) {
+ if (prePrefix != null) {
+ prefixResolverTypes.put(absPath, INTER_TO_INTER);
+ } else {
+ prefixResolverTypes.put(absPath, INTRA_TO_INTER);
+ }
+ } else {
+ prefixResolverTypes.put(absPath, NO_PREFIX_CHANGE_FOR_INTER);
+ }
+ } else {
+ if (prePrefix != null) {
+ prefixResolverTypes.put(absPath, INTER_TO_INTRA);
+ } else {
+ prefixResolverTypes.put(absPath, NO_PREFIX_CHANGE_FOR_INTRA);
+ }
+ }
+ }
+ }
+
+ /**
+ * Adds augment to rpc augmented list of input.
+ *
+ * @param augment augment
+ * @param rootNode root node
+ */
+ void addInModuleIfInput(YangAugment augment,
+ YangNode rootNode) {
+ ((RpcNotificationContainer) rootNode).addToAugmentList(augment);
+ }
+}
\ No newline at end of file
diff --git a/compiler/base/linker/src/main/java/org/onosproject/yang/compiler/linker/impl/package-info.java b/compiler/base/linker/src/main/java/org/onosproject/yang/compiler/linker/impl/package-info.java
new file mode 100644
index 0000000..7ddaed2
--- /dev/null
+++ b/compiler/base/linker/src/main/java/org/onosproject/yang/compiler/linker/impl/package-info.java
@@ -0,0 +1,20 @@
+/*
+ * 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.
+ */
+
+/**
+ * Provide intra/inter file and inter jar linking implementation.
+ */
+package org.onosproject.yang.compiler.linker.impl;
diff --git a/compiler/base/linker/src/main/java/org/onosproject/yang/compiler/linker/package-info.java b/compiler/base/linker/src/main/java/org/onosproject/yang/compiler/linker/package-info.java
new file mode 100644
index 0000000..5cef2e8
--- /dev/null
+++ b/compiler/base/linker/src/main/java/org/onosproject/yang/compiler/linker/package-info.java
@@ -0,0 +1,20 @@
+/*
+ * 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.
+ */
+
+/**
+ * Provide inter jar and inter file linking abstract interface.
+ */
+package org.onosproject.yang.compiler.linker;
\ No newline at end of file