dd5d42c61cb9d4bb7b48f8dcbaf159f3015890d0
[aai/aai-common.git] / aai-core / src / main / java / org / onap / aai / rest / db / HttpEntry.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.db;
21
22
23 import java.io.IOException;
24 import java.io.UnsupportedEncodingException;
25 import java.lang.reflect.InvocationTargetException;
26 import java.net.MalformedURLException;
27 import java.net.URI;
28 import java.net.URISyntaxException;
29 import java.util.ArrayList;
30 import java.util.HashMap;
31 import java.util.List;
32 import java.util.Map;
33 import java.util.Set;
34 import java.util.concurrent.TimeUnit;
35 import java.util.stream.Collectors;
36
37 import javax.ws.rs.core.HttpHeaders;
38 import javax.ws.rs.core.MediaType;
39 import javax.ws.rs.core.MultivaluedMap;
40 import javax.ws.rs.core.Response;
41 import javax.ws.rs.core.Response.Status;
42 import javax.ws.rs.core.UriBuilder;
43
44 import com.att.eelf.configuration.EELFLogger;
45 import com.att.eelf.configuration.EELFManager;
46 import com.fasterxml.jackson.databind.JsonNode;
47 import com.fasterxml.jackson.databind.ObjectMapper;
48 import com.github.fge.jsonpatch.JsonPatchException;
49 import com.github.fge.jsonpatch.mergepatch.JsonMergePatch;
50 import org.apache.commons.lang.StringUtils;
51 import org.apache.tinkerpop.gremlin.structure.Graph;
52 import org.apache.tinkerpop.gremlin.structure.Vertex;
53 import org.janusgraph.core.JanusGraphException;
54 import org.javatuples.Pair;
55 import org.onap.aai.db.props.AAIProperties;
56 import org.onap.aai.dbmap.DBConnectionType;
57 import org.onap.aai.domain.responseMessage.AAIResponseMessage;
58 import org.onap.aai.domain.responseMessage.AAIResponseMessageDatum;
59 import org.onap.aai.exceptions.AAIException;
60 import org.onap.aai.extensions.AAIExtensionMap;
61 import org.onap.aai.extensions.ExtensionController;
62 import org.onap.aai.introspection.*;
63 import org.onap.aai.introspection.exceptions.AAIUnknownObjectException;
64 import org.onap.aai.logging.ErrorLogHelper;
65 import org.onap.aai.logging.LoggingContext;
66 import org.onap.aai.nodes.NodeIngestor;
67 import org.onap.aai.parsers.query.QueryParser;
68 import org.onap.aai.parsers.uri.URIToExtensionInformation;
69
70 import org.onap.aai.rest.ueb.UEBNotification;
71 import org.onap.aai.restcore.HttpMethod;
72 import org.onap.aai.schema.enums.ObjectMetadata;
73 import org.onap.aai.serialization.db.DBSerializer;
74 import org.onap.aai.serialization.engines.JanusGraphDBEngine;
75 import org.onap.aai.serialization.engines.QueryStyle;
76 import org.onap.aai.serialization.engines.TransactionalGraphEngine;
77 import org.onap.aai.serialization.engines.query.QueryEngine;
78 import org.onap.aai.serialization.queryformats.Format;
79 import org.onap.aai.serialization.queryformats.FormatFactory;
80 import org.onap.aai.serialization.queryformats.Formatter;
81 import org.onap.aai.setup.SchemaVersion;
82 import org.onap.aai.setup.SchemaVersions;
83 import org.onap.aai.util.AAIConfig;
84 import org.springframework.beans.factory.annotation.Autowired;
85 import org.springframework.beans.factory.annotation.Value;
86
87 /**
88  * The Class HttpEntry.
89  */
90 public class HttpEntry {
91
92         private static final EELFLogger LOGGER = EELFManager.getInstance().getLogger(HttpEntry.class);
93         private static final String TARGET_ENTITY = "DB";
94
95         private  ModelType introspectorFactoryType;
96         
97         private  QueryStyle queryStyle;
98         
99         private SchemaVersion version;
100         
101         private Loader loader;
102         
103         private TransactionalGraphEngine dbEngine;
104                 
105         private boolean processSingle = true;
106
107         private int paginationBucket = -1;
108         private int paginationIndex = -1;
109         private int totalVertices = 0;
110         private int totalPaginationBuckets = 0;
111
112         @Autowired
113         private NodeIngestor nodeIngestor;
114
115         @Autowired
116         private LoaderFactory loaderFactory;
117
118         @Autowired
119         private SchemaVersions schemaVersions;
120
121         @Value("${schema.uri.base.path}")
122         private String basePath;
123
124         private UEBNotification notification;
125
126         /**
127          * Instantiates a new http entry.
128          *
129          * @param modelType the model type
130          * @param queryStyle the query style
131          */
132         public HttpEntry(ModelType modelType, QueryStyle queryStyle) {
133                 this.introspectorFactoryType = modelType;
134                 this.queryStyle = queryStyle;
135         }
136
137         public HttpEntry setHttpEntryProperties(SchemaVersion version, DBConnectionType connectionType){
138                 this.version = version;
139                 this.loader = loaderFactory.createLoaderForVersion(introspectorFactoryType, version);
140                 this.dbEngine = new JanusGraphDBEngine(
141                                 queryStyle,
142                                 connectionType,
143                                 loader);
144
145                 getDbEngine().startTransaction();
146                 this.notification = new UEBNotification(loader, loaderFactory, schemaVersions);
147                 return this;
148         }
149
150
151      public HttpEntry setHttpEntryProperties(SchemaVersion version, DBConnectionType connectionType, UEBNotification notification){
152                 this.version = version;
153                 this.loader = loaderFactory.createLoaderForVersion(introspectorFactoryType, version);
154                 this.dbEngine = new JanusGraphDBEngine(
155                                 queryStyle,
156                                 connectionType,
157                                 loader);
158
159                 this.notification = notification;
160                 //start transaction on creation
161                 getDbEngine().startTransaction();
162                 return this;
163         }
164         
165
166         /**
167          * Gets the introspector factory type.
168          *
169          * @return the introspector factory type
170          */
171         public ModelType getIntrospectorFactoryType() {
172                 return introspectorFactoryType;
173         }
174
175         /**
176          * Gets the query style.
177          *
178          * @return the query style
179          */
180         public QueryStyle getQueryStyle() {
181                 return queryStyle;
182         }
183
184         /**
185          * Gets the version.
186          *
187          * @return the version
188          */
189         public SchemaVersion getVersion() {
190                 return version;
191         }
192
193         /**
194          * Gets the loader.
195          *
196          * @return the loader
197          */
198         public Loader getLoader() {
199                 return loader;
200         }
201
202         /**
203          * Gets the db engine.
204          *
205          * @return the db engine
206          */
207         public TransactionalGraphEngine getDbEngine() {
208                 return dbEngine;
209         }
210
211         public Pair<Boolean, List<Pair<URI, Response>>> process (List<DBRequest> requests, String sourceOfTruth) throws AAIException {
212                 return this.process(requests, sourceOfTruth, true);
213         }
214
215
216         /**
217          * Checks the pagination bucket and pagination index variables to determine whether or not the user
218          * requested paginated results
219          *
220          * @return a boolean true/false of whether the user requested paginated results
221          */
222         public boolean isPaginated(){
223                 return this.paginationBucket > -1 && this.paginationIndex > -1;
224         }
225
226         /**
227          * Setter for the pagination bucket variable which stores in this object the size of results to return
228          * @param pb
229          */
230         public void setPaginationBucket(int pb){
231                 this.paginationBucket = pb;
232         }
233
234         /**
235          * Returns the pagination size
236          * @return integer of the size of results to be returned when paginated
237          */
238         public int getPaginationBucket(){
239                 return this.paginationBucket;
240         }
241
242         /**
243          * Sets the pagination index that was passed in by the user, to determine which index or results to retrieve when
244          * paginated
245          * @param pi
246          */
247         public void setPaginationIndex(int pi){
248                 if(pi == 0){
249                         pi = 1;
250                 }
251                 this.paginationIndex = pi;
252         }
253
254         /**
255          * Getter to return the pagination index requested by the user when requesting paginated results
256          * @return
257          */
258         public int getPaginationIndex(){
259                 return this.paginationIndex;
260         }
261
262         /**
263          * Sets the total vertices variables and calculates the amount of pages based on size and total vertices
264          * @param totalVertices
265          * @param paginationBucketSize
266          */
267         public void setTotalsForPaging(int totalVertices, int paginationBucketSize){
268                 this.totalVertices = totalVertices;
269                 //set total number of buckets equal to full pages
270                 this.totalPaginationBuckets = totalVertices/paginationBucketSize;
271                 //conditionally add a page for the remainder
272                 if(totalVertices % paginationBucketSize > 0){
273                         this.totalPaginationBuckets++;
274                 }
275         }
276
277         /**
278          * @return the total amount of pages
279          */
280         public int getTotalPaginationBuckets(){
281                 return this.totalPaginationBuckets;
282         }
283
284         /**
285          *
286          * @return the total number of vertices when paginated
287          */
288         public int getTotalVertices(){
289                 return this.totalVertices;
290         }
291
292         /**
293          * Process.
294          * @param requests the requests
295          * @param sourceOfTruth the source of truth
296          *
297          * @return the pair
298          * @throws AAIException the AAI exception
299          */
300         public Pair<Boolean, List<Pair<URI, Response>>> process (List<DBRequest> requests, String sourceOfTruth, boolean enableResourceVersion) throws AAIException {
301
302                 DBSerializer serializer = new DBSerializer(version, dbEngine, introspectorFactoryType, sourceOfTruth);
303                 String methodName = "process";
304                 Response response;
305                 Introspector obj = null;
306                 QueryParser query = null;
307                 URI uri = null;
308                 String transactionId = null;
309                 int depth = AAIProperties.MAXIMUM_DEPTH;
310                 Format format = null;
311                 List<Pair<URI,Response>> responses = new ArrayList<>();
312                 MultivaluedMap<String, String> params = null;
313                 HttpMethod method = null;
314                 String uriTemp = "";
315                 Boolean success = true;
316                 QueryEngine queryEngine = dbEngine.getQueryEngine();
317                 int maxRetries = 10;
318                 int retry = 0;
319         
320                 LoggingContext.save();
321                 for (DBRequest request : requests) {
322                         response = null;
323                         Status status = Status.NOT_FOUND;
324                         method = request.getMethod();
325                         try {
326                                 for (retry = 0; retry < maxRetries; ++retry) {
327                                         try {
328
329                                                 LoggingContext.targetEntity(TARGET_ENTITY);
330                                                 LoggingContext.targetServiceName(methodName + " " + method);
331
332                                                 obj = request.getIntrospector();
333                                                 query = request.getParser();
334                                                 transactionId = request.getTransactionId();
335                                                 uriTemp = request.getUri().getRawPath().replaceFirst("^v\\d+/", "");
336                                                 uri = UriBuilder.fromPath(uriTemp).build();
337                                                 LoggingContext.startTime();
338                                                 List<Vertex> vertTemp;
339                                                 List<Vertex> vertices;
340                                                 if(this.isPaginated()) {
341                                                         vertTemp = query.getQueryBuilder().toList();
342                                                         this.setTotalsForPaging(vertTemp.size(), this.paginationBucket);
343                                                         vertices = vertTemp.subList(((this.paginationIndex - 1) * this.paginationBucket), Math.min((this.paginationBucket * this.paginationIndex), vertTemp.size()));
344                                                 }else{
345                                                         vertices = query.getQueryBuilder().toList();
346                                                 }
347                                                 boolean isNewVertex = false;
348                                                 String outputMediaType = getMediaType(request.getHeaders().getAcceptableMediaTypes());
349                                                 String result = null;
350                                                 params = request.getInfo().getQueryParameters(false);
351                                                 depth = setDepth(obj, params.getFirst("depth"));
352                                                 if (params.containsKey("format")) {
353                                                         format = Format.getFormat(params.getFirst("format"));
354                                                 }
355                                                 String cleanUp = params.getFirst("cleanup");
356                                                 String requestContext = "";
357                                                 List<String> requestContextList = request.getHeaders().getRequestHeader("aai-request-context");
358                                                 if (requestContextList != null) {
359                                                         requestContext = requestContextList.get(0);
360                                                 }
361                                         
362                                                 if (cleanUp == null) {
363                                                         cleanUp = "false";
364                                                 }
365                                                 if (vertices.size() > 1 && processSingle && !method.equals(HttpMethod.GET)) {
366                                                         if (method.equals(HttpMethod.DELETE)) {
367                                                                 LoggingContext.restoreIfPossible();
368                                                                 throw new AAIException("AAI_6138");
369                                                         } else {
370                                                                 LoggingContext.restoreIfPossible();
371                                                                 throw new AAIException("AAI_6137");
372                                                         }
373                                                 }
374                                                 if (method.equals(HttpMethod.PUT)) {
375                                                         String resourceVersion = (String)obj.getValue("resource-version");
376                                                         if (vertices.isEmpty()) {
377                                                                 if (enableResourceVersion) {
378                                                                         serializer.verifyResourceVersion("create", query.getResultType(), "", resourceVersion, obj.getURI());
379                                                                 }
380                                                                 isNewVertex = true;
381                                                         } else {
382                                                                 if (enableResourceVersion) {
383                                                                         serializer.verifyResourceVersion("update", query.getResultType(), vertices.get(0).<String>property("resource-version").orElse(null), resourceVersion, obj.getURI());
384                                                                 }
385                                                                 isNewVertex = false;
386                                                         }
387                                                 } else {
388                                                         if (vertices.isEmpty()) {
389                                                                 String msg = createNotFoundMessage(query.getResultType(), request.getUri());
390                                                                 throw new AAIException("AAI_6114", msg);
391                                                         } else {
392                                                                 isNewVertex = false;
393                                                         }
394                                                 }
395                                                 Vertex v = null;
396                                                 if (!isNewVertex) {
397                                                         v = vertices.get(0);
398                                                 }
399                                                 HashMap<String, Introspector> relatedObjects = new HashMap<>();
400                                                 switch (method) {
401                                                         case GET:
402                                                                 String nodeOnly = params.getFirst("nodes-only");
403                                                                 boolean isNodeOnly = nodeOnly != null;
404
405                                                                 if (format == null) {
406                                                                         obj = this.getObjectFromDb(vertices, serializer, query, obj, request.getUri(), depth, isNodeOnly, cleanUp);
407
408
409                                                                         LoggingContext.elapsedTime((long) serializer.getDBTimeMsecs(), TimeUnit.MILLISECONDS);
410                                                                         LOGGER.info ("Completed");
411                                                                         LoggingContext.restoreIfPossible();
412
413                                                                         if (obj != null) {
414                                                                                 status = Status.OK;
415                                                                                 MarshallerProperties properties;
416                                                                                 if (!request.getMarshallerProperties().isPresent()) {
417                                                                                         properties = new MarshallerProperties.Builder(org.onap.aai.restcore.MediaType.getEnum(outputMediaType)).build();
418                                                                                 } else {
419                                                                                         properties = request.getMarshallerProperties().get();
420                                                                                 }
421                                                                                 result = obj.marshal(properties);
422                                                                         }
423                                                                 } else {
424                                                                         FormatFactory ff = new FormatFactory(loader, serializer, schemaVersions, basePath + "/");
425                                                                         Formatter formatter =  ff.get(format, params);
426                                                                         result = formatter.output(vertices.stream().map(vertex -> (Object) vertex).collect(Collectors.toList())).toString();
427                                                                         status = Status.OK;
428                                                                 }
429                                                                 
430                                                                 break;
431                                                         case PUT:
432                                                                 response = this.invokeExtension(dbEngine, this.dbEngine.tx(), method, request, sourceOfTruth, version, loader, obj, uri, true);
433                                                                 if (isNewVertex) {
434                                                                         v = serializer.createNewVertex(obj);
435                                                                 }
436                                                                 serializer.serializeToDb(obj, v, query, uri.getRawPath(), requestContext);
437                                                                 this.invokeExtension(dbEngine, this.dbEngine.tx(), HttpMethod.PUT, request, sourceOfTruth, version, loader, obj, uri, false);
438                                                                 status = Status.OK;
439                                                                 if (isNewVertex) {
440                                                                         status = Status.CREATED;
441                                                                 }
442                                                                 obj = serializer.getLatestVersionView(v);
443                                                                 if (query.isDependent()) {
444                                                                         relatedObjects = this.getRelatedObjects(serializer, queryEngine, v);
445                                                                 }
446                                                                 LoggingContext.elapsedTime((long)serializer.getDBTimeMsecs() + 
447                                                                                 (long)queryEngine.getDBTimeMsecs(), TimeUnit.MILLISECONDS);
448                                                                 LOGGER.info ("Completed ");
449                                                                 LoggingContext.restoreIfPossible();
450                                                                 notification.createNotificationEvent(transactionId, sourceOfTruth, status, uri, obj, relatedObjects, basePath);
451
452                                                                 break;
453                                                         case PUT_EDGE:
454                                                                 serializer.touchStandardVertexProperties(v, false);
455                                                                 this.invokeExtension(dbEngine, this.dbEngine.tx(), method, request, sourceOfTruth, version, loader, obj, uri, true);
456                                                                 serializer.createEdge(obj, v);
457                                                                 
458                                                                 LoggingContext.elapsedTime((long)serializer.getDBTimeMsecs(),TimeUnit.MILLISECONDS);
459                                                                 LOGGER.info ("Completed");
460                                                                 LoggingContext.restoreIfPossible();
461                                                                 status = Status.OK;
462                                                                 notification.createNotificationEvent(transactionId, sourceOfTruth, status, new URI(uri.toString().replace("/relationship-list/relationship", "")), serializer.getLatestVersionView(v), relatedObjects, basePath);
463                                                                 break;
464                                                         case MERGE_PATCH:
465                                                                 Introspector existingObj  = loader.introspectorFromName(obj.getDbName());
466                                                                 existingObj = this.getObjectFromDb(vertices, serializer, query, existingObj, request.getUri(), 0, false, cleanUp);
467                                                                 String existingJson = existingObj.marshal(false);
468                                                                 String newJson;
469                                                                 
470                                                                 if (request.getRawRequestContent().isPresent()) {
471                                                                         newJson = request.getRawRequestContent().get();
472                                                                 } else {
473                                                                         newJson = "";
474                                                                 }
475                                                                 Object relationshipList = request.getIntrospector().getValue("relationship-list");
476                                                                 ObjectMapper mapper = new ObjectMapper();
477                                                                 try {
478                                                                         JsonNode existingNode = mapper.readTree(existingJson);
479                                                                         JsonNode newNode = mapper.readTree(newJson);
480                                                                         JsonMergePatch patch = JsonMergePatch.fromJson(newNode);
481                                                                         JsonNode completed = patch.apply(existingNode);
482                                                                         String patched = mapper.writeValueAsString(completed);
483                                                                         Introspector patchedObj = loader.unmarshal(existingObj.getName(), patched);
484                                                                         if (relationshipList == null) {
485                                                                                 //if the caller didn't touch the relationship-list, we shouldn't either
486                                                                                 patchedObj.setValue("relationship-list", null);
487                                                                         }
488                                                                         serializer.serializeToDb(patchedObj, v, query, uri.getRawPath(), requestContext);
489                                                                         status = Status.OK;
490                                                                         patchedObj = serializer.getLatestVersionView(v);
491                                                                         if (query.isDependent()) {
492                                                                                 relatedObjects = this.getRelatedObjects(serializer, queryEngine, v);
493                                                                         }
494                                                                         LoggingContext.elapsedTime((long)serializer.getDBTimeMsecs() + 
495                                                                                         (long)queryEngine.getDBTimeMsecs(), TimeUnit.MILLISECONDS);
496                                                                         LOGGER.info ("Completed");
497                                                                         LoggingContext.restoreIfPossible();
498                                                                         notification.createNotificationEvent(transactionId, sourceOfTruth, status, uri, patchedObj, relatedObjects, basePath);
499                                                                 } catch (IOException | JsonPatchException e) {
500                                                                         
501                                                                         LOGGER.info ("Caught exception: " + e.getMessage());
502                                                                         LoggingContext.restoreIfPossible();
503                                                                         throw new AAIException("AAI_3000", "could not perform patch operation");
504                                                                 }
505                                                                 break;
506                                                         case DELETE:
507                                                                 String resourceVersion = params.getFirst("resource-version");
508                                                                 obj = serializer.getLatestVersionView(v);
509                                                                 if (query.isDependent()) {
510                                                                         relatedObjects = this.getRelatedObjects(serializer, queryEngine, v);
511                                                                 }
512                                                                 /*
513                                                                  * Find all Delete-other-vertex vertices and create structure for notify
514                                                                  * findDeleatble also returns the startVertex v and we dont want to create 
515                                                                  * duplicate notification events for the same
516                                                                  * So remove the startvertex first
517                                                                  */
518                                                                 
519                                                                 List<Vertex> deletableVertices = dbEngine.getQueryEngine().findDeletable(v);
520                                                                 Long vId = (Long) v.id();
521                                                                 
522                                                                 /*
523                                                                  * I am assuming vertexId cant be null
524                                                                  */
525                                                                 deletableVertices.removeIf(s -> vId.equals(s.id()));
526                                                                 boolean isDelVerticesPresent = !deletableVertices.isEmpty();
527                                                                 Map<Vertex, Introspector> deleteObjects = new HashMap<>();
528                                                                 Map<String, URI> uriMap = new HashMap<>();
529                                                                 Map<String, HashMap<String, Introspector>> deleteRelatedObjects = new HashMap<>();
530                                                                 
531                                                                 if(isDelVerticesPresent){
532                                                                         deleteObjects = this.buildIntrospectorObjects(serializer, deletableVertices);
533                                                                                 
534                                                                         uriMap = this.buildURIMap(serializer, deleteObjects);
535                                                                         deleteRelatedObjects = this.buildRelatedObjects(serializer, queryEngine, deleteObjects);
536                                                                 }
537                                                                 
538                                                                 this.invokeExtension(dbEngine, this.dbEngine.tx(), method, request, sourceOfTruth, version, loader, obj, uri, true);
539                                                                 serializer.delete(v, deletableVertices, resourceVersion, enableResourceVersion);
540                                                                 this.invokeExtension(dbEngine, this.dbEngine.tx(), method, request, sourceOfTruth, version, loader, obj, uri, false);
541                                                                 
542                                                                 LoggingContext.elapsedTime((long)serializer.getDBTimeMsecs() + 
543                                                                                 (long)queryEngine.getDBTimeMsecs(), TimeUnit.MILLISECONDS);
544                                                                 LOGGER.info ("Completed");
545                                                                 LoggingContext.restoreIfPossible();
546                                                                 status = Status.NO_CONTENT;
547                                                                 notification.createNotificationEvent(transactionId, sourceOfTruth, status, uri, obj, relatedObjects, basePath);
548                                                                 
549                                                                 /*
550                                                                  * Notify delete-other-v candidates
551                                                                  */
552                                                                 
553                                                                 if(isDelVerticesPresent){
554                                                                         this.buildNotificationEvent(sourceOfTruth, status, transactionId, notification, deleteObjects,
555                                                                         uriMap, deleteRelatedObjects, basePath);
556                                                                 }
557                                                                 
558                                                                 break;
559                                                         case DELETE_EDGE:
560                                                                 serializer.touchStandardVertexProperties(v, false);
561                                                                 serializer.deleteEdge(obj, v);
562                                                                 
563                                                                 LoggingContext.elapsedTime((long)serializer.getDBTimeMsecs(),TimeUnit.MILLISECONDS);
564                                                                 LOGGER.info ("Completed");
565                                                                 LoggingContext.restoreIfPossible();
566                                                                 status = Status.NO_CONTENT;
567                                                                 notification.createNotificationEvent(transactionId, sourceOfTruth, Status.OK, new URI(uri.toString().replace("/relationship-list/relationship", "")), serializer.getLatestVersionView(v), relatedObjects, basePath);
568                                                                 break;
569                                                         default:
570                                                                 break;
571                                                 }
572                                                 
573                                                 
574                                                 /* temporarily adding vertex id to the headers
575                                                  * to be able to use for testing the vertex id endpoint functionality
576                                                  * since we presently have no other way of generating those id urls
577                                                 */
578                                                 if (response == null && v != null && (
579                                                         method.equals(HttpMethod.PUT)
580                                                         || method.equals(HttpMethod.GET)
581                                                         || method.equals(HttpMethod.MERGE_PATCH))
582                                                 ) {
583                                                         String myvertid = v.id().toString();
584                                                         if(this.isPaginated()){
585                                                                 response = Response.status(status)
586                                                                                 .header("vertex-id", myvertid)
587                                                                                 .header("total-results", this.getTotalVertices())
588                                                                                 .header("total-pages", this.getTotalPaginationBuckets())
589                                                                                 .entity(result)
590                                                                                 .type(outputMediaType).build();
591                                                         }else {
592                                                                 response = Response.status(status)
593                                                                                 .header("vertex-id", myvertid)
594                                                                                 .entity(result)
595                                                                                 .type(outputMediaType).build();
596                                                         }
597                                                 } else if (response == null) {
598                                                         response = Response.status(status)
599                                                                         .type(outputMediaType).build();
600                                                 } else {
601                                                         //response already set to something
602                                                 }
603                                                 Pair<URI,Response> pairedResp = Pair.with(request.getUri(), response);
604                                                 responses.add(pairedResp);
605                                                 //break out of retry loop
606                                                 break;
607                                         } catch (JanusGraphException e) {
608                                                 this.dbEngine.rollback();
609                                                 
610                                                 LOGGER.info ("Caught exception: " + e.getMessage());
611                                                 LoggingContext.restoreIfPossible();
612                                                 AAIException ex = new AAIException("AAI_6142", e);
613                                                 ErrorLogHelper.logException(ex);
614                                                 Thread.sleep((retry + 1) * 20L);
615                                                 this.dbEngine.startTransaction();
616                                                 queryEngine = dbEngine.getQueryEngine();
617                                                 serializer = new DBSerializer(version, dbEngine, introspectorFactoryType, sourceOfTruth);
618                                         }
619                                         if (retry == maxRetries) {
620                                                 throw new AAIException("AAI_6134");
621                                         }
622                                 }
623                         } catch (AAIException e) {
624                                 success = false;
625                                 ArrayList<String> templateVars = new ArrayList<>();
626                                 templateVars.add(request.getMethod().toString()); //GET, PUT, etc
627                                 templateVars.add(request.getUri().getPath());
628                                 templateVars.addAll(e.getTemplateVars());
629                                 ErrorLogHelper.logException(e);
630                                 response = Response
631                                                 .status(e.getErrorObject().getHTTPResponseCode())
632                                                 .entity(ErrorLogHelper.getRESTAPIErrorResponse(request.getHeaders().getAcceptableMediaTypes(), e, templateVars))
633                                                 .build();
634                                 Pair<URI,Response> pairedResp = Pair.with(request.getUri(), response);
635                                 responses.add(pairedResp);
636                                 continue;
637                         } catch (Exception e) {
638                                 success = false;
639                                 e.printStackTrace();
640                                 AAIException ex = new AAIException("AAI_4000", e);
641                                 ArrayList<String> templateVars = new ArrayList<String>();
642                                 templateVars.add(request.getMethod().toString()); //GET, PUT, etc
643                                 templateVars.add(request.getUri().getPath().toString());
644                                 ErrorLogHelper.logException(ex);
645                                 response = Response
646                                                 .status(ex.getErrorObject().getHTTPResponseCode())
647                                                 .entity(ErrorLogHelper.getRESTAPIErrorResponse(request.getHeaders().getAcceptableMediaTypes(), ex, templateVars))
648                                                 .build();
649                                 Pair<URI, Response> pairedResp = Pair.with(request.getUri(), response);
650                                 responses.add(pairedResp);
651                                 continue;
652                         }
653                 }
654                 notification.triggerEvents();
655                 return Pair.with(success, responses);
656         }
657
658         
659         /**
660          * Gets the media type.
661          *
662          * @param mediaTypeList the media type list
663          * @return the media type
664          */
665         private String getMediaType(List <MediaType> mediaTypeList) {
666                 String mediaType = MediaType.APPLICATION_JSON;  // json is the default    
667                 for (MediaType mt : mediaTypeList) {
668                         if (MediaType.APPLICATION_XML_TYPE.isCompatible(mt)) {
669                                 mediaType = MediaType.APPLICATION_XML;
670                         } 
671                 }
672                 return mediaType;
673         }
674         
675         /**
676          * Gets the object from db.
677          *
678          * @param serializer the serializer
679          * @param query the query
680          * @param obj the obj
681          * @param uri the uri
682          * @param depth the depth
683          * @param cleanUp the clean up
684          * @return the object from db
685          * @throws AAIException the AAI exception
686          * @throws IllegalAccessException the illegal access exception
687          * @throws IllegalArgumentException the illegal argument exception
688          * @throws InvocationTargetException the invocation target exception
689          * @throws SecurityException the security exception
690          * @throws InstantiationException the instantiation exception
691          * @throws NoSuchMethodException the no such method exception
692          * @throws UnsupportedEncodingException the unsupported encoding exception
693          * @throws MalformedURLException the malformed URL exception
694          * @throws AAIUnknownObjectException 
695          * @throws URISyntaxException 
696          */
697         private Introspector getObjectFromDb(List<Vertex> results, DBSerializer serializer, QueryParser query, Introspector obj, URI uri, int depth, boolean nodeOnly, String cleanUp) throws AAIException, IllegalAccessException, IllegalArgumentException, InvocationTargetException, SecurityException, InstantiationException, NoSuchMethodException, UnsupportedEncodingException, AAIUnknownObjectException, URISyntaxException {
698         
699         //nothing found
700         if (results.isEmpty()) {
701                 String msg = createNotFoundMessage(query.getResultType(), uri);
702                         throw new AAIException("AAI_6114", msg);
703         }
704
705         return serializer.dbToObject(results, obj, depth, nodeOnly, cleanUp);
706         
707         }
708
709         /**
710          * Invoke extension.
711          *
712          * @param dbEngine the db engine
713          * @param g the g
714          * @param httpMethod the http method
715          * @param fromAppId the from app id
716          * @param apiVersion the api version
717          * @param loader the loader
718          * @param obj the obj
719          * @param uri the uri
720          * @param isPreprocess the is preprocess
721          * @return the response
722          * @throws IllegalArgumentException the illegal argument exception
723          * @throws UnsupportedEncodingException the unsupported encoding exception
724          * @throws AAIException the AAI exception
725          */
726         private Response invokeExtension(TransactionalGraphEngine dbEngine, Graph g, HttpMethod httpMethod, DBRequest request, String fromAppId, SchemaVersion apiVersion, Loader loader, Introspector obj, URI uri, boolean isPreprocess) throws IllegalArgumentException, UnsupportedEncodingException, AAIException {
727                 AAIExtensionMap aaiExtMap = new AAIExtensionMap();
728                 //ModelInjestor injestor = ModelInjestor.getInstance();
729                 Response response = null;
730                 URIToExtensionInformation extensionInformation = new URIToExtensionInformation(loader, uri);
731                 aaiExtMap.setHttpEntry(this);
732                 aaiExtMap.setDbRequest(request);
733                 aaiExtMap.setTransId(request.getTransactionId());
734                 aaiExtMap.setFromAppId(fromAppId);
735                 aaiExtMap.setGraph(g);
736                 aaiExtMap.setApiVersion(apiVersion.toString());
737                 aaiExtMap.setObjectFromRequest(obj);
738                 aaiExtMap.setObjectFromRequestType(obj.getJavaClassName());
739                 aaiExtMap.setObjectFromResponse(obj);
740                 aaiExtMap.setObjectFromResponseType(obj.getJavaClassName());
741                 aaiExtMap.setJaxbContext(nodeIngestor.getContextForVersion(apiVersion));
742                 aaiExtMap.setUri(uri.getRawPath());
743                 aaiExtMap.setTransactionalGraphEngine(dbEngine);
744                 aaiExtMap.setLoader(loader);
745                 aaiExtMap.setNamespace(extensionInformation.getNamespace());
746
747                 ExtensionController ext = new ExtensionController();
748                 ext.runExtension(aaiExtMap.getApiVersion(),
749                                 extensionInformation.getNamespace(),
750                                 extensionInformation.getTopObject(),
751                                 extensionInformation.getMethodName(httpMethod, isPreprocess),
752                                 aaiExtMap,
753                                 isPreprocess);
754
755                 if (aaiExtMap.getPrecheckAddedList().size() > 0) {
756                         response = notifyOnSkeletonCreation(aaiExtMap, obj, request.getHeaders());
757                 }
758
759                 return response;
760         }
761
762         /**
763          * Notify on skeleton creation.
764          *
765          * @param aaiExtMap the aai ext map
766          * @param input the input
767          * @param headers the headers
768          * @return the response
769          */
770         //Legacy support
771         private Response notifyOnSkeletonCreation(AAIExtensionMap aaiExtMap, Introspector input, HttpHeaders headers) {
772                 Response response = null;
773                 HashMap<AAIException, ArrayList<String>> exceptionList = new HashMap<AAIException, ArrayList<String>>();
774
775                 StringBuilder keyString = new StringBuilder();
776
777                 Set<String> resourceKeys = input.getKeys();
778                 for (String key : resourceKeys) {
779                         keyString.append(key).append("=").append(input.getValue(key).toString()).append(" ");
780                 }
781
782                 for (AAIResponseMessage msg : aaiExtMap.getPrecheckResponseMessages().getAAIResponseMessage()) {
783                         ArrayList<String> templateVars = new ArrayList<>();
784
785                         templateVars.add("PUT " + input.getDbName());
786                         templateVars.add(keyString.toString());
787                         List<String> keys = new ArrayList<>();
788                         templateVars.add(msg.getAaiResponseMessageResourceType());
789                         for (AAIResponseMessageDatum dat : msg.getAaiResponseMessageData().getAAIResponseMessageDatum()) {
790                                 keys.add(dat.getAaiResponseMessageDatumKey() + "=" + dat.getAaiResponseMessageDatumValue());
791                         }
792                         templateVars.add(StringUtils.join(keys, ", "));
793                         exceptionList.put(new AAIException("AAI_0004", msg.getAaiResponseMessageResourceType()),
794                                         templateVars);
795                 }
796                 response = Response
797                                 .status(Status.ACCEPTED).entity(ErrorLogHelper
798                                                 .getRESTAPIInfoResponse(headers.getAcceptableMediaTypes(), exceptionList))
799                                                 .build();
800
801                 return response;
802         }
803         
804         /**
805          * Creates the not found message.
806          *
807          * @param resultType the result type
808          * @param uri the uri
809          * @return the string
810          */
811         private String createNotFoundMessage(String resultType, URI uri) {
812                 
813         String msg = "No Node of type " + resultType + " found at: " + uri.getPath();
814
815         return msg;
816         }
817         
818         /**
819          * Sets the depth.
820          *
821          * @param depthParam the depth param
822          * @return the int
823          * @throws AAIException the AAI exception
824          */
825         protected int setDepth(Introspector obj, String depthParam) throws AAIException {
826                 int depth = AAIProperties.MAXIMUM_DEPTH;
827
828                 String getAllRandomStr = AAIConfig.get("aai.rest.getall.depthparam", "");
829                 if (depthParam != null && getAllRandomStr != null && !getAllRandomStr.isEmpty()
830                                 && getAllRandomStr.equals(depthParam)) {
831                         return depth;
832                 }
833
834         if(depthParam == null){
835                         if(this.version.compareTo(schemaVersions.getDepthVersion()) >= 0){
836                                 depth = 0;
837                         } else {
838                 depth = AAIProperties.MAXIMUM_DEPTH;
839                         }
840                 } else {
841                         if (!depthParam.isEmpty() && !"all".equals(depthParam)){
842                                 try {
843                                         depth = Integer.parseInt(depthParam);
844                                 } catch (Exception e) {
845                                         throw new AAIException("AAI_4016");
846                                 }
847
848                         }
849                 }
850         String maxDepth = obj.getMetadata(ObjectMetadata.MAXIMUM_DEPTH);
851         
852                 int maximumDepth = AAIProperties.MAXIMUM_DEPTH;
853
854                 if(maxDepth != null){
855             try {
856                 maximumDepth = Integer.parseInt(maxDepth);
857             } catch(Exception ex){
858                 throw new AAIException("AAI_4018");
859             }
860                 }
861
862                 if(depth > maximumDepth){
863                         throw new AAIException("AAI_3303");
864                 }
865
866                 return depth;
867         }
868         
869         /**
870          * Checks if is modification method.
871          *
872          * @param method the method
873          * @return true, if is modification method
874          */
875         private boolean isModificationMethod(HttpMethod method) {
876                 boolean result = false;
877                 
878                 if (method.equals(HttpMethod.PUT) || method.equals(HttpMethod.PUT_EDGE) || method.equals(HttpMethod.DELETE_EDGE) || method.equals(HttpMethod.MERGE_PATCH)) {
879                         result = true;
880                 }
881                 
882                 return result;
883                 
884         }
885         
886         private HashMap<String, Introspector> getRelatedObjects(DBSerializer serializer, QueryEngine queryEngine, Vertex v) throws IllegalAccessException, IllegalArgumentException, InvocationTargetException, SecurityException, InstantiationException, NoSuchMethodException, UnsupportedEncodingException, AAIException, URISyntaxException {
887                 HashMap<String, Introspector> relatedVertices = new HashMap<>();
888                 List<Vertex> vertexChain = queryEngine.findParents(v);
889                 for (Vertex vertex : vertexChain) {
890                         try {
891                                 final Introspector vertexObj = serializer.getVertexProperties(vertex);
892                                 relatedVertices.put(vertexObj.getObjectId(), vertexObj);
893                         } catch (AAIUnknownObjectException e) {
894                                 LOGGER.warn("Unable to get vertex properties, partial list of related vertices returned");
895                         }
896                         
897                 }
898                 
899                 return relatedVertices;
900         }
901         
902         private Map<Vertex, Introspector> buildIntrospectorObjects(DBSerializer serializer, Iterable<Vertex> vertices) {
903                 Map<Vertex, Introspector> deleteObjectMap = new HashMap<>();
904                 for (Vertex vertex : vertices) {
905                         try {
906                                 // deleteObjectMap.computeIfAbsent(vertex, s ->
907                                 // serializer.getLatestVersionView(vertex));
908                                 Introspector deleteObj = serializer.getLatestVersionView(vertex);
909                                 deleteObjectMap.put(vertex, deleteObj);
910                         } catch (UnsupportedEncodingException | AAIException e) {
911                                 LOGGER.warn("Unable to get Introspctor Objects, Just continue");
912                                 continue;
913                         }
914
915                 }
916
917                 return deleteObjectMap;
918
919         }
920
921         private Map<String, URI> buildURIMap(DBSerializer serializer, Map<Vertex, Introspector> introSpector) {
922                 Map<String, URI> uriMap = new HashMap<>();
923                 for (Map.Entry<Vertex, Introspector> entry : introSpector.entrySet()) {
924                         URI uri;
925                         try {
926                                 uri = serializer.getURIForVertex(entry.getKey());
927                                 if (null != entry.getValue())
928                                         uriMap.put(entry.getValue().getObjectId(), uri);
929                         } catch (UnsupportedEncodingException e) {
930                                 LOGGER.warn("Unable to get URIs, Just continue");
931                                 continue;
932                         }
933
934                 }
935
936                 return uriMap;
937
938         }
939
940         private Map<String, HashMap<String, Introspector>> buildRelatedObjects(DBSerializer serializer,
941                         QueryEngine queryEngine, Map<Vertex, Introspector> introSpector) {
942
943                 Map<String, HashMap<String, Introspector>> relatedObjectsMap = new HashMap<>();
944                 for (Map.Entry<Vertex, Introspector> entry : introSpector.entrySet()) {
945                         try {
946                                 HashMap<String, Introspector> relatedObjects = this.getRelatedObjects(serializer, queryEngine,
947                                                 entry.getKey());
948                                 if (null != entry.getValue())
949                                         relatedObjectsMap.put(entry.getValue().getObjectId(), relatedObjects);
950                         } catch (IllegalAccessException | IllegalArgumentException
951                                         | InvocationTargetException | SecurityException | InstantiationException | NoSuchMethodException
952                                         | UnsupportedEncodingException | AAIException | URISyntaxException e) {
953                                 LOGGER.warn("Unable to get realted Objects, Just continue");
954                                 continue;
955                         }
956
957                 }
958
959                 return relatedObjectsMap;
960
961         }
962         
963         private void buildNotificationEvent(String sourceOfTruth, Status status, String transactionId,
964                         UEBNotification notification, Map<Vertex, Introspector> deleteObjects, Map<String, URI> uriMap,
965                         Map<String, HashMap<String, Introspector>> deleteRelatedObjects, String basePath) {
966                 for (Map.Entry<Vertex, Introspector> entry : deleteObjects.entrySet()) {
967                         try {
968                                 String vertexObjectId = "";
969
970                                 if (null != entry.getValue()) {
971                                         vertexObjectId = entry.getValue().getObjectId();
972
973                                         if (uriMap.containsKey(vertexObjectId) && deleteRelatedObjects.containsKey(vertexObjectId))
974                                                 notification.createNotificationEvent(transactionId, sourceOfTruth, status,
975                                                                 uriMap.get(vertexObjectId), entry.getValue(), deleteRelatedObjects.get(vertexObjectId), basePath);
976                                 }
977                         } catch (UnsupportedEncodingException | AAIException e) {
978
979                                 LOGGER.warn("Error in sending notification");
980                         }
981                 }
982         }
983 }