Update core logic to change how to
[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                 try {
331
332                     LoggingContext.targetEntity(TARGET_ENTITY);
333                     LoggingContext.targetServiceName(methodName + " " + method);
334
335                     obj = request.getIntrospector();
336                     query = request.getParser();
337                     transactionId = request.getTransactionId();
338                     uriTemp = request.getUri().getRawPath().replaceFirst("^v\\d+/", "");
339                     uri = UriBuilder.fromPath(uriTemp).build();
340                     LoggingContext.startTime();
341                     List<Vertex> vertTemp;
342                     List<Vertex> vertices;
343                     if (this.isPaginated()) {
344                         vertTemp = query.getQueryBuilder().toList();
345                         this.setTotalsForPaging(vertTemp.size(), this.paginationBucket);
346                         vertices = vertTemp.subList(((this.paginationIndex - 1) * this.paginationBucket),
347                                 Math.min((this.paginationBucket * this.paginationIndex), vertTemp.size()));
348                     } else {
349                         vertices = query.getQueryBuilder().toList();
350                     }
351                     boolean isNewVertex = false;
352                     String outputMediaType = getMediaType(request.getHeaders().getAcceptableMediaTypes());
353                     String result = null;
354                     params = request.getInfo().getQueryParameters(false);
355                     depth = setDepth(obj, params.getFirst("depth"));
356                     if (params.containsKey("format")) {
357                         format = Format.getFormat(params.getFirst("format"));
358                     }
359                     String cleanUp = params.getFirst("cleanup");
360                     String requestContext = "";
361                     List<String> requestContextList = request.getHeaders().getRequestHeader("aai-request-context");
362                     if (requestContextList != null) {
363                         requestContext = requestContextList.get(0);
364                     }
365
366                     if (cleanUp == null) {
367                         cleanUp = "false";
368                     }
369                     if (vertices.size() > 1 && processSingle
370                             && !(method.equals(HttpMethod.GET) || method.equals(HttpMethod.GET_RELATIONSHIP))) {
371                         if (method.equals(HttpMethod.DELETE)) {
372                             LoggingContext.restoreIfPossible();
373                             throw new AAIException("AAI_6138");
374                         } else {
375                             LoggingContext.restoreIfPossible();
376                             throw new AAIException("AAI_6137");
377                         }
378                     }
379                     if (method.equals(HttpMethod.PUT)) {
380                         String resourceVersion = (String) obj.getValue("resource-version");
381                         if (vertices.isEmpty()) {
382                             if (enableResourceVersion) {
383                                 serializer.verifyResourceVersion("create", query.getResultType(), "",
384                                         resourceVersion, obj.getURI());
385                             }
386                             isNewVertex = true;
387                         } else {
388                             if (enableResourceVersion) {
389                                 serializer.verifyResourceVersion("update", query.getResultType(),
390                                         vertices.get(0).<String>property("resource-version").orElse(null),
391                                         resourceVersion, obj.getURI());
392                             }
393                             isNewVertex = false;
394                         }
395                     } else {
396                         if (vertices.isEmpty()) {
397                             String msg = createNotFoundMessage(query.getResultType(), request.getUri());
398                             throw new AAIException("AAI_6114", msg);
399                         } else {
400                             isNewVertex = false;
401                         }
402                     }
403                     Vertex v = null;
404                     if (!isNewVertex) {
405                         v = vertices.get(0);
406                     }
407                     HashMap<String, Introspector> relatedObjects = new HashMap<>();
408                     String nodeOnly = params.getFirst("nodes-only");
409                     boolean isNodeOnly = nodeOnly != null;
410                     switch (method) {
411                         case GET:
412
413                             if (format == null) {
414                                 obj = this.getObjectFromDb(vertices, serializer, query, obj, request.getUri(),
415                                         depth, isNodeOnly, cleanUp);
416
417                                 LoggingContext.elapsedTime((long) serializer.getDBTimeMsecs(),
418                                         TimeUnit.MILLISECONDS);
419                                 LOGGER.info("Completed");
420                                 LoggingContext.restoreIfPossible();
421
422                                 if (obj != null) {
423                                     status = Status.OK;
424                                     MarshallerProperties properties;
425                                     if (!request.getMarshallerProperties().isPresent()) {
426                                         properties = new MarshallerProperties.Builder(
427                                                 org.onap.aai.restcore.MediaType.getEnum(outputMediaType)).build();
428                                     } else {
429                                         properties = request.getMarshallerProperties().get();
430                                     }
431                                     result = obj.marshal(properties);
432                                 }
433                             } else {
434                                 FormatFactory ff =
435                                         new FormatFactory(loader, serializer, schemaVersions, basePath + "/");
436                                 Formatter formatter = ff.get(format, params);
437                                 result = formatter.output(vertices.stream().map(vertex -> (Object) vertex)
438                                         .collect(Collectors.toList())).toString();
439                                 status = Status.OK;
440                             }
441
442                             break;
443                         case GET_RELATIONSHIP:
444                             if (format == null) {
445                                 obj = this.getRelationshipObjectFromDb(vertices, serializer, query,
446                                         request.getInfo().getRequestUri());
447
448                                 LoggingContext.elapsedTime((long) serializer.getDBTimeMsecs(),
449                                         TimeUnit.MILLISECONDS);
450                                 LOGGER.info("Completed");
451                                 LoggingContext.restoreIfPossible();
452
453                                 if (obj != null) {
454                                     status = Status.OK;
455                                     MarshallerProperties properties;
456                                     if (!request.getMarshallerProperties().isPresent()) {
457                                         properties = new MarshallerProperties.Builder(
458                                                 org.onap.aai.restcore.MediaType.getEnum(outputMediaType)).build();
459                                     } else {
460                                         properties = request.getMarshallerProperties().get();
461                                     }
462                                     result = obj.marshal(properties);
463                                 } else {
464                                     String msg = createRelationshipNotFoundMessage(query.getResultType(),
465                                             request.getUri());
466                                     throw new AAIException("AAI_6149", msg);
467                                 }
468                             } else {
469                                 FormatFactory ff =
470                                         new FormatFactory(loader, serializer, schemaVersions, basePath + "/");
471                                 Formatter formatter = ff.get(format, params);
472                                 result = formatter.output(vertices.stream().map(vertex -> (Object) vertex)
473                                         .collect(Collectors.toList())).toString();
474                                 status = Status.OK;
475                             }
476                             break;
477                         case PUT:
478                             response = this.invokeExtension(dbEngine, this.dbEngine.tx(), method, request,
479                                     sourceOfTruth, version, loader, obj, uri, true);
480                             if (isNewVertex) {
481                                 v = serializer.createNewVertex(obj);
482                             }
483                             serializer.serializeToDb(obj, v, query, uri.getRawPath(), requestContext);
484                             this.invokeExtension(dbEngine, this.dbEngine.tx(), HttpMethod.PUT, request,
485                                     sourceOfTruth, version, loader, obj, uri, false);
486                             status = Status.OK;
487                             if (isNewVertex) {
488                                 status = Status.CREATED;
489                             }
490                             obj = serializer.getLatestVersionView(v);
491                             if (query.isDependent()) {
492                                 relatedObjects =
493                                         this.getRelatedObjects(serializer, queryEngine, v, obj, this.loader);
494                             }
495                             LoggingContext.elapsedTime(
496                                     (long) serializer.getDBTimeMsecs() + (long) queryEngine.getDBTimeMsecs(),
497                                     TimeUnit.MILLISECONDS);
498                             LOGGER.info("Completed ");
499                             LoggingContext.restoreIfPossible();
500                             notification.createNotificationEvent(transactionId, sourceOfTruth, status, uri, obj,
501                                     relatedObjects, basePath);
502
503                             break;
504                         case PUT_EDGE:
505                             serializer.touchStandardVertexProperties(v, false);
506                             this.invokeExtension(dbEngine, this.dbEngine.tx(), method, request, sourceOfTruth,
507                                     version, loader, obj, uri, true);
508                             serializer.createEdge(obj, v);
509
510                             LoggingContext.elapsedTime((long) serializer.getDBTimeMsecs(), TimeUnit.MILLISECONDS);
511                             LOGGER.info("Completed");
512                             LoggingContext.restoreIfPossible();
513                             status = Status.OK;
514                             notification.createNotificationEvent(transactionId, sourceOfTruth, status,
515                                     new URI(uri.toString().replace("/relationship-list/relationship", "")),
516                                     serializer.getLatestVersionView(v), relatedObjects, basePath);
517                             break;
518                         case MERGE_PATCH:
519                             Introspector existingObj = loader.introspectorFromName(obj.getDbName());
520                             existingObj = this.getObjectFromDb(vertices, serializer, query, existingObj,
521                                     request.getUri(), 0, false, cleanUp);
522                             String existingJson = existingObj.marshal(false);
523                             String newJson;
524
525                             if (request.getRawRequestContent().isPresent()) {
526                                 newJson = request.getRawRequestContent().get();
527                             } else {
528                                 newJson = "";
529                             }
530                             Object relationshipList = request.getIntrospector().getValue("relationship-list");
531                             ObjectMapper mapper = new ObjectMapper();
532                             try {
533                                 JsonNode existingNode = mapper.readTree(existingJson);
534                                 JsonNode newNode = mapper.readTree(newJson);
535                                 JsonMergePatch patch = JsonMergePatch.fromJson(newNode);
536                                 JsonNode completed = patch.apply(existingNode);
537                                 String patched = mapper.writeValueAsString(completed);
538                                 Introspector patchedObj = loader.unmarshal(existingObj.getName(), patched);
539                                 if (relationshipList == null) {
540                                     // if the caller didn't touch the relationship-list, we shouldn't either
541                                     patchedObj.setValue("relationship-list", null);
542                                 }
543                                 serializer.serializeToDb(patchedObj, v, query, uri.getRawPath(), requestContext);
544                                 status = Status.OK;
545                                 patchedObj = serializer.getLatestVersionView(v);
546                                 if (query.isDependent()) {
547                                     relatedObjects = this.getRelatedObjects(serializer, queryEngine, v, patchedObj,
548                                             this.loader);
549                                 }
550                                 LoggingContext.elapsedTime(
551                                         (long) serializer.getDBTimeMsecs() + (long) queryEngine.getDBTimeMsecs(),
552                                         TimeUnit.MILLISECONDS);
553                                 LOGGER.info("Completed");
554                                 LoggingContext.restoreIfPossible();
555                                 notification.createNotificationEvent(transactionId, sourceOfTruth, status, uri,
556                                         patchedObj, relatedObjects, basePath);
557                             } catch (IOException | JsonPatchException e) {
558
559                                 LOGGER.info("Caught exception: " + e.getMessage());
560                                 LoggingContext.restoreIfPossible();
561                                 throw new AAIException("AAI_3000", "could not perform patch operation");
562                             }
563                             break;
564                         case DELETE:
565                             String resourceVersion = params.getFirst("resource-version");
566                             obj = serializer.getLatestVersionView(v);
567                             if (query.isDependent()) {
568                                 relatedObjects =
569                                         this.getRelatedObjects(serializer, queryEngine, v, obj, this.loader);
570                             }
571                             /*
572                              * Find all Delete-other-vertex vertices and create structure for notify
573                              * findDeleatble also returns the startVertex v and we dont want to create
574                              * duplicate notification events for the same
575                              * So remove the startvertex first
576                              */
577
578                             List<Vertex> deletableVertices = dbEngine.getQueryEngine().findDeletable(v);
579                             Long vId = (Long) v.id();
580
581                             /*
582                              * I am assuming vertexId cant be null
583                              */
584                             deletableVertices.removeIf(s -> vId.equals(s.id()));
585                             boolean isDelVerticesPresent = !deletableVertices.isEmpty();
586                             Map<Vertex, Introspector> deleteObjects = new HashMap<>();
587                             Map<String, URI> uriMap = new HashMap<>();
588                             Map<String, HashMap<String, Introspector>> deleteRelatedObjects = new HashMap<>();
589
590                             if (isDelVerticesPresent) {
591                                 deleteObjects = this.buildIntrospectorObjects(serializer, deletableVertices);
592
593                                 uriMap = this.buildURIMap(serializer, deleteObjects);
594                                 deleteRelatedObjects =
595                                         this.buildRelatedObjects(serializer, queryEngine, deleteObjects);
596                             }
597
598                             this.invokeExtension(dbEngine, this.dbEngine.tx(), method, request, sourceOfTruth,
599                                     version, loader, obj, uri, true);
600                             serializer.delete(v, deletableVertices, resourceVersion, enableResourceVersion);
601                             this.invokeExtension(dbEngine, this.dbEngine.tx(), method, request, sourceOfTruth,
602                                     version, loader, obj, uri, false);
603
604                             LoggingContext.elapsedTime(
605                                     (long) serializer.getDBTimeMsecs() + (long) queryEngine.getDBTimeMsecs(),
606                                     TimeUnit.MILLISECONDS);
607                             LOGGER.info("Completed");
608                             LoggingContext.restoreIfPossible();
609                             status = Status.NO_CONTENT;
610                             notification.createNotificationEvent(transactionId, sourceOfTruth, status, uri, obj,
611                                     relatedObjects, basePath);
612
613                             /*
614                              * Notify delete-other-v candidates
615                              */
616
617                             if (isDelVerticesPresent) {
618                                 this.buildNotificationEvent(sourceOfTruth, status, transactionId, notification,
619                                         deleteObjects, uriMap, deleteRelatedObjects, basePath);
620                             }
621
622                             break;
623                         case DELETE_EDGE:
624                             serializer.touchStandardVertexProperties(v, false);
625                             serializer.deleteEdge(obj, v);
626
627                             LoggingContext.elapsedTime((long) serializer.getDBTimeMsecs(), TimeUnit.MILLISECONDS);
628                             LOGGER.info("Completed");
629                             LoggingContext.restoreIfPossible();
630                             status = Status.NO_CONTENT;
631                             notification.createNotificationEvent(transactionId, sourceOfTruth, Status.OK,
632                                     new URI(uri.toString().replace("/relationship-list/relationship", "")),
633                                     serializer.getLatestVersionView(v), relatedObjects, basePath);
634                             break;
635                         default:
636                             break;
637                     }
638
639                     /*
640                      * temporarily adding vertex id to the headers
641                      * to be able to use for testing the vertex id endpoint functionality
642                      * since we presently have no other way of generating those id urls
643                      */
644                     if (response == null && v != null
645                             && (method.equals(HttpMethod.PUT) || method.equals(HttpMethod.GET)
646                                     || method.equals(HttpMethod.MERGE_PATCH)
647                                     || method.equals(HttpMethod.GET_RELATIONSHIP))
648
649                     ) {
650                         String myvertid = v.id().toString();
651                         if (this.isPaginated()) {
652                             response = Response.status(status).header("vertex-id", myvertid)
653                                     .header("total-results", this.getTotalVertices())
654                                     .header("total-pages", this.getTotalPaginationBuckets()).entity(result)
655                                     .type(outputMediaType).build();
656                         } else {
657                             response = Response.status(status).header("vertex-id", myvertid).entity(result)
658                                     .type(outputMediaType).build();
659                         }
660                     } else if (response == null) {
661                         response = Response.status(status).type(outputMediaType).build();
662                     } else {
663                         // response already set to something
664                     }
665                     Pair<URI, Response> pairedResp = Pair.with(request.getUri(), response);
666                     responses.add(pairedResp);
667                 } catch (JanusGraphException e) {
668                     this.dbEngine.rollback();
669
670                     LOGGER.info("Caught exception: " + e.getMessage());
671                     LoggingContext.restoreIfPossible();
672                     throw new AAIException("AAI_6134", e);
673                 }
674                 if (retry == maxRetries) {
675                     throw new AAIException("AAI_6134");
676                 }
677             } catch (AAIException e) {
678                 success = false;
679                 ArrayList<String> templateVars = new ArrayList<>();
680                 templateVars.add(request.getMethod().toString()); // GET, PUT, etc
681                 templateVars.add(request.getUri().getPath());
682                 templateVars.addAll(e.getTemplateVars());
683                 ErrorLogHelper.logException(e);
684                 response = Response.status(e.getErrorObject().getHTTPResponseCode()).entity(ErrorLogHelper
685                         .getRESTAPIErrorResponse(request.getHeaders().getAcceptableMediaTypes(), e, templateVars))
686                         .build();
687                 Pair<URI, Response> pairedResp = Pair.with(request.getUri(), response);
688                 responses.add(pairedResp);
689                 continue;
690             } catch (Exception e) {
691                 success = false;
692                 e.printStackTrace();
693                 AAIException ex = new AAIException("AAI_4000", e);
694                 ArrayList<String> templateVars = new ArrayList<String>();
695                 templateVars.add(request.getMethod().toString()); // GET, PUT, etc
696                 templateVars.add(request.getUri().getPath().toString());
697                 ErrorLogHelper.logException(ex);
698                 response = Response.status(ex.getErrorObject().getHTTPResponseCode()).entity(ErrorLogHelper
699                         .getRESTAPIErrorResponse(request.getHeaders().getAcceptableMediaTypes(), ex, templateVars))
700                         .build();
701                 Pair<URI, Response> pairedResp = Pair.with(request.getUri(), response);
702                 responses.add(pairedResp);
703                 continue;
704             }
705         }
706         notification.triggerEvents();
707         return Pair.with(success, responses);
708     }
709
710     /**
711      * Gets the media type.
712      *
713      * @param mediaTypeList the media type list
714      * @return the media type
715      */
716     private String getMediaType(List<MediaType> mediaTypeList) {
717         String mediaType = MediaType.APPLICATION_JSON; // json is the default
718         for (MediaType mt : mediaTypeList) {
719             if (MediaType.APPLICATION_XML_TYPE.isCompatible(mt)) {
720                 mediaType = MediaType.APPLICATION_XML;
721             }
722         }
723         return mediaType;
724     }
725
726     /**
727      * Gets the object from db.
728      *
729      * @param serializer the serializer
730      * @param query the query
731      * @param obj the obj
732      * @param uri the uri
733      * @param depth the depth
734      * @param cleanUp the clean up
735      * @return the object from db
736      * @throws AAIException the AAI exception
737      * @throws IllegalAccessException the illegal access exception
738      * @throws IllegalArgumentException the illegal argument exception
739      * @throws InvocationTargetException the invocation target exception
740      * @throws SecurityException the security exception
741      * @throws InstantiationException the instantiation exception
742      * @throws NoSuchMethodException the no such method exception
743      * @throws UnsupportedEncodingException the unsupported encoding exception
744      * @throws MalformedURLException the malformed URL exception
745      * @throws AAIUnknownObjectException
746      * @throws URISyntaxException
747      */
748     private Introspector getObjectFromDb(List<Vertex> results, DBSerializer serializer, QueryParser query,
749             Introspector obj, URI uri, int depth, boolean nodeOnly, String cleanUp)
750             throws AAIException, IllegalAccessException, IllegalArgumentException, InvocationTargetException,
751             SecurityException, InstantiationException, NoSuchMethodException, UnsupportedEncodingException,
752             AAIUnknownObjectException, URISyntaxException {
753
754         // nothing found
755         if (results.isEmpty()) {
756             String msg = createNotFoundMessage(query.getResultType(), uri);
757             throw new AAIException("AAI_6114", msg);
758         }
759
760         return serializer.dbToObject(results, obj, depth, nodeOnly, cleanUp);
761
762     }
763
764     /**
765      * Gets the object from db.
766      *
767      * @param serializer the serializer
768      * @param query the query
769      * @param obj the obj
770      * @param uri the uri
771      * @param depth the depth
772      * @param cleanUp the clean up
773      * @return the object from db
774      * @throws AAIException the AAI exception
775      * @throws IllegalAccessException the illegal access exception
776      * @throws IllegalArgumentException the illegal argument exception
777      * @throws InvocationTargetException the invocation target exception
778      * @throws SecurityException the security exception
779      * @throws InstantiationException the instantiation exception
780      * @throws NoSuchMethodException the no such method exception
781      * @throws UnsupportedEncodingException the unsupported encoding exception
782      * @throws MalformedURLException the malformed URL exception
783      * @throws AAIUnknownObjectException
784      * @throws URISyntaxException
785      */
786     private Introspector getRelationshipObjectFromDb(List<Vertex> results, DBSerializer serializer, QueryParser query,
787             URI uri) throws AAIException, IllegalArgumentException, SecurityException, UnsupportedEncodingException,
788             AAIUnknownObjectException {
789
790         // nothing found
791         if (results.isEmpty()) {
792             String msg = createNotFoundMessage(query.getResultType(), uri);
793             throw new AAIException("AAI_6114", msg);
794         }
795
796         if (results.size() > 1) {
797             throw new AAIException("AAI_6148", uri.getPath());
798         }
799
800         Vertex v = results.get(0);
801         return serializer.dbToRelationshipObject(v);
802     }
803
804     /**
805      * Invoke extension.
806      *
807      * @param dbEngine the db engine
808      * @param g the g
809      * @param httpMethod the http method
810      * @param fromAppId the from app id
811      * @param apiVersion the api version
812      * @param loader the loader
813      * @param obj the obj
814      * @param uri the uri
815      * @param isPreprocess the is preprocess
816      * @return the response
817      * @throws IllegalArgumentException the illegal argument exception
818      * @throws UnsupportedEncodingException the unsupported encoding exception
819      * @throws AAIException the AAI exception
820      */
821     private Response invokeExtension(TransactionalGraphEngine dbEngine, Graph g, HttpMethod httpMethod,
822             DBRequest request, String fromAppId, SchemaVersion apiVersion, Loader loader, Introspector obj, URI uri,
823             boolean isPreprocess) throws IllegalArgumentException, UnsupportedEncodingException, AAIException {
824         AAIExtensionMap aaiExtMap = new AAIExtensionMap();
825         // ModelInjestor injestor = ModelInjestor.getInstance();
826         Response response = null;
827         URIToExtensionInformation extensionInformation = new URIToExtensionInformation(loader, uri);
828         aaiExtMap.setHttpEntry(this);
829         aaiExtMap.setDbRequest(request);
830         aaiExtMap.setTransId(request.getTransactionId());
831         aaiExtMap.setFromAppId(fromAppId);
832         aaiExtMap.setGraph(g);
833         aaiExtMap.setApiVersion(apiVersion.toString());
834         aaiExtMap.setObjectFromRequest(obj);
835         aaiExtMap.setObjectFromRequestType(obj.getJavaClassName());
836         aaiExtMap.setObjectFromResponse(obj);
837         aaiExtMap.setObjectFromResponseType(obj.getJavaClassName());
838         aaiExtMap.setJaxbContext(nodeIngestor.getContextForVersion(apiVersion));
839         aaiExtMap.setUri(uri.getRawPath());
840         aaiExtMap.setTransactionalGraphEngine(dbEngine);
841         aaiExtMap.setLoader(loader);
842         aaiExtMap.setNamespace(extensionInformation.getNamespace());
843
844         ExtensionController ext = new ExtensionController();
845         ext.runExtension(aaiExtMap.getApiVersion(), extensionInformation.getNamespace(),
846                 extensionInformation.getTopObject(), extensionInformation.getMethodName(httpMethod, isPreprocess),
847                 aaiExtMap, isPreprocess);
848
849         if (aaiExtMap.getPrecheckAddedList().size() > 0) {
850             response = notifyOnSkeletonCreation(aaiExtMap, obj, request.getHeaders());
851         }
852
853         return response;
854     }
855
856     /**
857      * Notify on skeleton creation.
858      *
859      * @param aaiExtMap the aai ext map
860      * @param input the input
861      * @param headers the headers
862      * @return the response
863      */
864     // Legacy support
865     private Response notifyOnSkeletonCreation(AAIExtensionMap aaiExtMap, Introspector input, HttpHeaders headers) {
866         Response response = null;
867         HashMap<AAIException, ArrayList<String>> exceptionList = new HashMap<AAIException, ArrayList<String>>();
868
869         StringBuilder keyString = new StringBuilder();
870
871         Set<String> resourceKeys = input.getKeys();
872         for (String key : resourceKeys) {
873             keyString.append(key).append("=").append(input.getValue(key).toString()).append(" ");
874         }
875
876         for (AAIResponseMessage msg : aaiExtMap.getPrecheckResponseMessages().getAAIResponseMessage()) {
877             ArrayList<String> templateVars = new ArrayList<>();
878
879             templateVars.add("PUT " + input.getDbName());
880             templateVars.add(keyString.toString());
881             List<String> keys = new ArrayList<>();
882             templateVars.add(msg.getAaiResponseMessageResourceType());
883             for (AAIResponseMessageDatum dat : msg.getAaiResponseMessageData().getAAIResponseMessageDatum()) {
884                 keys.add(dat.getAaiResponseMessageDatumKey() + "=" + dat.getAaiResponseMessageDatumValue());
885             }
886             templateVars.add(StringUtils.join(keys, ", "));
887             exceptionList.put(new AAIException("AAI_0004", msg.getAaiResponseMessageResourceType()), templateVars);
888         }
889         response = Response.status(Status.ACCEPTED)
890                 .entity(ErrorLogHelper.getRESTAPIInfoResponse(headers.getAcceptableMediaTypes(), exceptionList))
891                 .build();
892
893         return response;
894     }
895
896     /**
897      * Creates the not found message.
898      *
899      * @param resultType the result type
900      * @param uri the uri
901      * @return the string
902      */
903     private String createNotFoundMessage(String resultType, URI uri) {
904
905         String msg = "No Node of type " + resultType + " found at: " + uri.getPath();
906
907         return msg;
908     }
909
910     /**
911      * Creates the not found message.
912      *
913      * @param resultType the result type
914      * @param uri the uri
915      * @return the string
916      */
917     private String createRelationshipNotFoundMessage(String resultType, URI uri) {
918
919         String msg = "No relationship found of type " + resultType + " at the given URI: " + uri.getPath()
920                 + "/relationship-list";
921
922         return msg;
923     }
924
925     /**
926      * Sets the depth.
927      *
928      * @param depthParam the depth param
929      * @return the int
930      * @throws AAIException the AAI exception
931      */
932     protected int setDepth(Introspector obj, String depthParam) throws AAIException {
933         int depth = AAIProperties.MAXIMUM_DEPTH;
934
935         String getAllRandomStr = AAIConfig.get("aai.rest.getall.depthparam", "");
936         if (depthParam != null && getAllRandomStr != null && !getAllRandomStr.isEmpty()
937                 && getAllRandomStr.equals(depthParam)) {
938             return depth;
939         }
940
941         if (depthParam == null) {
942             if (this.version.compareTo(schemaVersions.getDepthVersion()) >= 0) {
943                 depth = 0;
944             } else {
945                 depth = AAIProperties.MAXIMUM_DEPTH;
946             }
947         } else {
948             if (!depthParam.isEmpty() && !"all".equals(depthParam)) {
949                 try {
950                     depth = Integer.parseInt(depthParam);
951                 } catch (Exception e) {
952                     throw new AAIException("AAI_4016");
953                 }
954
955             }
956         }
957         String maxDepth = obj.getMetadata(ObjectMetadata.MAXIMUM_DEPTH);
958
959         int maximumDepth = AAIProperties.MAXIMUM_DEPTH;
960
961         if (maxDepth != null) {
962             try {
963                 maximumDepth = Integer.parseInt(maxDepth);
964             } catch (Exception ex) {
965                 throw new AAIException("AAI_4018");
966             }
967         }
968
969         if (depth > maximumDepth) {
970             throw new AAIException("AAI_3303");
971         }
972
973         return depth;
974     }
975
976     /**
977      * Checks if is modification method.
978      *
979      * @param method the method
980      * @return true, if is modification method
981      */
982     private boolean isModificationMethod(HttpMethod method) {
983         boolean result = false;
984
985         if (method.equals(HttpMethod.PUT) || method.equals(HttpMethod.PUT_EDGE) || method.equals(HttpMethod.DELETE_EDGE)
986                 || method.equals(HttpMethod.MERGE_PATCH)) {
987             result = true;
988         }
989
990         return result;
991
992     }
993
994     /**
995      * Given an uri, introspector object and loader object
996      * it will check if the obj is top level object if it is,
997      * it will return immediately returning the uri passed in
998      * If it isn't, it will go through, get the uriTemplate
999      * from the introspector object and get the count of "/"s
1000      * and remove that part of the uri using substring
1001      * and keep doing that until the current object is top level
1002      * Also added the max depth just so worst case scenario
1003      * Then keep adding aai-uri to the list include the aai-uri passed in
1004      * Convert that list into an array and return it
1005      * <p>
1006      *
1007      * Example:
1008      *
1009      * <blockquote>
1010      * aai-uri ->
1011      * /cloud-infrastructure/cloud-regions/cloud-region/cloud-owner/cloud-region-id/tenants/tenant/tenant1/vservers/vserver/v1
1012      *
1013      * Given the uriTemplate vserver -> /vservers/vserver/{vserver-id}
1014      * it converts to /vservers/vserver
1015      *
1016      * lastIndexOf /vservers/vserver in
1017      * /cloud-infrastructure/cloud-regions/cloud-region/cloud-owner/cloud-region-id/tenants/tenant/tenant1/vservers/vserver/v1
1018      * ^
1019      * |
1020      * |
1021      * lastIndexOf
1022      * Use substring to get the string from 0 to that lastIndexOf
1023      * aai-uri -> /cloud-infrastructure/cloud-regions/cloud-region/cloud-owner/cloud-region-id/tenants/tenant/tenant1
1024      *
1025      * From this new aai-uri, generate a introspector from the URITOObject class
1026      * and keep doing this until you
1027      *
1028      * </blockquote>
1029      *
1030      * @param aaiUri - aai-uri of the vertex representating the unique id of a given vertex
1031      * @param obj - introspector object of the given starting vertex
1032      * @param loader - Type of loader which will always be MoxyLoader to support model driven
1033      * @return an array of strings which can be used to get the vertexes of parent and grand parents from a given vertex
1034      * @throws UnsupportedEncodingException
1035      * @throws AAIException
1036      */
1037     String[] convertIntrospectorToUriList(String aaiUri, Introspector obj, Loader loader)
1038             throws UnsupportedEncodingException, AAIException {
1039
1040         List<String> uriList = new ArrayList<>();
1041         String template = StringUtils.EMPTY;
1042         String truncatedUri = aaiUri;
1043         int depth = AAIProperties.MAXIMUM_DEPTH;
1044         uriList.add(truncatedUri);
1045
1046         while (depth >= 0 && !obj.isTopLevel()) {
1047             template = obj.getMetadata(ObjectMetadata.URI_TEMPLATE);
1048
1049             if (template == null) {
1050                 LOGGER.warn("Unable to find the uriTemplate for the object {}", obj.getDbName());
1051                 return null;
1052             }
1053
1054             int templateCount = StringUtils.countMatches(template, "/");
1055             int truncatedUriCount = StringUtils.countMatches(truncatedUri, "/");
1056
1057             if (templateCount > truncatedUriCount) {
1058                 LOGGER.warn("Template uri {} contains more slashes than truncatedUri {}", template, truncatedUri);
1059                 return null;
1060             }
1061
1062             int cutIndex = StringUtils.ordinalIndexOf(truncatedUri, "/", truncatedUriCount - templateCount + 1);
1063             truncatedUri = StringUtils.substring(truncatedUri, 0, cutIndex);
1064             uriList.add(truncatedUri);
1065             obj = new URIToObject(loader, UriBuilder.fromPath(truncatedUri).build()).getEntity();
1066             depth--;
1067         }
1068
1069         return uriList.toArray(new String[uriList.size()]);
1070     }
1071
1072     /**
1073      *
1074      * @param serializer
1075      * @param queryEngine
1076      * @param v
1077      * @param obj
1078      * @param loader
1079      * @return
1080      * @throws IllegalAccessException
1081      * @throws IllegalArgumentException
1082      * @throws InvocationTargetException
1083      * @throws SecurityException
1084      * @throws InstantiationException
1085      * @throws NoSuchMethodException
1086      * @throws UnsupportedEncodingException
1087      * @throws AAIException
1088      * @throws URISyntaxException
1089      */
1090     private HashMap<String, Introspector> getRelatedObjects(DBSerializer serializer, QueryEngine queryEngine, Vertex v,
1091             Introspector obj, Loader loader) throws IllegalAccessException, IllegalArgumentException,
1092             InvocationTargetException, SecurityException, InstantiationException, NoSuchMethodException,
1093             UnsupportedEncodingException, AAIException, URISyntaxException {
1094
1095         HashMap<String, Introspector> relatedVertices = new HashMap<>();
1096         VertexProperty aaiUriProperty = v.property(AAIProperties.AAI_URI);
1097
1098         if (!aaiUriProperty.isPresent()) {
1099             if (LOGGER.isDebugEnabled()) {
1100                 LOGGER.debug("For the given vertex {}, it seems aai-uri is not present so not getting related objects",
1101                         v.id().toString());
1102             } else {
1103                 LOGGER.info(
1104                         "It seems aai-uri is not present in vertex, so not getting related objects, for more info enable debug log");
1105             }
1106             return relatedVertices;
1107         }
1108
1109         String aaiUri = aaiUriProperty.value().toString();
1110
1111         if (!obj.isTopLevel()) {
1112             String[] uriList = convertIntrospectorToUriList(aaiUri, obj, loader);
1113             List<Vertex> vertexChain = null;
1114             // If the uriList is null then there is something wrong with converting the uri
1115             // into a list of aai-uris so falling back to the old mechanism for finding parents
1116             if (uriList == null) {
1117                 LOGGER.info(
1118                         "Falling back to the old mechanism due to unable to convert aai-uri to list of uris but this is not optimal");
1119                 vertexChain = queryEngine.findParents(v);
1120             } else {
1121                 vertexChain = queryEngine.findParents(uriList);
1122             }
1123             for (Vertex vertex : vertexChain) {
1124                 try {
1125                     final Introspector vertexObj = serializer.getVertexProperties(vertex);
1126                     relatedVertices.put(vertexObj.getObjectId(), vertexObj);
1127                 } catch (AAIUnknownObjectException e) {
1128                     LOGGER.warn("Unable to get vertex properties, partial list of related vertices returned");
1129                 }
1130             }
1131         } else {
1132             try {
1133                 final Introspector vertexObj = serializer.getVertexProperties(v);
1134                 relatedVertices.put(vertexObj.getObjectId(), vertexObj);
1135             } catch (AAIUnknownObjectException e) {
1136                 LOGGER.warn("Unable to get vertex properties, partial list of related vertices returned");
1137             }
1138         }
1139
1140         return relatedVertices;
1141     }
1142
1143     private Map<Vertex, Introspector> buildIntrospectorObjects(DBSerializer serializer, Iterable<Vertex> vertices) {
1144         Map<Vertex, Introspector> deleteObjectMap = new HashMap<>();
1145         for (Vertex vertex : vertices) {
1146             try {
1147                 // deleteObjectMap.computeIfAbsent(vertex, s ->
1148                 // serializer.getLatestVersionView(vertex));
1149                 Introspector deleteObj = serializer.getLatestVersionView(vertex);
1150                 deleteObjectMap.put(vertex, deleteObj);
1151             } catch (UnsupportedEncodingException | AAIException e) {
1152                 LOGGER.warn("Unable to get Introspctor Objects, Just continue");
1153                 continue;
1154             }
1155
1156         }
1157
1158         return deleteObjectMap;
1159
1160     }
1161
1162     private Map<String, URI> buildURIMap(DBSerializer serializer, Map<Vertex, Introspector> introSpector) {
1163         Map<String, URI> uriMap = new HashMap<>();
1164         for (Map.Entry<Vertex, Introspector> entry : introSpector.entrySet()) {
1165             URI uri;
1166             try {
1167                 uri = serializer.getURIForVertex(entry.getKey());
1168                 if (null != entry.getValue()) {
1169                     uriMap.put(entry.getValue().getObjectId(), uri);
1170                 }
1171             } catch (UnsupportedEncodingException e) {
1172                 LOGGER.warn("Unable to get URIs, Just continue");
1173                 continue;
1174             }
1175
1176         }
1177
1178         return uriMap;
1179
1180     }
1181
1182     private Map<String, HashMap<String, Introspector>> buildRelatedObjects(DBSerializer serializer,
1183             QueryEngine queryEngine, Map<Vertex, Introspector> introSpector) {
1184
1185         Map<String, HashMap<String, Introspector>> relatedObjectsMap = new HashMap<>();
1186         for (Map.Entry<Vertex, Introspector> entry : introSpector.entrySet()) {
1187             try {
1188                 HashMap<String, Introspector> relatedObjects =
1189                         this.getRelatedObjects(serializer, queryEngine, entry.getKey(), entry.getValue(), this.loader);
1190                 if (null != entry.getValue()) {
1191                     relatedObjectsMap.put(entry.getValue().getObjectId(), relatedObjects);
1192                 }
1193             } catch (IllegalAccessException | IllegalArgumentException | InvocationTargetException | SecurityException
1194                     | InstantiationException | NoSuchMethodException | UnsupportedEncodingException | AAIException
1195                     | URISyntaxException e) {
1196                 LOGGER.warn("Unable to get realted Objects, Just continue");
1197                 continue;
1198             }
1199
1200         }
1201
1202         return relatedObjectsMap;
1203
1204     }
1205
1206     private void buildNotificationEvent(String sourceOfTruth, Status status, String transactionId,
1207             UEBNotification notification, Map<Vertex, Introspector> deleteObjects, Map<String, URI> uriMap,
1208             Map<String, HashMap<String, Introspector>> deleteRelatedObjects, String basePath) {
1209         for (Map.Entry<Vertex, Introspector> entry : deleteObjects.entrySet()) {
1210             try {
1211                 String vertexObjectId = "";
1212
1213                 if (null != entry.getValue()) {
1214                     vertexObjectId = entry.getValue().getObjectId();
1215
1216                     if (uriMap.containsKey(vertexObjectId) && deleteRelatedObjects.containsKey(vertexObjectId)) {
1217                         notification.createNotificationEvent(transactionId, sourceOfTruth, status,
1218                                 uriMap.get(vertexObjectId), entry.getValue(), deleteRelatedObjects.get(vertexObjectId),
1219                                 basePath);
1220                     }
1221                 }
1222             } catch (UnsupportedEncodingException | AAIException e) {
1223
1224                 LOGGER.warn("Error in sending notification");
1225             }
1226         }
1227     }
1228
1229     public void setPaginationParameters(String resultIndex, String resultSize) {
1230         if (resultIndex != null && resultIndex != "-1" && resultSize != null && resultSize != "-1") {
1231             this.setPaginationIndex(Integer.parseInt(resultIndex));
1232             this.setPaginationBucket(Integer.parseInt(resultSize));
1233         }
1234     }
1235
1236     public List<Object> getPaginatedVertexList(List<Object> vertexList) throws AAIException {
1237         List<Object> vertices;
1238         if (this.isPaginated()) {
1239             this.setTotalsForPaging(vertexList.size(), this.getPaginationBucket());
1240             int startIndex = (this.getPaginationIndex() - 1) * this.getPaginationBucket();
1241             int endIndex = Math.min((this.getPaginationBucket() * this.getPaginationIndex()), vertexList.size());
1242             if (startIndex > endIndex) {
1243                 throw new AAIException("AAI_6150",
1244                         " ResultIndex is not appropriate for the result set, Needs to be <= " + endIndex);
1245             }
1246             vertices = vertexList.subList(startIndex, endIndex);
1247         } else {
1248             vertices = vertexList;
1249         }
1250         return vertices;
1251     }
1252 }