Gaurav Agrawal
Committed by Gerrit Code Review

[ONOS-3878, 3876, 3879] Yang Parser Manager with Stack and Error Validation

Change-Id: I10e68bd676eca4d576de1234fbb67026c7b49939
/*
* 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;
import org.antlr.v4.runtime.ANTLRFileStream;
import org.antlr.v4.runtime.ANTLRInputStream;
import org.antlr.v4.runtime.CommonTokenStream;
import org.antlr.v4.runtime.tree.ParseTree;
import org.antlr.v4.runtime.tree.ParseTreeWalker;
import org.onosproject.yangutils.datamodel.YangNode;
import org.onosproject.yangutils.parser.YangUtilsParser;
import org.onosproject.yangutils.parser.antlrgencode.GeneratedYangLexer;
import org.onosproject.yangutils.parser.antlrgencode.GeneratedYangParser;
import org.onosproject.yangutils.parser.exceptions.ParserException;
import org.onosproject.yangutils.parser.impl.parserutils.ParseTreeErrorListener;
import java.io.IOException;
/**
* Manages file parsing, parse tree creation and data model tree creation
* corresponding to an input YANG file.
*/
public class YangUtilsParserManager implements YangUtilsParser {
@Override
public YangNode getDataModel(String yangFile) throws IOException, ParserException {
/**
* Create a char stream that reads from YANG file. Throws an exception
* in case input YANG file is either null or non existent.
*/
ANTLRInputStream input = null;
try {
input = new ANTLRFileStream(yangFile);
} catch (IOException e) {
e.printStackTrace();
throw e;
}
// Create a lexer that feeds off of input char stream.
GeneratedYangLexer lexer = new GeneratedYangLexer(input);
// Create a buffer of tokens pulled from the lexer.
CommonTokenStream tokens = new CommonTokenStream(lexer);
// Create a parser that feeds off the tokens buffer.
GeneratedYangParser parser = new GeneratedYangParser(tokens);
// Remove console error listener.
parser.removeErrorListeners();
// Create instance of customized error listener.
ParseTreeErrorListener parseTreeErrorListener = new ParseTreeErrorListener();
// Add customized error listener to catch errors during parsing.
parser.addErrorListener(parseTreeErrorListener);
// Begin parsing YANG file and generate parse tree.
ParseTree tree = parser.yangfile();
/**
* Throws an parser Exception if exception flag is set i.e. exception has
* occurred during parsing.
*/
if (parseTreeErrorListener.isExceptionFlag()) {
// Get the exception occurred during parsing.
ParserException parserException = parseTreeErrorListener.getParserException();
parserException.setFileName(yangFile);
throw parserException;
}
// Create a walker to walk the parse tree.
ParseTreeWalker walker = new ParseTreeWalker();
// Create a listener implementation class object.
TreeWalkListener treeWalker = new TreeWalkListener();
/**
* Walk parse tree, provide call backs to methods in listener and
* build data model tree.
*/
walker.walk(treeWalker, tree);
// Throws an parser exception which has occurred during listener walk.
if (treeWalker.getErrorInformation().isErrorFlag()) {
// Create object of listener exception
ParserException listenerException = new ParserException();
listenerException.setMsg(treeWalker.getErrorInformation().getErrorMsg());
listenerException.setFileName(yangFile);
throw listenerException;
}
// Returns the Root Node of the constructed data model tree.
return treeWalker.getRootNode();
}
}
/*
* 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.parserutils;
import org.onosproject.yangutils.parser.impl.TreeWalkListener;
/**
* Its a utility to carry out listener validation.
*/
public final class ListenerValidation {
/**
* Creates a new belongto listener.
*/
private ListenerValidation() {
}
/**
* Checks if error is set or parsed data stack is empty.
*
* @param listener Listener's object.
* @param errNode parsable node for which validation needs to be done.
* @return validation result.
*/
public static boolean preValidation(TreeWalkListener listener, String errNode) {
// Check whether error found while walking YANG file, if yes return true.
if (listener.getErrorInformation().isErrorFlag()) {
return true;
}
// If stack is empty it indicates error condition
if (listener.getParsedDataStack().empty()) {
listener.getErrorInformation().setErrorFlag(true);
listener.getErrorInformation().setErrorMsg("Parsable stack empty at" + errNode + "entry");
return true;
}
return false;
}
}
\ No newline at end of file
/*
* 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.parserutils;
import org.antlr.v4.runtime.BaseErrorListener;
import org.antlr.v4.runtime.RecognitionException;
import org.antlr.v4.runtime.Recognizer;
import org.onosproject.yangutils.parser.exceptions.ParserException;
/**
* By default, ANTLR sends all errors to standard error, this is changed by
* providing this new implementation of interface ANTLRErrorListener. The
* interface has a syntaxError() method that applies to both lexer and
* parser.
*/
public class ParseTreeErrorListener extends BaseErrorListener {
// Exception of type parser exceptions are catched during parsing.
private ParserException parserException = new ParserException();
// Flag to indicate presence of exception.
private boolean exceptionFlag = false;
/**
* Returns the status of exception flag.
*
* @return flag which contains the status of exception.
*/
public boolean isExceptionFlag() {
return exceptionFlag;
}
/**
* Returns the parser exception object populated with line, character
* position and message.
*
* @return object of parser exception.
*/
public ParserException getParserException() {
return parserException;
}
@Override
public void syntaxError(Recognizer<?, ?> recognizer, Object offendingSymbol, int line, int charPositionInLine,
String msg, RecognitionException e) {
parserException.setLine(line);
parserException.setCharPosition(charPositionInLine);
parserException.setMsg(msg);
exceptionFlag = true;
}
}
\ No newline at end of file
/*
* 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;
import org.junit.After;
import org.junit.Before;
import org.junit.Test;
import org.onosproject.yangutils.datamodel.YangNode;
import org.onosproject.yangutils.parser.exceptions.ParserException;
import java.io.BufferedWriter;
import java.io.File;
import java.io.FileWriter;
import java.io.IOException;
/**
* Test case for testing YANG utils parser manager.
*/
public class YangUtilsParserManagerTest {
YangUtilsParserManager manager = new YangUtilsParserManager();
File file;
BufferedWriter out;
@Before
public void setUp() throws Exception {
file = new File("demo.yang");
out = new BufferedWriter(new FileWriter(file));
}
@After
public void tearDown() throws Exception {
file.delete();
}
/**
* This test case checks whether the null pointer exception is generated
* when the input YANG file is null.
*/
@Test(expected = NullPointerException.class)
public void getDataModelNullFileTest() throws IOException, ParserException {
YangUtilsParserManager manager = new YangUtilsParserManager();
YangNode node = manager.getDataModel(null);
}
/**
* This test case checks whether the io exception is generated
* when the input YANG file is non existent.
*/
@Test(expected = IOException.class)
public void getDataModelNonExistentFileTest() throws IOException, ParserException {
YangUtilsParserManager manager = new YangUtilsParserManager();
YangNode node = manager.getDataModel("nonexistent.yang");
}
/**
* This test case checks if the input YANG file is correct no exception
* should be generated.
*/
@Test
public void getDataModelCorrectFileTest() throws IOException, ParserException {
out.write("module ONOS {\n");
out.write("yang-version 1;\n");
out.write("namespace urn:ietf:params:xml:ns:yang:ietf-ospf;\n");
out.write("prefix On;\n");
out.write("}\n");
out.close();
YangNode node = manager.getDataModel("demo.yang");
}
/**
* This test case checks if the input YANG file with wrong YANG constructs
* than parser exception should be generated.
*/
@Test(expected = ParserException.class)
public void getDataModelIncorrectFileTest() throws IOException, ParserException {
out.write("module ONOS {\n");
out.write("yang-version 1\n");
out.write("namespace urn:ietf:params:xml:ns:yang:ietf-ospf;\n");
out.write("prefix On;\n");
out.write("}\n");
out.close();
YangNode node = manager.getDataModel("demo.yang");
}
}
\ No newline at end of file
/*
* 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.parseutils;
import org.junit.Test;
import org.onosproject.yangutils.datamodel.YangRevision;
import org.onosproject.yangutils.parser.impl.TreeWalkListener;
import org.onosproject.yangutils.parser.impl.parserutils.ListenerError;
import org.onosproject.yangutils.parser.impl.parserutils.ListenerValidation;
import static org.hamcrest.core.Is.is;
import static org.junit.Assert.assertThat;
/**
* Test case for testing listener validation util.
*/
public class ListenerValidationTest {
/**
* This test case checks in case error pre-exists, listener validate
* function returns true.
*/
@Test
public void listenerValidationErrorExists() {
// Create an test error.
ListenerError testError = new ListenerError();
testError.setErrorFlag(true);
testError.setErrorMsg("Test Error");
// Create test walker and assign test error to it.
TreeWalkListener testWalker = new TreeWalkListener();
testWalker.setErrorInformation(testError);
// Create a temporary node of parsable.
YangRevision tmpNode = new YangRevision();
testWalker.getParsedDataStack().push(tmpNode);
boolean errorFlag = ListenerValidation.preValidation(testWalker, "ErrorTest");
/**
* Check for the values set in syntax error function. If not set properly
* report an assert.
*/
assertThat(errorFlag, is(true));
}
/**
* This test case checks in case parsable stack is empty, listener validate
* function returns true.
*/
@Test
public void listenerValidationEmptyStack() {
// Create test walker and assign test error to it.
TreeWalkListener testWalker = new TreeWalkListener();
boolean errorFlag = ListenerValidation.preValidation(testWalker, "ErrorTest");
/**
* Check for the values set in syntax error function. If not set properly
* report an assert.
*/
assertThat(errorFlag, is(true));
}
/**
* This test case checks in case of error doesn't pre-exists and stack is,
* non empty, listener validate function returns false.
*/
@Test
public void listenerValidationNoErrorNotExists() {
// Create test walker and assign test error to it.
TreeWalkListener testWalker = new TreeWalkListener();
// Create a temporary node of parsable.
YangRevision tmpNode = new YangRevision();
testWalker.getParsedDataStack().push(tmpNode);
boolean errorFlag = ListenerValidation.preValidation(testWalker, "ErrorTest");
/**
* Check for the values set in syntax error function. If not set properly
* report an assert.
*/
assertThat(errorFlag, is(false));
}
}
\ No newline at end of file
/*
* 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.parseutils;
import org.antlr.v4.runtime.ANTLRFileStream;
import org.antlr.v4.runtime.ANTLRInputStream;
import org.antlr.v4.runtime.CommonTokenStream;
import org.antlr.v4.runtime.tree.ParseTree;
import org.junit.After;
import org.junit.Before;
import org.junit.Test;
import org.onosproject.yangutils.parser.antlrgencode.GeneratedYangLexer;
import org.onosproject.yangutils.parser.antlrgencode.GeneratedYangParser;
import org.onosproject.yangutils.parser.exceptions.ParserException;
import org.onosproject.yangutils.parser.impl.YangUtilsParserManager;
import org.onosproject.yangutils.parser.impl.parserutils.ParseTreeErrorListener;
import java.io.BufferedWriter;
import java.io.File;
import java.io.FileWriter;
import java.io.IOException;
import static org.hamcrest.core.Is.is;
import static org.junit.Assert.assertThat;
/**
* Test case for testing parse tree error listener.
*/
public class ParseTreeErrorListenerTest {
YangUtilsParserManager manager = new YangUtilsParserManager();
File file;
BufferedWriter out;
@Before
public void setUp() throws Exception {
file = new File("demo.yang");
out = new BufferedWriter(new FileWriter(file));
}
@After
public void tearDown() throws Exception {
file.delete();
}
/**
* This test case checks whether the error received from parser is correctly
* handled.
*/
@Test
public void syntaxErrorValidationTest() throws IOException {
out.write("module ONOS {\n");
out.write("yang-version 1\n");
out.write("namespace urn:ietf:params:xml:ns:yang:ietf-ospf;\n");
out.write("prefix On;\n");
out.write("}\n");
out.close();
ANTLRInputStream input = new ANTLRFileStream("demo.yang");
// Create a lexer that feeds off of input char stream.
GeneratedYangLexer lexer = new GeneratedYangLexer(input);
// Create a buffer of tokens pulled from the lexer.
CommonTokenStream tokens = new CommonTokenStream(lexer);
// Create a parser that feeds off the tokens buffer.
GeneratedYangParser parser = new GeneratedYangParser(tokens);
// Remove console error listener.
parser.removeErrorListeners();
// Create instance of customized error listener.
ParseTreeErrorListener parseTreeErrorListener = new ParseTreeErrorListener();
// Add customized error listener to catch errors during parsing.
parser.addErrorListener(parseTreeErrorListener);
// Begin parsing YANG file and generate parse tree.
ParseTree tree = parser.yangfile();
// Get the exception occurred during parsing.
ParserException parserException = parseTreeErrorListener.getParserException();
/**
* Check for the values set in syntax error function. If not set properly
* report an assert.
*/
assertThat(parseTreeErrorListener.isExceptionFlag(), is(true));
assertThat(parserException.getLineNumber(), is(3));
assertThat(parserException.getCharPositionInLine(), is(0));
}
}
\ No newline at end of file