aboutsummaryrefslogtreecommitdiffstats
path: root/src/main/java/org/onap/aai/rest
diff options
context:
space:
mode:
Diffstat (limited to 'src/main/java/org/onap/aai/rest')
-rw-r--r--src/main/java/org/onap/aai/rest/ExceptionHandler.java127
-rw-r--r--src/main/java/org/onap/aai/rest/QueryConsumer.java217
-rw-r--r--src/main/java/org/onap/aai/rest/dsl/DslListener.java314
-rw-r--r--src/main/java/org/onap/aai/rest/dsl/DslQueryProcessor.java85
-rw-r--r--src/main/java/org/onap/aai/rest/search/GenericQueryProcessor.java226
-rw-r--r--src/main/java/org/onap/aai/rest/search/GroovyShellImpl.java45
-rw-r--r--src/main/java/org/onap/aai/rest/search/QueryProcessorType.java26
-rw-r--r--src/main/java/org/onap/aai/rest/util/EchoResponse.java122
8 files changed, 1162 insertions, 0 deletions
diff --git a/src/main/java/org/onap/aai/rest/ExceptionHandler.java b/src/main/java/org/onap/aai/rest/ExceptionHandler.java
new file mode 100644
index 0000000..14c45da
--- /dev/null
+++ b/src/main/java/org/onap/aai/rest/ExceptionHandler.java
@@ -0,0 +1,127 @@
+/**
+ * ============LICENSE_START=======================================================
+ * org.onap.aai
+ * ================================================================================
+ * Copyright © 2017-2018 AT&T Intellectual Property. All rights reserved.
+ * ================================================================================
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ * ============LICENSE_END=========================================================
+ */
+package org.onap.aai.rest;
+
+import com.fasterxml.jackson.core.JsonParseException;
+import com.fasterxml.jackson.databind.JsonMappingException;
+import com.sun.istack.SAXParseException2;
+import org.onap.aai.exceptions.AAIException;
+import org.onap.aai.logging.ErrorLogHelper;
+
+import javax.servlet.http.HttpServletRequest;
+import javax.ws.rs.WebApplicationException;
+import javax.ws.rs.core.Context;
+import javax.ws.rs.core.HttpHeaders;
+import javax.ws.rs.core.MediaType;
+import javax.ws.rs.core.Response;
+import javax.ws.rs.ext.ExceptionMapper;
+import javax.ws.rs.ext.Provider;
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * The Class ExceptionHandler.
+ */
+@Provider
+public class ExceptionHandler implements ExceptionMapper<Exception> {
+
+ @Context
+ private HttpServletRequest request;
+
+ @Context
+ private HttpHeaders headers;
+
+ /**
+ * @{inheritDoc}
+ */
+ @Override
+ public Response toResponse(Exception exception) {
+
+ Response response = null;
+ ArrayList<String> templateVars = new ArrayList<String>();
+
+ //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() != null) {
+ 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 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;
+
+ 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/src/main/java/org/onap/aai/rest/QueryConsumer.java b/src/main/java/org/onap/aai/rest/QueryConsumer.java
new file mode 100644
index 0000000..85665da
--- /dev/null
+++ b/src/main/java/org/onap/aai/rest/QueryConsumer.java
@@ -0,0 +1,217 @@
+/**
+ * ============LICENSE_START=======================================================
+ * org.onap.aai
+ * ================================================================================
+ * Copyright © 2017-2018 AT&T Intellectual Property. All rights reserved.
+ * ================================================================================
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ * ============LICENSE_END=========================================================
+ */
+package org.onap.aai.rest;
+
+import com.att.eelf.configuration.EELFLogger;
+import com.att.eelf.configuration.EELFManager;
+import com.google.gson.JsonElement;
+import com.google.gson.JsonObject;
+import com.google.gson.JsonParser;
+import org.onap.aai.concurrent.AaiCallable;
+import org.onap.aai.dbmap.DBConnectionType;
+import org.onap.aai.exceptions.AAIException;
+import org.onap.aai.introspection.ModelType;
+import org.onap.aai.rest.dsl.DslQueryProcessor;
+import org.onap.aai.logging.LoggingContext;
+import org.onap.aai.logging.StopWatch;
+import org.onap.aai.rest.db.HttpEntry;
+import org.onap.aai.rest.search.GenericQueryProcessor;
+import org.onap.aai.rest.search.QueryProcessorType;
+import org.onap.aai.restcore.HttpMethod;
+import org.onap.aai.restcore.RESTAPI;
+import org.onap.aai.serialization.db.DBSerializer;
+import org.onap.aai.serialization.engines.TransactionalGraphEngine;
+import org.onap.aai.serialization.queryformats.Format;
+import org.onap.aai.serialization.queryformats.FormatFactory;
+import org.onap.aai.serialization.queryformats.Formatter;
+import org.onap.aai.serialization.queryformats.SubGraphStyle;
+import org.onap.aai.setup.SchemaVersion;
+import org.onap.aai.setup.SchemaVersions;
+import org.onap.aai.util.AAIConstants;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.beans.factory.annotation.Value;
+import org.springframework.stereotype.Component;
+
+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;
+
+@Component
+@Path("{version: v[1-9][0-9]*|latest}/dbquery")
+public class QueryConsumer extends RESTAPI {
+
+ /** The introspector factory type. */
+ private ModelType introspectorFactoryType = ModelType.MOXY;
+
+ private QueryProcessorType processorType = QueryProcessorType.LOCAL_GROOVY;
+
+ private static final String TARGET_ENTITY = "DB";
+ private static final EELFLogger LOGGER = EELFManager.getInstance().getLogger(QueryConsumer.class);
+
+ private HttpEntry traversalUriHttpEntry;
+
+ private DslQueryProcessor dslQueryProcessor;
+
+ private SchemaVersions schemaVersions;
+
+ private String basePath;
+
+ @Autowired
+ public QueryConsumer(
+ HttpEntry traversalUriHttpEntry,
+ DslQueryProcessor dslQueryProcessor,
+ SchemaVersions schemaVersions,
+ @Value("${schema.uri.base.path}") String basePath
+ ){
+ this.traversalUriHttpEntry = traversalUriHttpEntry;
+ this.dslQueryProcessor = dslQueryProcessor;
+ this.basePath = basePath;
+ this.schemaVersions = schemaVersions;
+ }
+
+
+ @PUT
+ @Consumes({ MediaType.APPLICATION_JSON})
+ @Produces({ MediaType.APPLICATION_JSON})
+ public Response executeQuery(String content, @PathParam("version")String versionParam, @PathParam("uri") @Encoded String uri, @DefaultValue("graphson") @QueryParam("format") String queryFormat,@DefaultValue("no_op") @QueryParam("subgraph") String subgraph, @Context HttpHeaders headers, @Context UriInfo info, @Context HttpServletRequest req){
+ return runner(AAIConstants.AAI_GRAPHADMIN_TIMEOUT_ENABLED,
+ AAIConstants.AAI_GRAPHADMIN_TIMEOUT_APP,
+ AAIConstants.AAI_GRAPHADMIN_TIMEOUT_LIMIT,
+ headers,
+ info,
+ HttpMethod.GET,
+ new AaiCallable<Response>() {
+ @Override
+ public Response process() {
+ return processExecuteQuery(content, versionParam, uri, queryFormat, subgraph, headers, info, req);
+ }
+ }
+ );
+ }
+
+ public Response processExecuteQuery(String content, @PathParam("version")String versionParam, @PathParam("uri") @Encoded String uri, @DefaultValue("graphson") @QueryParam("format") String queryFormat,@DefaultValue("no_op") @QueryParam("subgraph") String subgraph, @Context HttpHeaders headers, @Context UriInfo info, @Context HttpServletRequest req) {
+
+ String methodName = "executeQuery";
+ String sourceOfTruth = headers.getRequestHeaders().getFirst("X-FromAppId");
+ String realTime = headers.getRequestHeaders().getFirst("Real-Time");
+ String queryProcessor = headers.getRequestHeaders().getFirst("QueryProcessor");
+ QueryProcessorType processorType = this.processorType;
+ Response response = null;
+ TransactionalGraphEngine dbEngine = null;
+ try {
+ LoggingContext.save();
+ 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 gremlinElement = input.get("gremlin");
+ JsonElement dslElement = input.get("dsl");
+ String queryURI = "";
+ String gremlin = "";
+ String dsl = "";
+
+ SchemaVersion version = new SchemaVersion(versionParam);
+ DBConnectionType type = this.determineConnectionType(sourceOfTruth, realTime);
+ traversalUriHttpEntry.setHttpEntryProperties(version, type);
+ dbEngine = traversalUriHttpEntry.getDbEngine();
+
+ if (gremlinElement != null) {
+ gremlin = gremlinElement.getAsString();
+ }
+ if (dslElement != null) {
+ dsl = dslElement.getAsString();
+ }
+ GenericQueryProcessor processor = null;
+
+ LoggingContext.targetEntity(TARGET_ENTITY);
+ LoggingContext.targetServiceName(methodName);
+ LoggingContext.startTime();
+ StopWatch.conditionalStart();
+
+ if(!dsl.equals("")){
+ processor = new GenericQueryProcessor.Builder(dbEngine)
+ .queryFrom(dsl, "dsl")
+ .queryProcessor(dslQueryProcessor)
+ .processWith(processorType).create();
+ }else {
+ processor = new GenericQueryProcessor.Builder(dbEngine)
+ .queryFrom(gremlin, "gremlin")
+ .processWith(processorType).create();
+ }
+
+ String result = "";
+ List<Object> vertices = processor.execute(subGraphStyle);
+
+ DBSerializer serializer = new DBSerializer(version, dbEngine, introspectorFactoryType, sourceOfTruth);
+ FormatFactory ff = new FormatFactory(traversalUriHttpEntry.getLoader(), serializer, schemaVersions, basePath);
+
+ Formatter formater = ff.get(format, info.getQueryParameters());
+
+ result = formater.output(vertices).toString();
+
+ double msecs = StopWatch.stopIfStarted();
+ LoggingContext.elapsedTime((long)msecs,TimeUnit.MILLISECONDS);
+ LoggingContext.successStatusFields();
+ LOGGER.info ("Completed");
+
+ response = Response.status(Status.OK)
+ .type(MediaType.APPLICATION_JSON)
+ .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 {
+ LoggingContext.restoreIfPossible();
+ LoggingContext.successStatusFields();
+ 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");
+ Integer i = Integer.parseInt(depth);
+ if (i > 1) {
+ throw new AAIException("AAI_3303");
+ }
+ }
+
+
+ }
+
+}
diff --git a/src/main/java/org/onap/aai/rest/dsl/DslListener.java b/src/main/java/org/onap/aai/rest/dsl/DslListener.java
new file mode 100644
index 0000000..e41a946
--- /dev/null
+++ b/src/main/java/org/onap/aai/rest/dsl/DslListener.java
@@ -0,0 +1,314 @@
+/**
+ * ============LICENSE_START=======================================================
+ * org.onap.aai
+ * ================================================================================
+ * Copyright © 2017-2018 AT&T Intellectual Property. All rights reserved.
+ * ================================================================================
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ * ============LICENSE_END=========================================================
+ */
+package org.onap.aai.rest.dsl;
+
+import com.att.eelf.configuration.EELFLogger;
+import com.att.eelf.configuration.EELFManager;
+import org.antlr.v4.runtime.tree.TerminalNode;
+import org.onap.aai.AAIDslBaseListener;
+import org.onap.aai.AAIDslParser;
+import org.onap.aai.edges.EdgeIngestor;
+import org.onap.aai.edges.EdgeRule;
+import org.onap.aai.edges.EdgeRuleQuery;
+import org.onap.aai.edges.exceptions.AmbiguousRuleChoiceException;
+import org.onap.aai.edges.exceptions.EdgeRuleNotFoundException;
+import org.springframework.beans.factory.annotation.Autowired;
+
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+/**
+ * The Class DslListener.
+ */
+public class DslListener extends AAIDslBaseListener {
+
+ private static final EELFLogger LOGGER = EELFManager.getInstance().getLogger(DslQueryProcessor.class);
+ private final EdgeIngestor edgeRules;
+
+ //TODO Use StringBuilder to build the query than concat
+ String query = "";
+
+ Map<Integer, String> unionMap = new HashMap<>();
+ Map<String, String> flags = new HashMap<>();
+
+ String currentNode = "";
+ String prevsNode = "";
+ int commas = 0;
+
+ int unionKey = 0;
+ int unionMembers = 0;
+ boolean isUnionBeg = false;
+ boolean isUnionTraversal = false;
+
+ boolean isTraversal = false;
+ boolean isWhereTraversal = false;
+ String whereTraversalNode = "";
+
+ String limitQuery = "";
+ boolean isNot = false;
+
+ /**
+ * Instantiates a new DslListener.
+ */
+ @Autowired
+ public DslListener(EdgeIngestor edgeIngestor) {
+ this.edgeRules = edgeIngestor;
+ }
+
+ @Override
+ public void enterAaiquery(AAIDslParser.AaiqueryContext ctx) {
+ query += "builder";
+ }
+
+ @Override
+ public void enterDslStatement(AAIDslParser.DslStatementContext ctx) {
+ // LOGGER.info("Statement Enter"+ctx.getText());
+ /*
+ * This block of code is entered for every query statement
+ */
+ if (isUnionBeg) {
+ isUnionBeg = false;
+ isUnionTraversal = true;
+
+ } else if (unionMembers > 0) {
+ unionMembers--;
+ query += ",builder.newInstance()";
+ isUnionTraversal = true;
+ }
+
+ }
+
+ @Override
+ public void exitDslStatement(AAIDslParser.DslStatementContext ctx) {
+ /*
+ * Nothing to be done here for now
+ * LOGGER.info("Statement Exit"+ctx.getText());
+ */
+ }
+
+ @Override
+ public void exitAaiquery(AAIDslParser.AaiqueryContext ctx) {
+ /*
+ * dedup is by default for all queries If the query has limit in it
+ * include this as well LOGGER.info("Statement Exit"+ctx.getText());
+ */
+
+ query += ".cap('x').unfold().dedup()" + limitQuery;
+ }
+
+ /*
+ * TODO: The contexts are not inherited from a single parent in AAIDslParser
+ * Need to find a way to do that
+ */
+ @Override
+ public void enterSingleNodeStep(AAIDslParser.SingleNodeStepContext ctx) {
+
+ prevsNode = currentNode;
+ currentNode = ctx.NODE().getText();
+
+ this.generateQuery();
+ if (ctx.STORE() != null && ctx.STORE().getText().equals("*")) {
+ flags.put(currentNode, "store");
+ }
+
+ }
+
+ @Override
+ public void enterSingleQueryStep(AAIDslParser.SingleQueryStepContext ctx) {
+
+ prevsNode = currentNode;
+ currentNode = ctx.NODE().getText();
+ this.generateQuery();
+
+ if (ctx.STORE() != null && ctx.STORE().getText().equals("*")) {
+ flags.put(currentNode, "store");
+ }
+ }
+
+ @Override
+ public void enterMultiQueryStep(AAIDslParser.MultiQueryStepContext ctx) {
+
+ prevsNode = currentNode;
+ currentNode = ctx.NODE().getText();
+ this.generateQuery();
+
+ if (ctx.STORE() != null && ctx.STORE().getText().equals("*")) {
+ flags.put(currentNode, "store");
+ }
+
+ }
+
+ /*
+ * Generates the QueryBuilder syntax for the dsl query
+ */
+ private void generateQuery() {
+ String edgeType = "";
+
+ if (isUnionTraversal || isTraversal || isWhereTraversal) {
+ String previousNode = prevsNode;
+ if (isUnionTraversal) {
+ previousNode = unionMap.get(unionKey);
+ isUnionTraversal = false;
+ }
+
+ EdgeRuleQuery edgeRuleQuery = new EdgeRuleQuery.Builder(previousNode, currentNode).build();
+ EdgeRule edgeRule = null;
+
+ try {
+ edgeRule = edgeRules.getRule(edgeRuleQuery);
+ } catch (EdgeRuleNotFoundException | AmbiguousRuleChoiceException e) {
+ }
+
+ if (edgeRule == null) {
+ edgeType = "EdgeType.COUSIN";
+ } else if ("none".equalsIgnoreCase(edgeRule.getContains())){
+ edgeType = "EdgeType.COUSIN";
+ }else {
+ edgeType = "EdgeType.TREE";
+ }
+
+ query += ".createEdgeTraversal(" + edgeType + ", '" + previousNode + "','" + currentNode + "')";
+
+ }
+
+ else
+ query += ".getVerticesByProperty('aai-node-type', '" + currentNode + "')";
+ }
+
+ @Override
+ public void exitSingleNodeStep(AAIDslParser.SingleNodeStepContext ctx) {
+
+ generateExitStep();
+ }
+
+ @Override
+ public void exitSingleQueryStep(AAIDslParser.SingleQueryStepContext ctx) {
+ generateExitStep();
+ }
+
+ @Override
+ public void exitMultiQueryStep(AAIDslParser.MultiQueryStepContext ctx) {
+ generateExitStep();
+
+ }
+
+ private void generateExitStep() {
+ if (flags.containsKey(currentNode)) {
+ String storeFlag = flags.get(currentNode);
+ if (storeFlag != null && storeFlag.equals("store"))
+ query += ".store('x')";
+ flags.remove(currentNode);
+ }
+ }
+
+ @Override
+ public void enterUnionQueryStep(AAIDslParser.UnionQueryStepContext ctx) {
+ isUnionBeg = true;
+
+ unionKey++;
+ unionMap.put(unionKey, currentNode);
+ query += ".union(builder.newInstance()";
+
+ List<TerminalNode> commaNodes = ctx.COMMA();
+
+ for (TerminalNode node : commaNodes) {
+ unionMembers++;
+ }
+ }
+
+ @Override
+ public void exitUnionQueryStep(AAIDslParser.UnionQueryStepContext ctx) {
+ isUnionBeg = false;
+ unionMap.remove(unionKey);
+
+ query += ")";
+ unionKey--;
+
+ }
+
+ @Override
+ public void enterFilterTraverseStep(AAIDslParser.FilterTraverseStepContext ctx) {
+ isWhereTraversal = true;
+ whereTraversalNode = currentNode;
+ query += ".where(builder.newInstance()";
+ }
+
+ @Override
+ public void exitFilterTraverseStep(AAIDslParser.FilterTraverseStepContext ctx) {
+ query += ")";
+ isWhereTraversal = false;
+ currentNode = whereTraversalNode;
+ }
+
+ @Override
+ public void enterFilterStep(AAIDslParser.FilterStepContext ctx) {
+ if (ctx.NOT() != null && ctx.NOT().getText().equals("!"))
+ isNot = true;
+
+ List<TerminalNode> nodes = ctx.KEY();
+ String key = ctx.KEY(0).getText();
+
+ if (isNot) {
+ query += ".getVerticesExcludeByProperty(";
+ isNot = false;
+ } else
+ query += ".getVerticesByProperty(";
+
+ if (nodes.size() == 2) {
+ query += key + "," + ctx.KEY(1).getText();
+ query += ")";
+ }
+
+ if (nodes.size() > 2) {
+
+ for (TerminalNode node : nodes) {
+ if (node.getText().equals(key))
+ continue;
+
+ query += key + "," + node.getText();
+ query += ")";
+ }
+
+ }
+
+ }
+
+ @Override
+ public void exitFilterStep(AAIDslParser.FilterStepContext ctx) {
+ // For now do nothing
+ }
+
+ @Override
+ public void enterTraverseStep(AAIDslParser.TraverseStepContext ctx) {
+ isTraversal = true;
+ }
+
+ @Override
+ public void exitTraverseStep(AAIDslParser.TraverseStepContext ctx) {
+ isTraversal = false;
+ }
+
+ @Override
+ public void enterLimitStep(AAIDslParser.LimitStepContext ctx) {
+ String value = ctx.NODE().getText();
+ limitQuery += ".limit(" + value + ")";
+ }
+}
diff --git a/src/main/java/org/onap/aai/rest/dsl/DslQueryProcessor.java b/src/main/java/org/onap/aai/rest/dsl/DslQueryProcessor.java
new file mode 100644
index 0000000..582f0ea
--- /dev/null
+++ b/src/main/java/org/onap/aai/rest/dsl/DslQueryProcessor.java
@@ -0,0 +1,85 @@
+/**
+ * ============LICENSE_START=======================================================
+ * org.onap.aai
+ * ================================================================================
+ * Copyright © 2017-2018 AT&T Intellectual Property. All rights reserved.
+ * ================================================================================
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ * ============LICENSE_END=========================================================
+ */
+package org.onap.aai.rest.dsl;
+
+import com.att.eelf.configuration.EELFLogger;
+import com.att.eelf.configuration.EELFManager;
+import org.antlr.v4.runtime.CharStreams;
+import org.antlr.v4.runtime.CommonTokenStream;
+import org.antlr.v4.runtime.tree.ParseTree;
+import org.antlr.v4.runtime.tree.ParseTreeWalker;
+import org.onap.aai.AAIDslLexer;
+import org.onap.aai.AAIDslParser;
+import org.springframework.beans.factory.annotation.Autowired;
+
+import java.io.ByteArrayInputStream;
+import java.io.InputStream;
+import java.nio.charset.StandardCharsets;
+
+/**
+ * The Class DslQueryProcessor.
+ */
+public class DslQueryProcessor {
+
+ private static final EELFLogger LOGGER = EELFManager.getInstance().getLogger(DslQueryProcessor.class);
+
+ private DslListener dslListener;
+
+ @Autowired
+ public DslQueryProcessor(DslListener dslListener){
+ this.dslListener = dslListener;
+ }
+
+ public String parseAaiQuery(String aaiQuery) {
+ try {
+ // Create a input stream that reads our string
+ InputStream stream = new ByteArrayInputStream(aaiQuery.getBytes(StandardCharsets.UTF_8));
+
+ // Create a lexer from the input CharStream
+ AAIDslLexer lexer = new AAIDslLexer(CharStreams.fromStream(stream, StandardCharsets.UTF_8));
+
+ // Get a list of tokens pulled from the lexer
+ CommonTokenStream tokens = new CommonTokenStream(lexer);
+
+
+ // Parser that feeds off of the tokens buffer
+ AAIDslParser parser = new AAIDslParser(tokens);
+
+ // Specify our entry point
+ ParseTree ptree = parser.aaiquery();
+ LOGGER.info("QUERY-interim" + ptree.toStringTree(parser));
+
+ // Walk it and attach our listener
+ ParseTreeWalker walker = new ParseTreeWalker();
+ walker.walk(dslListener, ptree);
+ LOGGER.info("Final QUERY" + dslListener.query);
+
+ /*
+ * TODO - Visitor patternQueryDslVisitor visitor = new
+ * QueryDslVisitor(); String query = visitor.visit(ptree);
+ *
+ */
+ return dslListener.query;
+ } catch (Exception e) {
+ LOGGER.error("Error while processing the query"+e.getMessage());
+ }
+ return "";
+ }
+}
diff --git a/src/main/java/org/onap/aai/rest/search/GenericQueryProcessor.java b/src/main/java/org/onap/aai/rest/search/GenericQueryProcessor.java
new file mode 100644
index 0000000..2431d11
--- /dev/null
+++ b/src/main/java/org/onap/aai/rest/search/GenericQueryProcessor.java
@@ -0,0 +1,226 @@
+/**
+ * ============LICENSE_START=======================================================
+ * org.onap.aai
+ * ================================================================================
+ * Copyright © 2017-2018 AT&T Intellectual Property. All rights reserved.
+ * ================================================================================
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ * ============LICENSE_END=========================================================
+ */
+package org.onap.aai.rest.search;
+
+import 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.__;
+import org.apache.tinkerpop.gremlin.structure.Graph;
+import org.apache.tinkerpop.gremlin.structure.Vertex;
+import org.javatuples.Pair;
+import org.onap.aai.exceptions.AAIException;
+import org.onap.aai.rest.dsl.DslQueryProcessor;
+import org.onap.aai.restcore.search.GroovyQueryBuilderSingleton;
+import org.onap.aai.restcore.util.URITools;
+import org.onap.aai.serialization.engines.TransactionalGraphEngine;
+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;
+
+public abstract class GenericQueryProcessor {
+
+ 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 static GroovyQueryBuilderSingleton queryBuilderSingleton = GroovyQueryBuilderSingleton.getInstance();
+ protected final boolean isGremlin;
+ protected Optional<DslQueryProcessor> dslQueryProcessorOptional;
+ /* dsl parameters to store dsl query and to check
+ * if this is a DSL request
+ */
+ protected Optional<String> dsl;
+ protected final boolean isDsl ;
+
+ 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.dslQueryProcessorOptional = builder.getDslQueryProcessor();
+
+ if (uri.isPresent()) {
+ queryParams = URITools.getQueryMap(uri.get());
+ } else {
+ queryParams = new MultivaluedHashMap<>();
+ }
+ }
+
+ protected abstract GraphTraversal<?,?> runQuery(String query, Map<String, Object> params);
+
+ 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();
+ 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);
+
+ resultVertices = this.processSubGraph(style, g);
+
+ return resultVertices;
+ }
+
+ 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()){
+ String dslQuery = dslQueryProcessorOptional.get().parseAaiQuery(dslUserQuery);
+ query = queryBuilderSingleton.executeTraversal(dbEngine, dslQuery, params);
+ String startPrefix = "g.V()";
+ query = startPrefix + query;
+ }
+ }
+
+ 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;
+
+ public Builder(TransactionalGraphEngine dbEngine) {
+ this.dbEngine = dbEngine;
+ }
+
+ 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;
+ }
+ return this;
+ }
+
+ public Builder processWith(QueryProcessorType type) {
+ this.processorType = type;
+ return this;
+ }
+
+ public Builder queryProcessor(DslQueryProcessor dslQueryProcessor){
+ this.dslQueryProcessor = dslQueryProcessor;
+ return this;
+ }
+
+ public Optional<DslQueryProcessor> getDslQueryProcessor(){
+ return Optional.ofNullable(this.dslQueryProcessor);
+ }
+
+ public TransactionalGraphEngine getDbEngine() {
+ return dbEngine;
+ }
+
+ public Optional<URI> getUri() {
+ return uri;
+ }
+
+ 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 GenericQueryProcessor create() {
+ return new GroovyShellImpl(this);
+ }
+
+ }
+}
diff --git a/src/main/java/org/onap/aai/rest/search/GroovyShellImpl.java b/src/main/java/org/onap/aai/rest/search/GroovyShellImpl.java
new file mode 100644
index 0000000..3db4301
--- /dev/null
+++ b/src/main/java/org/onap/aai/rest/search/GroovyShellImpl.java
@@ -0,0 +1,45 @@
+/**
+ * ============LICENSE_START=======================================================
+ * org.onap.aai
+ * ================================================================================
+ * Copyright © 2017-2018 AT&T Intellectual Property. All rights reserved.
+ * ================================================================================
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ * ============LICENSE_END=========================================================
+ */
+package org.onap.aai.rest.search;
+
+import org.apache.tinkerpop.gremlin.process.traversal.dsl.graph.GraphTraversal;
+import org.onap.aai.restcore.search.GremlinGroovyShellSingleton;
+
+import java.util.Map;
+
+public class GroovyShellImpl extends GenericQueryProcessor {
+
+ protected GroovyShellImpl(Builder builder) {
+ super(builder);
+ }
+
+ @Override
+ protected GraphTraversal<?,?> runQuery(String query, Map<String, Object> params) {
+
+ params.put("g", this.dbEngine.asAdmin().getTraversalSource());
+
+ GremlinGroovyShellSingleton shell = GremlinGroovyShellSingleton.getInstance();
+
+ return shell.executeTraversal(query, params);
+ }
+
+}
+
+
diff --git a/src/main/java/org/onap/aai/rest/search/QueryProcessorType.java b/src/main/java/org/onap/aai/rest/search/QueryProcessorType.java
new file mode 100644
index 0000000..c8e1d14
--- /dev/null
+++ b/src/main/java/org/onap/aai/rest/search/QueryProcessorType.java
@@ -0,0 +1,26 @@
+/**
+ * ============LICENSE_START=======================================================
+ * org.onap.aai
+ * ================================================================================
+ * Copyright © 2017-2018 AT&T Intellectual Property. All rights reserved.
+ * ================================================================================
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ * ============LICENSE_END=========================================================
+ */
+package org.onap.aai.rest.search;
+
+public enum QueryProcessorType {
+
+ GREMLIN_SERVER,
+ LOCAL_GROOVY
+}
diff --git a/src/main/java/org/onap/aai/rest/util/EchoResponse.java b/src/main/java/org/onap/aai/rest/util/EchoResponse.java
new file mode 100644
index 0000000..05ff38e
--- /dev/null
+++ b/src/main/java/org/onap/aai/rest/util/EchoResponse.java
@@ -0,0 +1,122 @@
+/**
+ * ============LICENSE_START=======================================================
+ * org.onap.aai
+ * ================================================================================
+ * Copyright © 2017-2018 AT&T Intellectual Property. All rights reserved.
+ * ================================================================================
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ * ============LICENSE_END=========================================================
+ */
+package org.onap.aai.rest.util;
+
+import org.onap.aai.exceptions.AAIException;
+import org.onap.aai.logging.ErrorLogHelper;
+import org.onap.aai.restcore.RESTAPI;
+import org.springframework.stereotype.Component;
+
+import javax.servlet.http.HttpServletRequest;
+import javax.ws.rs.GET;
+import javax.ws.rs.Path;
+import javax.ws.rs.Produces;
+import javax.ws.rs.QueryParam;
+import javax.ws.rs.core.Context;
+import javax.ws.rs.core.HttpHeaders;
+import javax.ws.rs.core.MediaType;
+import javax.ws.rs.core.Response;
+import javax.ws.rs.core.Response.Status;
+import java.util.ArrayList;
+import java.util.HashMap;
+
+/**
+ * The Class EchoResponse.
+ */
+@Component
+@Path("/util")
+public class EchoResponse extends RESTAPI {
+
+ protected static String authPolicyFunctionName = "util";
+
+ public static final String echoPath = "/util/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")
+ public Response echoResult(@Context HttpHeaders headers, @Context HttpServletRequest req,
+ @QueryParam("action") String myAction) {
+ Response response = null;
+
+ AAIException ex = null;
+ String fromAppId = null;
+ String transId = null;
+
+ try {
+ fromAppId = getFromAppId(headers );
+ transId = getTransId(headers);
+ } catch (AAIException e) {
+ ArrayList<String> templateVars = new ArrayList<String>();
+ 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<AAIException, ArrayList<String>>();
+
+ ArrayList<String> templateVars = new ArrayList<String>();
+ 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<String>();
+ 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;
+ }
+
+}