Update the license for 2017-2018 license
[aai/traversal.git] / aai-traversal / src / main / java / org / onap / aai / rest / QueryConsumer.java
1 /**
2  * ============LICENSE_START=======================================================
3  * org.onap.aai
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
10  *
11  *    http://www.apache.org/licenses/LICENSE-2.0
12  *
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=========================================================
19  */
20 package org.onap.aai.rest;
21
22 import java.net.URI;
23 import java.util.ArrayList;
24 import java.util.LinkedHashSet;
25 import java.util.List;
26 import java.util.Set;
27 import java.util.concurrent.TimeUnit;
28 import java.util.concurrent.Callable;
29
30 import javax.servlet.http.HttpServletRequest;
31 import javax.ws.rs.Consumes;
32 import javax.ws.rs.DefaultValue;
33 import javax.ws.rs.Encoded;
34 import javax.ws.rs.PUT;
35 import javax.ws.rs.Path;
36 import javax.ws.rs.PathParam;
37 import javax.ws.rs.Produces;
38 import javax.ws.rs.QueryParam;
39 import javax.ws.rs.core.Context;
40 import javax.ws.rs.core.HttpHeaders;
41 import javax.ws.rs.core.MediaType;
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;
46
47 import org.apache.tinkerpop.gremlin.structure.Vertex;
48 import org.onap.aai.dbmap.DBConnectionType;
49 import org.onap.aai.exceptions.AAIException;
50 import org.onap.aai.introspection.ModelType;
51 import org.onap.aai.introspection.Version;
52 import org.onap.aai.logging.ErrorLogHelper;
53 import org.onap.aai.parsers.query.QueryParser;
54 import org.onap.aai.rest.db.HttpEntry;
55 import org.onap.aai.rest.search.CustomQueryConfig;
56 import org.onap.aai.rest.search.GenericQueryProcessor;
57 import org.onap.aai.rest.search.GremlinServerSingleton;
58 import org.onap.aai.rest.search.QueryProcessorType;
59 import org.onap.aai.restcore.HttpMethod;
60 import org.onap.aai.restcore.RESTAPI;
61 import org.onap.aai.restcore.util.URITools;
62 import org.onap.aai.serialization.db.DBSerializer;
63 import org.onap.aai.serialization.engines.QueryStyle;
64 import org.onap.aai.serialization.engines.TransactionalGraphEngine;
65 import org.onap.aai.serialization.queryformats.Format;
66 import org.onap.aai.serialization.queryformats.FormatFactory;
67 import org.onap.aai.serialization.queryformats.Formatter;
68 import org.onap.aai.serialization.queryformats.SubGraphStyle;
69 import com.att.eelf.configuration.EELFLogger;
70 import com.att.eelf.configuration.EELFManager;
71 import org.onap.aai.logging.LoggingContext;
72 import org.onap.aai.logging.LoggingContext.StatusCode;
73 import org.onap.aai.logging.StopWatch;
74
75 import com.google.gson.JsonElement;
76 import com.google.gson.JsonObject;
77 import com.google.gson.JsonParser;
78 import org.onap.aai.util.AAIConstants;
79
80 @Path("{version: v9|v1[0123]}/query")
81 public class QueryConsumer extends RESTAPI {
82
83     private static final String DEPTH = "depth";
84         
85         /** The introspector factory type. */
86         private ModelType introspectorFactoryType = ModelType.MOXY;
87         
88         private QueryProcessorType processorType = QueryProcessorType.LOCAL_GROOVY;
89         /** The query style. */
90         private QueryStyle queryStyle = QueryStyle.TRAVERSAL;
91         
92         private static final String TARGET_ENTITY = "DB";
93         private static final EELFLogger LOGGER = EELFManager.getInstance().getLogger(QueryConsumer.class);
94         
95         @PUT
96         @Consumes({ MediaType.APPLICATION_JSON})
97         @Produces({ MediaType.APPLICATION_JSON})
98         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){
99                 return runner(AAIConstants.AAI_TRAVERSAL_TIMEOUT_ENABLED,
100                                 AAIConstants.AAI_TRAVERSAL_TIMEOUT_APP,
101                                 AAIConstants.AAI_TRAVERSAL_TIMEOUT_LIMIT,
102                                 headers,
103                                 info,
104                                 HttpMethod.GET,
105                                 new Callable<Response>() {
106                                         @Override
107                                         public Response call() {
108                                                 return processExecuteQuery(content, versionParam, uri, queryFormat, subgraph, headers, info, req);
109                                         }
110                                 }
111                 );
112         }
113
114         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) {
115
116                 String methodName = "executeQuery";
117                 String sourceOfTruth = headers.getRequestHeaders().getFirst("X-FromAppId");
118                 String realTime = headers.getRequestHeaders().getFirst("Real-Time");
119                 String queryProcessor = headers.getRequestHeaders().getFirst("QueryProcessor");
120                 QueryProcessorType processorType = this.processorType;
121                 Response response = null;
122                 TransactionalGraphEngine dbEngine = null;
123                 try {
124                         LoggingContext.save();
125                         this.checkQueryParams(info.getQueryParameters());
126                         Format format = Format.valueOf(queryFormat);
127                         if (queryProcessor != null) {
128                                 processorType = QueryProcessorType.valueOf(queryProcessor);
129                         }
130                         SubGraphStyle subGraphStyle = SubGraphStyle.valueOf(subgraph);
131                         JsonParser parser = new JsonParser();
132                         
133                         JsonObject input = parser.parse(content).getAsJsonObject();
134                         
135                         JsonElement startElement = input.get("start");
136                         JsonElement queryElement = input.get("query");
137                         JsonElement gremlinElement = input.get("gremlin");
138                         JsonElement dslElement = input.get("dsl");
139                         List<URI> startURIs = new ArrayList<>();
140                         String queryURI = "";
141                         String gremlin = "";
142                         String dsl = "";
143                         
144                         Version version = Version.valueOf(versionParam);
145                         DBConnectionType type = this.determineConnectionType(sourceOfTruth, realTime);
146                         HttpEntry httpEntry = new HttpEntry(version, introspectorFactoryType, queryStyle, type);
147                         dbEngine = httpEntry.getDbEngine();
148
149                         if (startElement != null) {
150         
151                                 if (startElement.isJsonArray()) {
152                                         for (JsonElement element : startElement.getAsJsonArray()) {
153                                                 startURIs.add(new URI(element.getAsString()));
154                                         }
155                                 } else {
156                                         startURIs.add(new URI(startElement.getAsString()));
157                                 }
158                         }
159                         if (queryElement != null) {
160                                 queryURI = queryElement.getAsString();
161                         }
162                         if (gremlinElement != null) {
163                                 gremlin = gremlinElement.getAsString();
164                         }
165                         if (dslElement != null) {
166                                 dsl = dslElement.getAsString();
167                         }
168                         URI queryURIObj = new URI(queryURI);
169                         
170                         CustomQueryConfig customQueryConfig = getCustomQueryConfig(queryURIObj);
171                         if ( customQueryConfig != null ) {
172                                 List<String> missingRequiredQueryParameters =  checkForMissingQueryParameters( customQueryConfig.getQueryRequiredProperties(), URITools.getQueryMap(queryURIObj));
173                                 if ( !missingRequiredQueryParameters.isEmpty() ) {
174                                         return( createMessageMissingQueryRequiredParameters( missingRequiredQueryParameters, headers, info, req));
175                                 }
176                         } else if ( queryElement != null ) {
177                                 return( createMessageInvalidQuerySection( queryURI, headers, info, req));
178                         }
179                         
180
181                         GenericQueryProcessor processor = null;
182                         
183                         LoggingContext.targetEntity(TARGET_ENTITY);
184                         LoggingContext.targetServiceName(methodName);
185                         LoggingContext.startTime();
186                         StopWatch.conditionalStart();
187                         
188                         if (!startURIs.isEmpty()) {
189                                 Set<Vertex> vertexSet = new LinkedHashSet<>();
190                                 QueryParser uriQuery;
191                                 List<Vertex> vertices;
192                                 for (URI startUri : startURIs) {
193                                         uriQuery = dbEngine.getQueryBuilder().createQueryFromURI(startUri, URITools.getQueryMap(startUri));
194                                         vertices = uriQuery.getQueryBuilder().toList();
195                                         vertexSet.addAll(vertices);
196                                 }
197
198                                 processor = new GenericQueryProcessor.Builder(dbEngine)
199                                                 .startFrom(vertexSet).queryFrom(queryURIObj)
200                                                 .processWith(processorType).create();
201                         } else if (!queryURI.equals("")){
202                                 processor =  new GenericQueryProcessor.Builder(dbEngine)
203                                                 .queryFrom(queryURIObj)
204                                                 .processWith(processorType).create();
205                         } else if(!dsl.equals("")){
206                                 processor =  new GenericQueryProcessor.Builder(dbEngine)
207                                                 .queryFrom(dsl, "dsl")
208                                                 .processWith(processorType).create();
209                         }else {
210                                 processor =  new GenericQueryProcessor.Builder(dbEngine)
211                                                 .queryFrom(gremlin, "gremlin")
212                                                 .processWith(processorType).create();
213                         }
214                         String result = "";
215                         List<Object> vertices = processor.execute(subGraphStyle);
216                 
217                         DBSerializer serializer = new DBSerializer(version, dbEngine, introspectorFactoryType, sourceOfTruth);
218                         FormatFactory ff = new FormatFactory(httpEntry.getLoader(), serializer);
219                         
220                         Formatter formater =  ff.get(format, info.getQueryParameters());
221                 
222                         result = formater.output(vertices).toString();
223
224                         double msecs = StopWatch.stopIfStarted();
225                         LoggingContext.elapsedTime((long)msecs,TimeUnit.MILLISECONDS);
226                         LoggingContext.successStatusFields();
227                         LOGGER.info ("Completed");
228                         
229                         
230                         response = Response.status(Status.OK)
231                                         .type(MediaType.APPLICATION_JSON)
232                                         .entity(result).build();
233                 
234                 } catch (AAIException e) {
235                         response = consumerExceptionResponseGenerator(headers, info, HttpMethod.GET, e);
236                 } catch (Exception e ) {
237                         AAIException ex = new AAIException("AAI_4000", e);
238                         response = consumerExceptionResponseGenerator(headers, info, HttpMethod.GET, ex);
239                 } finally {
240                         LoggingContext.restoreIfPossible();
241                         LoggingContext.successStatusFields();
242                         if (dbEngine != null) {
243                                 dbEngine.rollback();
244                         }
245                         
246                 }
247                 
248                 return response;
249         }
250         
251         public void checkQueryParams(MultivaluedMap<String, String> params) throws AAIException {
252                 
253                 if (params.containsKey(DEPTH) && params.getFirst(DEPTH).matches("\\d+")) {
254                         String depth = params.getFirst(DEPTH);
255                         Integer i = Integer.parseInt(depth);
256                         if (i > 1) {
257                                 throw new AAIException("AAI_3303");
258                         }
259                 }
260                 
261                 
262         }
263         
264         private List<String> checkForMissingQueryParameters( List<String> requiredParameters, MultivaluedMap<String, String> queryParams ) {
265                 List<String> result = new ArrayList<>();
266
267                 for ( String param : requiredParameters ) {
268                         if ( !queryParams.containsKey(param)) {
269                                 result.add(param);
270                         }
271                 }
272                 return result;
273         }
274         
275         private CustomQueryConfig getCustomQueryConfig(URI uriObj ) {
276                 
277                 GremlinServerSingleton gremlinServerSingleton;
278                 CustomQueryConfig customQueryConfig;
279                 String path = uriObj.getPath();
280
281                 String[] parts = path.split("/");
282                 boolean hasQuery = false;
283                 for ( String part:parts ) {
284                         if  ( hasQuery) {
285                                 gremlinServerSingleton = GremlinServerSingleton.getInstance();
286                                 return gremlinServerSingleton.getCustomQueryConfig(part);
287                         }
288                         if ( "query".equals(part)) {
289                                 hasQuery = true;
290                         }
291                 }
292                 
293                 return null;
294                 
295         }
296         
297         private Response createMessageMissingQueryRequiredParameters(List<String> missingRequiredQueryParams, HttpHeaders headers, UriInfo info, HttpServletRequest req) {
298                 AAIException e = new AAIException("AAI_3013");
299                 
300                 ArrayList<String> templateVars = new ArrayList<>();
301
302                 if (templateVars.isEmpty()) {
303                         templateVars.add(missingRequiredQueryParams.toString());
304                 }
305
306                 Response response = Response
307                                 .status(e.getErrorObject().getHTTPResponseCode())
308                                 .entity(ErrorLogHelper.getRESTAPIErrorResponse(headers.getAcceptableMediaTypes(), e, 
309                                                 templateVars)).build(); 
310
311                 return response;
312         } 
313         
314         private Response createMessageInvalidQuerySection(String invalidQuery, HttpHeaders headers, UriInfo info, HttpServletRequest req) {
315                 AAIException e = new AAIException("AAI_3014");
316                 
317                 ArrayList<String> templateVars = new ArrayList<>();
318
319                 if (templateVars.isEmpty()) {
320                         templateVars.add(invalidQuery);
321                 }
322
323                 Response response = Response
324                                 .status(e.getErrorObject().getHTTPResponseCode())
325                                 .entity(ErrorLogHelper.getRESTAPIErrorResponse(headers.getAcceptableMediaTypes(), e, 
326                                                 templateVars)).build(); 
327
328                 return response;
329         } 
330
331
332 }