2 * ============LICENSE_START=======================================================
4 * ================================================================================
5 * Copyright © 2017 AT&T Intellectual Property. All rights reserved.
6 * ================================================================================
7 * Licensed under the Apache License, Version 2.0 (the "License");
8 * you may not use this file except in compliance with the License.
9 * You may obtain a copy of the License at
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 * ECOMP is a trademark and service mark of AT&T Intellectual Property.
22 package org.onap.aai.query.builder;
24 import java.util.ArrayList;
25 import java.util.HashMap;
26 import java.util.List;
30 import org.apache.tinkerpop.gremlin.process.traversal.dsl.graph.GraphTraversal;
31 import org.apache.tinkerpop.gremlin.process.traversal.dsl.graph.GraphTraversalSource;
32 import org.apache.tinkerpop.gremlin.structure.Direction;
33 import org.apache.tinkerpop.gremlin.structure.Edge;
34 import org.apache.tinkerpop.gremlin.structure.Vertex;
35 import org.onap.aai.db.props.AAIProperties;
36 import org.onap.aai.exceptions.AAIException;
37 import org.onap.aai.introspection.Introspector;
38 import org.onap.aai.introspection.Loader;
39 import org.onap.aai.restcore.search.GremlinGroovyShellSingleton;
40 import org.onap.aai.schema.enums.ObjectMetadata;
41 import org.onap.aai.serialization.db.EdgeRule;
42 import org.onap.aai.serialization.db.EdgeRules;
43 import org.onap.aai.serialization.db.EdgeType;
44 import org.onap.aai.serialization.db.exceptions.NoEdgeRuleFoundException;
46 import com.google.common.base.Joiner;
49 * The Class GremlinQueryBuilder.
51 public abstract class GremlinQueryBuilder<E> extends QueryBuilder<E> {
53 private EdgeRules edgeRules = EdgeRules.getInstance();
54 private GremlinGroovyShellSingleton gremlinGroovy = GremlinGroovyShellSingleton.getInstance();
55 private GraphTraversal<?, ?> completeTraversal = null;
56 protected List<String> list = null;
58 protected int parentStepIndex = 0;
59 protected int containerStepIndex = 0;
60 protected int stepIndex = 0;
63 * Instantiates a new gremlin query builder.
65 * @param loader the loader
67 public GremlinQueryBuilder(Loader loader, GraphTraversalSource source) {
68 super(loader, source);
69 list = new ArrayList<>();
73 * Instantiates a new graph gremlin builder.
75 * @param loader the loader
77 public GremlinQueryBuilder(Loader loader, GraphTraversalSource source, EdgeRules edgeRules) {
78 super(loader, source);
79 this.edgeRules = edgeRules;
80 list = new ArrayList<>();
85 * Instantiates a new gremlin query builder.
87 * @param loader the loader
88 * @param start the start
90 public GremlinQueryBuilder(Loader loader, GraphTraversalSource source, Vertex start) {
91 super(loader, source, start);
92 list = new ArrayList<>();
96 * Instantiates a new graph gremlin builder.
98 * @param loader the loader
99 * @param start the start
101 public GremlinQueryBuilder(Loader loader, GraphTraversalSource source, Vertex start, EdgeRules edgeRules) {
102 super(loader, source, start);
103 this.edgeRules = edgeRules;
104 list = new ArrayList<>();
109 public QueryBuilder<Vertex> exactMatchQuery(Introspector obj) {
110 // TODO not implemented because this is implementation is no longer used
111 this.createKeyQuery(obj);
112 this.createContainerQuery(obj);
113 return (QueryBuilder<Vertex>) this;
120 public QueryBuilder<Vertex> getVerticesByProperty(String key, Object value) {
123 if (value != null && !(value instanceof String) ) {
124 term = value.toString();
126 term = "'" + value + "'";
128 list.add(".has('" + key + "', " + term + ")");
130 return (QueryBuilder<Vertex>) this;
137 public QueryBuilder<Vertex> getVerticesByProperty(String key, List<?> values) {
140 String predicate = "P.within(#!#argument#!#)";
141 List<String> arguments = new ArrayList<>();
142 for (Object item : values) {
143 if (item != null && !(item instanceof String)) {
144 arguments.add(item.toString());
146 arguments.add("'" + item + "'");
149 String argument = Joiner.on(",").join(arguments);
150 predicate = predicate.replace("#!#argument#!#", argument);
151 list.add(".has('" + key + "', " + predicate + ")");
153 return (QueryBuilder<Vertex>) this;
160 public QueryBuilder<Vertex> getVerticesExcludeByProperty(String key, Object value) {
163 String predicate = "P.neq(#!#argument#!#)";
164 if (value != null && !(value instanceof String) ) {
165 term = value.toString();
167 term = "'" + value + "'";
169 predicate = predicate.replace("#!#argument#!#", term);
170 list.add(".has('" + key + "', " + predicate + ")");
172 return (QueryBuilder<Vertex>) this;
179 public QueryBuilder<Vertex> getVerticesExcludeByProperty(String key, List<?> values) {
182 String predicate = "P.without(#!#argument#!#)";
183 List<String> arguments = new ArrayList<>();
184 for (Object item : values) {
185 if (item != null && !(item instanceof String)) {
186 arguments.add(item.toString());
188 arguments.add("'" + item + "'");
191 String argument = Joiner.on(",").join(arguments);
192 predicate = predicate.replace("#!#argument#!#", argument);
193 list.add(".has('" + key + "', " + predicate + ")");
195 return (QueryBuilder<Vertex>) this;
202 public QueryBuilder<Vertex> getChildVerticesFromParent(String parentKey, String parentValue, String childType) {
204 String query = ".has('aai-node-type', '" + childType + "')";
206 return this.processGremlinQuery(parentKey, parentValue, query);
209 return (QueryBuilder<Vertex>) this;
216 public QueryBuilder<Vertex> getTypedVerticesByMap(String type, Map<String, String> map) {
218 for (Map.Entry<String, String> es : map.entrySet()) {
219 list.add(".has('" + es.getKey() + "', '" + es.getValue() + "')");
222 list.add(".has('aai-node-type', '" + type + "')");
224 return (QueryBuilder<Vertex>) this;
231 public QueryBuilder<Vertex> createKeyQuery(Introspector obj) {
232 Set<String> keys = obj.getKeys();
234 for (String key : keys) {
236 this.getVerticesByProperty(key, obj.<Object>getValue(key));
239 return (QueryBuilder<Vertex>) this;
243 * @throws NoEdgeRuleFoundException
244 * @throws AAIException
248 public QueryBuilder createEdgeTraversal(EdgeType type, Introspector parent, Introspector child) throws AAIException {
249 String parentName = parent.getDbName();
250 String childName = child.getDbName();
251 if (parent.isContainer()) {
252 parentName = parent.getChildDBName();
254 if (child.isContainer()) {
255 childName = child.getChildDBName();
257 this.edgeQueryToVertex(type, parentName, childName, null);
267 public QueryBuilder<Vertex> createEdgeTraversalWithLabels(EdgeType type, Introspector out, Introspector in, List<String> labels) throws AAIException {
268 String parentName = out.getDbName();
269 String childName = in.getDbName();
270 if (out.isContainer()) {
271 parentName = out.getChildDBName();
273 if (in.isContainer()) {
274 childName = in.getChildDBName();
276 this.edgeQueryToVertex(type, parentName, childName, labels);
277 return (QueryBuilder<Vertex>) this;
281 public QueryBuilder<Edge> getEdgesBetweenWithLabels(EdgeType type, String outNodeType, String inNodeType, List<String> labels) throws AAIException {
282 this.edgeQuery(type, outNodeType, inNodeType, labels);
283 return (QueryBuilder<Edge>)this;
289 * @param outType the out type
290 * @param inType the in type
291 * @throws NoEdgeRuleFoundException
292 * @throws AAIException
294 private void edgeQueryToVertex(EdgeType type, String outType, String inType, List<String> labels) throws AAIException {
295 markParentBoundary();
296 Map<String, EdgeRule> rules;
297 if (labels == null) {
298 rules = edgeRules.getEdgeRules(type, outType, inType);
300 rules = edgeRules.getEdgeRulesWithLabels(type, outType, inType, labels);
303 final List<String> inLabels = new ArrayList<>();
304 final List<String> outLabels = new ArrayList<>();
306 rules.forEach((k, edgeRule) -> {
307 if (labels != null && !labels.contains(k)) {
310 if (edgeRule.getDirection().equals(Direction.IN)) {
311 inLabels.add(edgeRule.getLabel());
313 outLabels.add(edgeRule.getLabel());
318 if(inLabels.isEmpty() && outLabels.isEmpty()) {
319 throw new NoEdgeRuleFoundException("no " + type.toString() + " edge rule between " + outType + " and " + inType );
320 } else if (inLabels.isEmpty() && !outLabels.isEmpty()) {
321 list.add(".out('" + String.join("','", outLabels) + "')");
322 } else if (outLabels.isEmpty() && !inLabels.isEmpty()) {
323 list.add(".in('" + String.join("','", inLabels) + "')");
325 list.add(".union(__.in('" + String.join("','", inLabels) + "')" + ", __.out('" + String.join("','", outLabels) + "'))");
328 list.add(".has('" + AAIProperties.NODE_TYPE + "', '" + inType + "')");
336 * @param outType the out type
337 * @param inType the in type
338 * @throws NoEdgeRuleFoundException
339 * @throws AAIException
341 private void edgeQuery(EdgeType type, String outType, String inType, List<String> labels) throws AAIException {
342 markParentBoundary();
343 Map<String, EdgeRule> rules;
344 if (labels == null) {
345 rules = edgeRules.getEdgeRules(type, outType, inType);
347 rules = edgeRules.getEdgeRulesWithLabels(type, outType, inType, labels);
350 final List<String> inLabels = new ArrayList<>();
351 final List<String> outLabels = new ArrayList<>();
353 rules.forEach((k, edgeRule) -> {
354 if (labels != null && !labels.contains(k)) {
357 if (edgeRule.getDirection().equals(Direction.IN)) {
358 inLabels.add(edgeRule.getLabel());
360 outLabels.add(edgeRule.getLabel());
365 if(inLabels.isEmpty() && outLabels.isEmpty()) {
366 throw new NoEdgeRuleFoundException("no " + type.toString() + " edge rule between " + outType + " and " + inType );
367 } else if (inLabels.isEmpty() && !outLabels.isEmpty()) {
368 list.add(".outE('" + String.join("','", outLabels) + "')");
369 } else if (outLabels.isEmpty() && !inLabels.isEmpty()) {
370 list.add(".inE('" + String.join("','", inLabels) + "')");
372 list.add(".union(__.inE('" + String.join("','", inLabels) + "')" + ", __.outE('" + String.join("','", outLabels) + "'))");
379 public QueryBuilder<E> limit(long amount) {
380 list.add(".limit(" + amount + ")");
387 public QueryBuilder<Vertex> createContainerQuery(Introspector obj) {
388 String type = obj.getChildDBName();
389 String abstractType = obj.getMetadata(ObjectMetadata.ABSTRACT);
390 if (abstractType != null) {
391 String[] inheritors = obj.getMetadata(ObjectMetadata.INHERITORS).split(",");
392 String[] wrapped = new String[inheritors.length];
393 StringBuilder command = new StringBuilder();
394 command.append("P.within(");
395 for (int i = 0; i < inheritors.length; i++) {
396 wrapped[i] = "'" + inheritors[i] + "'";
398 command.append(Joiner.on(",").join(wrapped));
400 list.add(".has('aai-node-type', " + command + ")");
403 list.add(".has('aai-node-type', '" + type + "')");
406 this.markContainer();
407 return (QueryBuilder<Vertex>) this;
411 public QueryBuilder<E> union(QueryBuilder<E>... builder) {
412 markParentBoundary();
413 String[] traversals = new String[builder.length];
414 StringBuilder command = new StringBuilder();
415 for (int i = 0; i < builder.length; i++) {
416 traversals[i] = "__" + (String)builder[i].getQuery();
418 command.append(".union(");
419 command.append(Joiner.on(",").join(traversals));
421 list.add(command.toString());
428 public QueryBuilder<E> where(QueryBuilder<E>... builder) {
429 markParentBoundary();
430 List<String> traversals = new ArrayList<>();
431 for (int i = 0; i < builder.length; i++) {
432 traversals.add(".where(__" + (String)builder[i].getQuery() + ")");
435 list.addAll(traversals);
442 public QueryBuilder<E> store(String name) {
443 this.list.add(".store('"+ name + "')");
450 public QueryBuilder<E> cap(String name) {
451 this.list.add(".cap('"+ name + "')");
458 public QueryBuilder<E> unfold() {
459 this.list.add(".unfold()");
466 public QueryBuilder<E> dedup() {
467 this.list.add(".dedup()");
474 public QueryBuilder<E> emit() {
475 this.list.add(".emit()");
482 public QueryBuilder<E> repeat(QueryBuilder<E> builder) {
483 this.list.add(".repeat(__" + builder.getQuery() + ")");
490 public QueryBuilder<E> until(QueryBuilder<E> builder) {
491 this.list.add(".until(__" + builder.getQuery() + ")");
498 public QueryBuilder<E> groupCount() {
499 this.list.add(".groupCount()");
506 public QueryBuilder<E> both() {
507 this.list.add(".both()");
514 public QueryBuilder<E> by(String name) {
515 this.list.add(".by('"+ name + "')");
525 public QueryBuilder<E> simplePath(){
526 this.list.add(".simplePath()");
532 public QueryBuilder<Edge> outE() {
533 this.list.add(".outE()");
536 return (QueryBuilder<Edge>)this;
540 public QueryBuilder<Edge> inE() {
541 this.list.add(".inE()");
544 return (QueryBuilder<Edge>)this;
548 public QueryBuilder<Vertex> outV() {
549 this.list.add(".outV()");
552 return (QueryBuilder<Vertex>)this;
556 public QueryBuilder<Vertex> inV() {
557 this.list.add(".inV()");
560 return (QueryBuilder<Vertex>)this;
564 public QueryBuilder<E> not(QueryBuilder<E> builder) {
565 this.list.add(".not(" + "__" + builder.getQuery() + ")");
572 public QueryBuilder<E> as(String name) {
573 this.list.add(".as('" + name + "')");
580 public QueryBuilder<E> select(String name) {
581 this.list.add(".select('" + name + "')");
590 public QueryBuilder<E> getParentQuery() {
591 return cloneQueryAtStep(parentStepIndex);
595 public QueryBuilder<E> getContainerQuery() {
596 return cloneQueryAtStep(containerStepIndex);
603 public <T2> T2 getQuery() {
604 StringBuilder sb = new StringBuilder();
606 for (String piece : this.list) {
610 return (T2)sb.toString();
617 public void markParentBoundary() {
618 parentStepIndex = stepIndex;
622 public void markContainer() {
623 this.containerStepIndex = stepIndex;
626 protected abstract QueryBuilder<E> cloneQueryAtStep(int index);
631 public Vertex getStart() {
635 protected int getParentStepIndex() {
636 return parentStepIndex;
639 protected int getContainerStepIndex() {
640 return containerStepIndex;
643 protected int getStepIndex() {
647 private void executeQuery() {
648 String queryString = "g" + Joiner.on("").join(list);
649 Map<String, Object> params = new HashMap<>();
650 if (this.start == null) {
651 params.put("g", source.V());
653 params.put("g", source.V(this.start));
655 this.completeTraversal = this.gremlinGroovy.executeTraversal(queryString, params);
658 public boolean hasNext() {
659 if (this.completeTraversal == null) {
663 return this.completeTraversal.hasNext();
668 if (this.completeTraversal == null) {
672 return (E)this.completeTraversal.next();
676 public List<E> toList() {
677 if (this.completeTraversal == null) {
681 return (List<E>)this.completeTraversal.toList();