8012229638dc5e5160a80417fe514af52eeccbec
[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-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.query.builder;
21
22 import org.apache.tinkerpop.gremlin.process.traversal.P;
23 import org.apache.tinkerpop.gremlin.process.traversal.Path;
24 import org.apache.tinkerpop.gremlin.process.traversal.Traversal;
25 import org.apache.tinkerpop.gremlin.process.traversal.Traversal.Admin;
26 import org.apache.tinkerpop.gremlin.process.traversal.dsl.graph.GraphTraversal;
27 import org.apache.tinkerpop.gremlin.process.traversal.dsl.graph.GraphTraversalSource;
28 import org.apache.tinkerpop.gremlin.process.traversal.dsl.graph.__;
29 import org.apache.tinkerpop.gremlin.process.traversal.step.util.Tree;
30 import org.apache.tinkerpop.gremlin.process.traversal.util.TraversalHelper;
31 import org.apache.tinkerpop.gremlin.structure.Direction;
32 import org.apache.tinkerpop.gremlin.structure.Edge;
33 import org.apache.tinkerpop.gremlin.structure.Vertex;
34 import org.onap.aai.db.props.AAIProperties;
35 import org.onap.aai.exceptions.AAIException;
36 import org.onap.aai.introspection.Introspector;
37 import org.onap.aai.introspection.Loader;
38 import org.onap.aai.schema.enums.ObjectMetadata;
39 import org.onap.aai.schema.enums.PropertyMetadata;
40 import org.onap.aai.edges.EdgeRule;
41 import org.onap.aai.edges.EdgeRuleQuery;
42 import org.onap.aai.edges.enums.EdgeType;
43 import org.onap.aai.edges.exceptions.EdgeRuleNotFoundException;
44 import org.onap.aai.serialization.db.exceptions.NoEdgeRuleFoundException;
45
46 import com.google.common.collect.ArrayListMultimap;
47 import com.google.common.collect.Multimap;
48
49 import java.util.*;
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
59         /**
60          * Instantiates a new graph traversal builder.
61          *
62          * @param loader the loader
63          */
64         public GraphTraversalBuilder(Loader loader, GraphTraversalSource source) {
65                 super(loader, source);
66
67                 traversal = (GraphTraversal<Vertex, E>) __.<E>start();
68
69         }
70
71         /**
72          * Instantiates a new graph traversal builder.
73          *
74          * @param loader the loader
75          * @param start the start
76          */
77         public GraphTraversalBuilder(Loader loader, GraphTraversalSource source, Vertex start) {
78                 super(loader, source, start);
79
80                 traversal = (GraphTraversal<Vertex, E>) __.__(start);
81
82         }
83
84         /**
85          * @{inheritDoc}
86          */
87         @Override
88         public QueryBuilder<Vertex> getVerticesByProperty(String key, Object value) {
89
90                 // correct value call because the index is registered as an Integer
91                 traversal.has(key, this.correctObjectType(value));
92
93                 stepIndex++;
94                 return (QueryBuilder<Vertex>) this;
95         }
96
97         /**
98          * @{inheritDoc}
99          */
100         @Override
101         public QueryBuilder<Vertex> getVerticesByProperty(final String key, final List<?> values) {
102
103                 //this is because the index is registered as an Integer
104                 List<Object> correctedValues = new ArrayList<>();
105                 for (Object item : values) {
106                         correctedValues.add(this.correctObjectType(item));
107                 }
108
109                 traversal.has(key, P.within(correctedValues));
110
111                 stepIndex++;
112                 return (QueryBuilder<Vertex>) this;
113         }
114
115         /**
116          * @{inheritDoc}
117          */
118         @Override
119         public QueryBuilder<Vertex> getVerticesStartsWithProperty(String key, Object value) {
120
121                 // correct value call because the index is registered as an Integer
122                 traversal.has(key, org.janusgraph.core.attribute.Text.textPrefix(value));
123
124                 stepIndex++;
125                 return (QueryBuilder<Vertex>) this;
126         }
127
128     /**
129      * @{inheritDoc}
130      */
131     @Override
132     public QueryBuilder<Vertex> getVerticesByProperty(String key) {
133
134         traversal.has(key);
135         stepIndex++;
136         return (QueryBuilder<Vertex>) this;
137     }
138
139     /**
140      * @{inheritDoc}
141      */
142     @Override
143     public QueryBuilder<Vertex> getVerticesExcludeByProperty(String key) {
144
145         traversal.hasNot(key);
146         stepIndex++;
147         return (QueryBuilder<Vertex>) this;
148     }
149
150
151         /**
152          * @{inheritDoc}
153          */
154         @Override
155         public QueryBuilder<Vertex> getVerticesExcludeByProperty(String key, Object value) {
156
157                 // correct value call because the index is registered as an Integer
158                 traversal.has(key, P.neq(this.correctObjectType(value)));
159
160                 stepIndex++;
161                 return (QueryBuilder<Vertex>) this;
162         }
163
164         /**
165          * @{inheritDoc}
166          */
167         @Override
168         public QueryBuilder<Vertex> getVerticesExcludeByProperty(final String key, final List<?> values) {
169
170                 //this is because the index is registered as an Integer
171                 List<Object> correctedValues = new ArrayList<>();
172                 for (Object item : values) {
173                         correctedValues.add(this.correctObjectType(item));
174                 }
175
176                 traversal.has(key, P.without(correctedValues));
177
178                 stepIndex++;
179                 return (QueryBuilder<Vertex>) this;
180         }
181
182     @Override
183     public QueryBuilder<Vertex> getVerticesGreaterThanProperty(final String key, Object value) {
184
185         traversal.has(key, P.gte(this.correctObjectType(value)));
186
187         stepIndex++;
188         return (QueryBuilder<Vertex>) this;
189     }
190
191     @Override
192     public QueryBuilder<Vertex> getVerticesLessThanProperty(final String key, Object value) {
193
194         traversal.has(key, P.lte(this.correctObjectType(value)));
195
196         stepIndex++;
197         return (QueryBuilder<Vertex>) this;
198     }
199
200
201         /**
202          * @{inheritDoc}
203          */
204         @Override
205         public QueryBuilder<Vertex> getChildVerticesFromParent(String parentKey, String parentValue, String childType) {
206                 traversal.has(parentKey, parentValue).has(AAIProperties.NODE_TYPE, childType);
207                 stepIndex++;
208                 return (QueryBuilder<Vertex>) this;
209         }
210
211         /**
212          * @{inheritDoc}
213          */
214         @Override
215         public QueryBuilder<Vertex> getTypedVerticesByMap(String type, Map<String, String> map) {
216
217                 for (Map.Entry<String, String> es : map.entrySet()) {
218                         traversal.has(es.getKey(), es.getValue());
219                         stepIndex++;
220                 }
221                 traversal.has(AAIProperties.NODE_TYPE, type);
222                 stepIndex++;
223                 return (QueryBuilder<Vertex>) this;
224         }
225
226         @Override
227         public QueryBuilder<Vertex> getVerticesByBooleanProperty(String key, Object value) {
228
229                 boolean bValue = false;
230
231             if(value instanceof String){
232                 bValue = Boolean.valueOf(value.toString());
233                 } else if(value instanceof Boolean){
234                 bValue = (Boolean) value;
235                 }
236
237                 traversal.has(key, bValue);
238                 stepIndex++;
239                 return (QueryBuilder<Vertex>) this;
240         }
241
242         /**
243          * @{inheritDoc}
244          */
245         @Override
246         public QueryBuilder<Vertex> createKeyQuery(Introspector obj) {
247                 Set<String> keys = obj.getKeys();
248                 Object val;
249                 for (String key : keys) {
250                         val = obj.getValue(key);
251                         Optional<String> metadata = obj.getPropertyMetadata(key, PropertyMetadata.DB_ALIAS);
252                         if (metadata.isPresent()) {
253                                 //use the db name for the field rather than the object model
254                                 key = metadata.get();
255                         }
256                         if (val != null) {
257                                 //this is because the index is registered as an Integer
258                                 if (val.getClass().equals(Long.class)) {
259                                         traversal.has(key,new Integer(val.toString()));
260                                 } else {
261                                         traversal.has(key, val);
262                                 }
263                                 stepIndex++;
264                         }
265                 }
266                 return (QueryBuilder<Vertex>) this;
267         }
268
269         @Override
270         public QueryBuilder<Vertex> exactMatchQuery(Introspector obj) {
271                 this.createKeyQuery(obj);
272                 allPropertiesQuery(obj);
273                 this.createContainerQuery(obj);
274                 return (QueryBuilder<Vertex>) this;
275         }
276
277         private void allPropertiesQuery(Introspector obj) {
278                 Set<String> props = obj.getProperties();
279                 Set<String> keys = obj.getKeys();
280                 Object val;
281                 for (String prop : props) {
282                         if (obj.isSimpleType(prop) && !keys.contains(prop)) {
283                                 val = obj.getValue(prop);
284                                 if (val != null) {
285                                         Optional<String> metadata = obj.getPropertyMetadata(prop, PropertyMetadata.DB_ALIAS);
286                                         if (metadata.isPresent()) {
287                                                 //use the db name for the field rather than the object model
288                                                 prop = metadata.get();
289                                         }
290                                         //this is because the index is registered as an Integer
291                                         if (val.getClass().equals(Long.class)) {
292                                                 traversal.has(prop,new Integer(val.toString()));
293                                         } else {
294                                                 traversal.has(prop, val);
295                                         }
296                                         stepIndex++;
297                                 }
298                         }
299                 }
300         }
301
302         /**
303          * @{inheritDoc}
304          */
305         @Override
306
307         public QueryBuilder<Vertex> createContainerQuery(Introspector obj) {
308                 String type = obj.getChildDBName();
309                 String abstractType = obj.getMetadata(ObjectMetadata.ABSTRACT);
310                 if (abstractType != null) {
311                         String[] inheritors = obj.getMetadata(ObjectMetadata.INHERITORS).split(",");
312                         traversal.has(AAIProperties.NODE_TYPE, P.within(inheritors));
313                 } else {
314                         traversal.has(AAIProperties.NODE_TYPE, type);
315                 }
316                 stepIndex++;
317                 markContainer();
318                 return (QueryBuilder<Vertex>) this;
319         }
320
321         /**
322          * @throws NoEdgeRuleFoundException
323          * @throws AAIException
324          * @{inheritDoc}
325          */
326         @Override
327         public QueryBuilder<Vertex> createEdgeTraversal(EdgeType type, Introspector parent, Introspector child) throws AAIException {
328                 createTraversal(type, parent, child, false);
329                 return (QueryBuilder<Vertex>) this;
330
331         }
332
333         @Override
334         public QueryBuilder<Vertex> createPrivateEdgeTraversal(EdgeType type, Introspector parent, Introspector child) throws AAIException {
335             this.createTraversal(type, parent, child, true);
336                 return (QueryBuilder<Vertex>) this;
337         }
338
339         private void createTraversal(EdgeType type, Introspector parent, Introspector child, boolean isPrivateEdge) throws AAIException {
340                 String isAbstractType = parent.getMetadata(ObjectMetadata.ABSTRACT);
341                 if ("true".equals(isAbstractType)) {
342                         markParentBoundary();
343                         traversal.union(handleAbstractEdge(type, parent, child, isPrivateEdge));
344                         stepIndex++;
345                 } else {
346                         this.edgeQueryToVertex(type, parent, child, null);
347                 }
348         }
349
350         /**
351          *
352          * @{inheritDoc}
353          */
354         @Override
355         public QueryBuilder<Vertex> createEdgeTraversalWithLabels(EdgeType type, Introspector out, Introspector in, List<String> labels) throws AAIException {
356                 this.edgeQueryToVertex(type, out, in, labels);
357                 return (QueryBuilder<Vertex>) this;
358         }
359
360         private Traversal<Vertex, Vertex>[] handleAbstractEdge(EdgeType type, Introspector abstractParent, Introspector child, boolean isPrivateEdge) throws AAIException {
361                 String childName = child.getDbName();
362                 String inheritorMetadata = abstractParent.getMetadata(ObjectMetadata.INHERITORS);
363                 String[] inheritors = inheritorMetadata.split(",");
364                 List<Traversal<Vertex, Vertex>> unionTraversals = new ArrayList<>(inheritors.length);
365
366                 for (int i = 0; i < inheritors.length; i++) {
367                         String inheritor = inheritors[i];
368                         EdgeRuleQuery.Builder qB = new EdgeRuleQuery.Builder(inheritor, childName);
369                         if (edgeRules.hasRule(qB.build())) {
370                                 Multimap<String, EdgeRule> rules = ArrayListMultimap.create();
371                                 try {
372                                         rules = edgeRules.getRules(qB.edgeType(type).build());
373                                 } catch (EdgeRuleNotFoundException e) {
374                                         throw new NoEdgeRuleFoundException(e);
375                                 }
376
377                                 GraphTraversal<Vertex, Vertex> innerTraversal = __.start();
378
379                                 final List<String> inLabels = new ArrayList<>();
380                                 final List<String> outLabels = new ArrayList<>();
381
382                                 rules.values().forEach(rule -> {
383                                         if (rule.getDirection().equals(Direction.IN)) {
384                                                 inLabels.add(rule.getLabel());
385                                         } else {
386                                                 outLabels.add(rule.getLabel());
387                                         }
388                                 } );
389
390                                 if (inLabels.isEmpty() && !outLabels.isEmpty()) {
391                                         innerTraversal.out(outLabels.toArray(new String[outLabels.size()]));
392                                 } else if (outLabels.isEmpty() && !inLabels.isEmpty()) {
393                                         innerTraversal.in(inLabels.toArray(new String[inLabels.size()]));
394                                 } else {
395                                         innerTraversal.union(__.out(outLabels.toArray(new String[outLabels.size()])), __.in(inLabels.toArray(new String[inLabels.size()])));
396                                 }
397
398                                 innerTraversal.has(AAIProperties.NODE_TYPE, childName);
399                                 unionTraversals.add(innerTraversal);
400                         }
401                 }
402
403                 return unionTraversals.toArray(new Traversal[unionTraversals.size()]);
404         }
405
406         public QueryBuilder<Edge> getEdgesBetweenWithLabels(EdgeType type, String outNodeType, String inNodeType, List<String> labels) throws AAIException {
407                 Introspector outObj = loader.introspectorFromName(outNodeType);
408                 Introspector inObj = loader.introspectorFromName(inNodeType);
409                 this.edgeQuery(type, outObj, inObj, labels);
410
411                 return (QueryBuilder<Edge>)this;
412         }
413
414
415         /**
416          * @{inheritDoc}
417          */
418         @Override
419         public QueryBuilder<E> union(QueryBuilder... builder) {
420                 GraphTraversal<Vertex, Vertex>[] traversals = new GraphTraversal[builder.length];
421                 for (int i = 0; i < builder.length; i++) {
422                         traversals[i] = (GraphTraversal<Vertex, Vertex>)builder[i].getQuery();
423                 }
424                 this.traversal.union(traversals);
425                 stepIndex++;
426
427                 return this;
428         }
429
430         /**
431          * @{inheritDoc}
432          */
433         @Override
434         public QueryBuilder<E> where(QueryBuilder... builder) {
435                 for (int i = 0; i < builder.length; i++) {
436                         this.traversal.where((GraphTraversal<Vertex, Vertex>)builder[i].getQuery());
437                         stepIndex++;
438                 }
439
440                 return this;
441         }
442
443         /**
444          * @{inheritDoc}
445          */
446         @Override
447         public QueryBuilder<E> or(QueryBuilder... builder) {
448                 GraphTraversal<Vertex, Vertex>[] traversals = new GraphTraversal[builder.length];
449                 for (int i = 0; i < builder.length; i++) {
450                         traversals[i] = (GraphTraversal<Vertex, Vertex>)builder[i].getQuery();
451                 }
452                 this.traversal.or(traversals);
453                 stepIndex++;
454
455                 return this;
456         }
457
458         @Override
459         public QueryBuilder<E> store(String name) {
460
461                 this.traversal.store(name);
462                 stepIndex++;
463
464                 return this;
465         }
466
467         @Override
468         public QueryBuilder<E> cap(String name) {
469                 this.traversal.cap(name);
470                 stepIndex++;
471
472                 return this;
473         }
474
475         @Override
476         public QueryBuilder<E> unfold() {
477                 this.traversal.unfold();
478                 stepIndex++;
479
480                 return this;
481         }
482
483         @Override
484         public QueryBuilder<E> dedup() {
485
486                 this.traversal.dedup();
487                 stepIndex++;
488
489                 return this;
490         }
491
492         @Override
493         public QueryBuilder<E> emit() {
494
495                 this.traversal.emit();
496                 stepIndex++;
497
498                 return this;
499
500         }
501
502         @Override
503         public QueryBuilder<E> repeat(QueryBuilder<E> builder) {
504
505                 this.traversal.repeat((GraphTraversal<Vertex, E>)builder.getQuery());
506                 stepIndex++;
507
508                 return this;
509         }
510
511         @Override
512         public QueryBuilder<E> until(QueryBuilder<E> builder) {
513                 this.traversal.until((GraphTraversal<Vertex,E>)builder.getQuery());
514                 stepIndex++;
515
516                 return this;
517         }
518
519         @Override
520         public QueryBuilder<E> groupCount() {
521                 this.traversal.groupCount();
522                 stepIndex++;
523
524                 return this;
525         }
526
527         @Override
528         public QueryBuilder<E> both() {
529                 this.traversal.both();
530                 stepIndex++;
531
532                 return this;
533         }
534
535         @Override
536         public QueryBuilder<Tree> tree() {
537
538                 this.traversal.tree();
539                 stepIndex++;
540
541                 return (QueryBuilder<Tree>)this;
542         }
543
544         @Override
545         public QueryBuilder<E> by(String name) {
546                 this.traversal.by(name);
547                 stepIndex++;
548
549                 return this;
550         }
551
552         /**
553          * {@inheritDoc}
554          */
555         @Override
556         public QueryBuilder<E> simplePath(){
557                 this.traversal.simplePath();
558                 stepIndex++;
559                 return this;
560         }
561
562         /**
563          * {@inheritDoc}
564          */
565         @Override
566         public QueryBuilder<Path> path(){
567                 this.traversal.path();
568                 stepIndex++;
569                 return (QueryBuilder<Path>)this;
570         }
571
572         @Override
573         public QueryBuilder<Edge> outE() {
574                 this.traversal.outE();
575                 stepIndex++;
576                 return (QueryBuilder<Edge>)this;
577         }
578
579         @Override
580         public QueryBuilder<Edge> inE() {
581                 this.traversal.inE();
582                 stepIndex++;
583                 return (QueryBuilder<Edge>)this;
584         }
585
586         @Override
587         public QueryBuilder<Vertex> outV() {
588                 this.traversal.outV();
589                 stepIndex++;
590                 return (QueryBuilder<Vertex>)this;
591         }
592
593         @Override
594         public QueryBuilder<Vertex> inV() {
595                 this.traversal.inV();
596                 stepIndex++;
597                 return (QueryBuilder<Vertex>)this;
598         }
599
600         @Override
601         public QueryBuilder<E> as(String name) {
602                 this.traversal.as(name);
603
604                 stepIndex++;
605                 return this;
606         }
607
608         @Override
609         public QueryBuilder<E> not(QueryBuilder<E> builder) {
610                 this.traversal.not(builder.getQuery());
611
612                 stepIndex++;
613                 return this;
614         }
615
616         @Override
617         public QueryBuilder<E> select(String name) {
618                 this.traversal.select(name);
619
620                 stepIndex++;
621
622                 return this;
623         }
624
625         @Override
626         public QueryBuilder<E> select(String... names) {
627                 if(names.length == 1) {
628                         this.traversal.select(names[0]);
629                 }
630                 else if(names.length == 2) {
631                         this.traversal.select(names[0], names[1]);
632                 }
633                 else if(names.length > 2){
634                         String[] otherNames = Arrays.copyOfRange(names, 2, names.length);
635                         this.traversal.select(names[0], names[1], otherNames);
636                 }
637
638                 stepIndex++;
639
640                 return this;
641         }
642
643         /**
644          * Edge query.
645          *
646          * @param outObj the out type
647          * @param inObj the in type
648          * @throws NoEdgeRuleFoundException
649          * @throws AAIException
650          */
651         private void edgeQueryToVertex(EdgeType type, Introspector outObj, Introspector inObj, List<String> labels) throws AAIException {
652                 String outType = outObj.getDbName();
653                 String inType = inObj.getDbName();
654
655                 if (outObj.isContainer()) {
656                         outType = outObj.getChildDBName();
657                 }
658                 if (inObj.isContainer()) {
659                         inType = inObj.getChildDBName();
660                 }
661                 markParentBoundary();
662                 Multimap<String, EdgeRule> rules = ArrayListMultimap.create();
663                 EdgeRuleQuery.Builder qB = new EdgeRuleQuery.Builder(outType, inType).edgeType(type);
664
665                 if (labels == null) {
666                         try {
667                                 rules.putAll(edgeRules.getRules(qB.build()));
668                         } catch (EdgeRuleNotFoundException e) {
669                                 //is ok per original functioning of this section
670                                 //TODO add "best try" sort of flag to the EdgeRuleQuery
671                                 // to indicate if the exception should be thrown or not
672                         }
673                 } else {
674                         for (String label : labels) {
675                                 try {
676                                         rules.putAll(edgeRules.getRules(qB.label(label).build()));
677                                 } catch (EdgeRuleNotFoundException e) {
678                                         throw new NoEdgeRuleFoundException(e);
679                                 }
680                         }
681                         if (rules.isEmpty()) {
682                                 throw new NoEdgeRuleFoundException("No edge rules found for " + outType + " and " + inType + " of type " + type.toString());
683                         }
684                 }
685
686
687                 final List<String> inLabels = new ArrayList<>();
688                 final List<String> outLabels = new ArrayList<>();
689
690                 for (EdgeRule rule : rules.values()) {
691                         if (labels != null && !labels.contains(rule.getLabel())) {
692                                 return;
693                         } else {
694                                 if (Direction.IN.equals(rule.getDirection())) {
695                                         inLabels.add(rule.getLabel());
696                                 } else {
697                                         outLabels.add(rule.getLabel());
698                                 }
699                         }
700                 }
701
702                 if (inLabels.isEmpty() && !outLabels.isEmpty()) {
703                         traversal.out(outLabels.toArray(new String[outLabels.size()]));
704                 } else if (outLabels.isEmpty() && !inLabels.isEmpty()) {
705                         traversal.in(inLabels.toArray(new String[inLabels.size()]));
706                 } else {
707                         traversal.union(__.out(outLabels.toArray(new String[outLabels.size()])), __.in(inLabels.toArray(new String[inLabels.size()])));
708                 }
709
710                 stepIndex++;
711
712                 this.createContainerQuery(inObj);
713
714         }
715
716         /**
717          * Edge query.
718          *
719          * @param outObj the out type
720          * @param inObj the in type
721          * @throws NoEdgeRuleFoundException
722          * @throws AAIException
723          */
724         private void edgeQuery(EdgeType type, Introspector outObj, Introspector inObj, List<String> labels) throws AAIException {
725                 String outType = outObj.getDbName();
726                 String inType = inObj.getDbName();
727
728                 if (outObj.isContainer()) {
729                         outType = outObj.getChildDBName();
730                 }
731                 if (inObj.isContainer()) {
732                         inType = inObj.getChildDBName();
733                 }
734
735                 markParentBoundary();
736                 Multimap<String, EdgeRule> rules = ArrayListMultimap.create();
737                 EdgeRuleQuery.Builder qB = new EdgeRuleQuery.Builder(outType, inType).edgeType(type);
738
739                 try {
740                         if (labels == null) {
741                                 rules.putAll(edgeRules.getRules(qB.build()));
742                         } else {
743                                 for (String label : labels) {
744                                         rules.putAll(edgeRules.getRules(qB.label(label).build()));
745                                 }
746                         }
747                 } catch (EdgeRuleNotFoundException e) {
748                         throw new NoEdgeRuleFoundException(e);
749                 }
750
751                 final List<String> inLabels = new ArrayList<>();
752                 final List<String> outLabels = new ArrayList<>();
753
754                 for (EdgeRule rule : rules.values()) {
755                         if (labels != null && !labels.contains(rule.getLabel())) {
756                                 return;
757                         } else {
758                                 if (Direction.IN.equals(rule.getDirection())) {
759                                         inLabels.add(rule.getLabel());
760                                 } else {
761                                         outLabels.add(rule.getLabel());
762                                 }
763                         }
764                 }
765
766                 if (inLabels.isEmpty() && !outLabels.isEmpty()) {
767                         traversal.outE(outLabels.toArray(new String[outLabels.size()]));
768                 } else if (outLabels.isEmpty() && !inLabels.isEmpty()) {
769                         traversal.inE(inLabels.toArray(new String[inLabels.size()]));
770                 } else {
771                         traversal.union(__.outE(outLabels.toArray(new String[outLabels.size()])), __.inE(inLabels.toArray(new String[inLabels.size()])));
772                 }
773         }
774
775         @Override
776         public QueryBuilder<E> limit(long amount) {
777                 traversal.limit(amount);
778                 return this;
779         }
780
781         /**
782          * @{inheritDoc}
783          */
784         @Override
785         public <E2> E2 getQuery() {
786                 return (E2)this.traversal;
787         }
788
789         /**
790          * @{inheritDoc}
791          */
792         @Override
793         public QueryBuilder<E> getParentQuery() {
794
795                 return cloneQueryAtStep(parentStepIndex);
796         }
797
798         @Override
799         public QueryBuilder<E> getContainerQuery() {
800
801                 if (this.parentStepIndex == 0) {
802                         return removeQueryStepsBetween(0, containerStepIndex);
803                 } else {
804                         return cloneQueryAtStep(containerStepIndex);
805                 }
806         }
807
808         /**
809          * @{inheritDoc}
810          */
811         @Override
812         public void markParentBoundary() {
813                 parentStepIndex = stepIndex;
814         }
815
816         @Override
817         public void markContainer() {
818                 containerStepIndex = stepIndex;
819         }
820
821
822         /**
823          * @{inheritDoc}
824          */
825         @Override
826         public Vertex getStart() {
827                 return this.start;
828         }
829
830         protected int getParentStepIndex() {
831                 return parentStepIndex;
832         }
833
834         protected int getContainerStepIndex() {
835                 return containerStepIndex;
836         }
837
838         protected int getStepIndex() {
839                 return stepIndex;
840         }
841
842         /**
843          * end is exclusive
844          *
845          * @param start
846          * @param end
847          * @return
848          */
849         protected abstract QueryBuilder<E> removeQueryStepsBetween(int start, int end);
850
851         protected void executeQuery() {
852
853                 Admin admin;
854                 if (start != null) {
855                         this.completeTraversal = traversal.asAdmin();
856                 } else {
857                         admin = source.V().asAdmin();
858                         TraversalHelper.insertTraversal(admin.getEndStep(), traversal.asAdmin(), admin);
859
860                         this.completeTraversal = (Admin<Vertex, E>) admin;
861
862                 }
863
864         }
865
866         @Override
867         public boolean hasNext() {
868                 if (this.completeTraversal == null) {
869                         executeQuery();
870                 }
871
872                 return this.completeTraversal.hasNext();
873         }
874
875         @Override
876         public E next() {
877                 if (this.completeTraversal == null) {
878                         executeQuery();
879                 }
880
881                 return this.completeTraversal.next();
882         }
883
884         @Override
885         public List<E> toList() {
886                 if (this.completeTraversal == null) {
887                         executeQuery();
888                 }
889                 return this.completeTraversal.toList();
890         }
891
892         protected QueryBuilder<Edge> has(String key, String value) {
893                 traversal.has(key, value);
894
895                 return (QueryBuilder<Edge>)this;
896         }
897 }