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