Update tinkerpop to 3.2.3 in aai-core
[aai/aai-common.git] / aai-core / src / main / java / org / onap / aai / query / builder / GremlinQueryBuilder.java
1 /**
2  * ============LICENSE_START=======================================================
3  * org.onap.aai
4  * ================================================================================
5  * Copyright © 2017-2018 AT&T Intellectual Property. All rights reserved.
6  * ================================================================================
7  * Modifications Copyright © 2018 IBM.
8  * ================================================================================
9  * Licensed under the Apache License, Version 2.0 (the "License");
10  * you may not use this file except in compliance with the License.
11  * You may obtain a copy of the License at
12  *
13  *    http://www.apache.org/licenses/LICENSE-2.0
14  *
15  * Unless required by applicable law or agreed to in writing, software
16  * distributed under the License is distributed on an "AS IS" BASIS,
17  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
18  * See the License for the specific language governing permissions and
19  * limitations under the License.
20  * ============LICENSE_END=========================================================
21  */
22
23 package org.onap.aai.query.builder;
24
25 import com.google.common.base.Joiner;
26 import com.google.common.collect.ArrayListMultimap;
27 import com.google.common.collect.Multimap;
28
29 import java.util.*;
30
31 import org.apache.tinkerpop.gremlin.process.traversal.Path;
32 import org.apache.tinkerpop.gremlin.process.traversal.dsl.graph.GraphTraversal;
33 import org.apache.tinkerpop.gremlin.process.traversal.dsl.graph.GraphTraversalSource;
34 import org.apache.tinkerpop.gremlin.process.traversal.step.util.Tree;
35 import org.apache.tinkerpop.gremlin.structure.Direction;
36 import org.apache.tinkerpop.gremlin.structure.Edge;
37 import org.apache.tinkerpop.gremlin.structure.Vertex;
38 import org.onap.aai.db.props.AAIProperties;
39 import org.onap.aai.edges.EdgeRule;
40 import org.onap.aai.edges.EdgeRuleQuery;
41 import org.onap.aai.edges.enums.EdgeType;
42 import org.onap.aai.edges.exceptions.EdgeRuleNotFoundException;
43 import org.onap.aai.exceptions.AAIException;
44 import org.onap.aai.introspection.Introspector;
45 import org.onap.aai.introspection.Loader;
46 import org.onap.aai.restcore.search.GremlinGroovyShell;
47 import org.onap.aai.schema.enums.ObjectMetadata;
48 import org.onap.aai.serialization.db.exceptions.NoEdgeRuleFoundException;
49 import org.slf4j.Logger;
50 import org.slf4j.LoggerFactory;
51
52 /**
53  * The Class GremlinQueryBuilder.
54  */
55 public abstract class GremlinQueryBuilder<E> extends QueryBuilder<E> {
56
57     private static final String ARGUMENT2 = "#!#argument#!#";
58     private static final String HAS = ".has('";
59     private static final String SINGLE_QUOTE = "'";
60     private static final String ESCAPE_SINGLE_QUOTE = "\\\'";
61     private GremlinGroovyShell gremlinGroovy = new GremlinGroovyShell();
62     private GraphTraversal<?, ?> completeTraversal = null;
63     protected List<String> list = null;
64
65     private static final Logger LOGGER = LoggerFactory.getLogger(QueryBuilder.class);
66
67     /**
68      * Instantiates a new gremlin query builder.
69      *
70      * @param loader the loader
71      */
72     public GremlinQueryBuilder(Loader loader, GraphTraversalSource source) {
73         super(loader, source);
74         list = new ArrayList<>();
75     }
76
77     /**
78      * Instantiates a new gremlin query builder.
79      *
80      * @param loader the loader
81      * @param start the start
82      */
83     public GremlinQueryBuilder(Loader loader, GraphTraversalSource source, Vertex start) {
84         super(loader, source, start);
85         list = new ArrayList<>();
86     }
87
88     @Override
89     public QueryBuilder<Vertex> exactMatchQuery(Introspector obj) {
90         // TODO not implemented because this is implementation is no longer used
91         this.createKeyQuery(obj);
92         this.createContainerQuery(obj);
93         return (QueryBuilder<Vertex>) this;
94     }
95
96     @Override
97     protected void vertexHas(String key, Object value) {
98         list.add(HAS + key + "', " + value + ")");
99     }
100
101     @Override
102     protected void vertexHasNot(String key) {
103         list.add(".hasNot('" + key + "')");
104
105     }
106
107     @Override
108     protected void vertexHas(String key) {
109         list.add(HAS + key + "')");
110     }
111
112     /**
113      * @{inheritDoc}
114      */
115     @Override
116     public QueryBuilder<Vertex> getVerticesByProperty(String key, Object value) {
117
118         String term = "";
119         if (value != null && !(value instanceof String)) {
120             String valueString = value.toString();
121
122             if (valueString.indexOf('\'') != -1) {
123                 value = valueString.replace(SINGLE_QUOTE, ESCAPE_SINGLE_QUOTE);
124             }
125             LOGGER.trace("Inside getVerticesByProperty(): key = {}, value = {}", key, value);
126             term = value.toString();
127         } else if (value != null && value instanceof String) {
128             String valueString = value.toString();
129
130             if (valueString.indexOf('\'') != -1) {
131                 value = valueString.replace(SINGLE_QUOTE, ESCAPE_SINGLE_QUOTE);
132             }
133             LOGGER.trace("Inside getVerticesByProperty(): key = {}, value = {}", key, value);
134             term = "'" + value + "'";
135         } else {
136             term = "'" + value + "'";
137         }
138         this.vertexHas(key, term);
139         stepIndex++;
140         return (QueryBuilder<Vertex>) this;
141     }
142
143     /**
144      * @{inheritDoc}
145      */
146     @Override
147     public QueryBuilder<Vertex> getVerticesByNumberProperty(String key, Object value) {
148         this.vertexHas(key, value);
149         stepIndex++;
150         return (QueryBuilder<Vertex>) this;
151     }
152
153     @Override
154     public QueryBuilder<Vertex> getVerticesByBooleanProperty(String key, Object value) {
155
156         if (value != null && !"".equals(value)) {
157             boolean bValue = false;
158             if (value instanceof String) {
159                 bValue = Boolean.valueOf(value.toString());
160             } else if (value instanceof Boolean) {
161                 bValue = (Boolean) value;
162             }
163
164             this.vertexHas(key, bValue);
165             stepIndex++;
166         }
167         return (QueryBuilder<Vertex>) this;
168     }
169
170     /**
171      * @{inheritDoc}
172      */
173     @Override
174     public QueryBuilder<Vertex> getVerticesByProperty(String key, List<?> values) {
175
176         String predicate = "P.within(#!#argument#!#)";
177         List<String> arguments = new ArrayList<>();
178         for (Object item : values) {
179             if (item != null && !(item instanceof String)) {
180                 arguments.add(item.toString());
181             } else {
182                 arguments.add("'" + item + "'");
183             }
184         }
185         String argument = Joiner.on(",").join(arguments);
186         predicate = predicate.replace(ARGUMENT2, argument);
187         this.vertexHas(key, predicate);
188         stepIndex++;
189         return (QueryBuilder<Vertex>) this;
190     }
191
192     /**
193      * @{inheritDoc}
194      */
195     @Override
196     public QueryBuilder<Vertex> getVerticesByCommaSeperatedValue(String key, String value) {
197         ArrayList<String> arguments = new ArrayList<>(Arrays.asList(value.split(",")));
198         // add the single quotes
199         for (int i = 0; i < arguments.size(); i++) {
200             if (arguments.get(i) != null && !arguments.get(i).startsWith("'") && !arguments.get(i).endsWith("'")) {
201                 arguments.set(i, "'" + arguments.get(i).trim() + "'");
202             } else {
203                 arguments.set(i, arguments.get(i).trim());
204             }
205         }
206         String predicate = "P.within(#!#argument#!#)";
207         String argument = Joiner.on(",").join(arguments);
208         predicate = predicate.replace(ARGUMENT2, argument);
209         this.vertexHas(key, predicate);
210         stepIndex++;
211         return (QueryBuilder<Vertex>) this;
212     }
213
214     /**
215      * @{inheritDoc}
216      */
217     @Override
218     public QueryBuilder<Vertex> getVerticesByProperty(String key) {
219         this.vertexHas(key);
220         stepIndex++;
221         return (QueryBuilder<Vertex>) this;
222     }
223
224     /**
225      * @{inheritDoc}
226      */
227     @Override
228     public QueryBuilder<Vertex> getVerticesExcludeByProperty(String key) {
229         this.vertexHasNot(key);
230         stepIndex++;
231         return (QueryBuilder<Vertex>) this;
232     }
233
234     /**
235      * @{inheritDoc}
236      */
237     @Override
238     public QueryBuilder<Vertex> getVerticesStartsWithProperty(String key, Object value) {
239         String term = "";
240         String predicate = "org.janusgraph.core.attribute.Text.textPrefix(#!#argument#!#)";
241         if (value != null && !(value instanceof String)) {
242             term = value.toString();
243         } else {
244             term = "'" + value + "'";
245         }
246         predicate = predicate.replace(ARGUMENT2, term);
247         this.vertexHas(key, predicate);
248         stepIndex++;
249         return (QueryBuilder<Vertex>) this;
250     }
251
252     /**
253      * @{inheritDoc}
254      */
255     @Override
256     public QueryBuilder<Vertex> getVerticesExcludeByProperty(String key, Object value) {
257
258         String term = "";
259         String predicate = "P.neq(#!#argument#!#)";
260         if (value != null && !(value instanceof String)) {
261             term = value.toString();
262         } else {
263             term = "'" + value + "'";
264         }
265         predicate = predicate.replace(ARGUMENT2, term);
266         this.vertexHas(key, predicate);
267         stepIndex++;
268         return (QueryBuilder<Vertex>) this;
269     }
270
271     /**
272      * @{inheritDoc}
273      */
274     @Override
275     public QueryBuilder<Vertex> getVerticesExcludeByProperty(String key, List<?> values) {
276
277         String predicate = "P.without(#!#argument#!#)";
278         List<String> arguments = new ArrayList<>();
279         for (Object item : values) {
280             if (item != null && !(item instanceof String)) {
281                 arguments.add(item.toString());
282             } else {
283                 arguments.add("'" + item + "'");
284             }
285         }
286         String argument = Joiner.on(",").join(arguments);
287         predicate = predicate.replace(ARGUMENT2, argument);
288         this.vertexHas(key, predicate);
289         stepIndex++;
290         return (QueryBuilder<Vertex>) this;
291     }
292
293     @Override
294     public QueryBuilder<Vertex> getVerticesGreaterThanProperty(String key, Object value) {
295         String predicate = "P.gte(#!#argument1#!#)";
296         String term;
297         if (value != null && !(value instanceof String)) {
298             term = value.toString();
299         } else {
300             term = "'" + value + "'";
301         }
302         predicate = predicate.replace("#!#argument1#!#", term);
303         this.vertexHas(key, predicate);
304         stepIndex++;
305         return (QueryBuilder<Vertex>) this;
306     }
307
308     @Override
309     public QueryBuilder<Vertex> getVerticesLessThanProperty(String key, Object value) {
310         String predicate = "P.lte(#!#argument1#!#)";
311         String term;
312         if (value != null && !(value instanceof String)) {
313             term = value.toString();
314         } else {
315             term = "'" + value + "'";
316         }
317         predicate = predicate.replace("#!#argument1#!#", term);
318         this.vertexHas(key, predicate);
319         stepIndex++;
320         return (QueryBuilder<Vertex>) this;
321     }
322
323     /**
324      * @{inheritDoc}
325      */
326     @Override
327     public QueryBuilder<Vertex> getChildVerticesFromParent(String parentKey, String parentValue, String childType) {
328         // TODO
329         return (QueryBuilder<Vertex>) this;
330     }
331
332     /**
333      * @{inheritDoc}
334      */
335     @Override
336     public QueryBuilder<Vertex> getTypedVerticesByMap(String type, Map<String, String> map) {
337
338         for (Map.Entry<String, String> es : map.entrySet()) {
339             // TODO what is this and where is it used - need to check
340             list.add(HAS + es.getKey() + "', '" + es.getValue() + "')");
341             stepIndex++;
342         }
343         list.add(".has('aai-node-type', '" + type + "')");
344         stepIndex++;
345         return (QueryBuilder<Vertex>) this;
346     }
347
348     /**
349      * @{inheritDoc}
350      */
351     @Override
352     public QueryBuilder<Vertex> createKeyQuery(Introspector obj) {
353         Set<String> keys = obj.getKeys();
354
355         for (String key : keys) {
356
357             this.getVerticesByProperty(key, obj.<Object>getValue(key));
358
359         }
360         return (QueryBuilder<Vertex>) this;
361     }
362
363     /**
364      * @throws NoEdgeRuleFoundException
365      * @throws AAIException
366      * @{inheritDoc}
367      */
368     @Override
369     public QueryBuilder createEdgeTraversal(EdgeType type, Introspector parent, Introspector child)
370             throws AAIException {
371         String parentName = parent.getDbName();
372         String childName = child.getDbName();
373         if (parent.isContainer()) {
374             parentName = parent.getChildDBName();
375         }
376         if (child.isContainer()) {
377             childName = child.getChildDBName();
378         }
379         this.edgeQueryToVertex(type, parentName, childName, null);
380         return this;
381
382     }
383
384     @Override
385     public QueryBuilder createPrivateEdgeTraversal(EdgeType type, Introspector parent, Introspector child)
386             throws AAIException {
387         String parentName = parent.getDbName();
388         String childName = child.getDbName();
389         if (parent.isContainer()) {
390             parentName = parent.getChildDBName();
391         }
392         if (child.isContainer()) {
393             childName = child.getChildDBName();
394         }
395         this.edgeQueryToVertex(type, parentName, childName, null, true);
396         return this;
397     }
398
399     /**
400      *
401      * @{inheritDoc}
402      */
403     @Override
404     public QueryBuilder<Vertex> createEdgeTraversalWithLabels(EdgeType type, Introspector out, Introspector in,
405             List<String> labels) throws AAIException {
406         String parentName = out.getDbName();
407         String childName = in.getDbName();
408         if (out.isContainer()) {
409             parentName = out.getChildDBName();
410         }
411         if (in.isContainer()) {
412             childName = in.getChildDBName();
413         }
414         this.edgeQueryToVertex(type, parentName, childName, labels);
415         return (QueryBuilder<Vertex>) this;
416     }
417
418     public QueryBuilder<Edge> getEdgesBetweenWithLabels(EdgeType type, String outNodeType, String inNodeType,
419             List<String> labels) throws AAIException {
420         this.edgeQuery(type, outNodeType, inNodeType, labels);
421         return (QueryBuilder<Edge>) this;
422     }
423
424     private void edgeQueryToVertex(EdgeType type, String outType, String inType, List<String> labels)
425             throws AAIException {
426         this.edgeQueryToVertex(type, outType, inType, labels, false);
427     }
428
429     /**
430      * Edge query.
431      *
432      * @param outType the out type
433      * @param inType the in type
434      * @throws NoEdgeRuleFoundException
435      * @throws AAIException
436      */
437     private void edgeQueryToVertex(EdgeType type, String outType, String inType, List<String> labels,
438             boolean isPrivateEdge) throws AAIException {
439         markParentBoundary();
440         Multimap<String, EdgeRule> rules = ArrayListMultimap.create();
441         EdgeRuleQuery.Builder qB = new EdgeRuleQuery.Builder(outType, inType).edgeType(type).setPrivate(isPrivateEdge);
442
443         try {
444             if (labels == null) {
445                 rules.putAll(edgeRules.getRules(qB.build()));
446             } else {
447                 for (String label : labels) {
448                     rules.putAll(edgeRules.getRules(qB.label(label).build()));
449                 }
450             }
451         } catch (EdgeRuleNotFoundException e) {
452             throw new NoEdgeRuleFoundException(e);
453         }
454
455         final List<String> inLabels = new ArrayList<>();
456         final List<String> outLabels = new ArrayList<>();
457
458         for (EdgeRule rule : rules.values()) {
459             if (labels != null && !labels.contains(rule.getLabel())) {
460                 return;
461             } else {
462                 if (Direction.IN.equals(rule.getDirection())) {
463                     inLabels.add(rule.getLabel());
464                     if (inType.equals(outType)) {// code to handle when a type edges to itself, to add both in and out
465                         outLabels.add(rule.getLabel());
466                     }
467                 } else {
468                     outLabels.add(rule.getLabel());
469                     if (inType.equals(outType)) {// code to handle when a type edges to itself, to add both in and out
470                         inLabels.add(rule.getLabel());
471                     }
472                 }
473             }
474         }
475
476         if (inLabels.isEmpty() && outLabels.isEmpty()) {
477             throw new NoEdgeRuleFoundException(
478                     "no " + type.toString() + " edge rule between " + outType + " and " + inType);
479         } else if (inLabels.isEmpty() && !outLabels.isEmpty()) {
480             list.add(".out('" + String.join("','", outLabels) + "')");
481         } else if (outLabels.isEmpty() && !inLabels.isEmpty()) {
482             list.add(".in('" + String.join("','", inLabels) + "')");
483         } else {
484             list.add(".union(__.in('" + String.join("','", inLabels) + "')" + ", __.out('"
485                     + String.join("','", outLabels) + "'))");
486         }
487         stepIndex++;
488         list.add(HAS + AAIProperties.NODE_TYPE + "', '" + inType + "')");
489         stepIndex++;
490
491     }
492
493     /**
494      * Edge query.
495      *
496      * @param outType the out type
497      * @param inType the in type
498      * @throws NoEdgeRuleFoundException
499      * @throws AAIException
500      */
501     private void edgeQuery(EdgeType type, String outType, String inType, List<String> labels) throws AAIException {
502         markParentBoundary();
503         Multimap<String, EdgeRule> rules = ArrayListMultimap.create();
504         EdgeRuleQuery.Builder qB = new EdgeRuleQuery.Builder(outType, inType).edgeType(type);
505         try {
506             if (labels == null) {
507                 rules.putAll(edgeRules.getRules(qB.build()));
508             } else {
509                 for (String label : labels) {
510                     rules.putAll(edgeRules.getRules(qB.label(label).build()));
511                 }
512             }
513         } catch (EdgeRuleNotFoundException e) {
514             throw new NoEdgeRuleFoundException(e);
515         }
516
517         final List<String> inLabels = new ArrayList<>();
518         final List<String> outLabels = new ArrayList<>();
519
520         for (EdgeRule rule : rules.values()) {
521             if (labels != null && !labels.contains(rule.getLabel())) {
522                 return;
523             } else {
524                 if (Direction.IN.equals(rule.getDirection())) {
525                     inLabels.add(rule.getLabel());
526                 } else {
527                     outLabels.add(rule.getLabel());
528                 }
529             }
530         }
531
532         if (inLabels.isEmpty() && outLabels.isEmpty()) {
533             throw new NoEdgeRuleFoundException(
534                     "no " + type.toString() + " edge rule between " + outType + " and " + inType);
535         } else if (inLabels.isEmpty() && !outLabels.isEmpty()) {
536             list.add(".outE('" + String.join("','", outLabels) + "')");
537         } else if (outLabels.isEmpty() && !inLabels.isEmpty()) {
538             list.add(".inE('" + String.join("','", inLabels) + "')");
539         } else {
540             list.add(".union(__.inE('" + String.join("','", inLabels) + "')" + ", __.outE('"
541                     + String.join("','", outLabels) + "'))");
542         }
543
544         stepIndex++;
545
546     }
547
548     @Override
549     public QueryBuilder<E> limit(long amount) {
550         list.add(".limit(" + amount + ")");
551         return this;
552     }
553
554     /**
555      * @{inheritDoc}
556      */
557     @Override
558     public QueryBuilder<Vertex> createContainerQuery(Introspector obj) {
559         String type = obj.getChildDBName();
560         String abstractType = obj.getMetadata(ObjectMetadata.ABSTRACT);
561         if (abstractType != null) {
562             String[] inheritors = obj.getMetadata(ObjectMetadata.INHERITORS).split(",");
563             String[] wrapped = new String[inheritors.length];
564             StringBuilder command = new StringBuilder();
565             command.append("P.within(");
566             for (int i = 0; i < inheritors.length; i++) {
567                 wrapped[i] = "'" + inheritors[i] + "'";
568             }
569             command.append(Joiner.on(",").join(wrapped));
570             command.append(")");
571             list.add(".has('aai-node-type', " + command + ")");
572
573         } else {
574             list.add(".has('aai-node-type', '" + type + "')");
575         }
576         stepIndex++;
577         this.markContainerIndex();
578         return (QueryBuilder<Vertex>) this;
579     }
580
581     @Override
582     public QueryBuilder<E> union(QueryBuilder<E>... builder) {
583         markParentBoundary();
584         String[] traversals = new String[builder.length];
585         StringBuilder command = new StringBuilder();
586         for (int i = 0; i < builder.length; i++) {
587             traversals[i] = "__" + builder[i].getQuery();
588         }
589         command.append(".union(");
590         command.append(Joiner.on(",").join(traversals));
591         command.append(")");
592         list.add(command.toString());
593         stepIndex++;
594
595         return this;
596     }
597
598     @Override
599     public QueryBuilder<E> where(QueryBuilder<E>... builder) {
600         markParentBoundary();
601         List<String> traversals = new ArrayList<>();
602         for (int i = 0; i < builder.length; i++) {
603             traversals.add(".where(__" + builder[i].getQuery() + ")");
604             stepIndex++;
605         }
606         list.addAll(traversals);
607
608         return this;
609     }
610
611     @Override
612     public QueryBuilder<E> or(QueryBuilder<E>... builder) {
613         markParentBoundary();
614         String[] traversals = new String[builder.length];
615         StringBuilder command = new StringBuilder();
616         for (int i = 0; i < builder.length; i++) {
617             traversals[i] = "__" + builder[i].getQuery();
618         }
619         command.append(".or(");
620         command.append(Joiner.on(",").join(traversals));
621         command.append(")");
622         list.add(command.toString());
623         stepIndex++;
624
625         return this;
626     }
627
628     @Override
629     public QueryBuilder<E> store(String name) {
630         this.list.add(".store('" + name + "')");
631         stepIndex++;
632
633         return this;
634     }
635
636     @Override
637     public QueryBuilder<E> cap(String name) {
638         this.list.add(".cap('" + name + "')");
639         stepIndex++;
640
641         return this;
642     }
643
644     @Override
645     public QueryBuilder<E> unfold() {
646         this.list.add(".unfold()");
647         stepIndex++;
648
649         return this;
650     }
651
652     @Override
653     public QueryBuilder<E> fold() {
654         this.list.add(".fold()");
655         stepIndex++;
656         return this;
657     }
658
659     @Override
660     public QueryBuilder<E> id() {
661         this.list.add(".id()");
662         stepIndex++;
663         return this;
664     }
665
666     @Override
667     public QueryBuilder<E> dedup() {
668         this.list.add(".dedup()");
669         stepIndex++;
670
671         return this;
672     }
673
674     @Override
675     public QueryBuilder<E> emit() {
676         this.list.add(".emit()");
677         stepIndex++;
678
679         return this;
680     }
681
682     @Override
683     public QueryBuilder<E> repeat(QueryBuilder<E> builder) {
684         this.list.add(".repeat(__" + builder.getQuery() + ")");
685         stepIndex++;
686
687         return this;
688     }
689
690     @Override
691     public QueryBuilder<E> until(QueryBuilder<E> builder) {
692         this.list.add(".until(__" + builder.getQuery() + ")");
693         stepIndex++;
694
695         return this;
696     }
697
698     @Override
699     public QueryBuilder<E> groupCount() {
700         this.list.add(".groupCount()");
701         stepIndex++;
702
703         return this;
704     }
705
706     @Override
707     public QueryBuilder<E> both() {
708         this.list.add(".both()");
709         stepIndex++;
710
711         return this;
712     }
713
714     @Override
715     public QueryBuilder<Tree> tree() {
716         this.list.add(".tree()");
717         stepIndex++;
718
719         return (QueryBuilder<Tree>) this;
720     }
721
722     @Override
723     public QueryBuilder<E> by(String name) {
724         this.list.add(".by('" + name + "')");
725         stepIndex++;
726
727         return this;
728     }
729
730     @Override
731     public QueryBuilder<E> valueMap() {
732         this.list.add(".valueMap()");
733         stepIndex++;
734
735         return this;
736     }
737
738     @Override
739     public QueryBuilder<E> valueMap(String... names) {
740         String stepString = ".valueMap('";
741         for (int i = 0; i < names.length; i++) {
742             stepString = stepString + names[i] + "'";
743             if (i != (names.length - 1)) {
744                 stepString = stepString + ",'";
745             }
746         }
747         stepString = stepString + ")";
748         this.list.add(stepString);
749         stepIndex++;
750
751         return this;
752     }
753
754     /**
755      * {@inheritDoc}
756      */
757     @Override
758     public QueryBuilder<E> simplePath() {
759         this.list.add(".simplePath()");
760         stepIndex++;
761         return this;
762     }
763
764     /**
765      * {@inheritDoc}
766      */
767     @Override
768     public QueryBuilder<Path> path() {
769         this.list.add(".path()");
770         stepIndex++;
771         return (QueryBuilder<Path>) this;
772     }
773
774     @Override
775     public QueryBuilder<Edge> outE() {
776         this.list.add(".outE()");
777         stepIndex++;
778
779         return (QueryBuilder<Edge>) this;
780     }
781
782     @Override
783     public QueryBuilder<Edge> inE() {
784         this.list.add(".inE()");
785         stepIndex++;
786
787         return (QueryBuilder<Edge>) this;
788     }
789
790     @Override
791     public QueryBuilder<Vertex> outV() {
792         this.list.add(".outV()");
793         stepIndex++;
794
795         return (QueryBuilder<Vertex>) this;
796     }
797
798     @Override
799     public QueryBuilder<Vertex> inV() {
800         this.list.add(".inV()");
801         stepIndex++;
802
803         return (QueryBuilder<Vertex>) this;
804     }
805
806     @Override
807     public QueryBuilder<E> not(QueryBuilder<E> builder) {
808         this.list.add(".not(" + "__" + builder.getQuery() + ")");
809         stepIndex++;
810
811         return this;
812     }
813
814     @Override
815     public QueryBuilder<E> as(String name) {
816         this.list.add(".as('" + name + "')");
817         stepIndex++;
818
819         return this;
820     }
821
822     @Override
823     public QueryBuilder<E> select(String name) {
824         this.list.add(".select('" + name + "')");
825         stepIndex++;
826
827         return this;
828     }
829
830     @Override
831     public QueryBuilder<E> select(String... names) {
832         String stepString = ".select('";
833         for (int i = 0; i < names.length; i++) {
834             stepString = stepString + names[i] + "'";
835             if (i != (names.length - 1)) {
836                 stepString = stepString + ",'";
837             }
838         }
839         stepString = stepString + ")";
840         this.list.add(stepString);
841         stepIndex++;
842
843         return this;
844     }
845
846     /**
847      * @{inheritDoc}
848      */
849     @Override
850     public QueryBuilder<E> getParentQuery() {
851         return cloneQueryAtStep(parentStepIndex);
852     }
853
854     @Override
855     public QueryBuilder<E> getContainerQuery() {
856         return cloneQueryAtStep(containerStepIndex);
857     }
858
859     /**
860      * @{inheritDoc}
861      */
862     @Override
863     public <T2> T2 getQuery() {
864         StringBuilder sb = new StringBuilder();
865
866         for (String piece : this.list) {
867             sb.append(piece);
868         }
869
870         return (T2) sb.toString();
871     }
872
873     /**
874      * @{inheritDoc}
875      */
876     @Override
877     public void markParentBoundary() {
878         parentStepIndex = stepIndex;
879     }
880
881     @Override
882     public void markContainerIndex() {
883         this.containerStepIndex = stepIndex;
884     }
885
886     /**
887      * @{inheritDoc}
888      */
889     @Override
890     public Vertex getStart() {
891         return this.start;
892     }
893
894     protected int getParentStepIndex() {
895         return parentStepIndex;
896     }
897
898     protected int getContainerStepIndex() {
899         return containerStepIndex;
900     }
901
902     protected int getStepIndex() {
903         return stepIndex;
904     }
905
906     private void executeQuery() {
907         String queryString = "g" + Joiner.on("").join(list);
908         Map<String, Object> params = new HashMap<>();
909         if (this.start == null) {
910             params.put("g", source.V());
911         } else {
912             params.put("g", source.V(this.start));
913         }
914         this.completeTraversal = this.gremlinGroovy.executeTraversal(queryString, params);
915     }
916
917     @Override
918     public boolean hasNext() {
919         if (this.completeTraversal == null) {
920             executeQuery();
921         }
922
923         return this.completeTraversal.hasNext();
924     }
925
926     @Override
927     public E next() {
928         if (this.completeTraversal == null) {
929             executeQuery();
930         }
931
932         return (E) this.completeTraversal.next();
933     }
934
935     @Override
936     public List<E> toList() {
937         if (this.completeTraversal == null) {
938             executeQuery();
939         }
940
941         return (List<E>) this.completeTraversal.toList();
942     }
943
944     protected QueryBuilder<Edge> has(String key, String value) {
945         this.list.add(HAS + key + "','" + value + "')");
946
947         return (QueryBuilder<Edge>) this;
948     }
949
950     /*
951      * This is required for the subgraphstrategies to work
952      */
953
954 }