Update license files, sonar plugin and fix tests
[aai/aai-common.git] / aai-core / src / main / java / org / openecomp / aai / serialization / db / DBSerializer.java
1 /*-
2  * ============LICENSE_START=======================================================
3  * org.openecomp.aai
4  * ================================================================================
5  * Copyright (C) 2017 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.openecomp.aai.serialization.db;
22
23
24 import com.att.eelf.configuration.EELFLogger;
25 import com.att.eelf.configuration.EELFManager;
26 import com.google.common.base.CaseFormat;
27 import com.thinkaurelius.titan.core.SchemaViolationException;
28 import org.apache.commons.collections.IteratorUtils;
29 import org.apache.tinkerpop.gremlin.process.traversal.dsl.graph.GraphTraversal;
30 import org.apache.tinkerpop.gremlin.process.traversal.dsl.graph.__;
31 import org.apache.tinkerpop.gremlin.process.traversal.step.util.Tree;
32 import org.apache.tinkerpop.gremlin.structure.*;
33 import org.javatuples.Pair;
34 import org.openecomp.aai.db.props.AAIProperties;
35 import org.openecomp.aai.exceptions.AAIException;
36 import org.openecomp.aai.introspection.*;
37 import org.openecomp.aai.introspection.exceptions.AAIUnknownObjectException;
38 import org.openecomp.aai.introspection.sideeffect.DataCopy;
39 import org.openecomp.aai.introspection.sideeffect.DataLinkReader;
40 import org.openecomp.aai.introspection.sideeffect.DataLinkWriter;
41 import org.openecomp.aai.introspection.sideeffect.SideEffectRunner;
42 import org.openecomp.aai.logging.ErrorLogHelper;
43 import org.openecomp.aai.parsers.query.QueryParser;
44 import org.openecomp.aai.parsers.uri.URIParser;
45 import org.openecomp.aai.parsers.uri.URIToRelationshipObject;
46 import org.openecomp.aai.query.builder.QueryBuilder;
47 import org.openecomp.aai.schema.enums.ObjectMetadata;
48 import org.openecomp.aai.schema.enums.PropertyMetadata;
49 import org.openecomp.aai.serialization.db.exceptions.NoEdgeRuleFoundException;
50 import org.openecomp.aai.serialization.engines.TransactionalGraphEngine;
51 import org.openecomp.aai.serialization.tinkerpop.TreeBackedVertex;
52 import org.openecomp.aai.util.AAIApiServerURLBase;
53 import org.openecomp.aai.util.AAIConfig;
54 import org.openecomp.aai.util.AAIConstants;
55 import org.openecomp.aai.workarounds.NamingExceptions;
56
57 import javax.ws.rs.core.UriBuilder;
58 import java.io.UnsupportedEncodingException;
59 import java.lang.reflect.Array;
60 import java.lang.reflect.InvocationTargetException;
61 import java.net.MalformedURLException;
62 import java.net.URI;
63 import java.net.URISyntaxException;
64 import java.util.*;
65 import java.util.concurrent.Callable;
66 import java.util.concurrent.ExecutionException;
67 import java.util.concurrent.ExecutorService;
68 import java.util.concurrent.Future;
69
70 public class DBSerializer {
71         
72         private static final EELFLogger LOGGER = EELFManager.getInstance().getLogger(DBSerializer.class);
73         
74         private final TransactionalGraphEngine engine;
75         private final String sourceOfTruth;
76         private final ModelType introspectionType;
77         private final Version version;
78         private final Loader latestLoader;
79         private final EdgeRules edgeRules = EdgeRules.getInstance();
80         private final Loader loader;
81         private final String baseURL;
82         /**
83          * Instantiates a new DB serializer.
84          *
85          * @param version the version
86          * @param engine the engine
87          * @param g the g
88          * @param introspectionType the introspection type
89          * @param sourceOfTruth the source of truth
90          * @param llBuilder the ll builder
91          * @throws AAIException
92          */
93         public DBSerializer(Version version, TransactionalGraphEngine engine, ModelType introspectionType, String sourceOfTruth) throws AAIException {
94                 this.engine = engine;
95                 this.sourceOfTruth = sourceOfTruth;
96                 this.introspectionType = introspectionType;
97                 this.latestLoader = LoaderFactory.createLoaderForVersion(introspectionType, AAIProperties.LATEST);
98                 this.version = version;
99                 this.loader = LoaderFactory.createLoaderForVersion(introspectionType, version);
100                 this.baseURL = AAIApiServerURLBase.get(version);
101         }
102         
103         /**
104          * Touch standard vertex properties.
105          *
106          * @param v the v
107          * @param isNewVertex the is new vertex
108          */
109         /*
110          * to be defined and expanded later
111          */
112         public void touchStandardVertexProperties(Vertex v, boolean isNewVertex) {
113                 
114                 long unixTimeNow = System.currentTimeMillis();
115                 String timeNowInSec = "" + unixTimeNow;
116                 if (isNewVertex) {
117                         v.property(AAIProperties.SOURCE_OF_TRUTH, this.sourceOfTruth);
118                         v.property(AAIProperties.CREATED_TS, timeNowInSec);
119                 }
120                 v.property(AAIProperties.RESOURCE_VERSION, timeNowInSec );
121                 v.property(AAIProperties.LAST_MOD_TS, timeNowInSec);
122                 v.property(AAIProperties.LAST_MOD_SOURCE_OF_TRUTH, this.sourceOfTruth);
123                 
124         }
125         
126         
127         
128         /**
129          * Creates the new vertex.
130          *
131          * @param wrappedObject the wrapped object
132          * @return the vertex
133          * @throws UnsupportedEncodingException the unsupported encoding exception
134          * @throws AAIException the AAI exception
135          */
136         public Vertex createNewVertex(Introspector wrappedObject) {
137
138                 
139                 Vertex v = this.engine.tx().addVertex();
140                 v.property(AAIProperties.NODE_TYPE, wrappedObject.getDbName());
141                 touchStandardVertexProperties(v, true);
142                 
143                 return v;
144         }
145         
146         /**
147          * Trim class name.
148          *
149          * @param className the class name
150          * @return the string
151          */
152         /*
153          * Removes the classpath from a class name
154          */
155         public String trimClassName (String className) {
156                 String returnValue = "";
157                 
158                 if (className.lastIndexOf('.') == -1) {
159                         return className;
160                 }
161                 returnValue = className.substring(className.lastIndexOf('.') + 1, className.length());
162                 
163                 return returnValue;
164         }
165         
166         /**
167          * Serialize to db.
168          *
169          * @param obj the obj
170          * @param v the v
171          * @param uriQuery the uri query
172          * @param identifier the identifier
173          * @throws SecurityException the security exception
174          * @throws IllegalAccessException the illegal access exception
175          * @throws IllegalArgumentException the illegal argument exception
176          * @throws InvocationTargetException the invocation target exception
177          * @throws InstantiationException the instantiation exception
178          * @throws InterruptedException the interrupted exception
179          * @throws NoSuchMethodException the no such method exception
180          * @throws AAIException the AAI exception
181          * @throws UnsupportedEncodingException the unsupported encoding exception
182          * @throws AAIUnknownObjectException
183          */
184         public void serializeToDb(Introspector obj, Vertex v, QueryParser uriQuery, String identifier, String requestContext) throws AAIException, UnsupportedEncodingException {
185
186                 try {
187                         if (uriQuery.isDependent()) {
188                                 //try to find the parent
189                                 List<Vertex> vertices = uriQuery.getQueryBuilder().getParentQuery().toList();
190                                 if (!vertices.isEmpty()) {
191                                         Vertex parent = vertices.get(0);
192                                         this.reflectDependentVertex(parent, v, obj, requestContext);
193                                 } else {
194                                         throw new AAIException("AAI_6114", "No parent Node of type " + uriQuery.getParentResultType() + " for " + identifier);
195                                 }
196                         } else {
197                                 serializeSingleVertex(v, obj, requestContext);
198                         }
199
200                 } catch (SchemaViolationException e) {
201                         throw new AAIException("AAI_6117", e);
202                 }
203                 
204         }
205         
206         public void serializeSingleVertex(Vertex v, Introspector obj, String requestContext) throws UnsupportedEncodingException, AAIException {
207                 try {
208                         boolean isTopLevel = obj.isTopLevel();
209                         if (isTopLevel) {
210                                 v.property(AAIProperties.AAI_URI, obj.getURI());
211                         }
212                         processObject(obj, v, requestContext);
213                         if (!isTopLevel) {
214                                 URI uri = this.getURIForVertex(v);
215                                 URIParser parser = new URIParser(this.loader, uri);
216                                 if (parser.validate()) {
217                                         VertexProperty<String> uriProp = v.property(AAIProperties.AAI_URI);
218                                         if (!uriProp.isPresent() || uriProp.isPresent() && !uriProp.value().equals(uri.toString())) {
219                                                 v.property(AAIProperties.AAI_URI, uri.toString());
220                                         }
221                                 }
222                         }
223                 } catch (SchemaViolationException e) {
224                         throw new AAIException("AAI_6117", e);
225                 }
226         }
227         
228         /**
229          * Process object.
230          *
231          * @param <T> the generic type
232          * @param obj the obj
233          * @param v the v
234          * @return the list
235          * @throws IllegalAccessException the illegal access exception
236          * @throws IllegalArgumentException the illegal argument exception
237          * @throws InvocationTargetException the invocation target exception
238          * @throws InstantiationException the instantiation exception
239          * @throws NoSuchMethodException the no such method exception
240          * @throws SecurityException the security exception
241          * @throws AAIException the AAI exception
242          * @throws UnsupportedEncodingException the unsupported encoding exception
243          * @throws AAIUnknownObjectException
244          */
245         /*
246          * Helper method for reflectToDb
247          * Handles all the property setting
248          */
249         private <T> List<Vertex> processObject (Introspector obj, Vertex v, String requestContext) throws UnsupportedEncodingException, AAIException {
250                 Set<String> properties = new LinkedHashSet<>(obj.getProperties());
251                 properties.remove(AAIProperties.RESOURCE_VERSION);
252                 List<Vertex> dependentVertexes = new ArrayList<>();
253                 List<Vertex> processedVertexes = new ArrayList<>();
254                 boolean isComplexType = false;
255                 boolean isListType = false;
256                 this.executePreSideEffects(obj, v);
257                 for (String property : properties) {
258                         Object value = null;
259                         final String propertyType;
260                         propertyType = obj.getType(property);
261                         isComplexType = obj.isComplexType(property);
262                         isListType = obj.isListType(property);
263                         value = obj.getValue(property);
264
265                         if (!(isComplexType || isListType)) {
266                                 boolean canModify = this.canModify(obj, property, requestContext);
267                                 
268                                 if (canModify) {
269                                         final Map<PropertyMetadata, String> metadata = obj.getPropertyMetadata(property);
270                                         String dbProperty = property;
271                                         if (metadata.containsKey(PropertyMetadata.DB_ALIAS)) {
272                                                 dbProperty = metadata.get(PropertyMetadata.DB_ALIAS);
273                                         }
274                                         if (metadata.containsKey(PropertyMetadata.DATA_LINK)) {
275                                                 //data linked properties are ephemeral
276                                                 //they are populated dynamically on GETs
277                                                 continue;
278                                         }
279                                         if (value != null) {
280                                                 if (propertyType.toLowerCase().contains(".long")) {
281                                                         v.property(dbProperty, new Integer(((Long)value).toString()));
282                                                 } else {
283                                                         v.property(dbProperty, value);
284                                                 }
285                                         } else {
286                                                 v.property(dbProperty).remove();
287                                         }
288                                 }
289                         } else if (isListType) {
290                                 List<Object> list = (List<Object>)value;
291                                 if (obj.isComplexGenericType(property)) {
292                                         if (list != null) {
293                                                 for (Object o : list) {
294                                                         Introspector child = IntrospectorFactory.newInstance(this.introspectionType, o);
295                                                         child.setURIChain(obj.getURI());
296                                                         processedVertexes.add(reflectDependentVertex(v, child, requestContext));
297                                                 }
298                                         }
299                                 } else {
300                                         //simple list case
301                                         engine.setListProperty(v, property, list);
302                                 }
303                         } else {
304                                 //method.getReturnType() is not 'simple' then create a vertex and edge recursively returning an edge back to this method
305                                 if (value != null) { //effectively ignore complex properties not included in the object we're processing
306                                         if (value.getClass().isArray()) {
307                                                 
308                                                 int length = Array.getLength(value);
309                                             for (int i = 0; i < length; i ++) {
310                                                 Object arrayElement = Array.get(value, i);
311                                                 Introspector child = IntrospectorFactory.newInstance(this.introspectionType, arrayElement);
312                                                         child.setURIChain(obj.getURI());
313                                                         processedVertexes.add(reflectDependentVertex(v, child, requestContext));
314
315                                             }
316                                         } else if (!property.equals("relationship-list")) {
317                                                 // container case
318                                                 Introspector introspector = IntrospectorFactory.newInstance(this.introspectionType, value);
319                                                 if (introspector.isContainer()) {
320                                                         dependentVertexes.addAll(this.engine.getQueryEngine().findChildrenOfType(v, introspector.getChildDBName()));
321                                                         introspector.setURIChain(obj.getURI());
322                                                         
323                                                         processedVertexes.addAll(processObject(introspector, v, requestContext));
324
325                                                 } else {
326                                                         dependentVertexes.addAll(this.engine.getQueryEngine().findChildrenOfType(v, introspector.getDbName()));
327                                                         processedVertexes.add(reflectDependentVertex(v, introspector, requestContext));
328
329                                                 }
330                                         } else if (property.equals("relationship-list")) {
331                                                 handleRelationships(obj, v);
332                                         }
333                                 }
334                         }
335                 }
336                 this.writeThroughDefaults(v, obj);
337                 /* handle those vertexes not touched */
338                 for (Vertex toBeRemoved : processedVertexes) {
339                         dependentVertexes.remove(toBeRemoved);
340                 }
341                 this.deleteItemsWithTraversal(dependentVertexes);
342                 
343                 this.executePostSideEffects(obj, v);
344                 return processedVertexes;
345         }
346         
347         /**
348          * Handle relationships.
349          *
350          * @param obj the obj
351          * @param vertex the vertex
352          * @throws SecurityException the security exception
353          * @throws IllegalAccessException the illegal access exception
354          * @throws IllegalArgumentException the illegal argument exception
355          * @throws InvocationTargetException the invocation target exception
356          * @throws UnsupportedEncodingException the unsupported encoding exception
357          * @throws AAIException the AAI exception
358          */
359         /*
360          * Handles the explicit relationships defined for an obj
361          */
362         private void handleRelationships(Introspector obj, Vertex vertex) throws UnsupportedEncodingException, AAIException {
363                 
364         
365         
366                 Introspector wrappedRl = obj.getWrappedValue("relationship-list");
367                 processRelationshipList(wrappedRl, vertex);
368                 
369         
370         }
371         
372         
373         /**
374          * Process relationship list.
375          *
376          * @param wrapped the wrapped
377          * @param v the v
378          * @throws UnsupportedEncodingException the unsupported encoding exception
379          * @throws AAIException the AAI exception
380          */
381         private void processRelationshipList(Introspector wrapped, Vertex v) throws UnsupportedEncodingException, AAIException {
382                                 
383                 List<Object> relationships = (List<Object>)wrapped.getValue("relationship");
384                 
385                 List<Pair<Vertex, Vertex>> addEdges = new ArrayList<>();
386                 List<Edge> existingEdges = this.engine.getQueryEngine().findEdgesForVersion(v, wrapped.getLoader());
387                 
388                 for (Object relationship : relationships) {
389                         Edge e = null;
390                         Vertex cousinVertex = null;
391                         Introspector wrappedRel = IntrospectorFactory.newInstance(this.introspectionType, relationship);
392                         QueryParser parser = engine.getQueryBuilder().createQueryFromRelationship(wrappedRel);
393                         
394                         List<Vertex> results = parser.getQueryBuilder().toList();
395                         if (results.isEmpty()) {
396                                 final AAIException ex = new AAIException("AAI_6129", "Node of type " + parser.getResultType() + ". Could not find object at: " + parser.getUri());
397                                 ex.getTemplateVars().add(parser.getResultType());
398                                 ex.getTemplateVars().add(parser.getUri().toString());
399                                 throw ex;
400                         } else { 
401                                 //still an issue if there's more than one
402                                 cousinVertex = results.get(0);
403                         }
404                         
405                         if (cousinVertex != null) {
406                                 try {
407                                         e = this.getEdgeBetween(EdgeType.COUSIN, v, cousinVertex);
408
409                                         if (e == null) {
410                                                 addEdges.add(new Pair<>(v, cousinVertex));
411                                         } else { 
412                                                 existingEdges.remove(e);
413                                         }
414                                 } catch (NoEdgeRuleFoundException e1) {
415                                         throw new AAIException("AAI_6145");
416                                 }
417                         }
418                 }
419                 
420                 for (Edge edge : existingEdges) {
421                         edge.remove();
422                 }
423                 for (Pair<Vertex, Vertex> pair : addEdges) {
424                          try {
425                                 edgeRules.addEdge(this.engine.asAdmin().getTraversalSource(), pair.getValue0(), pair.getValue1());
426                         } catch (NoEdgeRuleFoundException e) {
427                                 throw new AAIException("AAI_6129", e);
428                         }                       
429                 }
430
431         }
432
433         /**
434          * Write through defaults.
435          *
436          * @param v the v
437          * @param obj the obj
438          * @throws AAIUnknownObjectException
439          */
440         private void writeThroughDefaults(Vertex v, Introspector obj) throws AAIUnknownObjectException {
441                 Introspector latest = this.latestLoader.introspectorFromName(obj.getName());
442                 if (latest != null) {
443                         Set<String> required  = latest.getRequiredProperties();
444                         
445                         for (String field : required) {
446                                 String defaultValue = null;
447                                 Object vertexProp = null;
448                                 defaultValue = latest.getPropertyMetadata(field).get(PropertyMetadata.DEFAULT_VALUE);
449                                 if (defaultValue != null) {
450                                         vertexProp = v.<Object>property(field).orElse(null);
451                                         if (vertexProp == null) {
452                                                 v.property(field, defaultValue);
453                                         }
454                                 }
455                         }
456                 }
457                 
458         }
459
460         
461         /**
462           * Reflect dependent vertex.
463           *
464           * @param v the v
465           * @param dependentObj the dependent obj
466           * @return the vertex
467           * @throws IllegalAccessException the illegal access exception
468           * @throws IllegalArgumentException the illegal argument exception
469           * @throws InvocationTargetException the invocation target exception
470           * @throws InstantiationException the instantiation exception
471           * @throws NoSuchMethodException the no such method exception
472           * @throws SecurityException the security exception
473           * @throws AAIException the AAI exception
474           * @throws UnsupportedEncodingException the unsupported encoding exception
475          * @throws AAIUnknownObjectException
476           */
477          private Vertex reflectDependentVertex(Vertex v, Introspector dependentObj, String requestContext) throws AAIException, UnsupportedEncodingException {
478                 
479                 //QueryParser p = this.engine.getQueryBuilder().createQueryFromURI(obj.getURI());
480                 //List<Vertex> items = p.getQuery().toList();
481                 QueryBuilder query = this.engine.getQueryBuilder(v);
482                 query.createEdgeTraversal(EdgeType.TREE, v, dependentObj);
483                 query.createKeyQuery(dependentObj);
484                 
485                 List<Vertex> items = query.toList();
486                 
487                 Vertex dependentVertex = null;
488                 if (items.size() == 1) {
489                         dependentVertex = items.get(0);
490                         this.verifyResourceVersion("update", dependentObj.getDbName(), dependentVertex.<String>property(AAIProperties.RESOURCE_VERSION).orElse(null), (String)dependentObj.getValue(AAIProperties.RESOURCE_VERSION), (String)dependentObj.getURI());
491                 } else {
492                         this.verifyResourceVersion("create", dependentObj.getDbName(), "", (String)dependentObj.getValue(AAIProperties.RESOURCE_VERSION), (String)dependentObj.getURI());
493                         dependentVertex = createNewVertex(dependentObj);
494                 }
495
496                 return reflectDependentVertex(v, dependentVertex, dependentObj, requestContext);
497                                 
498         }
499         
500         /**
501           * Reflect dependent vertex.
502           *
503           * @param parent the parent
504           * @param child the child
505           * @param obj the obj
506           * @return the vertex
507           * @throws IllegalAccessException the illegal access exception
508           * @throws IllegalArgumentException the illegal argument exception
509           * @throws InvocationTargetException the invocation target exception
510           * @throws InstantiationException the instantiation exception
511           * @throws NoSuchMethodException the no such method exception
512           * @throws SecurityException the security exception
513           * @throws AAIException the AAI exception
514           * @throws UnsupportedEncodingException the unsupported encoding exception
515          * @throws AAIUnknownObjectException
516           */
517          private Vertex reflectDependentVertex(Vertex parent, Vertex child, Introspector obj, String requestContext) throws AAIException, UnsupportedEncodingException {
518                 
519                 String parentUri = parent.<String>property(AAIProperties.AAI_URI).orElse(null);
520                 if (parentUri != null) {
521                         child.property(AAIProperties.AAI_URI, parentUri + obj.getURI());
522                 }
523                 processObject(obj, child, requestContext);
524                 
525                 Edge e;
526                 e = this.getEdgeBetween(EdgeType.TREE, parent, child);
527                 if (e == null) {
528                         String canBeLinked = obj.getMetadata(ObjectMetadata.CAN_BE_LINKED);
529                         if (canBeLinked != null && canBeLinked.equals("true")) {
530                                 boolean isFirst = !this.engine.getQueryBuilder(parent).createEdgeTraversal(EdgeType.TREE, parent, obj).hasNext();
531                                 if (isFirst) {
532                                         child.property(AAIProperties.LINKED, true);
533                                 }
534                         }
535                         edgeRules.addTreeEdge(this.engine.asAdmin().getTraversalSource(), parent, child);
536                 }
537                 return child;
538                 
539         }
540          
541         /**
542           * Db to object.
543           *
544           * @param vertices the vertices
545           * @param obj the obj
546           * @param depth the depth
547           * @param cleanUp the clean up
548           * @return the introspector
549           * @throws AAIException the AAI exception
550           * @throws IllegalAccessException the illegal access exception
551           * @throws IllegalArgumentException the illegal argument exception
552           * @throws InvocationTargetException the invocation target exception
553           * @throws SecurityException the security exception
554           * @throws InstantiationException the instantiation exception
555           * @throws NoSuchMethodException the no such method exception
556           * @throws UnsupportedEncodingException the unsupported encoding exception
557           * @throws MalformedURLException the malformed URL exception
558          * @throws AAIUnknownObjectException
559          * @throws URISyntaxException 
560           */
561          public Introspector dbToObject(List<Vertex> vertices, final Introspector obj, int depth, boolean nodeOnly, String cleanUp) throws UnsupportedEncodingException, AAIException {
562                 
563                 final int internalDepth;
564                 if (depth == Integer.MAX_VALUE) {
565                         internalDepth = depth--;
566                 } else {
567                         internalDepth = depth;
568                 }
569                 if (vertices.size() > 1 && !obj.isContainer()) {
570                         throw new AAIException("AAI_6136", "query object mismatch: this object cannot hold multiple items." + obj.getDbName());
571                 } else if (obj.isContainer()) {
572                         final List getList;
573                         String listProperty = null;
574                         for (String property : obj.getProperties()) {
575                                 if (obj.isListType(property) && obj.isComplexGenericType(property)) {
576                                         listProperty = property;
577                                         break;
578                                 }
579                         }
580                         final String propertyName = listProperty;
581                         getList = (List)obj.getValue(listProperty);
582                         
583                         /* This is an experimental multithreading experiment
584                          * on get alls. 
585                          */
586                         ExecutorService pool = GetAllPool.getInstance().getPool();
587                         
588                         List<Future<Object>> futures = new ArrayList<>();
589                         for (Vertex v : vertices) {
590                                 Callable<Object> task = () -> {
591                                         Set<Vertex> seen = new HashSet<>();
592                                         Introspector childObject = obj.newIntrospectorInstanceOfNestedProperty(propertyName);
593                                         Tree<Element> tree = this.engine.getQueryEngine().findSubGraph(v, internalDepth, nodeOnly);
594                                         TreeBackedVertex treeVertex = new TreeBackedVertex(v, tree);
595                                         dbToObject(childObject, treeVertex, seen, internalDepth, nodeOnly, cleanUp);
596                                         return childObject.getUnderlyingObject();
597                                         //getList.add(childObject.getUnderlyingObject());
598                                 };
599                                 futures.add(pool.submit(task));
600                         }
601                         
602                         for (Future<Object> future : futures) {
603                                 try {
604                                         getList.add(future.get());
605                                 } catch (ExecutionException e) {
606                                         throw new AAIException("AAI_4000", e);
607                                 } catch (InterruptedException e) {
608                                         throw new AAIException("AAI_4000", e);
609                                 }
610                         }
611                 } else if (vertices.size() == 1) {
612                         Set<Vertex> seen = new HashSet<>();
613                         Tree<Element> tree = this.engine.getQueryEngine().findSubGraph(vertices.get(0), depth, nodeOnly);
614                         TreeBackedVertex treeVertex = new TreeBackedVertex(vertices.get(0), tree);
615                         dbToObject(obj, treeVertex, seen, depth, nodeOnly, cleanUp);
616                 } else {
617                         //obj = null;
618                 }
619                 
620
621                 return obj;
622         }
623         
624         /**
625          * Db to object.
626          *
627          * @param obj the obj
628          * @param v the v
629          * @param seen the seen
630          * @param depth the depth
631          * @param cleanUp the clean up
632          * @return the introspector
633          * @throws IllegalAccessException the illegal access exception
634          * @throws IllegalArgumentException the illegal argument exception
635          * @throws InvocationTargetException the invocation target exception
636          * @throws SecurityException the security exception
637          * @throws InstantiationException the instantiation exception
638          * @throws NoSuchMethodException the no such method exception
639          * @throws UnsupportedEncodingException the unsupported encoding exception
640          * @throws AAIException the AAI exception
641          * @throws MalformedURLException the malformed URL exception
642          * @throws AAIUnknownObjectException
643          * @throws URISyntaxException 
644          */
645         private Introspector dbToObject(Introspector obj, Vertex v, Set<Vertex> seen, int depth, boolean nodeOnly, String cleanUp) throws AAIException, UnsupportedEncodingException {
646                 
647                 if (depth < 0) {
648                         return null;
649                 }
650                 depth--;
651                 seen.add(v);
652                 
653                 boolean modified = false;
654                 for (String property : obj.getProperties(PropertyPredicates.isVisible())) {
655                         List<Object> getList = null;
656                         Vertex[] vertices = null;
657
658                         if (!(obj.isComplexType(property) || obj.isListType(property))) {
659                                 this.copySimpleProperty(property, obj, v);
660                                 modified = true;
661                         } else {
662                                 if (obj.isComplexType(property)) {
663                                 /* container case */
664         
665                                         if (!property.equals("relationship-list") && depth >= 0) {
666                                                 Introspector argumentObject = obj.newIntrospectorInstanceOfProperty(property);
667                                                 Object result  = dbToObject(argumentObject, v, seen, depth+1, nodeOnly, cleanUp);
668                                                 if (result != null) {
669                                                         obj.setValue(property, argumentObject.getUnderlyingObject());
670                                                         modified = true;
671                                                 }
672                                         } else if (property.equals("relationship-list") && !nodeOnly){
673                                                 /* relationships need to be handled correctly */
674                                                 Introspector relationshipList = obj.newIntrospectorInstanceOfProperty(property);
675                                                 relationshipList = createRelationshipList(v, relationshipList, cleanUp);
676                                                 if (relationshipList != null) {
677                                                         modified = true;
678                                                         obj.setValue(property, relationshipList.getUnderlyingObject());
679                                                         modified = true;
680                                                 }
681                                                 
682                                         }
683                                 } else if (obj.isListType(property)) {
684                                         
685                                         if (property.equals("any")) {
686                                                 continue;
687                                         }
688                                         String genericType = obj.getGenericTypeClass(property).getSimpleName();
689                                         if (obj.isComplexGenericType(property) && depth >= 0) {
690                                                 final String childDbName = convertFromCamelCase(genericType);
691                                                 String vType = v.<String>property(AAIProperties.NODE_TYPE).orElse(null);
692                                                 EdgeRule rule;
693                                                 
694                                                 rule = edgeRules.getEdgeRule(EdgeType.TREE, vType, childDbName);
695                                                 if (rule.getIsParent().equals("true") || rule.getIsParent().equals("reverse")) {
696                                                         //vertices = this.queryEngine.findRelatedVertices(v, Direction.OUT, rule.getLabel(), childDbName);
697                                                         Direction ruleDirection = rule.getDirection();
698                                                         Iterator<Vertex> itr = v.vertices(ruleDirection, rule.getLabel());
699                                                         List<Vertex> verticesList = (List<Vertex>) IteratorUtils.toList(itr);
700                                                         itr = verticesList.stream().filter(item -> {
701                                                                 return item.property(AAIProperties.NODE_TYPE).orElse("").equals(childDbName);
702                                                         }).iterator();
703                                                         if (itr.hasNext()) {
704                                                                 getList = (List<Object>)obj.getValue(property);
705                                                         }
706                                                         int processed = 0;
707                                                         int removed = 0;
708                                                         while (itr.hasNext()) {
709                                                                 Vertex childVertex = itr.next();
710                                                                 if (!seen.contains(childVertex)) {
711                                                                         Introspector argumentObject = obj.newIntrospectorInstanceOfNestedProperty(property);
712                                                                         
713                                                                         Object result = dbToObject(argumentObject, childVertex, seen, depth, nodeOnly, cleanUp);
714                                                                         if (result != null) { 
715                                                                                 getList.add(argumentObject.getUnderlyingObject());
716                                                                         }
717                                                                         
718                                                                         processed++;
719                                                                 } else {
720                                                                         removed++;
721                                                                         LOGGER.warn("Cycle found while serializing vertex id={}", childVertex.id().toString());
722                                                                 }
723                                                         }
724                                                         if (processed == 0) {
725                                                                 //vertices were all seen, reset the list
726                                                                 getList = null;
727                                                         }
728                                                         if (processed > 0) {
729                                                                 modified = true;
730                                                         }
731                                                 }
732                                         } else if (obj.isSimpleGenericType(property)) {
733                                                 List<Object> temp = this.engine.getListProperty(v, property);
734                                                 if (temp != null) {
735                                                         getList = (List<Object>)obj.getValue(property);
736                                                         getList.addAll(temp);
737                                                         modified = true;
738                                                 }
739
740                                         }
741
742                                 }
743
744                         }
745                 }
746                 
747                 //no changes were made to this obj, discard the instance
748                 if (!modified) {
749                         return null;
750                 }
751                 this.enrichData(obj, v);
752                 return obj;
753                 
754         }
755         
756         
757         public Introspector getVertexProperties(Vertex v) throws AAIException, IllegalAccessException, IllegalArgumentException, InvocationTargetException, SecurityException, InstantiationException, NoSuchMethodException, UnsupportedEncodingException, AAIUnknownObjectException, URISyntaxException {
758                 String nodeType = v.<String>property(AAIProperties.NODE_TYPE).orElse(null);
759                 if (nodeType == null) {
760                         throw new AAIException("AAI_6143");
761                 }
762                 Introspector obj = this.latestLoader.introspectorFromName(nodeType);
763                 Set<Vertex> seen = new HashSet<>();
764                 int depth = 0;
765                 String cleanUp = "false";
766                 boolean nodeOnly = true;
767                 this.dbToObject(obj, v, seen, depth, nodeOnly, cleanUp);
768                 
769                 return obj;
770                 
771         }
772         public Introspector getLatestVersionView(Vertex v) throws AAIException, IllegalAccessException, IllegalArgumentException, InvocationTargetException, SecurityException, InstantiationException, NoSuchMethodException, UnsupportedEncodingException, AAIUnknownObjectException, URISyntaxException {
773                 String nodeType = v.<String>property(AAIProperties.NODE_TYPE).orElse(null);
774                 if (nodeType == null) {
775                         throw new AAIException("AAI_6143");
776                 }
777                 Introspector obj = this.latestLoader.introspectorFromName(nodeType);
778                 Set<Vertex> seen = new HashSet<>();
779                 int depth = AAIProperties.MAXIMUM_DEPTH;
780                 String cleanUp = "false";
781                 boolean nodeOnly = false;
782                 Tree<Element> tree = this.engine.getQueryEngine().findSubGraph(v, depth, nodeOnly);
783                 TreeBackedVertex treeVertex = new TreeBackedVertex(v, tree);
784                 this.dbToObject(obj, treeVertex, seen, depth, nodeOnly, cleanUp);
785                 
786                 return obj;
787         }
788         /**
789          * Copy simple property.
790          *
791          * @param property the property
792          * @param obj the obj
793          * @param v the v
794          * @throws InstantiationException the instantiation exception
795          * @throws IllegalAccessException the illegal access exception
796          * @throws IllegalArgumentException the illegal argument exception
797          * @throws InvocationTargetException the invocation target exception
798          * @throws NoSuchMethodException the no such method exception
799          * @throws SecurityException the security exception
800          */
801         private void copySimpleProperty(String property, Introspector obj, Vertex v) {
802                 final Map<PropertyMetadata, String> metadata = obj.getPropertyMetadata(property);
803                 String dbPropertyName = property;
804                 if (metadata.containsKey(PropertyMetadata.DB_ALIAS)) {
805                         dbPropertyName = metadata.get(PropertyMetadata.DB_ALIAS);
806                 }
807                 final Object temp = v.<Object>property(dbPropertyName).orElse(null);
808                 if (temp != null) {
809                         
810                         obj.setValue(property, temp);
811                 }
812         }
813         
814         /**
815          * Simple db to object.
816          *
817          * @param obj the obj
818          * @param v the v
819          * @throws InstantiationException the instantiation exception
820          * @throws IllegalAccessException the illegal access exception
821          * @throws IllegalArgumentException the illegal argument exception
822          * @throws InvocationTargetException the invocation target exception
823          * @throws NoSuchMethodException the no such method exception
824          * @throws SecurityException the security exception
825          */
826         private void simpleDbToObject (Introspector obj, Vertex v) {
827                 for (String property : obj.getProperties()) {
828                         
829
830                         if (!(obj.isComplexType(property) || obj.isListType(property))) {
831                                 this.copySimpleProperty(property, obj, v);
832                         }
833                 }
834         }
835         
836         /**
837          * Creates the relationship list.
838          *
839          * @param v the v
840          * @param obj the obj
841          * @param cleanUp the clean up
842          * @return the object
843          * @throws InstantiationException the instantiation exception
844          * @throws IllegalAccessException the illegal access exception
845          * @throws IllegalArgumentException the illegal argument exception
846          * @throws InvocationTargetException the invocation target exception
847          * @throws NoSuchMethodException the no such method exception
848          * @throws SecurityException the security exception
849          * @throws UnsupportedEncodingException the unsupported encoding exception
850          * @throws AAIException the AAI exception
851          * @throws MalformedURLException the malformed URL exception
852          * @throws URISyntaxException 
853          */
854         private Introspector createRelationshipList(Vertex v, Introspector obj, String cleanUp) throws UnsupportedEncodingException, AAIException {
855                 
856
857                 List<Vertex> cousins = this.engine.getQueryEngine().findCousinVertices(v);
858
859                 List<Object> relationshipObjList = obj.getValue("relationship");
860                 
861                 for (Vertex cousin : cousins) {
862                 
863                                 Introspector relationshipObj = obj.newIntrospectorInstanceOfNestedProperty("relationship");
864                         Object result = processEdgeRelationship(relationshipObj, cousin, cleanUp);
865                                 if (result != null) {
866                                         relationshipObjList.add(result);
867                                 }
868                 
869                 }
870                 
871                 if (relationshipObjList.isEmpty()) {
872                         return null;
873                 } else {
874                         return obj;
875                 }
876         }
877         
878         /**
879          * Process edge relationship.
880          *
881          * @param relationshipObj the relationship obj
882          * @param edge the edge
883          * @param direction the direction
884          * @param cleanUp the clean up
885          * @return the object
886          * @throws InstantiationException the instantiation exception
887          * @throws IllegalAccessException the illegal access exception
888          * @throws IllegalArgumentException the illegal argument exception
889          * @throws InvocationTargetException the invocation target exception
890          * @throws NoSuchMethodException the no such method exception
891          * @throws SecurityException the security exception
892          * @throws UnsupportedEncodingException the unsupported encoding exception
893          * @throws AAIException the AAI exception
894          * @throws MalformedURLException the malformed URL exception
895          * @throws AAIUnknownObjectException
896          * @throws URISyntaxException 
897          */
898                 private Object processEdgeRelationship(Introspector relationshipObj, Vertex cousin, String cleanUp) throws UnsupportedEncodingException, AAIUnknownObjectException {
899
900
901                 //we must look up all parents in this case because we need to compute name-properties
902                 //we cannot used the cached aaiUri to perform this action currently
903                 Pair<Vertex, List<Introspector>> tuple = this.getParents(relationshipObj.getLoader(), cousin, "true".equals(cleanUp));
904                 //damaged vertex found, ignore
905                 if (tuple == null) {
906                         return null;
907                 }
908                 List<Introspector> list = tuple.getValue1();
909                 URI uri = this.getURIFromList(list);
910                 
911                 URIToRelationshipObject uriParser = null;
912                 Introspector result = null;
913                 try {
914                         uriParser = new URIToRelationshipObject(relationshipObj.getLoader(), uri, this.baseURL);
915                         result = uriParser.getResult();
916                 } catch (AAIException | URISyntaxException e) {
917                         LOGGER.error("Error while processing edge relationship in version " + relationshipObj.getVersion() + " (bad vertex ID=" + tuple.getValue0().id().toString() + ": " + e.getMessage(), e);
918                         if ("true".equals(cleanUp)) {
919                                 this.deleteWithTraversal(tuple.getValue0());
920                         }
921                         return null;
922                 }
923
924         if(list.size() > 0 && this.version.compareTo(Version.v8) >= 0){
925             this.addRelatedToProperty(result, list.get(0));
926         }
927
928                 return result.getUnderlyingObject();
929         }
930         
931         /**
932          * Gets the URI for vertex.
933          *
934          * @param v the v
935          * @return the URI for vertex
936          * @throws InstantiationException the instantiation exception
937          * @throws IllegalAccessException the illegal access exception
938          * @throws IllegalArgumentException the illegal argument exception
939          * @throws InvocationTargetException the invocation target exception
940          * @throws NoSuchMethodException the no such method exception
941          * @throws SecurityException the security exception
942          * @throws UnsupportedEncodingException the unsupported encoding exception
943          * @throws AAIUnknownObjectException
944          */
945         public URI getURIForVertex(Vertex v) throws UnsupportedEncodingException {
946                 
947                 return getURIForVertex(v, false); 
948         }
949         
950         public URI getURIForVertex(Vertex v, boolean overwrite) throws UnsupportedEncodingException {
951                 URI uri = null;
952                 
953                 String aaiUri = v.<String>property(AAIProperties.AAI_URI).orElse(null);
954                 
955                 if (aaiUri != null && !overwrite) {
956                         uri = UriBuilder.fromPath(aaiUri).build();
957                 } else {
958                         Pair<Vertex, List<Introspector>> tuple = this.getParents(this.loader, v, false);
959                         List<Introspector> list = tuple.getValue1();
960                         uri = this.getURIFromList(list);
961                 }
962                 return uri; 
963         }
964         /**
965          * Gets the URI from list.
966          *
967          * @param list the list
968          * @return the URI from list
969          * @throws UnsupportedEncodingException the unsupported encoding exception
970          */
971         private URI getURIFromList(List<Introspector> list) throws UnsupportedEncodingException {
972                 String uri = "";
973                 StringBuilder sb = new StringBuilder();
974                 for (Introspector i : list) {
975                         sb.insert(0, i.getURI());
976                 }
977                 
978                 uri = sb.toString();
979                 URI result = UriBuilder.fromPath(uri).build();
980                 return result;
981         }
982         
983         /**
984          * Gets the parents.
985          *
986          * @param start the start
987          * @param removeDamaged the remove damaged
988          * @return the parents
989          * @throws InstantiationException the instantiation exception
990          * @throws IllegalAccessException the illegal access exception
991          * @throws IllegalArgumentException the illegal argument exception
992          * @throws InvocationTargetException the invocation target exception
993          * @throws NoSuchMethodException the no such method exception
994          * @throws SecurityException the security exception
995          * @throws AAIUnknownObjectException
996          */
997         private Pair<Vertex, List<Introspector>> getParents(Loader loader, Vertex start, boolean removeDamaged) {
998                 
999                 List<Vertex> results = this.engine.getQueryEngine().findParents(start);
1000                 List<Introspector> objs = new ArrayList<>();
1001                 boolean shortCircuit = false;
1002                 for (Vertex v : results) {
1003                         String nodeType = v.<String>property(AAIProperties.NODE_TYPE).orElse(null);
1004                         Introspector obj = null;
1005                         //vertex on the other end of this edge is bad
1006                         if (nodeType == null) {
1007                                 //log something here about what was found and that it was removed
1008                                 ErrorLogHelper.logError("AAI-6143", "Found a damaged parent vertex " + v.id().toString());
1009                                 if (removeDamaged) {
1010                                         this.deleteWithTraversal(v);
1011                                 }
1012                                 shortCircuit = true;
1013                         } else {
1014                                 try {
1015                                         obj = loader.introspectorFromName(nodeType);
1016                                 } catch (AAIUnknownObjectException e) {
1017                                         LOGGER.info("attempted to create node type " + nodeType + " but we do not understand it for version: " + loader.getVersion());
1018                                         obj = null;
1019                                 }
1020                         }
1021                         
1022                         if (obj == null) {
1023                                 //can't make a valid path because we don't understand this object
1024                                 // don't include it
1025                         } else {
1026                                 this.simpleDbToObject(obj, v);
1027                                 objs.add(obj);
1028                         }
1029                 }
1030                 
1031                 //stop processing and don't return anything for this bad vertex
1032                 if (shortCircuit) {
1033                         return null;
1034                 }
1035                 
1036                 return new Pair<>(results.get(results.size()-1), objs);
1037         }
1038         /**
1039          * Takes a list of vertices and a list of objs and assumes they are in
1040          * the order you want the URIs to be nested.
1041          * [A,B,C] creates uris [A, AB, ABC]
1042          * @param vertices
1043          * @param objs
1044          * @throws UnsupportedEncodingException
1045          * @throws URISyntaxException
1046          */
1047         public void setCachedURIs(List<Vertex> vertices, List<Introspector> objs) throws UnsupportedEncodingException, URISyntaxException {
1048                 
1049                 String uriChain = "";
1050                 for (int i = 0; i < vertices.size(); i++) {
1051                         String aaiUri = "";
1052                         Vertex v = null;
1053                         v = vertices.get(i);
1054                         aaiUri = v.<String>property(AAIProperties.AAI_URI).orElse(null);
1055                         if (aaiUri != null) {
1056                                 uriChain += aaiUri;
1057                         } else {
1058                                 URI uri = UriBuilder.fromPath(objs.get(i).getURI()).build();
1059                                 aaiUri = uri.toString();
1060                                 uriChain += aaiUri;
1061                                 v.property(AAIProperties.AAI_URI, uriChain);
1062                         }
1063                 }
1064                 
1065                 
1066                 
1067         }
1068         
1069         
1070         /**
1071          * Adds the r
1072          * @throws AAIUnknownObjectException
1073          * @throws IllegalArgumentException elated to property.
1074          *
1075          * @param relationship the relationship
1076          * @param child the throws IllegalArgumentException, AAIUnknownObjectException child
1077          */
1078         public void addRelatedToProperty(Introspector relationship, Introspector child) throws AAIUnknownObjectException {
1079                 String nameProps = child.getMetadata(ObjectMetadata.NAME_PROPS);
1080                 List<Introspector> relatedToProperties = new ArrayList<>();
1081                 
1082                 if (nameProps != null) {
1083                         String[] props = nameProps.split(",");
1084                         for (String prop : props) {
1085                                 Introspector relatedTo = relationship.newIntrospectorInstanceOfNestedProperty("related-to-property");
1086                                 relatedTo.setValue("property-key", child.getDbName() + "." + prop);
1087                                 relatedTo.setValue("property-value", child.getValue(prop));
1088                                 relatedToProperties.add(relatedTo);
1089                         }
1090                 }
1091                 
1092                 if (relatedToProperties.size() > 0) {
1093                         List relatedToList = (List)relationship.getValue("related-to-property");
1094                         for (Introspector obj : relatedToProperties) {
1095                                 relatedToList.add(obj.getUnderlyingObject());
1096                         }
1097                 }
1098                 
1099         }
1100         
1101         /**
1102          * Creates the edge.
1103          *
1104          * @param relationship the relationship
1105          * @param inputVertex the input vertex
1106          * @return true, if successful
1107          * @throws UnsupportedEncodingException the unsupported encoding exception
1108          * @throws AAIException the AAI exception
1109          */
1110         public boolean createEdge(Introspector relationship, Vertex inputVertex) throws UnsupportedEncodingException, AAIException {
1111                 
1112                 Vertex relatedVertex = null;
1113                 
1114                 QueryParser parser = engine.getQueryBuilder().createQueryFromRelationship(relationship);
1115                 
1116                 List<Vertex> results = parser.getQueryBuilder().toList();
1117                 if (results.size() == 0) {
1118                         AAIException e = new AAIException("AAI_6129", "Node of type " + parser.getResultType() + ". Could not find object at: " + parser.getUri());
1119                         e.getTemplateVars().add(parser.getResultType());
1120                         e.getTemplateVars().add(parser.getUri().toString());
1121                         throw e;
1122                 } else { 
1123                         //still an issue if there's more than one
1124                         relatedVertex = results.get(0);
1125                 }
1126
1127                 if (relatedVertex != null) {
1128
1129                         Edge e;
1130                         try {
1131                                 e = this.getEdgeBetween(EdgeType.COUSIN, inputVertex, relatedVertex);
1132                                 if (e == null) {                                
1133                                         edgeRules.addEdge(this.engine.asAdmin().getTraversalSource(), inputVertex, relatedVertex);
1134                                         
1135                                 } else {
1136                                         //attempted to link two vertexes already linked
1137                                 }
1138                         } catch (NoEdgeRuleFoundException e1) {
1139                                 throw new AAIException("AAI_6129", e1);
1140                         }
1141                         
1142                         
1143                         
1144
1145                 }
1146                 
1147                 return true;
1148         }
1149         
1150         /**
1151          * Gets the edges between.
1152          *
1153          * @param aVertex the out vertex
1154          * @param bVertex the in vertex
1155          * @return the edges between
1156          * @throws AAIException the AAI exception
1157          * @throws NoEdgeRuleFoundException
1158          */
1159         private List<Edge> getEdgesBetween(EdgeType type, Vertex aVertex, Vertex bVertex) throws AAIException, NoEdgeRuleFoundException {
1160                 
1161                 List<Edge> result = new ArrayList<>();
1162                 
1163                 if (bVertex != null) {
1164                                 EdgeRule rule = edgeRules.getEdgeRule(type, aVertex, bVertex);
1165                                 GraphTraversal<Vertex, Edge> findEdgesBetween = null;
1166                                 findEdgesBetween = this.engine.asAdmin().getTraversalSource().V(aVertex).bothE(rule.getLabel()).filter(__.otherV().hasId(bVertex.id()));
1167                                 List<Edge> edges = findEdgesBetween.toList();
1168                                 for (Edge edge : edges) {
1169                                         if (edge.label().equals(rule.getLabel())) {
1170                                                 result.add(edge);
1171                                         }
1172                                 }
1173
1174                 }
1175                 
1176                 return result;
1177         }
1178         
1179         /**
1180          * Gets the edge between.
1181          *
1182          * @param aVertex the out vertex
1183          * @param bVertex the in vertex
1184          * @return the edge between
1185          * @throws AAIException the AAI exception
1186          * @throws NoEdgeRuleFoundException
1187          */
1188         private Edge getEdgeBetween(EdgeType type, Vertex aVertex, Vertex bVertex) throws AAIException {
1189                 
1190                 
1191                 
1192                 if (bVertex != null) {
1193
1194                                 List<Edge> edges = this.getEdgesBetween(type, aVertex, bVertex);
1195                                 
1196                                 if (edges.size() > 0) {
1197                                         return edges.get(0);
1198                                 }
1199
1200                 }
1201                 
1202                 return null;
1203         }
1204         
1205
1206         /**
1207          * Delete edge.
1208          *
1209          * @param relationship the relationship
1210          * @param inputVertex the input vertex
1211          * @return true, if successful
1212          * @throws UnsupportedEncodingException the unsupported encoding exception
1213          * @throws AAIException the AAI exception
1214          */
1215         public boolean deleteEdge(Introspector relationship, Vertex inputVertex) throws UnsupportedEncodingException, AAIException {
1216                 
1217                 Vertex relatedVertex = null;
1218
1219                 QueryParser parser = engine.getQueryBuilder().createQueryFromRelationship(relationship);
1220                 
1221                 List<Vertex> results = parser.getQueryBuilder().toList();
1222
1223                 if (results.size() == 0) {
1224                         return false;
1225                 }
1226                 
1227                 relatedVertex = results.get(0);
1228                 Edge edge;
1229                 try {
1230                         edge = this.getEdgeBetween(EdgeType.COUSIN, inputVertex, relatedVertex);
1231                 } catch (NoEdgeRuleFoundException e) {
1232                         throw new AAIException("AAI_6129", e);
1233                 }
1234                 if (edge != null) {
1235                         edge.remove();
1236                         return true;
1237                 } else {
1238                         return false;
1239                 }
1240                 
1241         }
1242         
1243         /**
1244          * Delete items with traversal.
1245          *
1246          * @param vertexes the vertexes
1247          * @throws IllegalStateException the illegal state exception
1248          */
1249         public void deleteItemsWithTraversal(List<Vertex> vertexes) throws IllegalStateException {
1250                 for (Vertex v : vertexes) {
1251                         LOGGER.debug("About to delete the vertex with id: " + v.id());
1252                         deleteWithTraversal(v);
1253                 }
1254         }
1255         
1256         /**
1257          * Delete with traversal.
1258          *
1259          * @param startVertex the start vertex
1260          */
1261         public void deleteWithTraversal(Vertex startVertex) {
1262                 
1263                 List<Vertex> results = this.engine.getQueryEngine().findDeletable(startVertex);
1264                 
1265                 for (Vertex v : results) {
1266                         LOGGER.warn("Removing vertex " + v.id().toString());
1267
1268                         v.remove();
1269                 }
1270                 
1271         }
1272
1273         /**
1274          * Delete.
1275          *
1276          * @param v the v
1277          * @param resourceVersion the resource version
1278          * @throws IllegalArgumentException the illegal argument exception
1279          * @throws AAIException the AAI exception
1280          * @throws InterruptedException the interrupted exception
1281          */
1282         public void delete(Vertex v, String resourceVersion, boolean enableResourceVersion) throws IllegalArgumentException, AAIException {
1283         
1284                 boolean result = verifyDeleteSemantics(v, resourceVersion, enableResourceVersion);
1285                 if (result) {
1286                         try {
1287                                 deleteWithTraversal(v);
1288                         } catch (IllegalStateException e) {
1289                                 throw new AAIException("AAI_6110", e);
1290                         }
1291
1292                 }
1293                 
1294         }
1295         
1296
1297         /**
1298          * Verify delete semantics.
1299          *
1300          * @param vertex the vertex
1301          * @param resourceVersion the resource version
1302          * @return true, if successful
1303          * @throws AAIException the AAI exception
1304          */
1305         private boolean verifyDeleteSemantics(Vertex vertex, String resourceVersion, boolean enableResourceVersion) throws AAIException {
1306                 boolean result = false;
1307                 String nodeType = "";
1308                 DeleteSemantic semantic = null;
1309                 List<Edge> inEdges = null;
1310                 List<Edge> outEdges = null;
1311                 String errorDetail = " unknown delete semantic found";
1312                 String aaiExceptionCode = "";
1313                 nodeType = vertex.<String>property(AAIProperties.NODE_TYPE).orElse(null);
1314                 if (enableResourceVersion && !this.verifyResourceVersion("delete", nodeType, vertex.<String>property(AAIProperties.RESOURCE_VERSION).orElse(null), resourceVersion, nodeType)) {
1315                 }
1316                 semantic = edgeRules.getDeleteSemantic(nodeType);
1317                 inEdges = (List<Edge>) IteratorUtils.toList(vertex.edges(Direction.IN));
1318                 outEdges = (List<Edge>) IteratorUtils.toList(vertex.edges(Direction.OUT));
1319                 if (semantic.equals(DeleteSemantic.CASCADE_TO_CHILDREN)) {
1320                         result = true;
1321                 } else if (semantic.equals(DeleteSemantic.ERROR_IF_ANY_EDGES)) {
1322                         if (inEdges.isEmpty() && outEdges.isEmpty()) {
1323                                 result = true;
1324                         } else {
1325                                 errorDetail = " Node cannot be deleted because it still has Edges and the " + semantic + " scope was used.\n";
1326                                 aaiExceptionCode = "AAI_6110";
1327                         }
1328                 } else if (semantic.equals(DeleteSemantic.ERROR_IF_ANY_IN_EDGES) || semantic.equals(DeleteSemantic.ERROR_4_IN_EDGES_OR_CASCADE)) {
1329                         
1330                         if (inEdges.isEmpty()) {
1331                                 result = true;
1332                         } else {
1333                                 //are there any cousin edges?
1334                                 long children = 0;
1335                                 for (Edge e : inEdges) {
1336                                         if (e.<Boolean>property("isParent").orElse(false)) {
1337                                                 children++;
1338                                         }
1339                                 }
1340                                 
1341                                 result = children == inEdges.size();
1342                         }
1343                         
1344                         if (!result) {
1345                                 errorDetail = " Node cannot be deleted because it still has Edges and the " + semantic + " scope was used.\n";
1346                                 aaiExceptionCode = "AAI_6110";
1347                         }
1348                 } else if (semantic.equals(DeleteSemantic.THIS_NODE_ONLY)) {
1349                         if (outEdges.isEmpty() && inEdges.isEmpty()) {
1350                                 result = true;
1351                         } else {
1352                                 result = true;
1353                                 for (Edge edge : outEdges) {
1354                                         Object property = edge.<Boolean>property("isParent").orElse(null);
1355                                         if (property != null && property.equals(Boolean.TRUE)) {
1356                                                 Vertex v = edge.inVertex();
1357                                                 String vType = v.<String>property(AAIProperties.NODE_TYPE).orElse(null);
1358                                                 errorDetail = " Node cannot be deleted using scope = " + semantic + 
1359                                                                 " another node (type = " + vType + ") depends on it for uniqueness.";
1360                                                 aaiExceptionCode = "AAI_6110";
1361                                                 result = false;
1362                                                 break;
1363                                         }
1364                                 }
1365                                 
1366                                 for (Edge edge : inEdges) {
1367                                         Object property = edge.<Boolean>property("isParent-REV").orElse(null);
1368                                         if (property != null && property.equals(Boolean.TRUE)) {
1369                                                 Vertex v = edge.outVertex();
1370                                                 String vType = v.<String>property(AAIProperties.NODE_TYPE).orElse(null);
1371                                                 errorDetail = " Node cannot be deleted using scope = " + semantic + 
1372                                                                 " another node (type = " + vType + ") depends on it for uniqueness.";
1373                                                 aaiExceptionCode = "AAI_6110";
1374                                                 result = false;
1375                                                 break;
1376                                         }
1377                                 }
1378                         }
1379                 }
1380                 
1381                 
1382                 if (!result) {
1383                         throw new AAIException(aaiExceptionCode, errorDetail);
1384                 }
1385                 return result;
1386         }
1387
1388         /**
1389          * Verify resource version.
1390          *
1391          * @param action the action
1392          * @param nodeType the node type
1393          * @param currentResourceVersion the current resource version
1394          * @param resourceVersion the resource version
1395          * @param uri the uri
1396          * @return true, if successful
1397          * @throws AAIException the AAI exception
1398          */
1399         public boolean verifyResourceVersion(String action, String nodeType, String currentResourceVersion, String resourceVersion, String uri) throws AAIException {
1400                 String enabled = "";
1401                 String errorDetail = "";
1402                 String aaiExceptionCode = "";
1403                 if (currentResourceVersion == null) {
1404                         currentResourceVersion = "";
1405                 }
1406                 
1407                 if (resourceVersion == null) {
1408                         resourceVersion = "";
1409                 }
1410                 try {
1411                         enabled = AAIConfig.get(AAIConstants.AAI_RESVERSION_ENABLEFLAG);
1412                 } catch (AAIException e) {
1413                         ErrorLogHelper.logException(e);
1414                 }
1415                 // We're only doing the resource version checks for v5 and later
1416                 if (enabled.equals("true") && this.version.compareTo(Version.v8) > 0) {
1417                         if (!currentResourceVersion.equals(resourceVersion)) {
1418                                 if (action.equals("create") && !resourceVersion.equals("")) {
1419                                         errorDetail = "resource-version passed for " + action + " of " + uri;
1420                                         aaiExceptionCode = "AAI_6135";
1421                                 } else if (resourceVersion.equals("")) {
1422                                         errorDetail = "resource-version not passed for " + action + " of " + uri;
1423                                         aaiExceptionCode = "AAI_6130";
1424                                 } else {
1425                                         errorDetail = "resource-version MISMATCH for " + action + " of " + uri;
1426                                         aaiExceptionCode = "AAI_6131";
1427                                 }
1428                                 
1429                                 throw new AAIException(aaiExceptionCode, errorDetail);
1430                                 
1431                         }
1432                 }
1433                 return true;
1434         }
1435         
1436         /**
1437          * Convert from camel case.
1438          *
1439          * @param name the name
1440          * @return the string
1441          */
1442         private String convertFromCamelCase (String name) {
1443                 String result = "";
1444                 result = CaseFormat.UPPER_CAMEL.to(CaseFormat.LOWER_HYPHEN, name);
1445                 
1446                 NamingExceptions exceptions = NamingExceptions.getInstance();
1447                 result = exceptions.getDBName(result);
1448                 
1449                 return result;
1450         }
1451         
1452         private boolean canModify(Introspector obj, String propName, String requestContext) {
1453                 final String readOnly = obj.getPropertyMetadata(propName).get(PropertyMetadata.READ_ONLY);
1454                 if (readOnly != null) {
1455                         final String[] items = readOnly.split(",");
1456                         for (String item : items) {
1457                                 if (requestContext.equals(item)) {
1458                                         return false;
1459                                 }
1460                         }
1461                 }
1462                 return true;
1463         }
1464         
1465         private void executePreSideEffects(Introspector obj, Vertex self) throws AAIException {
1466                 
1467                 SideEffectRunner runner = new SideEffectRunner
1468                                 .Builder(this.engine, this).addSideEffect(DataCopy.class).build();
1469                 
1470                 runner.execute(obj, self);
1471         }
1472         
1473         private void executePostSideEffects(Introspector obj, Vertex self) throws AAIException {
1474                 
1475                 SideEffectRunner runner = new SideEffectRunner
1476                                 .Builder(this.engine, this).addSideEffect(DataLinkWriter.class).build();
1477                 
1478                 runner.execute(obj, self);
1479         }
1480         
1481         private void enrichData(Introspector obj, Vertex self) throws AAIException {
1482                 
1483                 SideEffectRunner runner = new SideEffectRunner
1484                                 .Builder(this.engine, this).addSideEffect(DataLinkReader.class).build();
1485                 
1486                 runner.execute(obj, self);
1487         }
1488
1489 }