YANG augment listener
Change-Id: I11ece665a7627d784f82247d5a33e3453632d0f9
diff --git a/utils/yangutils/src/main/java/org/onosproject/yangutils/datamodel/YangAugment.java b/utils/yangutils/src/main/java/org/onosproject/yangutils/datamodel/YangAugment.java
index b2bd1ef..efe2561 100644
--- a/utils/yangutils/src/main/java/org/onosproject/yangutils/datamodel/YangAugment.java
+++ b/utils/yangutils/src/main/java/org/onosproject/yangutils/datamodel/YangAugment.java
@@ -22,6 +22,8 @@
import org.onosproject.yangutils.parser.Parsable;
import org.onosproject.yangutils.utils.YangConstructType;
+import static org.onosproject.yangutils.datamodel.utils.DataModelUtils.detectCollidingChildUtil;
+
/*-
* Reference RFC 6020.
*
@@ -77,12 +79,12 @@
* Data model node to maintain information defined in YANG augment.
*/
public class YangAugment extends YangNode
- implements YangLeavesHolder, YangCommonInfo, Parsable {
+ implements YangLeavesHolder, YangCommonInfo, Parsable, CollisionDetector {
/**
* Augment target node.
*/
- private String targetNode;
+ private String name;
/**
* Description of augment.
@@ -100,6 +102,11 @@
private List<YangLeafList> listOfLeafList;
/**
+ * List of node identifiers.
+ */
+ private List<YangNodeIdentifier> targetNode;
+
+ /**
* Reference of the YANG augment.
*/
private String reference;
@@ -121,17 +128,17 @@
*
* @return the augmented node
*/
- public String getTargetNode() {
+ public List<YangNodeIdentifier> getTargetNode() {
return targetNode;
}
/**
* Set the augmented node.
*
- * @param targetNode the augmented node
+ * @param nodeIdentifiers the augmented node
*/
- public void setTargetNode(String targetNode) {
- this.targetNode = targetNode;
+ public void setTargetNode(List<YangNodeIdentifier> nodeIdentifiers) {
+ this.targetNode = nodeIdentifiers;
}
/**
@@ -154,6 +161,20 @@
this.description = description;
}
+ @Override
+ public void detectCollidingChild(String identifierName, YangConstructType dataType) throws DataModelException {
+ // Detect colliding child.
+ detectCollidingChildUtil(identifierName, dataType, this);
+ }
+
+ @Override
+ public void detectSelfCollision(String identifierName, YangConstructType dataType) throws DataModelException {
+ if (this.getName().equals(identifierName)) {
+ throw new DataModelException("YANG file error: Duplicate input identifier detected, same as input \""
+ + this.getName() + "\"");
+ }
+ }
+
/**
* Get the list of leaves.
*
@@ -297,7 +318,7 @@
*/
@Override
public String getName() {
- return targetNode;
+ return name;
}
/**
@@ -307,7 +328,7 @@
*/
@Override
public void setName(String name) {
- targetNode = name;
+ this.name = name;
}
diff --git a/utils/yangutils/src/main/java/org/onosproject/yangutils/parser/impl/TreeWalkListener.java b/utils/yangutils/src/main/java/org/onosproject/yangutils/parser/impl/TreeWalkListener.java
index 029a4d7..473ee0e 100644
--- a/utils/yangutils/src/main/java/org/onosproject/yangutils/parser/impl/TreeWalkListener.java
+++ b/utils/yangutils/src/main/java/org/onosproject/yangutils/parser/impl/TreeWalkListener.java
@@ -25,6 +25,7 @@
import org.onosproject.yangutils.parser.Parsable;
import org.onosproject.yangutils.parser.antlrgencode.GeneratedYangListener;
import org.onosproject.yangutils.parser.antlrgencode.GeneratedYangParser;
+import org.onosproject.yangutils.parser.impl.listeners.AugmentListener;
import org.onosproject.yangutils.parser.impl.listeners.BaseFileListener;
import org.onosproject.yangutils.parser.impl.listeners.BelongsToListener;
import org.onosproject.yangutils.parser.impl.listeners.BitListener;
@@ -1041,12 +1042,12 @@
@Override
public void enterAugmentStatement(GeneratedYangParser.AugmentStatementContext ctx) {
- // TODO: implement the method.
+ AugmentListener.processAugmentEntry(this, ctx);
}
@Override
public void exitAugmentStatement(GeneratedYangParser.AugmentStatementContext ctx) {
- // TODO: implement the method.
+ AugmentListener.processAugmentExit(this, ctx);
}
@Override
diff --git a/utils/yangutils/src/main/java/org/onosproject/yangutils/parser/impl/listeners/AugmentListener.java b/utils/yangutils/src/main/java/org/onosproject/yangutils/parser/impl/listeners/AugmentListener.java
new file mode 100644
index 0000000..d332ab9
--- /dev/null
+++ b/utils/yangutils/src/main/java/org/onosproject/yangutils/parser/impl/listeners/AugmentListener.java
@@ -0,0 +1,166 @@
+/*
+ * Copyright 2016 Open Networking Laboratory
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.onosproject.yangutils.parser.impl.listeners;
+
+import java.util.List;
+import org.onosproject.yangutils.datamodel.YangAugment;
+import org.onosproject.yangutils.datamodel.YangNode;
+import org.onosproject.yangutils.datamodel.YangModule;
+import org.onosproject.yangutils.datamodel.YangSubModule;
+import org.onosproject.yangutils.datamodel.YangNodeIdentifier;
+import org.onosproject.yangutils.datamodel.exceptions.DataModelException;
+import org.onosproject.yangutils.parser.Parsable;
+import org.onosproject.yangutils.parser.antlrgencode.GeneratedYangParser;
+import org.onosproject.yangutils.parser.exceptions.ParserException;
+import org.onosproject.yangutils.parser.impl.TreeWalkListener;
+
+import static org.onosproject.yangutils.datamodel.utils.GeneratedLanguage.JAVA_GENERATION;
+import static org.onosproject.yangutils.datamodel.utils.YangDataModelFactory.getYangAugmentNode;
+import static org.onosproject.yangutils.parser.impl.parserutils.ListenerCollisionDetector.detectCollidingChildUtil;
+import static org.onosproject.yangutils.parser.impl.parserutils.ListenerErrorLocation.ENTRY;
+import static org.onosproject.yangutils.parser.impl.parserutils.ListenerErrorLocation.EXIT;
+import static org.onosproject.yangutils.parser.impl.parserutils.ListenerErrorMessageConstruction.constructExtendedListenerErrorMessage;
+import static org.onosproject.yangutils.parser.impl.parserutils.ListenerErrorMessageConstruction.constructListenerErrorMessage;
+import static org.onosproject.yangutils.parser.impl.parserutils.ListenerErrorType.MISSING_CURRENT_HOLDER;
+import static org.onosproject.yangutils.parser.impl.parserutils.ListenerErrorType.MISSING_HOLDER;
+import static org.onosproject.yangutils.parser.impl.parserutils.ListenerErrorType.UNHANDLED_PARSED_DATA;
+import static org.onosproject.yangutils.parser.impl.parserutils.ListenerErrorType.INVALID_HOLDER;
+import static org.onosproject.yangutils.parser.impl.parserutils.ListenerValidation.checkStackIsNotEmpty;
+import static org.onosproject.yangutils.parser.impl.parserutils.ListenerValidation.validateCardinalityMaxOne;
+import static org.onosproject.yangutils.parser.impl.parserutils.ListenerValidation.validateMutuallyExclusiveChilds;
+import static org.onosproject.yangutils.parser.impl.parserutils.ListenerUtil.getValidAbsoluteSchemaNodeId;
+import static org.onosproject.yangutils.utils.YangConstructType.AUGMENT_DATA;
+import static org.onosproject.yangutils.utils.YangConstructType.DATA_DEF_DATA;
+import static org.onosproject.yangutils.utils.YangConstructType.STATUS_DATA;
+import static org.onosproject.yangutils.utils.YangConstructType.REFERENCE_DATA;
+import static org.onosproject.yangutils.utils.YangConstructType.DESCRIPTION_DATA;
+import static org.onosproject.yangutils.utils.YangConstructType.WHEN_DATA;
+import static org.onosproject.yangutils.utils.YangConstructType.CASE_DATA;
+
+/*
+ * Reference: RFC6020 and YANG ANTLR Grammar
+ *
+ * ABNF grammar as per RFC6020
+ * augment-stmt = augment-keyword sep augment-arg-str optsep
+ * "{" stmtsep
+ * ;; these stmts can appear in any order
+ * [when-stmt stmtsep]
+ * *(if-feature-stmt stmtsep)
+ * [status-stmt stmtsep]
+ * [description-stmt stmtsep]
+ * [reference-stmt stmtsep]
+ * 1*((data-def-stmt stmtsep) /
+ * (case-stmt stmtsep))
+ * "}"
+ *
+ * ANTLR grammar rule
+ * augmentStatement : AUGMENT_KEYWORD augment LEFT_CURLY_BRACE (whenStatement | ifFeatureStatement | statusStatement
+ * | descriptionStatement | referenceStatement | dataDefStatement | caseStatement)* RIGHT_CURLY_BRACE;
+ */
+
+/**
+ * Implements listener based call back function corresponding to the "augment"
+ * rule defined in ANTLR grammar file for corresponding ABNF rule in RFC 6020.
+ */
+public final class AugmentListener {
+
+ /**
+ * Creates a new augment listener.
+ */
+ private AugmentListener() {
+ }
+
+ /**
+ * It is called when parser receives an input matching the grammar rule
+ * (augment), performs validation and updates the data model tree.
+ *
+ * @param listener listener's object
+ * @param ctx context object of the grammar rule
+ */
+ public static void processAugmentEntry(TreeWalkListener listener,
+ GeneratedYangParser.AugmentStatementContext ctx) {
+
+ // Check for stack to be non empty.
+ checkStackIsNotEmpty(listener, MISSING_HOLDER, AUGMENT_DATA, ctx.augment().getText(), ENTRY);
+
+ // Validate augment argument string
+ List<YangNodeIdentifier> targetNodes = getValidAbsoluteSchemaNodeId(ctx.augment().getText(),
+ AUGMENT_DATA, ctx);
+
+ // Validate sub statement cardinality.
+ validateSubStatementsCardinality(ctx);
+
+ // Check for identifier collision
+ int line = ctx.getStart().getLine();
+ int charPositionInLine = ctx.getStart().getCharPositionInLine();
+ detectCollidingChildUtil(listener, line, charPositionInLine, "", AUGMENT_DATA);
+
+ Parsable curData = listener.getParsedDataStack().peek();
+ if (curData instanceof YangModule || curData instanceof YangSubModule) {
+
+ YangNode curNode = (YangNode) curData;
+ YangAugment yangAugment = getYangAugmentNode(JAVA_GENERATION);
+ yangAugment.setTargetNode(targetNodes);
+ try {
+ curNode.addChild(yangAugment);
+ } catch (DataModelException e) {
+ throw new ParserException(constructExtendedListenerErrorMessage(UNHANDLED_PARSED_DATA,
+ AUGMENT_DATA, ctx.augment().getText(), ENTRY, e.getMessage()));
+ }
+ listener.getParsedDataStack().push(yangAugment);
+ } else {
+ throw new ParserException(constructListenerErrorMessage(INVALID_HOLDER, AUGMENT_DATA,
+ ctx.augment().getText(), ENTRY));
+ }
+
+ }
+
+ /**
+ * It is called when parser exits from grammar rule (augment), it perform
+ * validations and updates the data model tree.
+ *
+ * @param listener listener's object
+ * @param ctx context object of the grammar rule
+ */
+ public static void processAugmentExit(TreeWalkListener listener,
+ GeneratedYangParser.AugmentStatementContext ctx) {
+
+ //Check for stack to be non empty.
+ checkStackIsNotEmpty(listener, MISSING_HOLDER, AUGMENT_DATA, ctx.augment().getText(), EXIT);
+
+ if (!(listener.getParsedDataStack().peek() instanceof YangAugment)) {
+ throw new ParserException(constructListenerErrorMessage(MISSING_CURRENT_HOLDER, AUGMENT_DATA,
+ ctx.augment().getText(), EXIT));
+ }
+ listener.getParsedDataStack().pop();
+ }
+
+ /**
+ * Validates the cardinality of augment sub-statements as per grammar.
+ *
+ * @param ctx context object of the grammar rule
+ */
+ private static void validateSubStatementsCardinality(GeneratedYangParser.AugmentStatementContext ctx) {
+
+ validateCardinalityMaxOne(ctx.statusStatement(), STATUS_DATA, AUGMENT_DATA, ctx.augment().getText());
+ validateCardinalityMaxOne(ctx.descriptionStatement(), DESCRIPTION_DATA, AUGMENT_DATA, ctx.augment().getText());
+ validateCardinalityMaxOne(ctx.referenceStatement(), REFERENCE_DATA, AUGMENT_DATA, ctx.augment().getText());
+ validateCardinalityMaxOne(ctx.whenStatement(), WHEN_DATA, AUGMENT_DATA, ctx.augment().getText());
+ validateMutuallyExclusiveChilds(ctx.dataDefStatement(), DATA_DEF_DATA, ctx.caseStatement(),
+ CASE_DATA, AUGMENT_DATA, ctx.augment().getText());
+ }
+}
diff --git a/utils/yangutils/src/main/java/org/onosproject/yangutils/parser/impl/parserutils/ListenerUtil.java b/utils/yangutils/src/main/java/org/onosproject/yangutils/parser/impl/parserutils/ListenerUtil.java
index 8c3f36f..7b297f2 100644
--- a/utils/yangutils/src/main/java/org/onosproject/yangutils/parser/impl/parserutils/ListenerUtil.java
+++ b/utils/yangutils/src/main/java/org/onosproject/yangutils/parser/impl/parserutils/ListenerUtil.java
@@ -16,13 +16,14 @@
package org.onosproject.yangutils.parser.impl.parserutils;
-import org.antlr.v4.runtime.ParserRuleContext;
-
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.Calendar;
+import java.util.LinkedList;
+import java.util.List;
import java.util.regex.Pattern;
+import org.antlr.v4.runtime.ParserRuleContext;
import org.onosproject.yangutils.datamodel.YangNodeIdentifier;
import org.onosproject.yangutils.parser.antlrgencode.GeneratedYangParser;
import org.onosproject.yangutils.utils.YangConstructType;
@@ -45,6 +46,7 @@
private static final String SLASH = "/";
private static final String SPACE = " ";
private static final String COLON = ":";
+ private static final String CARET = "^";
/**
* Creates a new listener util.
@@ -237,4 +239,36 @@
throw parserException;
}
}
+
+ /**
+ * Checks and return valid absolute schema node id.
+ *
+ * @param argumentString string from yang file
+ * @param yangConstructType yang construct for creating error message
+ * @param ctx yang construct's context to get the line number and character position
+ * @return target nodes list of absolute schema node id
+ */
+ public static List<YangNodeIdentifier> getValidAbsoluteSchemaNodeId(String argumentString,
+ YangConstructType yangConstructType, ParserRuleContext ctx) {
+
+ List<YangNodeIdentifier> targetNodes = new LinkedList<>();
+ YangNodeIdentifier yangNodeIdentifier;
+ String tmpSchemaNodeId = removeQuotesAndHandleConcat(argumentString);
+
+ // absolute-schema-nodeid = 1*("/" node-identifier)
+ if (!tmpSchemaNodeId.startsWith(SLASH)) {
+ ParserException parserException = new ParserException("YANG file error : " +
+ YangConstructType.getYangConstructType(yangConstructType) + " name " + argumentString +
+ "is not valid");
+ parserException.setLine(ctx.getStart().getLine());
+ parserException.setCharPosition(ctx.getStart().getCharPositionInLine());
+ throw parserException;
+ }
+ String[] tmpData = tmpSchemaNodeId.replaceFirst(CARET + SLASH, EMPTY_STRING).split(SLASH);
+ for (String nodeIdentifiers : tmpData) {
+ yangNodeIdentifier = getValidNodeIdentifier(nodeIdentifiers, yangConstructType, ctx);
+ targetNodes.add(yangNodeIdentifier);
+ }
+ return targetNodes;
+ }
}
\ No newline at end of file
diff --git a/utils/yangutils/src/main/resources/GeneratedYang.g4 b/utils/yangutils/src/main/resources/GeneratedYang.g4
index 3fc0f9a..a0e4468 100644
--- a/utils/yangutils/src/main/resources/GeneratedYang.g4
+++ b/utils/yangutils/src/main/resources/GeneratedYang.g4
@@ -1055,7 +1055,7 @@
* "}"
* TODO : 0..1 occurance to be checked in listener
*/
- augmentStatement : AUGMENT_KEYWORD string LEFT_CURLY_BRACE (whenStatement | ifFeatureStatement | statusStatement
+ augmentStatement : AUGMENT_KEYWORD augment LEFT_CURLY_BRACE (whenStatement | ifFeatureStatement | statusStatement
| descriptionStatement | referenceStatement | dataDefStatement | caseStatement)* RIGHT_CURLY_BRACE;
/**
diff --git a/utils/yangutils/src/test/java/org/onosproject/yangutils/parser/impl/listeners/AugmentListenerTest.java b/utils/yangutils/src/test/java/org/onosproject/yangutils/parser/impl/listeners/AugmentListenerTest.java
new file mode 100644
index 0000000..2173183
--- /dev/null
+++ b/utils/yangutils/src/test/java/org/onosproject/yangutils/parser/impl/listeners/AugmentListenerTest.java
@@ -0,0 +1,72 @@
+/*
+ * Copyright 2016 Open Networking Laboratory
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.onosproject.yangutils.parser.impl.listeners;
+
+import java.io.IOException;
+import java.util.ListIterator;
+
+import org.junit.Test;
+import org.onosproject.yangutils.datamodel.YangNode;
+import org.onosproject.yangutils.datamodel.YangModule;
+import org.onosproject.yangutils.datamodel.YangAugment;
+import org.onosproject.yangutils.datamodel.YangLeaf;
+import org.onosproject.yangutils.datamodel.YangNodeIdentifier;
+import org.onosproject.yangutils.datamodel.YangDataTypes;
+import org.onosproject.yangutils.datamodel.YangNodeType;
+import org.onosproject.yangutils.parser.exceptions.ParserException;
+import org.onosproject.yangutils.parser.impl.YangUtilsParserManager;
+
+import static org.hamcrest.core.Is.is;
+import static org.junit.Assert.assertThat;
+
+/**
+ * Test cases for testing augment listener functionality.
+ */
+public class AugmentListenerTest {
+
+ private final YangUtilsParserManager manager = new YangUtilsParserManager();
+
+ /**
+ * Checks valid augment statement.
+ */
+ @Test
+ public void processValidAugmentStatement() throws IOException, ParserException {
+
+ YangNode node = manager.getDataModel("src/test/resources/ValidAugmentStatement.yang");
+
+ assertThat((node instanceof YangModule), is(true));
+ assertThat(node.getNodeType(), is(YangNodeType.MODULE_NODE));
+ YangModule yangNode = (YangModule) node;
+ assertThat(yangNode.getName(), is("Test"));
+
+ YangAugment yangAugment = (YangAugment) yangNode.getChild();
+ if (yangAugment.getTargetNode().isEmpty()) {
+ System.out.println("list is empty");
+ }
+ ListIterator<YangNodeIdentifier> nodeIdentifierIterator = yangAugment.getTargetNode().listIterator();
+ YangNodeIdentifier yangNodeIdentifier = nodeIdentifierIterator.next();
+ assertThat(yangNodeIdentifier.getPrefix(), is("if"));
+ assertThat(yangNodeIdentifier.getName(), is("interfaces"));
+
+ ListIterator<YangLeaf> leafIterator = yangAugment.getListOfLeaf().listIterator();
+ YangLeaf leafInfo = leafIterator.next();
+
+ assertThat(leafInfo.getLeafName(), is("ds0ChannelNumber"));
+ assertThat(leafInfo.getDataType().getDataTypeName(), is("ChannelNumber"));
+ assertThat(leafInfo.getDataType().getDataType(), is(YangDataTypes.DERIVED));
+ }
+}
diff --git a/utils/yangutils/src/test/resources/ValidAugmentStatement.yang b/utils/yangutils/src/test/resources/ValidAugmentStatement.yang
new file mode 100644
index 0000000..59ebe67
--- /dev/null
+++ b/utils/yangutils/src/test/resources/ValidAugmentStatement.yang
@@ -0,0 +1,15 @@
+module Test {
+ yang-version 1;
+ namespace http://example.com/schema/ds0;
+ prefix On;
+
+ import interface-module {
+ prefix "if";
+ }
+ augment "/if:interfaces/if:ifEntry" {
+ when "if:ifType='ds0'";
+ leaf ds0ChannelNumber {
+ type P:ChannelNumber;
+ }
+ }
+}