diff options
Diffstat (limited to 'aai-traversal/src/main/java/org/onap/aai/rest')
43 files changed, 3526 insertions, 3474 deletions
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 index d075f70..6e76c29 100644 --- a/aai-traversal/src/main/java/org/onap/aai/rest/CQ2Gremlin.java +++ b/aai-traversal/src/main/java/org/onap/aai/rest/CQ2Gremlin.java @@ -8,7 +8,7 @@ * 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 + * 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, @@ -19,6 +19,16 @@ */ 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.*; + import org.onap.aai.config.SpringContextAware; import org.onap.aai.introspection.LoaderFactory; import org.onap.aai.rest.db.HttpEntry; @@ -34,83 +44,72 @@ import org.springframework.beans.factory.annotation.Value; import org.springframework.http.HttpStatus; import org.springframework.web.bind.annotation.RequestBody; -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.*; -import java.util.LinkedHashMap; -import java.util.List; -import java.util.Map; - - @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{ - 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); - traversalUriHttpEntry.setHttpEntryProperties(schemaVersions.getDefaultVersion()); - 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(); - } - - } + 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 { + 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); + traversalUriHttpEntry.setHttpEntryProperties(schemaVersions.getDefaultVersion()); + 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 index e3cfaca..626c5f3 100644 --- a/aai-traversal/src/main/java/org/onap/aai/rest/CQ2GremlinTest.java +++ b/aai-traversal/src/main/java/org/onap/aai/rest/CQ2GremlinTest.java @@ -8,7 +8,7 @@ * 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 + * 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, @@ -19,9 +19,19 @@ */ package org.onap.aai.rest; - import com.beust.jcommander.internal.Lists; import com.beust.jcommander.internal.Maps; + +import java.util.*; +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.*; + 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; @@ -49,171 +59,156 @@ import org.springframework.beans.factory.annotation.Value; import org.springframework.http.HttpStatus; import org.springframework.web.bind.annotation.RequestBody; -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.*; -import java.util.*; -import java.util.concurrent.atomic.AtomicInteger; -import java.util.stream.Collectors; - - @Path("/cq2gremlintest") public class CQ2GremlinTest extends RESTAPI { - private static final Logger LOGGER = LoggerFactory.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); - traversalUriHttpEntry.setHttpEntryProperties(schemaVersions.getDefaultVersion()); - 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("v19")); - LinkedHashMap <String, Object> params = new LinkedHashMap<>(); - - //Adding parameters - content.getQueryRequiredProperties().forEach(params::put); - content.getQueryOptionalProperties().forEach(params::put); - - 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().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(k); - 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().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().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(",")); - } - - + private static final Logger LOGGER = LoggerFactory.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); + traversalUriHttpEntry.setHttpEntryProperties(schemaVersions.getDefaultVersion()); + 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("v19")); + LinkedHashMap<String, Object> params = new LinkedHashMap<>(); + + // Adding parameters + content.getQueryRequiredProperties().forEach(params::put); + content.getQueryOptionalProperties().forEach(params::put); + + 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().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(k); + 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().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() + .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 fefd2dc..2b6bbb9 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 @@ -8,7 +8,7 @@ * 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 + * 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, @@ -22,7 +22,17 @@ package org.onap.aai.rest; import com.google.gson.JsonElement; import com.google.gson.JsonObject; import com.google.gson.JsonParser; + import io.micrometer.core.annotation.Timed; + +import java.util.*; +import java.util.stream.Collectors; + +import javax.servlet.http.HttpServletRequest; +import javax.ws.rs.*; +import javax.ws.rs.core.*; +import javax.ws.rs.core.Response.Status; + import org.apache.tinkerpop.gremlin.process.traversal.dsl.graph.GraphTraversalSource; import org.janusgraph.core.SchemaViolationException; import org.onap.aai.concurrent.AaiCallable; @@ -51,222 +61,211 @@ 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.*; -import java.util.stream.Collectors; - @Path("{version: v[1-9][0-9]*|latest}/dsl") @Timed public class DslConsumer extends TraversalConsumer { - private HttpEntry traversalUriHttpEntry; - - private QueryProcessorType processorType = QueryProcessorType.LOCAL_GROOVY; - - private static final Logger LOGGER = LoggerFactory.getLogger(DslConsumer.class); - - private DslQueryProcessor dslQueryProcessor; - - private SchemaVersions schemaVersions; - - private String basePath; - - private GremlinServerSingleton gremlinServerSingleton; - private final QueryVersion DEFAULT_VERSION = QueryVersion.V1; - private QueryVersion dslApiVersion = DEFAULT_VERSION; - - private XmlFormatTransformer xmlFormatTransformer; - - @Autowired - public DslConsumer(HttpEntry traversalUriHttpEntry, DslQueryProcessor dslQueryProcessor, - SchemaVersions schemaVersions, GremlinServerSingleton gremlinServerSingleton, - XmlFormatTransformer xmlFormatTransformer, - @Value("${schema.uri.base.path}") String basePath) { - this.traversalUriHttpEntry = traversalUriHttpEntry; - this.dslQueryProcessor = dslQueryProcessor; - this.schemaVersions = schemaVersions; - this.gremlinServerSingleton = gremlinServerSingleton; - this.xmlFormatTransformer = xmlFormatTransformer; - this.basePath = basePath; - } - - @PUT - @Consumes({ MediaType.APPLICATION_JSON }) - @Produces({ MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML }) - public Response executeQuery(String content, - @PathParam("version") String versionParam, - @DefaultValue("graphson") @QueryParam("format") String queryFormat, - @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) { - Set<String> roles = this.getRoles(req.getUserPrincipal()); - - return runner(TraversalConstants.AAI_TRAVERSAL_DSL_TIMEOUT_ENABLED, - TraversalConstants.AAI_TRAVERSAL_DSL_TIMEOUT_APP, - TraversalConstants.AAI_TRAVERSAL_DSL_TIMEOUT_LIMIT, - headers, - info, - HttpMethod.PUT, - new AaiCallable() { - @Override - public Response process() throws Exception { - return (processExecuteQuery(content, req, versionParam, queryFormat, subgraph, validate, headers, info, - resultIndex, resultSize, roles)); - } - } - ); - } - - public Response processExecuteQuery(String content, HttpServletRequest req, String versionParam, String queryFormat, String subgraph, - String validate, HttpHeaders headers, UriInfo info, String resultIndex, - String resultSize, Set<String> roles) { - - String sourceOfTruth = headers.getRequestHeaders().getFirst("X-FromAppId"); - String dslOverride = headers.getRequestHeaders().getFirst("X-DslOverride"); - - Optional<String> dslApiVersionHeader = Optional.ofNullable(headers.getRequestHeaders().getFirst("X-DslApiVersion")); - if (dslApiVersionHeader.isPresent()) { - try { - dslApiVersion = QueryVersion.valueOf(dslApiVersionHeader.get()); - } catch (IllegalArgumentException e) { - LOGGER.debug("Defaulting DSL Api Version to "+DEFAULT_VERSION); - } - } - - Response response; - SchemaVersion version = new SchemaVersion(versionParam); - - TransactionalGraphEngine dbEngine = null; - try { - 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(); - JsonElement dslElement = input.get("dsl"); - String dsl = ""; - if (dslElement != null) { - dsl = dslElement.getAsString(); - } - - - boolean isDslOverride = dslOverride != null && !AAIConfig.get(TraversalConstants.DSL_OVERRIDE).equals("false") - && dslOverride.equals(AAIConfig.get(TraversalConstants.DSL_OVERRIDE)); - - if(isDslOverride) { - dslQueryProcessor.setStartNodeValidationFlag(false); - } - - dslQueryProcessor.setValidationRules(validate); - - Format format = Format.getFormat(queryFormat); - - if(isAggregate(format)){ - dslQueryProcessor.setAggregate(true); - } - - if(isHistory(format)){ - validateHistoryParams(format, info.getQueryParameters()); - } - - GraphTraversalSource traversalSource = getTraversalSource(dbEngine, format, info, roles); - - GenericQueryProcessor processor = new GenericQueryProcessor.Builder(dbEngine, gremlinServerSingleton) - .queryFrom(dsl, "dsl").queryProcessor(dslQueryProcessor).version(dslApiVersion).processWith(processorType) - .format(format).uriParams(info.getQueryParameters()).traversalSource(isHistory(format), traversalSource).create(); - - SubGraphStyle subGraphStyle = SubGraphStyle.valueOf(subgraph); - List<Object> vertTemp = processor.execute(subGraphStyle); - - - // Dedup if duplicate objects are returned in each array in the aggregate format scenario. - List<Object> vertTempDedupedObjectList = dedupObjectInAggregateFormatResult(vertTemp); - - List <Object> vertices; - if (isAggregate(format)){ - 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, serverBase); - - MultivaluedMap<String, String> mvm = new MultivaluedHashMap<>(); - mvm.putAll(info.getQueryParameters()); - if (isHistory(format)) { - mvm.putSingle("startTs", Long.toString(getStartTime(format, mvm))); - mvm.putSingle("endTs", Long.toString(getEndTime(mvm))); - } - Formatter formatter = ff.get(format, mvm); - - final Map<String, List<String>> propertiesMap = processor.getPropertiesMap(); - String result = ""; - if (propertiesMap != null && !propertiesMap.isEmpty()){ - result = formatter.output(vertices, propertiesMap).toString(); - } - else { - result = formatter.output(vertices).toString(); - } - - String acceptType = headers.getHeaderString("Accept"); - - if(acceptType == null){ - acceptType = MediaType.APPLICATION_JSON; - } - - if(MediaType.APPLICATION_XML_TYPE.isCompatible(MediaType.valueOf(acceptType))){ - result = xmlFormatTransformer.transform(result); - } - - if(traversalUriHttpEntry.isPaginated()){ - response = Response.status(Status.OK) - .type(acceptType) - .header("total-results", traversalUriHttpEntry.getTotalVertices()) - .header("total-pages", traversalUriHttpEntry.getTotalPaginationBuckets()) - .entity(result) - .build(); - }else { - response = Response.status(Status.OK) - .type(acceptType) - .entity(result).build(); - } - - } 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); - } finally { - if (dbEngine != null) { - dbEngine.rollback(); - } - - } - - return response; - } - - private List<Object> dedupObjectInAggregateFormatResult(List<Object> vertTemp) { - List<Object> vertTempDedupedObjectList = new ArrayList<Object>(); - Iterator<Object> 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; - } + private HttpEntry traversalUriHttpEntry; + + private QueryProcessorType processorType = QueryProcessorType.LOCAL_GROOVY; + + private static final Logger LOGGER = LoggerFactory.getLogger(DslConsumer.class); + + private DslQueryProcessor dslQueryProcessor; + + private SchemaVersions schemaVersions; + + private String basePath; + + private GremlinServerSingleton gremlinServerSingleton; + private final QueryVersion DEFAULT_VERSION = QueryVersion.V1; + private QueryVersion dslApiVersion = DEFAULT_VERSION; + + private XmlFormatTransformer xmlFormatTransformer; + + @Autowired + public DslConsumer(HttpEntry traversalUriHttpEntry, DslQueryProcessor dslQueryProcessor, + SchemaVersions schemaVersions, GremlinServerSingleton gremlinServerSingleton, + XmlFormatTransformer xmlFormatTransformer, + @Value("${schema.uri.base.path}") String basePath) { + this.traversalUriHttpEntry = traversalUriHttpEntry; + this.dslQueryProcessor = dslQueryProcessor; + this.schemaVersions = schemaVersions; + this.gremlinServerSingleton = gremlinServerSingleton; + this.xmlFormatTransformer = xmlFormatTransformer; + this.basePath = basePath; + } + + @PUT + @Consumes({MediaType.APPLICATION_JSON}) + @Produces({MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML}) + public Response executeQuery(String content, @PathParam("version") String versionParam, + @DefaultValue("graphson") @QueryParam("format") String queryFormat, + @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) { + Set<String> roles = this.getRoles(req.getUserPrincipal()); + + return runner(TraversalConstants.AAI_TRAVERSAL_DSL_TIMEOUT_ENABLED, + TraversalConstants.AAI_TRAVERSAL_DSL_TIMEOUT_APP, + TraversalConstants.AAI_TRAVERSAL_DSL_TIMEOUT_LIMIT, headers, info, HttpMethod.PUT, + new AaiCallable() { + @Override + public Response process() throws Exception { + return (processExecuteQuery(content, req, versionParam, queryFormat, subgraph, + validate, headers, info, resultIndex, resultSize, roles)); + } + }); + } + + public Response processExecuteQuery(String content, HttpServletRequest req, String versionParam, + String queryFormat, String subgraph, String validate, HttpHeaders headers, UriInfo info, + String resultIndex, String resultSize, Set<String> roles) { + + String sourceOfTruth = headers.getRequestHeaders().getFirst("X-FromAppId"); + String dslOverride = headers.getRequestHeaders().getFirst("X-DslOverride"); + + Optional<String> dslApiVersionHeader = + Optional.ofNullable(headers.getRequestHeaders().getFirst("X-DslApiVersion")); + if (dslApiVersionHeader.isPresent()) { + try { + dslApiVersion = QueryVersion.valueOf(dslApiVersionHeader.get()); + } catch (IllegalArgumentException e) { + LOGGER.debug("Defaulting DSL Api Version to " + DEFAULT_VERSION); + } + } + + Response response; + SchemaVersion version = new SchemaVersion(versionParam); + + TransactionalGraphEngine dbEngine = null; + try { + 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(); + JsonElement dslElement = input.get("dsl"); + String dsl = ""; + if (dslElement != null) { + dsl = dslElement.getAsString(); + } + + boolean isDslOverride = dslOverride != null + && !AAIConfig.get(TraversalConstants.DSL_OVERRIDE).equals("false") + && dslOverride.equals(AAIConfig.get(TraversalConstants.DSL_OVERRIDE)); + + if (isDslOverride) { + dslQueryProcessor.setStartNodeValidationFlag(false); + } + + dslQueryProcessor.setValidationRules(validate); + + Format format = Format.getFormat(queryFormat); + + if (isAggregate(format)) { + dslQueryProcessor.setAggregate(true); + } + + if (isHistory(format)) { + validateHistoryParams(format, info.getQueryParameters()); + } + + GraphTraversalSource traversalSource = + getTraversalSource(dbEngine, format, info, roles); + + GenericQueryProcessor processor = + new GenericQueryProcessor.Builder(dbEngine, gremlinServerSingleton) + .queryFrom(dsl, "dsl").queryProcessor(dslQueryProcessor).version(dslApiVersion) + .processWith(processorType).format(format).uriParams(info.getQueryParameters()) + .traversalSource(isHistory(format), traversalSource).create(); + + SubGraphStyle subGraphStyle = SubGraphStyle.valueOf(subgraph); + List<Object> vertTemp = processor.execute(subGraphStyle); + + // Dedup if duplicate objects are returned in each array in the aggregate format + // scenario. + List<Object> vertTempDedupedObjectList = dedupObjectInAggregateFormatResult(vertTemp); + + List<Object> vertices; + if (isAggregate(format)) { + 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, serverBase); + + MultivaluedMap<String, String> mvm = new MultivaluedHashMap<>(); + mvm.putAll(info.getQueryParameters()); + if (isHistory(format)) { + mvm.putSingle("startTs", Long.toString(getStartTime(format, mvm))); + mvm.putSingle("endTs", Long.toString(getEndTime(mvm))); + } + Formatter formatter = ff.get(format, mvm); + + final Map<String, List<String>> propertiesMap = processor.getPropertiesMap(); + String result = ""; + if (propertiesMap != null && !propertiesMap.isEmpty()) { + result = formatter.output(vertices, propertiesMap).toString(); + } else { + result = formatter.output(vertices).toString(); + } + + String acceptType = headers.getHeaderString("Accept"); + + if (acceptType == null) { + acceptType = MediaType.APPLICATION_JSON; + } + + if (MediaType.APPLICATION_XML_TYPE.isCompatible(MediaType.valueOf(acceptType))) { + result = xmlFormatTransformer.transform(result); + } + + if (traversalUriHttpEntry.isPaginated()) { + response = Response.status(Status.OK).type(acceptType) + .header("total-results", traversalUriHttpEntry.getTotalVertices()) + .header("total-pages", traversalUriHttpEntry.getTotalPaginationBuckets()) + .entity(result).build(); + } else { + response = Response.status(Status.OK).type(acceptType).entity(result).build(); + } + + } 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); + } finally { + if (dbEngine != null) { + dbEngine.rollback(); + } + + } + + return response; + } + + private List<Object> dedupObjectInAggregateFormatResult(List<Object> vertTemp) { + List<Object> vertTempDedupedObjectList = new ArrayList<Object>(); + Iterator<Object> 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/ExceptionHandler.java b/aai-traversal/src/main/java/org/onap/aai/rest/ExceptionHandler.java index 452815e..d6d2f5e 100644 --- a/aai-traversal/src/main/java/org/onap/aai/rest/ExceptionHandler.java +++ b/aai-traversal/src/main/java/org/onap/aai/rest/ExceptionHandler.java @@ -8,7 +8,7 @@ * 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 + * 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, @@ -19,6 +19,10 @@ */ package org.onap.aai.rest; +import com.fasterxml.jackson.core.JsonParseException; +import com.fasterxml.jackson.databind.JsonMappingException; +import com.sun.istack.SAXParseException2; + import java.util.ArrayList; import java.util.List; @@ -33,9 +37,6 @@ import javax.ws.rs.ext.Provider; import org.onap.aai.exceptions.AAIException; import org.onap.aai.logging.ErrorLogHelper; -import com.fasterxml.jackson.core.JsonParseException; -import com.fasterxml.jackson.databind.JsonMappingException; -import com.sun.istack.SAXParseException2; /** * The Class ExceptionHandler. @@ -43,84 +44,81 @@ import com.sun.istack.SAXParseException2; @Provider public class ExceptionHandler implements ExceptionMapper<Exception> { - private static final String AAI_4007 = "AAI_4007"; + private static final String AAI_4007 = "AAI_4007"; @Context private HttpServletRequest request; - + @Context private HttpHeaders headers; - + @Override public Response toResponse(Exception exception) { - Response response = null; - ArrayList<String> templateVars = new ArrayList<>(); + Response response = null; + ArrayList<String> templateVars = new ArrayList<>(); - //the general case is that cxf will give us a WebApplicationException - //with a linked exception - if (exception instanceof WebApplicationException) { - WebApplicationException e = (WebApplicationException) exception; - if (e.getCause() instanceof SAXParseException2) { - templateVars.add("UnmarshalException"); - AAIException ex = new AAIException(AAI_4007, exception); - response = Response - .status(400) - .entity(ErrorLogHelper.getRESTAPIErrorResponse(headers.getAcceptableMediaTypes(), ex, templateVars)) - .build(); + // the general case is that cxf will give us a WebApplicationException + // with a linked exception + if (exception instanceof WebApplicationException) { + WebApplicationException e = (WebApplicationException) exception; + if (e.getCause() instanceof SAXParseException2) { + templateVars.add("UnmarshalException"); + AAIException ex = new AAIException(AAI_4007, exception); + response = Response.status(400).entity(ErrorLogHelper + .getRESTAPIErrorResponse(headers.getAcceptableMediaTypes(), ex, templateVars)) + .build(); - } - } else if (exception instanceof JsonParseException) { - //jackson does it differently so we get the direct JsonParseException - templateVars.add("JsonParseException"); - AAIException ex = new AAIException(AAI_4007, exception); - response = Response - .status(400) - .entity(ErrorLogHelper.getRESTAPIErrorResponse(headers.getAcceptableMediaTypes(), ex, templateVars)) - .build(); + } + } else if (exception instanceof JsonParseException) { + // jackson does it differently so we get the direct JsonParseException + templateVars.add("JsonParseException"); + AAIException ex = new AAIException(AAI_4007, exception); + response = Response + .status(400).entity(ErrorLogHelper + .getRESTAPIErrorResponse(headers.getAcceptableMediaTypes(), ex, templateVars)) + .build(); } else if (exception instanceof JsonMappingException) { - //jackson does it differently so we get the direct JsonParseException - templateVars.add("JsonMappingException"); - AAIException ex = new AAIException(AAI_4007, exception); - response = Response - .status(400) - .entity(ErrorLogHelper.getRESTAPIErrorResponse(headers.getAcceptableMediaTypes(), ex, templateVars)) - .build(); - } - - // it didn't get set above, we wrap a general fault here - if (response == null) { - - Exception actual_e = exception; - if (exception instanceof WebApplicationException) { - WebApplicationException e = (WebApplicationException) exception; - response = e.getResponse(); - } else { - templateVars.add(request.getMethod()); - templateVars.add("unknown"); - AAIException ex = new AAIException("AAI_4000", actual_e); - List<MediaType> mediaTypes = headers.getAcceptableMediaTypes(); - int setError = 0; + // jackson does it differently so we get the direct JsonParseException + templateVars.add("JsonMappingException"); + AAIException ex = new AAIException(AAI_4007, exception); + response = Response + .status(400).entity(ErrorLogHelper + .getRESTAPIErrorResponse(headers.getAcceptableMediaTypes(), ex, templateVars)) + .build(); + } + + // it didn't get set above, we wrap a general fault here + if (response == null) { + + Exception actual_e = exception; + if (exception instanceof WebApplicationException) { + WebApplicationException e = (WebApplicationException) exception; + response = e.getResponse(); + } else { + templateVars.add(request.getMethod()); + templateVars.add("unknown"); + AAIException ex = new AAIException("AAI_4000", actual_e); + List<MediaType> mediaTypes = headers.getAcceptableMediaTypes(); + int setError = 0; - for (MediaType mediaType : mediaTypes) { - if (MediaType.APPLICATION_XML_TYPE.isCompatible(mediaType)) { - response = Response - .status(400) - .type(MediaType.APPLICATION_XML_TYPE) - .entity(ErrorLogHelper.getRESTAPIErrorResponse(headers.getAcceptableMediaTypes(), ex, templateVars)) - .build(); - setError = 1; - } - } - if (setError == 0) { - response = Response - .status(400) - .type(MediaType.APPLICATION_JSON_TYPE) - .entity(ErrorLogHelper.getRESTAPIErrorResponse(headers.getAcceptableMediaTypes(), ex, templateVars)) - .build(); - } - } - } - return response; + for (MediaType mediaType : mediaTypes) { + if (MediaType.APPLICATION_XML_TYPE.isCompatible(mediaType)) { + response = Response.status(400).type(MediaType.APPLICATION_XML_TYPE) + .entity(ErrorLogHelper.getRESTAPIErrorResponse( + headers.getAcceptableMediaTypes(), ex, templateVars)) + .build(); + setError = 1; + } + } + if (setError == 0) { + response = Response.status(400).type(MediaType.APPLICATION_JSON_TYPE) + .entity(ErrorLogHelper.getRESTAPIErrorResponse( + headers.getAcceptableMediaTypes(), ex, templateVars)) + .build(); + } + } + } + return response; } } 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 e015ec3..460065e 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 @@ -8,7 +8,7 @@ * 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 + * 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, @@ -22,14 +22,24 @@ package org.onap.aai.rest; import com.google.gson.JsonElement; import com.google.gson.JsonObject; import com.google.gson.JsonParser; + import io.micrometer.core.annotation.Timed; + +import java.net.URI; +import java.util.*; +import java.util.stream.Collectors; + +import javax.servlet.http.HttpServletRequest; +import javax.ws.rs.*; +import javax.ws.rs.core.*; +import javax.ws.rs.core.Response.Status; + import org.apache.tinkerpop.gremlin.process.traversal.dsl.graph.GraphTraversalSource; import org.apache.tinkerpop.gremlin.structure.Vertex; import org.onap.aai.concurrent.AaiCallable; import org.onap.aai.exceptions.AAIException; import org.onap.aai.introspection.ModelType; import org.onap.aai.logging.ErrorLogHelper; - import org.onap.aai.parsers.query.QueryParser; import org.onap.aai.rest.db.HttpEntry; import org.onap.aai.rest.search.CustomQueryConfig; @@ -54,181 +64,178 @@ 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.net.URI; -import java.util.*; -import java.util.stream.Collectors; - @Path("{version: v[1-9][0-9]*|latest}/query") @Timed public class QueryConsumer extends TraversalConsumer { - private QueryProcessorType processorType = QueryProcessorType.LOCAL_GROOVY; - - private static final Logger LOGGER = LoggerFactory.getLogger(QueryConsumer.class); - - private HttpEntry traversalUriHttpEntry; - - - private SchemaVersions schemaVersions; - - private String basePath; - - private GremlinServerSingleton gremlinServerSingleton; - - private XmlFormatTransformer xmlFormatTransformer; - - @Autowired - public QueryConsumer(HttpEntry traversalUriHttpEntry, SchemaVersions schemaVersions, - GremlinServerSingleton gremlinServerSingleton, XmlFormatTransformer xmlFormatTransformer, @Value("${schema.uri.base.path}") String basePath) { - this.traversalUriHttpEntry = traversalUriHttpEntry; - this.schemaVersions = schemaVersions; - this.gremlinServerSingleton = gremlinServerSingleton; - this.basePath = basePath; - this.xmlFormatTransformer = xmlFormatTransformer; - } - - @PUT - @Consumes({ MediaType.APPLICATION_JSON}) - @Produces({ MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML }) - public Response executeQuery(String content, - @PathParam("version") String versionParam, - @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) { - Set<String> roles = this.getRoles(req.getUserPrincipal()); - - return runner(TraversalConstants.AAI_TRAVERSAL_TIMEOUT_ENABLED, - TraversalConstants.AAI_TRAVERSAL_TIMEOUT_APP, - TraversalConstants.AAI_TRAVERSAL_TIMEOUT_LIMIT, - headers, - info, - HttpMethod.GET, - new AaiCallable<Response>() { - @Override - public Response process() { - return processExecuteQuery(content, req, versionParam, queryFormat, subgraph, headers, info, resultIndex, resultSize, roles); - } - }); - } - - public Response processExecuteQuery(String content, HttpServletRequest req, String versionParam, String queryFormat, String subgraph, - HttpHeaders headers, UriInfo info, String resultIndex, - String resultSize, Set<String> roles) { - - String sourceOfTruth = headers.getRequestHeaders().getFirst("X-FromAppId"); - String queryProcessor = headers.getRequestHeaders().getFirst("QueryProcessor"); - QueryProcessorType processorType = this.processorType; - Response response; - TransactionalGraphEngine dbEngine = null; - - try { - this.checkQueryParams(info.getQueryParameters()); - Format format = Format.getFormat(queryFormat); - if (queryProcessor != null) { - processorType = QueryProcessorType.valueOf(queryProcessor); - } - SubGraphStyle subGraphStyle = SubGraphStyle.valueOf(subgraph); - - JsonParser parser = new JsonParser(); - JsonObject input = parser.parse(content).getAsJsonObject(); - JsonElement startElement = input.get("start"); - JsonElement queryElement = input.get("query"); - JsonElement gremlinElement = input.get("gremlin"); - List<URI> startURIs = new ArrayList<>(); - String queryURI = ""; - String gremlin = ""; - - SchemaVersion version = new SchemaVersion(versionParam); - String serverBase = req.getRequestURL().toString().replaceAll("/(v[0-9]+|latest)/.*", "/"); - traversalUriHttpEntry.setHttpEntryProperties(version, serverBase); - /* - * Changes for Pagination - */ - - traversalUriHttpEntry.setPaginationParameters(resultIndex, resultSize); - dbEngine = traversalUriHttpEntry.getDbEngine(); - - if (startElement != null) { - - if (startElement.isJsonArray()) { - for (JsonElement element : startElement.getAsJsonArray()) { - startURIs.add(new URI(element.getAsString())); - } - } else { - startURIs.add(new URI(startElement.getAsString())); - } - } - if (queryElement != null) { - queryURI = queryElement.getAsString(); - } - if (gremlinElement != null) { - gremlin = gremlinElement.getAsString(); - } - URI queryURIObj = new URI(queryURI); - - CustomQueryConfig customQueryConfig = getCustomQueryConfig(queryURIObj); - if ( customQueryConfig != null ) { - List<String> missingRequiredQueryParameters = checkForMissingQueryParameters( customQueryConfig.getQueryRequiredProperties(), URITools.getQueryMap(queryURIObj)); - - if ( !missingRequiredQueryParameters.isEmpty() ) { - return( createMessageMissingQueryRequiredParameters( missingRequiredQueryParameters, headers)); - } - - List<String> invalidQueryParameters = checkForInvalidQueryParameters( customQueryConfig, URITools.getQueryMap(queryURIObj)); - - if ( !invalidQueryParameters.isEmpty() ) { - return( createMessageInvalidQueryParameters( invalidQueryParameters, headers)); - } - - } else if ( queryElement != null ) { - return (createMessageInvalidQuerySection(queryURI, headers)); - } - - GenericQueryProcessor processor; - - if(isHistory(format)){ - validateHistoryParams(format, info.getQueryParameters()); - } - GraphTraversalSource traversalSource = getTraversalSource(dbEngine, format, info, roles); - QueryStyle queryStyle = getQueryStyle(format, traversalUriHttpEntry); - - if (!startURIs.isEmpty()) { - Set<Vertex> vertexSet = new LinkedHashSet<>(); - QueryParser uriQuery; - List<Vertex> vertices; - for (URI startUri : startURIs) { - uriQuery = dbEngine.getQueryBuilder(queryStyle, traversalSource).createQueryFromURI(startUri, URITools.getQueryMap(startUri)); - vertices = uriQuery.getQueryBuilder().toList(); - vertexSet.addAll(vertices); - } - - processor = new GenericQueryProcessor.Builder(dbEngine, gremlinServerSingleton) - .startFrom(vertexSet).queryFrom(queryURIObj).format(format) - .processWith(processorType).traversalSource(isHistory(format), traversalSource).create(); - } else if (!queryURI.equals("")){ - processor = new GenericQueryProcessor.Builder(dbEngine, gremlinServerSingleton) - .queryFrom(queryURIObj) - .processWith(processorType).traversalSource(isHistory(format), traversalSource).create(); - } else { - processor = new GenericQueryProcessor.Builder(dbEngine, gremlinServerSingleton) - .queryFrom(gremlin, "gremlin") - .processWith(processorType).traversalSource(isHistory(format), traversalSource).create(); - } - List<Object> vertTemp = processor.execute(subGraphStyle); - List<Object> vertices = traversalUriHttpEntry.getPaginatedVertexList(vertTemp); - - DBSerializer serializer = new DBSerializer(version, dbEngine, ModelType.MOXY, sourceOfTruth); - FormatFactory ff = new FormatFactory(traversalUriHttpEntry.getLoader(), serializer, schemaVersions, this.basePath, serverBase); - - MultivaluedMap<String, String> mvm = new MultivaluedHashMap<>(); + private QueryProcessorType processorType = QueryProcessorType.LOCAL_GROOVY; + + private static final Logger LOGGER = LoggerFactory.getLogger(QueryConsumer.class); + + private HttpEntry traversalUriHttpEntry; + + private SchemaVersions schemaVersions; + + private String basePath; + + private GremlinServerSingleton gremlinServerSingleton; + + private XmlFormatTransformer xmlFormatTransformer; + + @Autowired + public QueryConsumer(HttpEntry traversalUriHttpEntry, SchemaVersions schemaVersions, + GremlinServerSingleton gremlinServerSingleton, XmlFormatTransformer xmlFormatTransformer, + @Value("${schema.uri.base.path}") String basePath) { + this.traversalUriHttpEntry = traversalUriHttpEntry; + this.schemaVersions = schemaVersions; + this.gremlinServerSingleton = gremlinServerSingleton; + this.basePath = basePath; + this.xmlFormatTransformer = xmlFormatTransformer; + } + + @PUT + @Consumes({MediaType.APPLICATION_JSON}) + @Produces({MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML}) + public Response executeQuery(String content, @PathParam("version") String versionParam, + @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) { + Set<String> roles = this.getRoles(req.getUserPrincipal()); + + return runner(TraversalConstants.AAI_TRAVERSAL_TIMEOUT_ENABLED, + TraversalConstants.AAI_TRAVERSAL_TIMEOUT_APP, + TraversalConstants.AAI_TRAVERSAL_TIMEOUT_LIMIT, headers, info, HttpMethod.GET, + new AaiCallable<Response>() { + @Override + public Response process() { + return processExecuteQuery(content, req, versionParam, queryFormat, subgraph, + headers, info, resultIndex, resultSize, roles); + } + }); + } + + public Response processExecuteQuery(String content, HttpServletRequest req, String versionParam, + String queryFormat, String subgraph, HttpHeaders headers, UriInfo info, String resultIndex, + String resultSize, Set<String> roles) { + + String sourceOfTruth = headers.getRequestHeaders().getFirst("X-FromAppId"); + String queryProcessor = headers.getRequestHeaders().getFirst("QueryProcessor"); + QueryProcessorType processorType = this.processorType; + Response response; + TransactionalGraphEngine dbEngine = null; + + try { + this.checkQueryParams(info.getQueryParameters()); + Format format = Format.getFormat(queryFormat); + if (queryProcessor != null) { + processorType = QueryProcessorType.valueOf(queryProcessor); + } + SubGraphStyle subGraphStyle = SubGraphStyle.valueOf(subgraph); + + JsonParser parser = new JsonParser(); + JsonObject input = parser.parse(content).getAsJsonObject(); + JsonElement startElement = input.get("start"); + JsonElement queryElement = input.get("query"); + JsonElement gremlinElement = input.get("gremlin"); + List<URI> startURIs = new ArrayList<>(); + String queryURI = ""; + String gremlin = ""; + + SchemaVersion version = new SchemaVersion(versionParam); + String serverBase = + req.getRequestURL().toString().replaceAll("/(v[0-9]+|latest)/.*", "/"); + traversalUriHttpEntry.setHttpEntryProperties(version, serverBase); + /* + * Changes for Pagination + */ + + traversalUriHttpEntry.setPaginationParameters(resultIndex, resultSize); + dbEngine = traversalUriHttpEntry.getDbEngine(); + + if (startElement != null) { + + if (startElement.isJsonArray()) { + for (JsonElement element : startElement.getAsJsonArray()) { + startURIs.add(new URI(element.getAsString())); + } + } else { + startURIs.add(new URI(startElement.getAsString())); + } + } + if (queryElement != null) { + queryURI = queryElement.getAsString(); + } + if (gremlinElement != null) { + gremlin = gremlinElement.getAsString(); + } + URI queryURIObj = new URI(queryURI); + + CustomQueryConfig customQueryConfig = getCustomQueryConfig(queryURIObj); + if (customQueryConfig != null) { + List<String> missingRequiredQueryParameters = + checkForMissingQueryParameters(customQueryConfig.getQueryRequiredProperties(), + URITools.getQueryMap(queryURIObj)); + + if (!missingRequiredQueryParameters.isEmpty()) { + return (createMessageMissingQueryRequiredParameters( + missingRequiredQueryParameters, headers)); + } + + List<String> invalidQueryParameters = checkForInvalidQueryParameters( + customQueryConfig, URITools.getQueryMap(queryURIObj)); + + if (!invalidQueryParameters.isEmpty()) { + return (createMessageInvalidQueryParameters(invalidQueryParameters, headers)); + } + + } else if (queryElement != null) { + return (createMessageInvalidQuerySection(queryURI, headers)); + } + + GenericQueryProcessor processor; + + if (isHistory(format)) { + validateHistoryParams(format, info.getQueryParameters()); + } + GraphTraversalSource traversalSource = + getTraversalSource(dbEngine, format, info, roles); + QueryStyle queryStyle = getQueryStyle(format, traversalUriHttpEntry); + + if (!startURIs.isEmpty()) { + Set<Vertex> vertexSet = new LinkedHashSet<>(); + QueryParser uriQuery; + List<Vertex> vertices; + for (URI startUri : startURIs) { + uriQuery = dbEngine.getQueryBuilder(queryStyle, traversalSource) + .createQueryFromURI(startUri, URITools.getQueryMap(startUri)); + vertices = uriQuery.getQueryBuilder().toList(); + vertexSet.addAll(vertices); + } + + processor = new GenericQueryProcessor.Builder(dbEngine, gremlinServerSingleton) + .startFrom(vertexSet).queryFrom(queryURIObj).format(format) + .processWith(processorType).traversalSource(isHistory(format), traversalSource) + .create(); + } else if (!queryURI.equals("")) { + processor = new GenericQueryProcessor.Builder(dbEngine, gremlinServerSingleton) + .queryFrom(queryURIObj).processWith(processorType) + .traversalSource(isHistory(format), traversalSource).create(); + } else { + processor = new GenericQueryProcessor.Builder(dbEngine, gremlinServerSingleton) + .queryFrom(gremlin, "gremlin").processWith(processorType) + .traversalSource(isHistory(format), traversalSource).create(); + } + List<Object> vertTemp = processor.execute(subGraphStyle); + List<Object> vertices = traversalUriHttpEntry.getPaginatedVertexList(vertTemp); + + DBSerializer serializer = + new DBSerializer(version, dbEngine, ModelType.MOXY, sourceOfTruth); + FormatFactory ff = new FormatFactory(traversalUriHttpEntry.getLoader(), serializer, + schemaVersions, this.basePath, serverBase); + + MultivaluedMap<String, String> mvm = new MultivaluedHashMap<>(); mvm.putAll(info.getQueryParameters()); if (isHistory(format)) { mvm.putSingle("startTs", Long.toString(getStartTime(format, mvm))); @@ -236,142 +243,139 @@ public class QueryConsumer extends TraversalConsumer { } Formatter formatter = ff.get(format, mvm); - String result = formatter.output(vertices).toString(); - - String acceptType = headers.getHeaderString("Accept"); - - if(acceptType == null){ - acceptType = MediaType.APPLICATION_JSON; - } - - if(MediaType.APPLICATION_XML_TYPE.isCompatible(MediaType.valueOf(acceptType))){ - result = xmlFormatTransformer.transform(result); - } - - if(traversalUriHttpEntry.isPaginated()){ - response = Response.status(Status.OK) - .type(acceptType) - .header("total-results", traversalUriHttpEntry.getTotalVertices()) - .header("total-pages", traversalUriHttpEntry.getTotalPaginationBuckets()) - .entity(result) - .build(); - }else { - response = Response.status(Status.OK) - .type(acceptType) - .entity(result).build(); - } - } catch (AAIException e) { - response = consumerExceptionResponseGenerator(headers, info, HttpMethod.GET, e); - } catch (Exception e ) { - AAIException ex = new AAIException("AAI_4000", e); - response = consumerExceptionResponseGenerator(headers, info, HttpMethod.GET, ex); - } finally { - if (dbEngine != null) { - dbEngine.rollback(); - } - - } - - return response; - } - - public void checkQueryParams(MultivaluedMap<String, String> params) throws AAIException { - - if (params.containsKey("depth") && params.getFirst("depth").matches("\\d+")) { - String depth = params.getFirst("depth"); - int i = Integer.parseInt(depth); - if (i > 1) { - throw new AAIException("AAI_3303"); - } - } - - - } - - private List<String> checkForMissingQueryParameters( List<String> requiredParameters, MultivaluedMap<String, String> queryParams ) { - List<String> result = new ArrayList<>(); - - for ( String param : requiredParameters ) { - if ( !queryParams.containsKey(param)) { - result.add(param); - } - } - return result; - } - - private CustomQueryConfig getCustomQueryConfig(URI uriObj ) { - String path = uriObj.getPath(); - - String[] parts = path.split("/"); - boolean hasQuery = false; - for ( String part:parts ) { - if ( hasQuery) { - return gremlinServerSingleton.getCustomQueryConfig(part); - } - if ( "query".equals(part)) { - hasQuery = true; - } - } - - return null; - - } - - private Response createMessageMissingQueryRequiredParameters(List<String> missingRequiredQueryParams, HttpHeaders headers) { - AAIException e = new AAIException("AAI_3013"); - - ArrayList<String> templateVars = new ArrayList<>(); - templateVars.add(missingRequiredQueryParams.toString()); - - return Response - .status(e.getErrorObject().getHTTPResponseCode()) - .entity(ErrorLogHelper.getRESTAPIErrorResponse(headers.getAcceptableMediaTypes(), e, - templateVars)).build(); - } - - private Response createMessageInvalidQuerySection(String invalidQuery, HttpHeaders headers) { - AAIException e = new AAIException("AAI_3014"); - - ArrayList<String> templateVars = new ArrayList<>(); - templateVars.add(invalidQuery); - - return Response - .status(e.getErrorObject().getHTTPResponseCode()) - .entity(ErrorLogHelper.getRESTAPIErrorResponse(headers.getAcceptableMediaTypes(), e, - templateVars)).build(); - } - - - private List<String> checkForInvalidQueryParameters( CustomQueryConfig customQueryConfig, MultivaluedMap<String, String> queryParams) { - - List<String> allParameters = new ArrayList<>(); - /* - * Add potential Required and Optional to allParameters - */ - Optional.ofNullable(customQueryConfig.getQueryOptionalProperties()).ifPresent(allParameters::addAll); - Optional.ofNullable(customQueryConfig.getQueryRequiredProperties()).ifPresent(allParameters::addAll); - - if(queryParams.isEmpty()) { - return new ArrayList<>(); - } - return queryParams.keySet().stream() - .filter(param -> !allParameters.contains(param)) - .collect(Collectors.toList()); - } - - private Response createMessageInvalidQueryParameters(List<String> invalidQueryParams, HttpHeaders headers) { - AAIException e = new AAIException("AAI_3022"); - - ArrayList<String> templateVars = new ArrayList<>(); - templateVars.add(invalidQueryParams.toString()); - - return Response - .status(e.getErrorObject().getHTTPResponseCode()) - .entity(ErrorLogHelper.getRESTAPIErrorResponse( - headers.getAcceptableMediaTypes(), - e, - templateVars)).build(); - - } + String result = formatter.output(vertices).toString(); + + String acceptType = headers.getHeaderString("Accept"); + + if (acceptType == null) { + acceptType = MediaType.APPLICATION_JSON; + } + + if (MediaType.APPLICATION_XML_TYPE.isCompatible(MediaType.valueOf(acceptType))) { + result = xmlFormatTransformer.transform(result); + } + + if (traversalUriHttpEntry.isPaginated()) { + response = Response.status(Status.OK).type(acceptType) + .header("total-results", traversalUriHttpEntry.getTotalVertices()) + .header("total-pages", traversalUriHttpEntry.getTotalPaginationBuckets()) + .entity(result).build(); + } else { + response = Response.status(Status.OK).type(acceptType).entity(result).build(); + } + } catch (AAIException e) { + response = consumerExceptionResponseGenerator(headers, info, HttpMethod.GET, e); + } catch (Exception e) { + AAIException ex = new AAIException("AAI_4000", e); + response = consumerExceptionResponseGenerator(headers, info, HttpMethod.GET, ex); + } finally { + if (dbEngine != null) { + dbEngine.rollback(); + } + + } + + return response; + } + + public void checkQueryParams(MultivaluedMap<String, String> params) throws AAIException { + + if (params.containsKey("depth") && params.getFirst("depth").matches("\\d+")) { + String depth = params.getFirst("depth"); + int i = Integer.parseInt(depth); + if (i > 1) { + throw new AAIException("AAI_3303"); + } + } + + } + + private List<String> checkForMissingQueryParameters(List<String> requiredParameters, + MultivaluedMap<String, String> queryParams) { + List<String> result = new ArrayList<>(); + + for (String param : requiredParameters) { + if (!queryParams.containsKey(param)) { + result.add(param); + } + } + return result; + } + + private CustomQueryConfig getCustomQueryConfig(URI uriObj) { + String path = uriObj.getPath(); + + String[] parts = path.split("/"); + boolean hasQuery = false; + for (String part : parts) { + if (hasQuery) { + return gremlinServerSingleton.getCustomQueryConfig(part); + } + if ("query".equals(part)) { + hasQuery = true; + } + } + + return null; + + } + + private Response createMessageMissingQueryRequiredParameters( + List<String> missingRequiredQueryParams, HttpHeaders headers) { + AAIException e = new AAIException("AAI_3013"); + + ArrayList<String> templateVars = new ArrayList<>(); + templateVars.add(missingRequiredQueryParams.toString()); + + return Response + .status(e.getErrorObject().getHTTPResponseCode()).entity(ErrorLogHelper + .getRESTAPIErrorResponse(headers.getAcceptableMediaTypes(), e, templateVars)) + .build(); + } + + private Response createMessageInvalidQuerySection(String invalidQuery, HttpHeaders headers) { + AAIException e = new AAIException("AAI_3014"); + + ArrayList<String> templateVars = new ArrayList<>(); + templateVars.add(invalidQuery); + + return Response + .status(e.getErrorObject().getHTTPResponseCode()).entity(ErrorLogHelper + .getRESTAPIErrorResponse(headers.getAcceptableMediaTypes(), e, templateVars)) + .build(); + } + + private List<String> checkForInvalidQueryParameters(CustomQueryConfig customQueryConfig, + MultivaluedMap<String, String> queryParams) { + + List<String> allParameters = new ArrayList<>(); + /* + * Add potential Required and Optional to allParameters + */ + Optional.ofNullable(customQueryConfig.getQueryOptionalProperties()) + .ifPresent(allParameters::addAll); + Optional.ofNullable(customQueryConfig.getQueryRequiredProperties()) + .ifPresent(allParameters::addAll); + + if (queryParams.isEmpty()) { + return new ArrayList<>(); + } + return queryParams.keySet().stream().filter(param -> !allParameters.contains(param)) + .collect(Collectors.toList()); + } + + private Response createMessageInvalidQueryParameters(List<String> invalidQueryParams, + HttpHeaders headers) { + AAIException e = new AAIException("AAI_3022"); + + ArrayList<String> templateVars = new ArrayList<>(); + templateVars.add(invalidQueryParams.toString()); + + return Response + .status(e.getErrorObject().getHTTPResponseCode()).entity(ErrorLogHelper + .getRESTAPIErrorResponse(headers.getAcceptableMediaTypes(), e, templateVars)) + .build(); + + } } 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 7ec20bc..7f40979 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 @@ -8,7 +8,7 @@ * 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 + * 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, @@ -20,11 +20,19 @@ package org.onap.aai.rest; import io.micrometer.core.annotation.Timed; + +import java.util.List; +import java.util.concurrent.TimeUnit; + +import javax.servlet.http.HttpServletRequest; +import javax.ws.rs.*; +import javax.ws.rs.core.*; +import javax.ws.rs.core.Response.Status; + import org.onap.aai.concurrent.AaiCallable; import org.onap.aai.exceptions.AAIException; import org.onap.aai.introspection.ModelType; import org.onap.aai.introspection.exceptions.AAIUnknownObjectException; - import org.onap.aai.rest.db.HttpEntry; import org.onap.aai.rest.search.GenericQueryProcessor; import org.onap.aai.rest.search.GremlinServerSingleton; @@ -47,209 +55,205 @@ 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.concurrent.TimeUnit; - @Path("/recents/{version: v[1-9][0-9]*|latest}") @Timed public class RecentAPIConsumer extends RESTAPI { private static final String AAI_3021 = "AAI_3021"; - - /** The introspector factory type. */ - private ModelType introspectorFactoryType = ModelType.MOXY; - - private QueryProcessorType processorType = QueryProcessorType.LOCAL_GROOVY; - /** The query style. */ - - private static final Logger LOGGER = LoggerFactory.getLogger(RecentAPIConsumer.class); - - private HttpEntry traversalUriHttpEntry; - - private SchemaVersions schemaVersions; - - private String basePath; - - private GremlinServerSingleton gremlinServerSingleton; - - private XmlFormatTransformer xmlFormatTransformer; - - - @Autowired - public RecentAPIConsumer( - HttpEntry traversalUriHttpEntry, - SchemaVersions schemaVersions, - GremlinServerSingleton gremlinServerSingleton, - XmlFormatTransformer xmlFormatTransformer, - @Value("${schema.uri.base.path}") String basePath - ){ - this.traversalUriHttpEntry = traversalUriHttpEntry; - this.schemaVersions = schemaVersions; - this.gremlinServerSingleton = gremlinServerSingleton; - this.xmlFormatTransformer = xmlFormatTransformer; - this.basePath = basePath; - } - - @GET - @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 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<Response>() { - @Override - public Response process() { - return processRecentData(content, req, versionParam, nodeType, info, headers); - } - }); - - } - - 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"); - String queryProcessor = headers.getRequestHeaders().getFirst("QueryProcessor"); - QueryProcessorType processorType = this.processorType; - Response response; - TransactionalGraphEngine dbEngine = null; - try { - - if (queryProcessor != null) { - processorType = QueryProcessorType.valueOf(queryProcessor); - } - - SchemaVersion version = new SchemaVersion(versionParam); - this.checkVersion(version); - - String serverBase = req.getRequestURL().toString().replaceAll("/(v[0-9]+|latest)/.*", "/"); - traversalUriHttpEntry.setHttpEntryProperties(version, serverBase); - dbEngine = traversalUriHttpEntry.getDbEngine(); - - /* - * Check for mandatory parameters here - */ - - this.checkNodeType(nodeType); - this.checkQueryParams(info.getQueryParameters()); - - GenericQueryProcessor processor = null; - - - - processor = new GenericQueryProcessor.Builder(dbEngine, gremlinServerSingleton).queryFrom(nodeType, "nodeQuery") - .uriParams(info.getQueryParameters()) - .processWith(processorType).create(); - - - - String result = ""; - SubGraphStyle subGraphStyle = null; - List<Object> vertices = processor.execute(subGraphStyle); - - DBSerializer serializer = new DBSerializer(version, dbEngine, introspectorFactoryType, sourceOfTruth); - FormatFactory ff = new FormatFactory(traversalUriHttpEntry.getLoader(), serializer, schemaVersions, this.basePath, serverBase); + + /** The introspector factory type. */ + private ModelType introspectorFactoryType = ModelType.MOXY; + + private QueryProcessorType processorType = QueryProcessorType.LOCAL_GROOVY; + /** The query style. */ + + private static final Logger LOGGER = LoggerFactory.getLogger(RecentAPIConsumer.class); + + private HttpEntry traversalUriHttpEntry; + + private SchemaVersions schemaVersions; + + private String basePath; + + private GremlinServerSingleton gremlinServerSingleton; + + private XmlFormatTransformer xmlFormatTransformer; + + @Autowired + public RecentAPIConsumer(HttpEntry traversalUriHttpEntry, SchemaVersions schemaVersions, + GremlinServerSingleton gremlinServerSingleton, XmlFormatTransformer xmlFormatTransformer, + @Value("${schema.uri.base.path}") String basePath) { + this.traversalUriHttpEntry = traversalUriHttpEntry; + this.schemaVersions = schemaVersions; + this.gremlinServerSingleton = gremlinServerSingleton; + this.xmlFormatTransformer = xmlFormatTransformer; + this.basePath = basePath; + } + + @GET + @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 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<Response>() { + @Override + public Response process() { + return processRecentData(content, req, versionParam, nodeType, info, headers); + } + }); + + } + + 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"); + String queryProcessor = headers.getRequestHeaders().getFirst("QueryProcessor"); + QueryProcessorType processorType = this.processorType; + Response response; + TransactionalGraphEngine dbEngine = null; + try { + + if (queryProcessor != null) { + processorType = QueryProcessorType.valueOf(queryProcessor); + } + + SchemaVersion version = new SchemaVersion(versionParam); + this.checkVersion(version); + + String serverBase = + req.getRequestURL().toString().replaceAll("/(v[0-9]+|latest)/.*", "/"); + traversalUriHttpEntry.setHttpEntryProperties(version, serverBase); + dbEngine = traversalUriHttpEntry.getDbEngine(); + + /* + * Check for mandatory parameters here + */ + + this.checkNodeType(nodeType); + this.checkQueryParams(info.getQueryParameters()); + + GenericQueryProcessor processor = null; + + processor = new GenericQueryProcessor.Builder(dbEngine, gremlinServerSingleton) + .queryFrom(nodeType, "nodeQuery").uriParams(info.getQueryParameters()) + .processWith(processorType).create(); + + String result = ""; + SubGraphStyle subGraphStyle = null; + List<Object> vertices = processor.execute(subGraphStyle); + + DBSerializer serializer = + new DBSerializer(version, dbEngine, introspectorFactoryType, sourceOfTruth); + FormatFactory ff = new FormatFactory(traversalUriHttpEntry.getLoader(), serializer, + schemaVersions, this.basePath, serverBase); Format format = Format.pathed_resourceversion; - - Formatter formater = ff.get(format, info.getQueryParameters()); - - result = formater.output(vertices).toString(); - - //LOGGER.info("Completed"); - - String acceptType = headers.getHeaderString("Accept"); - - if(acceptType == null){ - acceptType = MediaType.APPLICATION_JSON; - } - - if(MediaType.APPLICATION_XML_TYPE.isCompatible(MediaType.valueOf(acceptType))){ - result = xmlFormatTransformer.transform(result); - } - - response = Response.status(Status.OK).type(acceptType).entity(result).build(); - - } catch (AAIException e) { - response = consumerExceptionResponseGenerator(headers, info, HttpMethod.GET, e); - } catch (Exception e) { - AAIException ex = new AAIException("AAI_4000", e); - response = consumerExceptionResponseGenerator(headers, info, HttpMethod.GET, ex); - } finally { - - if (dbEngine != null) { - dbEngine.rollback(); - } - - } - - return response; - } - - private void checkVersion(SchemaVersion version) throws AAIException { - if(!schemaVersions.getVersions().contains(version)){ - throw new AAIException(AAI_3021, "Schema Version is not valid"); - } - } - - public void checkNodeType(String nodeType) throws AAIException { - try { - traversalUriHttpEntry.getLoader().introspectorFromName(nodeType); - } catch (AAIUnknownObjectException e) { - throw new AAIException("AAI_6115", "Unrecognized nodeType [" + nodeType + "] passed to recents query."); - } - } - public void checkQueryParams(MultivaluedMap<String, String> params) throws AAIException { - - boolean isHoursParameter = false; - boolean isDateTimeParameter = false; - - if (params != null && params.containsKey("hours") && params.getFirst("hours").matches("-?\\d+")) { - isHoursParameter = true; - long hours; - try{ - hours = Long.parseLong(params.getFirst("hours")); - } - catch(NumberFormatException ex){ - throw new AAIException(AAI_3021, " Invalid Hours. Valid values for hours are 1 to " + AAIConstants.HISTORY_MAX_HOURS); - } - if (hours < 1 || hours > AAIConstants.HISTORY_MAX_HOURS) { - throw new AAIException(AAI_3021, " Valid values for hours are 1 to " + AAIConstants.HISTORY_MAX_HOURS); - } - } - if (params != null && params.containsKey("date-time") && params.getFirst("date-time").matches("-?\\d+")) { - isDateTimeParameter = true; - Long minStartTime = System.currentTimeMillis() - TimeUnit.HOURS.toMillis(AAIConstants.HISTORY_MAX_HOURS); - Long startTime; - try{ - startTime = Long.parseLong(params.getFirst("date-time")); - } - catch(NumberFormatException ex){ - throw new AAIException(AAI_3021, " Invalid Data-time. Valid values for date-time are "+minStartTime+" to " + System.currentTimeMillis() ); - } - if (startTime < minStartTime) { - throw new AAIException(AAI_3021, " Valid values for date-time are "+minStartTime+" to " + System.currentTimeMillis() ); - } - } - - if(!isHoursParameter && !isDateTimeParameter){ - throw new AAIException(AAI_3021, "Send valid hours or date-time to specify the timebounds"); - } - - if(isHoursParameter && isDateTimeParameter){ - throw new AAIException(AAI_3021, "Send either hours or date-time and not both to specify the timebounds"); - } - - - } + + Formatter formater = ff.get(format, info.getQueryParameters()); + + result = formater.output(vertices).toString(); + + // LOGGER.info("Completed"); + + String acceptType = headers.getHeaderString("Accept"); + + if (acceptType == null) { + acceptType = MediaType.APPLICATION_JSON; + } + + if (MediaType.APPLICATION_XML_TYPE.isCompatible(MediaType.valueOf(acceptType))) { + result = xmlFormatTransformer.transform(result); + } + + response = Response.status(Status.OK).type(acceptType).entity(result).build(); + + } catch (AAIException e) { + response = consumerExceptionResponseGenerator(headers, info, HttpMethod.GET, e); + } catch (Exception e) { + AAIException ex = new AAIException("AAI_4000", e); + response = consumerExceptionResponseGenerator(headers, info, HttpMethod.GET, ex); + } finally { + + if (dbEngine != null) { + dbEngine.rollback(); + } + + } + + return response; + } + + private void checkVersion(SchemaVersion version) throws AAIException { + if (!schemaVersions.getVersions().contains(version)) { + throw new AAIException(AAI_3021, "Schema Version is not valid"); + } + } + + public void checkNodeType(String nodeType) throws AAIException { + try { + traversalUriHttpEntry.getLoader().introspectorFromName(nodeType); + } catch (AAIUnknownObjectException e) { + throw new AAIException("AAI_6115", + "Unrecognized nodeType [" + nodeType + "] passed to recents query."); + } + } + + public void checkQueryParams(MultivaluedMap<String, String> params) throws AAIException { + + boolean isHoursParameter = false; + boolean isDateTimeParameter = false; + + if (params != null && params.containsKey("hours") + && params.getFirst("hours").matches("-?\\d+")) { + isHoursParameter = true; + long hours; + try { + hours = Long.parseLong(params.getFirst("hours")); + } catch (NumberFormatException ex) { + throw new AAIException(AAI_3021, " Invalid Hours. Valid values for hours are 1 to " + + AAIConstants.HISTORY_MAX_HOURS); + } + if (hours < 1 || hours > AAIConstants.HISTORY_MAX_HOURS) { + throw new AAIException(AAI_3021, + " Valid values for hours are 1 to " + AAIConstants.HISTORY_MAX_HOURS); + } + } + if (params != null && params.containsKey("date-time") + && params.getFirst("date-time").matches("-?\\d+")) { + isDateTimeParameter = true; + Long minStartTime = System.currentTimeMillis() + - TimeUnit.HOURS.toMillis(AAIConstants.HISTORY_MAX_HOURS); + Long startTime; + try { + startTime = Long.parseLong(params.getFirst("date-time")); + } catch (NumberFormatException ex) { + throw new AAIException(AAI_3021, + " Invalid Data-time. Valid values for date-time are " + minStartTime + " to " + + System.currentTimeMillis()); + } + if (startTime < minStartTime) { + throw new AAIException(AAI_3021, " Valid values for date-time are " + minStartTime + + " to " + System.currentTimeMillis()); + } + } + + if (!isHoursParameter && !isDateTimeParameter) { + throw new AAIException(AAI_3021, + "Send valid hours or date-time to specify the timebounds"); + } + + if (isHoursParameter && isDateTimeParameter) { + throw new AAIException(AAI_3021, + "Send either hours or date-time and not both to specify the timebounds"); + } + + } } diff --git a/aai-traversal/src/main/java/org/onap/aai/rest/TraversalConsumer.java b/aai-traversal/src/main/java/org/onap/aai/rest/TraversalConsumer.java index a8f88ec..2980f28 100644 --- a/aai-traversal/src/main/java/org/onap/aai/rest/TraversalConsumer.java +++ b/aai-traversal/src/main/java/org/onap/aai/rest/TraversalConsumer.java @@ -8,7 +8,7 @@ * 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 + * 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, @@ -19,6 +19,15 @@ */ package org.onap.aai.rest; +import java.security.Principal; +import java.util.Collections; +import java.util.Set; +import java.util.concurrent.TimeUnit; +import java.util.stream.Collectors; + +import javax.ws.rs.core.MultivaluedMap; +import javax.ws.rs.core.UriInfo; + import org.apache.commons.lang3.ObjectUtils; import org.apache.commons.lang3.StringUtils; import org.apache.tinkerpop.gremlin.process.traversal.P; @@ -37,14 +46,6 @@ import org.onap.aai.serialization.engines.QueryStyle; import org.onap.aai.serialization.engines.TransactionalGraphEngine; import org.onap.aai.serialization.queryformats.Format; -import javax.ws.rs.core.MultivaluedMap; -import javax.ws.rs.core.UriInfo; -import java.security.Principal; -import java.util.Collections; -import java.util.Set; -import java.util.concurrent.TimeUnit; -import java.util.stream.Collectors; - public abstract class TraversalConsumer extends RESTAPI { private static final String HISTORICAL_FORMAT = "state,lifecycle"; @@ -57,12 +58,12 @@ public abstract class TraversalConsumer extends RESTAPI { private Long furthestInThePast = null; public TraversalConsumer() { - this.historyTruncateWindow = Integer.parseInt( - SpringContextAware.getApplicationContext().getEnvironment().getProperty("history.truncate.window.days", "365")); - this.historyEnabled = Boolean.parseBoolean( - SpringContextAware.getApplicationContext().getEnvironment().getProperty("history.enabled", "false")); - this.multiTenancyEnabled = Boolean.parseBoolean( - SpringContextAware.getApplicationContext().getEnvironment().getProperty("multi.tenancy.enabled", "false")); + this.historyTruncateWindow = Integer.parseInt(SpringContextAware.getApplicationContext() + .getEnvironment().getProperty("history.truncate.window.days", "365")); + this.historyEnabled = Boolean.parseBoolean(SpringContextAware.getApplicationContext() + .getEnvironment().getProperty("history.enabled", "false")); + this.multiTenancyEnabled = Boolean.parseBoolean(SpringContextAware.getApplicationContext() + .getEnvironment().getProperty("multi.tenancy.enabled", "false")); } public boolean isHistory(Format queryFormat) { @@ -84,85 +85,60 @@ public abstract class TraversalConsumer extends RESTAPI { } else if (Format.lifecycle.equals(format)) { return getLifeCycleSubgraphStrategy(startTs, endTs); } else { - return SubgraphStrategy.build() - .vertices(__.has(AAIProperties.START_TS, P.gte(startTs))) - .vertexProperties(__.has(AAIProperties.START_TS, P.gte(startTs))) - .edges(__.has(AAIProperties.START_TS, P.gte(startTs))).create(); + return SubgraphStrategy.build().vertices(__.has(AAIProperties.START_TS, P.gte(startTs))) + .vertexProperties(__.has(AAIProperties.START_TS, P.gte(startTs))) + .edges(__.has(AAIProperties.START_TS, P.gte(startTs))).create(); } } private SubgraphStrategy getLifeCycleSubgraphStrategy(long startTs, long endTs) { return SubgraphStrategy.build() - .vertices( - __.not( - __.or( - __.and( - __.has(AAIProperties.START_TS, P.gt(startTs)), - __.has(AAIProperties.START_TS, P.gt(endTs)) - ), - __.and( - __.has(AAIProperties.END_TS).has(AAIProperties.END_TS, P.lt(startTs)), - __.has(AAIProperties.END_TS).has(AAIProperties.END_TS, P.lt(endTs)) - ) - ) - ) - ).vertexProperties( - __.not( - __.or( - __.and( - __.has(AAIProperties.START_TS, P.gt(startTs)), - __.has(AAIProperties.START_TS, P.gt(endTs)) - ), - __.and( - __.has(AAIProperties.END_TS).has(AAIProperties.END_TS, P.lt(startTs)), - __.has(AAIProperties.END_TS).has(AAIProperties.END_TS, P.lt(endTs)) - ) - ) - ) - ).edges( - __.not( - __.or( - __.and( - __.has(AAIProperties.START_TS, P.gt(startTs)), - __.has(AAIProperties.START_TS, P.gt(endTs)) - ), - __.and( - __.has(AAIProperties.END_TS).has(AAIProperties.END_TS, P.lt(startTs)), - __.has(AAIProperties.END_TS).has(AAIProperties.END_TS, P.lt(endTs)) - ) - ) - ) - ).create(); + .vertices(__.not(__.or( + __.and(__.has(AAIProperties.START_TS, P.gt(startTs)), + __.has(AAIProperties.START_TS, P.gt(endTs))), + __.and(__.has(AAIProperties.END_TS).has(AAIProperties.END_TS, P.lt(startTs)), + __.has(AAIProperties.END_TS).has(AAIProperties.END_TS, P.lt(endTs)))))) + .vertexProperties(__.not(__.or( + __.and(__.has(AAIProperties.START_TS, P.gt(startTs)), + __.has(AAIProperties.START_TS, P.gt(endTs))), + __.and(__.has(AAIProperties.END_TS).has(AAIProperties.END_TS, P.lt(startTs)), + __.has(AAIProperties.END_TS).has(AAIProperties.END_TS, P.lt(endTs)))))) + .edges(__.not(__.or( + __.and(__.has(AAIProperties.START_TS, P.gt(startTs)), + __.has(AAIProperties.START_TS, P.gt(endTs))), + __.and(__.has(AAIProperties.END_TS).has(AAIProperties.END_TS, P.lt(startTs)), + __.has(AAIProperties.END_TS).has(AAIProperties.END_TS, P.lt(endTs)))))) + .create(); } private SubgraphStrategy getStateSubgraphStrategy(long startTs) { return SubgraphStrategy.build() - .vertices( - __.and(__.has(AAIProperties.START_TS, P.lte(startTs)), - __.or(__.hasNot(AAIProperties.END_TS), __.has(AAIProperties.END_TS, P.gt(startTs)))) - ).vertexProperties( - __.and(__.has(AAIProperties.START_TS, P.lte(startTs)), - __.or(__.hasNot(AAIProperties.END_TS), __.has(AAIProperties.END_TS, P.gt(startTs)))) - ).edges( - __.and(__.has(AAIProperties.START_TS, P.lte(startTs)), - __.or(__.hasNot(AAIProperties.END_TS), __.has(AAIProperties.END_TS, P.gt(startTs)))) - ).create(); + .vertices(__.and(__.has(AAIProperties.START_TS, P.lte(startTs)), + __.or(__.hasNot(AAIProperties.END_TS), + __.has(AAIProperties.END_TS, P.gt(startTs))))) + .vertexProperties(__.and(__.has(AAIProperties.START_TS, P.lte(startTs)), + __.or(__.hasNot(AAIProperties.END_TS), + __.has(AAIProperties.END_TS, P.gt(startTs))))) + .edges(__.and(__.has(AAIProperties.START_TS, P.lte(startTs)), __ + .or(__.hasNot(AAIProperties.END_TS), __.has(AAIProperties.END_TS, P.gt(startTs))))) + .create(); } private SubgraphStrategy getDataOwnerSubgraphStrategy(Set<String> roles) { return SubgraphStrategy.build() - .vertices( - __.or(__.has("data-owner", P.within(roles)), __.hasNot("data-owner")) - ).create(); + .vertices(__.or(__.has("data-owner", P.within(roles)), __.hasNot("data-owner"))) + .create(); } - protected GraphTraversalSource getTraversalSource(TransactionalGraphEngine dbEngine, Format format, UriInfo info, Set<String> roles) throws AAIException { + protected GraphTraversalSource getTraversalSource(TransactionalGraphEngine dbEngine, + Format format, UriInfo info, Set<String> roles) throws AAIException { GraphTraversalSource traversalSource; if (isHistory(format)) { long localStartTime = this.getStartTime(format, info.getQueryParameters()); long localEndTime = this.getEndTime(info.getQueryParameters()); - traversalSource = dbEngine.asAdmin().getTraversalSource().withStrategies(getSubgraphStrategy(localStartTime, localEndTime, format)); + traversalSource = dbEngine.asAdmin().getTraversalSource() + .withStrategies(getSubgraphStrategy(localStartTime, localEndTime, format)); } else { traversalSource = dbEngine.asAdmin().getTraversalSource(); @@ -185,13 +161,13 @@ public abstract class TraversalConsumer extends RESTAPI { return Collections.EMPTY_SET; } - return account.getRoles() - .stream() - .map(role -> StringUtils.removeEnd(role, OwnerCheck.READ_ONLY_SUFFIX)) - .collect(Collectors.toSet()); + return account.getRoles().stream() + .map(role -> StringUtils.removeEnd(role, OwnerCheck.READ_ONLY_SUFFIX)) + .collect(Collectors.toSet()); } - protected void validateHistoryParams(Format format, MultivaluedMap<String, String> params) throws AAIException { + protected void validateHistoryParams(Format format, MultivaluedMap<String, String> params) + throws AAIException { getStartTime(format, params); getEndTime(params); } @@ -199,31 +175,37 @@ public abstract class TraversalConsumer extends RESTAPI { /** * If a request comes in for information prior to our truncation timeframe, throw an error. * In the changes api, we never return change timestamps prior to the truncation timeframe. - * In the lifecycle api, we should treat a call with no timestamp as a lifecycle since call with a timestamp of the truncation time - * in the lifecycle api, we should return an error if the timestamp provided is prior to the truncation time - * In the state api, we should return an error if the timestamp provided is prior to the truncation time + * In the lifecycle api, we should treat a call with no timestamp as a lifecycle since call with + * a timestamp of the truncation time + * in the lifecycle api, we should return an error if the timestamp provided is prior to the + * truncation time + * In the state api, we should return an error if the timestamp provided is prior to the + * truncation time + * * @param params * @return */ - protected long getStartTime(Format format, MultivaluedMap<String, String> params) throws AAIException { + protected long getStartTime(Format format, MultivaluedMap<String, String> params) + throws AAIException { if (startTime != null) { return startTime; } - String startTs = params.getFirst("startTs") ; + String startTs = params.getFirst("startTs"); if (Format.state.equals(format)) { - if (startTs == null || startTs.isEmpty() || "-1".equals(startTs) || "now".equals(startTs)) { + if (startTs == null || startTs.isEmpty() || "-1".equals(startTs) + || "now".equals(startTs)) { startTime = currentTime; } else { startTime = Long.valueOf(startTs); verifyTimeAgainstTruncationTime(startTime); } } else if (Format.lifecycle.equals(format)) { - if("now".equals(startTs)) { + if ("now".equals(startTs)) { startTime = currentTime; - } else if (startTs == null || startTs.isEmpty()|| "-1".equals(startTs)) { + } else if (startTs == null || startTs.isEmpty() || "-1".equals(startTs)) { startTime = getFurthestInThePast(); } else { startTime = Long.valueOf(startTs); @@ -246,7 +228,7 @@ public abstract class TraversalConsumer extends RESTAPI { return endTime; } - String endTs = params.getFirst("endTs") ; + String endTs = params.getFirst("endTs"); if (endTs == null || endTs.isEmpty() || "-1".equals(endTs) || "now".equals(endTs)) { endTime = currentTime; 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 index 26a625a..33629f0 100644 --- 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 @@ -8,7 +8,7 @@ * 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 + * 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, @@ -27,8 +27,9 @@ 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 { + 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/DslContext.java b/aai-traversal/src/main/java/org/onap/aai/rest/dsl/DslContext.java index cf7f51d..6088561 100644 --- a/aai-traversal/src/main/java/org/onap/aai/rest/dsl/DslContext.java +++ b/aai-traversal/src/main/java/org/onap/aai/rest/dsl/DslContext.java @@ -8,7 +8,7 @@ * 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 + * 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, @@ -19,146 +19,146 @@ */ package org.onap.aai.rest.dsl; -import org.antlr.v4.runtime.ParserRuleContext; - import java.util.ArrayList; import java.util.Deque; import java.util.LinkedList; import java.util.List; +import org.antlr.v4.runtime.ParserRuleContext; + public class DslContext { - private ParserRuleContext ctx; - - private boolean validationFlag = true; - private boolean isStartNode = false; - private String startNode = ""; - private List<String> startNodeKeys = new ArrayList<>(); - - private String currentNode; - private String previousNode; - - private boolean isTraversal = false; - private boolean isWhereQuery = false; - private boolean isUnionQuery = false; - private boolean isUnionStart = false; - - private String whereStartNode = ""; - - private Deque<String> unionStartNodes = new LinkedList<>(); - - /* - * Limit Queries have to be applied in the end - so i have to set this in - * context - */ - public StringBuilder limitQuery = new StringBuilder(); - - public ParserRuleContext getCtx() { - return ctx; - } - - public void setCtx(ParserRuleContext ctx) { - this.ctx = ctx; - } - - public boolean isStartNode() { - return isStartNode; - } - - public void setStartNodeFlag(boolean isStartNode) { - this.isStartNode = isStartNode; - } - - public String getStartNode() { - return startNode; - } - - public void setStartNode(String startNode) { - this.startNode = startNode; - } - - public List<String> getStartNodeKeys() { - return startNodeKeys; - } - - public String getCurrentNode() { - return currentNode; - } - - public void setCurrentNode(String currentNode) { - this.currentNode = currentNode; - } - - public String getPreviousNode() { - return previousNode; - } - - public void setPreviousNode(String previousNode) { - this.previousNode = previousNode; - } - - public boolean isTraversal() { - return isTraversal; - } - - public void setTraversal(boolean isTraversal) { - this.isTraversal = isTraversal; - } - - public boolean isWhereQuery() { - return isWhereQuery; - } - - public void setWhereQuery(boolean isWhereQuery) { - this.isWhereQuery = isWhereQuery; - } - - public boolean isUnionQuery() { - return isUnionQuery; - } - - public void setUnionQuery(boolean isUnionQuery) { - this.isUnionQuery = isUnionQuery; - } - - public String getWhereStartNode() { - return whereStartNode; - } - - public void setWhereStartNode(String whereStartNode) { - this.whereStartNode = whereStartNode; - } - - public Deque<String> getUnionStartNodes() { - return unionStartNodes; - } - - public void setUnionStartNodes(Deque<String> unionStartNodes) { - this.unionStartNodes = unionStartNodes; - } - - public boolean isUnionStart() { - return isUnionStart; - } - - public void setUnionStart(boolean isUnionStart) { - this.isUnionStart = isUnionStart; - } - - public StringBuilder getLimitQuery() { - return limitQuery; - } - - public void setLimitQuery(StringBuilder limitQuery) { - this.limitQuery = limitQuery; - } - - public boolean isValidationFlag() { - return validationFlag; - } - - public void setValidationFlag(boolean validationFlag) { - this.validationFlag = validationFlag; - } + private ParserRuleContext ctx; + + private boolean validationFlag = true; + private boolean isStartNode = false; + private String startNode = ""; + private List<String> startNodeKeys = new ArrayList<>(); + + private String currentNode; + private String previousNode; + + private boolean isTraversal = false; + private boolean isWhereQuery = false; + private boolean isUnionQuery = false; + private boolean isUnionStart = false; + + private String whereStartNode = ""; + + private Deque<String> unionStartNodes = new LinkedList<>(); + + /* + * Limit Queries have to be applied in the end - so i have to set this in + * context + */ + public StringBuilder limitQuery = new StringBuilder(); + + public ParserRuleContext getCtx() { + return ctx; + } + + public void setCtx(ParserRuleContext ctx) { + this.ctx = ctx; + } + + public boolean isStartNode() { + return isStartNode; + } + + public void setStartNodeFlag(boolean isStartNode) { + this.isStartNode = isStartNode; + } + + public String getStartNode() { + return startNode; + } + + public void setStartNode(String startNode) { + this.startNode = startNode; + } + + public List<String> getStartNodeKeys() { + return startNodeKeys; + } + + public String getCurrentNode() { + return currentNode; + } + + public void setCurrentNode(String currentNode) { + this.currentNode = currentNode; + } + + public String getPreviousNode() { + return previousNode; + } + + public void setPreviousNode(String previousNode) { + this.previousNode = previousNode; + } + + public boolean isTraversal() { + return isTraversal; + } + + public void setTraversal(boolean isTraversal) { + this.isTraversal = isTraversal; + } + + public boolean isWhereQuery() { + return isWhereQuery; + } + + public void setWhereQuery(boolean isWhereQuery) { + this.isWhereQuery = isWhereQuery; + } + + public boolean isUnionQuery() { + return isUnionQuery; + } + + public void setUnionQuery(boolean isUnionQuery) { + this.isUnionQuery = isUnionQuery; + } + + public String getWhereStartNode() { + return whereStartNode; + } + + public void setWhereStartNode(String whereStartNode) { + this.whereStartNode = whereStartNode; + } + + public Deque<String> getUnionStartNodes() { + return unionStartNodes; + } + + public void setUnionStartNodes(Deque<String> unionStartNodes) { + this.unionStartNodes = unionStartNodes; + } + + public boolean isUnionStart() { + return isUnionStart; + } + + public void setUnionStart(boolean isUnionStart) { + this.isUnionStart = isUnionStart; + } + + public StringBuilder getLimitQuery() { + return limitQuery; + } + + public void setLimitQuery(StringBuilder limitQuery) { + this.limitQuery = limitQuery; + } + + public boolean isValidationFlag() { + return validationFlag; + } + + public void setValidationFlag(boolean validationFlag) { + 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 d5b365e..a953fcb 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 @@ -8,7 +8,7 @@ * 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 + * 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, @@ -21,6 +21,13 @@ package org.onap.aai.rest.dsl; import com.google.common.collect.ArrayListMultimap; import com.google.common.collect.Multimap; + +import java.util.List; +import java.util.Optional; +import java.util.regex.Matcher; +import java.util.regex.Pattern; +import java.util.stream.Collectors; + import org.onap.aai.edges.EdgeIngestor; import org.onap.aai.edges.EdgeRule; import org.onap.aai.edges.EdgeRuleQuery; @@ -35,12 +42,6 @@ import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.util.StringUtils; -import java.util.List; -import java.util.Optional; -import java.util.regex.Matcher; -import java.util.regex.Pattern; -import java.util.stream.Collectors; - public class DslQueryBuilder { private final EdgeIngestor edgeRules; @@ -84,7 +85,7 @@ public class DslQueryBuilder { */ public DslQueryBuilder end(long selectCounter) { selectCount = selectCounter; - if(selectCounter <= 0) { + if (selectCounter <= 0) { return this.end(); } else { query.append(".select('stepMain').fold().dedup()"); @@ -108,26 +109,28 @@ public class DslQueryBuilder { } public DslQueryBuilder edgeQuery(Edge edge, String aNode, String bNode) { - List<String> edgeLabels = edge.getLabels().stream().map(edgeLabel -> StringUtils.quote(edgeLabel.getLabel())).collect(Collectors.toList()); + List<String> edgeLabels = edge.getLabels().stream() + .map(edgeLabel -> StringUtils.quote(edgeLabel.getLabel())).collect(Collectors.toList()); EdgeRuleQuery.Builder baseQ = new EdgeRuleQuery.Builder(aNode, bNode); - if((AAIDirection.valueOf(edge.getDirection().name())) != AAIDirection.BOTH) { - baseQ = baseQ.direction(AAIDirection.valueOf(edge.getDirection().name())); + if ((AAIDirection.valueOf(edge.getDirection().name())) != AAIDirection.BOTH) { + baseQ = baseQ.direction(AAIDirection.valueOf(edge.getDirection().name())); } return edgeQueryWithBuilder(edgeLabels, aNode, bNode, baseQ); } - private DslQueryBuilder edgeQueryWithBuilder(List<String> edgeLabels, String aNode, String bNode, EdgeRuleQuery.Builder edgeBuilder) { - //TODO : change this for fuzzy search. + private DslQueryBuilder edgeQueryWithBuilder(List<String> edgeLabels, String aNode, + String bNode, EdgeRuleQuery.Builder edgeBuilder) { + // 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(", String.join(",", edgeLabels), "))"); + edgeLabelsClause = String.join("", ", new ArrayList<>(Arrays.asList(", + String.join(",", edgeLabels), "))"); } LOGGER.debug("EdgeLabels Clause: {}", edgeLabelsClause); @@ -140,23 +143,27 @@ public class DslQueryBuilder { try { rules.putAll(edgeRules.getRules(edgeBuilder.label(label).build())); } catch (EdgeRuleNotFoundException e) { - queryException.append("Exception while finding the edge rule between the nodeTypes: ").append(aNode).append(", ").append(bNode).append(label); + queryException + .append("Exception while finding the edge rule between the nodeTypes: ") + .append(aNode).append(", ").append(bNode).append(label); } }); } } catch (EdgeRuleNotFoundException e) { if (!edgeLabels.isEmpty()) { - queryException.append("- No EdgeRule found for passed nodeTypes: ").append(aNode).append(", ").append(bNode).append(edgeLabels.stream().toString()); - } - else { - queryException.append("- No EdgeRule found for passed nodeTypes: ").append(aNode).append(", ").append(bNode); + queryException.append("- No EdgeRule found for passed nodeTypes: ").append(aNode) + .append(", ").append(bNode).append(edgeLabels.stream().toString()); + } else { + queryException.append("- No EdgeRule found for passed nodeTypes: ").append(aNode) + .append(", ").append(bNode); } return this; } if (rules.isEmpty() || rules.keys().isEmpty()) { - queryException.append("- No EdgeRule found for passed nodeTypes: ").append(aNode).append(", ").append(bNode); + queryException.append("- No EdgeRule found for passed nodeTypes: ").append(aNode) + .append(", ").append(bNode); } else { if (edgeLabels.isEmpty()) { if (edgeRules.hasRule(edgeBuilder.edgeType(EdgeType.TREE).build())) { @@ -172,16 +179,15 @@ public class DslQueryBuilder { } } - query.append(edgeTraversalClause).append(edgeType).append(" '").append(aNode) - .append("','").append(bNode).append("'").append(edgeLabelsClause).append(")"); + query.append(edgeTraversalClause).append(edgeType).append(" '").append(aNode).append("','") + .append(bNode).append("'").append(edgeLabelsClause).append(")"); return this; } - public DslQueryBuilder where(boolean isNot) { query.append(".where("); - if(isNot){ + if (isNot) { query.append("builder.newInstance().not("); } return this; @@ -189,7 +195,7 @@ public class DslQueryBuilder { public DslQueryBuilder endWhere(boolean isNot) { query.append(")"); - if(isNot){ + if (isNot) { query.append(")"); } return this; @@ -201,13 +207,14 @@ public class DslQueryBuilder { } public DslQueryBuilder filter(boolean isNot, String node, String key, List<String> values) { - return this.filterPropertyStart(isNot,values).filterPropertyKeys(node, key, values).filterPropertyEnd(); + return this.filterPropertyStart(isNot, values).filterPropertyKeys(node, key, values) + .filterPropertyEnd(); } public DslQueryBuilder filterPropertyStart(boolean isNot, List<String> values) { if (isNot) { query.append(".getVerticesExcludeByProperty("); - } else if(values!= null && !values.isEmpty() && Boolean.parseBoolean(values.get(0))) { + } else if (values != null && !values.isEmpty() && Boolean.parseBoolean(values.get(0))) { query.append(".getVerticesByBooleanProperty("); } else { query.append(".getVerticesByProperty("); @@ -225,10 +232,8 @@ public class DslQueryBuilder { Introspector obj = loader.introspectorFromName(node); if (keys.isEmpty()) { - queryException.append("No keys sent. Valid keys for ") - .append(node) - .append(" are ") - .append(String.join(",", obj.getIndexedProperties())); + queryException.append("No keys sent. Valid keys for ").append(node).append(" are ") + .append(String.join(",", obj.getIndexedProperties())); return this; } @@ -241,21 +246,22 @@ public class DslQueryBuilder { public DslQueryBuilder select(long selectCounter, List<String> keys) { /* - * TODO : isNot should look at the vertex properties and include everything except the notKeys + * TODO : isNot should look at the vertex properties and include everything except the + * notKeys */ Pattern p = Pattern.compile("aai-node-type"); Matcher m = p.matcher(query); int count = 0; - while (m.find()){ + while (m.find()) { count++; } if (selectCounter == count || keys == null) { String selectStep = "step" + selectCounter; -// String keysArray = String.join(",", keys); - query.append(".as('").append(selectStep).append("')") - .append(".as('stepMain').select('").append(selectStep).append("')"); + // String keysArray = String.join(",", keys); + query.append(".as('").append(selectStep).append("')").append(".as('stepMain').select('") + .append(selectStep).append("')"); } return this; } @@ -263,7 +269,8 @@ public class DslQueryBuilder { public DslQueryBuilder filterPropertyKeys(String node, String key, List<String> values) { try { Introspector obj = loader.introspectorFromName(node); - Optional<String> alias = obj.getPropertyMetadata(key.replace("'",""), PropertyMetadata.DB_ALIAS); + Optional<String> alias = + obj.getPropertyMetadata(key.replace("'", ""), PropertyMetadata.DB_ALIAS); if (alias.isPresent()) { key = StringUtils.quote(alias.get()); } @@ -271,14 +278,15 @@ public class DslQueryBuilder { query.append(key); if (values != null && !values.isEmpty()) { - if (values.size() > 1) { // values.size() > 1 indicates possibility of a list + 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 { // otherwise values should only contain one value + query.append(",").append(" new ArrayList<>(Arrays.asList(").append(valuesArray) + .append("))"); + } else { // otherwise values should only contain one value query.append(",").append(getConvertedValue(classType, key, values.get(0))); } } @@ -297,30 +305,29 @@ public class DslQueryBuilder { if (classType.equals(Integer.class.getName())) { int castInt = Integer.parseInt(convertedValue); convertedValue = String.valueOf(castInt); - } - else if (classType.equals(Long.class.getName())) { + } else if (classType.equals(Long.class.getName())) { long castLong = Long.parseLong(convertedValue); convertedValue = String.valueOf(castLong); - } - else if (classType.equals(Boolean.class.getName())) { - if ("1".equals(convertedValue)) { // checking for integer true value + } else if (classType.equals(Boolean.class.getName())) { + if ("1".equals(convertedValue)) { // 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())); + 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())) { + if (classType.equals(Integer.class.getName()) || classType.equals(Boolean.class.getName()) + || classType.equals(Long.class.getName())) { return true; } return false; @@ -368,5 +375,4 @@ public class DslQueryBuilder { 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 14663e1..a21ca04 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 @@ -8,7 +8,7 @@ * 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 + * 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, @@ -19,6 +19,15 @@ */ 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.util.Map; + import org.antlr.v4.runtime.*; import org.antlr.v4.runtime.misc.ParseCancellationException; import org.antlr.v4.runtime.tree.ParseTree; @@ -32,138 +41,144 @@ import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.beans.factory.annotation.Autowired; -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.util.Map; - /** * The Class DslQueryProcessor. */ public class DslQueryProcessor { - private static final Logger LOGGER = LoggerFactory.getLogger(DslQueryProcessor.class); - - private Map<QueryVersion, ParseTreeListener> dslListeners; - private boolean startNodeValidationFlag = true; - private String validationRules = ""; - private String packageName = "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 isAggregate = false; - - @Autowired - public DslQueryProcessor(Map<QueryVersion, ParseTreeListener> dslListeners) { - this.dslListeners = dslListeners; - } - - 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)); - - packageName = packageName + 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); + private static final Logger LOGGER = LoggerFactory.getLogger(DslQueryProcessor.class); + + private Map<QueryVersion, ParseTreeListener> dslListeners; + private boolean startNodeValidationFlag = true; + private String validationRules = ""; + private String packageName = "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 isAggregate = false; + + @Autowired + public DslQueryProcessor(Map<QueryVersion, ParseTreeListener> dslListeners) { + this.dslListeners = dslListeners; + } + + 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)); + + packageName = packageName + 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"); - } - - } catch(ParseCancellationException e) { - throw new AAIException("AAI_6153", "DSL Syntax Error while processing the query: " + e.getMessage()); - - } catch (Exception e) { - throw new AAIException("AAI_6152","Error while processing the query: " + e.getMessage()); - - } - } - - public boolean isStartNodeValidationFlag() { - return startNodeValidationFlag; - } - - public void setStartNodeValidationFlag(boolean startNodeValidationFlag) { - this.startNodeValidationFlag = startNodeValidationFlag; - } - - public boolean isAggregate() { - return isAggregate; - } - - public void setAggregate(boolean aggregate) { - this.isAggregate = aggregate; - } - - public String getValidationRules() { - return validationRules; - } - - public void setValidationRules(String validationRules) { - this.validationRules = validationRules; - } + 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"); + } + + } catch (ParseCancellationException e) { + throw new AAIException("AAI_6153", + "DSL Syntax Error while processing the query: " + e.getMessage()); + + } catch (Exception e) { + throw new AAIException("AAI_6152", + "Error while processing the query: " + e.getMessage()); + + } + } + + public boolean isStartNodeValidationFlag() { + return startNodeValidationFlag; + } + + public void setStartNodeValidationFlag(boolean startNodeValidationFlag) { + this.startNodeValidationFlag = startNodeValidationFlag; + } + + public boolean isAggregate() { + return isAggregate; + } + + public void setAggregate(boolean aggregate) { + this.isAggregate = aggregate; + } + + public String getValidationRules() { + return validationRules; + } + + public void setValidationRules(String validationRules) { + this.validationRules = validationRules; + } } diff --git a/aai-traversal/src/main/java/org/onap/aai/rest/dsl/Edge.java b/aai-traversal/src/main/java/org/onap/aai/rest/dsl/Edge.java index c3be5dc..111c188 100644 --- a/aai-traversal/src/main/java/org/onap/aai/rest/dsl/Edge.java +++ b/aai-traversal/src/main/java/org/onap/aai/rest/dsl/Edge.java @@ -8,7 +8,7 @@ * 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 + * 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, @@ -19,17 +19,17 @@ */ package org.onap.aai.rest.dsl; -import org.onap.aai.rest.enums.EdgeDirection; - import java.util.List; import java.util.stream.Collectors; +import org.onap.aai.rest.enums.EdgeDirection; + public class Edge { private List<EdgeLabel> labels; private EdgeDirection direction; - public Edge (EdgeDirection direction, List<EdgeLabel> labels) { + public Edge(EdgeDirection direction, List<EdgeLabel> labels) { this.labels = labels; this.direction = direction; } @@ -53,7 +53,7 @@ public class Edge { @Override public String toString() { return String.format("labels: %s, direction: %s ", - labels.stream().map(EdgeLabel::getLabel).collect(Collectors.joining(",")), - this.getDirection().name()); + labels.stream().map(EdgeLabel::getLabel).collect(Collectors.joining(",")), + this.getDirection().name()); } -}
\ No newline at end of file +} diff --git a/aai-traversal/src/main/java/org/onap/aai/rest/dsl/EdgeLabel.java b/aai-traversal/src/main/java/org/onap/aai/rest/dsl/EdgeLabel.java index 703adaf..6acf758 100644 --- a/aai-traversal/src/main/java/org/onap/aai/rest/dsl/EdgeLabel.java +++ b/aai-traversal/src/main/java/org/onap/aai/rest/dsl/EdgeLabel.java @@ -8,7 +8,7 @@ * 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 + * 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, @@ -24,7 +24,7 @@ public class EdgeLabel { private String label; private boolean isExactMatch; - public EdgeLabel (String label, boolean isExactMatch) { + public EdgeLabel(String label, boolean isExactMatch) { this.isExactMatch = isExactMatch; this.label = label; } @@ -45,4 +45,4 @@ public class EdgeLabel { this.isExactMatch = isExactMatch; } -}
\ No newline at end of file +} 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 4bb093e..ad2899c 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 @@ -8,7 +8,7 @@ * 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 + * 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, @@ -20,6 +20,11 @@ package org.onap.aai.rest.dsl.v1; import com.google.common.collect.Lists; + +import java.util.*; +import java.util.stream.Collectors; +import java.util.stream.Stream; + import org.onap.aai.dsl.v1.AAIDslBaseListener; import org.onap.aai.dsl.v1.AAIDslParser; import org.onap.aai.edges.EdgeIngestor; @@ -36,271 +41,274 @@ import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.beans.factory.annotation.Autowired; -import java.util.*; -import java.util.stream.Collectors; -import java.util.stream.Stream; - /** * The Class DslListener. */ public class DslListener extends AAIDslBaseListener { - private static final Logger LOGGER = LoggerFactory.getLogger(DslListener.class); - - private boolean validationFlag = false; - private EdgeIngestor edgeIngestor; - private Loader loader; - private Optional<DslValidator> queryValidator = Optional.empty(); - private boolean hasReturnValue = false; - - private String validationRules = "none"; - - private Deque<DslQueryBuilder> dslQueryBuilders = new LinkedList<>(); - private Deque<String> traversedNodes = new LinkedList<>(); - private Deque<List<String>> returnedNodes = new LinkedList<>(); - - private List<String> traversedEdgeLabels = new LinkedList<>(); - - private boolean isAggregate = false; - - /* - * Additional datastructures to store all nodeCount & looped edges - */ - private int nodeCount = 0; - private List<String> traversedEdges = new LinkedList<>(); - - /** - * Instantiates a new DslListener. - */ - @Autowired - public DslListener(EdgeIngestor edgeIngestor, SchemaVersions schemaVersions, LoaderFactory loaderFactory) { - this.loader = loaderFactory.createLoaderForVersion(ModelType.MOXY, schemaVersions.getDefaultVersion()); - this.edgeIngestor = edgeIngestor; - } - - public DslQueryBuilder builder() { - return dslQueryBuilders.peekFirst(); - } - - public String getQuery() throws AAIException { - if (!getException().isEmpty()) { - AAIException aaiException = new AAIException("AAI_6149", getException()); - ErrorLogHelper.logException(aaiException); - throw aaiException; - } - - DslValidatorRule ruleValidator = new DslValidatorRule.Builder() - .loop(getValidationRules() , traversedEdges) - .nodeCount(getValidationRules(), nodeCount).build(); - if(queryValidator.isPresent() && !queryValidator.get().validate(ruleValidator)){ - AAIException aaiException = new AAIException("AAI_6151", "Validation error " + queryValidator.get().getErrorMessage() ); - ErrorLogHelper.logException(aaiException); - throw aaiException; - } - 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() { - List<String> exceptions = dslQueryBuilders.stream().map(dslQb -> dslQb.getQueryException().toString()).collect(Collectors.toList()); - return String.join("", Lists.reverse(exceptions)); - } - - @Override - public void enterAaiquery(AAIDslParser.AaiqueryContext ctx) { - dslQueryBuilders.push(new DslQueryBuilder(edgeIngestor, loader)); - } - - @Override - public void exitAaiquery(AAIDslParser.AaiqueryContext ctx) { - if (!hasReturnValue) { - throw new RuntimeException(new AAIException("AAI_6149", "No nodes marked for output")); - } - } - - @Override - public void enterStartStatement(AAIDslParser.StartStatementContext ctx) { - builder().start(); - } - - @Override - public void exitStartStatement(AAIDslParser.StartStatementContext ctx) { - builder().end(); - if (!traversedNodes.isEmpty()) { - traversedNodes.removeFirst(); - } - - } - - @Override - public void exitLimit(AAIDslParser.LimitContext ctx) { - builder().limit(ctx.num().getText()); - } - - @Override - public void enterNestedStatement(AAIDslParser.NestedStatementContext ctx) { - dslQueryBuilders.addFirst(new DslQueryBuilder(edgeIngestor, loader)); - builder().startInstance(); - } - - @Override - public void exitNestedStatement(AAIDslParser.NestedStatementContext ctx) { - int count = 1; - if(!ctx.traversal().isEmpty()) { - count += ctx.traversal().size() ; - } - String resultNode = traversedNodes.peekFirst(); - - 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(); - } - - @Override - public void enterVertex(AAIDslParser.VertexContext ctx) { - - if (!traversedNodes.isEmpty()) { - builder().edgeQuery(traversedEdgeLabels, traversedNodes.peekFirst(), ctx.label().getText()); - traversedEdges.add(traversedNodes.peekFirst() + ctx.label().getText()); - } else { - builder().nodeQuery(ctx.label().getText()); - } - - traversedNodes.addFirst(ctx.label().getText()); - } - - @Override - 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().replaceFirst("\'", "").substring(0, e.getText().length() - 2)).collect(Collectors.toList()); - - } - builder().validateFilter(ctx.label().getText(), allKeys); - } - if (ctx.store() != null) { - builder().store(); - hasReturnValue = true; - } - traversedEdgeLabels = new ArrayList<>(); - nodeCount++; - } - - - @Override - public void enterUnionVertex(AAIDslParser.UnionVertexContext ctx) { - returnedNodes.addFirst(new ArrayList<>()); - builder().union(); - } - - @Override - public void exitUnionVertex(AAIDslParser.UnionVertexContext ctx) { - String resultNode = returnedNodes.pop().get(0); - traversedNodes.addFirst(resultNode); - builder().endUnion(); - if (ctx.store() != null) { - builder().store(); - hasReturnValue = true; - } - } - - @Override - public void enterWhereFilter(AAIDslParser.WhereFilterContext ctx) { - boolean isNot = ctx.not() != null && !ctx.not().isEmpty(); - returnedNodes.addFirst(new ArrayList<>()); - builder().where(isNot); - } - - @Override - public void exitWhereFilter(AAIDslParser.WhereFilterContext ctx) { - if(!returnedNodes.isEmpty()) { - returnedNodes.pop(); - } - boolean isNot = ctx.not() != null && !ctx.not().isEmpty(); - builder().endWhere(isNot); - } - - @Override - public void enterEdgeFilter(AAIDslParser.EdgeFilterContext ctx) { - traversedEdgeLabels = ctx.key().stream().map(value -> value.getText()).collect(Collectors.toList()); - - } - - @Override - 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(); - - List<AAIDslParser.BoolContext> booleanValues = ctx.bool(); - - /* - * Add all String values - */ - List<String> values = valueList.stream().filter(value -> !filterKey.equals(value.getText())) - .map(value -> value.getText()).collect(Collectors.toList()); - - /* - * Add all numeric values - */ - values.addAll(numberValues.stream().filter(value -> !filterKey.equals(value.getText())) - .map(value -> value.getText()).collect(Collectors.toList())); - - /* - * Add all boolean values - */ - values.addAll(booleanValues.stream().filter(value -> !filterKey.equals(value.getText())) - .map(value -> value.getText().toLowerCase()).collect(Collectors.toList())); - - builder().filter(isNot, traversedNodes.peekFirst(), filterKey, values); - - } - - public boolean isValidationFlag() { - return validationFlag; - } - - public void setValidationFlag(boolean validationFlag) { - this.validationFlag = validationFlag; - } - - public void setQueryValidator(DslValidator queryValidator, String validationRules) { - this.queryValidator = Optional.of(queryValidator); - this.validationRules = validationRules; - } - public String getValidationRules() { - return validationRules; - } - - public void setAggregateFlag(boolean isAggregate) { - this.isAggregate = isAggregate; - } - - public boolean isAggregate(){ - return this.isAggregate; - } + private static final Logger LOGGER = LoggerFactory.getLogger(DslListener.class); + + private boolean validationFlag = false; + private EdgeIngestor edgeIngestor; + private Loader loader; + private Optional<DslValidator> queryValidator = Optional.empty(); + private boolean hasReturnValue = false; + + private String validationRules = "none"; + + private Deque<DslQueryBuilder> dslQueryBuilders = new LinkedList<>(); + private Deque<String> traversedNodes = new LinkedList<>(); + private Deque<List<String>> returnedNodes = new LinkedList<>(); + + private List<String> traversedEdgeLabels = new LinkedList<>(); + + private boolean isAggregate = false; + + /* + * Additional datastructures to store all nodeCount & looped edges + */ + private int nodeCount = 0; + private List<String> traversedEdges = new LinkedList<>(); + + /** + * Instantiates a new DslListener. + */ + @Autowired + public DslListener(EdgeIngestor edgeIngestor, SchemaVersions schemaVersions, + LoaderFactory loaderFactory) { + this.loader = loaderFactory.createLoaderForVersion(ModelType.MOXY, + schemaVersions.getDefaultVersion()); + this.edgeIngestor = edgeIngestor; + } + + public DslQueryBuilder builder() { + return dslQueryBuilders.peekFirst(); + } + + public String getQuery() throws AAIException { + if (!getException().isEmpty()) { + AAIException aaiException = new AAIException("AAI_6149", getException()); + ErrorLogHelper.logException(aaiException); + throw aaiException; + } + + DslValidatorRule ruleValidator = + new DslValidatorRule.Builder().loop(getValidationRules(), traversedEdges) + .nodeCount(getValidationRules(), nodeCount).build(); + if (queryValidator.isPresent() && !queryValidator.get().validate(ruleValidator)) { + AAIException aaiException = new AAIException("AAI_6151", + "Validation error " + queryValidator.get().getErrorMessage()); + ErrorLogHelper.logException(aaiException); + throw aaiException; + } + 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() { + List<String> exceptions = dslQueryBuilders.stream() + .map(dslQb -> dslQb.getQueryException().toString()).collect(Collectors.toList()); + return String.join("", Lists.reverse(exceptions)); + } + + @Override + public void enterAaiquery(AAIDslParser.AaiqueryContext ctx) { + dslQueryBuilders.push(new DslQueryBuilder(edgeIngestor, loader)); + } + + @Override + public void exitAaiquery(AAIDslParser.AaiqueryContext ctx) { + if (!hasReturnValue) { + throw new RuntimeException(new AAIException("AAI_6149", "No nodes marked for output")); + } + } + + @Override + public void enterStartStatement(AAIDslParser.StartStatementContext ctx) { + builder().start(); + } + + @Override + public void exitStartStatement(AAIDslParser.StartStatementContext ctx) { + builder().end(); + if (!traversedNodes.isEmpty()) { + traversedNodes.removeFirst(); + } + + } + + @Override + public void exitLimit(AAIDslParser.LimitContext ctx) { + builder().limit(ctx.num().getText()); + } + + @Override + public void enterNestedStatement(AAIDslParser.NestedStatementContext ctx) { + dslQueryBuilders.addFirst(new DslQueryBuilder(edgeIngestor, loader)); + builder().startInstance(); + } + + @Override + public void exitNestedStatement(AAIDslParser.NestedStatementContext ctx) { + int count = 1; + if (!ctx.traversal().isEmpty()) { + count += ctx.traversal().size(); + } + String resultNode = traversedNodes.peekFirst(); + + 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(); + } + + @Override + public void enterVertex(AAIDslParser.VertexContext ctx) { + + if (!traversedNodes.isEmpty()) { + builder().edgeQuery(traversedEdgeLabels, traversedNodes.peekFirst(), + ctx.label().getText()); + traversedEdges.add(traversedNodes.peekFirst() + ctx.label().getText()); + } else { + builder().nodeQuery(ctx.label().getText()); + } + + traversedNodes.addFirst(ctx.label().getText()); + } + + @Override + 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().replaceFirst("\'", "").substring(0, e.getText().length() - 2)) + .collect(Collectors.toList()); + + } + builder().validateFilter(ctx.label().getText(), allKeys); + } + if (ctx.store() != null) { + builder().store(); + hasReturnValue = true; + } + traversedEdgeLabels = new ArrayList<>(); + nodeCount++; + } + + @Override + public void enterUnionVertex(AAIDslParser.UnionVertexContext ctx) { + returnedNodes.addFirst(new ArrayList<>()); + builder().union(); + } + + @Override + public void exitUnionVertex(AAIDslParser.UnionVertexContext ctx) { + String resultNode = returnedNodes.pop().get(0); + traversedNodes.addFirst(resultNode); + builder().endUnion(); + if (ctx.store() != null) { + builder().store(); + hasReturnValue = true; + } + } + + @Override + public void enterWhereFilter(AAIDslParser.WhereFilterContext ctx) { + boolean isNot = ctx.not() != null && !ctx.not().isEmpty(); + returnedNodes.addFirst(new ArrayList<>()); + builder().where(isNot); + } + + @Override + public void exitWhereFilter(AAIDslParser.WhereFilterContext ctx) { + if (!returnedNodes.isEmpty()) { + returnedNodes.pop(); + } + boolean isNot = ctx.not() != null && !ctx.not().isEmpty(); + builder().endWhere(isNot); + } + + @Override + public void enterEdgeFilter(AAIDslParser.EdgeFilterContext ctx) { + traversedEdgeLabels = + ctx.key().stream().map(value -> value.getText()).collect(Collectors.toList()); + + } + + @Override + 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(); + + List<AAIDslParser.BoolContext> booleanValues = ctx.bool(); + + /* + * Add all String values + */ + List<String> values = valueList.stream().filter(value -> !filterKey.equals(value.getText())) + .map(value -> value.getText()).collect(Collectors.toList()); + + /* + * Add all numeric values + */ + values.addAll(numberValues.stream().filter(value -> !filterKey.equals(value.getText())) + .map(value -> value.getText()).collect(Collectors.toList())); + + /* + * Add all boolean values + */ + values.addAll(booleanValues.stream().filter(value -> !filterKey.equals(value.getText())) + .map(value -> value.getText().toLowerCase()).collect(Collectors.toList())); + + builder().filter(isNot, traversedNodes.peekFirst(), filterKey, values); + + } + + public boolean isValidationFlag() { + return validationFlag; + } + + public void setValidationFlag(boolean validationFlag) { + this.validationFlag = validationFlag; + } + + public void setQueryValidator(DslValidator queryValidator, String validationRules) { + this.queryValidator = Optional.of(queryValidator); + this.validationRules = validationRules; + } + + public String getValidationRules() { + return validationRules; + } + + public void setAggregateFlag(boolean isAggregate) { + this.isAggregate = isAggregate; + } + + public boolean isAggregate() { + return this.isAggregate; + } } 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 66ca8a1..7e46c0b 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 @@ -8,7 +8,7 @@ * 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 + * 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, @@ -20,6 +20,11 @@ package org.onap.aai.rest.dsl.v2; import com.google.common.collect.Lists; + +import java.util.*; +import java.util.stream.Collectors; +import java.util.stream.Stream; + import org.onap.aai.dsl.v2.AAIDslBaseListener; import org.onap.aai.dsl.v2.AAIDslParser; import org.onap.aai.edges.EdgeIngestor; @@ -39,273 +44,274 @@ import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.beans.factory.annotation.Autowired; -import java.util.*; -import java.util.stream.Collectors; -import java.util.stream.Stream; - /** * The Class DslListener. */ public class DslListener extends AAIDslBaseListener { - private static final Logger LOGGER = LoggerFactory.getLogger(DslListener.class.getName()); - - private boolean validationFlag = false; - private EdgeIngestor edgeIngestor; - private Loader loader; - private Optional<DslValidator> queryValidator = Optional.empty(); - private boolean hasReturnValue = false; - - private String validationRules = "none"; - - private Deque<DslQueryBuilder> dslQueryBuilders = new LinkedList<>(); - private Deque<String> traversedNodes = new LinkedList<>(); - private Deque<List<String>> returnedNodes = new LinkedList<>(); - - private Deque<Edge> traversedEdges = new ArrayDeque<>(); - private long selectCounter = 0; - - /* - * Additional datastructures to store all nodeCount & looped edges - */ - int nodeCount = 0; - private List<String> traversedEdgesOld = new LinkedList<>(); - - private Map<String, List<String>> selectKeys = new HashMap<String, List<String>>(); - private boolean isAggregate; - - public Map<String, List<String>> getSelectKeys() { - return selectKeys; - } - - public void setSelectKeys(String nodeType, List<String> properties) { - this.selectKeys.put(nodeType, properties); - } - - /** - * Instantiates a new DslListener. - */ - @Autowired - public DslListener(EdgeIngestor edgeIngestor, SchemaVersions schemaVersions, LoaderFactory loaderFactory) { - this.loader = loaderFactory.createLoaderForVersion(ModelType.MOXY, schemaVersions.getDefaultVersion()); - this.edgeIngestor = edgeIngestor; - } - - public DslQueryBuilder builder() { - return dslQueryBuilders.peekFirst(); - } - - public String getQuery() throws AAIException { - //TODO Change the exception reporting - if (!getException().isEmpty()) { - AAIException aaiException = new AAIException("AAI_6149", getException()); - ErrorLogHelper.logException(aaiException); - throw aaiException; - } - - DslValidatorRule ruleValidator = new DslValidatorRule.Builder() - .loop(getValidationRules() , traversedEdgesOld) - .nodeCount(getValidationRules(), nodeCount).build(); - if(queryValidator.isPresent() && !queryValidator.get().validate(ruleValidator)){ - AAIException aaiException = new AAIException("AAI_6151", "Validation error " + queryValidator.get().getErrorMessage() ); - ErrorLogHelper.logException(aaiException); - throw aaiException; - } - 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() { - List<String> exceptions = dslQueryBuilders.stream().map(dslQb -> dslQb.getQueryException().toString()).collect(Collectors.toList()); - return String.join("", Lists.reverse(exceptions)); - } - - @Override - public void enterAaiquery(AAIDslParser.AaiqueryContext ctx) { - dslQueryBuilders.push(new DslQueryBuilder(edgeIngestor, loader)); - } - - @Override - public void exitAaiquery(AAIDslParser.AaiqueryContext ctx) { - if (!hasReturnValue) { - throw new RuntimeException(new AAIException("AAI_6149", "No nodes marked for output")); - } - } - - @Override - public void enterStartStatement(AAIDslParser.StartStatementContext ctx) { - builder().start(); - } - - @Override - public void exitStartStatement(AAIDslParser.StartStatementContext ctx) { - builder().end(selectCounter); - if (!traversedNodes.isEmpty()) { - traversedNodes.removeFirst(); - } - - } - - @Override - public void exitLimit(AAIDslParser.LimitContext ctx) { - builder().limit(ctx.num().getText()); - } - - @Override - public void enterNestedStatement(AAIDslParser.NestedStatementContext ctx) { - dslQueryBuilders.addFirst(new DslQueryBuilder(edgeIngestor, loader)); - builder().startInstance(); - } - - @Override - public void exitNestedStatement(AAIDslParser.NestedStatementContext ctx) { - int count = 1; - if(!ctx.traversal().isEmpty()) { - count = ctx.traversal().size() ; - } - String resultNode = traversedNodes.peekFirst(); - - 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(); - } - - @Override - public void enterVertex(AAIDslParser.VertexContext ctx) { - - if (!traversedEdges.isEmpty() && !traversedNodes.isEmpty()) { - builder().edgeQuery(traversedEdges.peekFirst(), traversedNodes.peekFirst(), ctx.label().getText()); - traversedEdgesOld.add(traversedNodes.peekFirst() + ctx.label().getText()); - } else { - builder().nodeQuery(ctx.label().getText()); - } - - traversedNodes.addFirst(ctx.label().getText()); - } - - @Override - 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().replaceFirst("\'", "").substring(0, e.getText().length() - 2)).collect(Collectors.toList()); - } - builder().validateFilter(ctx.label().getText(), allKeys); - } - if (ctx.store() != null) { - if (isAggregate()) { - builder().select(selectCounter++, null); - } - builder().store(); - hasReturnValue = true; - } - nodeCount++; - } - - - @Override - public void enterUnionVertex(AAIDslParser.UnionVertexContext ctx) { - returnedNodes.addFirst(new ArrayList<>()); - builder().union(); - } - - @Override - public void exitUnionVertex(AAIDslParser.UnionVertexContext ctx) { - String resultNode = returnedNodes.pop().get(0); - traversedNodes.addFirst(resultNode); - builder().endUnion(); - if (ctx.store() != null) { - builder().store(); - hasReturnValue = true; - } - } - - @Override - public void enterWhereFilter(AAIDslParser.WhereFilterContext ctx) { - boolean isNot = ctx.not() != null && !ctx.not().isEmpty(); - returnedNodes.addFirst(new ArrayList<>()); - builder().where(isNot); - } - - @Override - public void exitWhereFilter(AAIDslParser.WhereFilterContext ctx) { - if(!returnedNodes.isEmpty()) { - returnedNodes.pop(); - } - boolean isNot = ctx.not() != null && !ctx.not().isEmpty(); - builder().endWhere(isNot); - } - - @Override - public void enterEdge(AAIDslParser.EdgeContext ctx) { - List<EdgeLabel> labels = new ArrayList<>(); - - if(ctx.edgeFilter() != null) { - labels.addAll(ctx.edgeFilter().key().stream().map( - e -> new EdgeLabel(removeSingleQuotes(e.getText()), true)) - .collect(Collectors.toList())); - } - EdgeDirection direction = EdgeDirection.BOTH; - if(ctx.DIRTRAVERSE() != null){ - direction = EdgeDirection.fromValue(ctx.DIRTRAVERSE().getText()); - } - traversedEdges.addFirst(new Edge(direction, labels)); - } - - protected String removeSingleQuotes(String value) { - return value.replaceFirst("^'(.*)'$", "$1"); - } - - @Override - 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(); - - List<AAIDslParser.BoolContext> booleanValues = ctx.bool(); - - /* - * Add all String values - */ - List<String> values = valueList.stream().filter(value -> !filterKey.equals(value.getText())) - .map(value -> value.getText()).collect(Collectors.toList()); - /* - * Add all numeric values - */ - values.addAll(numberValues.stream().filter(value -> !filterKey.equals(value.getText())) - .map(value -> value.getText()).collect(Collectors.toList())); - - /* - * Add all boolean values - */ - values.addAll(booleanValues.stream().filter(value -> !filterKey.equals(value.getText())) - .map(value -> value.getText().toLowerCase()).collect(Collectors.toList())); - - builder().filter(isNot, traversedNodes.peekFirst(), filterKey, values); - - } + private static final Logger LOGGER = LoggerFactory.getLogger(DslListener.class.getName()); + + private boolean validationFlag = false; + private EdgeIngestor edgeIngestor; + private Loader loader; + private Optional<DslValidator> queryValidator = Optional.empty(); + private boolean hasReturnValue = false; + + private String validationRules = "none"; + + private Deque<DslQueryBuilder> dslQueryBuilders = new LinkedList<>(); + private Deque<String> traversedNodes = new LinkedList<>(); + private Deque<List<String>> returnedNodes = new LinkedList<>(); + + private Deque<Edge> traversedEdges = new ArrayDeque<>(); + private long selectCounter = 0; + + /* + * Additional datastructures to store all nodeCount & looped edges + */ + int nodeCount = 0; + private List<String> traversedEdgesOld = new LinkedList<>(); + + private Map<String, List<String>> selectKeys = new HashMap<String, List<String>>(); + private boolean isAggregate; + + public Map<String, List<String>> getSelectKeys() { + return selectKeys; + } + + public void setSelectKeys(String nodeType, List<String> properties) { + this.selectKeys.put(nodeType, properties); + } + + /** + * Instantiates a new DslListener. + */ + @Autowired + public DslListener(EdgeIngestor edgeIngestor, SchemaVersions schemaVersions, + LoaderFactory loaderFactory) { + this.loader = loaderFactory.createLoaderForVersion(ModelType.MOXY, + schemaVersions.getDefaultVersion()); + this.edgeIngestor = edgeIngestor; + } + + public DslQueryBuilder builder() { + return dslQueryBuilders.peekFirst(); + } + + public String getQuery() throws AAIException { + // TODO Change the exception reporting + if (!getException().isEmpty()) { + AAIException aaiException = new AAIException("AAI_6149", getException()); + ErrorLogHelper.logException(aaiException); + throw aaiException; + } + + DslValidatorRule ruleValidator = + new DslValidatorRule.Builder().loop(getValidationRules(), traversedEdgesOld) + .nodeCount(getValidationRules(), nodeCount).build(); + if (queryValidator.isPresent() && !queryValidator.get().validate(ruleValidator)) { + AAIException aaiException = new AAIException("AAI_6151", + "Validation error " + queryValidator.get().getErrorMessage()); + ErrorLogHelper.logException(aaiException); + throw aaiException; + } + 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() { + List<String> exceptions = dslQueryBuilders.stream() + .map(dslQb -> dslQb.getQueryException().toString()).collect(Collectors.toList()); + return String.join("", Lists.reverse(exceptions)); + } + + @Override + public void enterAaiquery(AAIDslParser.AaiqueryContext ctx) { + dslQueryBuilders.push(new DslQueryBuilder(edgeIngestor, loader)); + } + + @Override + public void exitAaiquery(AAIDslParser.AaiqueryContext ctx) { + if (!hasReturnValue) { + throw new RuntimeException(new AAIException("AAI_6149", "No nodes marked for output")); + } + } + + @Override + public void enterStartStatement(AAIDslParser.StartStatementContext ctx) { + builder().start(); + } + + @Override + public void exitStartStatement(AAIDslParser.StartStatementContext ctx) { + builder().end(selectCounter); + if (!traversedNodes.isEmpty()) { + traversedNodes.removeFirst(); + } + + } + + @Override + public void exitLimit(AAIDslParser.LimitContext ctx) { + builder().limit(ctx.num().getText()); + } + + @Override + public void enterNestedStatement(AAIDslParser.NestedStatementContext ctx) { + dslQueryBuilders.addFirst(new DslQueryBuilder(edgeIngestor, loader)); + builder().startInstance(); + } + + @Override + public void exitNestedStatement(AAIDslParser.NestedStatementContext ctx) { + int count = 1; + if (!ctx.traversal().isEmpty()) { + count = ctx.traversal().size(); + } + String resultNode = traversedNodes.peekFirst(); + + 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(); + } + + @Override + public void enterVertex(AAIDslParser.VertexContext ctx) { + + if (!traversedEdges.isEmpty() && !traversedNodes.isEmpty()) { + builder().edgeQuery(traversedEdges.peekFirst(), traversedNodes.peekFirst(), + ctx.label().getText()); + traversedEdgesOld.add(traversedNodes.peekFirst() + ctx.label().getText()); + } else { + builder().nodeQuery(ctx.label().getText()); + } + + traversedNodes.addFirst(ctx.label().getText()); + } + + @Override + 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().replaceFirst("\'", "").substring(0, e.getText().length() - 2)) + .collect(Collectors.toList()); + } + builder().validateFilter(ctx.label().getText(), allKeys); + } + if (ctx.store() != null) { + if (isAggregate()) { + builder().select(selectCounter++, null); + } + builder().store(); + hasReturnValue = true; + } + nodeCount++; + } + + @Override + public void enterUnionVertex(AAIDslParser.UnionVertexContext ctx) { + returnedNodes.addFirst(new ArrayList<>()); + builder().union(); + } + + @Override + public void exitUnionVertex(AAIDslParser.UnionVertexContext ctx) { + String resultNode = returnedNodes.pop().get(0); + traversedNodes.addFirst(resultNode); + builder().endUnion(); + if (ctx.store() != null) { + builder().store(); + hasReturnValue = true; + } + } + + @Override + public void enterWhereFilter(AAIDslParser.WhereFilterContext ctx) { + boolean isNot = ctx.not() != null && !ctx.not().isEmpty(); + returnedNodes.addFirst(new ArrayList<>()); + builder().where(isNot); + } + + @Override + public void exitWhereFilter(AAIDslParser.WhereFilterContext ctx) { + if (!returnedNodes.isEmpty()) { + returnedNodes.pop(); + } + boolean isNot = ctx.not() != null && !ctx.not().isEmpty(); + builder().endWhere(isNot); + } + + @Override + public void enterEdge(AAIDslParser.EdgeContext ctx) { + List<EdgeLabel> labels = new ArrayList<>(); + + if (ctx.edgeFilter() != null) { + labels.addAll(ctx.edgeFilter().key().stream() + .map(e -> new EdgeLabel(removeSingleQuotes(e.getText()), true)) + .collect(Collectors.toList())); + } + EdgeDirection direction = EdgeDirection.BOTH; + if (ctx.DIRTRAVERSE() != null) { + direction = EdgeDirection.fromValue(ctx.DIRTRAVERSE().getText()); + } + traversedEdges.addFirst(new Edge(direction, labels)); + } + + protected String removeSingleQuotes(String value) { + return value.replaceFirst("^'(.*)'$", "$1"); + } + + @Override + 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(); + + List<AAIDslParser.BoolContext> booleanValues = ctx.bool(); + + /* + * Add all String values + */ + List<String> values = valueList.stream().filter(value -> !filterKey.equals(value.getText())) + .map(value -> value.getText()).collect(Collectors.toList()); + /* + * Add all numeric values + */ + values.addAll(numberValues.stream().filter(value -> !filterKey.equals(value.getText())) + .map(value -> value.getText()).collect(Collectors.toList())); + + /* + * Add all boolean values + */ + values.addAll(booleanValues.stream().filter(value -> !filterKey.equals(value.getText())) + .map(value -> value.getText().toLowerCase()).collect(Collectors.toList())); + + builder().filter(isNot, traversedNodes.peekFirst(), filterKey, values); + + } @Override public void enterSelectFilter(AAIDslParser.SelectFilterContext ctx) { @@ -315,37 +321,40 @@ public class DslListener extends AAIDslBaseListener { /* * Add all String values */ - List<String> allKeys = keyList.stream().map(keyValue -> "'" + keyValue.getText().replace("'", "") + "'").collect(Collectors.toList()); - if (allKeys != null && !allKeys.isEmpty()){ - setSelectKeys(traversedNodes.getFirst(), allKeys); - } - if (isAggregate() && (traversedNodes.size() == nodeCount)) { - builder().select(selectCounter++, allKeys); - } + List<String> allKeys = + keyList.stream().map(keyValue -> "'" + keyValue.getText().replace("'", "") + "'") + .collect(Collectors.toList()); + if (allKeys != null && !allKeys.isEmpty()) { + setSelectKeys(traversedNodes.getFirst(), allKeys); + } + if (isAggregate() && (traversedNodes.size() == nodeCount)) { + builder().select(selectCounter++, allKeys); + } + } + + public boolean isValidationFlag() { + return validationFlag; } - public boolean isValidationFlag() { - return validationFlag; - } - - public void setValidationFlag(boolean validationFlag) { - this.validationFlag = validationFlag; - } - - public void setAggregateFlag(boolean isAggregate) { - this.isAggregate = isAggregate; - } - - public boolean isAggregate(){ - return this.isAggregate; - } - - public void setQueryValidator(DslValidator queryValidator, String validationRules) { - this.queryValidator = Optional.of(queryValidator); - this.validationRules = validationRules; - } - public String getValidationRules() { - return validationRules; - } + public void setValidationFlag(boolean validationFlag) { + this.validationFlag = validationFlag; + } + + public void setAggregateFlag(boolean isAggregate) { + this.isAggregate = isAggregate; + } + + public boolean isAggregate() { + return this.isAggregate; + } + + public void setQueryValidator(DslValidator queryValidator, String validationRules) { + this.queryValidator = Optional.of(queryValidator); + this.validationRules = validationRules; + } + + public String getValidationRules() { + return validationRules; + } } diff --git a/aai-traversal/src/main/java/org/onap/aai/rest/dsl/validation/DslQueryValidator.java b/aai-traversal/src/main/java/org/onap/aai/rest/dsl/validation/DslQueryValidator.java index 53f2c72..e82cfc2 100644 --- a/aai-traversal/src/main/java/org/onap/aai/rest/dsl/validation/DslQueryValidator.java +++ b/aai-traversal/src/main/java/org/onap/aai/rest/dsl/validation/DslQueryValidator.java @@ -8,7 +8,7 @@ * 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 + * 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, @@ -19,13 +19,13 @@ */ package org.onap.aai.rest.dsl.validation; -import org.onap.aai.util.AAIConfig; -import org.onap.aai.util.TraversalConstants; - import java.util.LinkedHashSet; import java.util.List; import java.util.Set; +import org.onap.aai.util.AAIConfig; +import org.onap.aai.util.TraversalConstants; + public class DslQueryValidator extends DslValidator { protected DslQueryValidator(Builder builder) { @@ -34,7 +34,9 @@ public class DslQueryValidator extends DslValidator { public boolean validate(DslValidatorRule dslValidatorRule) { - return validateLoop(dslValidatorRule.isValidateLoop(), dslValidatorRule.getEdges()) && validateNodeCount(dslValidatorRule.isValidateNodeCount(), dslValidatorRule.getNodeCount()); + return validateLoop(dslValidatorRule.isValidateLoop(), dslValidatorRule.getEdges()) + && validateNodeCount(dslValidatorRule.isValidateNodeCount(), + dslValidatorRule.getNodeCount()); } private boolean validateLoop(boolean isValidateLoop, List<String> edges) { @@ -50,7 +52,8 @@ public class DslQueryValidator extends DslValidator { } private boolean validateNodeCount(boolean isValidateNodeCount, int nodeCount) { - String maxNodeString = AAIConfig.get("aai.dsl.max.nodecount", TraversalConstants.DSL_MAX_NODE_COUNT); + String maxNodeString = + AAIConfig.get("aai.dsl.max.nodecount", TraversalConstants.DSL_MAX_NODE_COUNT); int maxNodeCount = Integer.parseInt(maxNodeString); if (isValidateNodeCount && nodeCount > maxNodeCount) { this.errorMessage.append("NodeCount Validation failed"); diff --git a/aai-traversal/src/main/java/org/onap/aai/rest/dsl/validation/DslSchemaValidator.java b/aai-traversal/src/main/java/org/onap/aai/rest/dsl/validation/DslSchemaValidator.java index 54a2feb..15d8cca 100644 --- a/aai-traversal/src/main/java/org/onap/aai/rest/dsl/validation/DslSchemaValidator.java +++ b/aai-traversal/src/main/java/org/onap/aai/rest/dsl/validation/DslSchemaValidator.java @@ -8,7 +8,7 @@ * 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 + * 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, diff --git a/aai-traversal/src/main/java/org/onap/aai/rest/dsl/validation/DslValidator.java b/aai-traversal/src/main/java/org/onap/aai/rest/dsl/validation/DslValidator.java index 128f8a8..7f14458 100644 --- a/aai-traversal/src/main/java/org/onap/aai/rest/dsl/validation/DslValidator.java +++ b/aai-traversal/src/main/java/org/onap/aai/rest/dsl/validation/DslValidator.java @@ -8,7 +8,7 @@ * 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 + * 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, @@ -24,7 +24,6 @@ import org.onap.aai.exceptions.AAIException; public abstract class DslValidator { protected StringBuilder errorMessage = new StringBuilder(""); - protected DslValidator(DslValidator.Builder builder) { } diff --git a/aai-traversal/src/main/java/org/onap/aai/rest/dsl/validation/DslValidatorRule.java b/aai-traversal/src/main/java/org/onap/aai/rest/dsl/validation/DslValidatorRule.java index 54d45bd..117c9a5 100644 --- a/aai-traversal/src/main/java/org/onap/aai/rest/dsl/validation/DslValidatorRule.java +++ b/aai-traversal/src/main/java/org/onap/aai/rest/dsl/validation/DslValidatorRule.java @@ -8,7 +8,7 @@ * 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 + * 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, @@ -84,7 +84,7 @@ public class DslValidatorRule { public static class Builder { - //todo optional + // todo optional String query = ""; boolean validateLoop = false; boolean validateNodeCount = false; @@ -114,7 +114,8 @@ public class DslValidatorRule { } public Builder nodeCount(String validateNodeCount, int nodeCount) { - if (validateNodeCount.contains(NODECOUNT_RULE) || validateNodeCount.contains(ALL_RULE)) { + if (validateNodeCount.contains(NODECOUNT_RULE) + || validateNodeCount.contains(ALL_RULE)) { this.setValidateNodeCount(true); this.nodeCount = nodeCount; } diff --git a/aai-traversal/src/main/java/org/onap/aai/rest/enums/EdgeDirection.java b/aai-traversal/src/main/java/org/onap/aai/rest/enums/EdgeDirection.java index 61f35ac..8aa7a69 100644 --- a/aai-traversal/src/main/java/org/onap/aai/rest/enums/EdgeDirection.java +++ b/aai-traversal/src/main/java/org/onap/aai/rest/enums/EdgeDirection.java @@ -8,7 +8,7 @@ * 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 + * 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, @@ -20,10 +20,7 @@ package org.onap.aai.rest.enums; public enum EdgeDirection { - OUT(">>"), - IN("<<"), - BOTH(">"); - + OUT(">>"), IN("<<"), BOTH(">"); private final String value; @@ -31,7 +28,6 @@ public enum EdgeDirection { this.value = value; } - public static EdgeDirection fromValue(String value) { for (EdgeDirection d : values()) { @@ -41,8 +37,9 @@ public enum EdgeDirection { } return BOTH; } + @Override public String toString() { return value; } -}
\ No newline at end of file +} diff --git a/aai-traversal/src/main/java/org/onap/aai/rest/enums/QueryVersion.java b/aai-traversal/src/main/java/org/onap/aai/rest/enums/QueryVersion.java index 0e30f28..8ba2faf 100644 --- a/aai-traversal/src/main/java/org/onap/aai/rest/enums/QueryVersion.java +++ b/aai-traversal/src/main/java/org/onap/aai/rest/enums/QueryVersion.java @@ -8,7 +8,7 @@ * 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 + * 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, @@ -20,6 +20,5 @@ package org.onap.aai.rest.enums; public enum QueryVersion { - V1, - V2; -}
\ No newline at end of file + V1, V2; +} diff --git a/aai-traversal/src/main/java/org/onap/aai/rest/search/CQConfig.java b/aai-traversal/src/main/java/org/onap/aai/rest/search/CQConfig.java index d17fb2b..e6f55eb 100644 --- a/aai-traversal/src/main/java/org/onap/aai/rest/search/CQConfig.java +++ b/aai-traversal/src/main/java/org/onap/aai/rest/search/CQConfig.java @@ -8,7 +8,7 @@ * 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 + * 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, @@ -22,7 +22,7 @@ package org.onap.aai.rest.search; public abstract class CQConfig { protected GetCustomQueryConfig queryConfig; - public GetCustomQueryConfig getCustomQueryConfig(){ + public GetCustomQueryConfig getCustomQueryConfig() { return queryConfig; } } diff --git a/aai-traversal/src/main/java/org/onap/aai/rest/search/CustomQueryConfig.java b/aai-traversal/src/main/java/org/onap/aai/rest/search/CustomQueryConfig.java index 2fa7ec1..a7633ca 100644 --- a/aai-traversal/src/main/java/org/onap/aai/rest/search/CustomQueryConfig.java +++ b/aai-traversal/src/main/java/org/onap/aai/rest/search/CustomQueryConfig.java @@ -8,7 +8,7 @@ * 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 + * 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, @@ -22,32 +22,35 @@ package org.onap.aai.rest.search; import java.util.List; public class CustomQueryConfig { - public CustomQueryConfig() { - // used by GetCustomQueryConfig - } - - - private String query; - private List<String> queryOptionalProperties; - private List<String> queryRequiredProperties; - - 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; - } + public CustomQueryConfig() { + // used by GetCustomQueryConfig + } + + private String query; + private List<String> queryOptionalProperties; + private List<String> queryRequiredProperties; + + 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/CustomQueryConfigDTO.java b/aai-traversal/src/main/java/org/onap/aai/rest/search/CustomQueryConfigDTO.java index 30d8d30..7f90566 100644 --- 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 @@ -8,7 +8,7 @@ * 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 + * 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, @@ -39,32 +39,32 @@ package org.onap.aai.rest.search; * ============LICENSE_END========================================================= */ -import org.springframework.util.StringUtils; - import com.fasterxml.jackson.annotation.JsonProperty; +import org.springframework.util.StringUtils; + public class CustomQueryConfigDTO { - @JsonProperty("stored-query") - private String storedQuery; - @JsonProperty("query") - private CustomQueryDTO queryDTO; + @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 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 setQueryDTO(CustomQueryDTO query) { - this.queryDTO = query; - } + public void setStoredQuery(String storedQuery) { + this.storedQuery = storedQuery; + } - 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 index 16b1430..970e5b3 100644 --- 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 @@ -10,7 +10,7 @@ package org.onap.aai.rest.search; * 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 + * 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, @@ -20,37 +20,41 @@ package org.onap.aai.rest.search; * ============LICENSE_END========================================================= */ -import java.util.List; - import com.fasterxml.jackson.annotation.JsonProperty; import com.google.common.collect.Lists; +import java.util.List; + 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; - } + 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 index cdc9d15..b64f07f 100644 --- 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 @@ -8,7 +8,7 @@ * 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 + * 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, @@ -39,83 +39,79 @@ package org.onap.aai.rest.search; * ============LICENSE_END========================================================= */ +import com.beust.jcommander.internal.Maps; +import com.fasterxml.jackson.annotation.JsonProperty; + 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; - } - - + + @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 index 9c4c3b0..cda93fb 100644 --- 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 @@ -8,7 +8,7 @@ * 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 + * 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, @@ -20,20 +20,20 @@ package org.onap.aai.rest.search; -import java.util.List; - import com.fasterxml.jackson.annotation.JsonProperty; +import java.util.List; + public class ExpectedResultsDto { - @JsonProperty("ids") - List<String> ids; + @JsonProperty("ids") + List<String> ids; + + public List<String> getIds() { + return ids; + } - public List<String> getIds() { - return ids; - } + public void setIds(List<String> ids) { + this.ids = ids; + } - public void setIds(List<String> ids) { - this.ids = ids; - } - } diff --git a/aai-traversal/src/main/java/org/onap/aai/rest/search/GenericQueryProcessor.java b/aai-traversal/src/main/java/org/onap/aai/rest/search/GenericQueryProcessor.java index 8e62900..d63b910 100644 --- a/aai-traversal/src/main/java/org/onap/aai/rest/search/GenericQueryProcessor.java +++ b/aai-traversal/src/main/java/org/onap/aai/rest/search/GenericQueryProcessor.java @@ -8,7 +8,7 @@ * 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 + * 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, @@ -19,9 +19,17 @@ */ package org.onap.aai.rest.search; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; import com.att.eelf.configuration.EELFManager; + +import java.io.FileNotFoundException; +import java.net.URI; +import java.util.*; +import java.util.regex.Matcher; +import java.util.regex.Pattern; + +import javax.ws.rs.core.MultivaluedHashMap; +import javax.ws.rs.core.MultivaluedMap; + import org.apache.tinkerpop.gremlin.process.traversal.P; import org.apache.tinkerpop.gremlin.process.traversal.dsl.graph.GraphTraversal; import org.apache.tinkerpop.gremlin.process.traversal.dsl.graph.GraphTraversalSource; @@ -39,422 +47,431 @@ import org.onap.aai.serialization.engines.QueryStyle; import org.onap.aai.serialization.engines.TransactionalGraphEngine; import org.onap.aai.serialization.queryformats.Format; import org.onap.aai.serialization.queryformats.SubGraphStyle; - -import javax.ws.rs.core.MultivaluedHashMap; -import javax.ws.rs.core.MultivaluedMap; -import java.io.FileNotFoundException; -import java.net.URI; -import java.util.*; -import java.util.regex.Matcher; -import java.util.regex.Pattern; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; public abstract class GenericQueryProcessor { - private static Logger LOGGER = LoggerFactory.getLogger(GenericQueryProcessor.class); - - protected final Optional<URI> uri; - protected final MultivaluedMap<String, String> queryParams; - protected final Optional<Collection<Vertex>> vertices; - protected static Pattern p = Pattern.compile("query/(.*+)"); - protected Optional<String> gremlin; - protected final TransactionalGraphEngine dbEngine; - protected GremlinServerSingleton gremlinServerSingleton; - protected GroovyQueryBuilder groovyQueryBuilder = new GroovyQueryBuilder(); - protected final boolean isGremlin; - protected Optional<DslQueryProcessor> dslQueryProcessorOptional; - - public Map<String, List<String>> getPropertiesMap() { - return propertiesList; - } - - public void setPropertiesMap(Map<String, List<String>> propertiesMap) { - this.propertiesList = propertiesMap; - } - - private Map<String, List<String>> propertiesList; - /* dsl parameters to store dsl query and to check - - * if this is a DSL request - */ - protected Optional<String> dsl; - protected final boolean isDsl ; - protected boolean isHistory; - protected GraphTraversalSource traversalSource; - protected QueryStyle style; - protected QueryVersion dslApiVersion; - protected Format format; - - protected GenericQueryProcessor(Builder builder) { - this.uri = builder.getUri(); - this.dbEngine = builder.getDbEngine(); - this.vertices = builder.getVertices(); - this.gremlin = builder.getGremlin(); - this.isGremlin = builder.isGremlin(); - this.dsl = builder.getDsl(); - this.isDsl = builder.isDsl(); - this.gremlinServerSingleton = builder.getGremlinServerSingleton(); - this.dslQueryProcessorOptional = builder.getDslQueryProcessor(); - this.dslApiVersion = builder.getDslApiVersion(); - - if (uri.isPresent()) { - queryParams = URITools.getQueryMap(uri.get()); - } else if (builder.getUriParams() != null) { - queryParams = builder.getUriParams(); - } else { - queryParams = new MultivaluedHashMap<>(); - } - this.traversalSource = builder.getTraversalSource(); - this.style = builder.getStyle(); - this.isHistory = builder.isHistory(); - this.format = builder.getFormat(); - } - - protected abstract GraphTraversal<?,?> runQuery(String query, Map<String, Object> params, GraphTraversalSource traversalSource); - - protected List<Object> processSubGraph(SubGraphStyle style, GraphTraversal<?,?> g) { - final List<Object> resultVertices = new Vector<>(); - g.store("y"); - - if (SubGraphStyle.prune.equals(style) || SubGraphStyle.star.equals(style)) { - g.barrier().bothE(); - if (SubGraphStyle.prune.equals(style)) { - g.where(__.otherV().where(P.within("y"))); - } - g.dedup().subgraph("subGraph").cap("subGraph").map(x -> (Graph)x.get()).next().traversal().V().forEachRemaining(x -> { - resultVertices.add(x); - }); - } else { - resultVertices.addAll(g.toList()); - } - return resultVertices; - } - - public List<Object> execute(SubGraphStyle style) throws FileNotFoundException, AAIException { - final List<Object> resultVertices; - - Pair<String, Map<String, Object>> tuple = this.createQuery(); - String query = tuple.getValue0(); - if (queryParams.containsKey("as-tree")) { - if (queryParams.getFirst("as-tree").equalsIgnoreCase("true")) { - if (this.isDsl) { // If dsl query and as-tree parameter is true, remove "end" concatenation and append tree. - query = removeDslQueryEnd(query); - } - query = query.concat(".tree()"); // Otherwise, normal gremlin query will just append tree - } - } - Map<String, Object> params = tuple.getValue1(); - - if (query.equals("") && (vertices.isPresent() && vertices.get().isEmpty())) { - //nothing to do, just exit - return new ArrayList<>(); - } - GraphTraversal<?,?> g = this.runQuery(query, params, traversalSource); - - resultVertices = this.processSubGraph(style, g); - - return resultVertices; - } - - private String removeDslQueryEnd(String query) { - String end = ".cap('x').unfold().dedup()"; - if (query.length() <= end.length()) { - return query; - } - if (query.contains(end)) { - int startIndex = query.length() - end.length(); - for (int i = 0; startIndex - i >= 0; i++) { // remove tailing instance - startIndex = query.length() - end.length() - i; - int lastIndex = query.length() - i; - if (query.substring(startIndex, lastIndex).equals(end)) { - query = query.substring(0, startIndex) + query.substring(lastIndex); - break; - } - } - } - return query; - } - - protected Pair<String, Map<String, Object>> createQuery() throws AAIException { - Map<String, Object> params = new HashMap<>(); - String query = ""; - if (this.isGremlin) { - query = gremlin.get(); - - }else if (this.isDsl) { - String dslUserQuery = dsl.get(); - if(dslQueryProcessorOptional.isPresent()){ - Map<String, Object>resultMap = dslQueryProcessorOptional.get().parseAaiQuery(dslApiVersion, dslUserQuery); - String dslQuery = resultMap.get("query").toString(); - Object propMap = resultMap.get("propertiesMap"); - if (propMap instanceof Map) { - Map<String, List<String>> newPropMap = new HashMap<String, List<String>>(); - newPropMap = (Map<String, List<String>>)propMap; - setPropertiesMap(newPropMap); - } - query = groovyQueryBuilder.executeTraversal(dbEngine, dslQuery, params, style, traversalSource); - String startPrefix = "g.V()"; - query = startPrefix + query; - } - LOGGER.debug("Converted to gremlin query\n {}", query); - }else { - Matcher m = p.matcher(uri.get().getPath()); - String queryName = ""; - List<String> optionalParameters = Collections.emptyList(); - if (m.find()) { - queryName = m.group(1); - CustomQueryConfig queryConfig = gremlinServerSingleton.getCustomQueryConfig(queryName); - if ( queryConfig != null ) { - query = queryConfig.getQuery(); - optionalParameters = queryConfig.getQueryOptionalProperties(); - } - } - - for (String key : queryParams.keySet()) { - params.put(key, queryParams.getFirst(key)); - if ( optionalParameters.contains(key) ){ - optionalParameters.remove(key); - } - } - - if (!optionalParameters.isEmpty()){ - MissingOptionalParameter missingParameter = MissingOptionalParameter.getInstance(); - for ( String key : optionalParameters ) { - params.put(key, missingParameter); - } - } - - if (vertices.isPresent() && !vertices.get().isEmpty()) { - - // Get the vertices and convert them into object array - // The reason for this was .V() takes in an array of objects - // not a list of objects so that needs to be converted + private static Logger LOGGER = LoggerFactory.getLogger(GenericQueryProcessor.class); + + protected final Optional<URI> uri; + protected final MultivaluedMap<String, String> queryParams; + protected final Optional<Collection<Vertex>> vertices; + protected static Pattern p = Pattern.compile("query/(.*+)"); + protected Optional<String> gremlin; + protected final TransactionalGraphEngine dbEngine; + protected GremlinServerSingleton gremlinServerSingleton; + protected GroovyQueryBuilder groovyQueryBuilder = new GroovyQueryBuilder(); + protected final boolean isGremlin; + protected Optional<DslQueryProcessor> dslQueryProcessorOptional; + + public Map<String, List<String>> getPropertiesMap() { + return propertiesList; + } + + public void setPropertiesMap(Map<String, List<String>> propertiesMap) { + this.propertiesList = propertiesMap; + } + + private Map<String, List<String>> propertiesList; + /* + * dsl parameters to store dsl query and to check + * + * if this is a DSL request + */ + protected Optional<String> dsl; + protected final boolean isDsl; + protected boolean isHistory; + protected GraphTraversalSource traversalSource; + protected QueryStyle style; + protected QueryVersion dslApiVersion; + protected Format format; + + protected GenericQueryProcessor(Builder builder) { + this.uri = builder.getUri(); + this.dbEngine = builder.getDbEngine(); + this.vertices = builder.getVertices(); + this.gremlin = builder.getGremlin(); + this.isGremlin = builder.isGremlin(); + this.dsl = builder.getDsl(); + this.isDsl = builder.isDsl(); + this.gremlinServerSingleton = builder.getGremlinServerSingleton(); + this.dslQueryProcessorOptional = builder.getDslQueryProcessor(); + this.dslApiVersion = builder.getDslApiVersion(); + + if (uri.isPresent()) { + queryParams = URITools.getQueryMap(uri.get()); + } else if (builder.getUriParams() != null) { + queryParams = builder.getUriParams(); + } else { + queryParams = new MultivaluedHashMap<>(); + } + this.traversalSource = builder.getTraversalSource(); + this.style = builder.getStyle(); + this.isHistory = builder.isHistory(); + this.format = builder.getFormat(); + } + + protected abstract GraphTraversal<?, ?> runQuery(String query, Map<String, Object> params, + GraphTraversalSource traversalSource); + + protected List<Object> processSubGraph(SubGraphStyle style, GraphTraversal<?, ?> g) { + final List<Object> resultVertices = new Vector<>(); + g.store("y"); + + if (SubGraphStyle.prune.equals(style) || SubGraphStyle.star.equals(style)) { + g.barrier().bothE(); + if (SubGraphStyle.prune.equals(style)) { + g.where(__.otherV().where(P.within("y"))); + } + g.dedup().subgraph("subGraph").cap("subGraph").map(x -> (Graph) x.get()).next() + .traversal().V().forEachRemaining(x -> { + resultVertices.add(x); + }); + } else { + resultVertices.addAll(g.toList()); + } + return resultVertices; + } + + public List<Object> execute(SubGraphStyle style) throws FileNotFoundException, AAIException { + final List<Object> resultVertices; + + Pair<String, Map<String, Object>> tuple = this.createQuery(); + String query = tuple.getValue0(); + if (queryParams.containsKey("as-tree")) { + if (queryParams.getFirst("as-tree").equalsIgnoreCase("true")) { + if (this.isDsl) { // If dsl query and as-tree parameter is true, remove "end" + // concatenation and append tree. + query = removeDslQueryEnd(query); + } + query = query.concat(".tree()"); // Otherwise, normal gremlin query will just append + // tree + } + } + Map<String, Object> params = tuple.getValue1(); + + if (query.equals("") && (vertices.isPresent() && vertices.get().isEmpty())) { + // nothing to do, just exit + return new ArrayList<>(); + } + GraphTraversal<?, ?> g = this.runQuery(query, params, traversalSource); + + resultVertices = this.processSubGraph(style, g); + + return resultVertices; + } + + private String removeDslQueryEnd(String query) { + String end = ".cap('x').unfold().dedup()"; + if (query.length() <= end.length()) { + return query; + } + if (query.contains(end)) { + int startIndex = query.length() - end.length(); + for (int i = 0; startIndex - i >= 0; i++) { // remove tailing instance + startIndex = query.length() - end.length() - i; + int lastIndex = query.length() - i; + if (query.substring(startIndex, lastIndex).equals(end)) { + query = query.substring(0, startIndex) + query.substring(lastIndex); + break; + } + } + } + return query; + } + + protected Pair<String, Map<String, Object>> createQuery() throws AAIException { + Map<String, Object> params = new HashMap<>(); + String query = ""; + if (this.isGremlin) { + query = gremlin.get(); + + } else if (this.isDsl) { + String dslUserQuery = dsl.get(); + if (dslQueryProcessorOptional.isPresent()) { + Map<String, Object> resultMap = + dslQueryProcessorOptional.get().parseAaiQuery(dslApiVersion, dslUserQuery); + String dslQuery = resultMap.get("query").toString(); + Object propMap = resultMap.get("propertiesMap"); + if (propMap instanceof Map) { + Map<String, List<String>> newPropMap = new HashMap<String, List<String>>(); + newPropMap = (Map<String, List<String>>) propMap; + setPropertiesMap(newPropMap); + } + query = groovyQueryBuilder.executeTraversal(dbEngine, dslQuery, params, style, + traversalSource); + String startPrefix = "g.V()"; + query = startPrefix + query; + } + LOGGER.debug("Converted to gremlin query\n {}", query); + } else { + Matcher m = p.matcher(uri.get().getPath()); + String queryName = ""; + List<String> optionalParameters = Collections.emptyList(); + if (m.find()) { + queryName = m.group(1); + CustomQueryConfig queryConfig = + gremlinServerSingleton.getCustomQueryConfig(queryName); + if (queryConfig != null) { + query = queryConfig.getQuery(); + optionalParameters = queryConfig.getQueryOptionalProperties(); + } + } + + for (String key : queryParams.keySet()) { + params.put(key, queryParams.getFirst(key)); + if (optionalParameters.contains(key)) { + optionalParameters.remove(key); + } + } + + if (!optionalParameters.isEmpty()) { + MissingOptionalParameter missingParameter = MissingOptionalParameter.getInstance(); + for (String key : optionalParameters) { + params.put(key, missingParameter); + } + } + + if (vertices.isPresent() && !vertices.get().isEmpty()) { + + // Get the vertices and convert them into object array + // The reason for this was .V() takes in an array of objects + // not a list of objects so that needs to be converted // Also instead of statically creating the list which is a bad practice - // We are binding the array dynamically to the groovy processor correctly - // This will fix the memory issue of the method size too big - // as statically creating a list string and passing is not appropriate + // We are binding the array dynamically to the groovy processor correctly + // This will fix the memory issue of the method size too big + // as statically creating a list string and passing is not appropriate - Object [] startVertices = vertices.get().toArray(); + Object[] startVertices = vertices.get().toArray(); - params.put("startVertexes", startVertices); + params.put("startVertexes", startVertices); - if (query == null) { - query = ""; - } else { - query = groovyQueryBuilder.executeTraversal(dbEngine, query, params, style, traversalSource); - } + if (query == null) { + query = ""; + } else { + query = groovyQueryBuilder.executeTraversal(dbEngine, query, params, style, + traversalSource); + } - String startPrefix = "g.V(startVertexes)"; + String startPrefix = "g.V(startVertexes)"; - if (!"".equals(query)) { - query = startPrefix + query; - } else { - query = startPrefix; - } + if (!"".equals(query)) { + query = startPrefix + query; + } else { + query = startPrefix; + } - // Getting all the vertices and logging them is not reasonable - // As it could have performance impacts so doing a check here - // to see if the logger is trace so only print the start vertexes - // otherwise we would like to see what the gremlin query that was converted + // Getting all the vertices and logging them is not reasonable + // As it could have performance impacts so doing a check here + // to see if the logger is trace so only print the start vertexes + // otherwise we would like to see what the gremlin query that was converted // So to check if the output matches the desired behavior - // This way if to enable deeper logging, just changing logback would work - if(LOGGER.isTraceEnabled()){ - String readQuery = query.replaceAll("startVertexes", - Arrays.toString(startVertices).replaceAll("[^0-9,]", "")); - LOGGER.trace("Converted to gremlin query including the start vertices \n {}", readQuery); - } - else if(LOGGER.isDebugEnabled()){ - LOGGER.debug("Converted to gremlin query without the start vertices \n {}", query); - } - } else { - throw new AAIException("AAI_6148"); - } - - } - - return new Pair<>(query, params); - } - - public static class Builder { - - private final TransactionalGraphEngine dbEngine; - private Optional<URI> uri = Optional.empty(); - private Optional<String> gremlin = Optional.empty(); - private boolean isGremlin = false; - private Optional<Collection<Vertex>> vertices = Optional.empty(); - private QueryProcessorType processorType = QueryProcessorType.GREMLIN_SERVER; - - private Optional<String> dsl = Optional.empty(); - private boolean isDsl = false; - private DslQueryProcessor dslQueryProcessor; - private GremlinServerSingleton gremlinServerSingleton; - private Optional<String> nodeType = Optional.empty(); - private boolean isNodeTypeQuery = false; - protected MultivaluedMap<String, String> uriParams; - protected GraphTraversalSource traversalSource; - protected boolean isHistory = false; - protected QueryVersion dslApiVersion; - protected Format format; - - - protected QueryStyle style = QueryStyle.GREMLIN_TRAVERSAL; - - public Builder(TransactionalGraphEngine dbEngine, GremlinServerSingleton gremlinServerSingleton) { - this.dbEngine = dbEngine; - this.gremlinServerSingleton = gremlinServerSingleton; - } - - public Builder queryFrom(URI uri) { - this.uri = Optional.of(uri); - this.isGremlin = false; - return this; - } - - public Builder startFrom(Collection<Vertex> vertices) { - this.vertices = Optional.of(vertices); - return this; - } - - public Builder queryFrom( String query, String queryType) { - - if(queryType.equals("gremlin")){ - this.gremlin = Optional.of(query); - this.isGremlin = true; - } - if(queryType.equals("dsl")){ - this.dsl = Optional.of(query); - this.isDsl = true; - } - if(queryType.equals("nodeQuery")){ - this.nodeType = Optional.of(query); - this.isNodeTypeQuery = true; - } - return this; - } - - public Builder uriParams(MultivaluedMap<String, String> uriParams) { - this.uriParams = uriParams; - return this; - } - - public Builder processWith(QueryProcessorType type) { - this.processorType = type; - return this; - } - - public Builder format(Format format) { - this.format = format; - return this; - } - - public Builder traversalSource(boolean isHistory, GraphTraversalSource source) { - this.traversalSource = source; - this.isHistory = isHistory; - if(this.isHistory){ - this.style = QueryStyle.HISTORY_GREMLIN_TRAVERSAL; - } - - return this; - } - - public Builder queryProcessor(DslQueryProcessor dslQueryProcessor){ - this.dslQueryProcessor = dslQueryProcessor; - return this; - } - - public Builder version(QueryVersion version){ - this.dslApiVersion = version; - return this; - } - - public Optional<DslQueryProcessor> getDslQueryProcessor(){ - return Optional.ofNullable(this.dslQueryProcessor); - } - public TransactionalGraphEngine getDbEngine() { - return dbEngine; - } - - public Optional<URI> getUri() { - return uri; - } - - public MultivaluedMap<String, String> getUriParams() { return uriParams; } - - public Optional<String> getGremlin() { - return gremlin; - } - - public boolean isGremlin() { - return isGremlin; - } - - public Optional<String> getDsl() { - return dsl; - } - - public boolean isDsl() { - return isDsl; - } - - public Optional<Collection<Vertex>> getVertices() { - return vertices; - } - - public QueryProcessorType getProcessorType() { - return processorType; - } - - public GremlinServerSingleton getGremlinServerSingleton(){ - return gremlinServerSingleton; - } - - public Optional<String> getNodeType() { - return nodeType; - } - - public boolean isNodeTypeQuery() { - return isNodeTypeQuery; - } - - public GenericQueryProcessor create() { - if (isNodeTypeQuery()) { - return new NodeQueryProcessor(this); - } - return new GroovyShellImpl(this); - } - - public GraphTraversalSource getTraversalSource() { - return traversalSource; - } - - public void setTraversalSource(GraphTraversalSource traversalSource) { - this.traversalSource = traversalSource; - } - - public boolean isHistory() { - return isHistory; - } - - public void setHistory(boolean history) { - isHistory = history; - } - - public QueryStyle getStyle() { - return style; - } - - public void setStyle(QueryStyle style) { - this.style = style; - } - - public QueryVersion getDslApiVersion() { - return dslApiVersion; - } - - public void setDslApiVersion(QueryVersion dslApiVersion) { - this.dslApiVersion = dslApiVersion; - } - - public Format getFormat(){ return this.format; } - - } + // This way if to enable deeper logging, just changing logback would work + if (LOGGER.isTraceEnabled()) { + String readQuery = query.replaceAll("startVertexes", + Arrays.toString(startVertices).replaceAll("[^0-9,]", "")); + LOGGER.trace("Converted to gremlin query including the start vertices \n {}", + readQuery); + } else if (LOGGER.isDebugEnabled()) { + LOGGER.debug("Converted to gremlin query without the start vertices \n {}", + query); + } + } else { + throw new AAIException("AAI_6148"); + } + + } + + return new Pair<>(query, params); + } + + public static class Builder { + + private final TransactionalGraphEngine dbEngine; + private Optional<URI> uri = Optional.empty(); + private Optional<String> gremlin = Optional.empty(); + private boolean isGremlin = false; + private Optional<Collection<Vertex>> vertices = Optional.empty(); + private QueryProcessorType processorType = QueryProcessorType.GREMLIN_SERVER; + + private Optional<String> dsl = Optional.empty(); + private boolean isDsl = false; + private DslQueryProcessor dslQueryProcessor; + private GremlinServerSingleton gremlinServerSingleton; + private Optional<String> nodeType = Optional.empty(); + private boolean isNodeTypeQuery = false; + protected MultivaluedMap<String, String> uriParams; + protected GraphTraversalSource traversalSource; + protected boolean isHistory = false; + protected QueryVersion dslApiVersion; + protected Format format; + + protected QueryStyle style = QueryStyle.GREMLIN_TRAVERSAL; + + public Builder(TransactionalGraphEngine dbEngine, + GremlinServerSingleton gremlinServerSingleton) { + this.dbEngine = dbEngine; + this.gremlinServerSingleton = gremlinServerSingleton; + } + + public Builder queryFrom(URI uri) { + this.uri = Optional.of(uri); + this.isGremlin = false; + return this; + } + + public Builder startFrom(Collection<Vertex> vertices) { + this.vertices = Optional.of(vertices); + return this; + } + + public Builder queryFrom(String query, String queryType) { + + if (queryType.equals("gremlin")) { + this.gremlin = Optional.of(query); + this.isGremlin = true; + } + if (queryType.equals("dsl")) { + this.dsl = Optional.of(query); + this.isDsl = true; + } + if (queryType.equals("nodeQuery")) { + this.nodeType = Optional.of(query); + this.isNodeTypeQuery = true; + } + return this; + } + + public Builder uriParams(MultivaluedMap<String, String> uriParams) { + this.uriParams = uriParams; + return this; + } + + public Builder processWith(QueryProcessorType type) { + this.processorType = type; + return this; + } + + public Builder format(Format format) { + this.format = format; + return this; + } + + public Builder traversalSource(boolean isHistory, GraphTraversalSource source) { + this.traversalSource = source; + this.isHistory = isHistory; + if (this.isHistory) { + this.style = QueryStyle.HISTORY_GREMLIN_TRAVERSAL; + } + + return this; + } + + public Builder queryProcessor(DslQueryProcessor dslQueryProcessor) { + this.dslQueryProcessor = dslQueryProcessor; + return this; + } + + public Builder version(QueryVersion version) { + this.dslApiVersion = version; + return this; + } + + public Optional<DslQueryProcessor> getDslQueryProcessor() { + return Optional.ofNullable(this.dslQueryProcessor); + } + + public TransactionalGraphEngine getDbEngine() { + return dbEngine; + } + + public Optional<URI> getUri() { + return uri; + } + + public MultivaluedMap<String, String> getUriParams() { + return uriParams; + } + + public Optional<String> getGremlin() { + return gremlin; + } + + public boolean isGremlin() { + return isGremlin; + } + + public Optional<String> getDsl() { + return dsl; + } + + public boolean isDsl() { + return isDsl; + } + + public Optional<Collection<Vertex>> getVertices() { + return vertices; + } + + public QueryProcessorType getProcessorType() { + return processorType; + } + + public GremlinServerSingleton getGremlinServerSingleton() { + return gremlinServerSingleton; + } + + public Optional<String> getNodeType() { + return nodeType; + } + + public boolean isNodeTypeQuery() { + return isNodeTypeQuery; + } + + public GenericQueryProcessor create() { + if (isNodeTypeQuery()) { + return new NodeQueryProcessor(this); + } + return new GroovyShellImpl(this); + } + + public GraphTraversalSource getTraversalSource() { + return traversalSource; + } + + public void setTraversalSource(GraphTraversalSource traversalSource) { + this.traversalSource = traversalSource; + } + + public boolean isHistory() { + return isHistory; + } + + public void setHistory(boolean history) { + isHistory = history; + } + + public QueryStyle getStyle() { + return style; + } + + public void setStyle(QueryStyle style) { + this.style = style; + } + + public QueryVersion getDslApiVersion() { + return dslApiVersion; + } + + public void setDslApiVersion(QueryVersion dslApiVersion) { + this.dslApiVersion = dslApiVersion; + } + + public Format getFormat() { + return this.format; + } + + } } diff --git a/aai-traversal/src/main/java/org/onap/aai/rest/search/GetCustomQueryConfig.java b/aai-traversal/src/main/java/org/onap/aai/rest/search/GetCustomQueryConfig.java index 76ecd20..98eb551 100644 --- a/aai-traversal/src/main/java/org/onap/aai/rest/search/GetCustomQueryConfig.java +++ b/aai-traversal/src/main/java/org/onap/aai/rest/search/GetCustomQueryConfig.java @@ -8,7 +8,7 @@ * 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 + * 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, @@ -19,11 +19,6 @@ */ package org.onap.aai.rest.search; -import java.lang.reflect.Type; -import java.util.ArrayList; -import java.util.List; - - import com.google.gson.Gson; import com.google.gson.JsonArray; import com.google.gson.JsonElement; @@ -31,108 +26,108 @@ import com.google.gson.JsonObject; import com.google.gson.JsonParser; import com.google.gson.reflect.TypeToken; +import java.lang.reflect.Type; +import java.util.ArrayList; +import java.util.List; + public class GetCustomQueryConfig { - private JsonArray storedQueries = null; - private CustomQueryConfig customQueryConfig; - - - private static final String QUERY_CONFIG = "query"; - private static final String REQUIRED_CONFIG = "required-properties"; - private static final String OPTIONAL_CONFIG = "optional-properties"; - private static final String STORED_QUERIES_CONFIG = "stored-queries"; - private static final String STORED_QUERY_CONFIG = "stored-query"; - - public GetCustomQueryConfig(String customQueryJson ) { - init(customQueryJson); - } - - private void init( String customQueryJson) { - JsonParser parser = new JsonParser(); - JsonObject queriesObject = parser.parse(customQueryJson).getAsJsonObject(); - if (queriesObject.has(STORED_QUERIES_CONFIG)) { - - storedQueries = queriesObject.getAsJsonArray(STORED_QUERIES_CONFIG); - } - } - - private List<String> toStringList(JsonArray array) { - Gson converter = new Gson(); - Type listType = new TypeToken<List<String>>() {}.getType(); - return converter.fromJson(array, listType); - } - - private List<String> getPropertyList(JsonObject configObject, String config ) { - JsonElement subqueryConfig; - JsonArray props; - - if ( configObject.has(config)) { - subqueryConfig = configObject.get(config); - if ( subqueryConfig != null && !subqueryConfig.isJsonNull() ) { - props = subqueryConfig.getAsJsonArray(); - if ( props != null ) { - return toStringList(props); - } - } - } - return toStringList(null); - } - - private void getStoredQueryBlock( JsonObject configObject, String config ) { - if ( !configObject.has(config)) { - customQueryConfig.setQueryRequiredProperties( new ArrayList<>() ); - customQueryConfig.setQueryOptionalProperties( new ArrayList<>() ); - return; - } - - JsonElement queryConfig; - JsonObject subObject; - List<String> propertyList; - - queryConfig = configObject.get(config); - subObject = queryConfig.getAsJsonObject(); - propertyList = getPropertyList(subObject, REQUIRED_CONFIG); - if ( propertyList == null ) { - propertyList = new ArrayList<>(); - } - customQueryConfig.setQueryRequiredProperties( propertyList ); - propertyList = getPropertyList(subObject, OPTIONAL_CONFIG); - if ( propertyList == null ) { - propertyList = new ArrayList<>(); - } - customQueryConfig.setQueryOptionalProperties( propertyList ); - - } - - - public CustomQueryConfig getStoredQuery(String queryName ) { - - customQueryConfig = null; - JsonObject configObject; - JsonElement query; - JsonElement queryConfig; - - for (JsonElement storedQuery : storedQueries) { - if (storedQuery.isJsonObject()) { - JsonObject queryObject = storedQuery.getAsJsonObject(); - query = queryObject.get(queryName); - if ( query != null ) { - customQueryConfig = new CustomQueryConfig(); - configObject = query.getAsJsonObject(); - getStoredQueryBlock(configObject, QUERY_CONFIG); - if ( configObject.has(STORED_QUERY_CONFIG)) { - queryConfig = configObject.get(STORED_QUERY_CONFIG); - customQueryConfig.setQuery(queryConfig.getAsString()); - } - break; - } - } - } - - return customQueryConfig; - - } + private JsonArray storedQueries = null; + private CustomQueryConfig customQueryConfig; + + private static final String QUERY_CONFIG = "query"; + private static final String REQUIRED_CONFIG = "required-properties"; + private static final String OPTIONAL_CONFIG = "optional-properties"; + private static final String STORED_QUERIES_CONFIG = "stored-queries"; + private static final String STORED_QUERY_CONFIG = "stored-query"; + + public GetCustomQueryConfig(String customQueryJson) { + init(customQueryJson); + } + + private void init(String customQueryJson) { + JsonParser parser = new JsonParser(); + JsonObject queriesObject = parser.parse(customQueryJson).getAsJsonObject(); + if (queriesObject.has(STORED_QUERIES_CONFIG)) { + + storedQueries = queriesObject.getAsJsonArray(STORED_QUERIES_CONFIG); + } + } + + private List<String> toStringList(JsonArray array) { + Gson converter = new Gson(); + Type listType = new TypeToken<List<String>>() {}.getType(); + return converter.fromJson(array, listType); + } + + private List<String> getPropertyList(JsonObject configObject, String config) { + JsonElement subqueryConfig; + JsonArray props; + + if (configObject.has(config)) { + subqueryConfig = configObject.get(config); + if (subqueryConfig != null && !subqueryConfig.isJsonNull()) { + props = subqueryConfig.getAsJsonArray(); + if (props != null) { + return toStringList(props); + } + } + } + return toStringList(null); + } + + private void getStoredQueryBlock(JsonObject configObject, String config) { + if (!configObject.has(config)) { + customQueryConfig.setQueryRequiredProperties(new ArrayList<>()); + customQueryConfig.setQueryOptionalProperties(new ArrayList<>()); + return; + } + + JsonElement queryConfig; + JsonObject subObject; + List<String> propertyList; + + queryConfig = configObject.get(config); + subObject = queryConfig.getAsJsonObject(); + propertyList = getPropertyList(subObject, REQUIRED_CONFIG); + if (propertyList == null) { + propertyList = new ArrayList<>(); + } + customQueryConfig.setQueryRequiredProperties(propertyList); + propertyList = getPropertyList(subObject, OPTIONAL_CONFIG); + if (propertyList == null) { + propertyList = new ArrayList<>(); + } + customQueryConfig.setQueryOptionalProperties(propertyList); + + } + + public CustomQueryConfig getStoredQuery(String queryName) { + + customQueryConfig = null; + JsonObject configObject; + JsonElement query; + JsonElement queryConfig; + + for (JsonElement storedQuery : storedQueries) { + if (storedQuery.isJsonObject()) { + JsonObject queryObject = storedQuery.getAsJsonObject(); + query = queryObject.get(queryName); + if (query != null) { + customQueryConfig = new CustomQueryConfig(); + configObject = query.getAsJsonObject(); + getStoredQueryBlock(configObject, QUERY_CONFIG); + if (configObject.has(STORED_QUERY_CONFIG)) { + queryConfig = configObject.get(STORED_QUERY_CONFIG); + customQueryConfig.setQuery(queryConfig.getAsString()); + } + break; + } + } + } + return customQueryConfig; + } } diff --git a/aai-traversal/src/main/java/org/onap/aai/rest/search/GremlinServerSingleton.java b/aai-traversal/src/main/java/org/onap/aai/rest/search/GremlinServerSingleton.java index e30f13f..a3bb074 100644 --- a/aai-traversal/src/main/java/org/onap/aai/rest/search/GremlinServerSingleton.java +++ b/aai-traversal/src/main/java/org/onap/aai/rest/search/GremlinServerSingleton.java @@ -8,7 +8,7 @@ * 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 + * 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, @@ -19,16 +19,8 @@ */ package org.onap.aai.rest.search; -import org.onap.aai.logging.LogFormatTools; -import org.onap.aai.util.AAIConstants; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; import com.att.eelf.configuration.EELFManager; -import org.apache.tinkerpop.gremlin.driver.Cluster; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.beans.factory.annotation.Value; -import javax.annotation.PostConstruct; import java.io.File; import java.io.FileInputStream; import java.io.FileNotFoundException; @@ -41,6 +33,16 @@ import java.util.Properties; import java.util.Timer; import java.util.TimerTask; +import javax.annotation.PostConstruct; + +import org.apache.tinkerpop.gremlin.driver.Cluster; +import org.onap.aai.logging.LogFormatTools; +import org.onap.aai.util.AAIConstants; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.beans.factory.annotation.Value; + public class GremlinServerSingleton { private static Logger logger = LoggerFactory.getLogger(GremlinServerSingleton.class); @@ -48,8 +50,8 @@ public class GremlinServerSingleton { private boolean timerSet; private Timer timer; - CQConfig customQueryInfo; + /** * Initializes the gremlin server singleton * Loads the configuration of the gremlin server and creates a cluster @@ -60,29 +62,29 @@ public class GremlinServerSingleton { * */ @Autowired - public GremlinServerSingleton(CQConfig customQueryInfo){ - this.customQueryInfo = customQueryInfo; + public GremlinServerSingleton(CQConfig customQueryInfo) { + this.customQueryInfo = customQueryInfo; } /** * Gets the query using CustomQueryConfig + * * @param key * @return */ - public String getStoredQueryFromConfig(String key){ + public String getStoredQueryFromConfig(String key) { GetCustomQueryConfig queryConfig = customQueryInfo.getCustomQueryConfig(); - CustomQueryConfig customQueryConfig = queryConfig.getStoredQuery(key); - if ( customQueryConfig == null ) { - return null; - } - return customQueryConfig.getQuery(); + CustomQueryConfig customQueryConfig = queryConfig.getStoredQuery(key); + if (customQueryConfig == null) { + return null; + } + return customQueryConfig.getQuery(); } - + public CustomQueryConfig getCustomQueryConfig(String key) { GetCustomQueryConfig queryConfig = customQueryInfo.getCustomQueryConfig(); - return queryConfig.getStoredQuery(key); + return queryConfig.getStoredQuery(key); } - } diff --git a/aai-traversal/src/main/java/org/onap/aai/rest/search/GroovyShellImpl.java b/aai-traversal/src/main/java/org/onap/aai/rest/search/GroovyShellImpl.java index 340c525..126d754 100644 --- a/aai-traversal/src/main/java/org/onap/aai/rest/search/GroovyShellImpl.java +++ b/aai-traversal/src/main/java/org/onap/aai/rest/search/GroovyShellImpl.java @@ -8,7 +8,7 @@ * 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 + * 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, @@ -21,36 +21,35 @@ package org.onap.aai.rest.search; import java.util.Map; -import org.apache.tinkerpop.gremlin.process.traversal.dsl.graph.GraphTraversal; +import javax.ws.rs.core.MultivaluedHashMap; +import org.apache.tinkerpop.gremlin.process.traversal.dsl.graph.GraphTraversal; import org.apache.tinkerpop.gremlin.process.traversal.dsl.graph.GraphTraversalSource; import org.onap.aai.aailog.logs.AaiDBTraversalMetricLog; import org.onap.aai.restcore.search.GremlinGroovyShell; import org.onap.aai.restcore.util.URITools; import org.onap.aai.util.AAIConstants; -import javax.ws.rs.core.MultivaluedHashMap; - public class GroovyShellImpl extends GenericQueryProcessor { - protected GroovyShellImpl(Builder builder) { - super(builder); - } - - @Override - protected GraphTraversal<?,?> runQuery(String query, Map<String, Object> params, GraphTraversalSource traversalSource) { + protected GroovyShellImpl(Builder builder) { + super(builder); + } - AaiDBTraversalMetricLog metricLog = new AaiDBTraversalMetricLog (AAIConstants.AAI_TRAVERSAL_MS); - metricLog.pre(uri); + @Override + protected GraphTraversal<?, ?> runQuery(String query, Map<String, Object> params, + GraphTraversalSource traversalSource) { - params.put("g", traversalSource); - GremlinGroovyShell shell = new GremlinGroovyShell(); - GraphTraversal<?,?> graphTraversal = shell.executeTraversal(query, params); + AaiDBTraversalMetricLog metricLog = + new AaiDBTraversalMetricLog(AAIConstants.AAI_TRAVERSAL_MS); + metricLog.pre(uri); - metricLog.post(); - return graphTraversal; - } - -} + params.put("g", traversalSource); + GremlinGroovyShell shell = new GremlinGroovyShell(); + GraphTraversal<?, ?> graphTraversal = shell.executeTraversal(query, params); + metricLog.post(); + return graphTraversal; + } +} diff --git a/aai-traversal/src/main/java/org/onap/aai/rest/search/LocalCQConfig.java b/aai-traversal/src/main/java/org/onap/aai/rest/search/LocalCQConfig.java index 42d88af..ebf49d7 100644 --- a/aai-traversal/src/main/java/org/onap/aai/rest/search/LocalCQConfig.java +++ b/aai-traversal/src/main/java/org/onap/aai/rest/search/LocalCQConfig.java @@ -8,7 +8,7 @@ * 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 + * 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, @@ -19,16 +19,8 @@ */ package org.onap.aai.rest.search; -import org.onap.aai.exceptions.AAIException; -import org.onap.aai.logging.ErrorLogHelper; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; import com.att.eelf.configuration.EELFManager; -import org.onap.aai.logging.LogFormatTools; -import org.onap.aai.util.AAIConstants; -import org.springframework.beans.factory.annotation.Value; -import javax.annotation.PostConstruct; import java.io.File; import java.io.IOException; import java.nio.file.Files; @@ -38,6 +30,16 @@ import java.util.Date; import java.util.Timer; import java.util.TimerTask; +import javax.annotation.PostConstruct; + +import org.onap.aai.exceptions.AAIException; +import org.onap.aai.logging.ErrorLogHelper; +import org.onap.aai.logging.LogFormatTools; +import org.onap.aai.util.AAIConstants; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.beans.factory.annotation.Value; + public class LocalCQConfig extends CQConfig { private static Logger logger = LoggerFactory.getLogger(LocalCQConfig.class); @@ -51,7 +53,8 @@ public class LocalCQConfig extends CQConfig { public void init() { try { - String filepath = storedQueriesLocation + AAIConstants.AAI_FILESEP + "stored-queries.json"; + String filepath = + storedQueriesLocation + AAIConstants.AAI_FILESEP + "stored-queries.json"; logger.info("Using the Local stored queries"); Path path = Paths.get(filepath); String customQueryConfigJson = new String(Files.readAllBytes(path)); @@ -60,7 +63,8 @@ public class LocalCQConfig extends CQConfig { } catch (IOException e) { AAIException aaiException = new AAIException("AAI_4002", e); ErrorLogHelper.logException(aaiException); - //logger.error("Error occurred during the processing of query json file: " + LogFormatTools.getStackTop(e)); + // logger.error("Error occurred during the processing of query json file: " + + // LogFormatTools.getStackTop(e)); } TimerTask task = new FileWatcher(new File(storedQueriesLocation)) { @@ -75,7 +79,8 @@ public class LocalCQConfig extends CQConfig { } catch (IOException e) { AAIException aaiException = new AAIException("AAI_4002", e); ErrorLogHelper.logException(aaiException); - //logger.error("Error occurred during the processing of query json file: " + LogFormatTools.getStackTop(e)); + // logger.error("Error occurred during the processing of query json file: " + + // LogFormatTools.getStackTop(e)); } } }; diff --git a/aai-traversal/src/main/java/org/onap/aai/rest/search/ModelAndNamedQueryRestProvider.java b/aai-traversal/src/main/java/org/onap/aai/rest/search/ModelAndNamedQueryRestProvider.java index 821cb09..5c8b055 100644 --- a/aai-traversal/src/main/java/org/onap/aai/rest/search/ModelAndNamedQueryRestProvider.java +++ b/aai-traversal/src/main/java/org/onap/aai/rest/search/ModelAndNamedQueryRestProvider.java @@ -8,7 +8,7 @@ * 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 + * 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, @@ -19,12 +19,23 @@ */ package org.onap.aai.rest.search; +import java.net.URI; +import java.util.ArrayList; +import java.util.Optional; + +import javax.servlet.http.HttpServletRequest; +import javax.ws.rs.POST; +import javax.ws.rs.Path; +import javax.ws.rs.Produces; +import javax.ws.rs.QueryParam; +import javax.ws.rs.core.*; +import javax.ws.rs.core.Response.Status; + import org.onap.aai.aailog.logs.AaiDBTraversalMetricLog; import org.onap.aai.concurrent.AaiCallable; import org.onap.aai.dbgraphmap.SearchGraph; import org.onap.aai.exceptions.AAIException; import org.onap.aai.logging.ErrorLogHelper; - import org.onap.aai.rest.util.AAIExtensionMap; import org.onap.aai.restcore.HttpMethod; import org.onap.aai.restcore.RESTAPI; @@ -35,17 +46,6 @@ import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.beans.factory.annotation.Autowired; -import javax.servlet.http.HttpServletRequest; -import javax.ws.rs.POST; -import javax.ws.rs.Path; -import javax.ws.rs.Produces; -import javax.ws.rs.QueryParam; -import javax.ws.rs.core.*; -import javax.ws.rs.core.Response.Status; -import java.net.URI; -import java.util.ArrayList; -import java.util.Optional; - /** * Implements the search subdomain in the REST API. All API calls must include * X-FromAppId and X-TransactionId in the header. @@ -54,213 +54,199 @@ import java.util.Optional; @Path("/search") public class ModelAndNamedQueryRestProvider extends RESTAPI { - private static final Logger LOGGER = LoggerFactory.getLogger(ModelAndNamedQueryRestProvider.class); - - public static final String NAMED_QUERY = "/named-query"; - - public static final String MODEL_QUERY = "/model"; - - - private SearchGraph searchGraph; - - private SchemaVersions schemaVersions; - - @Autowired - public ModelAndNamedQueryRestProvider(SearchGraph searchGraph, SchemaVersions schemaVersions){ - this.searchGraph = searchGraph; - this.schemaVersions = schemaVersions; - } - - /** - * Gets the named query response. - * - * @param headers the headers - * @param req the req - * @param queryParameters the query parameters - * @return the named query response - */ - /* ---------------- Start Named Query --------------------- */ - @POST - @Produces({ MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML }) - @Path(NAMED_QUERY) - public Response getNamedQueryResponse(@Context HttpHeaders headers, - @Context HttpServletRequest req, - String queryParameters, - @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<Response>() { - @Override - public Response process() { - return processNamedQueryResponse(headers, req, queryParameters); - } - } - ); - } - - public Response processNamedQueryResponse(@Context HttpHeaders headers, - @Context HttpServletRequest req, - String queryParameters) { - AAIException ex = null; - Response response; - String fromAppId; - String transId; - - ArrayList<String> templateVars = new ArrayList<>(); - try { - fromAppId = getFromAppId(headers); - transId = getTransId(headers); - - AAIExtensionMap aaiExtMap = new AAIExtensionMap(); - aaiExtMap.setHttpHeaders(headers); - aaiExtMap.setServletRequest(req); - aaiExtMap.setApiVersion(schemaVersions.getDefaultVersion().toString()); - //only consider header value for search - - - AaiDBTraversalMetricLog metricLog = new AaiDBTraversalMetricLog (AAIConstants.AAI_TRAVERSAL_MS); - String uriString = req.getRequestURI(); - Optional<URI> o; - if (uriString != null) { - o = Optional.of(new URI(uriString)); - } - else { - o = Optional.empty(); - } - metricLog.pre(o); - - response = searchGraph.runNamedQuery(fromAppId, transId, queryParameters, aaiExtMap); - metricLog.post(); - - } catch (AAIException e) { - // send error response - ex = e; - templateVars.add("POST Search"); - templateVars.add("getNamedQueryResponse"); - response = Response - .status(e.getErrorObject().getHTTPResponseCode()) - .entity(ErrorLogHelper.getRESTAPIErrorResponse(headers.getAcceptableMediaTypes(), e, templateVars)) - .build(); - } catch (Exception e) { - // send error response - ex = new AAIException("AAI_4000", e); - templateVars.add("POST Search"); - templateVars.add("getNamedQueryResponse"); - response = Response - .status(Status.INTERNAL_SERVER_ERROR) - .entity(ErrorLogHelper.getRESTAPIErrorResponse(headers.getAcceptableMediaTypes(), ex, templateVars)) - .build(); - } finally { - // log success or failure - if (ex != null) { - ErrorLogHelper.logException(ex); - } - } - return response; - } - - /** - * Gets the model query response. - * - * @param headers the headers - * @param req the req - * @param inboundPayload the inbound payload - * @param action the action - * @return the model query response - */ - /* ---------------- Start Named Query --------------------- */ - @POST - @Produces({ MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML }) - @Path(MODEL_QUERY) - public Response getModelQueryResponse(@Context HttpHeaders headers, - @Context HttpServletRequest req, - String inboundPayload, - @QueryParam("action") String action, - @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<Response>() { - @Override - public Response process() { - return processModelQueryResponse(headers, req, inboundPayload, action); - } - } - ); - } - - public Response processModelQueryResponse(@Context HttpHeaders headers, - @Context HttpServletRequest req, - String inboundPayload, - @QueryParam("action") String action) { - AAIException ex = null; - Response response; - String fromAppId; - String transId; - ArrayList<String> templateVars = new ArrayList<>(); - try { - fromAppId = getFromAppId(headers); - transId = getTransId(headers); - - AAIExtensionMap aaiExtMap = new AAIExtensionMap(); - aaiExtMap.setHttpHeaders(headers); - aaiExtMap.setServletRequest(req); - aaiExtMap.setApiVersion(schemaVersions.getDefaultVersion().toString()); - aaiExtMap.setFromAppId(fromAppId); - aaiExtMap.setTransId(transId); - - //only consider header value for search - - - AaiDBTraversalMetricLog metricLog = new AaiDBTraversalMetricLog (AAIConstants.AAI_TRAVERSAL_MS); - String uriString = req.getRequestURI(); - Optional<URI> o; - if (uriString != null) { - o = Optional.of(new URI(uriString)); - } - else { - o = Optional.empty(); - } - metricLog.pre(o); - if (action != null && action.equalsIgnoreCase("DELETE")) { - response = searchGraph.executeModelOperation(fromAppId, transId, inboundPayload, true, aaiExtMap); - } else { - response = searchGraph.executeModelOperation(fromAppId, transId, inboundPayload, false, aaiExtMap); - } - metricLog.post(); - - } catch (AAIException e) { - // send error response - ex = e; - templateVars.add("POST Search"); - templateVars.add("getModelQueryResponse"); - response = Response - .status(e.getErrorObject().getHTTPResponseCode()) - .entity(ErrorLogHelper.getRESTAPIErrorResponse(headers.getAcceptableMediaTypes(), e, templateVars)) - .build(); - } catch (Exception e) { - // send error response - ex = new AAIException("AAI_4000", e); - templateVars.add("POST Search"); - templateVars.add("getModelQueryResponse"); - response = Response - .status(Status.INTERNAL_SERVER_ERROR) - .entity(ErrorLogHelper.getRESTAPIErrorResponse(headers.getAcceptableMediaTypes(), ex, templateVars)) - .build(); - } finally { - // log success or failure - if (ex != null) { - ErrorLogHelper.logException(ex); - } - } - return response; - } + private static final Logger LOGGER = + LoggerFactory.getLogger(ModelAndNamedQueryRestProvider.class); + + public static final String NAMED_QUERY = "/named-query"; + + public static final String MODEL_QUERY = "/model"; + + private SearchGraph searchGraph; + + private SchemaVersions schemaVersions; + + @Autowired + public ModelAndNamedQueryRestProvider(SearchGraph searchGraph, SchemaVersions schemaVersions) { + this.searchGraph = searchGraph; + this.schemaVersions = schemaVersions; + } + + /** + * Gets the named query response. + * + * @param headers the headers + * @param req the req + * @param queryParameters the query parameters + * @return the named query response + */ + /* ---------------- Start Named Query --------------------- */ + @POST + @Produces({MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML}) + @Path(NAMED_QUERY) + public Response getNamedQueryResponse(@Context HttpHeaders headers, + @Context HttpServletRequest req, String queryParameters, @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<Response>() { + @Override + public Response process() { + return processNamedQueryResponse(headers, req, queryParameters); + } + }); + } + + public Response processNamedQueryResponse(@Context HttpHeaders headers, + @Context HttpServletRequest req, String queryParameters) { + AAIException ex = null; + Response response; + String fromAppId; + String transId; + + ArrayList<String> templateVars = new ArrayList<>(); + try { + fromAppId = getFromAppId(headers); + transId = getTransId(headers); + + AAIExtensionMap aaiExtMap = new AAIExtensionMap(); + aaiExtMap.setHttpHeaders(headers); + aaiExtMap.setServletRequest(req); + aaiExtMap.setApiVersion(schemaVersions.getDefaultVersion().toString()); + // only consider header value for search + + AaiDBTraversalMetricLog metricLog = + new AaiDBTraversalMetricLog(AAIConstants.AAI_TRAVERSAL_MS); + String uriString = req.getRequestURI(); + Optional<URI> o; + if (uriString != null) { + o = Optional.of(new URI(uriString)); + } else { + o = Optional.empty(); + } + metricLog.pre(o); + + response = searchGraph.runNamedQuery(fromAppId, transId, queryParameters, aaiExtMap); + metricLog.post(); + + } catch (AAIException e) { + // send error response + ex = e; + templateVars.add("POST Search"); + templateVars.add("getNamedQueryResponse"); + response = Response + .status(e.getErrorObject().getHTTPResponseCode()).entity(ErrorLogHelper + .getRESTAPIErrorResponse(headers.getAcceptableMediaTypes(), e, templateVars)) + .build(); + } catch (Exception e) { + // send error response + ex = new AAIException("AAI_4000", e); + templateVars.add("POST Search"); + templateVars.add("getNamedQueryResponse"); + response = Response + .status(Status.INTERNAL_SERVER_ERROR).entity(ErrorLogHelper + .getRESTAPIErrorResponse(headers.getAcceptableMediaTypes(), ex, templateVars)) + .build(); + } finally { + // log success or failure + if (ex != null) { + ErrorLogHelper.logException(ex); + } + } + return response; + } + + /** + * Gets the model query response. + * + * @param headers the headers + * @param req the req + * @param inboundPayload the inbound payload + * @param action the action + * @return the model query response + */ + /* ---------------- Start Named Query --------------------- */ + @POST + @Produces({MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML}) + @Path(MODEL_QUERY) + public Response getModelQueryResponse(@Context HttpHeaders headers, + @Context HttpServletRequest req, String inboundPayload, @QueryParam("action") String action, + @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<Response>() { + @Override + public Response process() { + return processModelQueryResponse(headers, req, inboundPayload, action); + } + }); + } + + public Response processModelQueryResponse(@Context HttpHeaders headers, + @Context HttpServletRequest req, String inboundPayload, + @QueryParam("action") String action) { + AAIException ex = null; + Response response; + String fromAppId; + String transId; + ArrayList<String> templateVars = new ArrayList<>(); + try { + fromAppId = getFromAppId(headers); + transId = getTransId(headers); + + AAIExtensionMap aaiExtMap = new AAIExtensionMap(); + aaiExtMap.setHttpHeaders(headers); + aaiExtMap.setServletRequest(req); + aaiExtMap.setApiVersion(schemaVersions.getDefaultVersion().toString()); + aaiExtMap.setFromAppId(fromAppId); + aaiExtMap.setTransId(transId); + + // only consider header value for search + + AaiDBTraversalMetricLog metricLog = + new AaiDBTraversalMetricLog(AAIConstants.AAI_TRAVERSAL_MS); + String uriString = req.getRequestURI(); + Optional<URI> o; + if (uriString != null) { + o = Optional.of(new URI(uriString)); + } else { + o = Optional.empty(); + } + metricLog.pre(o); + if (action != null && action.equalsIgnoreCase("DELETE")) { + response = searchGraph.executeModelOperation(fromAppId, transId, inboundPayload, + true, aaiExtMap); + } else { + response = searchGraph.executeModelOperation(fromAppId, transId, inboundPayload, + false, aaiExtMap); + } + metricLog.post(); + + } catch (AAIException e) { + // send error response + ex = e; + templateVars.add("POST Search"); + templateVars.add("getModelQueryResponse"); + response = Response + .status(e.getErrorObject().getHTTPResponseCode()).entity(ErrorLogHelper + .getRESTAPIErrorResponse(headers.getAcceptableMediaTypes(), e, templateVars)) + .build(); + } catch (Exception e) { + // send error response + ex = new AAIException("AAI_4000", e); + templateVars.add("POST Search"); + templateVars.add("getModelQueryResponse"); + response = Response + .status(Status.INTERNAL_SERVER_ERROR).entity(ErrorLogHelper + .getRESTAPIErrorResponse(headers.getAcceptableMediaTypes(), ex, templateVars)) + .build(); + } finally { + // log success or failure + if (ex != null) { + ErrorLogHelper.logException(ex); + } + } + return response; + } } diff --git a/aai-traversal/src/main/java/org/onap/aai/rest/search/NodeQueryProcessor.java b/aai-traversal/src/main/java/org/onap/aai/rest/search/NodeQueryProcessor.java index 366e7df..fc3847e 100644 --- a/aai-traversal/src/main/java/org/onap/aai/rest/search/NodeQueryProcessor.java +++ b/aai-traversal/src/main/java/org/onap/aai/rest/search/NodeQueryProcessor.java @@ -8,7 +8,7 @@ * 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 + * 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, @@ -19,11 +19,15 @@ */ package org.onap.aai.rest.search; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - import edu.emory.mathcs.backport.java.util.concurrent.TimeUnit; +import java.io.FileNotFoundException; +import java.util.*; +import java.util.regex.Pattern; + +import javax.ws.rs.core.MultivaluedHashMap; +import javax.ws.rs.core.MultivaluedMap; + import org.apache.tinkerpop.gremlin.process.traversal.dsl.graph.GraphTraversal; import org.apache.tinkerpop.gremlin.structure.Vertex; import org.javatuples.Pair; @@ -31,87 +35,84 @@ import org.onap.aai.exceptions.AAIException; import org.onap.aai.restcore.search.GroovyQueryBuilder; import org.onap.aai.serialization.engines.TransactionalGraphEngine; import org.onap.aai.serialization.queryformats.SubGraphStyle; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; -import java.io.FileNotFoundException; -import java.util.*; -import java.util.regex.Pattern; +public class NodeQueryProcessor extends GroovyShellImpl { -import javax.ws.rs.core.MultivaluedHashMap; -import javax.ws.rs.core.MultivaluedMap; + private static Logger logger = LoggerFactory.getLogger(NodeQueryProcessor.class); -public class NodeQueryProcessor extends GroovyShellImpl { + protected String nodeType; + private MultivaluedMap<String, String> nodeQueryParams = new MultivaluedHashMap<>(); + protected final Optional<Collection<Vertex>> vertices; + protected static Pattern p = Pattern.compile("query/(.*+)"); + protected Optional<String> gremlin; + protected final TransactionalGraphEngine dbEngine; + protected GroovyQueryBuilder queryBuilder = new GroovyQueryBuilder(); + + protected NodeQueryProcessor(Builder builder) { + super(builder); + this.nodeQueryParams = builder.uriParams; + if (builder.getNodeType().isPresent()) { + this.nodeType = builder.getNodeType().get(); + } + this.dbEngine = builder.getDbEngine(); + this.vertices = builder.getVertices(); + + } + + public Pair<String, Map<String, Object>> createQuery() throws AAIException { + Map<String, Object> params = new HashMap<>(); + + Long timeNowInMilliSecs = System.currentTimeMillis(); + Long startTime = 0L; + if (nodeQueryParams.containsKey("hours")) { + Long hoursInMilliSec = + TimeUnit.HOURS.toMillis(Long.parseLong(nodeQueryParams.getFirst("hours"))); + startTime = timeNowInMilliSecs - hoursInMilliSec; + } else if (nodeQueryParams.containsKey("date-time")) { + Long dateTime = Long.parseLong(nodeQueryParams.getFirst("date-time")); + startTime = dateTime; + } + + String query = "builder.getVerticesByProperty('aai-node-type', nodeType)" + + ".or(builder.newInstance().getVerticesGreaterThanProperty('aai-created-ts',startTime)," + + " builder.newInstance().getVerticesGreaterThanProperty('aai-last-mod-ts',startTime)" + + ")"; + + params.put("startTime", startTime); + params.put("nodeType", nodeType); + + query = queryBuilder.executeTraversal(dbEngine, query, params); + + String startPrefix = "g.V()"; + + query = startPrefix + query; + + if (logger.isDebugEnabled()) { + logger.debug("Converted to gremlin query without the start vertices \n {}", query); + } + + return new Pair<>(query, params); + } + + public List<Object> execute(SubGraphStyle style) throws FileNotFoundException, AAIException { + final List<Object> resultVertices = new Vector<>(); + + Pair<String, Map<String, Object>> tuple = this.createQuery(); + String query = tuple.getValue0(); + Map<String, Object> params = tuple.getValue1(); + + if (query.equals("")) { + // nothing to do, just exit + return new ArrayList<>(); + } + GraphTraversal<?, ?> g = + this.runQuery(query, params, dbEngine.asAdmin().getTraversalSource()); + + resultVertices.addAll(g.toList()); - private static Logger logger = LoggerFactory.getLogger(NodeQueryProcessor.class); - - protected String nodeType; - private MultivaluedMap<String, String> nodeQueryParams = new MultivaluedHashMap<>(); - protected final Optional<Collection<Vertex>> vertices; - protected static Pattern p = Pattern.compile("query/(.*+)"); - protected Optional<String> gremlin; - protected final TransactionalGraphEngine dbEngine; - protected GroovyQueryBuilder queryBuilder = new GroovyQueryBuilder(); - - protected NodeQueryProcessor(Builder builder) { - super(builder); - this.nodeQueryParams = builder.uriParams; - if(builder.getNodeType().isPresent()) { - this.nodeType = builder.getNodeType().get(); - } - this.dbEngine = builder.getDbEngine(); - this.vertices = builder.getVertices(); - - } - - public Pair<String, Map<String, Object>> createQuery() throws AAIException { - Map<String, Object> params = new HashMap<>(); - - Long timeNowInMilliSecs = System.currentTimeMillis(); - Long startTime = 0L; - if(nodeQueryParams.containsKey("hours")){ - Long hoursInMilliSec = TimeUnit.HOURS.toMillis(Long.parseLong(nodeQueryParams.getFirst("hours"))); - startTime = timeNowInMilliSecs - hoursInMilliSec; - } - else if(nodeQueryParams.containsKey("date-time")){ - Long dateTime = Long.parseLong(nodeQueryParams.getFirst("date-time")); - startTime = dateTime; - } - - String query = "builder.getVerticesByProperty('aai-node-type', nodeType)" - + ".or(builder.newInstance().getVerticesGreaterThanProperty('aai-created-ts',startTime)," - + " builder.newInstance().getVerticesGreaterThanProperty('aai-last-mod-ts',startTime)" + ")"; - - params.put("startTime", startTime); - params.put("nodeType", nodeType); - - query = queryBuilder.executeTraversal(dbEngine, query, params); - - String startPrefix = "g.V()"; - - query = startPrefix + query; - - if (logger.isDebugEnabled()) { - logger.debug("Converted to gremlin query without the start vertices \n {}", query); - } - - return new Pair<>(query, params); - } - - public List<Object> execute(SubGraphStyle style) throws FileNotFoundException, AAIException { - final List<Object> resultVertices = new Vector<>(); - - Pair<String, Map<String, Object>> tuple = this.createQuery(); - String query = tuple.getValue0(); - Map<String, Object> params = tuple.getValue1(); - - if (query.equals("")) { - // nothing to do, just exit - return new ArrayList<>(); - } - GraphTraversal<?, ?> g = this.runQuery(query, params, dbEngine.asAdmin().getTraversalSource()); - - resultVertices.addAll(g.toList()); - - return resultVertices; - } + return resultVertices; + } } diff --git a/aai-traversal/src/main/java/org/onap/aai/rest/search/QueryProcessorType.java b/aai-traversal/src/main/java/org/onap/aai/rest/search/QueryProcessorType.java index c8e1d14..8e4c7cf 100644 --- a/aai-traversal/src/main/java/org/onap/aai/rest/search/QueryProcessorType.java +++ b/aai-traversal/src/main/java/org/onap/aai/rest/search/QueryProcessorType.java @@ -8,7 +8,7 @@ * 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 + * 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, @@ -21,6 +21,5 @@ package org.onap.aai.rest.search; public enum QueryProcessorType { - GREMLIN_SERVER, - LOCAL_GROOVY + GREMLIN_SERVER, LOCAL_GROOVY } diff --git a/aai-traversal/src/main/java/org/onap/aai/rest/search/SchemaServiceCQConfig.java b/aai-traversal/src/main/java/org/onap/aai/rest/search/SchemaServiceCQConfig.java index ea1b62f..49986de 100644 --- a/aai-traversal/src/main/java/org/onap/aai/rest/search/SchemaServiceCQConfig.java +++ b/aai-traversal/src/main/java/org/onap/aai/rest/search/SchemaServiceCQConfig.java @@ -8,7 +8,7 @@ * 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 + * 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, @@ -19,19 +19,21 @@ */ package org.onap.aai.rest.search; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; import com.att.eelf.configuration.EELFManager; + +import java.util.HashMap; +import java.util.Map; + +import javax.annotation.PostConstruct; + import org.onap.aai.restclient.RestClient; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.beans.factory.annotation.Value; import org.springframework.beans.factory.annotation.Qualifier; +import org.springframework.beans.factory.annotation.Value; import org.springframework.http.ResponseEntity; -import javax.annotation.PostConstruct; -import java.util.HashMap; -import java.util.Map; - public class SchemaServiceCQConfig extends CQConfig { private static Logger logger = LoggerFactory.getLogger(SchemaServiceCQConfig.class); @@ -46,19 +48,20 @@ public class SchemaServiceCQConfig extends CQConfig { @PostConstruct public void initialize() { - //Call SchemaService to get custom queries + // Call SchemaService to get custom queries retrieveCustomQueries(); } public void retrieveCustomQueries() { - /* - Call Schema MS to get custom queries using RestTemplate - */ + /* + * Call Schema MS to get custom queries using RestTemplate + */ logger.info("Calling the SchemaService to retrieve stored queries"); String content = ""; Map<String, String> headersMap = new HashMap<>(); - ResponseEntity<String> schemaResponse = restClient.getGetRequest(content, customQueriesUri, headersMap); + ResponseEntity<String> schemaResponse = + restClient.getGetRequest(content, customQueriesUri, headersMap); queryConfig = new GetCustomQueryConfig(schemaResponse.getBody()); } } diff --git a/aai-traversal/src/main/java/org/onap/aai/rest/search/SearchProvider.java b/aai-traversal/src/main/java/org/onap/aai/rest/search/SearchProvider.java index 1db2699..17edbc5 100644 --- a/aai-traversal/src/main/java/org/onap/aai/rest/search/SearchProvider.java +++ b/aai-traversal/src/main/java/org/onap/aai/rest/search/SearchProvider.java @@ -8,7 +8,7 @@ * 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 + * 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, @@ -20,6 +20,17 @@ package org.onap.aai.rest.search; import io.micrometer.core.annotation.Timed; + +import java.net.URI; +import java.util.ArrayList; +import java.util.List; +import java.util.Optional; + +import javax.servlet.http.HttpServletRequest; +import javax.ws.rs.*; +import javax.ws.rs.core.*; +import javax.ws.rs.core.Response.Status; + import org.onap.aai.aailog.logs.AaiDBTraversalMetricLog; import org.onap.aai.concurrent.AaiCallable; import org.onap.aai.dbgraphmap.SearchGraph; @@ -46,15 +57,6 @@ 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.net.URI; -import java.util.ArrayList; -import java.util.List; -import java.util.Optional; - /** * Implements the search subdomain in the REST API. All API calls must include X-FromAppId and * X-TransactionId in the header. @@ -78,8 +80,8 @@ public class SearchProvider extends RESTAPI { private String basePath; @Autowired - public SearchProvider(LoaderFactory loaderFactory, SearchGraph searchGraph, SchemaVersions schemaVersions, - @Value("${schema.uri.base.path}") String basePath) { + public SearchProvider(LoaderFactory loaderFactory, SearchGraph searchGraph, + SchemaVersions schemaVersions, @Value("${schema.uri.base.path}") String basePath) { this.loaderFactory = loaderFactory; this.searchGraph = searchGraph; this.schemaVersions = schemaVersions; @@ -101,27 +103,29 @@ public class SearchProvider extends RESTAPI { @GET @Produces({MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML}) @Path(GENERIC_QUERY) - public Response getGenericQueryResponse(@Context HttpHeaders headers, @Context HttpServletRequest req, - @QueryParam("start-node-type") final String startNodeType, - @QueryParam("key") final List<String> startNodeKeyParams, - @QueryParam("include") final List<String> includeNodeTypes, @QueryParam("depth") final int depth, - @PathParam("version") String versionParam, @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<Response>() { - @Override - public Response process() { - return processGenericQueryResponse(headers, req, startNodeType, startNodeKeyParams, - includeNodeTypes, depth, versionParam); - } - }); + public Response getGenericQueryResponse(@Context HttpHeaders headers, + @Context HttpServletRequest req, @QueryParam("start-node-type") final String startNodeType, + @QueryParam("key") final List<String> startNodeKeyParams, + @QueryParam("include") final List<String> includeNodeTypes, + @QueryParam("depth") final int depth, @PathParam("version") String versionParam, + @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<Response>() { + @Override + public Response process() { + return processGenericQueryResponse(headers, req, startNodeType, + startNodeKeyParams, includeNodeTypes, depth, versionParam); + } + }); } - public Response processGenericQueryResponse(@Context HttpHeaders headers, @Context HttpServletRequest req, - @QueryParam("start-node-type") final String startNodeType, - @QueryParam("key") final List<String> startNodeKeyParams, - @QueryParam("include") final List<String> includeNodeTypes, @QueryParam("depth") final int depth, - @PathParam("version") String versionParam) { + public Response processGenericQueryResponse(@Context HttpHeaders headers, + @Context HttpServletRequest req, @QueryParam("start-node-type") final String startNodeType, + @QueryParam("key") final List<String> startNodeKeyParams, + @QueryParam("include") final List<String> includeNodeTypes, + @QueryParam("depth") final int depth, @PathParam("version") String versionParam) { AAIException ex = null; Response searchResult; @@ -137,17 +141,20 @@ public class SearchProvider extends RESTAPI { final ModelType factoryType = ModelType.MOXY; Loader loader = loaderFactory.createLoaderForVersion(factoryType, version); - TransactionalGraphEngine dbEngine = new JanusGraphDBEngine(QueryStyle.TRAVERSAL, loader); + TransactionalGraphEngine dbEngine = + new JanusGraphDBEngine(QueryStyle.TRAVERSAL, loader); DBSerializer dbSerializer = new DBSerializer(version, dbEngine, factoryType, fromAppId); - UrlBuilder urlBuilder = new UrlBuilder(version, dbSerializer, schemaVersions, this.basePath); + UrlBuilder urlBuilder = + new UrlBuilder(version, dbSerializer, schemaVersions, this.basePath); - AaiDBTraversalMetricLog metricLog = new AaiDBTraversalMetricLog (AAIConstants.AAI_TRAVERSAL_MS); + AaiDBTraversalMetricLog metricLog = + new AaiDBTraversalMetricLog(AAIConstants.AAI_TRAVERSAL_MS); metricLog.pre(Optional.of(new URI(req.getRequestURI()))); - searchResult = searchGraph - .runGenericQuery(new GenericQueryBuilder().setHeaders(headers).setStartNodeType(startNodeType) - .setStartNodeKeyParams(startNodeKeyParams).setIncludeNodeTypes(includeNodeTypes) - .setDepth(depth).setDbEngine(dbEngine).setLoader(loader).setUrlBuilder(urlBuilder)); + searchResult = searchGraph.runGenericQuery(new GenericQueryBuilder().setHeaders(headers) + .setStartNodeType(startNodeType).setStartNodeKeyParams(startNodeKeyParams) + .setIncludeNodeTypes(includeNodeTypes).setDepth(depth).setDbEngine(dbEngine) + .setLoader(loader).setUrlBuilder(urlBuilder)); metricLog.post(); @@ -156,17 +163,19 @@ public class SearchProvider extends RESTAPI { ex = e; templateVars.add("GET Search"); templateVars.add("getGenericQueryResponse"); - searchResult = Response.status(e.getErrorObject().getHTTPResponseCode()) - .entity(ErrorLogHelper.getRESTAPIErrorResponse(headers.getAcceptableMediaTypes(), e, templateVars)) - .build(); + searchResult = Response + .status(e.getErrorObject().getHTTPResponseCode()).entity(ErrorLogHelper + .getRESTAPIErrorResponse(headers.getAcceptableMediaTypes(), e, templateVars)) + .build(); } catch (Exception e) { // send error response ex = new AAIException("AAI_4000", e); templateVars.add("GET Search"); templateVars.add("getGenericQueryResponse"); - searchResult = Response.status(Status.INTERNAL_SERVER_ERROR) - .entity(ErrorLogHelper.getRESTAPIErrorResponse(headers.getAcceptableMediaTypes(), ex, templateVars)) - .build(); + searchResult = Response + .status(Status.INTERNAL_SERVER_ERROR).entity(ErrorLogHelper + .getRESTAPIErrorResponse(headers.getAcceptableMediaTypes(), ex, templateVars)) + .build(); } finally { // log success or failure if (ex != null) { @@ -193,28 +202,32 @@ public class SearchProvider extends RESTAPI { @GET @Produces({MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML}) @Path(NODES_QUERY) - public Response getNodesQueryResponse(@Context HttpHeaders headers, @Context HttpServletRequest req, - @QueryParam("search-node-type") final String searchNodeType, - @QueryParam("edge-filter") final List<String> edgeFilterList, - @QueryParam("filter") final List<String> filterList, @PathParam("version") String versionParam, - @Context UriInfo info) + public Response getNodesQueryResponse(@Context HttpHeaders headers, + @Context HttpServletRequest req, + @QueryParam("search-node-type") final String searchNodeType, + @QueryParam("edge-filter") final List<String> edgeFilterList, + @QueryParam("filter") final List<String> filterList, + @PathParam("version") String versionParam, @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<Response>() { - @Override - public Response process() { - return processNodesQueryResponse(headers, req, searchNodeType, edgeFilterList, filterList, - versionParam); - } - }); + return runner(TraversalConstants.AAI_TRAVERSAL_TIMEOUT_ENABLED, + TraversalConstants.AAI_TRAVERSAL_TIMEOUT_APP, + TraversalConstants.AAI_TRAVERSAL_TIMEOUT_LIMIT, headers, info, HttpMethod.GET, + new AaiCallable<Response>() { + @Override + public Response process() { + return processNodesQueryResponse(headers, req, searchNodeType, edgeFilterList, + filterList, versionParam); + } + }); } - public Response processNodesQueryResponse(@Context HttpHeaders headers, @Context HttpServletRequest req, - @QueryParam("search-node-type") final String searchNodeType, - @QueryParam("edge-filter") final List<String> edgeFilterList, - @QueryParam("filter") final List<String> filterList, @PathParam("version") String versionParam) { + public Response processNodesQueryResponse(@Context HttpHeaders headers, + @Context HttpServletRequest req, + @QueryParam("search-node-type") final String searchNodeType, + @QueryParam("edge-filter") final List<String> edgeFilterList, + @QueryParam("filter") final List<String> filterList, + @PathParam("version") String versionParam) { AAIException ex = null; Response searchResult; @@ -231,15 +244,18 @@ public class SearchProvider extends RESTAPI { final ModelType factoryType = ModelType.MOXY; Loader loader = loaderFactory.createLoaderForVersion(factoryType, version); - TransactionalGraphEngine dbEngine = new JanusGraphDBEngine(QueryStyle.TRAVERSAL, loader); + TransactionalGraphEngine dbEngine = + new JanusGraphDBEngine(QueryStyle.TRAVERSAL, loader); DBSerializer dbSerializer = new DBSerializer(version, dbEngine, factoryType, fromAppId); - UrlBuilder urlBuilder = new UrlBuilder(version, dbSerializer, schemaVersions, this.basePath); - + UrlBuilder urlBuilder = + new UrlBuilder(version, dbSerializer, schemaVersions, this.basePath); - AaiDBTraversalMetricLog metricLog = new AaiDBTraversalMetricLog (AAIConstants.AAI_TRAVERSAL_MS); + AaiDBTraversalMetricLog metricLog = + new AaiDBTraversalMetricLog(AAIConstants.AAI_TRAVERSAL_MS); metricLog.pre(Optional.of(new URI(req.getRequestURI()))); - searchResult = searchGraph.runNodesQuery(new NodesQueryBuilder().setHeaders(headers) - .setTargetNodeType(searchNodeType).setEdgeFilterParams(edgeFilterList).setFilterParams(filterList) + searchResult = searchGraph.runNodesQuery( + new NodesQueryBuilder().setHeaders(headers).setTargetNodeType(searchNodeType) + .setEdgeFilterParams(edgeFilterList).setFilterParams(filterList) .setDbEngine(dbEngine).setLoader(loader).setUrlBuilder(urlBuilder)); metricLog.post(); @@ -249,17 +265,19 @@ public class SearchProvider extends RESTAPI { ex = e; templateVars.add("GET Search"); templateVars.add("getNodesQueryResponse"); - searchResult = Response.status(e.getErrorObject().getHTTPResponseCode()) - .entity(ErrorLogHelper.getRESTAPIErrorResponse(headers.getAcceptableMediaTypes(), e, templateVars)) - .build(); + searchResult = Response + .status(e.getErrorObject().getHTTPResponseCode()).entity(ErrorLogHelper + .getRESTAPIErrorResponse(headers.getAcceptableMediaTypes(), e, templateVars)) + .build(); } catch (Exception e) { // send error response ex = new AAIException("AAI_4000", e); templateVars.add("GET Search"); templateVars.add("getNodesQueryResponse"); - searchResult = Response.status(Status.INTERNAL_SERVER_ERROR) - .entity(ErrorLogHelper.getRESTAPIErrorResponse(headers.getAcceptableMediaTypes(), ex, templateVars)) - .build(); + searchResult = Response + .status(Status.INTERNAL_SERVER_ERROR).entity(ErrorLogHelper + .getRESTAPIErrorResponse(headers.getAcceptableMediaTypes(), ex, templateVars)) + .build(); } finally { // log success or failure if (ex != null) { @@ -269,6 +287,4 @@ public class SearchProvider extends RESTAPI { return searchResult; } - - } diff --git a/aai-traversal/src/main/java/org/onap/aai/rest/security/WebSecurityConfig.java b/aai-traversal/src/main/java/org/onap/aai/rest/security/WebSecurityConfig.java index c92d818..e24013b 100644 --- a/aai-traversal/src/main/java/org/onap/aai/rest/security/WebSecurityConfig.java +++ b/aai-traversal/src/main/java/org/onap/aai/rest/security/WebSecurityConfig.java @@ -11,7 +11,7 @@ * 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 + * 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, @@ -23,6 +23,7 @@ * ============LICENSE_END========================================================= */ package org.onap.aai.rest.security; + import org.keycloak.adapters.springboot.KeycloakSpringBootConfigResolver; import org.keycloak.adapters.springsecurity.KeycloakConfiguration; import org.keycloak.adapters.springsecurity.authentication.KeycloakAuthenticationProvider; @@ -40,35 +41,36 @@ import org.springframework.security.core.session.SessionRegistryImpl; import org.springframework.security.web.authentication.session.RegisterSessionAuthenticationStrategy; import org.springframework.security.web.authentication.session.SessionAuthenticationStrategy; import org.springframework.security.web.session.HttpSessionEventPublisher; + @Profile("keycloak") @KeycloakConfiguration @Import({KeycloakSpringBootConfigResolver.class}) public class WebSecurityConfig extends KeycloakWebSecurityConfigurerAdapter { @Autowired public void configureGlobal(AuthenticationManagerBuilder auth) { - KeycloakAuthenticationProvider keycloakAuthenticationProvider - = keycloakAuthenticationProvider(); - keycloakAuthenticationProvider.setGrantedAuthoritiesMapper( - new SimpleAuthorityMapper()); + KeycloakAuthenticationProvider keycloakAuthenticationProvider = + keycloakAuthenticationProvider(); + keycloakAuthenticationProvider.setGrantedAuthoritiesMapper(new SimpleAuthorityMapper()); auth.authenticationProvider(keycloakAuthenticationProvider); } + @Bean public ServletListenerRegistrationBean<HttpSessionEventPublisher> httpSessionEventPublisher() { return new ServletListenerRegistrationBean<>(new HttpSessionEventPublisher()); } + @Bean @Override protected SessionAuthenticationStrategy sessionAuthenticationStrategy() { - return new RegisterSessionAuthenticationStrategy( - new SessionRegistryImpl()); + return new RegisterSessionAuthenticationStrategy(new SessionRegistryImpl()); } + @Override protected void configure(HttpSecurity http) throws Exception { super.configure(http); - http.authorizeRequests() - .antMatchers("/**") - .permitAll().and().csrf().disable(); + http.authorizeRequests().antMatchers("/**").permitAll().and().csrf().disable(); } + @Override public void configure(WebSecurity web) throws Exception { web.ignoring().regexMatchers("^.*/util/echo$"); diff --git a/aai-traversal/src/main/java/org/onap/aai/rest/util/AAIExtensionMap.java b/aai-traversal/src/main/java/org/onap/aai/rest/util/AAIExtensionMap.java index 0aa70e3..4e5651d 100644 --- a/aai-traversal/src/main/java/org/onap/aai/rest/util/AAIExtensionMap.java +++ b/aai-traversal/src/main/java/org/onap/aai/rest/util/AAIExtensionMap.java @@ -8,7 +8,7 @@ * 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 + * 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, @@ -20,6 +20,14 @@ package org.onap.aai.rest.util; +import java.lang.reflect.Method; +import java.util.ArrayList; +import java.util.HashMap; + +import javax.servlet.http.HttpServletRequest; +import javax.ws.rs.core.HttpHeaders; +import javax.ws.rs.core.UriInfo; + import org.apache.tinkerpop.gremlin.structure.Graph; import org.apache.tinkerpop.gremlin.structure.Vertex; import org.eclipse.persistence.jaxb.dynamic.DynamicJAXBContext; @@ -29,13 +37,6 @@ import org.onap.aai.rest.db.DBRequest; import org.onap.aai.rest.db.HttpEntry; import org.onap.aai.serialization.engines.TransactionalGraphEngine; -import javax.servlet.http.HttpServletRequest; -import javax.ws.rs.core.HttpHeaders; -import javax.ws.rs.core.UriInfo; -import java.lang.reflect.Method; -import java.util.ArrayList; -import java.util.HashMap; - public class AAIExtensionMap { // ======================================================================= // Attribute | Type diff --git a/aai-traversal/src/main/java/org/onap/aai/rest/util/ConvertQueryPropertiesToJson.java b/aai-traversal/src/main/java/org/onap/aai/rest/util/ConvertQueryPropertiesToJson.java index f16e700..f3ec5f8 100644 --- a/aai-traversal/src/main/java/org/onap/aai/rest/util/ConvertQueryPropertiesToJson.java +++ b/aai-traversal/src/main/java/org/onap/aai/rest/util/ConvertQueryPropertiesToJson.java @@ -8,7 +8,7 @@ * 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 + * 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, @@ -26,86 +26,88 @@ import java.util.List; import java.util.Properties; public class ConvertQueryPropertiesToJson { - - private static final int MAX_FILE_SIZE = 256000; - - private void addStart( StringBuilder sb ) { - sb.append("{\n \"stored-queries\":[{\n"); - } - - private void addRequiredQueryProperties( StringBuilder sb, List<String> rqd ) { - Iterator it = rqd.iterator(); - sb.append(" \"query\":{\n \"required-properties\":["); - while( it.hasNext()) { - sb.append("\"" + it.next() + "\""); - if ( it.hasNext()) { - sb.append(","); - } - } - sb.append("]\n },\n"); - } - - private void addAnotherQuery( StringBuilder sb, String queryName, String query, List<String> rqd ) { - sb.append(" \"" + queryName + "\":{\n"); - if ( !rqd.isEmpty()) { - addRequiredQueryProperties( sb, rqd); - } - sb.append(" \"stored-query\":\"" + query + "\"\n }\n },{\n"); - } - - private void addLastQuery( StringBuilder sb, String queryName, String query, List<String> rqd ) { - sb.append(" \"" + queryName + "\":{\n"); - if ( !rqd.isEmpty() ) { - addRequiredQueryProperties( sb, rqd); - } - sb.append(" \"stored-query\":\"" + query + "\"\n }\n }]\n}\n"); - } - - private String get2ndParameter( String paramString) { - String endParams = paramString.substring(0, paramString.indexOf(')')); - String result = endParams.substring(endParams.indexOf(',') + 1 ); - String lastParam = result.trim(); - if ( lastParam.startsWith("\\") || lastParam.startsWith("'") || lastParam.startsWith("new ") ){ - return null; - } - - return lastParam; - } - - private List<String> findRqdProperties( String query) { - String[] parts = query.split("getVerticesByProperty"); - List<String> result = new ArrayList<>(); - if ( parts.length == 1 ) - return result; - int count = 0; - String foundRqdProperty; - while ( count++ < parts.length - 1 ) { - foundRqdProperty = get2ndParameter(parts[count]); - if ( foundRqdProperty != null && !result.contains(foundRqdProperty)) { - result.add(foundRqdProperty); - } - } - return result; - } - public String convertProperties( Properties props ) { - Enumeration<?> e = props.propertyNames(); - StringBuilder sb = new StringBuilder(MAX_FILE_SIZE); - String queryName; - String query; - addStart( sb ); - List<String> rqd; - while ( e.hasMoreElements()) { - queryName = (String)e.nextElement(); - query = props.getProperty(queryName).trim().replace("\"", "\\\""); - rqd = findRqdProperties( query); - if ( e.hasMoreElements()) { - addAnotherQuery( sb, queryName, query, rqd); - } else { - addLastQuery( sb, queryName, query, rqd); - } - } - + private static final int MAX_FILE_SIZE = 256000; + + private void addStart(StringBuilder sb) { + sb.append("{\n \"stored-queries\":[{\n"); + } + + private void addRequiredQueryProperties(StringBuilder sb, List<String> rqd) { + Iterator it = rqd.iterator(); + sb.append(" \"query\":{\n \"required-properties\":["); + while (it.hasNext()) { + sb.append("\"" + it.next() + "\""); + if (it.hasNext()) { + sb.append(","); + } + } + sb.append("]\n },\n"); + } + + private void addAnotherQuery(StringBuilder sb, String queryName, String query, + List<String> rqd) { + sb.append(" \"" + queryName + "\":{\n"); + if (!rqd.isEmpty()) { + addRequiredQueryProperties(sb, rqd); + } + sb.append(" \"stored-query\":\"" + query + "\"\n }\n },{\n"); + } + + private void addLastQuery(StringBuilder sb, String queryName, String query, List<String> rqd) { + sb.append(" \"" + queryName + "\":{\n"); + if (!rqd.isEmpty()) { + addRequiredQueryProperties(sb, rqd); + } + sb.append(" \"stored-query\":\"" + query + "\"\n }\n }]\n}\n"); + } + + private String get2ndParameter(String paramString) { + String endParams = paramString.substring(0, paramString.indexOf(')')); + String result = endParams.substring(endParams.indexOf(',') + 1); + String lastParam = result.trim(); + if (lastParam.startsWith("\\") || lastParam.startsWith("'") + || lastParam.startsWith("new ")) { + return null; + } + + return lastParam; + } + + private List<String> findRqdProperties(String query) { + String[] parts = query.split("getVerticesByProperty"); + List<String> result = new ArrayList<>(); + if (parts.length == 1) + return result; + int count = 0; + String foundRqdProperty; + while (count++ < parts.length - 1) { + foundRqdProperty = get2ndParameter(parts[count]); + if (foundRqdProperty != null && !result.contains(foundRqdProperty)) { + result.add(foundRqdProperty); + } + } + return result; + } + + public String convertProperties(Properties props) { + Enumeration<?> e = props.propertyNames(); + StringBuilder sb = new StringBuilder(MAX_FILE_SIZE); + String queryName; + String query; + addStart(sb); + List<String> rqd; + while (e.hasMoreElements()) { + queryName = (String) e.nextElement(); + query = props.getProperty(queryName).trim().replace("\"", "\\\""); + rqd = findRqdProperties(query); + if (e.hasMoreElements()) { + addAnotherQuery(sb, queryName, query, rqd); + } else { + addLastQuery(sb, queryName, query, rqd); + } + } + return sb.toString(); - } + } } diff --git a/aai-traversal/src/main/java/org/onap/aai/rest/util/EchoResponse.java b/aai-traversal/src/main/java/org/onap/aai/rest/util/EchoResponse.java index 16c2618..d0ba708 100644 --- a/aai-traversal/src/main/java/org/onap/aai/rest/util/EchoResponse.java +++ b/aai-traversal/src/main/java/org/onap/aai/rest/util/EchoResponse.java @@ -8,7 +8,7 @@ * 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 + * 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, @@ -42,79 +42,79 @@ import org.onap.aai.restcore.RESTAPI; */ @Path("/util") public class EchoResponse extends RESTAPI { - - protected static String authPolicyFunctionName = "util"; - - public static final String ECHO_PATH = "/echo"; - - /** - * Simple health-check API that echos back the X-FromAppId and X-TransactionId to clients. - * If there is a query string, a transaction gets logged into hbase, proving the application is connected to the data store. - * If there is no query string, no transacction logging is done to hbase. - * - * @param headers the headers - * @param req the req - * @param myAction if exists will cause transaction to be logged to hbase - * @return the response - */ - @GET - @Produces( { MediaType.APPLICATION_XML, MediaType.APPLICATION_JSON }) - @Path(ECHO_PATH) - public Response echoResult(@Context HttpHeaders headers, @Context HttpServletRequest req, - @QueryParam("action") String myAction) { - AAIException ex = null; - Response response; - String fromAppId; - String transId; - - try { - fromAppId = getFromAppId(headers ); - transId = getTransId(headers); - } catch (AAIException e) { - ArrayList<String> templateVars = new ArrayList<>(); - templateVars.add("PUT uebProvider"); - templateVars.add("addTopic"); - return Response - .status(e.getErrorObject().getHTTPResponseCode()) - .entity(ErrorLogHelper.getRESTAPIErrorResponse(headers.getAcceptableMediaTypes(), e, templateVars)) - .build(); - } - - try { - - HashMap<AAIException, ArrayList<String>> exceptionList = new HashMap<>(); - - ArrayList<String> templateVars = new ArrayList<>(); - templateVars.add(fromAppId); - templateVars.add(transId); - - exceptionList.put(new AAIException("AAI_0002", "OK"), templateVars); - - response = Response.status(Status.OK) - .entity(ErrorLogHelper.getRESTAPIInfoResponse( - headers.getAcceptableMediaTypes(), exceptionList)) - .build(); - - } catch (Exception e) { - ex = new AAIException("AAI_4000", e); - ArrayList<String> templateVars = new ArrayList<>(); - templateVars.add(Action.GET.name()); - templateVars.add(fromAppId +" "+transId); - - response = Response - .status(Status.INTERNAL_SERVER_ERROR) - .entity(ErrorLogHelper.getRESTAPIErrorResponse( - headers.getAcceptableMediaTypes(), ex, - templateVars)).build(); - - } finally { - if (ex != null) { - ErrorLogHelper.logException(ex); - } - - } - - return response; - } + + protected static String authPolicyFunctionName = "util"; + + public static final String ECHO_PATH = "/echo"; + + /** + * Simple health-check API that echos back the X-FromAppId and X-TransactionId to clients. + * If there is a query string, a transaction gets logged into hbase, proving the application is + * connected to the data store. + * If there is no query string, no transacction logging is done to hbase. + * + * @param headers the headers + * @param req the req + * @param myAction if exists will cause transaction to be logged to hbase + * @return the response + */ + @GET + @Produces({MediaType.APPLICATION_XML, MediaType.APPLICATION_JSON}) + @Path(ECHO_PATH) + public Response echoResult(@Context HttpHeaders headers, @Context HttpServletRequest req, + @QueryParam("action") String myAction) { + AAIException ex = null; + Response response; + String fromAppId; + String transId; + + try { + fromAppId = getFromAppId(headers); + transId = getTransId(headers); + } catch (AAIException e) { + ArrayList<String> templateVars = new ArrayList<>(); + templateVars.add("PUT uebProvider"); + templateVars.add("addTopic"); + return Response + .status(e.getErrorObject().getHTTPResponseCode()).entity(ErrorLogHelper + .getRESTAPIErrorResponse(headers.getAcceptableMediaTypes(), e, templateVars)) + .build(); + } + + try { + + HashMap<AAIException, ArrayList<String>> exceptionList = new HashMap<>(); + + ArrayList<String> templateVars = new ArrayList<>(); + templateVars.add(fromAppId); + templateVars.add(transId); + + exceptionList.put(new AAIException("AAI_0002", "OK"), templateVars); + + response = Response + .status(Status.OK).entity(ErrorLogHelper + .getRESTAPIInfoResponse(headers.getAcceptableMediaTypes(), exceptionList)) + .build(); + + } catch (Exception e) { + ex = new AAIException("AAI_4000", e); + ArrayList<String> templateVars = new ArrayList<>(); + templateVars.add(Action.GET.name()); + templateVars.add(fromAppId + " " + transId); + + response = Response + .status(Status.INTERNAL_SERVER_ERROR).entity(ErrorLogHelper + .getRESTAPIErrorResponse(headers.getAcceptableMediaTypes(), ex, templateVars)) + .build(); + + } finally { + if (ex != null) { + ErrorLogHelper.logException(ex); + } + + } + + return response; + } } diff --git a/aai-traversal/src/main/java/org/onap/aai/rest/util/LogFormatTools.java b/aai-traversal/src/main/java/org/onap/aai/rest/util/LogFormatTools.java index 931ab0b..f7539a0 100644 --- a/aai-traversal/src/main/java/org/onap/aai/rest/util/LogFormatTools.java +++ b/aai-traversal/src/main/java/org/onap/aai/rest/util/LogFormatTools.java @@ -8,7 +8,7 @@ * 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 + * 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, @@ -25,11 +25,11 @@ import java.time.format.DateTimeFormatter; public class LogFormatTools { - private static final String DATE_FORMAT = "yyyy-MM-dd'T'HH:mm:ss.SSSZ"; - private static final DateTimeFormatter DTF = DateTimeFormatter.ofPattern(DATE_FORMAT) - .withZone(ZoneOffset.UTC); - - public static String getCurrentDateTime() { - return DTF.format(ZonedDateTime.now()); - } + private static final String DATE_FORMAT = "yyyy-MM-dd'T'HH:mm:ss.SSSZ"; + private static final DateTimeFormatter DTF = + DateTimeFormatter.ofPattern(DATE_FORMAT).withZone(ZoneOffset.UTC); + + public static String getCurrentDateTime() { + return DTF.format(ZonedDateTime.now()); + } } diff --git a/aai-traversal/src/main/java/org/onap/aai/rest/util/ValidateEncoding.java b/aai-traversal/src/main/java/org/onap/aai/rest/util/ValidateEncoding.java index 7d04bf7..fcf7e42 100644 --- a/aai-traversal/src/main/java/org/onap/aai/rest/util/ValidateEncoding.java +++ b/aai-traversal/src/main/java/org/onap/aai/rest/util/ValidateEncoding.java @@ -8,7 +8,7 @@ * 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 + * 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, @@ -32,131 +32,133 @@ import org.springframework.web.util.UriUtils; */ public class ValidateEncoding { - private final String encoding = "UTF-8"; - - /** - * Instantiates a new validate encoding. - */ - private ValidateEncoding() { - - } - - /** - * The Class Helper. - */ - private static class Helper { - - /** The Constant INSTANCE. */ - private static final ValidateEncoding INSTANCE = new ValidateEncoding(); - } - - /** - * Gets the single instance of ValidateEncoding. - * - * @return single instance of ValidateEncoding - */ - public static ValidateEncoding getInstance() { - return Helper.INSTANCE; - } - - /** - * Validate. - * - * @param uri the uri - * @return true, if successful - * @throws UnsupportedEncodingException the unsupported encoding exception - */ - public boolean validate(URI uri) throws UnsupportedEncodingException { - boolean result = true; - if (!validatePath(uri.getRawPath())) { - result = false; - } - /*if (!validateQueryParams(uri.getRawQuery())) { - result = false; - } //TODO - */ - - return result; - } - - /** - * Validate. - * - * @param info the info - * @return true, if successful - * @throws UnsupportedEncodingException the unsupported encoding exception - */ - public boolean validate(UriInfo info) throws UnsupportedEncodingException { - boolean result = true; - if (!validatePath(info.getPath(false))) { - result = false; - } - if (!validateQueryParams(info.getQueryParameters(false))) { - result = false; - } - - return result; - } - - /** - * Validate path. - * - * @param path the path - * @return true, if successful - * @throws UnsupportedEncodingException the unsupported encoding exception - */ - private boolean validatePath(String path) throws UnsupportedEncodingException { - String[] segments = path.split("/"); - boolean valid = true; - for (String segment : segments) { - if (!this.checkEncoding(segment)) { - valid = false; - } - } - - return valid; - - } - - /** - * Validate query params. - * - * @param params the params - * @return true, if successful - * @throws UnsupportedEncodingException the unsupported encoding exception - */ - private boolean validateQueryParams(MultivaluedMap<String, String> params) throws UnsupportedEncodingException { - boolean valid = true; - - for (String key : params.keySet()) { - if (!this.checkEncoding(key)) { - valid = false; - } - for (String item : params.get(key)) { - if(item.contains("+")){ - item = item.replaceAll("\\+", "%20"); - } - if (!this.checkEncoding(item)) { - valid = false; - } - } - } - return valid; - } - - /** - * Check encoding. - * - * @param segment the segment - * @return true, if successful - * @throws UnsupportedEncodingException the unsupported encoding exception - */ - private boolean checkEncoding(String segment) throws UnsupportedEncodingException { - boolean result = false; - String decode = UriUtils.decode(segment, encoding); - String encode = UriUtils.encode(decode, encoding); - result = segment.equals(encode); - - return result; - } + private final String encoding = "UTF-8"; + + /** + * Instantiates a new validate encoding. + */ + private ValidateEncoding() { + + } + + /** + * The Class Helper. + */ + private static class Helper { + + /** The Constant INSTANCE. */ + private static final ValidateEncoding INSTANCE = new ValidateEncoding(); + } + + /** + * Gets the single instance of ValidateEncoding. + * + * @return single instance of ValidateEncoding + */ + public static ValidateEncoding getInstance() { + return Helper.INSTANCE; + } + + /** + * Validate. + * + * @param uri the uri + * @return true, if successful + * @throws UnsupportedEncodingException the unsupported encoding exception + */ + public boolean validate(URI uri) throws UnsupportedEncodingException { + boolean result = true; + if (!validatePath(uri.getRawPath())) { + result = false; + } + /* + * if (!validateQueryParams(uri.getRawQuery())) { + * result = false; + * } //TODO + */ + + return result; + } + + /** + * Validate. + * + * @param info the info + * @return true, if successful + * @throws UnsupportedEncodingException the unsupported encoding exception + */ + public boolean validate(UriInfo info) throws UnsupportedEncodingException { + boolean result = true; + if (!validatePath(info.getPath(false))) { + result = false; + } + if (!validateQueryParams(info.getQueryParameters(false))) { + result = false; + } + + return result; + } + + /** + * Validate path. + * + * @param path the path + * @return true, if successful + * @throws UnsupportedEncodingException the unsupported encoding exception + */ + private boolean validatePath(String path) throws UnsupportedEncodingException { + String[] segments = path.split("/"); + boolean valid = true; + for (String segment : segments) { + if (!this.checkEncoding(segment)) { + valid = false; + } + } + + return valid; + + } + + /** + * Validate query params. + * + * @param params the params + * @return true, if successful + * @throws UnsupportedEncodingException the unsupported encoding exception + */ + private boolean validateQueryParams(MultivaluedMap<String, String> params) + throws UnsupportedEncodingException { + boolean valid = true; + + for (String key : params.keySet()) { + if (!this.checkEncoding(key)) { + valid = false; + } + for (String item : params.get(key)) { + if (item.contains("+")) { + item = item.replaceAll("\\+", "%20"); + } + if (!this.checkEncoding(item)) { + valid = false; + } + } + } + return valid; + } + + /** + * Check encoding. + * + * @param segment the segment + * @return true, if successful + * @throws UnsupportedEncodingException the unsupported encoding exception + */ + private boolean checkEncoding(String segment) throws UnsupportedEncodingException { + boolean result = false; + String decode = UriUtils.decode(segment, encoding); + String encode = UriUtils.encode(decode, encoding); + result = segment.equals(encode); + + return result; + } } |