From bd4c050748ac957f6bb6684915233e478d71c0a1 Mon Sep 17 00:00:00 2001 From: "LaMont, William(wl2432)" Date: Mon, 22 Jun 2020 12:50:38 -0400 Subject: traversal support for v20 Issue-ID: AAI-2933 Change-Id: I76f970d15ef911a3dd14d97f2fa050c8b6e29e96 Signed-off-by: LaMont, William(wl2432) --- .../main/java/org/onap/aai/rest/DslConsumer.java | 38 ++++++++--- .../main/java/org/onap/aai/rest/QueryConsumer.java | 23 ++++--- .../java/org/onap/aai/rest/RecentAPIConsumer.java | 24 ++++--- .../org/onap/aai/rest/dsl/DslQueryBuilder.java | 75 ++++++++++++++++++---- .../java/org/onap/aai/rest/dsl/v2/DslListener.java | 12 ++-- 5 files changed, 125 insertions(+), 47 deletions(-) (limited to 'aai-traversal/src/main/java') 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 6cb6565..b9295a9 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 @@ -23,6 +23,7 @@ import com.google.gson.JsonElement; import com.google.gson.JsonObject; import com.google.gson.JsonParser; import org.apache.tinkerpop.gremlin.process.traversal.dsl.graph.GraphTraversalSource; +import org.janusgraph.core.SchemaViolationException; import org.onap.aai.concurrent.AaiCallable; import org.onap.aai.exceptions.AAIException; import org.onap.aai.introspection.ModelType; @@ -49,12 +50,12 @@ import org.slf4j.LoggerFactory; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Value; +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.Map; -import java.util.Optional; +import java.util.*; +import java.util.stream.Collectors; @Path("{version: v[1-9][0-9]*|latest}/dsl") public class DslConsumer extends TraversalConsumer { @@ -99,6 +100,7 @@ public class DslConsumer extends TraversalConsumer { @DefaultValue("no_op") @QueryParam("subgraph") String subgraph, @DefaultValue("all") @QueryParam("validate") String validate, @Context HttpHeaders headers, + @Context HttpServletRequest req, @Context UriInfo info, @DefaultValue("-1") @QueryParam("resultIndex") String resultIndex, @DefaultValue("-1") @QueryParam("resultSize") String resultSize) { @@ -111,14 +113,14 @@ public class DslConsumer extends TraversalConsumer { new AaiCallable() { @Override public Response process() throws Exception { - return (processExecuteQuery(content, versionParam, queryFormat, subgraph, validate, headers, info, + return (processExecuteQuery(content, req, versionParam, queryFormat, subgraph, validate, headers, info, resultIndex, resultSize)); } } ); } - public Response processExecuteQuery(String content, String versionParam, String queryFormat, String subgraph, + public Response processExecuteQuery(String content, HttpServletRequest req, String versionParam, String queryFormat, String subgraph, String validate, HttpHeaders headers, UriInfo info, String resultIndex, String resultSize) { @@ -139,7 +141,8 @@ public class DslConsumer extends TraversalConsumer { TransactionalGraphEngine dbEngine = null; try { - traversalUriHttpEntry.setHttpEntryProperties(version); + String serverBase = req.getRequestURL().toString().replaceAll("/(v[0-9]+|latest)/.*", "/"); + traversalUriHttpEntry.setHttpEntryProperties(version, serverBase); traversalUriHttpEntry.setPaginationParameters(resultIndex, resultSize); dbEngine = traversalUriHttpEntry.getDbEngine(); JsonObject input = new JsonParser().parse(content).getAsJsonObject(); @@ -178,16 +181,20 @@ public class DslConsumer extends TraversalConsumer { SubGraphStyle subGraphStyle = SubGraphStyle.valueOf(subgraph); List vertTemp = processor.execute(subGraphStyle); + + // Dedup if duplicate objects are returned in each array in the aggregate format scenario. + List vertTempDedupedObjectList = dedupObjectInAggregateFormatResult(vertTemp); + List vertices; if (isAggregate(format)){ - vertices = traversalUriHttpEntry.getPaginatedVertexListForAggregateFormat(vertTemp); + vertices = traversalUriHttpEntry.getPaginatedVertexListForAggregateFormat(vertTempDedupedObjectList); } else { vertices = traversalUriHttpEntry.getPaginatedVertexList(vertTemp); } DBSerializer serializer = new DBSerializer(version, dbEngine, ModelType.MOXY, sourceOfTruth); FormatFactory ff = new FormatFactory(traversalUriHttpEntry.getLoader(), serializer, schemaVersions, - this.basePath); + this.basePath, serverBase); MultivaluedMap mvm = new MultivaluedHashMap<>(); mvm.putAll(info.getQueryParameters()); @@ -231,6 +238,9 @@ public class DslConsumer extends TraversalConsumer { } catch (AAIException e) { response = consumerExceptionResponseGenerator(headers, info, HttpMethod.PUT, e); + } catch (SchemaViolationException sve) { + AAIException ex = new AAIException("AAI_4020", sve); + response = consumerExceptionResponseGenerator(headers, info, HttpMethod.PUT, ex); } catch (Exception e) { AAIException ex = new AAIException("AAI_4000", e); response = consumerExceptionResponseGenerator(headers, info, HttpMethod.PUT, ex); @@ -243,4 +253,16 @@ public class DslConsumer extends TraversalConsumer { return response; } + + private List dedupObjectInAggregateFormatResult(List vertTemp) { + List vertTempDedupedObjectList = new ArrayList(); + Iterator itr = vertTemp.listIterator(); + while (itr.hasNext()){ + Object o = itr.next(); + if (o instanceof ArrayList) { + vertTempDedupedObjectList.add(((ArrayList) o).stream().distinct().collect(Collectors.toList())); + } + } + return vertTempDedupedObjectList; + } } diff --git a/aai-traversal/src/main/java/org/onap/aai/rest/QueryConsumer.java b/aai-traversal/src/main/java/org/onap/aai/rest/QueryConsumer.java index 54e6d06..5297de5 100644 --- a/aai-traversal/src/main/java/org/onap/aai/rest/QueryConsumer.java +++ b/aai-traversal/src/main/java/org/onap/aai/rest/QueryConsumer.java @@ -47,13 +47,13 @@ import org.onap.aai.serialization.queryformats.SubGraphStyle; import org.onap.aai.setup.SchemaVersion; import org.onap.aai.setup.SchemaVersions; import org.onap.aai.transforms.XmlFormatTransformer; - import org.onap.aai.util.TraversalConstants; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Value; +import javax.servlet.http.HttpServletRequest; import javax.ws.rs.*; import javax.ws.rs.core.*; import javax.ws.rs.core.Response.Status; @@ -97,6 +97,7 @@ public class QueryConsumer extends TraversalConsumer { @DefaultValue("graphson") @QueryParam("format") String queryFormat, @DefaultValue("no_op") @QueryParam("subgraph") String subgraph, @Context HttpHeaders headers, + @Context HttpServletRequest req, @Context UriInfo info, @DefaultValue("-1") @QueryParam("resultIndex") String resultIndex, @DefaultValue("-1") @QueryParam("resultSize") String resultSize) { @@ -109,19 +110,18 @@ public class QueryConsumer extends TraversalConsumer { new AaiCallable() { @Override public Response process() { - return processExecuteQuery(content, versionParam, queryFormat, subgraph, headers, info, resultIndex, resultSize); + return processExecuteQuery(content, req, versionParam, queryFormat, subgraph, headers, info, resultIndex, resultSize); } }); } - public Response processExecuteQuery(String content, String versionParam, String queryFormat, String subgraph, + public Response processExecuteQuery(String content, HttpServletRequest req, String versionParam, String queryFormat, String subgraph, HttpHeaders headers, UriInfo info, String resultIndex, String resultSize) { String sourceOfTruth = headers.getRequestHeaders().getFirst("X-FromAppId"); String queryProcessor = headers.getRequestHeaders().getFirst("QueryProcessor"); QueryProcessorType processorType = this.processorType; - Response response; TransactionalGraphEngine dbEngine = null; @@ -143,7 +143,8 @@ public class QueryConsumer extends TraversalConsumer { String gremlin = ""; SchemaVersion version = new SchemaVersion(versionParam); - traversalUriHttpEntry.setHttpEntryProperties(version); + String serverBase = req.getRequestURL().toString().replaceAll("/(v[0-9]+|latest)/.*", "/"); + traversalUriHttpEntry.setHttpEntryProperties(version, serverBase); /* * Changes for Pagination */ @@ -171,13 +172,13 @@ public class QueryConsumer extends TraversalConsumer { CustomQueryConfig customQueryConfig = getCustomQueryConfig(queryURIObj); if ( customQueryConfig != null ) { - List missingRequiredQueryParameters = checkForMissingQueryParameters( customQueryConfig.getQueryRequiredProperties(), URITools.getQueryMap(queryURIObj)); + List missingRequiredQueryParameters = checkForMissingQueryParameters( customQueryConfig.getQueryRequiredProperties(), URITools.getQueryMap(queryURIObj)); if ( !missingRequiredQueryParameters.isEmpty() ) { return( createMessageMissingQueryRequiredParameters( missingRequiredQueryParameters, headers)); } - List invalidQueryParameters = checkForInvalidQueryParameters( customQueryConfig, URITools.getQueryMap(queryURIObj)); + List invalidQueryParameters = checkForInvalidQueryParameters( customQueryConfig, URITools.getQueryMap(queryURIObj)); if ( !invalidQueryParameters.isEmpty() ) { return( createMessageInvalidQueryParameters( invalidQueryParameters, headers)); @@ -221,7 +222,7 @@ public class QueryConsumer extends TraversalConsumer { List vertices = traversalUriHttpEntry.getPaginatedVertexList(vertTemp); DBSerializer serializer = new DBSerializer(version, dbEngine, ModelType.MOXY, sourceOfTruth); - FormatFactory ff = new FormatFactory(traversalUriHttpEntry.getLoader(), serializer, schemaVersions, this.basePath); + FormatFactory ff = new FormatFactory(traversalUriHttpEntry.getLoader(), serializer, schemaVersions, this.basePath, serverBase); MultivaluedMap mvm = new MultivaluedHashMap<>(); mvm.putAll(info.getQueryParameters()); @@ -233,8 +234,6 @@ public class QueryConsumer extends TraversalConsumer { String result = formatter.output(vertices).toString(); - //LOGGER.info ("Completed"); - String acceptType = headers.getHeaderString("Accept"); if(acceptType == null){ @@ -325,7 +324,7 @@ public class QueryConsumer extends TraversalConsumer { .entity(ErrorLogHelper.getRESTAPIErrorResponse(headers.getAcceptableMediaTypes(), e, templateVars)).build(); } - + private Response createMessageInvalidQuerySection(String invalidQuery, HttpHeaders headers) { AAIException e = new AAIException("AAI_3014"); @@ -338,6 +337,7 @@ public class QueryConsumer extends TraversalConsumer { templateVars)).build(); } + private List checkForInvalidQueryParameters( CustomQueryConfig customQueryConfig, MultivaluedMap queryParams) { List allParameters = new ArrayList<>(); @@ -353,7 +353,6 @@ public class QueryConsumer extends TraversalConsumer { return queryParams.keySet().stream() .filter(param -> !allParameters.contains(param)) .collect(Collectors.toList()); - } private Response createMessageInvalidQueryParameters(List invalidQueryParams, HttpHeaders headers) { diff --git a/aai-traversal/src/main/java/org/onap/aai/rest/RecentAPIConsumer.java b/aai-traversal/src/main/java/org/onap/aai/rest/RecentAPIConsumer.java index 86ed49d..f2b88f3 100644 --- a/aai-traversal/src/main/java/org/onap/aai/rest/RecentAPIConsumer.java +++ b/aai-traversal/src/main/java/org/onap/aai/rest/RecentAPIConsumer.java @@ -46,6 +46,7 @@ import org.slf4j.LoggerFactory; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Value; +import javax.servlet.http.HttpServletRequest; import javax.ws.rs.*; import javax.ws.rs.core.*; import javax.ws.rs.core.Response.Status; @@ -55,8 +56,8 @@ import java.util.concurrent.TimeUnit; @Path("/recents/{version: v[1-9][0-9]*|latest}") public class RecentAPIConsumer extends RESTAPI { - private static final String AAI_3021 = "AAI_3021"; - + private static final String AAI_3021 = "AAI_3021"; + /** The introspector factory type. */ private ModelType introspectorFactoryType = ModelType.MOXY; @@ -95,20 +96,24 @@ public class RecentAPIConsumer extends RESTAPI { @Path("/{nodeType: .+}") @Consumes({ MediaType.APPLICATION_JSON }) @Produces({ MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML }) - public Response getRecentData(String content, @PathParam("version") String versionParam, - @PathParam("nodeType") String nodeType, @Context HttpHeaders headers, @Context UriInfo info) { + public Response getRecentData(String content, + @PathParam("version") String versionParam, + @PathParam("nodeType") String nodeType, + @Context HttpHeaders headers, + @Context HttpServletRequest req, + @Context UriInfo info) { return runner(TraversalConstants.AAI_TRAVERSAL_TIMEOUT_ENABLED, TraversalConstants.AAI_TRAVERSAL_TIMEOUT_APP, TraversalConstants.AAI_TRAVERSAL_TIMEOUT_LIMIT, headers, info, HttpMethod.GET, new AaiCallable() { @Override public Response process() { - return processRecentData(content, versionParam, nodeType, info, headers); + return processRecentData(content, req, versionParam, nodeType, info, headers); } }); } - public Response processRecentData(String content, @PathParam("version") String versionParam, + public Response processRecentData(String content, HttpServletRequest req, @PathParam("version") String versionParam, @PathParam("nodeType") String nodeType, @Context UriInfo info, @Context HttpHeaders headers) { String sourceOfTruth = headers.getRequestHeaders().getFirst("X-FromAppId"); @@ -124,8 +129,9 @@ public class RecentAPIConsumer extends RESTAPI { SchemaVersion version = new SchemaVersion(versionParam); this.checkVersion(version); - - traversalUriHttpEntry.setHttpEntryProperties(version); + + String serverBase = req.getRequestURL().toString().replaceAll("/(v[0-9]+|latest)/.*", "/"); + traversalUriHttpEntry.setHttpEntryProperties(version, serverBase); dbEngine = traversalUriHttpEntry.getDbEngine(); /* @@ -150,7 +156,7 @@ public class RecentAPIConsumer extends RESTAPI { List vertices = processor.execute(subGraphStyle); DBSerializer serializer = new DBSerializer(version, dbEngine, introspectorFactoryType, sourceOfTruth); - FormatFactory ff = new FormatFactory(traversalUriHttpEntry.getLoader(), serializer, schemaVersions, this.basePath); + FormatFactory ff = new FormatFactory(traversalUriHttpEntry.getLoader(), serializer, schemaVersions, this.basePath, serverBase); Format format = Format.pathed_resourceversion; Formatter formater = ff.get(format, info.getQueryParameters()); 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 3d324ad..649826e 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 @@ -49,6 +49,7 @@ public class DslQueryBuilder { private StringBuilder queryException; private static final Logger LOGGER = LoggerFactory.getLogger(DslQueryBuilder.class); + private long selectCount = 0; public DslQueryBuilder(EdgeIngestor edgeIngestor, Loader loader) { this.edgeRules = edgeIngestor; @@ -82,18 +83,15 @@ public class DslQueryBuilder { * DSL always dedupes the results */ public DslQueryBuilder end(long selectCounter) { + selectCount = selectCounter; if(selectCounter <= 0) { return this.end(); } else { - String selectStep = "step" + selectCounter; - query.append(".as('").append(selectStep).append("')").append(".as('stepMain')" + - ".select('").append(selectStep).append("')").append(".store('x')").append(".select('stepMain').fold().dedup()"); + query.append(".select('stepMain').fold().dedup()"); } return this; } - - public DslQueryBuilder end() { query.append(".cap('x').unfold().dedup()"); return this; @@ -241,7 +239,7 @@ public class DslQueryBuilder { } - public DslQueryBuilder select(boolean isNot, long selectCounter, List keys) { + public DslQueryBuilder select(long selectCounter, List keys) { /* * TODO : isNot should look at the vertex properties and include everything except the notKeys */ @@ -269,15 +267,19 @@ public class DslQueryBuilder { if (alias.isPresent()) { key = StringUtils.quote(alias.get()); } - + String classType = obj.getType(trimSingleQuotes(key)); query.append(key); - if (!values.isEmpty()) { - if (values.size() > 1) { + if (values != null && !values.isEmpty()) { + if (values.size() > 1) { // values.size() > 1 indicates possibility of a list + // eliminate quotes from each element + for (int i = 0; i < values.size(); i++) { + values.set(i, getConvertedValue(classType, key, values.get(i))); + } String valuesArray = String.join(",", values); query.append(",").append(" new ArrayList<>(Arrays.asList(").append(valuesArray).append("))"); - } else { - query.append(",").append(values.get(0)); + } else { // otherwise values should only contain one value + query.append(",").append(getConvertedValue(classType, key, values.get(0))); } } } catch (AAIUnknownObjectException e) { @@ -286,6 +288,57 @@ public class DslQueryBuilder { return this; } + private String getConvertedValue(String classType, String key, String value) { + String convertedValue = value; + if (isTypeSensitive(classType)) { + convertedValue = trimSingleQuotes(value); + try { + // cast it to the corresponding type + if (classType.equals(Integer.class.getName())) { + int castInt = Integer.parseInt(convertedValue); + convertedValue = String.valueOf(castInt); + } + else if (classType.equals(Long.class.getName())) { + long castLong = Long.parseLong(convertedValue); + convertedValue = String.valueOf(castLong); + } + else if (classType.equals(Boolean.class.getName())) { + if (convertedValue.equals("1")) { // checking for integer true value + convertedValue = "true"; + } + boolean castBoolean = Boolean.parseBoolean(convertedValue); + convertedValue = String.valueOf(castBoolean); + } + } catch (Exception e) { + queryException.append("AAI_4020 ").append(String.format("Value [%s] is not an instance of the expected data type for property key [%s] and cannot be converted. " + + "Expected: class %s, found: class %s", value, key, classType, String.class.getName())); + } + } + return convertedValue; + } + + private boolean isTypeSensitive(String classType) { + if (classType.equals(Integer.class.getName()) || + classType.equals(Boolean.class.getName()) || + classType.equals(Long.class.getName())) { + return true; + } + return false; + } + + private String trimSingleQuotes(String s) { + if (s == null || s.isEmpty()) { + return s; + } + String trimSingleQuotes = ""; + if (s.startsWith("'") && s.endsWith("'")) { + trimSingleQuotes = s.substring(1, s.length() - 1); + } else { + trimSingleQuotes = s; + } + return trimSingleQuotes; + } + public DslQueryBuilder union() { query.append(".union("); return this; 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 8f9f145..66ca8a1 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 @@ -207,13 +207,13 @@ public class DslListener extends AAIDslBaseListener { if (ctx.filter() != null) { allKeys = ctx.filter().propertyFilter().stream().flatMap( pf -> pf.key().stream()).map( - e -> e.getText().replaceAll("\'", "")).collect(Collectors.toList()); + e -> e.getText().replaceFirst("\'", "").substring(0, e.getText().length() - 2)).collect(Collectors.toList()); } builder().validateFilter(ctx.label().getText(), allKeys); } if (ctx.store() != null) { - if (isAggregate() && (selectCounter == nodeCount) && (nodeCount < traversedNodes.size())) { - builder().select(false, selectCounter++, null); + if (isAggregate()) { + builder().select(selectCounter++, null); } builder().store(); hasReturnValue = true; @@ -290,7 +290,7 @@ public class DslListener extends AAIDslBaseListener { * Add all String values */ List values = valueList.stream().filter(value -> !filterKey.equals(value.getText())) - .map(value -> "'" + value.getText().replace("'", "") + "'").collect(Collectors.toList()); + .map(value -> value.getText()).collect(Collectors.toList()); /* * Add all numeric values */ @@ -312,8 +312,6 @@ public class DslListener extends AAIDslBaseListener { List keyList = ctx.key(); - boolean isNot = ctx.not() != null && !ctx.not().isEmpty(); - /* * Add all String values */ @@ -322,7 +320,7 @@ public class DslListener extends AAIDslBaseListener { setSelectKeys(traversedNodes.getFirst(), allKeys); } if (isAggregate() && (traversedNodes.size() == nodeCount)) { - builder().select(isNot, selectCounter++, allKeys); + builder().select(selectCounter++, allKeys); } } -- cgit 1.2.3-korg