diff options
author | Fiete Ostkamp <Fiete.Ostkamp@telekom.de> | 2024-02-23 17:01:49 +0100 |
---|---|---|
committer | Fiete Ostkamp <Fiete.Ostkamp@telekom.de> | 2024-02-26 09:01:48 +0100 |
commit | e5b5a5e4d7cae28a72641aae6f5f6099db1ed695 (patch) | |
tree | a6038e4ae2abd00465697c4e2d2dcdef45aa9dc0 /aai-traversal/src/main/java/org/onap/aai/rest/dsl | |
parent | 26c4ef2510d0736ae9a18c8eac2ea2406a83092d (diff) |
Do not use reflection for injecting the DslQueryProcessors
- trade terseness for easier understanding of the code and maintainability
- Split up DslQueryProcessor in two separate classes (v1 and v2)
Issue-ID: AAI-3786
Change-Id: I7fe0411f6b694eb82616ac4a61a5376c630b5b2a
Signed-off-by: Fiete Ostkamp <Fiete.Ostkamp@telekom.de>
Diffstat (limited to 'aai-traversal/src/main/java/org/onap/aai/rest/dsl')
5 files changed, 252 insertions, 115 deletions
diff --git a/aai-traversal/src/main/java/org/onap/aai/rest/dsl/DslQueryProcessor.java b/aai-traversal/src/main/java/org/onap/aai/rest/dsl/DslQueryProcessor.java index 59d4df1..b280304 100644 --- a/aai-traversal/src/main/java/org/onap/aai/rest/dsl/DslQueryProcessor.java +++ b/aai-traversal/src/main/java/org/onap/aai/rest/dsl/DslQueryProcessor.java @@ -2,7 +2,7 @@ * ============LICENSE_START======================================================= * org.onap.aai * ================================================================================ - * Copyright © 2017-2018 AT&T Intellectual Property. All rights reserved. + * Copyright © 2024 Deutsche Telekom SA. * ================================================================================ * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -17,133 +17,35 @@ * limitations under the License. * ============LICENSE_END========================================================= */ + package org.onap.aai.rest.dsl; -import java.io.ByteArrayInputStream; -import java.io.InputStream; -import java.io.InputStreamReader; -import java.lang.reflect.InvocationTargetException; -import java.nio.charset.StandardCharsets; -import java.util.HashMap; -import java.util.List; +import java.io.IOException; import java.util.Map; -import org.antlr.v4.runtime.*; +import org.antlr.v4.runtime.CommonTokenStream; +import org.antlr.v4.runtime.Token; import org.antlr.v4.runtime.misc.ParseCancellationException; -import org.antlr.v4.runtime.tree.ParseTree; -import org.antlr.v4.runtime.tree.ParseTreeListener; -import org.antlr.v4.runtime.tree.ParseTreeWalker; import org.onap.aai.exceptions.AAIException; -import org.onap.aai.rest.dsl.v2.DslListener; -import org.onap.aai.rest.dsl.validation.DslValidator; import org.onap.aai.rest.enums.QueryVersion; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; -/** - * The Class DslQueryProcessor. - */ -public class DslQueryProcessor { +public abstract class DslQueryProcessor { - private static final Logger LOGGER = LoggerFactory.getLogger(DslQueryProcessor.class); - - private Map<QueryVersion, ParseTreeListener> dslListeners; - private boolean startNodeValidationFlag = true; - private String validationRules = ""; - private static final String DSL_BASE_PACKAGE = "org.onap.aai.dsl."; - private static final String LEXER = "AAIDslLexer"; - private static final String PARSER = "AAIDslParser"; private static final String EOF_TOKEN = "<EOF>"; + private boolean hasStartNodeValidationFlag = true; private boolean isAggregate = false; + private String validationRules = ""; - public DslQueryProcessor(Map<QueryVersion, ParseTreeListener> dslListeners) { - this.dslListeners = dslListeners; - } + protected abstract Map<String, Object> getQueryResultMap(String aaiQuery) throws IOException, AAIException; public Map<String, Object> parseAaiQuery(QueryVersion version, String aaiQuery) throws AAIException { - Map<String, Object> resultMap = new HashMap<>(); try { - // Create a input stream that reads our string - InputStream stream = - new ByteArrayInputStream(aaiQuery.getBytes(StandardCharsets.UTF_8)); - - String packageName = DSL_BASE_PACKAGE + version.toString().toLowerCase() + "."; - Class<?> lexerClass = Class.forName(packageName + LEXER); - Class<?> parserClass = Class.forName(packageName + PARSER); - - Lexer lexer = (Lexer) lexerClass.getConstructor(CharStream.class) - .newInstance(CharStreams.fromStream(stream, StandardCharsets.UTF_8)); - lexer.removeErrorListeners(); - lexer.addErrorListener(new AAIDslErrorListener()); - CommonTokenStream tokens = new CommonTokenStream(lexer); - - // Parser that feeds off of the tokens buffer - Parser parser = - (Parser) parserClass.getConstructor(TokenStream.class).newInstance(tokens); - parser.removeErrorListeners(); - parser.addErrorListener(new AAIDslErrorListener()); - ParseTreeListener dslListener = dslListeners.get(version); - dslListener.getClass().getMethod("setValidationFlag", boolean.class).invoke(dslListener, - isStartNodeValidationFlag()); - dslListener.getClass().getMethod("setAggregateFlag", boolean.class).invoke(dslListener, - isAggregate()); - - if (!getValidationRules().isEmpty() && !"none".equals(getValidationRules())) { - DslValidator validator = new DslValidator.Builder().create(); - dslListener.getClass() - .getMethod("setQueryValidator", DslValidator.class, String.class) - .invoke(dslListener, validator, getValidationRules()); - } - - // Specify our entry point - ParseTree ptree = (ParseTree) parserClass.getMethod("aaiquery").invoke(parser); - - // Check if there is no EOF token at the end of the parsed aaiQuery - // If none, DSL query may have not been parsed correctly and omitted part of the query - // out. If so error out. - // If it wasn't expecting a opening parens after a closing bracket for union, it will - // drop the proceeding part of the query. - Token eofToken = tokens.get(tokens.size() - 1); - if (eofToken != null && !eofToken.getText().equals(EOF_TOKEN)) { - if (eofToken.getText().equals("(")) { - throw new AAIException("AAI_6153", - "DSL Syntax Error while processing the query: DSL Query could not be parsed correctly. Please check your syntax."); - } - } - - if (LOGGER.isInfoEnabled()) { - LOGGER.info("QUERY-interim {}", ptree.toStringTree(parser)); - } - - // Walk it and attach our listener - ParseTreeWalker walker = new ParseTreeWalker(); - - walker.walk(dslListener, ptree); - String query = - (String) dslListener.getClass().getMethod("getQuery").invoke(dslListener); - resultMap.put("query", query); - if (version.equals(QueryVersion.V2)) { - Map<String, List<String>> selectKeys = ((DslListener) dslListener).getSelectKeys(); - if (selectKeys != null && !selectKeys.isEmpty()) { - resultMap.put("propertiesMap", selectKeys); - } - } - LOGGER.info("Final QUERY {}", query); - return resultMap; - } catch (InvocationTargetException e) { - if (e.getTargetException() instanceof ParseCancellationException) { - throw new AAIException("AAI_6153", "DSL Syntax Error while processing the query :" - + e.getTargetException().getMessage()); - } else if (e.getTargetException() instanceof AAIException) { - AAIException ex = (AAIException) e.getTargetException(); - throw new AAIException((ex.getCode().isEmpty() ? "AAI_6149" : ex.getCode()), - "DSL Error while processing the query :" + ex.getMessage()); - } else { - throw new AAIException("AAI_6152", "Exception while processing DSL query"); - } - + return getQueryResultMap(aaiQuery); + } catch(AAIException ex) { + throw new AAIException((ex.getCode().isEmpty() ? "AAI_6149" : ex.getCode()), + "DSL Error while processing the query :" + ex.getMessage()); } catch (ParseCancellationException e) { throw new AAIException("AAI_6153", "DSL Syntax Error while processing the query: " + e.getMessage()); @@ -151,16 +53,35 @@ public class DslQueryProcessor { } catch (Exception e) { throw new AAIException("AAI_6152", "Error while processing the query: " + e.getMessage()); + } + } + /** + * Check if there is no EOF token at the end of the parsed aaiQuery + * If none, DSL query may have not been parsed correctly and omitted part of the query + * out. If so error out. + * If it wasn't expecting an opening parenthesis after a closing bracket for union, it will + * drop the proceeding part of the query. + * @param tokens + * @throws AAIException + */ + protected void validateQueryIsParsable(CommonTokenStream tokens) throws AAIException { + + Token eofToken = tokens.get(tokens.size() - 1); + if (eofToken != null && !eofToken.getText().equals(EOF_TOKEN)) { + if (eofToken.getText().equals("(")) { + throw new AAIException("AAI_6153", + "DSL Syntax Error while processing the query: DSL Query could not be parsed correctly. Please check your syntax."); + } } } - public boolean isStartNodeValidationFlag() { - return startNodeValidationFlag; + public boolean hasStartNodeValidationFlag() { + return hasStartNodeValidationFlag; } public void setStartNodeValidationFlag(boolean startNodeValidationFlag) { - this.startNodeValidationFlag = startNodeValidationFlag; + this.hasStartNodeValidationFlag = startNodeValidationFlag; } public boolean isAggregate() { @@ -178,4 +99,5 @@ public class DslQueryProcessor { public void setValidationRules(String validationRules) { this.validationRules = validationRules; } -} + +}
\ No newline at end of file diff --git a/aai-traversal/src/main/java/org/onap/aai/rest/dsl/V1DslQueryProcessor.java b/aai-traversal/src/main/java/org/onap/aai/rest/dsl/V1DslQueryProcessor.java new file mode 100644 index 0000000..cc89b7d --- /dev/null +++ b/aai-traversal/src/main/java/org/onap/aai/rest/dsl/V1DslQueryProcessor.java @@ -0,0 +1,99 @@ +/** + * ============LICENSE_START======================================================= + * org.onap.aai + * ================================================================================ + * Copyright © 2017-2018 AT&T Intellectual Property. All rights reserved. + * ================================================================================ + * Modifications Copyright © 2024 Deutsche Telekom SA. + * ================================================================================ + * 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. + * ============LICENSE_END========================================================= + */ +package org.onap.aai.rest.dsl; + +import java.io.ByteArrayInputStream; +import java.io.IOException; +import java.io.InputStream; +import java.nio.charset.StandardCharsets; +import java.util.HashMap; +import java.util.Map; + +import org.antlr.v4.runtime.*; +import org.antlr.v4.runtime.misc.ParseCancellationException; +import org.antlr.v4.runtime.tree.ParseTree; +import org.antlr.v4.runtime.tree.ParseTreeWalker; +import org.onap.aai.config.SpringContextAware; +import org.onap.aai.dsl.v1.AAIDslLexer; +import org.onap.aai.dsl.v1.AAIDslParser; +import org.onap.aai.exceptions.AAIException; +import org.onap.aai.rest.dsl.v1.DslListener; +import org.onap.aai.rest.dsl.validation.DslValidator; +import org.onap.aai.rest.enums.QueryVersion; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.context.annotation.Scope; +import org.springframework.stereotype.Component; + +/** + * The Class DslQueryProcessor. + */ +@Scope("prototype") +@Component(value = "dslQueryProcessor") +public class V1DslQueryProcessor extends DslQueryProcessor { + + private static final Logger LOGGER = LoggerFactory.getLogger(V1DslQueryProcessor.class); + + @Override + public Map<String, Object> getQueryResultMap(String aaiQuery) throws IOException, AAIException { + Map<String, Object> resultMap = new HashMap<>(); + // Create a input stream that reads our string + InputStream stream = + new ByteArrayInputStream(aaiQuery.getBytes(StandardCharsets.UTF_8)); + + Lexer lexer = new AAIDslLexer(CharStreams.fromStream(stream, StandardCharsets.UTF_8)); + lexer.removeErrorListeners(); + lexer.addErrorListener(new AAIDslErrorListener()); + CommonTokenStream tokens = new CommonTokenStream(lexer); + + // Parser that feeds off of the tokens buffer + AAIDslParser parser = new AAIDslParser(tokens); + parser.removeErrorListeners(); + parser.addErrorListener(new AAIDslErrorListener()); + + ParseTree ptree = parser.aaiquery(); + + validateQueryIsParsable(tokens); + + if (LOGGER.isInfoEnabled()) { + LOGGER.info("QUERY-interim {}", ptree.toStringTree(parser)); + } + + DslListener dslListener = SpringContextAware.getApplicationContext().getBean(DslListener.class); + dslListener.setValidationFlag(hasStartNodeValidationFlag()); + dslListener.setAggregateFlag(isAggregate()); + + if (!getValidationRules().isEmpty() && !"none".equals(getValidationRules())) { + DslValidator validator = new DslValidator.Builder().create(); + dslListener.setQueryValidator(validator, getValidationRules()); + } + + // Walk it and attach our listener + ParseTreeWalker walker = new ParseTreeWalker(); + walker.walk(dslListener, ptree); + String query = dslListener.getQuery(); + resultMap.put("query", query); + + LOGGER.info("Final QUERY {}", query); + return resultMap; + } +} diff --git a/aai-traversal/src/main/java/org/onap/aai/rest/dsl/V2DslQueryProcessor.java b/aai-traversal/src/main/java/org/onap/aai/rest/dsl/V2DslQueryProcessor.java new file mode 100644 index 0000000..28d5ef0 --- /dev/null +++ b/aai-traversal/src/main/java/org/onap/aai/rest/dsl/V2DslQueryProcessor.java @@ -0,0 +1,106 @@ +/** + * ============LICENSE_START======================================================= + * org.onap.aai + * ================================================================================ + * Copyright © 2017-2018 AT&T Intellectual Property. All rights reserved. + * ================================================================================ + * Modifications Copyright © 2024 Deutsche Telekom SA. + * ================================================================================ + * 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. + * ============LICENSE_END========================================================= + */ +package org.onap.aai.rest.dsl; + +import java.io.ByteArrayInputStream; +import java.io.IOException; +import java.io.InputStream; +import java.nio.charset.StandardCharsets; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +import org.antlr.v4.runtime.*; +import org.antlr.v4.runtime.misc.ParseCancellationException; +import org.antlr.v4.runtime.tree.ParseTree; +import org.antlr.v4.runtime.tree.ParseTreeWalker; +import org.onap.aai.config.SpringContextAware; +import org.onap.aai.dsl.v2.AAIDslLexer; +import org.onap.aai.dsl.v2.AAIDslParser; +import org.onap.aai.exceptions.AAIException; +import org.onap.aai.rest.dsl.v2.DslListener; +import org.onap.aai.rest.dsl.validation.DslValidator; +import org.onap.aai.rest.enums.QueryVersion; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.context.annotation.Scope; +import org.springframework.stereotype.Component; + +/** + * The Class DslQueryProcessor. + */ +@Component +@Scope("prototype") +public class V2DslQueryProcessor extends DslQueryProcessor { + + private static final Logger LOGGER = LoggerFactory.getLogger(V2DslQueryProcessor.class); + + @Override + protected Map<String, Object> getQueryResultMap(String aaiQuery) throws IOException, AAIException { + // Create a input stream that reads our string + InputStream stream = + new ByteArrayInputStream(aaiQuery.getBytes(StandardCharsets.UTF_8)); + + Lexer lexer = new AAIDslLexer(CharStreams.fromStream(stream, StandardCharsets.UTF_8)); + lexer.removeErrorListeners(); + lexer.addErrorListener(new AAIDslErrorListener()); + CommonTokenStream tokens = new CommonTokenStream(lexer); + + // Parser that feeds off of the tokens buffer + AAIDslParser parser = new AAIDslParser(tokens); + parser.removeErrorListeners(); + parser.addErrorListener(new AAIDslErrorListener()); + + ParseTree ptree = parser.aaiquery(); + + validateQueryIsParsable(tokens); + + if (LOGGER.isInfoEnabled()) { + LOGGER.info("QUERY-interim {}", ptree.toStringTree(parser)); + } + + DslListener dslListener = SpringContextAware.getApplicationContext().getBean(DslListener.class); + dslListener.setValidationFlag(hasStartNodeValidationFlag()); + dslListener.setAggregateFlag(isAggregate()); + + if (!getValidationRules().isEmpty() && !"none".equals(getValidationRules())) { + DslValidator validator = new DslValidator.Builder().create(); + dslListener.setQueryValidator(validator, getValidationRules()); + } + + // Walk it and attach our listener + ParseTreeWalker walker = new ParseTreeWalker(); + walker.walk(dslListener, ptree); + String query = dslListener.getQuery(); + + Map<String, Object> resultMap = new HashMap<>(); + resultMap.put("query", query); + + Map<String, List<String>> selectKeys = dslListener.getSelectKeys(); + if (selectKeys != null && !selectKeys.isEmpty()) { + resultMap.put("propertiesMap", selectKeys); + } + + LOGGER.info("Final QUERY {}", query); + return resultMap; + } +} diff --git a/aai-traversal/src/main/java/org/onap/aai/rest/dsl/v1/DslListener.java b/aai-traversal/src/main/java/org/onap/aai/rest/dsl/v1/DslListener.java index 1987310..1ad1292 100644 --- a/aai-traversal/src/main/java/org/onap/aai/rest/dsl/v1/DslListener.java +++ b/aai-traversal/src/main/java/org/onap/aai/rest/dsl/v1/DslListener.java @@ -39,10 +39,15 @@ import org.onap.aai.rest.dsl.validation.DslValidatorRule; import org.onap.aai.setup.SchemaVersions; import org.slf4j.Logger; import org.slf4j.LoggerFactory; +import org.springframework.context.annotation.Scope; +import org.springframework.context.annotation.ScopedProxyMode; +import org.springframework.stereotype.Component; /** * The Class DslListener. */ +@Scope(value = "prototype") +@Component(value = "v1DslListener") public class DslListener extends AAIDslBaseListener { private static final Logger LOGGER = LoggerFactory.getLogger(DslListener.class); diff --git a/aai-traversal/src/main/java/org/onap/aai/rest/dsl/v2/DslListener.java b/aai-traversal/src/main/java/org/onap/aai/rest/dsl/v2/DslListener.java index 5395af0..571f6f6 100644 --- a/aai-traversal/src/main/java/org/onap/aai/rest/dsl/v2/DslListener.java +++ b/aai-traversal/src/main/java/org/onap/aai/rest/dsl/v2/DslListener.java @@ -42,10 +42,15 @@ import org.onap.aai.rest.enums.EdgeDirection; import org.onap.aai.setup.SchemaVersions; import org.slf4j.Logger; import org.slf4j.LoggerFactory; +import org.springframework.context.annotation.Scope; +import org.springframework.context.annotation.ScopedProxyMode; +import org.springframework.stereotype.Component; /** * The Class DslListener. */ +@Scope(value = "prototype") +@Component(value = "v2DslListener") public class DslListener extends AAIDslBaseListener { private static final Logger LOGGER = LoggerFactory.getLogger(DslListener.class.getName()); |