summaryrefslogtreecommitdiffstats
path: root/aai-traversal/src/main
diff options
context:
space:
mode:
Diffstat (limited to 'aai-traversal/src/main')
-rw-r--r--aai-traversal/src/main/java/org/onap/aai/TraversalApp.java1
-rw-r--r--aai-traversal/src/main/java/org/onap/aai/interceptors/pre/VersionInterceptor.java2
-rw-r--r--aai-traversal/src/main/java/org/onap/aai/rest/CQ2Gremlin.java126
-rw-r--r--aai-traversal/src/main/java/org/onap/aai/rest/CQ2GremlinTest.java235
-rw-r--r--aai-traversal/src/main/java/org/onap/aai/rest/DslConsumer.java39
-rw-r--r--aai-traversal/src/main/java/org/onap/aai/rest/dsl/AAIDslErrorListener.java34
-rw-r--r--aai-traversal/src/main/java/org/onap/aai/rest/dsl/DslListener.java276
-rw-r--r--aai-traversal/src/main/java/org/onap/aai/rest/dsl/DslQueryBuilder.java443
-rw-r--r--aai-traversal/src/main/java/org/onap/aai/rest/dsl/DslQueryProcessor.java29
-rw-r--r--aai-traversal/src/main/java/org/onap/aai/rest/search/CustomQueryConfigDTO.java70
-rw-r--r--aai-traversal/src/main/java/org/onap/aai/rest/search/CustomQueryDTO.java56
-rw-r--r--aai-traversal/src/main/java/org/onap/aai/rest/search/CustomQueryTestDTO.java121
-rw-r--r--aai-traversal/src/main/java/org/onap/aai/rest/search/ExpectedResultsDto.java39
-rw-r--r--aai-traversal/src/main/java/org/onap/aai/web/JerseyConfiguration.java5
-rw-r--r--aai-traversal/src/main/resources/antlr4/org/onap/aai/AAIDsl.g455
-rw-r--r--aai-traversal/src/main/resources/etc/appprops/aaiconfig.properties8
-rw-r--r--aai-traversal/src/main/resources/retired.properties2
17 files changed, 1124 insertions, 417 deletions
diff --git a/aai-traversal/src/main/java/org/onap/aai/TraversalApp.java b/aai-traversal/src/main/java/org/onap/aai/TraversalApp.java
index 64a3b44..4d8f4a8 100644
--- a/aai-traversal/src/main/java/org/onap/aai/TraversalApp.java
+++ b/aai-traversal/src/main/java/org/onap/aai/TraversalApp.java
@@ -179,6 +179,7 @@ public class TraversalApp {
}
String currentDirectory = System.getProperty("user.dir");
+ System.setProperty("aai.service.name", TraversalApp.class.getSimpleName());
if (System.getProperty("AJSC_HOME") == null) {
System.setProperty("AJSC_HOME", ".");
diff --git a/aai-traversal/src/main/java/org/onap/aai/interceptors/pre/VersionInterceptor.java b/aai-traversal/src/main/java/org/onap/aai/interceptors/pre/VersionInterceptor.java
index df9807c..902d6f0 100644
--- a/aai-traversal/src/main/java/org/onap/aai/interceptors/pre/VersionInterceptor.java
+++ b/aai-traversal/src/main/java/org/onap/aai/interceptors/pre/VersionInterceptor.java
@@ -62,7 +62,7 @@ public class VersionInterceptor extends AAIContainerFilter implements ContainerR
String uri = requestContext.getUriInfo().getPath();
- if (uri.startsWith("search") || uri.startsWith("util/echo") || uri.startsWith("tools") || uri.startsWith("recents")) {
+ if (uri.startsWith("search") || uri.startsWith("util/echo") || uri.startsWith("tools") || uri.startsWith("recents")|| uri.startsWith("cq2gremlin")|| uri.startsWith("cq2gremlintest")) {
return;
}
diff --git a/aai-traversal/src/main/java/org/onap/aai/rest/CQ2Gremlin.java b/aai-traversal/src/main/java/org/onap/aai/rest/CQ2Gremlin.java
new file mode 100644
index 0000000..dcf8418
--- /dev/null
+++ b/aai-traversal/src/main/java/org/onap/aai/rest/CQ2Gremlin.java
@@ -0,0 +1,126 @@
+/**
+ * ============LICENSE_START=======================================================
+ * org.onap.aai
+ * ================================================================================
+ * Copyright © 2017-2018 AT&T Intellectual Property. All rights reserved.
+ * ================================================================================
+ * 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;
+
+import java.util.LinkedHashMap;
+import java.util.List;
+import java.util.Map;
+
+import javax.ws.rs.Consumes;
+import javax.ws.rs.PUT;
+import javax.ws.rs.Path;
+import javax.ws.rs.Produces;
+import javax.ws.rs.core.Context;
+import javax.ws.rs.core.HttpHeaders;
+import javax.ws.rs.core.MediaType;
+import javax.ws.rs.core.Response;
+import javax.ws.rs.core.UriInfo;
+
+import org.onap.aai.config.SpringContextAware;
+import org.onap.aai.dbmap.DBConnectionType;
+import org.onap.aai.exceptions.AAIException;
+import org.onap.aai.introspection.LoaderFactory;
+import org.onap.aai.rest.db.HttpEntry;
+import org.onap.aai.rest.search.CustomQueryConfigDTO;
+import org.onap.aai.rest.search.CustomQueryDTO;
+import org.onap.aai.restcore.RESTAPI;
+import org.onap.aai.restcore.search.GroovyQueryBuilder;
+import org.onap.aai.serialization.db.EdgeSerializer;
+import org.onap.aai.serialization.engines.TransactionalGraphEngine;
+import org.onap.aai.setup.SchemaVersions;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.beans.factory.annotation.Value;
+import org.springframework.http.HttpStatus;
+import org.springframework.web.bind.annotation.RequestBody;
+
+
+@Path("/cq2gremlin")
+public class CQ2Gremlin extends RESTAPI {
+
+ private HttpEntry traversalUriHttpEntry;
+
+
+ @Autowired
+ protected LoaderFactory loaderFactory;
+
+ @Autowired
+ protected EdgeSerializer rules;
+
+
+ @Autowired
+ public CQ2Gremlin(
+ HttpEntry traversalUriHttpEntry,
+ @Value("${schema.uri.base.path}") String basePath
+ ){
+ this.traversalUriHttpEntry = traversalUriHttpEntry;
+ }
+
+ @PUT
+ @Path("")
+ @Consumes({ MediaType.APPLICATION_JSON })
+ @Produces({ MediaType.APPLICATION_JSON })
+ public Response getC2Qgremlin(@RequestBody Map<String, CustomQueryConfigDTO> content,@Context HttpHeaders headers, @Context UriInfo info) {
+ if(content.size() == 0){
+ return Response.status(HttpStatus.BAD_REQUEST.value()).entity("At least one custom query should be passed").build();
+ }
+ return processGremlinQuery(content.values().toArray(new CustomQueryConfigDTO[0])[0], info, headers);
+ }
+
+ protected Response processGremlinQuery(CustomQueryConfigDTO content, UriInfo info,
+ HttpHeaders headers) {
+ try{
+ String sourceOfTruth = headers.getRequestHeaders().getFirst("X-FromAppId");
+ String realTime = headers.getRequestHeaders().getFirst("Real-Time");
+ LinkedHashMap <String, Object> params;
+ CustomQueryDTO queryDTO = content.getQueryDTO();
+ String query = queryDTO.getQuery();
+ params = new LinkedHashMap <>();
+
+ List<String> optionalParameters = queryDTO.getQueryOptionalProperties();
+ if (!optionalParameters.isEmpty()){
+ for ( String key : optionalParameters ) {
+ params.put(key, key);
+ }
+ }
+
+ List<String> requiredParameters = queryDTO.getQueryRequiredProperties();
+ if (!requiredParameters.isEmpty()){
+ for ( String key : requiredParameters ) {
+ params.put(key, key);
+ }
+ }
+
+ SchemaVersions schemaVersions = SpringContextAware.getBean(SchemaVersions.class);
+ DBConnectionType type = this.determineConnectionType(sourceOfTruth, realTime);
+ traversalUriHttpEntry.setHttpEntryProperties(schemaVersions.getDefaultVersion(), type);
+ traversalUriHttpEntry.setPaginationParameters("-1", "-1");
+
+ TransactionalGraphEngine dbEngine = traversalUriHttpEntry.getDbEngine();
+
+ query = new GroovyQueryBuilder().executeTraversal(dbEngine,query, params);
+ query = "g" + query;
+ return Response.ok(query).build();
+ }
+ catch(Exception ex){
+ return Response.status(500).entity("Query conversion failed with following reason: " + ex.toString()).build();
+ }
+
+ }
+}
diff --git a/aai-traversal/src/main/java/org/onap/aai/rest/CQ2GremlinTest.java b/aai-traversal/src/main/java/org/onap/aai/rest/CQ2GremlinTest.java
new file mode 100644
index 0000000..40538be
--- /dev/null
+++ b/aai-traversal/src/main/java/org/onap/aai/rest/CQ2GremlinTest.java
@@ -0,0 +1,235 @@
+/**
+ * ============LICENSE_START=======================================================
+ * org.onap.aai
+ * ================================================================================
+ * Copyright © 2017-2018 AT&T Intellectual Property. All rights reserved.
+ * ================================================================================
+ * 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;
+
+
+import java.util.ArrayList;
+import java.util.Comparator;
+import java.util.HashSet;
+import java.util.LinkedHashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.Optional;
+import java.util.concurrent.atomic.AtomicInteger;
+import java.util.stream.Collectors;
+
+import javax.ws.rs.Consumes;
+import javax.ws.rs.PUT;
+import javax.ws.rs.Path;
+import javax.ws.rs.Produces;
+import javax.ws.rs.core.Context;
+import javax.ws.rs.core.HttpHeaders;
+import javax.ws.rs.core.MediaType;
+import javax.ws.rs.core.Response;
+import javax.ws.rs.core.UriInfo;
+
+import org.apache.tinkerpop.gremlin.process.traversal.dsl.graph.GraphTraversal;
+import org.apache.tinkerpop.gremlin.process.traversal.dsl.graph.GraphTraversalSource;
+import org.apache.tinkerpop.gremlin.structure.Graph;
+import org.apache.tinkerpop.gremlin.structure.T;
+import org.apache.tinkerpop.gremlin.structure.Vertex;
+import org.apache.tinkerpop.gremlin.tinkergraph.structure.TinkerGraph;
+import org.onap.aai.config.SpringContextAware;
+import org.onap.aai.dbmap.DBConnectionType;
+import org.onap.aai.exceptions.AAIException;
+import org.onap.aai.introspection.Loader;
+import org.onap.aai.introspection.LoaderFactory;
+import org.onap.aai.introspection.ModelType;
+import org.onap.aai.rest.db.HttpEntry;
+import org.onap.aai.rest.search.CustomQueryTestDTO;
+import org.onap.aai.restcore.RESTAPI;
+import org.onap.aai.restcore.search.GremlinGroovyShell;
+import org.onap.aai.restcore.search.GroovyQueryBuilder;
+import org.onap.aai.serialization.db.EdgeSerializer;
+import org.onap.aai.serialization.engines.TransactionalGraphEngine;
+import org.onap.aai.setup.SchemaVersion;
+import org.onap.aai.setup.SchemaVersions;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.beans.factory.annotation.Value;
+import org.springframework.http.HttpStatus;
+import org.springframework.web.bind.annotation.RequestBody;
+
+import com.att.eelf.configuration.EELFLogger;
+import com.att.eelf.configuration.EELFManager;
+import com.beust.jcommander.internal.Lists;
+import com.beust.jcommander.internal.Maps;
+
+
+@Path("/cq2gremlintest")
+public class CQ2GremlinTest extends RESTAPI {
+
+ private static final EELFLogger LOGGER = EELFManager.getInstance().getLogger(CQ2GremlinTest.class);
+
+ private HttpEntry traversalUriHttpEntry;
+
+
+ @Autowired
+ protected LoaderFactory loaderFactory;
+
+ @Autowired
+ protected EdgeSerializer rules;
+
+ protected Loader loader;
+ protected GraphTraversalSource gts;
+
+
+ @Autowired
+ public CQ2GremlinTest(
+ HttpEntry traversalUriHttpEntry,
+ @Value("${schema.uri.base.path}") String basePath
+ ){
+ this.traversalUriHttpEntry = traversalUriHttpEntry;
+
+ }
+
+ @PUT
+ @Path("")
+ @Consumes({ MediaType.APPLICATION_JSON })
+ @Produces({ MediaType.APPLICATION_JSON })
+ public Response getC2Qgremlin(@RequestBody CustomQueryTestDTO content,@Context HttpHeaders headers, @Context UriInfo info) throws AAIException {
+ if(content == null){
+ return Response.status(HttpStatus.BAD_REQUEST.value()).entity("At least one Json payload should be passed").build();
+ }
+ String sourceOfTruth = headers.getRequestHeaders().getFirst("X-FromAppId");
+ String realTime = headers.getRequestHeaders().getFirst("Real-Time");
+ SchemaVersions schemaVersions = SpringContextAware.getBean(SchemaVersions.class);
+ DBConnectionType type = this.determineConnectionType(sourceOfTruth, realTime);
+ traversalUriHttpEntry.setHttpEntryProperties(schemaVersions.getDefaultVersion(), type);
+ traversalUriHttpEntry.setPaginationParameters("-1", "-1");
+ return processC2UnitTest(content);
+ }
+
+ private Response processC2UnitTest(CustomQueryTestDTO content) {
+
+ TransactionalGraphEngine dbEngine = traversalUriHttpEntry.getDbEngine();
+ Graph graph = TinkerGraph.open();
+ gts = graph.traversal();
+ List<Vertex> expectedVertices = createGraph(content, graph);
+ GremlinGroovyShell shell = new GremlinGroovyShell();
+ loader = loaderFactory.createLoaderForVersion(ModelType.MOXY, new SchemaVersion("v16"));
+ LinkedHashMap <String, Object> params = new LinkedHashMap<>();
+
+ //Adding parameters
+ content.getQueryRequiredProperties().forEach((K, V) -> {params.put(K, V);});
+ content.getQueryOptionalProperties().forEach((K, V) -> {params.put(K, V);});
+
+ String query = new GroovyQueryBuilder().executeTraversal(dbEngine, content.getStoredQuery(), params);
+ query = "g" + query;
+ GraphTraversal<Vertex, Vertex> g = graph.traversal().V();
+ addStartNode(g, content);
+ params.put("g", g);
+
+ //Assertion
+ GraphTraversal<Vertex, Vertex> result = (GraphTraversal<Vertex, Vertex>)shell.executeTraversal(query, params);
+
+ List<Vertex> vertices = result.toList();
+
+ LOGGER.info("Expected result set of vertexes [{}]", convert(expectedVertices));
+ LOGGER.info("Actual Result set of vertexes [{}]", convert(vertices));
+
+ List<Vertex> nonDuplicateExpectedResult = new ArrayList<>(new HashSet<>(expectedVertices));
+ vertices = new ArrayList<>(new HashSet<>(vertices));
+
+ nonDuplicateExpectedResult.sort(Comparator.comparing(vertex -> vertex.id().toString()));
+ vertices.sort(Comparator.comparing(vertex -> vertex.id().toString()));
+
+
+ // Use this instead of the assertTrue as this provides more useful
+ // debugging information such as this when expected and actual differ:
+ // java.lang.AssertionError: Expected all the vertices to be found
+ // Expected :[v[2], v[3], v[4], v[5], v[6], v[7], v[8], v[9], v[10], v[11], v[12]]
+ // Actual :[v[1], v[2], v[3], v[4], v[5], v[6], v[7], v[8], v[9], v[10], v[11], v[12]]
+ if(nonDuplicateExpectedResult.equals(vertices)){
+ return Response.ok("Sucessfully executed Junit").build();
+ }
+ return Response.status(400).build();
+
+ }
+
+ private List<Vertex> createGraph(CustomQueryTestDTO content, Graph graph) {
+ Map<String, Vertex> verticesMap = Maps.newLinkedHashMap();
+ //Creating all the Vertices
+ content.getVerticesDtos().stream().forEach(vertex -> {
+ StringBuilder vertexIdentifier = new StringBuilder();
+ List<String> keyValues = Lists.newArrayList();
+ keyValues.add(T.id.toString());
+ keyValues.add(String.format("%02d", verticesMap.size() * 10));
+ AtomicInteger index = new AtomicInteger(0);
+ vertex.forEach((K, V) -> {
+ if(index.get() == 1)
+ vertexIdentifier.append(V);
+ keyValues.add(K);
+ keyValues.add(V);
+ index.incrementAndGet();
+ });
+ Vertex graphVertex = graph.addVertex(keyValues.toArray());
+ verticesMap.put(vertexIdentifier.toString(), graphVertex);
+ });
+
+ GraphTraversalSource g = graph.traversal();
+
+ //Creating all the Edges
+ content.getEdgesDtos().stream().forEach(edge -> {
+ String fromId = edge.get("from-id");
+ String toId = edge.get("to-id");
+ boolean treeEdgeIdentifier = !"NONE".equalsIgnoreCase(edge.get("contains-other-v"));
+ Vertex fromVertex = verticesMap.get(fromId);
+ Vertex toVertex = verticesMap.get(toId);
+ try{
+ if(treeEdgeIdentifier){
+ rules.addTreeEdge(g, fromVertex, toVertex);
+ }
+ else{
+ rules.addEdge(g, fromVertex, toVertex);
+ }
+ } catch(AAIException ex){
+ LOGGER.warn(ex.toString(), ex);
+ }
+
+ });
+
+
+ List<Vertex> expectedVertices = Lists.newArrayList();
+ content.getExpectedResultsDtos().getIds().stream().forEach(vertexId -> {
+ expectedVertices.add(verticesMap.get(vertexId));
+ });
+ return expectedVertices;
+ }
+
+ protected void addStartNode(GraphTraversal<Vertex, Vertex> g, CustomQueryTestDTO content) {
+ Optional<LinkedHashMap<String, String>> startNodeVertex = content.getVerticesDtos().stream().filter(map -> map.containsKey("start-node")).findFirst();
+ if(!startNodeVertex.isPresent()){
+ throw new IllegalArgumentException("start-node was not specified");
+ }
+ startNodeVertex.get().forEach((K, V) -> {
+ g.has(K, V);
+ });
+ }
+
+ protected String convert(List<Vertex> vertices){
+ return vertices
+ .stream()
+ .map(vertex -> vertex.property("aai-node-type").value().toString())
+ .collect(Collectors.joining(","));
+ }
+
+
+
+}
diff --git a/aai-traversal/src/main/java/org/onap/aai/rest/DslConsumer.java b/aai-traversal/src/main/java/org/onap/aai/rest/DslConsumer.java
index ad5fffb..2d09636 100644
--- a/aai-traversal/src/main/java/org/onap/aai/rest/DslConsumer.java
+++ b/aai-traversal/src/main/java/org/onap/aai/rest/DslConsumer.java
@@ -19,25 +19,11 @@
*/
package org.onap.aai.rest;
-import java.util.List;
-import java.util.concurrent.TimeUnit;
-
-import javax.servlet.http.HttpServletRequest;
-import javax.ws.rs.Consumes;
-import javax.ws.rs.DefaultValue;
-import javax.ws.rs.Encoded;
-import javax.ws.rs.PUT;
-import javax.ws.rs.Path;
-import javax.ws.rs.PathParam;
-import javax.ws.rs.Produces;
-import javax.ws.rs.QueryParam;
-import javax.ws.rs.core.Context;
-import javax.ws.rs.core.HttpHeaders;
-import javax.ws.rs.core.MediaType;
-import javax.ws.rs.core.Response;
-import javax.ws.rs.core.UriInfo;
-import javax.ws.rs.core.Response.Status;
-
+import com.att.eelf.configuration.EELFLogger;
+import com.att.eelf.configuration.EELFManager;
+import com.google.gson.JsonElement;
+import com.google.gson.JsonObject;
+import com.google.gson.JsonParser;
import org.onap.aai.concurrent.AaiCallable;
import org.onap.aai.dbmap.DBConnectionType;
import org.onap.aai.exceptions.AAIException;
@@ -64,11 +50,12 @@ import org.onap.aai.util.TraversalConstants;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
-import com.att.eelf.configuration.EELFLogger;
-import com.att.eelf.configuration.EELFManager;
-import com.google.gson.JsonElement;
-import com.google.gson.JsonObject;
-import com.google.gson.JsonParser;
+import javax.servlet.http.HttpServletRequest;
+import javax.ws.rs.*;
+import javax.ws.rs.core.*;
+import javax.ws.rs.core.Response.Status;
+import java.util.List;
+import java.util.concurrent.TimeUnit;
@Path("{version: v[1-9][0-9]*|latest}/dsl")
public class DslConsumer extends RESTAPI {
@@ -90,8 +77,8 @@ public class DslConsumer extends RESTAPI {
@Autowired
public DslConsumer(HttpEntry traversalUriHttpEntry, DslQueryProcessor dslQueryProcessor,
- SchemaVersions schemaVersions, GremlinServerSingleton gremlinServerSingleton,
- @Value("${schema.uri.base.path}") String basePath) {
+ SchemaVersions schemaVersions, GremlinServerSingleton gremlinServerSingleton,
+ @Value("${schema.uri.base.path}") String basePath) {
this.traversalUriHttpEntry = traversalUriHttpEntry;
this.dslQueryProcessor = dslQueryProcessor;
this.schemaVersions = schemaVersions;
diff --git a/aai-traversal/src/main/java/org/onap/aai/rest/dsl/AAIDslErrorListener.java b/aai-traversal/src/main/java/org/onap/aai/rest/dsl/AAIDslErrorListener.java
new file mode 100644
index 0000000..26a625a
--- /dev/null
+++ b/aai-traversal/src/main/java/org/onap/aai/rest/dsl/AAIDslErrorListener.java
@@ -0,0 +1,34 @@
+/**
+ * ============LICENSE_START=======================================================
+ * org.onap.aai
+ * ================================================================================
+ * Copyright © 2017-2018 AT&T Intellectual Property. All rights reserved.
+ * ================================================================================
+ * 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 org.antlr.v4.runtime.BaseErrorListener;
+import org.antlr.v4.runtime.RecognitionException;
+import org.antlr.v4.runtime.Recognizer;
+import org.antlr.v4.runtime.misc.ParseCancellationException;
+
+public class AAIDslErrorListener extends BaseErrorListener {
+
+ @Override
+ public void syntaxError(Recognizer<?, ?> recognizer, Object offendingSymbol, int line, int charPositionInLine, String msg, RecognitionException e)
+ throws ParseCancellationException {
+ throw new ParseCancellationException("line " + line + ":" + charPositionInLine + " " + msg);
+ }
+}
diff --git a/aai-traversal/src/main/java/org/onap/aai/rest/dsl/DslListener.java b/aai-traversal/src/main/java/org/onap/aai/rest/dsl/DslListener.java
index a6be24c..8fd23cc 100644
--- a/aai-traversal/src/main/java/org/onap/aai/rest/dsl/DslListener.java
+++ b/aai-traversal/src/main/java/org/onap/aai/rest/dsl/DslListener.java
@@ -19,235 +19,239 @@
*/
package org.onap.aai.rest.dsl;
-import java.util.ArrayList;
-import java.util.Deque;
-import java.util.HashMap;
-import java.util.LinkedList;
-import java.util.Map;
-import java.util.List;
-
-import org.antlr.v4.runtime.tree.TerminalNode;
-
+import com.att.eelf.configuration.EELFLogger;
+import com.att.eelf.configuration.EELFManager;
+import com.google.common.collect.Lists;
+import org.onap.aai.AAIDslBaseListener;
import org.onap.aai.AAIDslParser;
-import org.onap.aai.config.SpringContextAware;
-import org.onap.aai.edges.EdgeRuleQuery;
-import org.onap.aai.edges.enums.EdgeType;
+import org.onap.aai.edges.EdgeIngestor;
import org.onap.aai.exceptions.AAIException;
-import org.onap.aai.introspection.Introspector;
import org.onap.aai.introspection.Loader;
import org.onap.aai.introspection.LoaderFactory;
import org.onap.aai.introspection.ModelType;
-import org.onap.aai.logging.LogFormatTools;
-import org.onap.aai.setup.SchemaVersion;
import org.onap.aai.setup.SchemaVersions;
import org.springframework.beans.factory.annotation.Autowired;
-import org.onap.aai.AAIDslBaseListener;
-import org.onap.aai.edges.EdgeIngestor;
-import com.att.eelf.configuration.EELFLogger;
-import com.att.eelf.configuration.EELFManager;
+
+import java.util.ArrayList;
+import java.util.Deque;
+import java.util.LinkedList;
+import java.util.List;
+import java.util.stream.Collectors;
+import java.util.stream.Stream;
/**
* The Class DslListener.
*/
public class DslListener extends AAIDslBaseListener {
- private static final EELFLogger LOGGER = EELFManager.getInstance().getLogger(DslQueryProcessor.class);
+ private static final EELFLogger LOGGER = EELFManager.getInstance().getLogger(DslListener.class);
- private final EdgeIngestor edgeRules;
+ boolean validationFlag = false;
+ EdgeIngestor edgeIngestor;
+ Loader loader;
- DslContext context = null;
- DslQueryBuilder dslBuilder = null;
+ private Deque<DslQueryBuilder> dslQueryBuilders = new LinkedList<>();
+ private Deque<String> traversedNodes = new LinkedList<>();
+ private Deque<List<String>> returnedNodes = new LinkedList<>();
+
+ List<String> traversedEdgeLabels = new LinkedList<>();
/**
* Instantiates a new DslListener.
*/
@Autowired
public DslListener(EdgeIngestor edgeIngestor, SchemaVersions schemaVersions, LoaderFactory loaderFactory) {
- this.edgeRules = edgeIngestor;
- context = new DslContext();
+ this.loader = loaderFactory.createLoaderForVersion(ModelType.MOXY, schemaVersions.getDefaultVersion());
+ this.edgeIngestor = edgeIngestor;
+ }
- Loader loader = loaderFactory.createLoaderForVersion(ModelType.MOXY, schemaVersions.getDefaultVersion());
- dslBuilder = new DslQueryBuilder(edgeIngestor, loader);
+ public DslQueryBuilder builder() {
+ return dslQueryBuilders.peekFirst();
}
public String getQuery() throws AAIException {
+ //TODO Change the exception reporting
if (!getException().isEmpty()) {
LOGGER.error("Exception in the DSL Query" + getException());
throw new AAIException("AAI_6149", getException());
}
- return dslBuilder.getQuery().toString();
+
+ return this.compile();
+ }
+
+ public String compile() {
+ List<String> queries = dslQueryBuilders.stream().map(dslQb -> dslQb.getQuery().toString()).collect(Collectors.toList());
+ return String.join("", Lists.reverse(queries));
}
public String getException() {
- return dslBuilder.getQueryException().toString();
+ return builder().getQueryException().toString();
}
@Override
public void enterAaiquery(AAIDslParser.AaiqueryContext ctx) {
- /*
- * This is my start-node, have some validations here
- */
- context.setStartNodeFlag(true);
- dslBuilder.start();
+ dslQueryBuilders.push(new DslQueryBuilder(edgeIngestor, loader));
}
@Override
- public void exitAaiquery(AAIDslParser.AaiqueryContext ctx) {
- dslBuilder.end(context);
+ public void enterStartStatement(AAIDslParser.StartStatementContext ctx) {
+ builder().start();
}
@Override
- public void enterDslStatement(AAIDslParser.DslStatementContext ctx) {
- if (context.isUnionStart()) {
- dslBuilder.startUnion();
+ public void exitStartStatement(AAIDslParser.StartStatementContext ctx) {
+ builder().end();
+ if (!traversedNodes.isEmpty()) {
+ traversedNodes.removeFirst();
}
+
}
@Override
- public void exitDslStatement(AAIDslParser.DslStatementContext ctx) {
- if (context.isUnionQuery()) {
- dslBuilder.comma(context);
- context.setUnionStart(true);
- }
+ public void exitLimit(AAIDslParser.LimitContext ctx) {
+ builder().limit(ctx.num().getText());
}
@Override
- public void enterSingleNodeStep(AAIDslParser.SingleNodeStepContext ctx) {
- try {
- /*
- * Set the previous Node to current node and get the new current
- * node
- */
- context.setPreviousNode(context.getCurrentNode());
- context.setCurrentNode(ctx.NODE().getText());
-
- if (context.isUnionQuery() || context.isTraversal() || context.isWhereQuery()) {
- String oldPreviousNode = context.getPreviousNode();
-
- if (context.isUnionStart()) {
- String previousNode = context.getUnionStartNodes().peek();
- context.setPreviousNode(previousNode);
-
- context.setUnionStart(false);
- }
+ public void enterNestedStatement(AAIDslParser.NestedStatementContext ctx) {
+ dslQueryBuilders.addFirst(new DslQueryBuilder(edgeIngestor, loader));
+ builder().startInstance();
+ }
- dslBuilder.edgeQuery(context);
+ @Override
+ public void exitNestedStatement(AAIDslParser.NestedStatementContext ctx) {
+ int count = 1;
+ if(!ctx.traversal().isEmpty()) {
+ count += ctx.traversal().size() ;
+ }
+ //TODO so ugly
+ String resultNode = traversedNodes.peekFirst();
- /*
- * Reset is required bcos for union queries im changing the
- * context
- */
- context.setPreviousNode(oldPreviousNode);
+ if (!traversedNodes.isEmpty()) {
+ Stream<Integer> integers = Stream.iterate(0, i -> i + 1);
+ integers.limit(count)
+ .forEach(i -> traversedNodes.removeFirst());
+ }
+ List<String> resultNodes = returnedNodes.pop();
+ resultNodes.add(resultNode);
+ returnedNodes.addFirst(resultNodes);
+ }
- }
+ @Override
+ public void enterComma(AAIDslParser.CommaContext ctx) {
+ builder().comma();
+ }
- else {
- dslBuilder.nodeQuery(context);
- }
+ @Override
+ public void enterVertex(AAIDslParser.VertexContext ctx) {
- } catch (AAIException e) {
- LOGGER.info("AAIException in DslListener" + e.getMessage());
+ if (!traversedNodes.isEmpty()) {
+ builder().edgeQuery(traversedEdgeLabels, traversedNodes.peekFirst(), ctx.label().getText());
+ } else {
+ builder().nodeQuery(ctx.label().getText());
}
+ traversedNodes.addFirst(ctx.label().getText());
}
@Override
- public void exitSingleNodeStep(AAIDslParser.SingleNodeStepContext ctx) {
- if (context.isStartNode() && isValidationFlag()) {
- try {
- dslBuilder.validateFilter(context);
- } catch (AAIException e) {
- LOGGER.error("AAIException in DslListener" + LogFormatTools.getStackTop(e));
+ public void exitVertex(AAIDslParser.VertexContext ctx) {
+
+ /*TODO dont use context */
+ if (ctx.getParent() instanceof AAIDslParser.StartStatementContext && isValidationFlag()) {
+ List<String> allKeys = new ArrayList<>();
+
+ if (ctx.filter() != null) {
+ allKeys = ctx.filter().propertyFilter().stream().flatMap(
+ pf -> pf.key().stream()).map(
+ e -> e.getText().replaceAll("\'", "")).collect(Collectors.toList());
+
}
+ builder().validateFilter(ctx.label().getText(), allKeys);
}
- context.setStartNodeFlag(false);
- context.setCtx(ctx);
- dslBuilder.store(context);
+ if (ctx.store() != null) {
+ builder().store();
+ }
+ traversedEdgeLabels = new ArrayList<>();
}
- private void generateExitStep() {
+ @Override
+ public void enterUnionVertex(AAIDslParser.UnionVertexContext ctx) {
+ returnedNodes.addFirst(new ArrayList<>());
+ builder().union();
}
@Override
- public void enterUnionQueryStep(AAIDslParser.UnionQueryStepContext ctx) {
-
- Deque<String> unionStartNodes = context.getUnionStartNodes();
- unionStartNodes.add(context.getCurrentNode());
-
- context.setUnionStart(true);
- /*
- * I may not need this
- */
- context.setUnionQuery(true);
- dslBuilder.union(context);
+ public void exitUnionVertex(AAIDslParser.UnionVertexContext ctx) {
+ String resultNode = returnedNodes.pop().get(0);
+ traversedNodes.addFirst(resultNode);
+ builder().endUnion();
+ }
+ @Override
+ public void enterWhereFilter(AAIDslParser.WhereFilterContext ctx) {
+ returnedNodes.addFirst(new ArrayList<>());
+ builder().where();
}
@Override
- public void exitUnionQueryStep(AAIDslParser.UnionQueryStepContext ctx) {
- context.setUnionStart(false);
- context.setUnionQuery(false);
- Deque<String> unionStartNodes = context.getUnionStartNodes();
- if (unionStartNodes.peek() != null) {
- unionStartNodes.pop();
+ public void exitWhereFilter(AAIDslParser.WhereFilterContext ctx) {
+ if(!returnedNodes.isEmpty()) {
+ returnedNodes.pop();
}
-
- dslBuilder.endUnion(context);
-
+ builder().endWhere();
}
@Override
- public void enterFilterTraverseStep(AAIDslParser.FilterTraverseStepContext ctx) {
- context.setWhereQuery(true);
- context.setWhereStartNode(context.getCurrentNode());
- dslBuilder.where(context);
-
+ public void enterTraversal(AAIDslParser.TraversalContext ctx) {
}
@Override
- public void exitFilterTraverseStep(AAIDslParser.FilterTraverseStepContext ctx) {
- context.setWhereQuery(false);
- context.setCurrentNode(context.getWhereStartNode());
-
- dslBuilder.endWhere(context);
-
+ public void enterEdge(AAIDslParser.EdgeContext ctx) {
}
@Override
- public void enterFilterStep(AAIDslParser.FilterStepContext ctx) {
+ public void enterEdgeFilter(AAIDslParser.EdgeFilterContext ctx) {
+ traversedEdgeLabels = ctx.key().stream().map(value -> value.getText()).collect(Collectors.toList());
- context.setCtx(ctx);
- dslBuilder.filter(context);
}
@Override
- public void exitFilterStep(AAIDslParser.FilterStepContext ctx) {
- // For now do nothing
- }
+ public void enterFilter(AAIDslParser.FilterContext ctx) {
- @Override
- public void enterTraverseStep(AAIDslParser.TraverseStepContext ctx) {
- context.setTraversal(true);
}
@Override
- public void exitTraverseStep(AAIDslParser.TraverseStepContext ctx) {
- context.setTraversal(false);
+ public void enterPropertyFilter(AAIDslParser.PropertyFilterContext ctx) {
+
+ List<AAIDslParser.KeyContext> valueList = ctx.key();
+ String filterKey = valueList.get(0).getText();
+
+ boolean isNot = ctx.not() != null && !ctx.not().isEmpty();
+ List<AAIDslParser.NumContext> numberValues = ctx.num();
+
+ /*
+ * Add all String values
+ */
+ List<String> values = valueList.stream().filter(value -> !filterKey.equals(value.getText()))
+ .map(value -> "'" + value.getText().replace("'", "") + "'").collect(Collectors.toList());
+ /*
+ * Add all numeric values
+ */
+ values.addAll(numberValues.stream().filter(value -> !filterKey.equals(value.getText()))
+ .map(value -> value.getText()).collect(Collectors.toList()));
+
+ builder().filter(isNot, traversedNodes.peekFirst(), filterKey, values);
+
}
- @Override
- public void enterLimitStep(AAIDslParser.LimitStepContext ctx) {
- context.setCtx(ctx);
- dslBuilder.limit(context);
+ public boolean isValidationFlag() {
+ return validationFlag;
}
-
+
public void setValidationFlag(boolean validationFlag) {
- this.context.setValidationFlag(validationFlag);
- }
-
- public boolean isValidationFlag() {
- return this.context.isValidationFlag();
+ this.validationFlag = validationFlag;
}
}
diff --git a/aai-traversal/src/main/java/org/onap/aai/rest/dsl/DslQueryBuilder.java b/aai-traversal/src/main/java/org/onap/aai/rest/dsl/DslQueryBuilder.java
index fce8a98..6817cf7 100644
--- a/aai-traversal/src/main/java/org/onap/aai/rest/dsl/DslQueryBuilder.java
+++ b/aai-traversal/src/main/java/org/onap/aai/rest/dsl/DslQueryBuilder.java
@@ -19,224 +19,247 @@
*/
package org.onap.aai.rest.dsl;
-import java.util.ArrayList;
-import java.util.List;
-import java.util.Set;
-import java.util.stream.Collectors;
-
-import org.antlr.v4.runtime.tree.TerminalNode;
-import org.apache.tinkerpop.gremlin.structure.Direction;
-import org.apache.tinkerpop.gremlin.structure.Edge;
-import org.onap.aai.AAIDslBaseListener;
-import org.onap.aai.AAIDslParser;
+import com.google.common.base.Joiner;
+import com.google.common.collect.ArrayListMultimap;
+import com.google.common.collect.Multimap;
import org.onap.aai.edges.EdgeIngestor;
+import org.onap.aai.edges.EdgeRule;
import org.onap.aai.edges.EdgeRuleQuery;
import org.onap.aai.edges.enums.EdgeType;
-import org.onap.aai.exceptions.AAIException;
+import org.onap.aai.edges.exceptions.EdgeRuleNotFoundException;
import org.onap.aai.introspection.Introspector;
import org.onap.aai.introspection.Loader;
import org.onap.aai.introspection.exceptions.AAIUnknownObjectException;
+import org.onap.aai.schema.enums.PropertyMetadata;
-import com.jcabi.log.Logger;
+import java.util.List;
+import java.util.Optional;
+import java.util.stream.Collectors;
public class DslQueryBuilder {
- private StringBuilder query;
- private StringBuilder queryException;
- private final EdgeIngestor edgeRules;
- private final Loader loader;
-
- public DslQueryBuilder(EdgeIngestor edgeIngestor, Loader loader) {
- this.edgeRules = edgeIngestor;
- this.loader = loader;
- query = new StringBuilder();
- queryException = new StringBuilder();
- }
-
- public StringBuilder getQuery() {
- return query;
- }
-
- public void setQuery(StringBuilder query) {
- this.query = query;
- }
-
- public StringBuilder getQueryException() {
- return queryException;
- }
-
- public void setQueryException(StringBuilder queryException) {
- this.queryException = queryException;
- }
-
- public DslQueryBuilder start() {
- query.append("builder");
- return this;
- }
-
- public DslQueryBuilder startUnion() {
- query.append("builder.newInstance()");
- return this;
- }
-
- public DslQueryBuilder end(DslContext context) {
- query.append(".cap('x').unfold().dedup()").append(context.getLimitQuery());
- return this;
- }
-
- public DslQueryBuilder nodeQuery(DslContext context) {
- query.append(".getVerticesByProperty('aai-node-type', '").append(context.getCurrentNode()).append("')");
- if(context.isStartNode() && context.getStartNode().isEmpty())
- context.setStartNode(context.getCurrentNode());
- return this;
- }
-
- public DslQueryBuilder edgeQuery(DslContext context) throws AAIException {
- EdgeRuleQuery.Builder baseQ = new EdgeRuleQuery.Builder(context.getPreviousNode(), context.getCurrentNode());
- String edgeType = "";
- if (!edgeRules.hasRule(baseQ.build())) {
- throw new AAIException("AAI_6120", "No EdgeRule found for passed nodeTypes: " + context.getPreviousNode()
- + ", " + context.getCurrentNode());
- } else if (edgeRules.hasRule(baseQ.edgeType(EdgeType.TREE).build())) {
- edgeType = "EdgeType.TREE";
- } else if (edgeRules.hasRule(baseQ.edgeType(EdgeType.COUSIN).build())) {
- edgeType = "EdgeType.COUSIN";
- } else
- edgeType = "EdgeType.COUSIN";
-
- query.append(".createEdgeTraversal(").append(edgeType).append(", '").append(context.getPreviousNode())
- .append("','").append(context.getCurrentNode()).append("')");
-
- return this;
- }
-
- public DslQueryBuilder where(DslContext context) {
- query.append(".where(builder.newInstance()");
- return this;
- }
-
- public DslQueryBuilder endWhere(DslContext context) {
- query.append(")");
- return this;
- }
-
- public DslQueryBuilder endUnion(DslContext context) {
- /*
- * Need to delete the last comma
- */
- if (query.toString().endsWith(",")) {
- query.deleteCharAt(query.length() - 1);
- }
- query.append(")");
- return this;
- }
-
- public DslQueryBuilder limit(DslContext context) {
- /*
- * limit queries are strange - You have to append in the end
- */
- AAIDslParser.LimitStepContext ctx = (AAIDslParser.LimitStepContext) context.getCtx();
- context.setLimitQuery(new StringBuilder(".limit(").append(ctx.NODE().getText()).append(")"));
- return this;
- }
-
- public DslQueryBuilder filter(DslContext context) {
- return this.filterPropertyStart(context).filterPropertyKeys(context).filterPropertyEnd();
-
- }
-
- public DslQueryBuilder filterPropertyStart(DslContext context) {
- AAIDslParser.FilterStepContext ctx = (AAIDslParser.FilterStepContext) context.getCtx();
- if (ctx.NOT() != null && ctx.NOT().getText().equals("!"))
- query.append(".getVerticesExcludeByProperty(");
- else
- query.append(".getVerticesByProperty(");
-
- return this;
-
- }
-
- public DslQueryBuilder filterPropertyEnd() {
- query.append(")");
- return this;
-
- }
-
- public DslQueryBuilder validateFilter(DslContext context) throws AAIException {
- Introspector obj = loader.introspectorFromName(context.getStartNode());
- if(context.getStartNodeKeys().isEmpty()){
- queryException.append("No keys sent. Valid keys for " + context.getStartNode() + " are "
- + String.join(",", obj.getIndexedProperties()));
- return this;
- }
- boolean notIndexed = context.getStartNodeKeys().stream()
- .filter((prop) -> obj.getIndexedProperties().contains(prop)).collect(Collectors.toList()).isEmpty();
- if (notIndexed)
- queryException.append("Non indexed keys sent. Valid keys for " + context.getStartNode() + " "
- + String.join(",", obj.getIndexedProperties()));
-
- return this;
- }
-
- public DslQueryBuilder filterPropertyKeys(DslContext context) {
- AAIDslParser.FilterStepContext ctx = (AAIDslParser.FilterStepContext) context.getCtx();
- final String key = ctx.KEY(0).getText();
- /*
- * This key should be indexed if it is start node
- */
- if (context.isStartNode() && context.getStartNodeKeys().isEmpty()) {
- // check if key is not indexed, then throw exception
- context.getStartNodeKeys().add(key.replaceAll("'", ""));
- }
-
- query.append(key);
- List<TerminalNode> nodes = ctx.KEY();
- List<TerminalNode> numberValues = ctx.NODE();
- /*
- * Add all String values
- */
- List<String> valuesArray = nodes.stream().filter((node) -> !key.equals(node.getText()))
- .map((node) -> "'" + node.getText().replace("'", "").trim() + "'").collect(Collectors.toList());
-
- /*
- * Add all numeric values
- */
- valuesArray.addAll(numberValues.stream().filter((node) -> !key.equals(node.getText()) )
- .map((node) -> node.getText()).collect(Collectors.toList()));
-
-
- /*
- * The whole point of doing this to separate P.within from key-value
- * search For a list of values QB uses P.within For just a single value
- * QB uses key,value check
- */
- if (nodes.size() > 2) {
- String values = String.join(",", valuesArray);
- query.append(",").append(" new ArrayList<>(Arrays.asList(" + values.toString() + "))");
- } else {
- if (!valuesArray.isEmpty())
- query.append(",").append(valuesArray.get(0).toString());
- }
- return this;
- }
-
- public DslQueryBuilder union(DslContext context) {
- query.append(".union(");
- return this;
- }
-
- public DslQueryBuilder store(DslContext context) {
- AAIDslParser.SingleNodeStepContext ctx = (AAIDslParser.SingleNodeStepContext) context.getCtx();
- if (ctx.STORE() != null && ctx.STORE().getText().equals("*")) {
- query.append(".store('x')");
- }
- return this;
-
- }
-
- public DslQueryBuilder comma(DslContext context) {
- query.append(",");
- return this;
-
- }
+ private final EdgeIngestor edgeRules;
+ private final Loader loader;
+ private StringBuilder query;
+ private StringBuilder queryException;
+
+ public DslQueryBuilder(EdgeIngestor edgeIngestor, Loader loader) {
+ this.edgeRules = edgeIngestor;
+ this.loader = loader;
+ query = new StringBuilder();
+ queryException = new StringBuilder();
+ }
+
+ public StringBuilder getQuery() {
+ return query;
+ }
+
+ public void setQuery(StringBuilder query) {
+ this.query = query;
+ }
+
+ public StringBuilder getQueryException() {
+ return queryException;
+ }
+
+ public void setQueryException(StringBuilder queryException) {
+ this.queryException = queryException;
+ }
+
+ public DslQueryBuilder start() {
+ query.append("builder");
+ return this;
+ }
+
+ /*
+ * DSL always dedupes the results
+ */
+ public DslQueryBuilder end() {
+ query.append(".cap('x').unfold().dedup()");
+ return this;
+ }
+
+ public DslQueryBuilder nodeQuery(String node) {
+ query.append(".getVerticesByProperty('aai-node-type', '").append(node).append("')");
+ return this;
+ }
+
+ public DslQueryBuilder edgeQuery(List<String> edgeLabels, String aNode, String bNode) {
+ //TODO : change this for fuzzy search.
+
+ String edgeType = "";
+ String edgeLabelsClause = "";
+ String edgeTraversalClause = ".createEdgeTraversal(";
+
+
+ if (!edgeLabels.isEmpty()) {
+ edgeTraversalClause = ".createEdgeTraversalWithLabels(";
+ edgeLabelsClause = String.join("", ", new ArrayList<>(Arrays.asList(", Joiner.on(",").join(edgeLabels), "))");
+ }
+
+ EdgeRuleQuery.Builder baseQ = new EdgeRuleQuery.Builder(aNode, bNode);
+ Multimap<String, EdgeRule> rules = ArrayListMultimap.create();
+ try {
+ //TODO chnage this - ugly
+ if (edgeLabels.isEmpty()) {
+ rules.putAll(edgeRules.getRules(baseQ.build()));
+ } else {
+ edgeLabels.stream().forEach(label -> {
+ try {
+ rules.putAll(edgeRules.getRules(baseQ.label(label).build()));
+ } catch (EdgeRuleNotFoundException e) {
+ queryException.append("AAI_6120" + "No EdgeRule found for passed nodeTypes: " + aNode
+ + ", " + bNode + label);
+
+ }
+ });
+
+ }
+ } catch (EdgeRuleNotFoundException e) {
+ if (!edgeLabels.isEmpty()) {
+ queryException.append("AAI_6120" + "No EdgeRule found for passed nodeTypes: " + aNode
+ + ", " + bNode + edgeLabels.stream().toString());
+ }
+ else {
+ queryException.append("AAI_6120" + "No EdgeRule found for passed nodeTypes: " + aNode
+ + ", " + bNode);
+ }
+ return this;
+ }
+
+ if (rules.isEmpty() || rules.keys().isEmpty()) {
+ queryException.append("AAI_6120" + "No EdgeRule found for passed nodeTypes: " + aNode
+ + ", " + bNode);
+ } else {
+ if (edgeLabels.isEmpty()) {
+ if (edgeRules.hasRule(baseQ.edgeType(EdgeType.TREE).build())) {
+ edgeType = "EdgeType.TREE" + ",";
+ }
+ if (edgeRules.hasRule(baseQ.edgeType(EdgeType.COUSIN).build())) {
+ if (edgeType.isEmpty()) {
+ edgeType = "EdgeType.COUSIN" + ",";
+ } else {
+ edgeType = "";
+ }
+ }
+ }
+ }
+
+ query.append(edgeTraversalClause).append(edgeType).append(" '").append(aNode)
+ .append("','").append(bNode).append("'").append(edgeLabelsClause).append(")");
+
+ return this;
+ }
+
+
+ public DslQueryBuilder where() {
+ query.append(".where(");
+ return this;
+ }
+
+ public DslQueryBuilder endWhere() {
+ query.append(")");
+ return this;
+ }
+
+ public DslQueryBuilder limit(String limit) {
+ query.append(".limit(").append(limit).append(")");
+ return this;
+ }
+
+ public DslQueryBuilder filter(boolean isNot, String node, String key, List<String> values) {
+ return this.filterPropertyStart(isNot).filterPropertyKeys(node, key, values).filterPropertyEnd();
+ }
+
+ public DslQueryBuilder filterPropertyStart(boolean isNot) {
+ if (isNot) {
+ query.append(".getVerticesExcludeByProperty(");
+ } else {
+ query.append(".getVerticesByProperty(");
+ }
+ return this;
+ }
+
+ public DslQueryBuilder filterPropertyEnd() {
+ query.append(")");
+ return this;
+ }
+
+ public DslQueryBuilder validateFilter(String node, List<String> keys) {
+ try {
+ Introspector obj = loader.introspectorFromName(node);
+ if (keys.isEmpty()) {
+ queryException.append("No keys sent. Valid keys for " + node + " are "
+ + String.join(",", obj.getIndexedProperties()));
+ return this;
+ }
+
+ boolean notIndexed = keys.stream()
+ .filter(prop -> obj.getIndexedProperties().contains(prop)).collect(Collectors.toList()).isEmpty();
+
+ if (notIndexed) {
+ queryException.append("Non indexed keys sent. Valid keys for " + node + " "
+ + String.join(",", obj.getIndexedProperties()));
+ }
+ } catch (AAIUnknownObjectException e) {
+ queryException.append("Unknown Object being referenced by the query" + node);
+ }
+ return this;
+
+ }
+
+ public DslQueryBuilder filterPropertyKeys(String node, String key, List<String> values) {
+ try {
+ Introspector obj = loader.introspectorFromName(node);
+
+ Optional<String> alias = obj.getPropertyMetadata(key, PropertyMetadata.DB_ALIAS);
+ if (alias.isPresent()) {
+ key = alias.get();
+ }
+ query.append(key);
+
+ if (!values.isEmpty()) {
+ if (values.size() > 1) {
+ String valuesArray = String.join(",", values);
+ query.append(",").append(" new ArrayList<>(Arrays.asList(" + valuesArray + "))");
+ } else {
+ query.append(",").append(values.get(0));
+ }
+ }
+ } catch (AAIUnknownObjectException e) {
+ queryException.append("Unknown Object being referenced by the query" + node);
+ }
+ return this;
+ }
+
+ public DslQueryBuilder union() {
+ query.append(".union(");
+ return this;
+ }
+
+ public DslQueryBuilder endUnion() {
+ query.append(")");
+ return this;
+ }
+
+ public DslQueryBuilder store() {
+ query.append(".store('x')");
+ return this;
+ }
+
+ public DslQueryBuilder startInstance() {
+ query.append("builder.newInstance()");
+ return this;
+ }
+
+ public DslQueryBuilder endInstance() {
+ return this;
+ }
+
+ public DslQueryBuilder comma() {
+ query.append(",");
+ return this;
+ }
+
+
}
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 d9ce63e..a3978fd 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
@@ -19,25 +19,23 @@
*/
package org.onap.aai.rest.dsl;
-import java.io.ByteArrayInputStream;
-import java.io.InputStream;
-import java.nio.charset.StandardCharsets;
-
+import com.att.eelf.configuration.EELFLogger;
+import com.att.eelf.configuration.EELFManager;
import org.antlr.v4.runtime.CharStreams;
import org.antlr.v4.runtime.CommonTokenStream;
+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.AAIDslLexer;
import org.onap.aai.AAIDslParser;
import org.onap.aai.exceptions.AAIException;
-import org.onap.aai.rest.dsl.DslListener;
-import org.antlr.v4.runtime.Token;
-
-import com.att.eelf.configuration.EELFLogger;
-import com.att.eelf.configuration.EELFManager;
import org.springframework.beans.factory.annotation.Autowired;
+import java.io.ByteArrayInputStream;
+import java.io.InputStream;
+import java.nio.charset.StandardCharsets;
+
+
/**
* The Class DslQueryProcessor.
*/
@@ -60,18 +58,23 @@ public class DslQueryProcessor {
// Create a lexer from the input CharStream
AAIDslLexer lexer = new AAIDslLexer(CharStreams.fromStream(stream, StandardCharsets.UTF_8));
+ lexer.removeErrorListeners();
+ lexer.addErrorListener(new AAIDslErrorListener());
// Get a list of tokens pulled from the lexer
CommonTokenStream tokens = new CommonTokenStream(lexer);
// Parser that feeds off of the tokens buffer
AAIDslParser parser = new AAIDslParser(tokens);
+ parser.removeErrorListeners(); // remove ConsoleErrorListener
+ parser.addErrorListener(new AAIDslErrorListener());
dslListener.setValidationFlag(isValidationFlag());
// Specify our entry point
ParseTree ptree = parser.aaiquery();
LOGGER.info("QUERY-interim" + ptree.toStringTree(parser));
+
// Walk it and attach our listener
ParseTreeWalker walker = new ParseTreeWalker();
walker.walk(dslListener, ptree);
@@ -83,8 +86,10 @@ public class DslQueryProcessor {
*
*/
return dslListener.getQuery();
- } catch (AAIException e) {
- throw new AAIException("AAI_6149", "Error while processing the query :" + e.getMessage());
+ } catch(ParseCancellationException e){
+ throw new AAIException("AAI_6149", "DSL Syntax Error while processing the query :" + e.getMessage());
+ } catch(AAIException e) {
+ throw new AAIException("AAI_6149", "DSL Syntax Error while processing the query :" + e.getMessage());
} catch (Exception e) {
throw new AAIException("AAI_6149","Error while processing the query :" + e.getMessage());
}
diff --git a/aai-traversal/src/main/java/org/onap/aai/rest/search/CustomQueryConfigDTO.java b/aai-traversal/src/main/java/org/onap/aai/rest/search/CustomQueryConfigDTO.java
new file mode 100644
index 0000000..30d8d30
--- /dev/null
+++ b/aai-traversal/src/main/java/org/onap/aai/rest/search/CustomQueryConfigDTO.java
@@ -0,0 +1,70 @@
+/**
+ * ============LICENSE_START=======================================================
+ * org.onap.aai
+ * ================================================================================
+ * Copyright © 2017-2018 AT&T Intellectual Property. All rights reserved.
+ * ================================================================================
+ * 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.search;
+
+/*-
+ * ============LICENSE_START=======================================================
+ * org.onap.aai
+ * ================================================================================
+ * Copyright (C) 2017 AT&T Intellectual Property. All rights reserved.
+ * ================================================================================
+ * 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=========================================================
+ */
+
+import org.springframework.util.StringUtils;
+
+import com.fasterxml.jackson.annotation.JsonProperty;
+
+public class CustomQueryConfigDTO {
+
+ @JsonProperty("stored-query")
+ private String storedQuery;
+ @JsonProperty("query")
+ private CustomQueryDTO queryDTO;
+
+ public CustomQueryDTO getQueryDTO() {
+ if(queryDTO == null)
+ queryDTO = new CustomQueryDTO();
+ if (!StringUtils.isEmpty(storedQuery)) {
+ queryDTO.setQuery(storedQuery);
+ }
+ return queryDTO;
+ }
+
+ public void setQueryDTO(CustomQueryDTO query) {
+ this.queryDTO = query;
+ }
+
+ public void setStoredQuery(String storedQuery) {
+ this.storedQuery = storedQuery;
+ }
+
+}
diff --git a/aai-traversal/src/main/java/org/onap/aai/rest/search/CustomQueryDTO.java b/aai-traversal/src/main/java/org/onap/aai/rest/search/CustomQueryDTO.java
new file mode 100644
index 0000000..16b1430
--- /dev/null
+++ b/aai-traversal/src/main/java/org/onap/aai/rest/search/CustomQueryDTO.java
@@ -0,0 +1,56 @@
+package org.onap.aai.rest.search;
+
+/**
+ * ============LICENSE_START=======================================================
+ * org.onap.aai
+ * ================================================================================
+ * Copyright © 2017-2018 AT&T Intellectual Property. All rights reserved.
+ * ================================================================================
+ * 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=========================================================
+ */
+
+import java.util.List;
+
+import com.fasterxml.jackson.annotation.JsonProperty;
+import com.google.common.collect.Lists;
+
+public class CustomQueryDTO {
+
+ private String query;
+ @JsonProperty("optional-properties")
+ private List<String> queryOptionalProperties = Lists.newArrayList();
+ @JsonProperty("required-properties")
+ private List<String> queryRequiredProperties = Lists.newArrayList();;
+
+ public void setQuery(String query) {
+ this.query = query;
+ }
+ public String getQuery() {
+ return this.query;
+ }
+
+ public void setQueryOptionalProperties( List<String> queryOptionalProperties) {
+ this.queryOptionalProperties = queryOptionalProperties;
+ }
+ public List<String> getQueryOptionalProperties( ) {
+ return queryOptionalProperties;
+ }
+ public void setQueryRequiredProperties( List<String> queryRequiredProperties) {
+ this.queryRequiredProperties = queryRequiredProperties;
+ }
+ public List<String> getQueryRequiredProperties( ) {
+ return queryRequiredProperties;
+ }
+
+}
diff --git a/aai-traversal/src/main/java/org/onap/aai/rest/search/CustomQueryTestDTO.java b/aai-traversal/src/main/java/org/onap/aai/rest/search/CustomQueryTestDTO.java
new file mode 100644
index 0000000..cdc9d15
--- /dev/null
+++ b/aai-traversal/src/main/java/org/onap/aai/rest/search/CustomQueryTestDTO.java
@@ -0,0 +1,121 @@
+/**
+ * ============LICENSE_START=======================================================
+ * org.onap.aai
+ * ================================================================================
+ * Copyright © 2017-2018 AT&T Intellectual Property. All rights reserved.
+ * ================================================================================
+ * 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.search;
+
+/*-
+ * ============LICENSE_START=======================================================
+ * org.onap.aai
+ * ================================================================================
+ * Copyright (C) 2017 AT&T Intellectual Property. All rights reserved.
+ * ================================================================================
+ * 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=========================================================
+ */
+
+import java.util.LinkedHashMap;
+import java.util.List;
+import java.util.Map;
+
+import com.beust.jcommander.internal.Maps;
+import com.fasterxml.jackson.annotation.JsonProperty;
+
+public class CustomQueryTestDTO {
+
+
+ @JsonProperty("stored-query")
+ private String storedQuery;
+
+ @JsonProperty("vertices")
+ private List<LinkedHashMap<String, String>> verticesDtos;
+
+ @JsonProperty("edges")
+ private List<LinkedHashMap<String, String>> edgesDtos;
+
+ @JsonProperty("optional-properties")
+ private Map<String, String> queryOptionalProperties = Maps.newHashMap();
+
+ @JsonProperty("required-properties")
+ private Map<String, String> queryRequiredProperties = Maps.newHashMap();
+
+ @JsonProperty("expected-result")
+ private ExpectedResultsDto expectedResultsDtos;
+
+ public String getStoredQuery() {
+ return storedQuery;
+ }
+
+ public void setStoredQuery(String storedQuery) {
+ this.storedQuery = storedQuery;
+ }
+
+ public List<LinkedHashMap<String, String>> getVerticesDtos() {
+ return verticesDtos;
+ }
+
+ public void setVerticesDtos(List<LinkedHashMap<String, String>> verticesDtos) {
+ this.verticesDtos = verticesDtos;
+ }
+
+ public List<LinkedHashMap<String, String>> getEdgesDtos() {
+ return edgesDtos;
+ }
+
+ public void setEdgesDtos(List<LinkedHashMap<String, String>> edgesDtos) {
+ this.edgesDtos = edgesDtos;
+ }
+
+ public Map<String, String> getQueryOptionalProperties() {
+ return queryOptionalProperties;
+ }
+
+ public void setQueryOptionalProperties(
+ Map<String, String> queryOptionalProperties) {
+ this.queryOptionalProperties = queryOptionalProperties;
+ }
+
+ public Map<String, String> getQueryRequiredProperties() {
+ return queryRequiredProperties;
+ }
+
+ public void setQueryRequiredProperties(
+ Map<String, String> queryRequiredProperties) {
+ this.queryRequiredProperties = queryRequiredProperties;
+ }
+
+ public ExpectedResultsDto getExpectedResultsDtos() {
+ return expectedResultsDtos;
+ }
+
+ public void setExpectedResultsDtos(ExpectedResultsDto expectedResultsDtos) {
+ this.expectedResultsDtos = expectedResultsDtos;
+ }
+
+
+}
diff --git a/aai-traversal/src/main/java/org/onap/aai/rest/search/ExpectedResultsDto.java b/aai-traversal/src/main/java/org/onap/aai/rest/search/ExpectedResultsDto.java
new file mode 100644
index 0000000..9c4c3b0
--- /dev/null
+++ b/aai-traversal/src/main/java/org/onap/aai/rest/search/ExpectedResultsDto.java
@@ -0,0 +1,39 @@
+/**
+ * ============LICENSE_START=======================================================
+ * org.onap.aai
+ * ================================================================================
+ * Copyright © 2017-2018 AT&T Intellectual Property. All rights reserved.
+ * ================================================================================
+ * 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.search;
+
+import java.util.List;
+
+import com.fasterxml.jackson.annotation.JsonProperty;
+
+public class ExpectedResultsDto {
+ @JsonProperty("ids")
+ List<String> ids;
+
+ public List<String> getIds() {
+ return ids;
+ }
+
+ public void setIds(List<String> ids) {
+ this.ids = ids;
+ }
+
+}
diff --git a/aai-traversal/src/main/java/org/onap/aai/web/JerseyConfiguration.java b/aai-traversal/src/main/java/org/onap/aai/web/JerseyConfiguration.java
index 231c82b..ab3c9fd 100644
--- a/aai-traversal/src/main/java/org/onap/aai/web/JerseyConfiguration.java
+++ b/aai-traversal/src/main/java/org/onap/aai/web/JerseyConfiguration.java
@@ -22,6 +22,8 @@ package org.onap.aai.web;
import org.glassfish.jersey.filter.LoggingFilter;
import org.glassfish.jersey.server.ResourceConfig;
import org.glassfish.jersey.servlet.ServletProperties;
+import org.onap.aai.rest.CQ2Gremlin;
+import org.onap.aai.rest.CQ2GremlinTest;
import org.onap.aai.rest.DslConsumer;
import org.onap.aai.rest.QueryConsumer;
import org.onap.aai.rest.RecentAPIConsumer;
@@ -37,6 +39,7 @@ import org.springframework.stereotype.Component;
import javax.annotation.Priority;
import javax.ws.rs.container.ContainerRequestFilter;
import javax.ws.rs.container.ContainerResponseFilter;
+
import java.util.List;
import java.util.Set;
import java.util.logging.Logger;
@@ -60,6 +63,8 @@ public class JerseyConfiguration extends ResourceConfig {
register(RecentAPIConsumer.class);
register(DslConsumer.class);
register(EchoResponse.class);
+ register(CQ2Gremlin.class);
+ register(CQ2GremlinTest.class);
//Request Filters
registerFiltersForRequests();
diff --git a/aai-traversal/src/main/resources/antlr4/org/onap/aai/AAIDsl.g4 b/aai-traversal/src/main/resources/antlr4/org/onap/aai/AAIDsl.g4
index cf34571..78162f5 100644
--- a/aai-traversal/src/main/resources/antlr4/org/onap/aai/AAIDsl.g4
+++ b/aai-traversal/src/main/resources/antlr4/org/onap/aai/AAIDsl.g4
@@ -1,29 +1,41 @@
/**
- * Define a grammar called AAIDsl
+ * Define a parser grammar called AAIDsl
*/
grammar AAIDsl;
+aaiquery: startStatement limit?;
-aaiquery: dslStatement;
+startStatement: (vertex ) (traversal)* ;
+nestedStatement: (vertex|unionVertex ) (traversal)* ;
-dslStatement: (singleNodeStep ) (traverseStep )* limitStep*;
+vertex: label store? (filter)?;
-unionQueryStep: LBRACKET dslStatement ( COMMA (dslStatement))* RBRACKET;
+traversal: (edge (vertex|unionVertex));
-traverseStep: (TRAVERSE ( singleNodeStep | unionQueryStep));
+filter: (propertyFilter)* whereFilter?;
+propertyFilter: (not? '(' key (',' (key | num))* ')');
-singleNodeStep: NODE STORE? (filterStep | filterTraverseStep)*;
+whereFilter: (not? '(' edge nestedStatement ')' );
-filterStep: NOT? (LPAREN KEY (COMMA (KEY | NODE))* RPAREN);
-filterTraverseStep: (LPAREN traverseStep* RPAREN);
+unionVertex: '[' ( (edgeFilter)* nestedStatement ( comma ( (edgeFilter)* nestedStatement))*) ']';
-limitStep: LIMIT NODE;
+comma: ',';
+edge: TRAVERSE (edgeFilter)*;
+edgeFilter: '(' key (',' key )* ')';
-LIMIT: 'LIMIT';
-NODE: ID;
+num: NUM;
+limit: LIMIT num;
+label: (ID | NUM )+;
+key: KEY;
-KEY: ['] (ID | ' ')* ['] ;
+store: STORE;
+not: NOT;
+LIMIT: 'LIMIT'|'limit';
+NUM: (DIGIT)+;
+
+/*NODE: (ID | NUM )+;*/
+KEY : '\'' ( ~['\r\n] )*? '\'';
AND: [&];
@@ -33,29 +45,18 @@ OR: [|];
TRAVERSE: [>] ;
-LPAREN: [(];
-
-RPAREN: [)];
-
-COMMA: [,] ;
-
EQUAL: [=];
-LBRACKET: [[];
-
-RBRACKET: [\]];
-
NOT: [!];
-VALUE: [DIGIT]+;
-
fragment LOWERCASE : [a-z] ;
fragment UPPERCASE : [A-Z] ;
fragment DIGIT : [0-9] ;
+fragment ESC : '\\' . ;
+fragment ID_SPECIALS: [-:_];
+
ID
- : ( LOWERCASE | UPPERCASE | DIGIT) ( LOWERCASE | UPPERCASE | DIGIT | '-' | '.' | '_' | '/')*
+ : ( LOWERCASE | UPPERCASE | DIGIT | ID_SPECIALS)
;
WS : [ \t\r\n]+ -> skip ; // skip spaces, tabs, newlines
-
-
diff --git a/aai-traversal/src/main/resources/etc/appprops/aaiconfig.properties b/aai-traversal/src/main/resources/etc/appprops/aaiconfig.properties
index a07e985..b94c3b1 100644
--- a/aai-traversal/src/main/resources/etc/appprops/aaiconfig.properties
+++ b/aai-traversal/src/main/resources/etc/appprops/aaiconfig.properties
@@ -31,23 +31,23 @@ aai.transaction.logging.get=true
aai.transaction.logging.post=true
aai.server.url.base=https://localhost:8443/aai/
-aai.server.url=https://localhost:8443/aai/v15/
+aai.server.url=https://localhost:8443/aai/v16/
aai.global.callback.url=https://localhost:8443/aai/
-aai.notification.current.version=v15
+aai.notification.current.version=v16
aai.notificationEvent.default.status=UNPROCESSED
aai.notificationEvent.default.eventType=AAI-EVENT
aai.notificationEvent.default.domain=devINT1
aai.notificationEvent.default.sourceName=aai
aai.notificationEvent.default.sequenceNumber=0
aai.notificationEvent.default.severity=NORMAL
-aai.notificationEvent.default.version=v15
+aai.notificationEvent.default.version=v16
# This one lets us enable/disable resource-version checking on updates/deletes
aai.resourceversion.enableflag=true
# This will specify how deep the stack trace should be logged
aai.logging.maxStackTraceEntries=10
-aai.default.api.version=v15
+aai.default.api.version=v16
# Used by Model-processing code
aai.model.query.resultset.maxcount=50
diff --git a/aai-traversal/src/main/resources/retired.properties b/aai-traversal/src/main/resources/retired.properties
index 2261713..2be5d88 100644
--- a/aai-traversal/src/main/resources/retired.properties
+++ b/aai-traversal/src/main/resources/retired.properties
@@ -1,5 +1,5 @@
# Retired properties
retired.api.pattern.list=\
- ^/aai/v[2-7]+/.*$\
+ ^/aai/v[2-9]+/.*$\
retired.api.all.versions= \ No newline at end of file