Integrate aai-schema-ingest library into aai-core
[aai/aai-common.git] / aai-core / src / main / java / org / onap / aai / serialization / db / DBSerializer.java
1 /**
2  * ============LICENSE_START=======================================================
3  * org.onap.aai
4  * ================================================================================
5  * Copyright © 2017-2018 AT&T Intellectual Property. All rights reserved.
6  * ================================================================================
7  * Licensed under the Apache License, Version 2.0 (the "License");
8  * you may not use this file except in compliance with the License.
9  * You may obtain a copy of the License at
10  *
11  *    http://www.apache.org/licenses/LICENSE-2.0
12  *
13  * Unless required by applicable law or agreed to in writing, software
14  * distributed under the License is distributed on an "AS IS" BASIS,
15  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16  * See the License for the specific language governing permissions and
17  * limitations under the License.
18  * ============LICENSE_END=========================================================
19  */
20 package org.onap.aai.serialization.db;
21
22
23 import com.att.eelf.configuration.EELFLogger;
24 import com.att.eelf.configuration.EELFManager;
25 import com.google.common.base.CaseFormat;
26 import org.janusgraph.core.SchemaViolationException;
27 import org.apache.commons.collections.IteratorUtils;
28 import org.apache.tinkerpop.gremlin.process.traversal.dsl.graph.GraphTraversal;
29 import org.apache.tinkerpop.gremlin.process.traversal.dsl.graph.__;
30 import org.apache.tinkerpop.gremlin.process.traversal.step.util.Tree;
31 import org.apache.tinkerpop.gremlin.structure.*;
32 import org.javatuples.Pair;
33 import org.javatuples.Triplet;
34 import org.onap.aai.db.props.AAIProperties;
35 import org.onap.aai.edges.EdgeIngestor;
36 import org.onap.aai.edges.EdgeRule;
37 import org.onap.aai.edges.EdgeRuleQuery;
38 import org.onap.aai.edges.enums.AAIDirection;
39 import org.onap.aai.edges.enums.EdgeField;
40 import org.onap.aai.edges.enums.EdgeProperty;
41 import org.onap.aai.edges.enums.EdgeType;
42 import org.onap.aai.edges.exceptions.AmbiguousRuleChoiceException;
43 import org.onap.aai.edges.exceptions.EdgeRuleNotFoundException;
44 import org.onap.aai.exceptions.AAIException;
45 import org.onap.aai.introspection.*;
46 import org.onap.aai.introspection.exceptions.AAIUnknownObjectException;
47 import org.onap.aai.introspection.sideeffect.*;
48 import org.onap.aai.logging.ErrorLogHelper;
49 import org.onap.aai.logging.LogFormatTools;
50 import org.onap.aai.logging.StopWatch;
51 import org.onap.aai.parsers.query.QueryParser;
52 import org.onap.aai.parsers.uri.URIParser;
53 import org.onap.aai.parsers.uri.URIToRelationshipObject;
54 import org.onap.aai.query.builder.QueryBuilder;
55 import org.onap.aai.schema.enums.ObjectMetadata;
56 import org.onap.aai.schema.enums.PropertyMetadata;
57 import org.onap.aai.serialization.db.exceptions.MultipleEdgeRuleFoundException;
58 import org.onap.aai.serialization.db.exceptions.NoEdgeRuleFoundException;
59 import org.onap.aai.serialization.engines.TransactionalGraphEngine;
60 import org.onap.aai.serialization.tinkerpop.TreeBackedVertex;
61 import org.onap.aai.setup.SchemaVersion;
62 import org.onap.aai.setup.SchemaVersions;
63 import org.onap.aai.util.AAIConfig;
64 import org.onap.aai.util.AAIConstants;
65 import org.onap.aai.workarounds.NamingExceptions;
66 import org.springframework.context.ApplicationContext;
67 import org.onap.aai.concurrent.AaiCallable;
68 import org.onap.aai.config.SpringContextAware;
69
70 import javax.ws.rs.core.UriBuilder;
71 import java.io.UnsupportedEncodingException;
72 import java.lang.reflect.Array;
73 import java.lang.reflect.InvocationTargetException;
74 import java.net.MalformedURLException;
75 import java.net.URI;
76 import java.net.URISyntaxException;
77 import java.util.*;
78 import java.util.concurrent.ExecutionException;
79 import java.util.concurrent.ExecutorService;
80 import java.util.concurrent.Future;
81 import java.util.regex.Matcher;
82 import java.util.regex.Pattern;
83 import org.onap.aai.serialization.engines.query.QueryEngine;
84
85 public class DBSerializer {
86         
87         private static final EELFLogger LOGGER = EELFManager.getInstance().getLogger(DBSerializer.class);
88         
89         private final TransactionalGraphEngine engine;
90         private final String sourceOfTruth;
91         private final ModelType introspectionType;
92         private final SchemaVersion version;
93         private final Loader latestLoader;
94         private EdgeSerializer edgeSer;
95         private EdgeIngestor edgeRules;
96         private final Loader loader;
97         private final String baseURL;
98         private double dbTimeMsecs = 0;
99
100         private SchemaVersions schemaVersions;
101         /**
102          * Instantiates a new DB serializer.
103          *
104          * @param version the version
105          * @param engine the engine
106          * @param introspectionType the introspection type
107          * @param sourceOfTruth the source of truth
108          * @throws AAIException
109          */
110         public DBSerializer(SchemaVersion version, TransactionalGraphEngine engine, ModelType introspectionType, String sourceOfTruth) throws AAIException {
111                 this.engine = engine;
112                 this.sourceOfTruth = sourceOfTruth;
113                 this.introspectionType = introspectionType;
114                 this.schemaVersions = SpringContextAware.getBean(SchemaVersions.class);
115                 SchemaVersion LATEST = schemaVersions.getDefaultVersion();
116                 this.latestLoader = SpringContextAware.getBean(LoaderFactory.class).createLoaderForVersion(introspectionType, LATEST);
117                 this.version = version;
118                 this.loader = SpringContextAware.getBean(LoaderFactory.class).createLoaderForVersion(introspectionType, version);
119                 this.baseURL = AAIConfig.get(AAIConstants.AAI_SERVER_URL_BASE);
120                 initBeans();
121         }
122
123         private void initBeans() {
124                 //TODO proper spring wiring, but that requires a lot of refactoring so for now we have this
125                 ApplicationContext ctx = SpringContextAware.getApplicationContext();
126                 EdgeIngestor ei = ctx.getBean(EdgeIngestor.class);
127                 setEdgeIngestor(ei);
128                 EdgeSerializer es = ctx.getBean(EdgeSerializer.class);
129                 setEdgeSerializer(es);
130         }
131
132         private void backupESInit() {
133                 setEdgeSerializer(new EdgeSerializer(this.edgeRules));
134         }
135
136         public void setEdgeSerializer(EdgeSerializer edgeSer) {
137                 this.edgeSer = edgeSer;
138         }
139
140         public EdgeSerializer getEdgeSeriailizer() {
141             return this.edgeSer;
142         }
143
144         public void setEdgeIngestor(EdgeIngestor ei) {
145                 this.edgeRules = ei;
146         }
147
148         public EdgeIngestor getEdgeIngestor(){
149                 return this.edgeRules;
150         }
151
152         /**
153          * Touch standard vertex properties.
154          *
155          * @param v the v
156          * @param isNewVertex the is new vertex
157          */
158         public void touchStandardVertexProperties(Vertex v, boolean isNewVertex) {
159                 
160                 String timeNowInSec = Long.toString(System.currentTimeMillis());
161                 if (isNewVertex) {
162                         v.property(AAIProperties.SOURCE_OF_TRUTH, this.sourceOfTruth);
163                         v.property(AAIProperties.CREATED_TS, timeNowInSec);
164                         v.property(AAIProperties.AAI_UUID, UUID.randomUUID().toString());
165                 }
166                 v.property(AAIProperties.RESOURCE_VERSION, timeNowInSec );
167                 v.property(AAIProperties.LAST_MOD_TS, timeNowInSec);
168                 v.property(AAIProperties.LAST_MOD_SOURCE_OF_TRUTH, this.sourceOfTruth);
169                 
170         }
171         
172         private void touchStandardVertexProperties(String nodeType, Vertex v, boolean isNewVertex) {
173                 
174                 v.property(AAIProperties.NODE_TYPE, nodeType);
175                 touchStandardVertexProperties(v, isNewVertex);
176
177         }
178         
179         
180         
181         /**
182          * Creates the new vertex.
183          *
184          * @param wrappedObject the wrapped object
185          * @return the vertex
186          * @throws UnsupportedEncodingException the unsupported encoding exception
187          * @throws AAIException the AAI exception
188          */
189         public Vertex createNewVertex(Introspector wrappedObject) {
190                 Vertex v;
191                 try {
192                         StopWatch.conditionalStart();
193                         v = this.engine.tx().addVertex();
194                         touchStandardVertexProperties(wrappedObject.getDbName(), v, true);
195                 }
196                 finally {
197                         dbTimeMsecs += StopWatch.stopIfStarted();
198                 }
199                 return v;
200         }
201         
202         /**
203          * Trim class name.
204          *
205          * @param className the class name
206          * @return the string
207          */
208         /*
209          * Removes the classpath from a class name
210          */
211         public String trimClassName (String className) {
212                 String returnValue = "";
213                 
214                 if (className.lastIndexOf('.') == -1) {
215                         return className;
216                 }
217                 returnValue = className.substring(className.lastIndexOf('.') + 1, className.length());
218                 
219                 return returnValue;
220         }
221         
222         /**
223          * Serialize to db.
224          *
225          * @param obj the obj
226          * @param v the v
227          * @param uriQuery the uri query
228          * @param identifier the identifier
229          * @throws SecurityException the security exception
230          * @throws IllegalAccessException the illegal access exception
231          * @throws IllegalArgumentException the illegal argument exception
232          * @throws InvocationTargetException the invocation target exception
233          * @throws InstantiationException the instantiation exception
234          * @throws InterruptedException the interrupted exception
235          * @throws NoSuchMethodException the no such method exception
236          * @throws AAIException the AAI exception
237          * @throws UnsupportedEncodingException the unsupported encoding exception
238          * @throws AAIUnknownObjectException 
239          */
240         public void serializeToDb(Introspector obj, Vertex v, QueryParser uriQuery, String identifier, String requestContext) throws AAIException, UnsupportedEncodingException {
241                 StopWatch.conditionalStart();
242                 try {
243                         if (uriQuery.isDependent()) {
244                                 //try to find the parent
245                                 List<Vertex> vertices = uriQuery.getQueryBuilder().getParentQuery().toList();
246                                 if (!vertices.isEmpty()) {
247                                         Vertex parent = vertices.get(0);
248                                         this.reflectDependentVertex(parent, v, obj, requestContext);
249                                 } else {
250                                         dbTimeMsecs += StopWatch.stopIfStarted();
251                                         throw new AAIException("AAI_6114", "No parent Node of type " + uriQuery.getParentResultType() + " for " + identifier);
252                                 }
253                         } else {
254                                 serializeSingleVertex(v, obj, requestContext);
255                         }
256
257                 } catch (SchemaViolationException e) {
258                         dbTimeMsecs += StopWatch.stopIfStarted();
259                         throw new AAIException("AAI_6117", e);
260                 }
261                 dbTimeMsecs += StopWatch.stopIfStarted();
262         }
263         
264         public void serializeSingleVertex(Vertex v, Introspector obj, String requestContext) throws UnsupportedEncodingException, AAIException {
265                 StopWatch.conditionalStart();
266                 try {
267                         boolean isTopLevel = obj.isTopLevel();
268                         if (isTopLevel) {
269                                 addUriIfNeeded(v, obj.getURI());
270                         }
271                         
272                         processObject(obj, v, requestContext);
273                         if (!isTopLevel) {
274                                 URI uri = this.getURIForVertex(v);
275                                 URIParser parser = new URIParser(this.loader, uri);
276                                 if (parser.validate()) {
277                                         addUriIfNeeded(v, uri.toString());
278                                 }
279                         }
280                 } catch (SchemaViolationException e) {
281                         throw new AAIException("AAI_6117", e);
282                 }
283                 finally {
284                         dbTimeMsecs += StopWatch.stopIfStarted();
285                 }
286         }
287
288         private void addUriIfNeeded(Vertex v, String uri) {
289                 VertexProperty<String> uriProp = v.property(AAIProperties.AAI_URI);
290                 if (!uriProp.isPresent() || (uriProp.isPresent() && !uriProp.value().equals(uri))) {
291                         v.property(AAIProperties.AAI_URI, uri);
292                 }
293         }
294
295         /**
296          * Process object.
297          *
298          * @param <T> the generic type
299          * @param obj the obj
300          * @param v the v
301          * @return the list
302          * @throws IllegalAccessException the illegal access exception
303          * @throws IllegalArgumentException the illegal argument exception
304          * @throws InvocationTargetException the invocation target exception
305          * @throws InstantiationException the instantiation exception
306          * @throws NoSuchMethodException the no such method exception
307          * @throws SecurityException the security exception
308          * @throws AAIException the AAI exception
309          * @throws UnsupportedEncodingException the unsupported encoding exception
310          * @throws AAIUnknownObjectException 
311          */
312         /*
313          * Helper method for reflectToDb
314          * Handles all the property setting
315          */
316         private <T> List<Vertex> processObject (Introspector obj, Vertex v, String requestContext) throws UnsupportedEncodingException, AAIException {
317                 Set<String> properties = new LinkedHashSet<>(obj.getProperties());
318                 properties.remove(AAIProperties.RESOURCE_VERSION);
319                 List<Vertex> dependentVertexes = new ArrayList<>();
320                 List<Vertex> processedVertexes = new ArrayList<>();
321                 boolean isComplexType = false;
322                 boolean isListType = false;
323                 if (!obj.isContainer()) {
324                         this.touchStandardVertexProperties(obj.getDbName(), v, false);
325                 }
326                 this.executePreSideEffects(obj, v);
327                 for (String property : properties) {
328                         Object value = null;
329                         final String propertyType;
330                         propertyType = obj.getType(property);
331                         isComplexType = obj.isComplexType(property);
332                         isListType = obj.isListType(property);
333                         value = obj.getValue(property);
334
335                         if (!(isComplexType || isListType)) {
336                                 boolean canModify = this.canModify(obj, property, requestContext);
337                                 
338                                 if (canModify) {
339                                         final Map<PropertyMetadata, String> metadata = obj.getPropertyMetadata(property);
340                                         String dbProperty = property;
341                                         if (metadata.containsKey(PropertyMetadata.DB_ALIAS)) {
342                                                 dbProperty = metadata.get(PropertyMetadata.DB_ALIAS);
343                                         }
344                                         if (metadata.containsKey(PropertyMetadata.DATA_LINK)) {
345                                                 //data linked properties are ephemeral
346                                                 //they are populated dynamically on GETs
347                                                 continue;
348                                         }
349                                         if (value != null) {
350                                                 if (!value.equals(v.property(dbProperty).orElse(null))) {
351                                                         if (propertyType.toLowerCase().contains(".long")) {
352                                                                 v.property(dbProperty, new Integer(((Long)value).toString()));
353                                                         } else {
354                                                                 v.property(dbProperty, value);
355                                                         }
356                                                 }
357                                         } else {
358                                                 v.property(dbProperty).remove();
359                                         }
360                                 }
361                         } else if (isListType) {
362                                 List<Object> list = (List<Object>)value;
363                                 if (obj.isComplexGenericType(property)) {
364                                         if (list != null) {
365                                                 for (Object o : list) {
366                                                         Introspector child = IntrospectorFactory.newInstance(this.introspectionType, o);
367                                                         child.setURIChain(obj.getURI());
368                                                         processedVertexes.add(reflectDependentVertex(v, child, requestContext));
369                                                 }
370                                         }
371                                 } else {
372                                         //simple list case
373                                         engine.setListProperty(v, property, list);
374                                 }
375                         } else {
376                                 //method.getReturnType() is not 'simple' then create a vertex and edge recursively returning an edge back to this method
377                                 if (value != null) { //effectively ignore complex properties not included in the object we're processing
378                                         if (value.getClass().isArray()) {
379                                                 
380                                                 int length = Array.getLength(value);
381                                             for (int i = 0; i < length; i ++) {
382                                                 Object arrayElement = Array.get(value, i);
383                                                 Introspector child = IntrospectorFactory.newInstance(this.introspectionType, arrayElement);
384                                                         child.setURIChain(obj.getURI());
385                                                         processedVertexes.add(reflectDependentVertex(v, child, requestContext));
386
387                                             }
388                                         } else if (!property.equals("relationship-list")) {
389                                                 // container case
390                                                 Introspector introspector = IntrospectorFactory.newInstance(this.introspectionType, value);
391                                                 if (introspector.isContainer()) {
392                                                         dependentVertexes.addAll(this.engine.getQueryEngine().findChildrenOfType(v, introspector.getChildDBName()));
393                                                         introspector.setURIChain(obj.getURI());
394                                                         
395                                                         processedVertexes.addAll(processObject(introspector, v, requestContext));
396
397                                                 } else {
398                                                         dependentVertexes.addAll(this.engine.getQueryEngine().findChildrenOfType(v, introspector.getDbName()));
399                                                         processedVertexes.add(reflectDependentVertex(v, introspector, requestContext));
400
401                                                 }
402                                         } else if (property.equals("relationship-list")) {
403                                                 handleRelationships(obj, v);
404                                         }
405                                 }
406                         }
407                 }
408                 this.writeThroughDefaults(v, obj);
409                 /* handle those vertexes not touched */
410                 for (Vertex toBeRemoved : processedVertexes) {
411                         dependentVertexes.remove(toBeRemoved);
412                 }
413                 this.deleteItemsWithTraversal(dependentVertexes);
414                 
415                 this.executePostSideEffects(obj, v);
416                 return processedVertexes;
417         }
418         
419         /**
420          * Handle relationships.
421          *
422          * @param obj the obj
423          * @param vertex the vertex
424          * @throws SecurityException the security exception
425          * @throws IllegalAccessException the illegal access exception
426          * @throws IllegalArgumentException the illegal argument exception
427          * @throws InvocationTargetException the invocation target exception
428          * @throws UnsupportedEncodingException the unsupported encoding exception
429          * @throws AAIException the AAI exception
430          */
431         /*
432          * Handles the explicit relationships defined for an obj
433          */
434         private void handleRelationships(Introspector obj, Vertex vertex) throws UnsupportedEncodingException, AAIException {
435                 
436         
437         
438                 Introspector wrappedRl = obj.getWrappedValue("relationship-list");
439                 processRelationshipList(wrappedRl, vertex);
440                 
441         
442         }
443         
444         
445         /**
446          * Process relationship list.
447          *
448          * @param wrapped the wrapped
449          * @param v the v
450          * @throws UnsupportedEncodingException the unsupported encoding exception
451          * @throws AAIException the AAI exception
452          */
453         private void processRelationshipList(Introspector wrapped, Vertex v) throws UnsupportedEncodingException, AAIException {
454                                 
455                 List<Object> relationships = (List<Object>)wrapped.getValue("relationship");
456                 
457                 List<Triplet<Vertex, Vertex, String>> addEdges = new ArrayList<>();
458                 List<Edge> existingEdges = this.engine.getQueryEngine().findEdgesForVersion(v, wrapped.getLoader());
459                 
460                 for (Object relationship : relationships) {
461                         Edge e = null;
462                         Vertex cousinVertex = null;
463                         String label = null;
464                         Introspector wrappedRel = IntrospectorFactory.newInstance(this.introspectionType, relationship);
465                         QueryParser parser = engine.getQueryBuilder().createQueryFromRelationship(wrappedRel);
466                         
467                         if (wrappedRel.hasProperty("relationship-label")) {
468                                 label = wrappedRel.getValue("relationship-label");
469                         }
470                         
471                         List<Vertex> results = parser.getQueryBuilder().toList();
472                         if (results.isEmpty()) {
473                                 final AAIException ex = new AAIException("AAI_6129", "Node of type " + parser.getResultType() + ". Could not find object at: " + parser.getUri());
474                                 ex.getTemplateVars().add(parser.getResultType());
475                                 ex.getTemplateVars().add(parser.getUri().toString());
476                                 throw ex;
477                         } else { 
478                                 //still an issue if there's more than one
479                                 cousinVertex = results.get(0);
480                         }
481                         
482                         if (cousinVertex != null) {
483                                 String vType = (String)v.property(AAIProperties.NODE_TYPE).value();
484                                 String cousinType = (String)cousinVertex.property(AAIProperties.NODE_TYPE).value();
485                                 EdgeRuleQuery.Builder baseQ = new EdgeRuleQuery.Builder(vType, cousinType).label(label);
486
487
488                                 if (!edgeRules.hasRule(baseQ.build())) {
489                                         throw new AAIException("AAI_6120", "No EdgeRule found for passed nodeTypes: " + v.property(AAIProperties.NODE_TYPE).value().toString() + ", " 
490                                                         + cousinVertex.property(AAIProperties.NODE_TYPE).value().toString() + (label != null ? (" with label " + label):"")  +"."); 
491                                 } else if (edgeRules.hasRule(baseQ.edgeType(EdgeType.TREE).build()) && !edgeRules.hasRule(baseQ.edgeType(EdgeType.COUSIN).build())) {
492                                         throw new AAIException("AAI_6145");
493                                 }
494                                 
495                                 e = this.getEdgeBetween(EdgeType.COUSIN, v, cousinVertex, label);
496
497                                 if (e == null) {
498                                         addEdges.add(new Triplet<>(v, cousinVertex, label));
499                                 } else { 
500                                         existingEdges.remove(e);
501                                 }
502                         }
503                 }
504                 
505                 for (Edge edge : existingEdges) {
506                         edge.remove();
507                 }
508                 for (Triplet<Vertex, Vertex, String> triplet : addEdges) {
509                          try {
510                                  edgeSer.addEdge(this.engine.asAdmin().getTraversalSource(), triplet.getValue0(), triplet.getValue1(), triplet.getValue2());
511                         } catch (NoEdgeRuleFoundException e) {
512                                 throw new AAIException("AAI_6129", e);
513                         }                       
514                 }
515
516         }
517
518         /**
519          * Write through defaults.
520          *
521          * @param v the v
522          * @param obj the obj
523          * @throws AAIUnknownObjectException 
524          */
525         private void writeThroughDefaults(Vertex v, Introspector obj) throws AAIUnknownObjectException {
526                 Introspector latest = this.latestLoader.introspectorFromName(obj.getName());
527                 if (latest != null) {
528                         Set<String> required  = latest.getRequiredProperties();
529                         
530                         for (String field : required) {
531                                 String defaultValue = null;
532                                 Object vertexProp = null;
533                                 defaultValue = latest.getPropertyMetadata(field).get(PropertyMetadata.DEFAULT_VALUE);
534                                 if (defaultValue != null) {
535                                         vertexProp = v.<Object>property(field).orElse(null);
536                                         if (vertexProp == null) {
537                                                 v.property(field, defaultValue);
538                                         }
539                                 }
540                         }
541                 }
542                 
543         }
544
545         
546         /**
547           * Reflect dependent vertex.
548           *
549           * @param v the v
550           * @param dependentObj the dependent obj
551           * @return the vertex
552           * @throws IllegalAccessException the illegal access exception
553           * @throws IllegalArgumentException the illegal argument exception
554           * @throws InvocationTargetException the invocation target exception
555           * @throws InstantiationException the instantiation exception
556           * @throws NoSuchMethodException the no such method exception
557           * @throws SecurityException the security exception
558           * @throws AAIException the AAI exception
559           * @throws UnsupportedEncodingException the unsupported encoding exception
560          * @throws AAIUnknownObjectException 
561           */
562          private Vertex reflectDependentVertex(Vertex v, Introspector dependentObj, String requestContext) throws AAIException, UnsupportedEncodingException {
563                 
564                 //QueryParser p = this.engine.getQueryBuilder().createQueryFromURI(obj.getURI());
565                 //List<Vertex> items = p.getQuery().toList();
566                 QueryBuilder<Vertex> query = this.engine.getQueryBuilder(v);
567                 query.createEdgeTraversal(EdgeType.TREE, v, dependentObj);
568                 query.createKeyQuery(dependentObj);
569                 
570                 List<Vertex> items = query.toList();
571                 
572                 Vertex dependentVertex = null;
573                 if (items.size() == 1) {
574                         dependentVertex = items.get(0);
575                         this.verifyResourceVersion("update", dependentObj.getDbName(), dependentVertex.<String>property(AAIProperties.RESOURCE_VERSION).orElse(null), (String)dependentObj.getValue(AAIProperties.RESOURCE_VERSION), (String)dependentObj.getURI());
576                 } else {
577                         this.verifyResourceVersion("create", dependentObj.getDbName(), "", (String)dependentObj.getValue(AAIProperties.RESOURCE_VERSION), (String)dependentObj.getURI());
578                         dependentVertex = createNewVertex(dependentObj);
579                 }
580
581                 return reflectDependentVertex(v, dependentVertex, dependentObj, requestContext);
582                                 
583         }
584         
585         /**
586           * Reflect dependent vertex.
587           *
588           * @param parent the parent
589           * @param child the child
590           * @param obj the obj
591           * @return the vertex
592           * @throws IllegalAccessException the illegal access exception
593           * @throws IllegalArgumentException the illegal argument exception
594           * @throws InvocationTargetException the invocation target exception
595           * @throws InstantiationException the instantiation exception
596           * @throws NoSuchMethodException the no such method exception
597           * @throws SecurityException the security exception
598           * @throws AAIException the AAI exception
599           * @throws UnsupportedEncodingException the unsupported encoding exception
600          * @throws AAIUnknownObjectException 
601           */
602          private Vertex reflectDependentVertex(Vertex parent, Vertex child, Introspector obj, String requestContext) throws AAIException, UnsupportedEncodingException {
603                 
604                 String parentUri = parent.<String>property(AAIProperties.AAI_URI).orElse(null);
605                 if (parentUri != null) {
606                         String uri;
607                         uri = obj.getURI();
608                         addUriIfNeeded(child, parentUri + uri);
609                 }
610                 processObject(obj, child, requestContext);
611                 
612                 Edge e;
613                 e = this.getEdgeBetween(EdgeType.TREE, parent, child, null);
614                 if (e == null) {
615                         String canBeLinked = obj.getMetadata(ObjectMetadata.CAN_BE_LINKED);
616                         if (canBeLinked != null && canBeLinked.equals("true")) {
617                                 Loader ldrForCntxt = SpringContextAware.getBean(LoaderFactory.class).createLoaderForVersion(introspectionType, getVerForContext(requestContext));
618                                 boolean isFirst = !this.engine.getQueryBuilder(ldrForCntxt, parent).createEdgeTraversal(EdgeType.TREE, parent, obj).hasNext();
619                                 if (isFirst) {
620                                         child.property(AAIProperties.LINKED, true);
621                                 }
622                         }
623                         edgeSer.addTreeEdge(this.engine.asAdmin().getTraversalSource(), parent, child);
624                 }
625                 return child;
626                 
627         }
628          
629         private SchemaVersion getVerForContext(String requestContext) {
630                 Pattern pattern = Pattern.compile("v[0-9]+");
631                 Matcher m = pattern.matcher(requestContext);
632                 if (!m.find()) {
633                         return this.version;
634                 } else {
635                         return new SchemaVersion(requestContext);
636                 }
637         }
638          
639         /**
640           * Db to object.
641           *
642           * @param vertices the vertices
643           * @param obj the obj
644           * @param depth the depth
645           * @param cleanUp the clean up
646           * @return the introspector
647           * @throws AAIException the AAI exception
648           * @throws IllegalAccessException the illegal access exception
649           * @throws IllegalArgumentException the illegal argument exception
650           * @throws InvocationTargetException the invocation target exception
651           * @throws SecurityException the security exception
652           * @throws InstantiationException the instantiation exception
653           * @throws NoSuchMethodException the no such method exception
654           * @throws UnsupportedEncodingException the unsupported encoding exception
655           * @throws MalformedURLException the malformed URL exception
656          * @throws AAIUnknownObjectException 
657          * @throws URISyntaxException 
658           */
659          public Introspector dbToObject(List<Vertex> vertices, final Introspector obj, int depth, boolean nodeOnly, String cleanUp) throws UnsupportedEncodingException, AAIException {
660                 final int internalDepth;
661                 if (depth == Integer.MAX_VALUE) {
662                         internalDepth = depth--;
663                 } else {
664                         internalDepth = depth;
665                 }
666                 StopWatch.conditionalStart();
667                 if (vertices.size() > 1 && !obj.isContainer()) {
668                         dbTimeMsecs += StopWatch.stopIfStarted();
669                         throw new AAIException("AAI_6136", "query object mismatch: this object cannot hold multiple items." + obj.getDbName());
670                 } else if (obj.isContainer()) {
671                         final List getList;
672                         String listProperty = null;
673                         for (String property : obj.getProperties()) {
674                                 if (obj.isListType(property) && obj.isComplexGenericType(property)) {
675                                         listProperty = property;
676                                         break;
677                                 }
678                         }
679                         final String propertyName = listProperty;
680                         getList = (List)obj.getValue(listProperty);
681                         
682                         /* This is an experimental multithreading experiment
683                          * on get alls. 
684                          */
685                         ExecutorService pool = GetAllPool.getInstance().getPool();
686                         
687                         List<Future<Object>> futures = new ArrayList<>();
688                         
689                         QueryEngine tgEngine = this.engine.getQueryEngine();
690                         for (Vertex v : vertices) {
691
692                                 AaiCallable<Object> task = new AaiCallable<Object>() {
693                                         @Override
694                                         public Object process() throws UnsupportedEncodingException, AAIException {
695                                                 Set<Vertex> seen = new HashSet<>();
696                                                 Introspector childObject;
697                                                 try {
698                                                         childObject = obj.newIntrospectorInstanceOfNestedProperty(propertyName);
699                                                 } catch (AAIUnknownObjectException e) {
700                                                         throw e;
701                                                 }
702                                                 Tree<Element> tree = tgEngine.findSubGraph(v, internalDepth, nodeOnly);
703                                                 TreeBackedVertex treeVertex = new TreeBackedVertex(v, tree);
704                                                 try {
705                                                         dbToObject(childObject, treeVertex, seen, internalDepth, nodeOnly, cleanUp);
706                                                 } catch (UnsupportedEncodingException e) {
707                                                         throw e;
708                                                 } catch (AAIException e) {
709                                                         throw e;
710                                                 }
711                                                 return childObject.getUnderlyingObject();
712                                                 //getList.add(childObject.getUnderlyingObject());
713                                         }
714                                 };
715                                 futures.add(pool.submit(task));
716                         }
717                         
718                         for (Future<Object> future : futures) {
719                                 try {
720                                         getList.add(future.get());
721                                 } catch (ExecutionException e) {
722                                         dbTimeMsecs += StopWatch.stopIfStarted();
723                                         throw new AAIException("AAI_4000", e);
724                                 } catch (InterruptedException e) {
725                                         dbTimeMsecs += StopWatch.stopIfStarted();
726                                         throw new AAIException("AAI_4000", e);
727                                 }
728                         }
729                 } else if (vertices.size() == 1) {
730                         Set<Vertex> seen = new HashSet<>();
731                         Tree<Element> tree = this.engine.getQueryEngine().findSubGraph(vertices.get(0), depth, nodeOnly);
732                         TreeBackedVertex treeVertex = new TreeBackedVertex(vertices.get(0), tree);
733                         dbToObject(obj, treeVertex, seen, depth, nodeOnly, cleanUp);
734                 } else {
735                         //obj = null;
736                 }
737                 
738                 dbTimeMsecs += StopWatch.stopIfStarted();
739                 return obj;
740         }
741         
742         /**
743          * Db to object.
744          *
745          * @param obj the obj
746          * @param v the v
747          * @param seen the seen
748          * @param depth the depth
749          * @param cleanUp the clean up
750          * @return the introspector
751          * @throws IllegalAccessException the illegal access exception
752          * @throws IllegalArgumentException the illegal argument exception
753          * @throws InvocationTargetException the invocation target exception
754          * @throws SecurityException the security exception
755          * @throws InstantiationException the instantiation exception
756          * @throws NoSuchMethodException the no such method exception
757          * @throws UnsupportedEncodingException the unsupported encoding exception
758          * @throws AAIException the AAI exception
759          * @throws MalformedURLException the malformed URL exception
760          * @throws AAIUnknownObjectException 
761          * @throws URISyntaxException 
762          */
763         private Introspector dbToObject(Introspector obj, Vertex v, Set<Vertex> seen, int depth, boolean nodeOnly, String cleanUp) throws AAIException, UnsupportedEncodingException {
764                 
765                 if (depth < 0) {
766                         return null;
767                 }
768                 depth--;
769                 seen.add(v);
770                 
771                 boolean modified = false;
772                 for (String property : obj.getProperties(PropertyPredicates.isVisible())) {
773                         List<Object> getList = null;
774                         Vertex[] vertices = null;
775
776                         if (!(obj.isComplexType(property) || obj.isListType(property))) {
777                                 this.copySimpleProperty(property, obj, v);
778                                 modified = true;
779                         } else {
780                                 if (obj.isComplexType(property)) {
781                                 /* container case */
782         
783                                         if (!property.equals("relationship-list") && depth >= 0) {
784                                                 Introspector argumentObject = obj.newIntrospectorInstanceOfProperty(property);
785                                                 Object result  = dbToObject(argumentObject, v, seen, depth+1, nodeOnly, cleanUp);
786                                                 if (result != null) {
787                                                         obj.setValue(property, argumentObject.getUnderlyingObject());
788                                                         modified = true;
789                                                 }
790                                         } else if (property.equals("relationship-list") && !nodeOnly){
791                                                 /* relationships need to be handled correctly */
792                                                 Introspector relationshipList = obj.newIntrospectorInstanceOfProperty(property);
793                                                 relationshipList = createRelationshipList(v, relationshipList, cleanUp);
794                                                 if (relationshipList != null) {
795                                                         modified = true;
796                                                         obj.setValue(property, relationshipList.getUnderlyingObject());
797                                                         modified = true;
798                                                 }
799                                                 
800                                         }
801                                 } else if (obj.isListType(property)) {
802                                         
803                                         if (property.equals("any")) {
804                                                 continue;
805                                         }
806                                         String genericType = obj.getGenericTypeClass(property).getSimpleName();
807                                         if (obj.isComplexGenericType(property) && depth >= 0) {
808                                                 final String childDbName = convertFromCamelCase(genericType);
809                                                 String vType = v.<String>property(AAIProperties.NODE_TYPE).orElse(null);
810                                                 EdgeRule rule;
811                                                 
812                                                 try {
813                                                         rule = edgeRules.getRule(new EdgeRuleQuery.Builder(vType, childDbName).edgeType(EdgeType.TREE).build());
814                                                 } catch (EdgeRuleNotFoundException e) {
815                                                         throw new NoEdgeRuleFoundException(e);
816                                                 } catch (AmbiguousRuleChoiceException e) {
817                                                         throw new MultipleEdgeRuleFoundException(e);
818                                                 }
819                                                 if (!rule.getContains().equals(AAIDirection.NONE.toString())) {
820                                                         //vertices = this.queryEngine.findRelatedVertices(v, Direction.OUT, rule.getLabel(), childDbName);
821                                                         Direction ruleDirection = rule.getDirection();
822                                                         Iterator<Vertex> itr = v.vertices(ruleDirection, rule.getLabel());
823                                                         List<Vertex> verticesList = (List<Vertex>)IteratorUtils.toList(itr);
824                                                         itr = verticesList.stream().filter(item -> {
825                                                                 return item.property(AAIProperties.NODE_TYPE).orElse("").equals(childDbName);
826                                                         }).iterator();
827                                                         if (itr.hasNext()) {
828                                                                 getList = (List<Object>)obj.getValue(property);
829                                                         }
830                                                         int processed = 0;
831                                                         int removed = 0;
832                                                         while (itr.hasNext()) {
833                                                                 Vertex childVertex = itr.next();
834                                                                 if (!seen.contains(childVertex)) {
835                                                                         Introspector argumentObject = obj.newIntrospectorInstanceOfNestedProperty(property);
836                                                                         
837                                                                         Object result = dbToObject(argumentObject, childVertex, seen, depth, nodeOnly, cleanUp);
838                                                                         if (result != null) {
839                                                                                 getList.add(argumentObject.getUnderlyingObject());
840                                                                         }
841                                                                         
842                                                                         processed++;
843                                                                 } else {
844                                                                         removed++;
845                                                                         LOGGER.warn("Cycle found while serializing vertex id={}", childVertex.id().toString());
846                                                                 }
847                                                         }
848                                                         if (processed == 0) {
849                                                                 //vertices were all seen, reset the list
850                                                                 getList = null;
851                                                         }
852                                                         if (processed > 0) {
853                                                                 modified = true;
854                                                         }
855                                                 }
856                                         } else if (obj.isSimpleGenericType(property)) {
857                                                 List<Object> temp = this.engine.getListProperty(v, property);
858                                                 if (temp != null) {
859                                                         getList = (List<Object>)obj.getValue(property);
860                                                         getList.addAll(temp);
861                                                         modified = true;
862                                                 }
863
864                                         }
865
866                                 }
867
868                         }
869                 }
870                 
871                 //no changes were made to this obj, discard the instance
872                 if (!modified) {
873                         return null;
874                 }
875                 this.enrichData(obj, v);
876                 return obj;
877                 
878         }
879         
880         
881         public Introspector getVertexProperties(Vertex v) throws AAIException, UnsupportedEncodingException {
882                 String nodeType = v.<String>property(AAIProperties.NODE_TYPE).orElse(null);
883                 if (nodeType == null) {
884                         throw new AAIException("AAI_6143");
885                 }
886                 
887                 Introspector obj = this.latestLoader.introspectorFromName(nodeType);
888                 Set<Vertex> seen = new HashSet<>();
889                 int depth = 0;
890                 String cleanUp = "false";
891                 boolean nodeOnly = true;
892                 StopWatch.conditionalStart();
893                 this.dbToObject(obj, v, seen, depth, nodeOnly, cleanUp);
894                 dbTimeMsecs += StopWatch.stopIfStarted();
895                 return obj;
896                 
897         }
898         public Introspector getLatestVersionView(Vertex v) throws AAIException, UnsupportedEncodingException {
899                 String nodeType = v.<String>property(AAIProperties.NODE_TYPE).orElse(null);
900                 if (nodeType == null) {
901                         throw new AAIException("AAI_6143");
902                 }
903                 Introspector obj = this.latestLoader.introspectorFromName(nodeType);
904                 Set<Vertex> seen = new HashSet<>();
905                 int depth = AAIProperties.MAXIMUM_DEPTH;
906                 String cleanUp = "false";
907                 boolean nodeOnly = false;
908                 StopWatch.conditionalStart();
909                 Tree<Element> tree = this.engine.getQueryEngine().findSubGraph(v, depth, nodeOnly);
910                 TreeBackedVertex treeVertex = new TreeBackedVertex(v, tree);
911                 this.dbToObject(obj, treeVertex, seen, depth, nodeOnly, cleanUp);
912                 dbTimeMsecs += StopWatch.stopIfStarted();
913                 return obj;
914         }
915         /**
916          * Copy simple property.
917          *
918          * @param property the property
919          * @param obj the obj
920          * @param v the v
921          * @throws InstantiationException the instantiation exception
922          * @throws IllegalAccessException the illegal access exception
923          * @throws IllegalArgumentException the illegal argument exception
924          * @throws InvocationTargetException the invocation target exception
925          * @throws NoSuchMethodException the no such method exception
926          * @throws SecurityException the security exception
927          */
928         private void copySimpleProperty(String property, Introspector obj, Vertex v) {
929
930                 final Map<PropertyMetadata, String> metadata = obj.getPropertyMetadata(property);
931                 String dbPropertyName = property;
932
933                 if (metadata.containsKey(PropertyMetadata.DB_ALIAS)) {
934                         dbPropertyName = metadata.get(PropertyMetadata.DB_ALIAS);
935                 }
936
937
938
939                 final Object temp = v.<Object>property(dbPropertyName).orElse(null);
940                 if (temp != null) {
941                         obj.setValue(property, temp);
942                 }
943         }
944         
945         /**
946          * Simple db to object.
947          *
948          * @param obj the obj
949          * @param v the v
950          * @throws InstantiationException the instantiation exception
951          * @throws IllegalAccessException the illegal access exception
952          * @throws IllegalArgumentException the illegal argument exception
953          * @throws InvocationTargetException the invocation target exception
954          * @throws NoSuchMethodException the no such method exception
955          * @throws SecurityException the security exception
956          */
957         private void simpleDbToObject (Introspector obj, Vertex v) {
958                 for (String property : obj.getProperties()) {
959                         
960
961                         if (!(obj.isComplexType(property) || obj.isListType(property))) {
962                                 this.copySimpleProperty(property, obj, v);
963                         }
964                 }
965         }
966         
967         /**
968          * Creates the relationship list.
969          *
970          * @param v the v
971          * @param obj the obj
972          * @param cleanUp the clean up
973          * @return the object
974          * @throws InstantiationException the instantiation exception
975          * @throws IllegalAccessException the illegal access exception
976          * @throws IllegalArgumentException the illegal argument exception
977          * @throws InvocationTargetException the invocation target exception
978          * @throws NoSuchMethodException the no such method exception
979          * @throws SecurityException the security exception
980          * @throws UnsupportedEncodingException the unsupported encoding exception
981          * @throws AAIException the AAI exception
982          * @throws MalformedURLException the malformed URL exception
983          * @throws URISyntaxException 
984          */
985         private Introspector createRelationshipList(Vertex v, Introspector obj, String cleanUp) throws UnsupportedEncodingException, AAIException {
986                 
987                 List<Vertex> cousins = this.engine.getQueryEngine().findCousinVertices(v);
988
989                 List<Object> relationshipObjList = obj.getValue("relationship");
990                 
991                 for (Vertex cousin : cousins) {
992                         if (obj.getVersion().compareTo(schemaVersions.getEdgeLabelVersion()) >= 0) {
993                                 List<Edge> edges = this.getEdgesBetween(EdgeType.COUSIN, v, cousin);
994                                 for (Edge e : edges) {
995                                         Introspector relationshipObj = obj.newIntrospectorInstanceOfNestedProperty("relationship");
996                                         Object result = processEdgeRelationship(relationshipObj, cousin, cleanUp, e);
997                                         if (result != null) {
998                                                 relationshipObjList.add(result);
999                                         }
1000                                 }
1001                         } else {
1002                                 Introspector relationshipObj = obj.newIntrospectorInstanceOfNestedProperty("relationship");
1003                                 Object result = processEdgeRelationship(relationshipObj, cousin, cleanUp, null);
1004                                 if (result != null) {
1005                                         relationshipObjList.add(result);
1006                                 }
1007                         }
1008
1009                 }
1010                 
1011                 if (relationshipObjList.isEmpty()) {
1012                         return null;
1013                 } else {
1014                         return obj;
1015                 }
1016         }
1017         
1018         /**
1019          * Process edge relationship.
1020          *
1021          * @param relationshipObj the relationship obj
1022          * @param edge the edge
1023          * @param cleanUp the clean up
1024          * @return the object
1025          * @throws InstantiationException the instantiation exception
1026          * @throws IllegalAccessException the illegal access exception
1027          * @throws IllegalArgumentException the illegal argument exception
1028          * @throws InvocationTargetException the invocation target exception
1029          * @throws NoSuchMethodException the no such method exception
1030          * @throws SecurityException the security exception
1031          * @throws UnsupportedEncodingException the unsupported encoding exception
1032          * @throws AAIException the AAI exception
1033          * @throws MalformedURLException the malformed URL exception
1034          * @throws AAIUnknownObjectException 
1035          * @throws URISyntaxException 
1036          */
1037         private Object processEdgeRelationship(Introspector relationshipObj, Vertex cousin, String cleanUp, Edge edge) throws UnsupportedEncodingException, AAIUnknownObjectException {
1038
1039
1040                 //we must look up all parents in this case because we need to compute name-properties
1041                 //we cannot used the cached aaiUri to perform this action currently
1042                 Optional<Pair<Vertex, List<Introspector>>> tuple = this.getParents(relationshipObj.getLoader(), cousin, "true".equals(cleanUp));
1043                 //damaged vertex found, ignore
1044                 if (!tuple.isPresent()) {
1045                         return null;
1046                 }
1047                 List<Introspector> list = tuple.get().getValue1();
1048                 URI uri = this.getURIFromList(list);
1049                 
1050                 URIToRelationshipObject uriParser = null;
1051                 Introspector result = null;
1052                 try {
1053                         uriParser = new URIToRelationshipObject(relationshipObj.getLoader(), uri, this.baseURL);
1054                         result = uriParser.getResult();
1055                 } catch (AAIException | URISyntaxException e) {
1056                         LOGGER.error("Error while processing edge relationship in version " + relationshipObj.getVersion() + " (bad vertex ID=" + tuple.get().getValue0().id().toString() + ": " 
1057                                         + e.getMessage() + " " + LogFormatTools.getStackTop(e));
1058                         if ("true".equals(cleanUp)) {
1059                                 this.deleteWithTraversal(tuple.get().getValue0());
1060                         }
1061                         return null;
1062                 }
1063                 if (!list.isEmpty()) {
1064                         this.addRelatedToProperty(result, list.get(0));
1065                 }
1066                 
1067                 if (edge != null && result.hasProperty("relationship-label")) {
1068                         result.setValue("relationship-label", edge.label());
1069                 }
1070                 
1071                 return result.getUnderlyingObject();
1072         }
1073         
1074         /**
1075          * Gets the URI for vertex.
1076          *
1077          * @param v the v
1078          * @return the URI for vertex
1079          * @throws InstantiationException the instantiation exception
1080          * @throws IllegalAccessException the illegal access exception
1081          * @throws IllegalArgumentException the illegal argument exception
1082          * @throws InvocationTargetException the invocation target exception
1083          * @throws NoSuchMethodException the no such method exception
1084          * @throws SecurityException the security exception
1085          * @throws UnsupportedEncodingException the unsupported encoding exception
1086          * @throws AAIUnknownObjectException 
1087          */
1088         public URI getURIForVertex(Vertex v) throws UnsupportedEncodingException {
1089                 
1090                 return getURIForVertex(v, false); 
1091         }
1092         
1093         public URI getURIForVertex(Vertex v, boolean overwrite) throws UnsupportedEncodingException {
1094                 URI uri = UriBuilder.fromPath("/unknown-uri").build();
1095                 
1096                 String aaiUri = v.<String>property(AAIProperties.AAI_URI).orElse(null);
1097                 
1098                 if (aaiUri != null && !overwrite) {
1099                         uri = UriBuilder.fromPath(aaiUri).build();
1100                 } else {
1101                         StopWatch.conditionalStart();
1102                         Optional<Pair<Vertex, List<Introspector>>> tuple = this.getParents(this.loader, v, false);
1103                         dbTimeMsecs += StopWatch.stopIfStarted();
1104                         if (tuple.isPresent()) {
1105                                 List<Introspector> list = tuple.get().getValue1();
1106                                 uri = this.getURIFromList(list);
1107                         }
1108                         
1109                         
1110                 }
1111                 return uri;
1112         }
1113         /**
1114          * Gets the URI from list.
1115          *
1116          * @param list the list
1117          * @return the URI from list
1118          * @throws UnsupportedEncodingException the unsupported encoding exception
1119          */
1120         private URI getURIFromList(List<Introspector> list) throws UnsupportedEncodingException {
1121                 String uri = "";
1122                 StringBuilder sb = new StringBuilder();
1123                 for (Introspector i : list) {
1124                         sb.insert(0, i.getURI());
1125                 }
1126                 
1127                 uri = sb.toString();
1128                 return UriBuilder.fromPath(uri).build();
1129         }
1130         
1131         /**
1132          * Gets the parents.
1133          *
1134          * @param start the start
1135          * @param removeDamaged the remove damaged
1136          * @return the parents
1137          * @throws InstantiationException the instantiation exception
1138          * @throws IllegalAccessException the illegal access exception
1139          * @throws IllegalArgumentException the illegal argument exception
1140          * @throws InvocationTargetException the invocation target exception
1141          * @throws NoSuchMethodException the no such method exception
1142          * @throws SecurityException the security exception
1143          * @throws AAIUnknownObjectException 
1144          */
1145         private Optional<Pair<Vertex, List<Introspector>>> getParents(Loader loader, Vertex start, boolean removeDamaged) {
1146                 
1147                 List<Vertex> results = this.engine.getQueryEngine().findParents(start);
1148                 List<Introspector> objs = new ArrayList<>();
1149                 boolean shortCircuit = false;
1150                 for (Vertex v : results) {
1151                         String nodeType = v.<String>property(AAIProperties.NODE_TYPE).orElse(null);
1152                         Introspector obj = null;
1153                         //vertex on the other end of this edge is bad
1154                         if (nodeType == null) {
1155                                 //log something here about what was found and that it was removed
1156                                 ErrorLogHelper.logError("AAI-6143", "Found a damaged parent vertex " + v.id().toString());
1157                                 if (removeDamaged) {
1158                                         this.deleteWithTraversal(v);
1159                                 }
1160                                 shortCircuit = true;
1161                         } else {
1162                                 try {
1163                                         obj = loader.introspectorFromName(nodeType);
1164                                 } catch (AAIUnknownObjectException e) {
1165                                         LOGGER.info("attempted to create node type " + nodeType + " but we do not understand it for version: " + loader.getVersion());
1166                                         obj = null;
1167                                 }
1168                         }
1169                         
1170                         if (obj == null) {
1171                                 //can't make a valid path because we don't understand this object
1172                                 // don't include it
1173                         } else {
1174                                 this.simpleDbToObject(obj, v);
1175                                 objs.add(obj);
1176                         }
1177                 }
1178                 
1179                 //stop processing and don't return anything for this bad vertex
1180                 if (shortCircuit) {
1181                         return Optional.empty();
1182                 }
1183                 
1184                 return Optional.of(new Pair<>(results.get(results.size()-1), objs));
1185         }
1186
1187         /**
1188          * Adds the r
1189          * @throws AAIUnknownObjectException 
1190          * @throws IllegalArgumentException elated to property.
1191          *
1192          * @param relationship the relationship
1193          * @param child the throws IllegalArgumentException, AAIUnknownObjectException child
1194          */
1195         public void addRelatedToProperty(Introspector relationship, Introspector child) throws AAIUnknownObjectException {
1196                 String nameProps = child.getMetadata(ObjectMetadata.NAME_PROPS);
1197                 List<Introspector> relatedToProperties = new ArrayList<>();
1198                 
1199                 if (nameProps != null) {
1200                         String[] props = nameProps.split(",");
1201                         for (String prop : props) {
1202                                 Introspector relatedTo = relationship.newIntrospectorInstanceOfNestedProperty("related-to-property");
1203                                 relatedTo.setValue("property-key", child.getDbName() + "." + prop);
1204                                 relatedTo.setValue("property-value", child.getValue(prop));
1205                                 relatedToProperties.add(relatedTo);
1206                         }
1207                 }
1208                 
1209                 if (!relatedToProperties.isEmpty()) {
1210                         List relatedToList = (List)relationship.getValue("related-to-property");
1211                         for (Introspector obj : relatedToProperties) {
1212                                 relatedToList.add(obj.getUnderlyingObject());
1213                         }
1214                 }
1215                 
1216         }
1217         
1218         /**
1219          * Creates the edge.
1220          *
1221          * @param relationship the relationship
1222          * @param inputVertex the input vertex
1223          * @return true, if successful
1224          * @throws UnsupportedEncodingException the unsupported encoding exception
1225          * @throws AAIException the AAI exception
1226          */
1227         public boolean createEdge(Introspector relationship, Vertex inputVertex) throws UnsupportedEncodingException, AAIException {
1228                 
1229                 Vertex relatedVertex = null;
1230                 StopWatch.conditionalStart();
1231                 QueryParser parser = engine.getQueryBuilder().createQueryFromRelationship(relationship);
1232                 
1233                 String label = null;
1234                 if (relationship.hasProperty("relationship-label")) {
1235                         label = relationship.getValue("relationship-label");
1236                 }
1237                 
1238                 List<Vertex> results = parser.getQueryBuilder().toList();
1239                 if (results.isEmpty()) {
1240                         dbTimeMsecs += StopWatch.stopIfStarted();
1241                         AAIException e = new AAIException("AAI_6129", "Node of type " + parser.getResultType() + ". Could not find object at: " + parser.getUri());
1242                         e.getTemplateVars().add(parser.getResultType());
1243                         e.getTemplateVars().add(parser.getUri().toString());
1244                         throw e;
1245                 } else { 
1246                         //still an issue if there's more than one
1247                         relatedVertex = results.get(0);
1248                 }
1249
1250                 if (relatedVertex != null) {
1251
1252                         Edge e;
1253                         try {
1254                                 e = this.getEdgeBetween(EdgeType.COUSIN, inputVertex, relatedVertex, label);
1255                                 if (e == null) {
1256                                         edgeSer.addEdge(this.engine.asAdmin().getTraversalSource(), inputVertex, relatedVertex, label);
1257                                 } else {
1258                                         //attempted to link two vertexes already linked
1259                                 }
1260                         } finally {
1261                                 dbTimeMsecs += StopWatch.stopIfStarted();
1262                         }
1263                 }
1264                 
1265                 dbTimeMsecs += StopWatch.stopIfStarted();
1266                 return true;
1267         }
1268         
1269         /**
1270          * Gets all the edges between of the type.
1271          *
1272          * @param aVertex the out vertex
1273          * @param bVertex the in vertex
1274          * @return the edges between
1275          * @throws AAIException the AAI exception
1276          * @throws NoEdgeRuleFoundException 
1277          */
1278         private List<Edge> getEdgesBetween(EdgeType type, Vertex aVertex, Vertex bVertex) {
1279                 
1280                 List<Edge> result = new ArrayList<>();
1281                 
1282                 if (bVertex != null) {
1283                         GraphTraversal<Vertex, Edge> findEdgesBetween = null;
1284                         findEdgesBetween = this.engine.asAdmin().getTraversalSource().V(aVertex).bothE();
1285                         if (EdgeType.TREE.equals(type)) {
1286                                 findEdgesBetween = findEdgesBetween
1287                                         .not(
1288                                                 __.or(
1289                                                         __.has(EdgeProperty.CONTAINS.toString(), "NONE"),
1290                                                         __.has(EdgeField.PRIVATE.toString(), true)
1291                                                 )
1292                                         );
1293                         } else {
1294                                 findEdgesBetween = findEdgesBetween
1295                                         .has(EdgeProperty.CONTAINS.toString(), "NONE")
1296                                         .not(
1297                                                 __.has(EdgeField.PRIVATE.toString(), true)
1298                                         );
1299                         }
1300                         findEdgesBetween = findEdgesBetween.filter(__.otherV().hasId(bVertex.id()));
1301                         result = findEdgesBetween.toList();
1302                 }
1303                 
1304                 return result;
1305         }
1306         /**
1307          * Gets all the edges between the vertexes with the label and type.
1308          *
1309          * @param aVertex the out vertex
1310          * @param bVertex the in vertex
1311          * @param label 
1312          * @return the edges between
1313          * @throws AAIException the AAI exception
1314          */
1315         private List<Edge> getEdgesBetween(EdgeType type, Vertex aVertex, Vertex bVertex, String label) throws AAIException {
1316                 
1317                 List<Edge> result = new ArrayList<>();
1318                 
1319                 if (bVertex != null) {
1320                         String aType = aVertex.<String>property(AAIProperties.NODE_TYPE).value();
1321                         String bType = bVertex.<String>property(AAIProperties.NODE_TYPE).value();
1322                         EdgeRuleQuery q = new EdgeRuleQuery.Builder(aType, bType).edgeType(type).label(label).build();
1323                         EdgeRule rule;
1324                         try {
1325                                 rule = edgeRules.getRule(q);
1326                         } catch (EdgeRuleNotFoundException e) {
1327                                 throw new NoEdgeRuleFoundException(e);
1328                         } catch (AmbiguousRuleChoiceException e) {
1329                                 throw new MultipleEdgeRuleFoundException(e);
1330                         }
1331                         List<Edge> edges = this.getEdgesBetween(type, aVertex, bVertex);
1332                         for (Edge edge : edges) {
1333                                 if (edge.label().equals(rule.getLabel())) {
1334                                         result.add(edge);
1335                                 }
1336                         }               
1337                 }
1338                 
1339                 return result;
1340         }
1341         
1342         /**
1343          * Gets the edge between with the label and edge type.
1344          *
1345          * @param aVertex the out vertex
1346          * @param bVertex the in vertex
1347          * @param label 
1348          * @return the edge between
1349          * @throws AAIException the AAI exception
1350          * @throws NoEdgeRuleFoundException 
1351          */
1352         public Edge getEdgeBetween(EdgeType type, Vertex aVertex, Vertex bVertex, String label) throws AAIException {
1353         
1354                 StopWatch.conditionalStart();
1355                 if (bVertex != null) {
1356
1357                                 List<Edge> edges = this.getEdgesBetween(type, aVertex, bVertex, label);
1358                                 
1359                                 if (!edges.isEmpty()) {
1360                                         dbTimeMsecs += StopWatch.stopIfStarted();
1361                                         return edges.get(0);
1362                                 }
1363
1364                 }
1365                 dbTimeMsecs += StopWatch.stopIfStarted();
1366                 return null;
1367         }
1368         public Edge getEdgeBetween(EdgeType type, Vertex aVertex, Vertex bVertex) throws AAIException {
1369                 return this.getEdgeBetween(type, aVertex, bVertex, null);
1370         }
1371         
1372
1373         /**
1374          * Delete edge.
1375          *
1376          * @param relationship the relationship
1377          * @param inputVertex the input vertex
1378          * @return true, if successful
1379          * @throws UnsupportedEncodingException the unsupported encoding exception
1380          * @throws AAIException the AAI exception
1381          */
1382         public boolean deleteEdge(Introspector relationship, Vertex inputVertex) throws UnsupportedEncodingException, AAIException {
1383                 
1384                 Vertex relatedVertex = null;
1385                 StopWatch.conditionalStart();
1386                 QueryParser parser = engine.getQueryBuilder().createQueryFromRelationship(relationship);
1387                 
1388                 List<Vertex> results = parser.getQueryBuilder().toList();
1389                 
1390                 String label = null;
1391                 if (relationship.hasProperty("relationship-label")) {
1392                         label = relationship.getValue("relationship-label");
1393                 }
1394
1395                 if (results.isEmpty()) {
1396                         dbTimeMsecs += StopWatch.stopIfStarted();
1397                         return false;
1398                 }
1399                 
1400                 relatedVertex = results.get(0);
1401                 Edge edge;
1402                 try {
1403                         edge = this.getEdgeBetween(EdgeType.COUSIN, inputVertex, relatedVertex, label);
1404                 } catch (NoEdgeRuleFoundException e) {
1405                         dbTimeMsecs += StopWatch.stopIfStarted();
1406                         throw new AAIException("AAI_6129", e);
1407                 }
1408                 if (edge != null) {
1409                         edge.remove();
1410                         dbTimeMsecs += StopWatch.stopIfStarted();
1411                         return true;
1412                 } else {
1413                         dbTimeMsecs += StopWatch.stopIfStarted();
1414                         return false;
1415                 }
1416                 
1417         }
1418         
1419         /**
1420          * Delete items with traversal.
1421          *
1422          * @param vertexes the vertexes
1423          * @throws IllegalStateException the illegal state exception
1424          */
1425         public void deleteItemsWithTraversal(List<Vertex> vertexes) throws IllegalStateException {
1426                 
1427                 for (Vertex v : vertexes) {
1428             LOGGER.debug("About to delete the vertex with id: " + v.id());
1429                         deleteWithTraversal(v);
1430                 }
1431                 
1432         }
1433         
1434         /**
1435          * Delete with traversal.
1436          *
1437          * @param startVertex the start vertex
1438          */
1439         public void deleteWithTraversal(Vertex startVertex) {
1440                 StopWatch.conditionalStart();
1441                 List<Vertex> results = this.engine.getQueryEngine().findDeletable(startVertex);
1442                 
1443                 for (Vertex v : results) {
1444                         LOGGER.warn("Removing vertex " + v.id().toString());
1445
1446                         v.remove();
1447                 }
1448                 dbTimeMsecs += StopWatch.stopIfStarted();
1449         }
1450
1451         /**
1452          * Delete.
1453          *
1454          * @param v the v
1455          * @param resourceVersion the resource version
1456          * @throws IllegalArgumentException the illegal argument exception
1457          * @throws AAIException the AAI exception
1458          * @throws InterruptedException the interrupted exception
1459          */
1460         public void delete(Vertex v, List<Vertex> deletableVertices, String resourceVersion, boolean enableResourceVersion) throws IllegalArgumentException, AAIException {
1461
1462                 boolean result = verifyDeleteSemantics(v, resourceVersion, enableResourceVersion);
1463                 /*
1464                  * The reason why I want to call PreventDeleteSemantics second time is to catch the prevent-deletes in a chain
1465                  * These are far-fewer than seeing a prevnt-delete on the vertex to be deleted
1466                  * So its better to make these in 2 steps
1467                  */
1468                 if(result && !deletableVertices.isEmpty()){
1469                         result = verifyPreventDeleteSemantics(deletableVertices);
1470                 }
1471                 if (result) {
1472
1473                         try {
1474                                 deleteWithTraversal(v);
1475                         } catch (IllegalStateException e) {
1476                                 throw new AAIException("AAI_6110", e);
1477                         }
1478
1479                 }
1480
1481         }
1482
1483
1484         /**
1485          * Delete.
1486          *
1487          * @param v the v
1488          * @param resourceVersion the resource version
1489          * @throws IllegalArgumentException the illegal argument exception
1490          * @throws AAIException the AAI exception
1491          * @throws InterruptedException the interrupted exception
1492          */
1493         public void delete(Vertex v, String resourceVersion, boolean enableResourceVersion) throws IllegalArgumentException, AAIException {
1494         
1495                 boolean result = verifyDeleteSemantics(v, resourceVersion, enableResourceVersion);
1496
1497                 if (result) {
1498
1499                         try {
1500                                 deleteWithTraversal(v);
1501                         } catch (IllegalStateException e) {
1502                                 throw new AAIException("AAI_6110", e);
1503                         }
1504
1505                 }
1506                 
1507         }
1508         /**
1509          * Verify delete semantics.
1510          *
1511          * @param vertex the vertex
1512          * @param resourceVersion the resource version
1513          * @return true, if successful
1514          * @throws AAIException the AAI exception
1515          */
1516         private boolean verifyDeleteSemantics(Vertex vertex, String resourceVersion, boolean enableResourceVersion) throws AAIException {
1517                 boolean result = true;
1518                 String nodeType = "";
1519                 String errorDetail = " unknown delete semantic found";
1520                 String aaiExceptionCode = "";
1521                 nodeType = vertex.<String>property(AAIProperties.NODE_TYPE).orElse(null);
1522                 if (enableResourceVersion && !this.verifyResourceVersion("delete", nodeType, vertex.<String>property(AAIProperties.RESOURCE_VERSION).orElse(null), resourceVersion, nodeType)) {
1523                 }
1524                 List<Vertex> vertices = new ArrayList<Vertex>();
1525                 vertices.add(vertex);
1526                 result = verifyPreventDeleteSemantics(vertices);
1527
1528                 return result;
1529         }
1530
1531         /**
1532          * Verify Prevent delete semantics.
1533          * @param vertices the list of vertices
1534          * @return true, if successful
1535          * @throws AAIException the AAI exception
1536          */
1537         private boolean verifyPreventDeleteSemantics(List<Vertex> vertices) throws AAIException {
1538                 boolean result = true;
1539                 String nodeType = "";
1540                 String errorDetail = " unknown delete semantic found";
1541                 String aaiExceptionCode = "";
1542
1543                 StopWatch.conditionalStart();
1544                 /*
1545                  * This takes in all the vertices in a cascade-delete-chain and checks if there is any edge with a "prevent-delete" condition
1546                  * If yes - that should prevent the deletion of the vertex
1547                  * Dedup makes sure we dont capture the prevent-delete vertices twice
1548                  * The prevent-delete vertices are stored so that the error message displays what prevents the delete
1549                  */
1550
1551                 List<Object> preventDeleteVertices = this.engine.asAdmin().getReadOnlyTraversalSource().V(vertices).
1552                                                                      union(__.inE().has(EdgeProperty.PREVENT_DELETE.toString(), AAIDirection.IN.toString()).outV().values(AAIProperties.NODE_TYPE),
1553                                                                            __.outE().has(EdgeProperty.PREVENT_DELETE.toString(), AAIDirection.OUT.toString()).inV().values(AAIProperties.NODE_TYPE))
1554                                                                      .dedup().toList();
1555                 
1556                 dbTimeMsecs += StopWatch.stopIfStarted();
1557                 if (!preventDeleteVertices.isEmpty()) {
1558                         aaiExceptionCode = "AAI_6110";
1559                         errorDetail = String.format("Object is being reference by additional objects preventing it from being deleted. Please clean up references from the following types %s", preventDeleteVertices);
1560                         result = false;
1561                 }
1562                 if (!result) {
1563                         throw new AAIException(aaiExceptionCode, errorDetail); 
1564                 }
1565                 return result;
1566         }
1567
1568         /**
1569          * Verify resource version.
1570          *
1571          * @param action the action
1572          * @param nodeType the node type
1573          * @param currentResourceVersion the current resource version
1574          * @param resourceVersion the resource version
1575          * @param uri the uri
1576          * @return true, if successful
1577          * @throws AAIException the AAI exception
1578          */
1579         public boolean verifyResourceVersion(String action, String nodeType, String currentResourceVersion, String resourceVersion, String uri) throws AAIException {
1580                 String enabled = "";
1581                 String errorDetail = "";
1582                 String aaiExceptionCode = "";
1583                 if (currentResourceVersion == null) {
1584                         currentResourceVersion = "";
1585                 }
1586                 
1587                 if (resourceVersion == null) {
1588                         resourceVersion = "";
1589                 }
1590                 try {
1591                         enabled = AAIConfig.get(AAIConstants.AAI_RESVERSION_ENABLEFLAG);
1592                 } catch (AAIException e) {
1593                         ErrorLogHelper.logException(e);
1594                 }
1595                 if (enabled.equals("true")) {
1596                         if (!currentResourceVersion.equals(resourceVersion)) {
1597                                 if (action.equals("create") && !resourceVersion.equals("")) {
1598                                         errorDetail = "resource-version passed for " + action + " of " + uri;
1599                                         aaiExceptionCode = "AAI_6135";
1600                                 } else if (resourceVersion.equals("")) {
1601                                         errorDetail = "resource-version not passed for " + action + " of " + uri;
1602                                         aaiExceptionCode = "AAI_6130";
1603                                 } else {
1604                                         errorDetail = "resource-version MISMATCH for " + action + " of " + uri;
1605                                         aaiExceptionCode = "AAI_6131";
1606                                 }
1607                                 
1608                                 throw new AAIException(aaiExceptionCode, errorDetail); 
1609                                 
1610                         }
1611                 }
1612                 return true;
1613         }
1614         
1615         /**
1616          * Convert from camel case.
1617          *
1618          * @param name the name
1619          * @return the string
1620          */
1621         private String convertFromCamelCase (String name) {
1622                 String result = "";
1623                 result = CaseFormat.UPPER_CAMEL.to(CaseFormat.LOWER_HYPHEN, name);
1624                 
1625                 NamingExceptions exceptions = NamingExceptions.getInstance();
1626                 result = exceptions.getDBName(result);
1627                 
1628                 return result;
1629         }
1630         
1631         private boolean canModify(Introspector obj, String propName, String requestContext) {
1632                 final String readOnly = obj.getPropertyMetadata(propName).get(PropertyMetadata.READ_ONLY);
1633                 if (readOnly != null) {
1634                         final String[] items = readOnly.split(",");
1635                         for (String item : items) {
1636                                 if (requestContext.equals(item)) {
1637                                         return false;
1638                                 }
1639                         }
1640                 }
1641                 return true;
1642         }
1643         
1644         private void executePreSideEffects(Introspector obj, Vertex self) throws AAIException {
1645                 
1646                 SideEffectRunner runner = new SideEffectRunner
1647                                 .Builder(this.engine, this).addSideEffect(DataCopy.class).addSideEffect(PrivateEdge.class).build();
1648                 
1649                 runner.execute(obj, self);
1650         }
1651         
1652         private void executePostSideEffects(Introspector obj, Vertex self) throws AAIException {
1653                 
1654                 SideEffectRunner runner = new SideEffectRunner
1655                                 .Builder(this.engine, this).addSideEffect(DataLinkWriter.class).build();
1656                 
1657                 runner.execute(obj, self);
1658         }
1659         
1660         private void enrichData(Introspector obj, Vertex self) throws AAIException  {
1661                 
1662                 SideEffectRunner runner = new SideEffectRunner
1663                                 .Builder(this.engine, this).addSideEffect(DataLinkReader.class).build();
1664                 
1665                 runner.execute(obj, self);
1666         }
1667
1668         public double getDBTimeMsecs() {
1669                 return (dbTimeMsecs);
1670         }
1671         
1672         /**
1673           * Db to object With Filters 
1674           * This is for a one-time run with Tenant Isloation to only filter relationships 
1675           * TODO: Chnage the original dbToObject to take filter parent/cousins 
1676           *
1677           * @param obj the obj
1678           * @param v the vertex from the graph
1679           * @param depth the depth
1680           * @param nodeOnly specify if to exclude relationships or not
1681           * @param filterCousinNodes
1682           * @return the introspector
1683           * @throws AAIException the AAI exception
1684           * @throws IllegalAccessException the illegal access exception
1685           * @throws IllegalArgumentException the illegal argument exception
1686           * @throws InvocationTargetException the invocation target exception
1687           * @throws SecurityException the security exception
1688           * @throws InstantiationException the instantiation exception
1689           * @throws NoSuchMethodException the no such method exception
1690           * @throws UnsupportedEncodingException the unsupported encoding exception
1691           * @throws MalformedURLException the malformed URL exception
1692          * @throws AAIUnknownObjectException 
1693          * @throws URISyntaxException 
1694           */
1695          //TODO - See if you can merge the 2 dbToObjectWithFilters
1696          public Introspector dbToObjectWithFilters(Introspector obj, Vertex v, Set<Vertex> seen, int depth, boolean nodeOnly,  List<String> filterCousinNodes, List<String> filterParentNodes) throws AAIException, UnsupportedEncodingException {
1697                         String cleanUp = "false";
1698                         if (depth < 0) {
1699                                 return null;
1700                         }
1701                         depth--;
1702                         seen.add(v);
1703                         boolean modified = false;
1704                         for (String property : obj.getProperties(PropertyPredicates.isVisible())) {
1705                                 List<Object> getList = null;
1706                                 Vertex[] vertices = null;
1707
1708                                 if (!(obj.isComplexType(property) || obj.isListType(property))) {
1709                                         this.copySimpleProperty(property, obj, v);
1710                                         modified = true;
1711                                 } else {
1712                                         if (obj.isComplexType(property)) {
1713                                         /* container case */
1714                 
1715                                                 if (!property.equals("relationship-list") && depth >= 0) {
1716                                                         Introspector argumentObject = obj.newIntrospectorInstanceOfProperty(property);
1717                                                         Object result  = dbToObjectWithFilters(argumentObject, v, seen, depth+1, nodeOnly,  filterCousinNodes, filterParentNodes);
1718                                                         if (result != null) {
1719                                                                 obj.setValue(property, argumentObject.getUnderlyingObject());
1720                                                                 modified = true;
1721                                                         }
1722                                                 } else if (property.equals("relationship-list") && !nodeOnly){
1723                                                         /* relationships need to be handled correctly */
1724                                                         Introspector relationshipList = obj.newIntrospectorInstanceOfProperty(property);
1725                                                         relationshipList = createFilteredRelationshipList(v, relationshipList, cleanUp, filterCousinNodes);
1726                                                         if (relationshipList != null) {
1727                                                                 modified = true;
1728                                                                 obj.setValue(property, relationshipList.getUnderlyingObject());
1729                                                                 modified = true;
1730                                                         }
1731                                                         
1732                                                 }
1733                                         } else if (obj.isListType(property)) {
1734                                                 
1735                                                 if (property.equals("any")) {
1736                                                         continue;
1737                                                 }
1738                                                 String genericType = obj.getGenericTypeClass(property).getSimpleName();
1739                                                 if (obj.isComplexGenericType(property) && depth >= 0) {
1740                                                         final String childDbName = convertFromCamelCase(genericType);
1741                                                         String vType = v.<String>property(AAIProperties.NODE_TYPE).orElse(null);
1742                                                         EdgeRule rule;
1743                                                         
1744                                                         boolean isthisParentRequired = filterParentNodes.parallelStream().anyMatch(childDbName::contains);
1745                                                         
1746                                                         EdgeRuleQuery q = new EdgeRuleQuery.Builder(vType, childDbName).edgeType(EdgeType.TREE).build();
1747
1748                                                         try {
1749                                                                 rule = edgeRules.getRule(q);
1750                                                         } catch (EdgeRuleNotFoundException e) {
1751                                                                 throw new NoEdgeRuleFoundException(e);
1752                                                         } catch (AmbiguousRuleChoiceException e) {
1753                                                                 throw new MultipleEdgeRuleFoundException(e);
1754                                                         }
1755                                                         if (!rule.getContains().equals(AAIDirection.NONE.toString()) && isthisParentRequired) {
1756                                                                 //vertices = this.queryEngine.findRelatedVertices(v, Direction.OUT, rule.getLabel(), childDbName);
1757                                                                 Direction ruleDirection = rule.getDirection();
1758                                                                 Iterator<Vertex> itr = v.vertices(ruleDirection, rule.getLabel());
1759                                                                 List<Vertex> verticesList = (List<Vertex>)IteratorUtils.toList(itr);
1760                                                                 itr = verticesList.stream().filter(item -> {
1761                                                                         return item.property(AAIProperties.NODE_TYPE).orElse("").equals(childDbName);
1762                                                                 }).iterator();
1763                                                                 if (itr.hasNext()) {
1764                                                                         getList = (List<Object>)obj.getValue(property);
1765                                                                 }
1766                                                                 int processed = 0;
1767                                                                 int removed = 0;
1768                                                                 while (itr.hasNext()) {
1769                                                                         Vertex childVertex = itr.next();
1770                                                                         if (!seen.contains(childVertex)) {
1771                                                                                 Introspector argumentObject = obj.newIntrospectorInstanceOfNestedProperty(property);
1772                                                                                 
1773                                                                                 Object result = dbToObjectWithFilters(argumentObject, childVertex, seen, depth, nodeOnly, filterCousinNodes, filterParentNodes);
1774                                                                                 if (result != null) {
1775                                                                                         getList.add(argumentObject.getUnderlyingObject());
1776                                                                                 }
1777                                                                                 
1778                                                                                 processed++;
1779                                                                         } else {
1780                                                                                 removed++;
1781                                                                                 LOGGER.warn("Cycle found while serializing vertex id={}", childVertex.id().toString());
1782                                                                         }
1783                                                                 }
1784                                                                 if (processed == 0) {
1785                                                                         //vertices were all seen, reset the list
1786                                                                         getList = null;
1787                                                                 }
1788                                                                 if (processed > 0) {
1789                                                                         modified = true;
1790                                                                 }
1791                                                         }
1792                                                 } else if (obj.isSimpleGenericType(property)) {
1793                                                         List<Object> temp = this.engine.getListProperty(v, property);
1794                                                         if (temp != null) {
1795                                                                 getList = (List<Object>)obj.getValue(property);
1796                                                                 getList.addAll(temp);
1797                                                                 modified = true;
1798                                                         }
1799
1800                                                 }
1801
1802                                         }
1803
1804                                 }
1805                         }
1806                         
1807                         //no changes were made to this obj, discard the instance
1808                         if (!modified) {
1809                                 return null;
1810                         }
1811                         this.enrichData(obj, v);
1812                         return obj;
1813                         
1814                 }
1815          
1816          /**
1817                  * Creates the relationship list with the filtered node types.
1818                  *
1819                  * @param v the v
1820                  * @param obj the obj
1821                  * @param cleanUp the clean up
1822                  * @return the object
1823                  * @throws InstantiationException the instantiation exception
1824                  * @throws IllegalAccessException the illegal access exception
1825                  * @throws IllegalArgumentException the illegal argument exception
1826                  * @throws InvocationTargetException the invocation target exception
1827                  * @throws NoSuchMethodException the no such method exception
1828                  * @throws SecurityException the security exception
1829                  * @throws UnsupportedEncodingException the unsupported encoding exception
1830                  * @throws AAIException the AAI exception
1831                  * @throws MalformedURLException the malformed URL exception
1832                  * @throws URISyntaxException 
1833                  */
1834                 private Introspector createFilteredRelationshipList(Vertex v, Introspector obj, String cleanUp, List<String> filterNodes) throws UnsupportedEncodingException, AAIException {
1835                         List<Vertex> allCousins = this.engine.getQueryEngine().findCousinVertices(v);
1836                         
1837                         Iterator<Vertex> cousinVertices = allCousins.stream().filter(item -> {
1838                                 String node = (String)item.property(AAIProperties.NODE_TYPE).orElse("");
1839                                 return filterNodes.parallelStream().anyMatch(node::contains);
1840                         }).iterator();
1841                         
1842                         
1843                         List<Vertex> cousins = (List<Vertex>)IteratorUtils.toList(cousinVertices);
1844                         
1845                         //items.parallelStream().anyMatch(inputStr::contains)
1846                         List<Object> relationshipObjList = obj.getValue("relationship");
1847                         for (Vertex cousin : cousins) {
1848                                 
1849                                         Introspector relationshipObj = obj.newIntrospectorInstanceOfNestedProperty("relationship");
1850                                         Object result = processEdgeRelationship(relationshipObj, cousin, cleanUp, null);
1851                                         if (result != null) {
1852                                                 relationshipObjList.add(result);
1853                                         }
1854                                 
1855
1856                         }
1857                         
1858                         if (relationshipObjList.isEmpty()) {
1859                                 return null;
1860                         } else {
1861                                 return obj;
1862                         }
1863                 }
1864
1865 }