2 * ============LICENSE_START=======================================================
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
11 * http://www.apache.org/licenses/LICENSE-2.0
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=========================================================
20 package org.onap.aai.query.builder;
22 import com.google.common.base.Joiner;
23 import com.google.common.collect.ArrayListMultimap;
24 import com.google.common.collect.Multimap;
26 import org.apache.tinkerpop.gremlin.process.traversal.Path;
27 import org.apache.tinkerpop.gremlin.process.traversal.dsl.graph.GraphTraversal;
28 import org.apache.tinkerpop.gremlin.process.traversal.dsl.graph.GraphTraversalSource;
29 import org.apache.tinkerpop.gremlin.process.traversal.step.util.Tree;
30 import org.apache.tinkerpop.gremlin.structure.Direction;
31 import org.apache.tinkerpop.gremlin.structure.Edge;
32 import org.apache.tinkerpop.gremlin.structure.Vertex;
33 import org.onap.aai.db.props.AAIProperties;
34 import org.onap.aai.exceptions.AAIException;
35 import org.onap.aai.introspection.Introspector;
36 import org.onap.aai.introspection.Loader;
37 import org.onap.aai.restcore.search.GremlinGroovyShellSingleton;
38 import org.onap.aai.schema.enums.ObjectMetadata;
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.serialization.db.exceptions.NoEdgeRuleFoundException;
48 * The Class GremlinQueryBuilder.
50 public abstract class GremlinQueryBuilder<E> extends QueryBuilder<E> {
52 private GremlinGroovyShellSingleton gremlinGroovy = GremlinGroovyShellSingleton.getInstance();
53 private GraphTraversal<?, ?> completeTraversal = null;
54 protected List<String> list = null;
57 * Instantiates a new gremlin query builder.
59 * @param loader the loader
61 public GremlinQueryBuilder(Loader loader, GraphTraversalSource source) {
62 super(loader, source);
63 list = new ArrayList<>();
67 * Instantiates a new gremlin query builder.
69 * @param loader the loader
70 * @param start the start
72 public GremlinQueryBuilder(Loader loader, GraphTraversalSource source, Vertex start) {
73 super(loader, source, start);
74 list = new ArrayList<>();
78 public QueryBuilder<Vertex> exactMatchQuery(Introspector obj) {
79 // TODO not implemented because this is implementation is no longer used
80 this.createKeyQuery(obj);
81 this.createContainerQuery(obj);
82 return (QueryBuilder<Vertex>) this;
89 public QueryBuilder<Vertex> getVerticesByProperty(String key, Object value) {
92 if (value != null && !(value instanceof String) ) {
93 term = value.toString();
95 term = "'" + value + "'";
97 list.add(".has('" + key + "', " + term + ")");
99 return (QueryBuilder<Vertex>) this;
103 public QueryBuilder<Vertex> getVerticesByBooleanProperty(String key, Object value) {
104 boolean bValue = false;
106 if(value instanceof String){
107 bValue = Boolean.valueOf(value.toString());
108 } else if(value instanceof Boolean){
109 bValue = (Boolean) value;
112 list.add(".has('" + key + "', " + bValue + ")");
114 return (QueryBuilder<Vertex>) this;
121 public QueryBuilder<Vertex> getVerticesByProperty(String key, List<?> values) {
123 String predicate = "P.within(#!#argument#!#)";
124 List<String> arguments = new ArrayList<>();
125 for (Object item : values) {
126 if (item != null && !(item instanceof String)) {
127 arguments.add(item.toString());
129 arguments.add("'" + item + "'");
132 String argument = Joiner.on(",").join(arguments);
133 predicate = predicate.replace("#!#argument#!#", argument);
134 list.add(".has('" + key + "', " + predicate + ")");
136 return (QueryBuilder<Vertex>) this;
143 public QueryBuilder<Vertex> getVerticesByProperty(String key) {
145 list.add(".has('" + key + "')");
147 return (QueryBuilder<Vertex>) this;
154 public QueryBuilder<Vertex> getVerticesExcludeByProperty(String key) {
157 list.add(".hasNot('" + key + "')");
159 return (QueryBuilder<Vertex>) this;
166 public QueryBuilder<Vertex> getVerticesStartsWithProperty(String key, Object value) {
169 String predicate = "org.janusgraph.core.attribute.Text.textPrefix(#!#argument#!#)";
170 if (value != null && !(value instanceof String) ) {
171 term = value.toString();
173 term = "'" + value + "'";
175 predicate = predicate.replace("#!#argument#!#", term);
176 list.add(".has('" + key + "', " + predicate + ")");
178 return (QueryBuilder<Vertex>) this;
185 public QueryBuilder<Vertex> getVerticesExcludeByProperty(String key, Object value) {
188 String predicate = "P.neq(#!#argument#!#)";
189 if (value != null && !(value instanceof String) ) {
190 term = value.toString();
192 term = "'" + value + "'";
194 predicate = predicate.replace("#!#argument#!#", term);
195 list.add(".has('" + key + "', " + predicate + ")");
197 return (QueryBuilder<Vertex>) this;
204 public QueryBuilder<Vertex> getVerticesExcludeByProperty(String key, List<?> values) {
206 String predicate = "P.without(#!#argument#!#)";
207 List<String> arguments = new ArrayList<>();
208 for (Object item : values) {
209 if (item != null && !(item instanceof String)) {
210 arguments.add(item.toString());
212 arguments.add("'" + item + "'");
215 String argument = Joiner.on(",").join(arguments);
216 predicate = predicate.replace("#!#argument#!#", argument);
217 list.add(".has('" + key + "', " + predicate + ")");
219 return (QueryBuilder<Vertex>) this;
223 public QueryBuilder<Vertex> getVerticesGreaterThanProperty(String key, Object value) {
224 String predicate = "P.gte(#!#argument1#!#)";
226 if (value != null && !(value instanceof String) ) {
227 term = value.toString();
229 term = "'" + value + "'";
231 predicate = predicate.replace("#!#argument1#!#", term);
232 list.add(".has('" + key + "', " + predicate + ")");
234 return (QueryBuilder<Vertex>) this;
238 public QueryBuilder<Vertex> getVerticesLessThanProperty(String key, Object value) {
239 String predicate = "P.lte(#!#argument1#!#)";
241 if (value != null && !(value instanceof String) ) {
242 term = value.toString();
244 term = "'" + value + "'";
246 predicate = predicate.replace("#!#argument1#!#", term);
247 list.add(".has('" + key + "', " + predicate + ")");
249 return (QueryBuilder<Vertex>) this;
259 public QueryBuilder<Vertex> getChildVerticesFromParent(String parentKey, String parentValue, String childType) {
261 String query = ".has('aai-node-type', '" + childType + "')";
263 return this.processGremlinQuery(parentKey, parentValue, query);
266 return (QueryBuilder<Vertex>) this;
273 public QueryBuilder<Vertex> getTypedVerticesByMap(String type, Map<String, String> map) {
275 for (Map.Entry<String, String> es : map.entrySet()) {
276 list.add(".has('" + es.getKey() + "', '" + es.getValue() + "')");
279 list.add(".has('aai-node-type', '" + type + "')");
281 return (QueryBuilder<Vertex>) this;
288 public QueryBuilder<Vertex> createKeyQuery(Introspector obj) {
289 Set<String> keys = obj.getKeys();
291 for (String key : keys) {
293 this.getVerticesByProperty(key, obj.<Object>getValue(key));
296 return (QueryBuilder<Vertex>) this;
300 * @throws NoEdgeRuleFoundException
301 * @throws AAIException
305 public QueryBuilder createEdgeTraversal(EdgeType type, Introspector parent, Introspector child) throws AAIException {
306 String parentName = parent.getDbName();
307 String childName = child.getDbName();
308 if (parent.isContainer()) {
309 parentName = parent.getChildDBName();
311 if (child.isContainer()) {
312 childName = child.getChildDBName();
314 this.edgeQueryToVertex(type, parentName, childName, null);
320 public QueryBuilder createPrivateEdgeTraversal(EdgeType type, Introspector parent, Introspector child) throws AAIException{
321 String parentName = parent.getDbName();
322 String childName = child.getDbName();
323 if (parent.isContainer()) {
324 parentName = parent.getChildDBName();
326 if (child.isContainer()) {
327 childName = child.getChildDBName();
329 this.edgeQueryToVertex(type, parentName, childName, null, true);
338 public QueryBuilder<Vertex> createEdgeTraversalWithLabels(EdgeType type, Introspector out, Introspector in, List<String> labels) throws AAIException {
339 String parentName = out.getDbName();
340 String childName = in.getDbName();
341 if (out.isContainer()) {
342 parentName = out.getChildDBName();
344 if (in.isContainer()) {
345 childName = in.getChildDBName();
347 this.edgeQueryToVertex(type, parentName, childName, labels);
348 return (QueryBuilder<Vertex>) this;
352 public QueryBuilder<Edge> getEdgesBetweenWithLabels(EdgeType type, String outNodeType, String inNodeType, List<String> labels) throws AAIException {
353 this.edgeQuery(type, outNodeType, inNodeType, labels);
354 return (QueryBuilder<Edge>)this;
357 private void edgeQueryToVertex(EdgeType type, String outType, String inType, List<String> labels) throws AAIException {
358 this.edgeQueryToVertex(type, outType, inType, labels, false);
364 * @param outType the out type
365 * @param inType the in type
366 * @throws NoEdgeRuleFoundException
367 * @throws AAIException
369 private void edgeQueryToVertex(EdgeType type, String outType, String inType, List<String> labels, boolean isPrivateEdge) throws AAIException {
370 markParentBoundary();
371 Multimap<String, EdgeRule> rules = ArrayListMultimap.create();
372 EdgeRuleQuery.Builder qB = new EdgeRuleQuery.Builder(outType, inType).edgeType(type).setPrivate(isPrivateEdge);
375 if (labels == null) {
376 rules.putAll(edgeRules.getRules(qB.build()));
378 for (String label : labels) {
379 rules.putAll(edgeRules.getRules(qB.label(label).build()));
382 } catch (EdgeRuleNotFoundException e) {
383 throw new NoEdgeRuleFoundException(e);
386 final List<String> inLabels = new ArrayList<>();
387 final List<String> outLabels = new ArrayList<>();
389 for (EdgeRule rule : rules.values()) {
390 if (labels != null && !labels.contains(rule.getLabel())) {
393 if (Direction.IN.equals(rule.getDirection())) {
394 inLabels.add(rule.getLabel());
396 outLabels.add(rule.getLabel());
401 if(inLabels.isEmpty() && outLabels.isEmpty()) {
402 throw new NoEdgeRuleFoundException("no " + type.toString() + " edge rule between " + outType + " and " + inType );
403 } else if (inLabels.isEmpty() && !outLabels.isEmpty()) {
404 list.add(".out('" + String.join("','", outLabels) + "')");
405 } else if (outLabels.isEmpty() && !inLabels.isEmpty()) {
406 list.add(".in('" + String.join("','", inLabels) + "')");
408 list.add(".union(__.in('" + String.join("','", inLabels) + "')" + ", __.out('" + String.join("','", outLabels) + "'))");
411 list.add(".has('" + AAIProperties.NODE_TYPE + "', '" + inType + "')");
419 * @param outType the out type
420 * @param inType the in type
421 * @throws NoEdgeRuleFoundException
422 * @throws AAIException
424 private void edgeQuery(EdgeType type, String outType, String inType, List<String> labels) throws AAIException {
425 markParentBoundary();
426 Multimap<String, EdgeRule> rules = ArrayListMultimap.create();
427 EdgeRuleQuery.Builder qB = new EdgeRuleQuery.Builder(outType, inType).edgeType(type);
429 if (labels == null) {
430 rules.putAll(edgeRules.getRules(qB.build()));
432 for (String label : labels) {
433 rules.putAll(edgeRules.getRules(qB.label(label).build()));
436 } catch (EdgeRuleNotFoundException e) {
437 throw new NoEdgeRuleFoundException(e);
440 final List<String> inLabels = new ArrayList<>();
441 final List<String> outLabels = new ArrayList<>();
443 for (EdgeRule rule : rules.values()) {
444 if (labels != null && !labels.contains(rule.getLabel())) {
447 if (Direction.IN.equals(rule.getDirection())) {
448 inLabels.add(rule.getLabel());
450 outLabels.add(rule.getLabel());
455 if(inLabels.isEmpty() && outLabels.isEmpty()) {
456 throw new NoEdgeRuleFoundException("no " + type.toString() + " edge rule between " + outType + " and " + inType );
457 } else if (inLabels.isEmpty() && !outLabels.isEmpty()) {
458 list.add(".outE('" + String.join("','", outLabels) + "')");
459 } else if (outLabels.isEmpty() && !inLabels.isEmpty()) {
460 list.add(".inE('" + String.join("','", inLabels) + "')");
462 list.add(".union(__.inE('" + String.join("','", inLabels) + "')" + ", __.outE('" + String.join("','", outLabels) + "'))");
469 public QueryBuilder<E> limit(long amount) {
470 list.add(".limit(" + amount + ")");
477 public QueryBuilder<Vertex> createContainerQuery(Introspector obj) {
478 String type = obj.getChildDBName();
479 String abstractType = obj.getMetadata(ObjectMetadata.ABSTRACT);
480 if (abstractType != null) {
481 String[] inheritors = obj.getMetadata(ObjectMetadata.INHERITORS).split(",");
482 String[] wrapped = new String[inheritors.length];
483 StringBuilder command = new StringBuilder();
484 command.append("P.within(");
485 for (int i = 0; i < inheritors.length; i++) {
486 wrapped[i] = "'" + inheritors[i] + "'";
488 command.append(Joiner.on(",").join(wrapped));
490 list.add(".has('aai-node-type', " + command + ")");
493 list.add(".has('aai-node-type', '" + type + "')");
496 this.markContainer();
497 return (QueryBuilder<Vertex>) this;
501 public QueryBuilder<E> union(QueryBuilder<E>... builder) {
502 markParentBoundary();
503 String[] traversals = new String[builder.length];
504 StringBuilder command = new StringBuilder();
505 for (int i = 0; i < builder.length; i++) {
506 traversals[i] = "__" + builder[i].getQuery();
508 command.append(".union(");
509 command.append(Joiner.on(",").join(traversals));
511 list.add(command.toString());
518 public QueryBuilder<E> where(QueryBuilder<E>... builder) {
519 markParentBoundary();
520 List<String> traversals = new ArrayList<>();
521 for (int i = 0; i < builder.length; i++) {
522 traversals.add(".where(__" + builder[i].getQuery() + ")");
525 list.addAll(traversals);
532 public QueryBuilder<E> or(QueryBuilder<E>... builder) {
533 markParentBoundary();
534 String[] traversals = new String[builder.length];
535 StringBuilder command = new StringBuilder();
536 for (int i = 0; i < builder.length; i++) {
537 traversals[i] = "__" + builder[i].getQuery();
539 command.append(".or(");
540 command.append(Joiner.on(",").join(traversals));
542 list.add(command.toString());
549 public QueryBuilder<E> store(String name) {
550 this.list.add(".store('"+ name + "')");
557 public QueryBuilder<E> cap(String name) {
558 this.list.add(".cap('"+ name + "')");
565 public QueryBuilder<E> unfold() {
566 this.list.add(".unfold()");
573 public QueryBuilder<E> dedup() {
574 this.list.add(".dedup()");
581 public QueryBuilder<E> emit() {
582 this.list.add(".emit()");
589 public QueryBuilder<E> repeat(QueryBuilder<E> builder) {
590 this.list.add(".repeat(__" + builder.getQuery() + ")");
597 public QueryBuilder<E> until(QueryBuilder<E> builder) {
598 this.list.add(".until(__" + builder.getQuery() + ")");
605 public QueryBuilder<E> groupCount() {
606 this.list.add(".groupCount()");
613 public QueryBuilder<E> both() {
614 this.list.add(".both()");
621 public QueryBuilder<Tree> tree() {
622 this.list.add(".tree()");
625 return (QueryBuilder<Tree>)this;
629 public QueryBuilder<E> by(String name) {
630 this.list.add(".by('"+ name + "')");
640 public QueryBuilder<E> simplePath(){
641 this.list.add(".simplePath()");
650 public QueryBuilder<Path> path(){
651 this.list.add(".path()");
653 return (QueryBuilder<Path>)this;
657 public QueryBuilder<Edge> outE() {
658 this.list.add(".outE()");
661 return (QueryBuilder<Edge>)this;
665 public QueryBuilder<Edge> inE() {
666 this.list.add(".inE()");
669 return (QueryBuilder<Edge>)this;
673 public QueryBuilder<Vertex> outV() {
674 this.list.add(".outV()");
677 return (QueryBuilder<Vertex>)this;
681 public QueryBuilder<Vertex> inV() {
682 this.list.add(".inV()");
685 return (QueryBuilder<Vertex>)this;
689 public QueryBuilder<E> not(QueryBuilder<E> builder) {
690 this.list.add(".not(" + "__" + builder.getQuery() + ")");
697 public QueryBuilder<E> as(String name) {
698 this.list.add(".as('" + name + "')");
705 public QueryBuilder<E> select(String name) {
706 this.list.add(".select('" + name + "')");
715 public QueryBuilder<E> getParentQuery() {
716 return cloneQueryAtStep(parentStepIndex);
720 public QueryBuilder<E> getContainerQuery() {
721 return cloneQueryAtStep(containerStepIndex);
728 public <T2> T2 getQuery() {
729 StringBuilder sb = new StringBuilder();
731 for (String piece : this.list) {
735 return (T2)sb.toString();
742 public void markParentBoundary() {
743 parentStepIndex = stepIndex;
747 public void markContainer() {
748 this.containerStepIndex = stepIndex;
755 public Vertex getStart() {
759 protected int getParentStepIndex() {
760 return parentStepIndex;
763 protected int getContainerStepIndex() {
764 return containerStepIndex;
767 protected int getStepIndex() {
771 private void executeQuery() {
772 String queryString = "g" + Joiner.on("").join(list);
773 Map<String, Object> params = new HashMap<>();
774 if (this.start == null) {
775 params.put("g", source.V());
777 params.put("g", source.V(this.start));
779 this.completeTraversal = this.gremlinGroovy.executeTraversal(queryString, params);
782 public boolean hasNext() {
783 if (this.completeTraversal == null) {
787 return this.completeTraversal.hasNext();
792 if (this.completeTraversal == null) {
796 return (E)this.completeTraversal.next();
800 public List<E> toList() {
801 if (this.completeTraversal == null) {
805 return (List<E>)this.completeTraversal.toList();
808 protected QueryBuilder<Edge> has(String key, String value) {
809 this.list.add(".has('" + key + "','" + value + "')");
811 return (QueryBuilder<Edge>)this;