8156dd09bb18b693af940619bb589ef5c1bd0d5c
[aai/aai-common.git] / aai-core / src / main / java / org / onap / aai / query / builder / GraphTraversalBuilder.java
1 /**
2  * ============LICENSE_START=======================================================
3  * org.onap.aai
4  * ================================================================================
5  * Copyright © 2017 AT&T Intellectual Property. All rights reserved.
6  * ================================================================================
7  * Licensed under the Apache License, Version 2.0 (the "License");
8  * you may not use this file except in compliance with the License.
9  * You may obtain a copy of the License at
10  *
11  *    http://www.apache.org/licenses/LICENSE-2.0
12  *
13  * Unless required by applicable law or agreed to in writing, software
14  * distributed under the License is distributed on an "AS IS" BASIS,
15  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16  * See the License for the specific language governing permissions and
17  * limitations under the License.
18  * ============LICENSE_END=========================================================
19  *
20  * ECOMP is a trademark and service mark of AT&T Intellectual Property.
21  */
22 package org.onap.aai.query.builder;
23
24 import java.util.ArrayList;
25 import java.util.List;
26 import java.util.Map;
27 import java.util.Optional;
28 import java.util.Set;
29
30 import org.apache.tinkerpop.gremlin.process.traversal.P;
31 import org.apache.tinkerpop.gremlin.process.traversal.Traversal;
32 import org.apache.tinkerpop.gremlin.process.traversal.Traversal.Admin;
33 import org.apache.tinkerpop.gremlin.process.traversal.dsl.graph.GraphTraversal;
34 import org.apache.tinkerpop.gremlin.process.traversal.dsl.graph.GraphTraversalSource;
35 import org.apache.tinkerpop.gremlin.process.traversal.dsl.graph.__;
36 import org.apache.tinkerpop.gremlin.process.traversal.util.TraversalHelper;
37 import org.apache.tinkerpop.gremlin.structure.Direction;
38 import org.apache.tinkerpop.gremlin.structure.Edge;
39 import org.apache.tinkerpop.gremlin.structure.Vertex;
40 import org.onap.aai.db.props.AAIProperties;
41 import org.onap.aai.exceptions.AAIException;
42 import org.onap.aai.introspection.Introspector;
43 import org.onap.aai.introspection.Loader;
44 import org.onap.aai.schema.enums.ObjectMetadata;
45 import org.onap.aai.schema.enums.PropertyMetadata;
46 import org.onap.aai.serialization.db.EdgeRule;
47 import org.onap.aai.serialization.db.EdgeRules;
48 import org.onap.aai.serialization.db.EdgeType;
49 import org.onap.aai.serialization.db.exceptions.NoEdgeRuleFoundException;
50
51 /**
52  * The Class GraphTraversalBuilder.
53  */
54 public abstract class GraphTraversalBuilder<E> extends QueryBuilder<E> {
55
56         protected GraphTraversal<Vertex, E> traversal = null;
57         protected Admin<Vertex, E> completeTraversal = null;
58         private EdgeRules edgeRules = EdgeRules.getInstance();
59         
60         protected int parentStepIndex = 0;
61         protected int containerStepIndex = 0;
62         protected int stepIndex = 0;
63         
64         /**
65          * Instantiates a new graph traversal builder.
66          *
67          * @param loader the loader
68          */
69         public GraphTraversalBuilder(Loader loader, GraphTraversalSource source) {
70                 super(loader, source);
71                 
72                 traversal = (GraphTraversal<Vertex, E>) __.<E>start();
73                 
74         }
75         
76         /**
77          * Instantiates a new graph traversal builder.
78          *
79          * @param loader the loader
80          */
81         public GraphTraversalBuilder(Loader loader, GraphTraversalSource source, EdgeRules edgeRules) {
82                 super(loader, source);
83                 this.edgeRules = edgeRules;
84                 traversal = (GraphTraversal<Vertex, E>) __.<E>start();
85                 
86         }
87         
88         /**
89          * Instantiates a new graph traversal builder.
90          *
91          * @param loader the loader
92          * @param start the start
93          */
94         public GraphTraversalBuilder(Loader loader, GraphTraversalSource source, Vertex start) {
95                 super(loader, source, start);
96                 
97                 traversal = (GraphTraversal<Vertex, E>) __.__(start);
98                 
99         }
100         
101         /**
102          * Instantiates a new graph traversal builder.
103          *
104          * @param loader the loader
105          * @param start the start
106          */
107         public GraphTraversalBuilder(Loader loader, GraphTraversalSource source, Vertex start, EdgeRules edgeRules) {
108                 super(loader, source, start);
109                 this.edgeRules = edgeRules;
110                 traversal = (GraphTraversal<Vertex, E>) __.__(start);
111                 
112         }
113
114         /**
115          * @{inheritDoc}
116          */
117         @Override
118         public QueryBuilder<Vertex> getVerticesByProperty(String key, Object value) {
119                 
120                 // correct value call because the index is registered as an Integer
121                 traversal.has(key, this.correctObjectType(value));
122                 
123                 stepIndex++;
124                 return (QueryBuilder<Vertex>) this;
125         }
126         
127         /**
128          * @{inheritDoc}
129          */
130         @Override
131         public QueryBuilder<Vertex> getVerticesByProperty(final String key, final List<?> values) {
132                 
133                 //this is because the index is registered as an Integer
134                 List<Object> correctedValues = new ArrayList<>();
135                 for (Object item : values) {
136                         correctedValues.add(this.correctObjectType(item));
137                 }
138                 
139                 traversal.has(key, P.within(correctedValues));
140                 
141                 stepIndex++;
142                 return (QueryBuilder<Vertex>) this;
143         }
144         
145         /**
146          * @{inheritDoc}
147          */
148         @Override
149         public QueryBuilder<Vertex> getVerticesExcludeByProperty(String key, Object value) {
150                 
151                 // correct value call because the index is registered as an Integer
152                 traversal.has(key, P.neq(this.correctObjectType(value)));
153                 
154                 stepIndex++;
155                 return (QueryBuilder<Vertex>) this;
156         }
157         
158         /**
159          * @{inheritDoc}
160          */
161         @Override
162         public QueryBuilder<Vertex> getVerticesExcludeByProperty(final String key, final List<?> values) {
163                 
164                 //this is because the index is registered as an Integer
165                 List<Object> correctedValues = new ArrayList<>();
166                 for (Object item : values) {
167                         correctedValues.add(this.correctObjectType(item));
168                 }
169                 
170                 traversal.has(key, P.without(correctedValues));
171                 
172                 stepIndex++;
173                 return (QueryBuilder<Vertex>) this;
174         }
175
176         /**
177          * @{inheritDoc}
178          */
179         @Override
180         public QueryBuilder<Vertex> getChildVerticesFromParent(String parentKey, String parentValue, String childType) {
181                 traversal.has(parentKey, parentValue).has(AAIProperties.NODE_TYPE, childType);
182                 stepIndex++;
183                 return (QueryBuilder<Vertex>) this;
184         }
185
186         /**
187          * @{inheritDoc}
188          */
189         @Override
190         public QueryBuilder<Vertex> getTypedVerticesByMap(String type, Map<String, String> map) {
191                 
192                 for (Map.Entry<String, String> es : map.entrySet()) {
193                         traversal.has(es.getKey(), es.getValue());
194                         stepIndex++;
195                 }
196                 traversal.has(AAIProperties.NODE_TYPE, type);
197                 stepIndex++;
198                 return (QueryBuilder<Vertex>) this;
199         }
200
201         /**
202          * @{inheritDoc}
203          */
204         @Override
205         public QueryBuilder<Vertex> createKeyQuery(Introspector obj) {
206                 Set<String> keys = obj.getKeys();
207                 Object val;
208                 for (String key : keys) {
209                         val = obj.getValue(key);
210                         Optional<String> metadata = obj.getPropertyMetadata(key, PropertyMetadata.DB_ALIAS);
211                         if (metadata.isPresent()) {
212                                 //use the db name for the field rather than the object model
213                                 key = metadata.get();
214                         }
215                         if (val != null) {
216                                 //this is because the index is registered as an Integer
217                                 if (val.getClass().equals(Long.class)) {
218                                         traversal.has(key,new Integer(val.toString()));
219                                 } else {
220                                         traversal.has(key, val);
221                                 }
222                                 stepIndex++;
223                         }
224                 }
225                 return (QueryBuilder<Vertex>) this;
226         }
227
228         @Override
229         public QueryBuilder<Vertex> exactMatchQuery(Introspector obj) {
230                 this.createKeyQuery(obj);
231                 allPropertiesQuery(obj);
232                 this.createContainerQuery(obj);
233                 return (QueryBuilder<Vertex>) this;
234         }
235         
236         private void allPropertiesQuery(Introspector obj) {
237                 Set<String> props = obj.getProperties();
238                 Set<String> keys = obj.getKeys();
239                 Object val;
240                 for (String prop : props) {
241                         if (obj.isSimpleType(prop) && !keys.contains(prop)) {
242                                 val = obj.getValue(prop);
243                                 if (val != null) {
244                                         Optional<String> metadata = obj.getPropertyMetadata(prop, PropertyMetadata.DB_ALIAS);
245                                         if (metadata.isPresent()) {
246                                                 //use the db name for the field rather than the object model
247                                                 prop = metadata.get();
248                                         }
249                                         //this is because the index is registered as an Integer
250                                         if (val.getClass().equals(Long.class)) {
251                                                 traversal.has(prop,new Integer(val.toString()));
252                                         } else {
253                                                 traversal.has(prop, val);
254                                         }
255                                         stepIndex++;
256                                 }
257                         }
258                 }
259         }
260         
261         /**
262          * @{inheritDoc}
263          */
264         @Override
265         
266         public QueryBuilder<Vertex> createContainerQuery(Introspector obj) {
267                 String type = obj.getChildDBName();
268                 String abstractType = obj.getMetadata(ObjectMetadata.ABSTRACT);
269                 if (abstractType != null) {
270                         String[] inheritors = obj.getMetadata(ObjectMetadata.INHERITORS).split(",");
271                         traversal.has(AAIProperties.NODE_TYPE, P.within(inheritors));
272                 } else {
273                         traversal.has(AAIProperties.NODE_TYPE, type);
274                 }
275                 stepIndex++;
276                 markContainer();
277                 return (QueryBuilder<Vertex>) this;
278         }
279
280         /**
281          * @throws NoEdgeRuleFoundException 
282          * @throws AAIException 
283          * @{inheritDoc}
284          */
285         @Override
286         public QueryBuilder<Vertex> createEdgeTraversal(EdgeType type, Introspector parent, Introspector child) throws AAIException {
287                 String isAbstractType = parent.getMetadata(ObjectMetadata.ABSTRACT);
288                 if ("true".equals(isAbstractType)) {
289                         markParentBoundary();
290                         traversal.union(handleAbstractEdge(type, parent, child));
291                         stepIndex++;
292                 } else {
293                         this.edgeQueryToVertex(type, parent, child, null);
294                 }
295                 return (QueryBuilder<Vertex>) this;
296                         
297         }
298
299         /**
300          *
301          * @{inheritDoc}
302          */
303         @Override
304         public QueryBuilder<Vertex> createEdgeTraversalWithLabels(EdgeType type, Introspector out, Introspector in, List<String> labels) throws AAIException {
305                 this.edgeQueryToVertex(type, out, in, labels);
306                 return (QueryBuilder<Vertex>) this;
307         }
308
309
310         private Traversal<Vertex, Vertex>[] handleAbstractEdge(EdgeType type, Introspector abstractParent, Introspector child) throws AAIException, NoEdgeRuleFoundException {
311                 String childName = child.getDbName();
312                 String inheritorMetadata = abstractParent.getMetadata(ObjectMetadata.INHERITORS);
313                 String[] inheritors = inheritorMetadata.split(",");
314                 List<Traversal<Vertex, Vertex>> unionTraversals = new ArrayList<>(inheritors.length);
315
316                 for (int i = 0; i < inheritors.length; i++) {
317                         String inheritor = inheritors[i];
318                         if (edgeRules.hasEdgeRule(inheritor, childName) || edgeRules.hasEdgeRule(childName, inheritor)) {
319                                 Map<String, EdgeRule> rules = edgeRules.getEdgeRules(type, inheritor, childName);
320                                 GraphTraversal<Vertex, Vertex> innerTraversal = __.start();
321                                 
322                                 final List<String> inLabels = new ArrayList<>();
323                                 final List<String> outLabels = new ArrayList<>();
324
325                                 rules.forEach((k,v) -> {
326                                         if (v.getDirection().equals(Direction.IN)) {
327                                                 inLabels.add(k);
328                                         } else {
329                                                 outLabels.add(k);
330                                         }
331                                 } );
332                 
333                                 if (inLabels.isEmpty() && !outLabels.isEmpty()) {
334                                         innerTraversal.out(outLabels.toArray(new String[outLabels.size()]));
335                                 } else if (outLabels.isEmpty() && !inLabels.isEmpty()) {
336                                         innerTraversal.in(inLabels.toArray(new String[inLabels.size()]));
337                                 } else {                                
338                                         innerTraversal.union(__.out(outLabels.toArray(new String[outLabels.size()])), __.in(inLabels.toArray(new String[inLabels.size()])));
339                                 }
340                                 
341                                 innerTraversal.has(AAIProperties.NODE_TYPE, childName);
342                                 unionTraversals.add(innerTraversal);
343                         }
344                 }
345                 
346                 return unionTraversals.toArray(new Traversal[unionTraversals.size()]);
347         }
348
349         public QueryBuilder<Edge> getEdgesBetweenWithLabels(EdgeType type, String outNodeType, String inNodeType, List<String> labels) throws AAIException {
350                 Introspector outObj = loader.introspectorFromName(outNodeType);
351                 Introspector inObj = loader.introspectorFromName(inNodeType);
352                 this.edgeQuery(type, outObj, inObj, labels);
353
354                 return (QueryBuilder<Edge>)this;
355         }
356
357
358         /**
359          * @{inheritDoc}
360          */
361         @Override
362         public QueryBuilder<E> union(QueryBuilder... builder) {
363                 GraphTraversal<Vertex, Vertex>[] traversals = new GraphTraversal[builder.length];
364                 for (int i = 0; i < builder.length; i++) {
365                         traversals[i] = (GraphTraversal<Vertex, Vertex>)builder[i].getQuery();
366                 }
367                 this.traversal.union(traversals);
368                 stepIndex++;
369                 
370                 return this;
371         }
372         
373         /**
374          * @{inheritDoc}
375          */
376         @Override
377         public QueryBuilder<E> where(QueryBuilder... builder) {
378                 GraphTraversal<Vertex, Vertex>[] traversals = new GraphTraversal[builder.length];
379                 for (int i = 0; i < builder.length; i++) {
380                         this.traversal.where((GraphTraversal<Vertex, Vertex>)builder[i].getQuery());
381                         stepIndex++;
382                 }
383                 
384                 return this;
385         }
386         
387         @Override
388         public QueryBuilder<E> store(String name) {
389                 
390                 this.traversal.store(name);
391                 stepIndex++;
392                 
393                 return this;
394         }
395         
396         @Override
397         public QueryBuilder<E> cap(String name) {
398                 this.traversal.cap(name);
399                 stepIndex++;
400                 
401                 return this;
402         }
403         
404         @Override
405         public QueryBuilder<E> unfold() {
406                 this.traversal.unfold();
407                 stepIndex++;
408                         
409                 return this;
410         }
411         
412         @Override
413         public QueryBuilder<E> dedup() {
414                 
415                 this.traversal.dedup();
416                 stepIndex++;
417                 
418                 return this;
419         }
420         
421         @Override
422         public QueryBuilder<E> emit() {
423                 
424                 this.traversal.emit();
425                 stepIndex++;
426                 
427                 return this;
428                 
429         }
430         
431         @Override
432         public QueryBuilder<E> repeat(QueryBuilder<E> builder) {
433                 
434                 this.traversal.repeat((GraphTraversal<Vertex, E>)builder.getQuery());
435                 stepIndex++;
436
437                 return this;
438         }
439         
440         @Override
441         public QueryBuilder<E> until(QueryBuilder<E> builder) {
442                 this.traversal.until((GraphTraversal<Vertex,E>)builder.getQuery());
443                 stepIndex++;
444                 
445                 return this;
446         }
447         
448         @Override
449         public QueryBuilder<E> groupCount() {
450                 this.traversal.groupCount();
451                 stepIndex++;
452                 
453                 return this;
454         }
455         
456         @Override
457         public QueryBuilder<E> both() {
458                 this.traversal.both();
459                 stepIndex++;
460                 
461                 return this;
462         }
463         
464         @Override
465         public QueryBuilder<E> by(String name) {
466                 this.traversal.by(name);
467                 stepIndex++;
468                 
469                 return this;
470         }
471         
472         /**
473          * {@inheritDoc}
474          */
475         @Override
476         public QueryBuilder<E> simplePath(){
477                 this.traversal.simplePath();
478                 stepIndex++;
479                 return this;
480         }
481         
482         @Override
483         public QueryBuilder<Edge> outE() {
484                 this.traversal.outE();
485                 stepIndex++;
486                 return (QueryBuilder<Edge>)this;
487         }
488         
489         @Override
490         public QueryBuilder<Edge> inE() {
491                 this.traversal.inE();
492                 stepIndex++;
493                 return (QueryBuilder<Edge>)this;
494         }
495         
496         @Override
497         public QueryBuilder<Vertex> outV() {
498                 this.traversal.outV();
499                 stepIndex++;
500                 return (QueryBuilder<Vertex>)this;
501         }
502         
503         @Override
504         public QueryBuilder<Vertex> inV() {
505                 this.traversal.inV();
506                 stepIndex++;
507                 return (QueryBuilder<Vertex>)this;
508         }
509         
510         @Override
511         public QueryBuilder<E> as(String name) {
512                 this.traversal.as(name);
513                 
514                 stepIndex++;
515                 return this;
516         }
517         
518         @Override
519         public QueryBuilder<E> not(QueryBuilder<E> builder) {
520                 this.traversal.not(builder.getQuery());
521                 
522                 stepIndex++;
523                 return this;
524         }
525         
526         @Override
527         public QueryBuilder<E> select(String name) {
528                 this.traversal.select(name);
529                 
530                 stepIndex++;
531                 
532                 return this;
533         }
534         
535         /**
536          * Edge query.
537          *
538          * @param outObj the out type
539          * @param inObj the in type
540          * @throws NoEdgeRuleFoundException 
541          * @throws AAIException 
542          */
543         private void edgeQueryToVertex(EdgeType type, Introspector outObj, Introspector inObj, List<String> labels) throws AAIException {
544                 String outType = outObj.getDbName();
545                 String inType = inObj.getDbName();
546                 
547                 if (outObj.isContainer()) {
548                         outType = outObj.getChildDBName();
549                 }
550                 if (inObj.isContainer()) {
551                         inType = inObj.getChildDBName();
552                 }
553                 markParentBoundary();
554                 Map<String, EdgeRule> rules;
555                 if (labels == null) {
556                         rules = edgeRules.getEdgeRules(type, outType, inType);
557                 } else {
558                         rules = edgeRules.getEdgeRulesWithLabels(type, outType, inType, labels);
559                 }
560                 
561                 final List<String> inLabels = new ArrayList<>();
562                 final List<String> outLabels = new ArrayList<>();
563
564                 rules.forEach((k, edgeRule) -> {
565                         if (labels != null && !labels.contains(k)) {
566                                 return;
567                         } else {
568                                 if (edgeRule.getDirection().equals(Direction.IN)) {
569                                         inLabels.add(edgeRule.getLabel());
570                                 } else {
571                                         outLabels.add(edgeRule.getLabel());
572                                 }
573                         }
574                 });
575
576                 if (inLabels.isEmpty() && !outLabels.isEmpty()) {
577                         traversal.out(outLabels.toArray(new String[outLabels.size()]));
578                 } else if (outLabels.isEmpty() && !inLabels.isEmpty()) {
579                         traversal.in(inLabels.toArray(new String[inLabels.size()]));
580                 } else {                                
581                         traversal.union(__.out(outLabels.toArray(new String[outLabels.size()])), __.in(inLabels.toArray(new String[inLabels.size()])));
582                 }
583                 
584                 stepIndex++;
585
586                 this.createContainerQuery(inObj);
587                 
588         }
589         
590         /**
591          * Edge query.
592          *
593          * @param outObj the out type
594          * @param inObj the in type
595          * @throws NoEdgeRuleFoundException 
596          * @throws AAIException 
597          */
598         private void edgeQuery(EdgeType type, Introspector outObj, Introspector inObj, List<String> labels) throws AAIException {
599                 String outType = outObj.getDbName();
600                 String inType = inObj.getDbName();
601                 
602                 if (outObj.isContainer()) {
603                         outType = outObj.getChildDBName();
604                 }
605                 if (inObj.isContainer()) {
606                         inType = inObj.getChildDBName();
607                 }
608                 
609                 markParentBoundary();
610                 Map<String, EdgeRule> rules;
611                 if (labels == null) {
612                         rules = edgeRules.getEdgeRules(type, outType, inType);
613                 } else {
614                         rules = edgeRules.getEdgeRulesWithLabels(type, outType, inType, labels);
615                 }
616                 
617                 final List<String> inLabels = new ArrayList<>();
618                 final List<String> outLabels = new ArrayList<>();
619
620                 rules.forEach((k, edgeRule) -> {
621                         if (labels != null && !labels.contains(k)) {
622                                 return;
623                         } else {
624                                 if (edgeRule.getDirection().equals(Direction.IN)) {
625                                         inLabels.add(edgeRule.getLabel());
626                                 } else {
627                                         outLabels.add(edgeRule.getLabel());
628                                 }
629                         }
630                 });
631
632                 if (inLabels.isEmpty() && !outLabels.isEmpty()) {
633                         traversal.outE(outLabels.toArray(new String[outLabels.size()]));
634                 } else if (outLabels.isEmpty() && !inLabels.isEmpty()) {
635                         traversal.inE(inLabels.toArray(new String[inLabels.size()]));
636                 } else {                                
637                         traversal.union(__.outE(outLabels.toArray(new String[outLabels.size()])), __.inE(inLabels.toArray(new String[inLabels.size()])));
638                 }
639         }
640         
641         @Override
642         public QueryBuilder<E> limit(long amount) {
643                 traversal.limit(amount);
644                 return this;
645         }
646
647         /**
648          * @{inheritDoc}
649          */
650         @Override
651         public <E2> E2 getQuery() {
652                 return (E2)this.traversal;
653         }
654         
655         /**
656          * @{inheritDoc}
657          */
658         @Override
659         public QueryBuilder<E> getParentQuery() {
660
661                 return cloneQueryAtStep(parentStepIndex);
662         }
663         
664         @Override
665         public QueryBuilder<E> getContainerQuery() {
666                 
667                 if (this.parentStepIndex == 0) {
668                         return removeQueryStepsBetween(0, containerStepIndex);
669                 } else {
670                         return cloneQueryAtStep(containerStepIndex);
671                 }
672         }
673         
674         /**
675          * @{inheritDoc}
676          */
677         @Override
678         public void markParentBoundary() {
679                 parentStepIndex = stepIndex;
680         }
681         
682         @Override
683         public void markContainer() {
684                 containerStepIndex = stepIndex;
685         }
686         
687         
688         /**
689          * @{inheritDoc}
690          */
691         @Override
692         public Vertex getStart() {
693                 return this.start;
694         }
695
696         protected int getParentStepIndex() {
697                 return parentStepIndex;
698         }
699
700         protected int getContainerStepIndex() {
701                 return containerStepIndex;
702         }
703
704         protected int getStepIndex() {
705                 return stepIndex;
706         }
707
708         protected abstract QueryBuilder<E> cloneQueryAtStep(int index);
709         /**
710          * end is exclusive
711          * 
712          * @param start
713          * @param end
714          * @return
715          */
716         protected abstract QueryBuilder<E> removeQueryStepsBetween(int start, int end);
717         
718         private void executeQuery() {
719                 
720                 Admin admin;
721                 if (start != null) {
722                         this.completeTraversal = traversal.asAdmin();
723                 } else {
724                         admin = source.V().asAdmin();
725                         TraversalHelper.insertTraversal(admin.getEndStep(), traversal.asAdmin(), admin);
726                         
727                         this.completeTraversal = (Admin<Vertex, E>) admin;
728
729                 }
730                 
731                 
732         }
733         
734         @Override
735         public boolean hasNext() {
736                 if (this.completeTraversal == null) {
737                         executeQuery();
738                 }
739                 
740                 return this.completeTraversal.hasNext();
741         }
742         
743         @Override
744         public E next() {
745                 if (this.completeTraversal == null) {
746                         executeQuery();
747                 }
748                 
749                 return this.completeTraversal.next();
750         }
751         
752         @Override
753         public List<E> toList() {
754                 if (this.completeTraversal == null) {
755                         executeQuery();
756                 }
757                 
758                 return this.completeTraversal.toList();
759         }
760
761 }