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