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 java.util.ArrayList;
23 import java.util.HashMap;
24 import java.util.List;
28 import org.apache.tinkerpop.gremlin.process.traversal.dsl.graph.GraphTraversal;
29 import org.apache.tinkerpop.gremlin.process.traversal.dsl.graph.GraphTraversalSource;
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.serialization.db.EdgeRule;
40 import org.onap.aai.serialization.db.EdgeRules;
41 import org.onap.aai.serialization.db.EdgeType;
42 import org.onap.aai.serialization.db.exceptions.NoEdgeRuleFoundException;
44 import com.google.common.base.Joiner;
47 * The Class GremlinQueryBuilder.
49 public abstract class GremlinQueryBuilder<E> extends QueryBuilder<E> {
51 private EdgeRules edgeRules = EdgeRules.getInstance();
52 private GremlinGroovyShellSingleton gremlinGroovy = GremlinGroovyShellSingleton.getInstance();
53 private GraphTraversal<?, ?> completeTraversal = null;
54 protected List<String> list = null;
56 protected int parentStepIndex = 0;
57 protected int containerStepIndex = 0;
58 protected int stepIndex = 0;
61 * Instantiates a new gremlin query builder.
63 * @param loader the loader
65 public GremlinQueryBuilder(Loader loader, GraphTraversalSource source) {
66 super(loader, source);
67 list = new ArrayList<>();
71 * Instantiates a new graph gremlin builder.
73 * @param loader the loader
75 public GremlinQueryBuilder(Loader loader, GraphTraversalSource source, EdgeRules edgeRules) {
76 super(loader, source);
77 this.edgeRules = edgeRules;
78 list = new ArrayList<>();
83 * Instantiates a new gremlin query builder.
85 * @param loader the loader
86 * @param start the start
88 public GremlinQueryBuilder(Loader loader, GraphTraversalSource source, Vertex start) {
89 super(loader, source, start);
90 list = new ArrayList<>();
94 * Instantiates a new graph gremlin builder.
96 * @param loader the loader
97 * @param start the start
99 public GremlinQueryBuilder(Loader loader, GraphTraversalSource source, Vertex start, EdgeRules edgeRules) {
100 super(loader, source, start);
101 this.edgeRules = edgeRules;
102 list = new ArrayList<>();
107 public QueryBuilder<Vertex> exactMatchQuery(Introspector obj) {
108 // TODO not implemented because this is implementation is no longer used
109 this.createKeyQuery(obj);
110 this.createContainerQuery(obj);
111 return (QueryBuilder<Vertex>) this;
118 public QueryBuilder<Vertex> getVerticesByProperty(String key, Object value) {
121 if (value != null && !(value instanceof String) ) {
122 term = value.toString();
124 term = "'" + value + "'";
126 list.add(".has('" + key + "', " + term + ")");
128 return (QueryBuilder<Vertex>) this;
135 public QueryBuilder<Vertex> getVerticesByProperty(String key, List<?> values) {
138 String predicate = "P.within(#!#argument#!#)";
139 List<String> arguments = new ArrayList<>();
140 for (Object item : values) {
141 if (item != null && !(item instanceof String)) {
142 arguments.add(item.toString());
144 arguments.add("'" + item + "'");
147 String argument = Joiner.on(",").join(arguments);
148 predicate = predicate.replace("#!#argument#!#", argument);
149 list.add(".has('" + key + "', " + predicate + ")");
151 return (QueryBuilder<Vertex>) this;
158 public QueryBuilder<Vertex> getVerticesExcludeByProperty(String key, Object value) {
161 String predicate = "P.neq(#!#argument#!#)";
162 if (value != null && !(value instanceof String) ) {
163 term = value.toString();
165 term = "'" + value + "'";
167 predicate = predicate.replace("#!#argument#!#", term);
168 list.add(".has('" + key + "', " + predicate + ")");
170 return (QueryBuilder<Vertex>) this;
177 public QueryBuilder<Vertex> getVerticesExcludeByProperty(String key, List<?> values) {
180 String predicate = "P.without(#!#argument#!#)";
181 List<String> arguments = new ArrayList<>();
182 for (Object item : values) {
183 if (item != null && !(item instanceof String)) {
184 arguments.add(item.toString());
186 arguments.add("'" + item + "'");
189 String argument = Joiner.on(",").join(arguments);
190 predicate = predicate.replace("#!#argument#!#", argument);
191 list.add(".has('" + key + "', " + predicate + ")");
193 return (QueryBuilder<Vertex>) this;
200 public QueryBuilder<Vertex> getChildVerticesFromParent(String parentKey, String parentValue, String childType) {
202 String query = ".has('aai-node-type', '" + childType + "')";
204 return this.processGremlinQuery(parentKey, parentValue, query);
207 return (QueryBuilder<Vertex>) this;
214 public QueryBuilder<Vertex> getTypedVerticesByMap(String type, Map<String, String> map) {
216 for (Map.Entry<String, String> es : map.entrySet()) {
217 list.add(".has('" + es.getKey() + "', '" + es.getValue() + "')");
220 list.add(".has('aai-node-type', '" + type + "')");
222 return (QueryBuilder<Vertex>) this;
229 public QueryBuilder<Vertex> createKeyQuery(Introspector obj) {
230 Set<String> keys = obj.getKeys();
232 for (String key : keys) {
234 this.getVerticesByProperty(key, obj.<Object>getValue(key));
237 return (QueryBuilder<Vertex>) this;
241 * @throws NoEdgeRuleFoundException
242 * @throws AAIException
246 public QueryBuilder createEdgeTraversal(EdgeType type, Introspector parent, Introspector child) throws AAIException {
247 String parentName = parent.getDbName();
248 String childName = child.getDbName();
249 if (parent.isContainer()) {
250 parentName = parent.getChildDBName();
252 if (child.isContainer()) {
253 childName = child.getChildDBName();
255 this.edgeQueryToVertex(type, parentName, childName, null);
265 public QueryBuilder<Vertex> createEdgeTraversalWithLabels(EdgeType type, Introspector out, Introspector in, List<String> labels) throws AAIException {
266 String parentName = out.getDbName();
267 String childName = in.getDbName();
268 if (out.isContainer()) {
269 parentName = out.getChildDBName();
271 if (in.isContainer()) {
272 childName = in.getChildDBName();
274 this.edgeQueryToVertex(type, parentName, childName, labels);
275 return (QueryBuilder<Vertex>) this;
279 public QueryBuilder<Edge> getEdgesBetweenWithLabels(EdgeType type, String outNodeType, String inNodeType, List<String> labels) throws AAIException {
280 this.edgeQuery(type, outNodeType, inNodeType, labels);
281 return (QueryBuilder<Edge>)this;
287 * @param outType the out type
288 * @param inType the in type
289 * @throws NoEdgeRuleFoundException
290 * @throws AAIException
292 private void edgeQueryToVertex(EdgeType type, String outType, String inType, List<String> labels) throws AAIException {
293 markParentBoundary();
294 Map<String, EdgeRule> rules;
295 if (labels == null) {
296 rules = edgeRules.getEdgeRules(type, outType, inType);
298 rules = edgeRules.getEdgeRulesWithLabels(type, outType, inType, labels);
301 final List<String> inLabels = new ArrayList<>();
302 final List<String> outLabels = new ArrayList<>();
304 rules.forEach((k, edgeRule) -> {
305 if (labels != null && !labels.contains(k)) {
308 if (edgeRule.getDirection().equals(Direction.IN)) {
309 inLabels.add(edgeRule.getLabel());
311 outLabels.add(edgeRule.getLabel());
316 if(inLabels.isEmpty() && outLabels.isEmpty()) {
317 throw new NoEdgeRuleFoundException("no " + type.toString() + " edge rule between " + outType + " and " + inType );
318 } else if (inLabels.isEmpty() && !outLabels.isEmpty()) {
319 list.add(".out('" + String.join("','", outLabels) + "')");
320 } else if (outLabels.isEmpty() && !inLabels.isEmpty()) {
321 list.add(".in('" + String.join("','", inLabels) + "')");
323 list.add(".union(__.in('" + String.join("','", inLabels) + "')" + ", __.out('" + String.join("','", outLabels) + "'))");
326 list.add(".has('" + AAIProperties.NODE_TYPE + "', '" + inType + "')");
334 * @param outType the out type
335 * @param inType the in type
336 * @throws NoEdgeRuleFoundException
337 * @throws AAIException
339 private void edgeQuery(EdgeType type, String outType, String inType, List<String> labels) throws AAIException {
340 markParentBoundary();
341 Map<String, EdgeRule> rules;
342 if (labels == null) {
343 rules = edgeRules.getEdgeRules(type, outType, inType);
345 rules = edgeRules.getEdgeRulesWithLabels(type, outType, inType, labels);
348 final List<String> inLabels = new ArrayList<>();
349 final List<String> outLabels = new ArrayList<>();
351 rules.forEach((k, edgeRule) -> {
352 if (labels != null && !labels.contains(k)) {
355 if (edgeRule.getDirection().equals(Direction.IN)) {
356 inLabels.add(edgeRule.getLabel());
358 outLabels.add(edgeRule.getLabel());
363 if(inLabels.isEmpty() && outLabels.isEmpty()) {
364 throw new NoEdgeRuleFoundException("no " + type.toString() + " edge rule between " + outType + " and " + inType );
365 } else if (inLabels.isEmpty() && !outLabels.isEmpty()) {
366 list.add(".outE('" + String.join("','", outLabels) + "')");
367 } else if (outLabels.isEmpty() && !inLabels.isEmpty()) {
368 list.add(".inE('" + String.join("','", inLabels) + "')");
370 list.add(".union(__.inE('" + String.join("','", inLabels) + "')" + ", __.outE('" + String.join("','", outLabels) + "'))");
377 public QueryBuilder<E> limit(long amount) {
378 list.add(".limit(" + amount + ")");
385 public QueryBuilder<Vertex> createContainerQuery(Introspector obj) {
386 String type = obj.getChildDBName();
387 String abstractType = obj.getMetadata(ObjectMetadata.ABSTRACT);
388 if (abstractType != null) {
389 String[] inheritors = obj.getMetadata(ObjectMetadata.INHERITORS).split(",");
390 String[] wrapped = new String[inheritors.length];
391 StringBuilder command = new StringBuilder();
392 command.append("P.within(");
393 for (int i = 0; i < inheritors.length; i++) {
394 wrapped[i] = "'" + inheritors[i] + "'";
396 command.append(Joiner.on(",").join(wrapped));
398 list.add(".has('aai-node-type', " + command + ")");
401 list.add(".has('aai-node-type', '" + type + "')");
404 this.markContainer();
405 return (QueryBuilder<Vertex>) this;
409 public QueryBuilder<E> union(QueryBuilder<E>... builder) {
410 markParentBoundary();
411 String[] traversals = new String[builder.length];
412 StringBuilder command = new StringBuilder();
413 for (int i = 0; i < builder.length; i++) {
414 traversals[i] = "__" + (String)builder[i].getQuery();
416 command.append(".union(");
417 command.append(Joiner.on(",").join(traversals));
419 list.add(command.toString());
426 public QueryBuilder<E> where(QueryBuilder<E>... builder) {
427 markParentBoundary();
428 List<String> traversals = new ArrayList<>();
429 for (int i = 0; i < builder.length; i++) {
430 traversals.add(".where(__" + (String)builder[i].getQuery() + ")");
433 list.addAll(traversals);
440 public QueryBuilder<E> store(String name) {
441 this.list.add(".store('"+ name + "')");
448 public QueryBuilder<E> cap(String name) {
449 this.list.add(".cap('"+ name + "')");
456 public QueryBuilder<E> unfold() {
457 this.list.add(".unfold()");
464 public QueryBuilder<E> dedup() {
465 this.list.add(".dedup()");
472 public QueryBuilder<E> emit() {
473 this.list.add(".emit()");
480 public QueryBuilder<E> repeat(QueryBuilder<E> builder) {
481 this.list.add(".repeat(__" + builder.getQuery() + ")");
488 public QueryBuilder<E> until(QueryBuilder<E> builder) {
489 this.list.add(".until(__" + builder.getQuery() + ")");
496 public QueryBuilder<E> groupCount() {
497 this.list.add(".groupCount()");
504 public QueryBuilder<E> both() {
505 this.list.add(".both()");
512 public QueryBuilder<E> by(String name) {
513 this.list.add(".by('"+ name + "')");
523 public QueryBuilder<E> simplePath(){
524 this.list.add(".simplePath()");
530 public QueryBuilder<Edge> outE() {
531 this.list.add(".outE()");
534 return (QueryBuilder<Edge>)this;
538 public QueryBuilder<Edge> inE() {
539 this.list.add(".inE()");
542 return (QueryBuilder<Edge>)this;
546 public QueryBuilder<Vertex> outV() {
547 this.list.add(".outV()");
550 return (QueryBuilder<Vertex>)this;
554 public QueryBuilder<Vertex> inV() {
555 this.list.add(".inV()");
558 return (QueryBuilder<Vertex>)this;
562 public QueryBuilder<E> not(QueryBuilder<E> builder) {
563 this.list.add(".not(" + "__" + builder.getQuery() + ")");
570 public QueryBuilder<E> as(String name) {
571 this.list.add(".as('" + name + "')");
578 public QueryBuilder<E> select(String name) {
579 this.list.add(".select('" + name + "')");
588 public QueryBuilder<E> getParentQuery() {
589 return cloneQueryAtStep(parentStepIndex);
593 public QueryBuilder<E> getContainerQuery() {
594 return cloneQueryAtStep(containerStepIndex);
601 public <T2> T2 getQuery() {
602 StringBuilder sb = new StringBuilder();
604 for (String piece : this.list) {
608 return (T2)sb.toString();
615 public void markParentBoundary() {
616 parentStepIndex = stepIndex;
620 public void markContainer() {
621 this.containerStepIndex = stepIndex;
624 protected abstract QueryBuilder<E> cloneQueryAtStep(int index);
629 public Vertex getStart() {
633 protected int getParentStepIndex() {
634 return parentStepIndex;
637 protected int getContainerStepIndex() {
638 return containerStepIndex;
641 protected int getStepIndex() {
645 private void executeQuery() {
646 String queryString = "g" + Joiner.on("").join(list);
647 Map<String, Object> params = new HashMap<>();
648 if (this.start == null) {
649 params.put("g", source.V());
651 params.put("g", source.V(this.start));
653 this.completeTraversal = this.gremlinGroovy.executeTraversal(queryString, params);
656 public boolean hasNext() {
657 if (this.completeTraversal == null) {
661 return this.completeTraversal.hasNext();
666 if (this.completeTraversal == null) {
670 return (E)this.completeTraversal.next();
674 public List<E> toList() {
675 if (this.completeTraversal == null) {
679 return (List<E>)this.completeTraversal.toList();