[ONOS-6694] Multi augment with same name.
Change-Id: Ib319944816679c5c9a703ff771bdfbd0d6af67ab
diff --git a/compiler/base/datamodel/src/main/java/org/onosproject/yang/compiler/datamodel/YangAugment.java b/compiler/base/datamodel/src/main/java/org/onosproject/yang/compiler/datamodel/YangAugment.java
index 934a869..c7a2422 100644
--- a/compiler/base/datamodel/src/main/java/org/onosproject/yang/compiler/datamodel/YangAugment.java
+++ b/compiler/base/datamodel/src/main/java/org/onosproject/yang/compiler/datamodel/YangAugment.java
@@ -158,6 +158,11 @@
private String setterMethodName;
/**
+ * Logical node of YANG augment.
+ */
+ private YangAugment logicalNode;
+
+ /**
* Create a YANG augment node.
*/
public YangAugment() {
@@ -569,4 +574,22 @@
public void setSetterMethodName(String name) {
setterMethodName = name;
}
+
+ /**
+ * Returns the logical YANG augment node.
+ *
+ * @return logical YANG augment
+ */
+ public YangAugment getLogicalNode() {
+ return logicalNode;
+ }
+
+ /**
+ * Sets the logical YANG augment node.
+ *
+ * @param logicalNode logical YANG augment
+ */
+ public void setLogicalNode(YangAugment logicalNode) {
+ this.logicalNode = logicalNode;
+ }
}
diff --git a/compiler/base/parser/src/main/java/org/onosproject/yang/compiler/parser/impl/listeners/AugmentListener.java b/compiler/base/parser/src/main/java/org/onosproject/yang/compiler/parser/impl/listeners/AugmentListener.java
index 4f77d69..dbe46a8 100644
--- a/compiler/base/parser/src/main/java/org/onosproject/yang/compiler/parser/impl/listeners/AugmentListener.java
+++ b/compiler/base/parser/src/main/java/org/onosproject/yang/compiler/parser/impl/listeners/AugmentListener.java
@@ -16,6 +16,7 @@
package org.onosproject.yang.compiler.parser.impl.listeners;
+import org.antlr.v4.runtime.Token;
import org.onosproject.yang.compiler.datamodel.YangAtomicPath;
import org.onosproject.yang.compiler.datamodel.YangAugment;
import org.onosproject.yang.compiler.datamodel.YangModule;
@@ -49,9 +50,12 @@
import static org.onosproject.yang.compiler.parser.impl.parserutils.ListenerErrorType.MISSING_CURRENT_HOLDER;
import static org.onosproject.yang.compiler.parser.impl.parserutils.ListenerErrorType.MISSING_HOLDER;
import static org.onosproject.yang.compiler.parser.impl.parserutils.ListenerErrorType.UNHANDLED_PARSED_DATA;
+import static org.onosproject.yang.compiler.parser.impl.parserutils.ListenerUtil.checkAugNameCollision;
import static org.onosproject.yang.compiler.parser.impl.parserutils.ListenerUtil.getPrefixRemovedName;
import static org.onosproject.yang.compiler.parser.impl.parserutils.ListenerUtil.getValidAbsoluteSchemaNodeId;
+import static org.onosproject.yang.compiler.parser.impl.parserutils.ListenerUtil.isDuplicateNode;
import static org.onosproject.yang.compiler.parser.impl.parserutils.ListenerUtil.parseUsesAugment;
+import static org.onosproject.yang.compiler.parser.impl.parserutils.ListenerUtil.removeAugment;
import static org.onosproject.yang.compiler.parser.impl.parserutils.ListenerUtil.removeQuotesAndHandleConcat;
import static org.onosproject.yang.compiler.parser.impl.parserutils.ListenerValidation.checkStackIsNotEmpty;
import static org.onosproject.yang.compiler.parser.impl.parserutils.ListenerValidation.validateCardinalityEitherOne;
@@ -141,6 +145,7 @@
augment.setName(removeQuotesAndHandleConcat(ctx.augment().getText()));
augment.setPrefixRemovedName(name);
+ checkAugNameCollision(root, augment);
try {
root.addChild(augment);
} catch (DataModelException e) {
@@ -149,11 +154,6 @@
ctx.augment().getText(), ENTRY, e.getMessage()));
}
listener.getParsedDataStack().push(augment);
-
- // Adds resolution info to the list
- YangResolutionInfoImpl<YangAugment> info =
- new YangResolutionInfoImpl<>(augment, root, line, pos);
- addToResolution(info, ctx);
}
/**
@@ -175,7 +175,19 @@
MISSING_CURRENT_HOLDER, AUGMENT_DATA,
ctx.augment().getText(), EXIT));
}
- listener.getParsedDataStack().pop();
+ YangAugment augment = (YangAugment) listener.getParsedDataStack().pop();
+
+ boolean isDup = isDuplicateNode(augment);
+ if (isDup) {
+ removeAugment(augment);
+ } else {
+ Token txt = ctx.getStart();
+ YangResolutionInfoImpl<YangAugment> info =
+ new YangResolutionInfoImpl<>(augment, augment.getParent(),
+ txt.getLine(),
+ txt.getCharPositionInLine());
+ addToResolution(info, ctx);
+ }
}
/**
diff --git a/compiler/base/parser/src/main/java/org/onosproject/yang/compiler/parser/impl/parserutils/ListenerUtil.java b/compiler/base/parser/src/main/java/org/onosproject/yang/compiler/parser/impl/parserutils/ListenerUtil.java
index aaadaf2..25ec87b 100644
--- a/compiler/base/parser/src/main/java/org/onosproject/yang/compiler/parser/impl/parserutils/ListenerUtil.java
+++ b/compiler/base/parser/src/main/java/org/onosproject/yang/compiler/parser/impl/parserutils/ListenerUtil.java
@@ -18,7 +18,10 @@
import org.antlr.v4.runtime.ParserRuleContext;
import org.onosproject.yang.compiler.datamodel.YangAtomicPath;
+import org.onosproject.yang.compiler.datamodel.YangAugment;
import org.onosproject.yang.compiler.datamodel.YangImport;
+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.YangModule;
import org.onosproject.yang.compiler.datamodel.YangNode;
@@ -29,9 +32,11 @@
import org.onosproject.yang.compiler.datamodel.YangRelativePath;
import org.onosproject.yang.compiler.datamodel.YangSubModule;
import org.onosproject.yang.compiler.datamodel.YangUniqueHolder;
+import org.onosproject.yang.compiler.datamodel.exceptions.DataModelException;
import org.onosproject.yang.compiler.datamodel.utils.YangConstructType;
import org.onosproject.yang.compiler.parser.antlrgencode.GeneratedYangParser.AugmentStatementContext;
import org.onosproject.yang.compiler.parser.exceptions.ParserException;
+import org.onosproject.yang.compiler.translator.tojava.javamodel.YangJavaAugmentTranslator;
import org.slf4j.Logger;
import java.text.ParseException;
@@ -51,6 +56,9 @@
import static org.onosproject.yang.compiler.datamodel.utils.YangConstructType.getYangConstructType;
import static org.onosproject.yang.compiler.parser.antlrgencode.GeneratedYangParser.PathStatementContext;
import static org.onosproject.yang.compiler.parser.antlrgencode.GeneratedYangParser.YangVersionStatementContext;
+import static org.onosproject.yang.compiler.parser.impl.parserutils.ListenerErrorLocation.ENTRY;
+import static org.onosproject.yang.compiler.parser.impl.parserutils.ListenerErrorMessageConstruction.constructExtendedListenerErrorMessage;
+import static org.onosproject.yang.compiler.parser.impl.parserutils.ListenerErrorType.UNHANDLED_PARSED_DATA;
import static org.onosproject.yang.compiler.utils.UtilConstants.ADD;
import static org.onosproject.yang.compiler.utils.UtilConstants.ANCESTOR;
import static org.onosproject.yang.compiler.utils.UtilConstants.AT;
@@ -1030,4 +1038,145 @@
}
return builder.toString();
}
+
+ /**
+ * Checks if the augment node is a duplicate node. If the augment is
+ * duplicate, then it adds all its children to the logical node.
+ *
+ * @param augment YANG augment
+ * @return true if it is a duplicate node; false otherwise
+ */
+ public static boolean isDuplicateNode(YangAugment augment) {
+ YangAugment logical = augment.getLogicalNode();
+ if (logical == null) {
+ return false;
+ }
+ YangNode lastChild = logical;
+
+ YangNode child = logical.getChild();
+ while (child != null) {
+ lastChild = child;
+ child = child.getNextSibling();
+ }
+ addChildToLogicalNode(logical, augment, lastChild);
+ addLeafAndLeafList(logical, augment);
+ return true;
+ }
+
+ /**
+ * Adds the child and its sibling in duplicate augment to the logical
+ * augment node.
+ *
+ * @param logical logical augment node
+ * @param augment YANG augment
+ * @param lastChild logical node's last node
+ */
+ private static void addChildToLogicalNode(YangAugment logical,
+ YangAugment augment,
+ YangNode lastChild) {
+ YangNode augChild = augment.getChild();
+ while (augChild != null) {
+ if (lastChild == logical) {
+ augChild.setParent(lastChild);
+ try {
+ lastChild.addChild(augChild);
+ } catch (DataModelException e) {
+ throw new ParserException(
+ constructExtendedListenerErrorMessage(
+ UNHANDLED_PARSED_DATA, AUGMENT_DATA,
+ augment.getName(), ENTRY, e.getMessage()));
+ }
+ } else {
+ augChild.setParent(lastChild.getParent());
+ augChild.setPreviousSibling(lastChild);
+ lastChild.setNextSibling(augChild);
+ }
+ lastChild = augChild;
+ augChild = augChild.getNextSibling();
+ }
+ }
+
+ /**
+ * Adds leaf and leaf-list from the YANG augment to the logical augment
+ * node.
+ *
+ * @param logical logical YANG augment
+ * @param augment duplicate YANG augment
+ */
+ private static void addLeafAndLeafList(YangAugment logical,
+ YangAugment augment) {
+
+ List<YangLeaf> logLeaves = logical.getListOfLeaf();
+ List<YangLeafList> logLl = logical.getListOfLeafList();
+ List<YangLeaf> augLeaves = augment.getListOfLeaf();
+ List<YangLeafList> augLl = augment.getListOfLeafList();
+
+ if (augLeaves != null && !augLeaves.isEmpty()) {
+ for (YangLeaf leaf : augLeaves) {
+ leaf.setContainedIn(logical);
+ if (logLeaves == null) {
+ logLeaves = new LinkedList<>();
+ }
+ logLeaves.add(leaf);
+ }
+ }
+ if (augLl != null && !augLl.isEmpty()) {
+ for (YangLeafList ll : augLl) {
+ ll.setContainedIn(logical);
+ if (logLl == null) {
+ logLl = new LinkedList<>();
+ }
+ logLl.add(ll);
+ }
+ }
+ }
+
+ /**
+ * Checks for the augment name name collision. If there are augments with
+ * the same name present, then the new augment will be set with a logical
+ * node.
+ *
+ * @param root augment parent node
+ * @param aug YANG augment node
+ */
+ public static void checkAugNameCollision(YangNode root, YangAugment aug) {
+ YangNode child = root.getChild();
+ while (child != null) {
+ if (child instanceof YangAugment) {
+ if (child.getName().equals(aug.getName())) {
+ aug.setLogicalNode((YangAugment) child);
+ }
+ }
+ child = child.getNextSibling();
+ }
+ }
+
+ /**
+ * Removes the duplicate YANG augment from the data tree by detaching it
+ * from its parent and from its sibling.
+ *
+ * @param augment duplicate YANG augment
+ */
+ public static void removeAugment(YangAugment augment) {
+ YangNode root = augment.getParent();
+ YangNode child = root.getChild();
+ YangNode pSib = null;
+ if (child == null) {
+ throw new ParserException("The root node of augment " + augment
+ .getName() + " must have atleast one child");
+ }
+ while (child != null) {
+ if (child == augment) {
+ if (pSib == null) {
+ root.setChild(null);
+ } else {
+ pSib.setNextSibling(null);
+ }
+ }
+ pSib = child;
+ child = child.getNextSibling();
+ }
+ augment = new YangJavaAugmentTranslator();
+ augment = null;
+ }
}
diff --git a/compiler/plugin/maven/src/test/java/org/onosproject/yang/compiler/plugin/maven/AugmentTranslatorTest.java b/compiler/plugin/maven/src/test/java/org/onosproject/yang/compiler/plugin/maven/AugmentTranslatorTest.java
index 156194e..97e2a86 100644
--- a/compiler/plugin/maven/src/test/java/org/onosproject/yang/compiler/plugin/maven/AugmentTranslatorTest.java
+++ b/compiler/plugin/maven/src/test/java/org/onosproject/yang/compiler/plugin/maven/AugmentTranslatorTest.java
@@ -435,4 +435,67 @@
YangPluginConfig.compileCode(COMP);
deleteDirectory(DIR);
}
+
+ /**
+ * Checks multiple augment handling which has the same name for open
+ * config YANG files.
+ *
+ * @throws IOException if any error occurs during IO on files
+ * @throws ParserException if any error occurs during parsing
+ * @throws MojoExecutionException if any mojo operation fails
+ */
+ @Test
+ public void processOpenConfigAugment() throws IOException,
+ ParserException, MojoExecutionException {
+
+ deleteDirectory(DIR);
+ String dir = "src/test/resources/augwithsamename/oc/";
+
+ Set<Path> paths = new HashSet<>();
+ for (String file : getYangFiles(dir)) {
+ paths.add(Paths.get(file));
+ }
+
+ utilManager.createYangFileInfoSet(paths);
+ utilManager.parseYangFileInfoSet();
+ utilManager.createYangNodeSet();
+ utilManager.resolveDependenciesUsingLinker();
+
+ YangPluginConfig yangPluginConfig = new YangPluginConfig();
+ yangPluginConfig.setCodeGenDir(DIR);
+ utilManager.translateToJava(yangPluginConfig);
+ YangPluginConfig.compileCode(COMP);
+ deleteDirectory(DIR);
+ }
+
+ /**
+ * Checks multiple augment handling which has the same name.
+ *
+ * @throws IOException if any error occurs during IO on files
+ * @throws ParserException if any error occurs during parsing
+ * @throws MojoExecutionException if any mojo operation fail
+ */
+ @Test
+ public void processSameAugName() throws IOException,
+ ParserException, MojoExecutionException {
+
+ deleteDirectory(DIR);
+ String dir = "src/test/resources/augwithsamename/multiaugwithsamename/";
+
+ Set<Path> paths = new HashSet<>();
+ for (String file : getYangFiles(dir)) {
+ paths.add(Paths.get(file));
+ }
+
+ utilManager.createYangFileInfoSet(paths);
+ utilManager.parseYangFileInfoSet();
+ utilManager.createYangNodeSet();
+ utilManager.resolveDependenciesUsingLinker();
+
+ YangPluginConfig yangPluginConfig = new YangPluginConfig();
+ yangPluginConfig.setCodeGenDir(DIR);
+ utilManager.translateToJava(yangPluginConfig);
+ YangPluginConfig.compileCode(COMP);
+ deleteDirectory(DIR);
+ }
}
diff --git a/compiler/plugin/maven/src/test/resources/augwithsamename/multiaugwithsamename/module1.yang b/compiler/plugin/maven/src/test/resources/augwithsamename/multiaugwithsamename/module1.yang
new file mode 100644
index 0000000..fedf735
--- /dev/null
+++ b/compiler/plugin/maven/src/test/resources/augwithsamename/multiaugwithsamename/module1.yang
@@ -0,0 +1,14 @@
+module module1 {
+
+ namespace "urn:ietf:params:xml:ns:aug:module:1";
+
+ prefix mod-a;
+
+ container cont{
+ container val {
+ leaf-list create {
+ type string;
+ }
+ }
+ }
+}
diff --git a/compiler/plugin/maven/src/test/resources/augwithsamename/multiaugwithsamename/module2.yang b/compiler/plugin/maven/src/test/resources/augwithsamename/multiaugwithsamename/module2.yang
new file mode 100644
index 0000000..7ec09aa
--- /dev/null
+++ b/compiler/plugin/maven/src/test/resources/augwithsamename/multiaugwithsamename/module2.yang
@@ -0,0 +1,39 @@
+module module2 {
+
+ namespace "urn:ietf:params:xml:ns:aug:module:2";
+
+ prefix mod-b;
+
+ import module1 {
+ prefix mod-a;
+ }
+
+ augment "/mod-a:cont/mod-a:val" {
+ leaf arg {
+ type string;
+ }
+ }
+
+ augment "/mod-a:cont/mod-a:val" {
+ leaf-list arg-lis {
+ type string;
+ }
+ }
+
+ augment "/mod-a:cont/mod-a:val" {
+ container cont {
+ leaf ll {
+ type binary;
+ }
+ }
+ }
+
+ augment "/mod-a:cont/mod-a:val" {
+ list contlist {
+ key true;
+ leaf true {
+ type boolean;
+ }
+ }
+ }
+}
diff --git a/compiler/plugin/maven/src/test/resources/augwithsamename/oc/openconfig-if-ip.yang b/compiler/plugin/maven/src/test/resources/augwithsamename/oc/openconfig-if-ip.yang
new file mode 100644
index 0000000..1c7a8ce
--- /dev/null
+++ b/compiler/plugin/maven/src/test/resources/augwithsamename/oc/openconfig-if-ip.yang
@@ -0,0 +1,69 @@
+module openconfig-if-ip {
+
+ yang-version "1";
+
+ namespace "http://openconfig.net/yang/interfaces/ip";
+
+ prefix "oc-ip";
+
+ import openconfig-interfaces {
+ prefix oc-if;
+ }
+
+ grouping ip-vrrp-top {
+ container vrrp {
+ list vrrp-group {
+ key "virtual-router-id";
+ leaf virtual-router-id {
+ type string;
+ }
+ }
+ }
+ }
+
+ grouping ipv4-top {
+ container ipv4 {
+ container addresses {
+ list address {
+ key "ip";
+ leaf ip {
+ type string;
+ }
+ }
+ }
+ }
+ }
+
+ grouping ipv6-top {
+ container ipv6 {
+ container addresses {
+ list address {
+ key "ip";
+ leaf ip {
+ type string;
+ }
+ }
+ }
+ }
+ }
+
+ augment "/oc-if:interfaces/oc-if:interface/oc-if:subinterfaces/" +
+ "oc-if:subinterface" {
+ uses ipv4-top;
+ }
+
+ augment "/oc-if:interfaces/oc-if:interface/oc-if:subinterfaces/" +
+ "oc-if:subinterface" {
+ uses ipv6-top;
+ }
+
+ augment "/oc-if:interfaces/oc-if:interface/oc-if:subinterfaces/" +
+ "oc-if:subinterface/oc-ip:ipv4/oc-ip:addresses/oc-ip:address" {
+ uses ip-vrrp-top;
+ }
+
+ augment "/oc-if:interfaces/oc-if:interface/oc-if:subinterfaces/" +
+ "oc-if:subinterface/oc-ip:ipv6/oc-ip:addresses/oc-ip:address" {
+ uses ip-vrrp-top;
+ }
+}
diff --git a/compiler/plugin/maven/src/test/resources/augwithsamename/oc/openconfig-interfaces.yang b/compiler/plugin/maven/src/test/resources/augwithsamename/oc/openconfig-interfaces.yang
new file mode 100644
index 0000000..2804dc6
--- /dev/null
+++ b/compiler/plugin/maven/src/test/resources/augwithsamename/oc/openconfig-interfaces.yang
@@ -0,0 +1,42 @@
+module openconfig-interfaces {
+
+ yang-version "1";
+
+ namespace "http://openconfig.net/yang/interfaces";
+
+ prefix "oc-if";
+
+ contact
+ "OpenConfig working group
+ netopenconfig@googlegroups.com";
+
+ grouping subinterfaces-top {
+ container subinterfaces {
+ list subinterface {
+ key "index";
+ leaf index {
+ type int8;
+ }
+ }
+ }
+ }
+
+ grouping interfaces-top {
+ description
+ "Top-level grouping for interface configuration and
+ operational state data";
+
+ container interfaces {
+ list interface {
+ key "name";
+
+ leaf name {
+ type string;
+ }
+ uses subinterfaces-top;
+ }
+ }
+ }
+
+ uses interfaces-top;
+}