Gaurav Agrawal
Committed by Gerrit Code Review

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

Change-Id: I10e68bd676eca4d576de1234fbb67026c7b49939
1 +/*
2 + * Copyright 2016 Open Networking Laboratory
3 + *
4 + * Licensed under the Apache License, Version 2.0 (the "License");
5 + * you may not use this file except in compliance with the License.
6 + * You may obtain a copy of the License at
7 + *
8 + * http://www.apache.org/licenses/LICENSE-2.0
9 + *
10 + * Unless required by applicable law or agreed to in writing, software
11 + * distributed under the License is distributed on an "AS IS" BASIS,
12 + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 + * See the License for the specific language governing permissions and
14 + * limitations under the License.
15 + */
16 +
17 +package org.onosproject.yangutils.parser.impl;
18 +
19 +import org.antlr.v4.runtime.ANTLRFileStream;
20 +import org.antlr.v4.runtime.ANTLRInputStream;
21 +import org.antlr.v4.runtime.CommonTokenStream;
22 +import org.antlr.v4.runtime.tree.ParseTree;
23 +import org.antlr.v4.runtime.tree.ParseTreeWalker;
24 +import org.onosproject.yangutils.datamodel.YangNode;
25 +import org.onosproject.yangutils.parser.YangUtilsParser;
26 +import org.onosproject.yangutils.parser.antlrgencode.GeneratedYangLexer;
27 +import org.onosproject.yangutils.parser.antlrgencode.GeneratedYangParser;
28 +import org.onosproject.yangutils.parser.exceptions.ParserException;
29 +import org.onosproject.yangutils.parser.impl.parserutils.ParseTreeErrorListener;
30 +
31 +import java.io.IOException;
32 +
33 +/**
34 + * Manages file parsing, parse tree creation and data model tree creation
35 + * corresponding to an input YANG file.
36 + */
37 +public class YangUtilsParserManager implements YangUtilsParser {
38 +
39 + @Override
40 + public YangNode getDataModel(String yangFile) throws IOException, ParserException {
41 +
42 + /**
43 + * Create a char stream that reads from YANG file. Throws an exception
44 + * in case input YANG file is either null or non existent.
45 + */
46 + ANTLRInputStream input = null;
47 + try {
48 + input = new ANTLRFileStream(yangFile);
49 + } catch (IOException e) {
50 + e.printStackTrace();
51 + throw e;
52 + }
53 +
54 + // Create a lexer that feeds off of input char stream.
55 + GeneratedYangLexer lexer = new GeneratedYangLexer(input);
56 +
57 + // Create a buffer of tokens pulled from the lexer.
58 + CommonTokenStream tokens = new CommonTokenStream(lexer);
59 +
60 + // Create a parser that feeds off the tokens buffer.
61 + GeneratedYangParser parser = new GeneratedYangParser(tokens);
62 +
63 + // Remove console error listener.
64 + parser.removeErrorListeners();
65 +
66 + // Create instance of customized error listener.
67 + ParseTreeErrorListener parseTreeErrorListener = new ParseTreeErrorListener();
68 +
69 + // Add customized error listener to catch errors during parsing.
70 + parser.addErrorListener(parseTreeErrorListener);
71 +
72 + // Begin parsing YANG file and generate parse tree.
73 + ParseTree tree = parser.yangfile();
74 +
75 + /**
76 + * Throws an parser Exception if exception flag is set i.e. exception has
77 + * occurred during parsing.
78 + */
79 + if (parseTreeErrorListener.isExceptionFlag()) {
80 + // Get the exception occurred during parsing.
81 + ParserException parserException = parseTreeErrorListener.getParserException();
82 + parserException.setFileName(yangFile);
83 + throw parserException;
84 + }
85 +
86 + // Create a walker to walk the parse tree.
87 + ParseTreeWalker walker = new ParseTreeWalker();
88 +
89 + // Create a listener implementation class object.
90 + TreeWalkListener treeWalker = new TreeWalkListener();
91 +
92 + /**
93 + * Walk parse tree, provide call backs to methods in listener and
94 + * build data model tree.
95 + */
96 + walker.walk(treeWalker, tree);
97 +
98 + // Throws an parser exception which has occurred during listener walk.
99 + if (treeWalker.getErrorInformation().isErrorFlag()) {
100 + // Create object of listener exception
101 + ParserException listenerException = new ParserException();
102 + listenerException.setMsg(treeWalker.getErrorInformation().getErrorMsg());
103 + listenerException.setFileName(yangFile);
104 + throw listenerException;
105 + }
106 +
107 + // Returns the Root Node of the constructed data model tree.
108 + return treeWalker.getRootNode();
109 + }
110 +}
1 +/*
2 + * Copyright 2016 Open Networking Laboratory
3 + *
4 + * Licensed under the Apache License, Version 2.0 (the "License");
5 + * you may not use this file except in compliance with the License.
6 + * You may obtain a copy of the License at
7 + *
8 + * http://www.apache.org/licenses/LICENSE-2.0
9 + *
10 + * Unless required by applicable law or agreed to in writing, software
11 + * distributed under the License is distributed on an "AS IS" BASIS,
12 + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 + * See the License for the specific language governing permissions and
14 + * limitations under the License.
15 + */
16 +
17 +package org.onosproject.yangutils.parser.impl.parserutils;
18 +
19 +import org.onosproject.yangutils.parser.impl.TreeWalkListener;
20 +
21 +/**
22 + * Its a utility to carry out listener validation.
23 + */
24 +public final class ListenerValidation {
25 +
26 + /**
27 + * Creates a new belongto listener.
28 + */
29 + private ListenerValidation() {
30 + }
31 +
32 + /**
33 + * Checks if error is set or parsed data stack is empty.
34 + *
35 + * @param listener Listener's object.
36 + * @param errNode parsable node for which validation needs to be done.
37 + * @return validation result.
38 + */
39 + public static boolean preValidation(TreeWalkListener listener, String errNode) {
40 +
41 + // Check whether error found while walking YANG file, if yes return true.
42 + if (listener.getErrorInformation().isErrorFlag()) {
43 + return true;
44 + }
45 +
46 + // If stack is empty it indicates error condition
47 + if (listener.getParsedDataStack().empty()) {
48 + listener.getErrorInformation().setErrorFlag(true);
49 + listener.getErrorInformation().setErrorMsg("Parsable stack empty at" + errNode + "entry");
50 + return true;
51 + }
52 + return false;
53 + }
54 +}
...\ No newline at end of file ...\ No newline at end of file
1 +/*
2 + * Copyright 2016 Open Networking Laboratory
3 + *
4 + * Licensed under the Apache License, Version 2.0 (the "License");
5 + * you may not use this file except in compliance with the License.
6 + * You may obtain a copy of the License at
7 + *
8 + * http://www.apache.org/licenses/LICENSE-2.0
9 + *
10 + * Unless required by applicable law or agreed to in writing, software
11 + * distributed under the License is distributed on an "AS IS" BASIS,
12 + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 + * See the License for the specific language governing permissions and
14 + * limitations under the License.
15 + */
16 +
17 +package org.onosproject.yangutils.parser.impl.parserutils;
18 +
19 +import org.antlr.v4.runtime.BaseErrorListener;
20 +import org.antlr.v4.runtime.RecognitionException;
21 +import org.antlr.v4.runtime.Recognizer;
22 +import org.onosproject.yangutils.parser.exceptions.ParserException;
23 +
24 +/**
25 + * By default, ANTLR sends all errors to standard error, this is changed by
26 + * providing this new implementation of interface ANTLRErrorListener. The
27 + * interface has a syntaxError() method that applies to both lexer and
28 + * parser.
29 + */
30 +public class ParseTreeErrorListener extends BaseErrorListener {
31 +
32 + // Exception of type parser exceptions are catched during parsing.
33 + private ParserException parserException = new ParserException();
34 +
35 + // Flag to indicate presence of exception.
36 + private boolean exceptionFlag = false;
37 +
38 + /**
39 + * Returns the status of exception flag.
40 + *
41 + * @return flag which contains the status of exception.
42 + */
43 + public boolean isExceptionFlag() {
44 + return exceptionFlag;
45 + }
46 +
47 + /**
48 + * Returns the parser exception object populated with line, character
49 + * position and message.
50 + *
51 + * @return object of parser exception.
52 + */
53 + public ParserException getParserException() {
54 + return parserException;
55 + }
56 +
57 + @Override
58 + public void syntaxError(Recognizer<?, ?> recognizer, Object offendingSymbol, int line, int charPositionInLine,
59 + String msg, RecognitionException e) {
60 + parserException.setLine(line);
61 + parserException.setCharPosition(charPositionInLine);
62 + parserException.setMsg(msg);
63 + exceptionFlag = true;
64 + }
65 +}
...\ No newline at end of file ...\ No newline at end of file
1 +/*
2 + * Copyright 2016 Open Networking Laboratory
3 + *
4 + * Licensed under the Apache License, Version 2.0 (the "License");
5 + * you may not use this file except in compliance with the License.
6 + * You may obtain a copy of the License at
7 + *
8 + * http://www.apache.org/licenses/LICENSE-2.0
9 + *
10 + * Unless required by applicable law or agreed to in writing, software
11 + * distributed under the License is distributed on an "AS IS" BASIS,
12 + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 + * See the License for the specific language governing permissions and
14 + * limitations under the License.
15 + */
16 +
17 +package org.onosproject.yangutils.parser.impl;
18 +
19 +import org.junit.After;
20 +import org.junit.Before;
21 +import org.junit.Test;
22 +import org.onosproject.yangutils.datamodel.YangNode;
23 +import org.onosproject.yangutils.parser.exceptions.ParserException;
24 +
25 +import java.io.BufferedWriter;
26 +import java.io.File;
27 +import java.io.FileWriter;
28 +import java.io.IOException;
29 +
30 +/**
31 + * Test case for testing YANG utils parser manager.
32 + */
33 +public class YangUtilsParserManagerTest {
34 +
35 + YangUtilsParserManager manager = new YangUtilsParserManager();
36 + File file;
37 + BufferedWriter out;
38 +
39 + @Before
40 + public void setUp() throws Exception {
41 + file = new File("demo.yang");
42 + out = new BufferedWriter(new FileWriter(file));
43 + }
44 + @After
45 + public void tearDown() throws Exception {
46 + file.delete();
47 + }
48 +
49 + /**
50 + * This test case checks whether the null pointer exception is generated
51 + * when the input YANG file is null.
52 + */
53 + @Test(expected = NullPointerException.class)
54 + public void getDataModelNullFileTest() throws IOException, ParserException {
55 + YangUtilsParserManager manager = new YangUtilsParserManager();
56 + YangNode node = manager.getDataModel(null);
57 + }
58 +
59 + /**
60 + * This test case checks whether the io exception is generated
61 + * when the input YANG file is non existent.
62 + */
63 + @Test(expected = IOException.class)
64 + public void getDataModelNonExistentFileTest() throws IOException, ParserException {
65 +
66 + YangUtilsParserManager manager = new YangUtilsParserManager();
67 + YangNode node = manager.getDataModel("nonexistent.yang");
68 + }
69 +
70 + /**
71 + * This test case checks if the input YANG file is correct no exception
72 + * should be generated.
73 + */
74 + @Test
75 + public void getDataModelCorrectFileTest() throws IOException, ParserException {
76 +
77 + out.write("module ONOS {\n");
78 + out.write("yang-version 1;\n");
79 + out.write("namespace urn:ietf:params:xml:ns:yang:ietf-ospf;\n");
80 + out.write("prefix On;\n");
81 + out.write("}\n");
82 + out.close();
83 +
84 + YangNode node = manager.getDataModel("demo.yang");
85 + }
86 +
87 + /**
88 + * This test case checks if the input YANG file with wrong YANG constructs
89 + * than parser exception should be generated.
90 + */
91 + @Test(expected = ParserException.class)
92 + public void getDataModelIncorrectFileTest() throws IOException, ParserException {
93 +
94 + out.write("module ONOS {\n");
95 + out.write("yang-version 1\n");
96 + out.write("namespace urn:ietf:params:xml:ns:yang:ietf-ospf;\n");
97 + out.write("prefix On;\n");
98 + out.write("}\n");
99 + out.close();
100 +
101 + YangNode node = manager.getDataModel("demo.yang");
102 + }
103 +}
...\ No newline at end of file ...\ No newline at end of file
1 +/*
2 + * Copyright 2016 Open Networking Laboratory
3 + *
4 + * Licensed under the Apache License, Version 2.0 (the "License");
5 + * you may not use this file except in compliance with the License.
6 + * You may obtain a copy of the License at
7 + *
8 + * http://www.apache.org/licenses/LICENSE-2.0
9 + *
10 + * Unless required by applicable law or agreed to in writing, software
11 + * distributed under the License is distributed on an "AS IS" BASIS,
12 + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 + * See the License for the specific language governing permissions and
14 + * limitations under the License.
15 + */
16 +
17 +package org.onosproject.yangutils.parser.parseutils;
18 +
19 +import org.junit.Test;
20 +import org.onosproject.yangutils.datamodel.YangRevision;
21 +import org.onosproject.yangutils.parser.impl.TreeWalkListener;
22 +import org.onosproject.yangutils.parser.impl.parserutils.ListenerError;
23 +import org.onosproject.yangutils.parser.impl.parserutils.ListenerValidation;
24 +
25 +import static org.hamcrest.core.Is.is;
26 +import static org.junit.Assert.assertThat;
27 +
28 +/**
29 + * Test case for testing listener validation util.
30 + */
31 +public class ListenerValidationTest {
32 +
33 + /**
34 + * This test case checks in case error pre-exists, listener validate
35 + * function returns true.
36 + */
37 + @Test
38 + public void listenerValidationErrorExists() {
39 +
40 + // Create an test error.
41 + ListenerError testError = new ListenerError();
42 + testError.setErrorFlag(true);
43 + testError.setErrorMsg("Test Error");
44 +
45 + // Create test walker and assign test error to it.
46 + TreeWalkListener testWalker = new TreeWalkListener();
47 + testWalker.setErrorInformation(testError);
48 +
49 + // Create a temporary node of parsable.
50 + YangRevision tmpNode = new YangRevision();
51 + testWalker.getParsedDataStack().push(tmpNode);
52 +
53 + boolean errorFlag = ListenerValidation.preValidation(testWalker, "ErrorTest");
54 +
55 + /**
56 + * Check for the values set in syntax error function. If not set properly
57 + * report an assert.
58 + */
59 + assertThat(errorFlag, is(true));
60 + }
61 +
62 + /**
63 + * This test case checks in case parsable stack is empty, listener validate
64 + * function returns true.
65 + */
66 + @Test
67 + public void listenerValidationEmptyStack() {
68 +
69 + // Create test walker and assign test error to it.
70 + TreeWalkListener testWalker = new TreeWalkListener();
71 +
72 + boolean errorFlag = ListenerValidation.preValidation(testWalker, "ErrorTest");
73 +
74 + /**
75 + * Check for the values set in syntax error function. If not set properly
76 + * report an assert.
77 + */
78 + assertThat(errorFlag, is(true));
79 + }
80 +
81 + /**
82 + * This test case checks in case of error doesn't pre-exists and stack is,
83 + * non empty, listener validate function returns false.
84 + */
85 + @Test
86 + public void listenerValidationNoErrorNotExists() {
87 +
88 + // Create test walker and assign test error to it.
89 + TreeWalkListener testWalker = new TreeWalkListener();
90 +
91 + // Create a temporary node of parsable.
92 + YangRevision tmpNode = new YangRevision();
93 + testWalker.getParsedDataStack().push(tmpNode);
94 +
95 + boolean errorFlag = ListenerValidation.preValidation(testWalker, "ErrorTest");
96 +
97 + /**
98 + * Check for the values set in syntax error function. If not set properly
99 + * report an assert.
100 + */
101 + assertThat(errorFlag, is(false));
102 + }
103 +}
...\ No newline at end of file ...\ No newline at end of file
1 +/*
2 + * Copyright 2016 Open Networking Laboratory
3 + *
4 + * Licensed under the Apache License, Version 2.0 (the "License");
5 + * you may not use this file except in compliance with the License.
6 + * You may obtain a copy of the License at
7 + *
8 + * http://www.apache.org/licenses/LICENSE-2.0
9 + *
10 + * Unless required by applicable law or agreed to in writing, software
11 + * distributed under the License is distributed on an "AS IS" BASIS,
12 + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 + * See the License for the specific language governing permissions and
14 + * limitations under the License.
15 + */
16 +
17 +package org.onosproject.yangutils.parser.impl.parseutils;
18 +
19 +import org.antlr.v4.runtime.ANTLRFileStream;
20 +import org.antlr.v4.runtime.ANTLRInputStream;
21 +import org.antlr.v4.runtime.CommonTokenStream;
22 +import org.antlr.v4.runtime.tree.ParseTree;
23 +import org.junit.After;
24 +import org.junit.Before;
25 +import org.junit.Test;
26 +import org.onosproject.yangutils.parser.antlrgencode.GeneratedYangLexer;
27 +import org.onosproject.yangutils.parser.antlrgencode.GeneratedYangParser;
28 +import org.onosproject.yangutils.parser.exceptions.ParserException;
29 +import org.onosproject.yangutils.parser.impl.YangUtilsParserManager;
30 +import org.onosproject.yangutils.parser.impl.parserutils.ParseTreeErrorListener;
31 +
32 +import java.io.BufferedWriter;
33 +import java.io.File;
34 +import java.io.FileWriter;
35 +import java.io.IOException;
36 +
37 +import static org.hamcrest.core.Is.is;
38 +import static org.junit.Assert.assertThat;
39 +
40 +/**
41 + * Test case for testing parse tree error listener.
42 + */
43 +public class ParseTreeErrorListenerTest {
44 +
45 + YangUtilsParserManager manager = new YangUtilsParserManager();
46 + File file;
47 + BufferedWriter out;
48 +
49 + @Before
50 + public void setUp() throws Exception {
51 + file = new File("demo.yang");
52 + out = new BufferedWriter(new FileWriter(file));
53 + }
54 + @After
55 + public void tearDown() throws Exception {
56 + file.delete();
57 + }
58 +
59 + /**
60 + * This test case checks whether the error received from parser is correctly
61 + * handled.
62 + */
63 + @Test
64 + public void syntaxErrorValidationTest() throws IOException {
65 +
66 + out.write("module ONOS {\n");
67 + out.write("yang-version 1\n");
68 + out.write("namespace urn:ietf:params:xml:ns:yang:ietf-ospf;\n");
69 + out.write("prefix On;\n");
70 + out.write("}\n");
71 + out.close();
72 +
73 + ANTLRInputStream input = new ANTLRFileStream("demo.yang");
74 +
75 + // Create a lexer that feeds off of input char stream.
76 + GeneratedYangLexer lexer = new GeneratedYangLexer(input);
77 + // Create a buffer of tokens pulled from the lexer.
78 + CommonTokenStream tokens = new CommonTokenStream(lexer);
79 + // Create a parser that feeds off the tokens buffer.
80 + GeneratedYangParser parser = new GeneratedYangParser(tokens);
81 + // Remove console error listener.
82 + parser.removeErrorListeners();
83 + // Create instance of customized error listener.
84 + ParseTreeErrorListener parseTreeErrorListener = new ParseTreeErrorListener();
85 + // Add customized error listener to catch errors during parsing.
86 + parser.addErrorListener(parseTreeErrorListener);
87 + // Begin parsing YANG file and generate parse tree.
88 + ParseTree tree = parser.yangfile();
89 + // Get the exception occurred during parsing.
90 + ParserException parserException = parseTreeErrorListener.getParserException();
91 +
92 + /**
93 + * Check for the values set in syntax error function. If not set properly
94 + * report an assert.
95 + */
96 + assertThat(parseTreeErrorListener.isExceptionFlag(), is(true));
97 + assertThat(parserException.getLineNumber(), is(3));
98 + assertThat(parserException.getCharPositionInLine(), is(0));
99 + }
100 +}
...\ No newline at end of file ...\ No newline at end of file