2 * ============LICENSE_START=======================================================
4 * ================================================================================
5 * Copyright © 2017-2018 AT&T Intellectual Property. All rights reserved.
6 * ================================================================================
7 * Licensed under the Apache License, Version 2.0 (the "License");
8 * you may not use this file except in compliance with the License.
9 * You may obtain a copy of the License at
11 * http://www.apache.org/licenses/LICENSE-2.0
13 * Unless required by applicable law or agreed to in writing, software
14 * distributed under the License is distributed on an "AS IS" BASIS,
15 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16 * See the License for the specific language governing permissions and
17 * limitations under the License.
18 * ============LICENSE_END=========================================================
20 package org.onap.aai.rest;
22 import java.util.ArrayList;
23 import java.util.Iterator;
24 import java.util.List;
26 import java.util.Optional;
28 import java.util.stream.Collectors;
30 import javax.servlet.http.HttpServletRequest;
31 import javax.ws.rs.Consumes;
32 import javax.ws.rs.DefaultValue;
33 import javax.ws.rs.PUT;
34 import javax.ws.rs.Path;
35 import javax.ws.rs.PathParam;
36 import javax.ws.rs.Produces;
37 import javax.ws.rs.QueryParam;
38 import javax.ws.rs.core.Context;
39 import javax.ws.rs.core.HttpHeaders;
40 import javax.ws.rs.core.MediaType;
41 import javax.ws.rs.core.MultivaluedHashMap;
42 import javax.ws.rs.core.MultivaluedMap;
43 import javax.ws.rs.core.Response;
44 import javax.ws.rs.core.Response.Status;
45 import javax.ws.rs.core.UriInfo;
47 import org.apache.tinkerpop.gremlin.process.traversal.dsl.graph.GraphTraversalSource;
48 import org.janusgraph.core.SchemaViolationException;
49 import org.onap.aai.concurrent.AaiCallable;
50 import org.onap.aai.exceptions.AAIException;
51 import org.onap.aai.introspection.ModelType;
52 import org.onap.aai.rest.db.HttpEntry;
53 import org.onap.aai.rest.dsl.DslQueryProcessor;
54 import org.onap.aai.rest.enums.QueryVersion;
55 import org.onap.aai.rest.search.GenericQueryProcessor;
56 import org.onap.aai.rest.search.GremlinServerSingleton;
57 import org.onap.aai.rest.search.QueryProcessorType;
58 import org.onap.aai.restcore.HttpMethod;
59 import org.onap.aai.serialization.db.DBSerializer;
60 import org.onap.aai.serialization.engines.TransactionalGraphEngine;
61 import org.onap.aai.serialization.queryformats.Format;
62 import org.onap.aai.serialization.queryformats.FormatFactory;
63 import org.onap.aai.serialization.queryformats.Formatter;
64 import org.onap.aai.serialization.queryformats.SubGraphStyle;
65 import org.onap.aai.setup.SchemaVersion;
66 import org.onap.aai.setup.SchemaVersions;
67 import org.onap.aai.transforms.XmlFormatTransformer;
68 import org.onap.aai.util.AAIConfig;
69 import org.onap.aai.util.TraversalConstants;
70 import org.slf4j.Logger;
71 import org.slf4j.LoggerFactory;
72 import org.springframework.beans.factory.annotation.Autowired;
73 import org.springframework.beans.factory.annotation.Value;
75 import com.google.gson.JsonElement;
76 import com.google.gson.JsonObject;
77 import com.google.gson.JsonParser;
79 import io.micrometer.core.annotation.Timed;
81 @Path("{version: v[1-9][0-9]*|latest}/dsl")
83 public class DslConsumer extends TraversalConsumer {
85 private HttpEntry traversalUriHttpEntry;
87 private QueryProcessorType processorType = QueryProcessorType.LOCAL_GROOVY;
89 private static final Logger LOGGER = LoggerFactory.getLogger(DslConsumer.class);
91 private DslQueryProcessor dslQueryProcessor;
93 private SchemaVersions schemaVersions;
95 private String basePath;
97 private GremlinServerSingleton gremlinServerSingleton;
98 private final QueryVersion DEFAULT_VERSION = QueryVersion.V1;
99 private QueryVersion dslApiVersion = DEFAULT_VERSION;
101 private XmlFormatTransformer xmlFormatTransformer;
104 public DslConsumer(HttpEntry traversalUriHttpEntry, DslQueryProcessor dslQueryProcessor,
105 SchemaVersions schemaVersions, GremlinServerSingleton gremlinServerSingleton,
106 XmlFormatTransformer xmlFormatTransformer,
107 @Value("${schema.uri.base.path}") String basePath) {
108 this.traversalUriHttpEntry = traversalUriHttpEntry;
109 this.dslQueryProcessor = dslQueryProcessor;
110 this.schemaVersions = schemaVersions;
111 this.gremlinServerSingleton = gremlinServerSingleton;
112 this.xmlFormatTransformer = xmlFormatTransformer;
113 this.basePath = basePath;
117 @Consumes({MediaType.APPLICATION_JSON})
118 @Produces({MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML})
119 public Response executeQuery(String content, @PathParam("version") String versionParam,
120 @DefaultValue("graphson") @QueryParam("format") String queryFormat,
121 @DefaultValue("no_op") @QueryParam("subgraph") String subgraph,
122 @DefaultValue("all") @QueryParam("validate") String validate, @Context HttpHeaders headers,
123 @Context HttpServletRequest req, @Context UriInfo info,
124 @DefaultValue("-1") @QueryParam("resultIndex") String resultIndex,
125 @DefaultValue("-1") @QueryParam("resultSize") String resultSize) {
126 Set<String> roles = this.getRoles(req.getUserPrincipal());
128 return runner(TraversalConstants.AAI_TRAVERSAL_DSL_TIMEOUT_ENABLED,
129 TraversalConstants.AAI_TRAVERSAL_DSL_TIMEOUT_APP,
130 TraversalConstants.AAI_TRAVERSAL_DSL_TIMEOUT_LIMIT, headers, info, HttpMethod.PUT,
133 public Response process() throws Exception {
134 return (processExecuteQuery(content, req, versionParam, queryFormat, subgraph,
135 validate, headers, info, resultIndex, resultSize, roles));
140 public Response processExecuteQuery(String content, HttpServletRequest req, String versionParam,
141 String queryFormat, String subgraph, String validate, HttpHeaders headers, UriInfo info,
142 String resultIndex, String resultSize, Set<String> roles) {
144 String sourceOfTruth = headers.getRequestHeaders().getFirst("X-FromAppId");
145 String dslOverride = headers.getRequestHeaders().getFirst("X-DslOverride");
147 Optional<String> dslApiVersionHeader =
148 Optional.ofNullable(headers.getRequestHeaders().getFirst("X-DslApiVersion"));
149 if (dslApiVersionHeader.isPresent()) {
151 dslApiVersion = QueryVersion.valueOf(dslApiVersionHeader.get());
152 } catch (IllegalArgumentException e) {
153 LOGGER.debug("Defaulting DSL Api Version to " + DEFAULT_VERSION);
158 SchemaVersion version = new SchemaVersion(versionParam);
160 TransactionalGraphEngine dbEngine = null;
163 req.getRequestURL().toString().replaceAll("/(v[0-9]+|latest)/.*", "/");
164 traversalUriHttpEntry.setHttpEntryProperties(version, serverBase);
165 traversalUriHttpEntry.setPaginationParameters(resultIndex, resultSize);
166 dbEngine = traversalUriHttpEntry.getDbEngine();
167 JsonObject input = JsonParser.parseString(content).getAsJsonObject();
168 JsonElement dslElement = input.get("dsl");
170 if (dslElement != null) {
171 dsl = dslElement.getAsString();
174 boolean isDslOverride = dslOverride != null
175 && !AAIConfig.get(TraversalConstants.DSL_OVERRIDE).equals("false")
176 && dslOverride.equals(AAIConfig.get(TraversalConstants.DSL_OVERRIDE));
179 dslQueryProcessor.setStartNodeValidationFlag(false);
182 dslQueryProcessor.setValidationRules(validate);
184 Format format = Format.getFormat(queryFormat);
186 if (isAggregate(format)) {
187 dslQueryProcessor.setAggregate(true);
190 if (isHistory(format)) {
191 validateHistoryParams(format, info.getQueryParameters());
194 GraphTraversalSource traversalSource =
195 getTraversalSource(dbEngine, format, info, roles);
197 GenericQueryProcessor processor =
198 new GenericQueryProcessor.Builder(dbEngine, gremlinServerSingleton)
199 .queryFrom(dsl, "dsl").queryProcessor(dslQueryProcessor).version(dslApiVersion)
200 .processWith(processorType).format(format).uriParams(info.getQueryParameters())
201 .traversalSource(isHistory(format), traversalSource).create();
203 SubGraphStyle subGraphStyle = SubGraphStyle.valueOf(subgraph);
204 List<Object> vertTemp = processor.execute(subGraphStyle);
206 // Dedup if duplicate objects are returned in each array in the aggregate format
208 List<Object> vertTempDedupedObjectList = dedupObjectInAggregateFormatResult(vertTemp);
210 List<Object> vertices;
211 if (isAggregate(format)) {
212 vertices = traversalUriHttpEntry
213 .getPaginatedVertexListForAggregateFormat(vertTempDedupedObjectList);
215 vertices = traversalUriHttpEntry.getPaginatedVertexList(vertTemp);
218 DBSerializer serializer =
219 new DBSerializer(version, dbEngine, ModelType.MOXY, sourceOfTruth);
220 FormatFactory ff = new FormatFactory(traversalUriHttpEntry.getLoader(), serializer,
221 schemaVersions, this.basePath, serverBase);
223 MultivaluedMap<String, String> mvm = new MultivaluedHashMap<>();
224 mvm.putAll(info.getQueryParameters());
225 if (isHistory(format)) {
226 mvm.putSingle("startTs", Long.toString(getStartTime(format, mvm)));
227 mvm.putSingle("endTs", Long.toString(getEndTime(mvm)));
229 Formatter formatter = ff.get(format, mvm);
231 final Map<String, List<String>> propertiesMap = processor.getPropertiesMap();
233 if (propertiesMap != null && !propertiesMap.isEmpty()) {
234 result = formatter.output(vertices, propertiesMap).toString();
236 result = formatter.output(vertices).toString();
239 String acceptType = headers.getHeaderString("Accept");
241 if (acceptType == null) {
242 acceptType = MediaType.APPLICATION_JSON;
245 if (MediaType.APPLICATION_XML_TYPE.isCompatible(MediaType.valueOf(acceptType))) {
246 result = xmlFormatTransformer.transform(result);
249 if (traversalUriHttpEntry.isPaginated()) {
250 response = Response.status(Status.OK).type(acceptType)
251 .header("total-results", traversalUriHttpEntry.getTotalVertices())
252 .header("total-pages", traversalUriHttpEntry.getTotalPaginationBuckets())
253 .entity(result).build();
255 response = Response.status(Status.OK).type(acceptType).entity(result).build();
258 } catch (AAIException e) {
259 response = consumerExceptionResponseGenerator(headers, info, HttpMethod.PUT, e);
260 } catch (SchemaViolationException sve) {
261 AAIException ex = new AAIException("AAI_4020", sve);
262 response = consumerExceptionResponseGenerator(headers, info, HttpMethod.PUT, ex);
263 } catch (Exception e) {
264 AAIException ex = new AAIException("AAI_4000", e);
265 response = consumerExceptionResponseGenerator(headers, info, HttpMethod.PUT, ex);
267 if (dbEngine != null) {
276 private List<Object> dedupObjectInAggregateFormatResult(List<Object> vertTemp) {
277 List<Object> vertTempDedupedObjectList = new ArrayList<Object>();
278 Iterator<Object> itr = vertTemp.listIterator();
279 while (itr.hasNext()) {
280 Object o = itr.next();
281 if (o instanceof ArrayList) {
282 vertTempDedupedObjectList
283 .add(((ArrayList) o).stream().distinct().collect(Collectors.toList()));
286 return vertTempDedupedObjectList;