Vidyashree Rama
Committed by Gerrit Code Review

YANG augment listener

Change-Id: I11ece665a7627d784f82247d5a33e3453632d0f9
......@@ -22,6 +22,8 @@ import org.onosproject.yangutils.datamodel.exceptions.DataModelException;
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 @@ import org.onosproject.yangutils.utils.YangConstructType;
* 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 @@ public class YangAugment extends YangNode
private List<YangLeafList> listOfLeafList;
/**
* List of node identifiers.
*/
private List<YangNodeIdentifier> targetNode;
/**
* Reference of the YANG augment.
*/
private String reference;
......@@ -121,17 +128,17 @@ public class YangAugment extends YangNode
*
* @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 @@ public class YangAugment extends YangNode
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 @@ public class YangAugment extends YangNode
*/
@Override
public String getName() {
return targetNode;
return name;
}
/**
......@@ -307,7 +328,7 @@ public class YangAugment extends YangNode
*/
@Override
public void setName(String name) {
targetNode = name;
this.name = name;
}
......
......@@ -25,6 +25,7 @@ import org.onosproject.yangutils.datamodel.YangNode;
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 @@ public class TreeWalkListener implements GeneratedYangListener {
@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
......
/*
* 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());
}
}
......@@ -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 @@ public final class ListenerUtil {
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 @@ public final class ListenerUtil {
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
......
......@@ -1055,7 +1055,7 @@ package org.onosproject.yangutils.parser.antlrgencode;
* "}"
* 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;
/**
......
/*
* 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));
}
}
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;
}
}
}