8556c111ea33c80eda031d143124c7cfd8d33120
[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
21 package org.onap.aai.rest.db;
22
23 import com.att.eelf.configuration.EELFLogger;
24 import com.att.eelf.configuration.EELFManager;
25 import com.fasterxml.jackson.databind.JsonNode;
26 import com.fasterxml.jackson.databind.ObjectMapper;
27 import com.github.fge.jsonpatch.JsonPatchException;
28 import com.github.fge.jsonpatch.mergepatch.JsonMergePatch;
29
30 import java.io.IOException;
31 import java.io.UnsupportedEncodingException;
32 import java.lang.reflect.InvocationTargetException;
33 import java.net.MalformedURLException;
34 import java.net.URI;
35 import java.net.URISyntaxException;
36 import java.util.ArrayList;
37 import java.util.HashMap;
38 import java.util.List;
39 import java.util.Map;
40 import java.util.Set;
41 import java.util.concurrent.TimeUnit;
42 import java.util.stream.Collectors;
43
44 import javax.ws.rs.core.HttpHeaders;
45 import javax.ws.rs.core.MediaType;
46 import javax.ws.rs.core.MultivaluedMap;
47 import javax.ws.rs.core.Response;
48 import javax.ws.rs.core.Response.Status;
49 import javax.ws.rs.core.UriBuilder;
50
51 import org.apache.commons.lang.StringUtils;
52 import org.apache.tinkerpop.gremlin.structure.Graph;
53 import org.apache.tinkerpop.gremlin.structure.Vertex;
54 import org.apache.tinkerpop.gremlin.structure.VertexProperty;
55 import org.janusgraph.core.JanusGraphException;
56 import org.javatuples.Pair;
57 import org.json.JSONException;
58 import org.json.JSONObject;
59 import org.onap.aai.db.props.AAIProperties;
60 import org.onap.aai.dbmap.DBConnectionType;
61 import org.onap.aai.domain.responseMessage.AAIResponseMessage;
62 import org.onap.aai.domain.responseMessage.AAIResponseMessageDatum;
63 import org.onap.aai.exceptions.AAIException;
64 import org.onap.aai.extensions.AAIExtensionMap;
65 import org.onap.aai.extensions.ExtensionController;
66 import org.onap.aai.introspection.*;
67 import org.onap.aai.introspection.exceptions.AAIUnknownObjectException;
68 import org.onap.aai.logging.ErrorLogHelper;
69 import org.onap.aai.logging.LoggingContext;
70 import org.onap.aai.nodes.NodeIngestor;
71 import org.onap.aai.parsers.query.QueryParser;
72 import org.onap.aai.parsers.uri.URIToExtensionInformation;
73 import org.onap.aai.parsers.uri.URIToObject;
74 import org.onap.aai.rest.ueb.UEBNotification;
75 import org.onap.aai.restcore.HttpMethod;
76 import org.onap.aai.schema.enums.ObjectMetadata;
77 import org.onap.aai.serialization.db.DBSerializer;
78 import org.onap.aai.serialization.engines.JanusGraphDBEngine;
79 import org.onap.aai.serialization.engines.QueryStyle;
80 import org.onap.aai.serialization.engines.TransactionalGraphEngine;
81 import org.onap.aai.serialization.engines.query.QueryEngine;
82 import org.onap.aai.serialization.queryformats.Format;
83 import org.onap.aai.serialization.queryformats.FormatFactory;
84 import org.onap.aai.serialization.queryformats.Formatter;
85 import org.onap.aai.setup.SchemaVersion;
86 import org.onap.aai.setup.SchemaVersions;
87 import org.onap.aai.util.AAIConfig;
88 import org.springframework.beans.factory.annotation.Autowired;
89 import org.springframework.beans.factory.annotation.Value;
90
91 /**
92  * The Class HttpEntry.
93  */
94 public class HttpEntry {
95
96     private static final EELFLogger LOGGER = EELFManager.getInstance().getLogger(HttpEntry.class);
97     private static final String TARGET_ENTITY = "DB";
98
99     private ModelType introspectorFactoryType;
100
101     private QueryStyle queryStyle;
102
103     private SchemaVersion version;
104
105     private Loader loader;
106
107     private TransactionalGraphEngine dbEngine;
108
109     private boolean processSingle = true;
110
111     private int paginationBucket = -1;
112     private int paginationIndex = -1;
113     private int totalVertices = 0;
114     private int totalPaginationBuckets = 0;
115
116     @Autowired
117     private NodeIngestor nodeIngestor;
118
119     @Autowired
120     private LoaderFactory loaderFactory;
121
122     @Autowired
123     private SchemaVersions schemaVersions;
124
125     @Value("${schema.uri.base.path}")
126     private String basePath;
127
128     private UEBNotification notification;
129
130     /**
131      * Instantiates a new http entry.
132      *
133      * @param modelType the model type
134      * @param queryStyle the query style
135      */
136     public HttpEntry(ModelType modelType, QueryStyle queryStyle) {
137         this.introspectorFactoryType = modelType;
138         this.queryStyle = queryStyle;
139     }
140
141     public HttpEntry setHttpEntryProperties(SchemaVersion version, DBConnectionType connectionType) {
142         this.version = version;
143         this.loader = loaderFactory.createLoaderForVersion(introspectorFactoryType, version);
144         this.dbEngine = new JanusGraphDBEngine(queryStyle, connectionType, loader);
145
146         getDbEngine().startTransaction();
147         this.notification = new UEBNotification(loader, loaderFactory, schemaVersions);
148         return this;
149     }
150
151     public HttpEntry setHttpEntryProperties(SchemaVersion version, DBConnectionType connectionType,
152             UEBNotification notification) {
153         this.version = version;
154         this.loader = loaderFactory.createLoaderForVersion(introspectorFactoryType, version);
155         this.dbEngine = new JanusGraphDBEngine(queryStyle, connectionType, loader);
156
157         this.notification = notification;
158         // start transaction on creation
159         getDbEngine().startTransaction();
160         return this;
161     }
162
163     /**
164      * Gets the introspector factory type.
165      *
166      * @return the introspector factory type
167      */
168     public ModelType getIntrospectorFactoryType() {
169         return introspectorFactoryType;
170     }
171
172     /**
173      * Gets the query style.
174      *
175      * @return the query style
176      */
177     public QueryStyle getQueryStyle() {
178         return queryStyle;
179     }
180
181     /**
182      * Gets the version.
183      *
184      * @return the version
185      */
186     public SchemaVersion getVersion() {
187         return version;
188     }
189
190     /**
191      * Gets the loader.
192      *
193      * @return the loader
194      */
195     public Loader getLoader() {
196         return loader;
197     }
198
199     /**
200      * Gets the db engine.
201      *
202      * @return the db engine
203      */
204     public TransactionalGraphEngine getDbEngine() {
205         return dbEngine;
206     }
207
208     public Pair<Boolean, List<Pair<URI, Response>>> process(List<DBRequest> requests, String sourceOfTruth)
209             throws AAIException {
210         return this.process(requests, sourceOfTruth, true);
211     }
212
213     /**
214      * Checks the pagination bucket and pagination index variables to determine whether or not the user
215      * requested paginated results
216      *
217      * @return a boolean true/false of whether the user requested paginated results
218      */
219     public boolean isPaginated() {
220         return this.paginationBucket > -1 && this.paginationIndex > -1;
221     }
222
223     /**
224      * Returns the pagination size
225      * 
226      * @return integer of the size of results to be returned when paginated
227      */
228     public int getPaginationBucket() {
229         return this.paginationBucket;
230     }
231
232     /**
233      * Setter for the pagination bucket variable which stores in this object the size of results to return
234      * 
235      * @param pb
236      */
237     public void setPaginationBucket(int pb) {
238         this.paginationBucket = pb;
239     }
240
241     /**
242      * Getter to return the pagination index requested by the user when requesting paginated results
243      * 
244      * @return
245      */
246     public int getPaginationIndex() {
247         return this.paginationIndex;
248     }
249
250     /**
251      * Sets the pagination index that was passed in by the user, to determine which index or results to retrieve when
252      * paginated
253      * 
254      * @param pi
255      */
256     public void setPaginationIndex(int pi) {
257         if (pi == 0) {
258             pi = 1;
259         }
260         this.paginationIndex = pi;
261     }
262
263     /**
264      * Sets the total vertices variables and calculates the amount of pages based on size and total vertices
265      * 
266      * @param totalVertices
267      * @param paginationBucketSize
268      */
269     public void setTotalsForPaging(int totalVertices, int paginationBucketSize) {
270         this.totalVertices = totalVertices;
271         // set total number of buckets equal to full pages
272         this.totalPaginationBuckets = totalVertices / paginationBucketSize;
273         // conditionally add a page for the remainder
274         if (totalVertices % paginationBucketSize > 0) {
275             this.totalPaginationBuckets++;
276         }
277     }
278
279     /**
280      * @return the total amount of pages
281      */
282     public int getTotalPaginationBuckets() {
283         return this.totalPaginationBuckets;
284     }
285
286     /**
287      *
288      * @return the total number of vertices when paginated
289      */
290     public int getTotalVertices() {
291         return this.totalVertices;
292     }
293
294     /**
295      * Process.
296      * 
297      * @param requests the requests
298      * @param sourceOfTruth the source of truth
299      *
300      * @return the pair
301      * @throws AAIException the AAI exception
302      */
303     public Pair<Boolean, List<Pair<URI, Response>>> process(List<DBRequest> requests, String sourceOfTruth,
304             boolean enableResourceVersion) throws AAIException {
305
306         DBSerializer serializer = new DBSerializer(version, dbEngine, introspectorFactoryType, sourceOfTruth);
307         String methodName = "process";
308         Response response;
309         Introspector obj = null;
310         QueryParser query = null;
311         URI uri = null;
312         String transactionId = null;
313         int depth = AAIProperties.MAXIMUM_DEPTH;
314         Format format = null;
315         List<Pair<URI, Response>> responses = new ArrayList<>();
316         MultivaluedMap<String, String> params = null;
317         HttpMethod method = null;
318         String uriTemp = "";
319         Boolean success = true;
320         QueryEngine queryEngine = dbEngine.getQueryEngine();
321         int maxRetries = 10;
322         int retry = 0;
323
324         LoggingContext.save();
325         for (DBRequest request : requests) {
326             response = null;
327             Status status = Status.NOT_FOUND;
328             method = request.getMethod();
329             try {
330                 for (retry = 0; retry < maxRetries; ++retry) {
331                     try {
332
333                         LoggingContext.targetEntity(TARGET_ENTITY);
334                         LoggingContext.targetServiceName(methodName + " " + method);
335
336                         obj = request.getIntrospector();
337                         query = request.getParser();
338                         transactionId = request.getTransactionId();
339                         uriTemp = request.getUri().getRawPath().replaceFirst("^v\\d+/", "");
340                         uri = UriBuilder.fromPath(uriTemp).build();
341                         LoggingContext.startTime();
342                         List<Vertex> vertTemp;
343                         List<Vertex> vertices;
344                         if (this.isPaginated()) {
345                             vertTemp = query.getQueryBuilder().toList();
346                             this.setTotalsForPaging(vertTemp.size(), this.paginationBucket);
347                             vertices = vertTemp.subList(((this.paginationIndex - 1) * this.paginationBucket),
348                                     Math.min((this.paginationBucket * this.paginationIndex), vertTemp.size()));
349                         } else {
350                             vertices = query.getQueryBuilder().toList();
351                         }
352                         boolean isNewVertex = false;
353                         String outputMediaType = getMediaType(request.getHeaders().getAcceptableMediaTypes());
354                         String result = null;
355                         params = request.getInfo().getQueryParameters(false);
356                         depth = setDepth(obj, params.getFirst("depth"));
357                         if (params.containsKey("format")) {
358                             format = Format.getFormat(params.getFirst("format"));
359                         }
360                         String cleanUp = params.getFirst("cleanup");
361                         String requestContext = "";
362                         List<String> requestContextList = request.getHeaders().getRequestHeader("aai-request-context");
363                         if (requestContextList != null) {
364                             requestContext = requestContextList.get(0);
365                         }
366
367                         if (cleanUp == null) {
368                             cleanUp = "false";
369                         }
370                         if (vertices.size() > 1 && processSingle
371                                 && !(method.equals(HttpMethod.GET) || method.equals(HttpMethod.GET_RELATIONSHIP))) {
372                             if (method.equals(HttpMethod.DELETE)) {
373                                 LoggingContext.restoreIfPossible();
374                                 throw new AAIException("AAI_6138");
375                             } else {
376                                 LoggingContext.restoreIfPossible();
377                                 throw new AAIException("AAI_6137");
378                             }
379                         }
380                         if (method.equals(HttpMethod.PUT)) {
381                             String resourceVersion = (String) obj.getValue("resource-version");
382                             if (vertices.isEmpty()) {
383                                 if (enableResourceVersion) {
384                                     serializer.verifyResourceVersion("create", query.getResultType(), "",
385                                             resourceVersion, obj.getURI());
386                                 }
387                                 isNewVertex = true;
388                             } else {
389                                 if (enableResourceVersion) {
390                                     serializer.verifyResourceVersion("update", query.getResultType(),
391                                             vertices.get(0).<String>property("resource-version").orElse(null),
392                                             resourceVersion, obj.getURI());
393                                 }
394                                 isNewVertex = false;
395                             }
396                         } else {
397                             if (vertices.isEmpty()) {
398                                 String msg = createNotFoundMessage(query.getResultType(), request.getUri());
399                                 throw new AAIException("AAI_6114", msg);
400                             } else {
401                                 isNewVertex = false;
402                             }
403                         }
404                         Vertex v = null;
405                         if (!isNewVertex) {
406                             v = vertices.get(0);
407                         }
408                         HashMap<String, Introspector> relatedObjects = new HashMap<>();
409                         String nodeOnly = params.getFirst("nodes-only");
410                         boolean isNodeOnly = nodeOnly != null;
411                         switch (method) {
412                             case GET:
413
414                                 if (format == null) {
415                                     obj = this.getObjectFromDb(vertices, serializer, query, obj, request.getUri(),
416                                             depth, isNodeOnly, cleanUp);
417
418                                     LoggingContext.elapsedTime((long) serializer.getDBTimeMsecs(),
419                                             TimeUnit.MILLISECONDS);
420                                     LOGGER.info("Completed");
421                                     LoggingContext.restoreIfPossible();
422
423                                     if (obj != null) {
424                                         status = Status.OK;
425                                         MarshallerProperties properties;
426                                         if (!request.getMarshallerProperties().isPresent()) {
427                                             properties = new MarshallerProperties.Builder(
428                                                     org.onap.aai.restcore.MediaType.getEnum(outputMediaType)).build();
429                                         } else {
430                                             properties = request.getMarshallerProperties().get();
431                                         }
432                                         result = obj.marshal(properties);
433                                     }
434                                 } else {
435                                     FormatFactory ff =
436                                             new FormatFactory(loader, serializer, schemaVersions, basePath + "/");
437                                     Formatter formatter = ff.get(format, params);
438                                     result = formatter.output(vertices.stream().map(vertex -> (Object) vertex)
439                                             .collect(Collectors.toList())).toString();
440                                     status = Status.OK;
441                                 }
442
443                                 break;
444                             case GET_RELATIONSHIP:
445                                 if (format == null) {
446                                     obj = this.getRelationshipObjectFromDb(vertices, serializer, query,
447                                             request.getInfo().getRequestUri());
448
449                                     LoggingContext.elapsedTime((long) serializer.getDBTimeMsecs(),
450                                             TimeUnit.MILLISECONDS);
451                                     LOGGER.info("Completed");
452                                     LoggingContext.restoreIfPossible();
453
454                                     if (obj != null) {
455                                         status = Status.OK;
456                                         MarshallerProperties properties;
457                                         if (!request.getMarshallerProperties().isPresent()) {
458                                             properties = new MarshallerProperties.Builder(
459                                                     org.onap.aai.restcore.MediaType.getEnum(outputMediaType)).build();
460                                         } else {
461                                             properties = request.getMarshallerProperties().get();
462                                         }
463                                         result = obj.marshal(properties);
464                                     } else {
465                                         String msg = createRelationshipNotFoundMessage(query.getResultType(),
466                                                 request.getUri());
467                                         throw new AAIException("AAI_6149", msg);
468                                     }
469                                 } else {
470                                     FormatFactory ff =
471                                             new FormatFactory(loader, serializer, schemaVersions, basePath + "/");
472                                     Formatter formatter = ff.get(format, params);
473                                     result = formatter.output(vertices.stream().map(vertex -> (Object) vertex)
474                                             .collect(Collectors.toList())).toString();
475                                     status = Status.OK;
476                                 }
477                                 break;
478                             case PUT:
479                                 response = this.invokeExtension(dbEngine, this.dbEngine.tx(), method, request,
480                                         sourceOfTruth, version, loader, obj, uri, true);
481                                 if (isNewVertex) {
482                                     v = serializer.createNewVertex(obj);
483                                 }
484                                 serializer.serializeToDb(obj, v, query, uri.getRawPath(), requestContext);
485                                 this.invokeExtension(dbEngine, this.dbEngine.tx(), HttpMethod.PUT, request,
486                                         sourceOfTruth, version, loader, obj, uri, false);
487                                 status = Status.OK;
488                                 if (isNewVertex) {
489                                     status = Status.CREATED;
490                                 }
491                                 obj = serializer.getLatestVersionView(v);
492                                 if (query.isDependent()) {
493                                     relatedObjects =
494                                             this.getRelatedObjects(serializer, queryEngine, v, obj, this.loader);
495                                 }
496                                 LoggingContext.elapsedTime(
497                                         (long) serializer.getDBTimeMsecs() + (long) queryEngine.getDBTimeMsecs(),
498                                         TimeUnit.MILLISECONDS);
499                                 LOGGER.info("Completed ");
500                                 LoggingContext.restoreIfPossible();
501                                 notification.createNotificationEvent(transactionId, sourceOfTruth, status, uri, obj,
502                                         relatedObjects, basePath);
503
504                                 break;
505                             case PUT_EDGE:
506                                 serializer.touchStandardVertexProperties(v, false);
507                                 this.invokeExtension(dbEngine, this.dbEngine.tx(), method, request, sourceOfTruth,
508                                         version, loader, obj, uri, true);
509                                 serializer.createEdge(obj, v);
510
511                                 LoggingContext.elapsedTime((long) serializer.getDBTimeMsecs(), TimeUnit.MILLISECONDS);
512                                 LOGGER.info("Completed");
513                                 LoggingContext.restoreIfPossible();
514                                 status = Status.OK;
515                                 notification.createNotificationEvent(transactionId, sourceOfTruth, status,
516                                         new URI(uri.toString().replace("/relationship-list/relationship", "")),
517                                         serializer.getLatestVersionView(v), relatedObjects, basePath);
518                                 break;
519                             case MERGE_PATCH:
520                                 Introspector existingObj = loader.introspectorFromName(obj.getDbName());
521                                 existingObj = this.getObjectFromDb(vertices, serializer, query, existingObj,
522                                         request.getUri(), 0, false, cleanUp);
523                                 String existingJson = existingObj.marshal(false);
524                                 String newJson;
525
526                                 if (request.getRawRequestContent().isPresent()) {
527                                     newJson = request.getRawRequestContent().get();
528                                 } else {
529                                     newJson = "";
530                                 }
531                                 Object relationshipList = request.getIntrospector().getValue("relationship-list");
532                                 ObjectMapper mapper = new ObjectMapper();
533                                 try {
534                                     JsonNode existingNode = mapper.readTree(existingJson);
535                                     JsonNode newNode = mapper.readTree(newJson);
536                                     JsonMergePatch patch = JsonMergePatch.fromJson(newNode);
537                                     JsonNode completed = patch.apply(existingNode);
538                                     String patched = mapper.writeValueAsString(completed);
539                                     Introspector patchedObj = loader.unmarshal(existingObj.getName(), patched);
540                                     if (relationshipList == null) {
541                                         // if the caller didn't touch the relationship-list, we shouldn't either
542                                         patchedObj.setValue("relationship-list", null);
543                                     }
544                                     serializer.serializeToDb(patchedObj, v, query, uri.getRawPath(), requestContext);
545                                     status = Status.OK;
546                                     patchedObj = serializer.getLatestVersionView(v);
547                                     if (query.isDependent()) {
548                                         relatedObjects = this.getRelatedObjects(serializer, queryEngine, v, patchedObj,
549                                                 this.loader);
550                                     }
551                                     LoggingContext.elapsedTime(
552                                             (long) serializer.getDBTimeMsecs() + (long) queryEngine.getDBTimeMsecs(),
553                                             TimeUnit.MILLISECONDS);
554                                     LOGGER.info("Completed");
555                                     LoggingContext.restoreIfPossible();
556                                     notification.createNotificationEvent(transactionId, sourceOfTruth, status, uri,
557                                             patchedObj, relatedObjects, basePath);
558                                 } catch (IOException | JsonPatchException e) {
559
560                                     LOGGER.info("Caught exception: " + e.getMessage());
561                                     LoggingContext.restoreIfPossible();
562                                     throw new AAIException("AAI_3000", "could not perform patch operation");
563                                 }
564                                 break;
565                             case DELETE:
566                                 String resourceVersion = params.getFirst("resource-version");
567                                 obj = serializer.getLatestVersionView(v);
568                                 if (query.isDependent()) {
569                                     relatedObjects =
570                                             this.getRelatedObjects(serializer, queryEngine, v, obj, this.loader);
571                                 }
572                                 /*
573                                  * Find all Delete-other-vertex vertices and create structure for notify
574                                  * findDeleatble also returns the startVertex v and we dont want to create
575                                  * duplicate notification events for the same
576                                  * So remove the startvertex first
577                                  */
578
579                                 List<Vertex> deletableVertices = dbEngine.getQueryEngine().findDeletable(v);
580                                 Long vId = (Long) v.id();
581
582                                 /*
583                                  * I am assuming vertexId cant be null
584                                  */
585                                 deletableVertices.removeIf(s -> vId.equals(s.id()));
586                                 boolean isDelVerticesPresent = !deletableVertices.isEmpty();
587                                 Map<Vertex, Introspector> deleteObjects = new HashMap<>();
588                                 Map<String, URI> uriMap = new HashMap<>();
589                                 Map<String, HashMap<String, Introspector>> deleteRelatedObjects = new HashMap<>();
590
591                                 if (isDelVerticesPresent) {
592                                     deleteObjects = this.buildIntrospectorObjects(serializer, deletableVertices);
593
594                                     uriMap = this.buildURIMap(serializer, deleteObjects);
595                                     deleteRelatedObjects =
596                                             this.buildRelatedObjects(serializer, queryEngine, deleteObjects);
597                                 }
598
599                                 this.invokeExtension(dbEngine, this.dbEngine.tx(), method, request, sourceOfTruth,
600                                         version, loader, obj, uri, true);
601                                 serializer.delete(v, deletableVertices, resourceVersion, enableResourceVersion);
602                                 this.invokeExtension(dbEngine, this.dbEngine.tx(), method, request, sourceOfTruth,
603                                         version, loader, obj, uri, false);
604
605                                 LoggingContext.elapsedTime(
606                                         (long) serializer.getDBTimeMsecs() + (long) queryEngine.getDBTimeMsecs(),
607                                         TimeUnit.MILLISECONDS);
608                                 LOGGER.info("Completed");
609                                 LoggingContext.restoreIfPossible();
610                                 status = Status.NO_CONTENT;
611                                 notification.createNotificationEvent(transactionId, sourceOfTruth, status, uri, obj,
612                                         relatedObjects, basePath);
613
614                                 /*
615                                  * Notify delete-other-v candidates
616                                  */
617
618                                 if (isDelVerticesPresent) {
619                                     this.buildNotificationEvent(sourceOfTruth, status, transactionId, notification,
620                                             deleteObjects, uriMap, deleteRelatedObjects, basePath);
621                                 }
622
623                                 break;
624                             case DELETE_EDGE:
625                                 serializer.touchStandardVertexProperties(v, false);
626                                 serializer.deleteEdge(obj, v);
627
628                                 LoggingContext.elapsedTime((long) serializer.getDBTimeMsecs(), TimeUnit.MILLISECONDS);
629                                 LOGGER.info("Completed");
630                                 LoggingContext.restoreIfPossible();
631                                 status = Status.NO_CONTENT;
632                                 notification.createNotificationEvent(transactionId, sourceOfTruth, Status.OK,
633                                         new URI(uri.toString().replace("/relationship-list/relationship", "")),
634                                         serializer.getLatestVersionView(v), relatedObjects, basePath);
635                                 break;
636                             default:
637                                 break;
638                         }
639
640                         /*
641                          * temporarily adding vertex id to the headers
642                          * to be able to use for testing the vertex id endpoint functionality
643                          * since we presently have no other way of generating those id urls
644                          */
645                         if (response == null && v != null
646                                 && (method.equals(HttpMethod.PUT) || method.equals(HttpMethod.GET)
647                                         || method.equals(HttpMethod.MERGE_PATCH)
648                                         || method.equals(HttpMethod.GET_RELATIONSHIP))
649
650                         ) {
651                             String myvertid = v.id().toString();
652                             if (this.isPaginated()) {
653                                 response = Response.status(status).header("vertex-id", myvertid)
654                                         .header("total-results", this.getTotalVertices())
655                                         .header("total-pages", this.getTotalPaginationBuckets()).entity(result)
656                                         .type(outputMediaType).build();
657                             } else {
658                                 response = Response.status(status).header("vertex-id", myvertid).entity(result)
659                                         .type(outputMediaType).build();
660                             }
661                         } else if (response == null) {
662                             response = Response.status(status).type(outputMediaType).build();
663                         } else {
664                             // response already set to something
665                         }
666                         Pair<URI, Response> pairedResp = Pair.with(request.getUri(), response);
667                         responses.add(pairedResp);
668                         // break out of retry loop
669                         break;
670                     } catch (JanusGraphException e) {
671                         this.dbEngine.rollback();
672
673                         LOGGER.info("Caught exception: " + e.getMessage());
674                         LoggingContext.restoreIfPossible();
675                         AAIException ex = new AAIException("AAI_6142", e);
676                         ErrorLogHelper.logException(ex);
677                         Thread.sleep((retry + 1) * 20L);
678                         this.dbEngine.startTransaction();
679                         queryEngine = dbEngine.getQueryEngine();
680                         serializer = new DBSerializer(version, dbEngine, introspectorFactoryType, sourceOfTruth);
681                     }
682                     if (retry == maxRetries) {
683                         throw new AAIException("AAI_6134");
684                     }
685                 }
686             } catch (AAIException e) {
687                 success = false;
688                 ArrayList<String> templateVars = new ArrayList<>();
689                 templateVars.add(request.getMethod().toString()); // GET, PUT, etc
690                 templateVars.add(request.getUri().getPath());
691                 templateVars.addAll(e.getTemplateVars());
692                 ErrorLogHelper.logException(e);
693                 response = Response.status(e.getErrorObject().getHTTPResponseCode()).entity(ErrorLogHelper
694                         .getRESTAPIErrorResponse(request.getHeaders().getAcceptableMediaTypes(), e, templateVars))
695                         .build();
696                 Pair<URI, Response> pairedResp = Pair.with(request.getUri(), response);
697                 responses.add(pairedResp);
698                 continue;
699             } catch (Exception e) {
700                 success = false;
701                 e.printStackTrace();
702                 AAIException ex = new AAIException("AAI_4000", e);
703                 ArrayList<String> templateVars = new ArrayList<String>();
704                 templateVars.add(request.getMethod().toString()); // GET, PUT, etc
705                 templateVars.add(request.getUri().getPath().toString());
706                 ErrorLogHelper.logException(ex);
707                 response = Response.status(ex.getErrorObject().getHTTPResponseCode()).entity(ErrorLogHelper
708                         .getRESTAPIErrorResponse(request.getHeaders().getAcceptableMediaTypes(), ex, templateVars))
709                         .build();
710                 Pair<URI, Response> pairedResp = Pair.with(request.getUri(), response);
711                 responses.add(pairedResp);
712                 continue;
713             }
714         }
715         notification.triggerEvents();
716         return Pair.with(success, responses);
717     }
718
719     /**
720      * Gets the media type.
721      *
722      * @param mediaTypeList the media type list
723      * @return the media type
724      */
725     private String getMediaType(List<MediaType> mediaTypeList) {
726         String mediaType = MediaType.APPLICATION_JSON; // json is the default
727         for (MediaType mt : mediaTypeList) {
728             if (MediaType.APPLICATION_XML_TYPE.isCompatible(mt)) {
729                 mediaType = MediaType.APPLICATION_XML;
730             }
731         }
732         return mediaType;
733     }
734
735     /**
736      * Gets the object from db.
737      *
738      * @param serializer the serializer
739      * @param query the query
740      * @param obj the obj
741      * @param uri the uri
742      * @param depth the depth
743      * @param cleanUp the clean up
744      * @return the object from db
745      * @throws AAIException the AAI exception
746      * @throws IllegalAccessException the illegal access exception
747      * @throws IllegalArgumentException the illegal argument exception
748      * @throws InvocationTargetException the invocation target exception
749      * @throws SecurityException the security exception
750      * @throws InstantiationException the instantiation exception
751      * @throws NoSuchMethodException the no such method exception
752      * @throws UnsupportedEncodingException the unsupported encoding exception
753      * @throws MalformedURLException the malformed URL exception
754      * @throws AAIUnknownObjectException
755      * @throws URISyntaxException
756      */
757     private Introspector getObjectFromDb(List<Vertex> results, DBSerializer serializer, QueryParser query,
758             Introspector obj, URI uri, int depth, boolean nodeOnly, String cleanUp)
759             throws AAIException, IllegalAccessException, IllegalArgumentException, InvocationTargetException,
760             SecurityException, InstantiationException, NoSuchMethodException, UnsupportedEncodingException,
761             AAIUnknownObjectException, URISyntaxException {
762
763         // nothing found
764         if (results.isEmpty()) {
765             String msg = createNotFoundMessage(query.getResultType(), uri);
766             throw new AAIException("AAI_6114", msg);
767         }
768
769         return serializer.dbToObject(results, obj, depth, nodeOnly, cleanUp);
770
771     }
772
773     /**
774      * Gets the object from db.
775      *
776      * @param serializer the serializer
777      * @param query the query
778      * @param obj the obj
779      * @param uri the uri
780      * @param depth the depth
781      * @param cleanUp the clean up
782      * @return the object from db
783      * @throws AAIException the AAI exception
784      * @throws IllegalAccessException the illegal access exception
785      * @throws IllegalArgumentException the illegal argument exception
786      * @throws InvocationTargetException the invocation target exception
787      * @throws SecurityException the security exception
788      * @throws InstantiationException the instantiation exception
789      * @throws NoSuchMethodException the no such method exception
790      * @throws UnsupportedEncodingException the unsupported encoding exception
791      * @throws MalformedURLException the malformed URL exception
792      * @throws AAIUnknownObjectException
793      * @throws URISyntaxException
794      */
795     private Introspector getRelationshipObjectFromDb(List<Vertex> results, DBSerializer serializer, QueryParser query,
796             URI uri) throws AAIException, IllegalArgumentException, SecurityException, UnsupportedEncodingException,
797             AAIUnknownObjectException {
798
799         // nothing found
800         if (results.isEmpty()) {
801             String msg = createNotFoundMessage(query.getResultType(), uri);
802             throw new AAIException("AAI_6114", msg);
803         }
804
805         if (results.size() > 1) {
806             throw new AAIException("AAI_6148", uri.getPath());
807         }
808
809         Vertex v = results.get(0);
810         return serializer.dbToRelationshipObject(v);
811     }
812
813     /**
814      * Invoke extension.
815      *
816      * @param dbEngine the db engine
817      * @param g the g
818      * @param httpMethod the http method
819      * @param fromAppId the from app id
820      * @param apiVersion the api version
821      * @param loader the loader
822      * @param obj the obj
823      * @param uri the uri
824      * @param isPreprocess the is preprocess
825      * @return the response
826      * @throws IllegalArgumentException the illegal argument exception
827      * @throws UnsupportedEncodingException the unsupported encoding exception
828      * @throws AAIException the AAI exception
829      */
830     private Response invokeExtension(TransactionalGraphEngine dbEngine, Graph g, HttpMethod httpMethod,
831             DBRequest request, String fromAppId, SchemaVersion apiVersion, Loader loader, Introspector obj, URI uri,
832             boolean isPreprocess) throws IllegalArgumentException, UnsupportedEncodingException, AAIException {
833         AAIExtensionMap aaiExtMap = new AAIExtensionMap();
834         // ModelInjestor injestor = ModelInjestor.getInstance();
835         Response response = null;
836         URIToExtensionInformation extensionInformation = new URIToExtensionInformation(loader, uri);
837         aaiExtMap.setHttpEntry(this);
838         aaiExtMap.setDbRequest(request);
839         aaiExtMap.setTransId(request.getTransactionId());
840         aaiExtMap.setFromAppId(fromAppId);
841         aaiExtMap.setGraph(g);
842         aaiExtMap.setApiVersion(apiVersion.toString());
843         aaiExtMap.setObjectFromRequest(obj);
844         aaiExtMap.setObjectFromRequestType(obj.getJavaClassName());
845         aaiExtMap.setObjectFromResponse(obj);
846         aaiExtMap.setObjectFromResponseType(obj.getJavaClassName());
847         aaiExtMap.setJaxbContext(nodeIngestor.getContextForVersion(apiVersion));
848         aaiExtMap.setUri(uri.getRawPath());
849         aaiExtMap.setTransactionalGraphEngine(dbEngine);
850         aaiExtMap.setLoader(loader);
851         aaiExtMap.setNamespace(extensionInformation.getNamespace());
852
853         ExtensionController ext = new ExtensionController();
854         ext.runExtension(aaiExtMap.getApiVersion(), extensionInformation.getNamespace(),
855                 extensionInformation.getTopObject(), extensionInformation.getMethodName(httpMethod, isPreprocess),
856                 aaiExtMap, isPreprocess);
857
858         if (aaiExtMap.getPrecheckAddedList().size() > 0) {
859             response = notifyOnSkeletonCreation(aaiExtMap, obj, request.getHeaders());
860         }
861
862         return response;
863     }
864
865     /**
866      * Notify on skeleton creation.
867      *
868      * @param aaiExtMap the aai ext map
869      * @param input the input
870      * @param headers the headers
871      * @return the response
872      */
873     // Legacy support
874     private Response notifyOnSkeletonCreation(AAIExtensionMap aaiExtMap, Introspector input, HttpHeaders headers) {
875         Response response = null;
876         HashMap<AAIException, ArrayList<String>> exceptionList = new HashMap<AAIException, ArrayList<String>>();
877
878         StringBuilder keyString = new StringBuilder();
879
880         Set<String> resourceKeys = input.getKeys();
881         for (String key : resourceKeys) {
882             keyString.append(key).append("=").append(input.getValue(key).toString()).append(" ");
883         }
884
885         for (AAIResponseMessage msg : aaiExtMap.getPrecheckResponseMessages().getAAIResponseMessage()) {
886             ArrayList<String> templateVars = new ArrayList<>();
887
888             templateVars.add("PUT " + input.getDbName());
889             templateVars.add(keyString.toString());
890             List<String> keys = new ArrayList<>();
891             templateVars.add(msg.getAaiResponseMessageResourceType());
892             for (AAIResponseMessageDatum dat : msg.getAaiResponseMessageData().getAAIResponseMessageDatum()) {
893                 keys.add(dat.getAaiResponseMessageDatumKey() + "=" + dat.getAaiResponseMessageDatumValue());
894             }
895             templateVars.add(StringUtils.join(keys, ", "));
896             exceptionList.put(new AAIException("AAI_0004", msg.getAaiResponseMessageResourceType()), templateVars);
897         }
898         response = Response.status(Status.ACCEPTED)
899                 .entity(ErrorLogHelper.getRESTAPIInfoResponse(headers.getAcceptableMediaTypes(), exceptionList))
900                 .build();
901
902         return response;
903     }
904
905     /**
906      * Creates the not found message.
907      *
908      * @param resultType the result type
909      * @param uri the uri
910      * @return the string
911      */
912     private String createNotFoundMessage(String resultType, URI uri) {
913
914         String msg = "No Node of type " + resultType + " found at: " + uri.getPath();
915
916         return msg;
917     }
918
919     /**
920      * Creates the not found message.
921      *
922      * @param resultType the result type
923      * @param uri the uri
924      * @return the string
925      */
926     private String createRelationshipNotFoundMessage(String resultType, URI uri) {
927
928         String msg = "No relationship found of type " + resultType + " at the given URI: " + uri.getPath()
929                 + "/relationship-list";
930
931         return msg;
932     }
933
934     /**
935      * Sets the depth.
936      *
937      * @param depthParam the depth param
938      * @return the int
939      * @throws AAIException the AAI exception
940      */
941     protected int setDepth(Introspector obj, String depthParam) throws AAIException {
942         int depth = AAIProperties.MAXIMUM_DEPTH;
943
944         String getAllRandomStr = AAIConfig.get("aai.rest.getall.depthparam", "");
945         if (depthParam != null && getAllRandomStr != null && !getAllRandomStr.isEmpty()
946                 && getAllRandomStr.equals(depthParam)) {
947             return depth;
948         }
949
950         if (depthParam == null) {
951             if (this.version.compareTo(schemaVersions.getDepthVersion()) >= 0) {
952                 depth = 0;
953             } else {
954                 depth = AAIProperties.MAXIMUM_DEPTH;
955             }
956         } else {
957             if (!depthParam.isEmpty() && !"all".equals(depthParam)) {
958                 try {
959                     depth = Integer.parseInt(depthParam);
960                 } catch (Exception e) {
961                     throw new AAIException("AAI_4016");
962                 }
963
964             }
965         }
966         String maxDepth = obj.getMetadata(ObjectMetadata.MAXIMUM_DEPTH);
967
968         int maximumDepth = AAIProperties.MAXIMUM_DEPTH;
969
970         if (maxDepth != null) {
971             try {
972                 maximumDepth = Integer.parseInt(maxDepth);
973             } catch (Exception ex) {
974                 throw new AAIException("AAI_4018");
975             }
976         }
977
978         if (depth > maximumDepth) {
979             throw new AAIException("AAI_3303");
980         }
981
982         return depth;
983     }
984
985     /**
986      * Checks if is modification method.
987      *
988      * @param method the method
989      * @return true, if is modification method
990      */
991     private boolean isModificationMethod(HttpMethod method) {
992         boolean result = false;
993
994         if (method.equals(HttpMethod.PUT) || method.equals(HttpMethod.PUT_EDGE) || method.equals(HttpMethod.DELETE_EDGE)
995                 || method.equals(HttpMethod.MERGE_PATCH)) {
996             result = true;
997         }
998
999         return result;
1000
1001     }
1002
1003     /**
1004      * Given an uri, introspector object and loader object
1005      * it will check if the obj is top level object if it is,
1006      * it will return immediately returning the uri passed in
1007      * If it isn't, it will go through, get the uriTemplate
1008      * from the introspector object and get the count of "/"s
1009      * and remove that part of the uri using substring
1010      * and keep doing that until the current object is top level
1011      * Also added the max depth just so worst case scenario
1012      * Then keep adding aai-uri to the list include the aai-uri passed in
1013      * Convert that list into an array and return it
1014      * <p>
1015      *
1016      * Example:
1017      *
1018      * <blockquote>
1019      * aai-uri ->
1020      * /cloud-infrastructure/cloud-regions/cloud-region/cloud-owner/cloud-region-id/tenants/tenant/tenant1/vservers/vserver/v1
1021      *
1022      * Given the uriTemplate vserver -> /vservers/vserver/{vserver-id}
1023      * it converts to /vservers/vserver
1024      *
1025      * lastIndexOf /vservers/vserver in
1026      * /cloud-infrastructure/cloud-regions/cloud-region/cloud-owner/cloud-region-id/tenants/tenant/tenant1/vservers/vserver/v1
1027      * ^
1028      * |
1029      * |
1030      * lastIndexOf
1031      * Use substring to get the string from 0 to that lastIndexOf
1032      * aai-uri -> /cloud-infrastructure/cloud-regions/cloud-region/cloud-owner/cloud-region-id/tenants/tenant/tenant1
1033      *
1034      * From this new aai-uri, generate a introspector from the URITOObject class
1035      * and keep doing this until you
1036      *
1037      * </blockquote>
1038      *
1039      * @param aaiUri - aai-uri of the vertex representating the unique id of a given vertex
1040      * @param obj - introspector object of the given starting vertex
1041      * @param loader - Type of loader which will always be MoxyLoader to support model driven
1042      * @return an array of strings which can be used to get the vertexes of parent and grand parents from a given vertex
1043      * @throws UnsupportedEncodingException
1044      * @throws AAIException
1045      */
1046     String[] convertIntrospectorToUriList(String aaiUri, Introspector obj, Loader loader)
1047             throws UnsupportedEncodingException, AAIException {
1048
1049         List<String> uriList = new ArrayList<>();
1050         String template = StringUtils.EMPTY;
1051         String truncatedUri = aaiUri;
1052         int depth = AAIProperties.MAXIMUM_DEPTH;
1053         uriList.add(truncatedUri);
1054
1055         while (depth >= 0 && !obj.isTopLevel()) {
1056             template = obj.getMetadata(ObjectMetadata.URI_TEMPLATE);
1057
1058             if (template == null) {
1059                 LOGGER.warn("Unable to find the uriTemplate for the object {}", obj.getDbName());
1060                 return null;
1061             }
1062
1063             int templateCount = StringUtils.countMatches(template, "/");
1064             int truncatedUriCount = StringUtils.countMatches(truncatedUri, "/");
1065
1066             if (templateCount > truncatedUriCount) {
1067                 LOGGER.warn("Template uri {} contains more slashes than truncatedUri {}", template, truncatedUri);
1068                 return null;
1069             }
1070
1071             int cutIndex = StringUtils.ordinalIndexOf(truncatedUri, "/", truncatedUriCount - templateCount + 1);
1072             truncatedUri = StringUtils.substring(truncatedUri, 0, cutIndex);
1073             uriList.add(truncatedUri);
1074             obj = new URIToObject(loader, UriBuilder.fromPath(truncatedUri).build()).getEntity();
1075             depth--;
1076         }
1077
1078         return uriList.toArray(new String[uriList.size()]);
1079     }
1080
1081     /**
1082      *
1083      * @param serializer
1084      * @param queryEngine
1085      * @param v
1086      * @param obj
1087      * @param loader
1088      * @return
1089      * @throws IllegalAccessException
1090      * @throws IllegalArgumentException
1091      * @throws InvocationTargetException
1092      * @throws SecurityException
1093      * @throws InstantiationException
1094      * @throws NoSuchMethodException
1095      * @throws UnsupportedEncodingException
1096      * @throws AAIException
1097      * @throws URISyntaxException
1098      */
1099     private HashMap<String, Introspector> getRelatedObjects(DBSerializer serializer, QueryEngine queryEngine, Vertex v,
1100             Introspector obj, Loader loader) throws IllegalAccessException, IllegalArgumentException,
1101             InvocationTargetException, SecurityException, InstantiationException, NoSuchMethodException,
1102             UnsupportedEncodingException, AAIException, URISyntaxException {
1103
1104         HashMap<String, Introspector> relatedVertices = new HashMap<>();
1105         VertexProperty aaiUriProperty = v.property(AAIProperties.AAI_URI);
1106
1107         if (!aaiUriProperty.isPresent()) {
1108             if (LOGGER.isDebugEnabled()) {
1109                 LOGGER.debug("For the given vertex {}, it seems aai-uri is not present so not getting related objects",
1110                         v.id().toString());
1111             } else {
1112                 LOGGER.info(
1113                         "It seems aai-uri is not present in vertex, so not getting related objects, for more info enable debug log");
1114             }
1115             return relatedVertices;
1116         }
1117
1118         String aaiUri = aaiUriProperty.value().toString();
1119
1120         if (!obj.isTopLevel()) {
1121             String[] uriList = convertIntrospectorToUriList(aaiUri, obj, loader);
1122             List<Vertex> vertexChain = null;
1123             // If the uriList is null then there is something wrong with converting the uri
1124             // into a list of aai-uris so falling back to the old mechanism for finding parents
1125             if (uriList == null) {
1126                 LOGGER.info(
1127                         "Falling back to the old mechanism due to unable to convert aai-uri to list of uris but this is not optimal");
1128                 vertexChain = queryEngine.findParents(v);
1129             } else {
1130                 vertexChain = queryEngine.findParents(uriList);
1131             }
1132             for (Vertex vertex : vertexChain) {
1133                 try {
1134                     final Introspector vertexObj = serializer.getVertexProperties(vertex);
1135                     relatedVertices.put(vertexObj.getObjectId(), vertexObj);
1136                 } catch (AAIUnknownObjectException e) {
1137                     LOGGER.warn("Unable to get vertex properties, partial list of related vertices returned");
1138                 }
1139             }
1140         } else {
1141             try {
1142                 final Introspector vertexObj = serializer.getVertexProperties(v);
1143                 relatedVertices.put(vertexObj.getObjectId(), vertexObj);
1144             } catch (AAIUnknownObjectException e) {
1145                 LOGGER.warn("Unable to get vertex properties, partial list of related vertices returned");
1146             }
1147         }
1148
1149         return relatedVertices;
1150     }
1151
1152     private Map<Vertex, Introspector> buildIntrospectorObjects(DBSerializer serializer, Iterable<Vertex> vertices) {
1153         Map<Vertex, Introspector> deleteObjectMap = new HashMap<>();
1154         for (Vertex vertex : vertices) {
1155             try {
1156                 // deleteObjectMap.computeIfAbsent(vertex, s ->
1157                 // serializer.getLatestVersionView(vertex));
1158                 Introspector deleteObj = serializer.getLatestVersionView(vertex);
1159                 deleteObjectMap.put(vertex, deleteObj);
1160             } catch (UnsupportedEncodingException | AAIException e) {
1161                 LOGGER.warn("Unable to get Introspctor Objects, Just continue");
1162                 continue;
1163             }
1164
1165         }
1166
1167         return deleteObjectMap;
1168
1169     }
1170
1171     private Map<String, URI> buildURIMap(DBSerializer serializer, Map<Vertex, Introspector> introSpector) {
1172         Map<String, URI> uriMap = new HashMap<>();
1173         for (Map.Entry<Vertex, Introspector> entry : introSpector.entrySet()) {
1174             URI uri;
1175             try {
1176                 uri = serializer.getURIForVertex(entry.getKey());
1177                 if (null != entry.getValue()) {
1178                     uriMap.put(entry.getValue().getObjectId(), uri);
1179                 }
1180             } catch (UnsupportedEncodingException e) {
1181                 LOGGER.warn("Unable to get URIs, Just continue");
1182                 continue;
1183             }
1184
1185         }
1186
1187         return uriMap;
1188
1189     }
1190
1191     private Map<String, HashMap<String, Introspector>> buildRelatedObjects(DBSerializer serializer,
1192             QueryEngine queryEngine, Map<Vertex, Introspector> introSpector) {
1193
1194         Map<String, HashMap<String, Introspector>> relatedObjectsMap = new HashMap<>();
1195         for (Map.Entry<Vertex, Introspector> entry : introSpector.entrySet()) {
1196             try {
1197                 HashMap<String, Introspector> relatedObjects =
1198                         this.getRelatedObjects(serializer, queryEngine, entry.getKey(), entry.getValue(), this.loader);
1199                 if (null != entry.getValue()) {
1200                     relatedObjectsMap.put(entry.getValue().getObjectId(), relatedObjects);
1201                 }
1202             } catch (IllegalAccessException | IllegalArgumentException | InvocationTargetException | SecurityException
1203                     | InstantiationException | NoSuchMethodException | UnsupportedEncodingException | AAIException
1204                     | URISyntaxException e) {
1205                 LOGGER.warn("Unable to get realted Objects, Just continue");
1206                 continue;
1207             }
1208
1209         }
1210
1211         return relatedObjectsMap;
1212
1213     }
1214
1215     private void buildNotificationEvent(String sourceOfTruth, Status status, String transactionId,
1216             UEBNotification notification, Map<Vertex, Introspector> deleteObjects, Map<String, URI> uriMap,
1217             Map<String, HashMap<String, Introspector>> deleteRelatedObjects, String basePath) {
1218         for (Map.Entry<Vertex, Introspector> entry : deleteObjects.entrySet()) {
1219             try {
1220                 String vertexObjectId = "";
1221
1222                 if (null != entry.getValue()) {
1223                     vertexObjectId = entry.getValue().getObjectId();
1224
1225                     if (uriMap.containsKey(vertexObjectId) && deleteRelatedObjects.containsKey(vertexObjectId)) {
1226                         notification.createNotificationEvent(transactionId, sourceOfTruth, status,
1227                                 uriMap.get(vertexObjectId), entry.getValue(), deleteRelatedObjects.get(vertexObjectId),
1228                                 basePath);
1229                     }
1230                 }
1231             } catch (UnsupportedEncodingException | AAIException e) {
1232
1233                 LOGGER.warn("Error in sending notification");
1234             }
1235         }
1236     }
1237
1238     public void setPaginationParameters(String resultIndex, String resultSize) {
1239         if (resultIndex != null && resultIndex != "-1" && resultSize != null && resultSize != "-1") {
1240             this.setPaginationIndex(Integer.parseInt(resultIndex));
1241             this.setPaginationBucket(Integer.parseInt(resultSize));
1242         }
1243     }
1244
1245     public List<Object> getPaginatedVertexList(List<Object> vertexList) throws AAIException {
1246         List<Object> vertices;
1247         if (this.isPaginated()) {
1248             this.setTotalsForPaging(vertexList.size(), this.getPaginationBucket());
1249             int startIndex = (this.getPaginationIndex() - 1) * this.getPaginationBucket();
1250             int endIndex = Math.min((this.getPaginationBucket() * this.getPaginationIndex()), vertexList.size());
1251             if (startIndex > endIndex) {
1252                 throw new AAIException("AAI_6150",
1253                         " ResultIndex is not appropriate for the result set, Needs to be <= " + endIndex);
1254             }
1255             vertices = vertexList.subList(startIndex, endIndex);
1256         } else {
1257             vertices = vertexList;
1258         }
1259         return vertices;
1260     }
1261 }