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.List;
25 import java.util.Optional;
28 import org.apache.tinkerpop.gremlin.process.traversal.P;
29 import org.apache.tinkerpop.gremlin.process.traversal.Traversal;
30 import org.apache.tinkerpop.gremlin.process.traversal.Traversal.Admin;
31 import org.apache.tinkerpop.gremlin.process.traversal.dsl.graph.GraphTraversal;
32 import org.apache.tinkerpop.gremlin.process.traversal.dsl.graph.GraphTraversalSource;
33 import org.apache.tinkerpop.gremlin.process.traversal.dsl.graph.__;
34 import org.apache.tinkerpop.gremlin.process.traversal.util.TraversalHelper;
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.exceptions.AAIException;
40 import org.onap.aai.introspection.Introspector;
41 import org.onap.aai.introspection.Loader;
42 import org.onap.aai.schema.enums.ObjectMetadata;
43 import org.onap.aai.schema.enums.PropertyMetadata;
44 import org.onap.aai.serialization.db.EdgeRule;
45 import org.onap.aai.serialization.db.EdgeRules;
46 import org.onap.aai.serialization.db.EdgeType;
47 import org.onap.aai.serialization.db.exceptions.NoEdgeRuleFoundException;
50 * The Class GraphTraversalBuilder.
52 public abstract class GraphTraversalBuilder<E> extends QueryBuilder<E> {
54 protected GraphTraversal<Vertex, E> traversal = null;
55 protected Admin<Vertex, E> completeTraversal = null;
56 private EdgeRules edgeRules = EdgeRules.getInstance();
58 protected int parentStepIndex = 0;
59 protected int containerStepIndex = 0;
60 protected int stepIndex = 0;
63 * Instantiates a new graph traversal builder.
65 * @param loader the loader
67 public GraphTraversalBuilder(Loader loader, GraphTraversalSource source) {
68 super(loader, source);
70 traversal = (GraphTraversal<Vertex, E>) __.<E>start();
75 * Instantiates a new graph traversal builder.
77 * @param loader the loader
79 public GraphTraversalBuilder(Loader loader, GraphTraversalSource source, EdgeRules edgeRules) {
80 super(loader, source);
81 this.edgeRules = edgeRules;
82 traversal = (GraphTraversal<Vertex, E>) __.<E>start();
87 * Instantiates a new graph traversal builder.
89 * @param loader the loader
90 * @param start the start
92 public GraphTraversalBuilder(Loader loader, GraphTraversalSource source, Vertex start) {
93 super(loader, source, start);
95 traversal = (GraphTraversal<Vertex, E>) __.__(start);
100 * Instantiates a new graph traversal builder.
102 * @param loader the loader
103 * @param start the start
105 public GraphTraversalBuilder(Loader loader, GraphTraversalSource source, Vertex start, EdgeRules edgeRules) {
106 super(loader, source, start);
107 this.edgeRules = edgeRules;
108 traversal = (GraphTraversal<Vertex, E>) __.__(start);
116 public QueryBuilder<Vertex> getVerticesByProperty(String key, Object value) {
118 // correct value call because the index is registered as an Integer
119 traversal.has(key, this.correctObjectType(value));
122 return (QueryBuilder<Vertex>) this;
129 public QueryBuilder<Vertex> getVerticesByProperty(final String key, final List<?> values) {
131 //this is because the index is registered as an Integer
132 List<Object> correctedValues = new ArrayList<>();
133 for (Object item : values) {
134 correctedValues.add(this.correctObjectType(item));
137 traversal.has(key, P.within(correctedValues));
140 return (QueryBuilder<Vertex>) this;
147 public QueryBuilder<Vertex> getVerticesExcludeByProperty(String key, Object value) {
149 // correct value call because the index is registered as an Integer
150 traversal.has(key, P.neq(this.correctObjectType(value)));
153 return (QueryBuilder<Vertex>) this;
160 public QueryBuilder<Vertex> getVerticesExcludeByProperty(final String key, final List<?> values) {
162 //this is because the index is registered as an Integer
163 List<Object> correctedValues = new ArrayList<>();
164 for (Object item : values) {
165 correctedValues.add(this.correctObjectType(item));
168 traversal.has(key, P.without(correctedValues));
171 return (QueryBuilder<Vertex>) this;
178 public QueryBuilder<Vertex> getChildVerticesFromParent(String parentKey, String parentValue, String childType) {
179 traversal.has(parentKey, parentValue).has(AAIProperties.NODE_TYPE, childType);
181 return (QueryBuilder<Vertex>) this;
188 public QueryBuilder<Vertex> getTypedVerticesByMap(String type, Map<String, String> map) {
190 for (Map.Entry<String, String> es : map.entrySet()) {
191 traversal.has(es.getKey(), es.getValue());
194 traversal.has(AAIProperties.NODE_TYPE, type);
196 return (QueryBuilder<Vertex>) this;
203 public QueryBuilder<Vertex> createKeyQuery(Introspector obj) {
204 Set<String> keys = obj.getKeys();
206 for (String key : keys) {
207 val = obj.getValue(key);
208 Optional<String> metadata = obj.getPropertyMetadata(key, PropertyMetadata.DB_ALIAS);
209 if (metadata.isPresent()) {
210 //use the db name for the field rather than the object model
211 key = metadata.get();
214 //this is because the index is registered as an Integer
215 if (val.getClass().equals(Long.class)) {
216 traversal.has(key,new Integer(val.toString()));
218 traversal.has(key, val);
223 return (QueryBuilder<Vertex>) this;
227 public QueryBuilder<Vertex> exactMatchQuery(Introspector obj) {
228 this.createKeyQuery(obj);
229 allPropertiesQuery(obj);
230 this.createContainerQuery(obj);
231 return (QueryBuilder<Vertex>) this;
234 private void allPropertiesQuery(Introspector obj) {
235 Set<String> props = obj.getProperties();
236 Set<String> keys = obj.getKeys();
238 for (String prop : props) {
239 if (obj.isSimpleType(prop) && !keys.contains(prop)) {
240 val = obj.getValue(prop);
242 Optional<String> metadata = obj.getPropertyMetadata(prop, PropertyMetadata.DB_ALIAS);
243 if (metadata.isPresent()) {
244 //use the db name for the field rather than the object model
245 prop = metadata.get();
247 //this is because the index is registered as an Integer
248 if (val.getClass().equals(Long.class)) {
249 traversal.has(prop,new Integer(val.toString()));
251 traversal.has(prop, val);
264 public QueryBuilder<Vertex> createContainerQuery(Introspector obj) {
265 String type = obj.getChildDBName();
266 String abstractType = obj.getMetadata(ObjectMetadata.ABSTRACT);
267 if (abstractType != null) {
268 String[] inheritors = obj.getMetadata(ObjectMetadata.INHERITORS).split(",");
269 traversal.has(AAIProperties.NODE_TYPE, P.within(inheritors));
271 traversal.has(AAIProperties.NODE_TYPE, type);
275 return (QueryBuilder<Vertex>) this;
279 * @throws NoEdgeRuleFoundException
280 * @throws AAIException
284 public QueryBuilder<Vertex> createEdgeTraversal(EdgeType type, Introspector parent, Introspector child) throws AAIException {
285 String isAbstractType = parent.getMetadata(ObjectMetadata.ABSTRACT);
286 if ("true".equals(isAbstractType)) {
287 markParentBoundary();
288 traversal.union(handleAbstractEdge(type, parent, child));
291 this.edgeQueryToVertex(type, parent, child, null);
293 return (QueryBuilder<Vertex>) this;
302 public QueryBuilder<Vertex> createEdgeTraversalWithLabels(EdgeType type, Introspector out, Introspector in, List<String> labels) throws AAIException {
303 this.edgeQueryToVertex(type, out, in, labels);
304 return (QueryBuilder<Vertex>) this;
308 private Traversal<Vertex, Vertex>[] handleAbstractEdge(EdgeType type, Introspector abstractParent, Introspector child) throws AAIException, NoEdgeRuleFoundException {
309 String childName = child.getDbName();
310 String inheritorMetadata = abstractParent.getMetadata(ObjectMetadata.INHERITORS);
311 String[] inheritors = inheritorMetadata.split(",");
312 List<Traversal<Vertex, Vertex>> unionTraversals = new ArrayList<>(inheritors.length);
314 for (int i = 0; i < inheritors.length; i++) {
315 String inheritor = inheritors[i];
316 if (edgeRules.hasEdgeRule(inheritor, childName) || edgeRules.hasEdgeRule(childName, inheritor)) {
317 Map<String, EdgeRule> rules = edgeRules.getEdgeRules(type, inheritor, childName);
318 GraphTraversal<Vertex, Vertex> innerTraversal = __.start();
320 final List<String> inLabels = new ArrayList<>();
321 final List<String> outLabels = new ArrayList<>();
323 rules.forEach((k,v) -> {
324 if (v.getDirection().equals(Direction.IN)) {
331 if (inLabels.isEmpty() && !outLabels.isEmpty()) {
332 innerTraversal.out(outLabels.toArray(new String[outLabels.size()]));
333 } else if (outLabels.isEmpty() && !inLabels.isEmpty()) {
334 innerTraversal.in(inLabels.toArray(new String[inLabels.size()]));
336 innerTraversal.union(__.out(outLabels.toArray(new String[outLabels.size()])), __.in(inLabels.toArray(new String[inLabels.size()])));
339 innerTraversal.has(AAIProperties.NODE_TYPE, childName);
340 unionTraversals.add(innerTraversal);
344 return unionTraversals.toArray(new Traversal[unionTraversals.size()]);
348 public QueryBuilder<Edge> getEdgesBetweenWithLabels(EdgeType type, String outNodeType, String inNodeType, List<String> labels) throws AAIException {
349 Introspector outObj = loader.introspectorFromName(outNodeType);
350 Introspector inObj = loader.introspectorFromName(inNodeType);
351 this.edgeQuery(type, outObj, inObj, labels);
353 return (QueryBuilder<Edge>)this;
361 public QueryBuilder<E> union(QueryBuilder... builder) {
362 GraphTraversal<Vertex, Vertex>[] traversals = new GraphTraversal[builder.length];
363 for (int i = 0; i < builder.length; i++) {
364 traversals[i] = (GraphTraversal<Vertex, Vertex>)builder[i].getQuery();
366 this.traversal.union(traversals);
376 public QueryBuilder<E> where(QueryBuilder... builder) {
377 GraphTraversal<Vertex, Vertex>[] traversals = new GraphTraversal[builder.length];
378 for (int i = 0; i < builder.length; i++) {
379 this.traversal.where((GraphTraversal<Vertex, Vertex>)builder[i].getQuery());
387 public QueryBuilder<E> store(String name) {
389 this.traversal.store(name);
396 public QueryBuilder<E> cap(String name) {
397 this.traversal.cap(name);
404 public QueryBuilder<E> unfold() {
405 this.traversal.unfold();
412 public QueryBuilder<E> dedup() {
414 this.traversal.dedup();
421 public QueryBuilder<E> emit() {
423 this.traversal.emit();
431 public QueryBuilder<E> repeat(QueryBuilder<E> builder) {
433 this.traversal.repeat((GraphTraversal<Vertex, E>)builder.getQuery());
440 public QueryBuilder<E> until(QueryBuilder<E> builder) {
441 this.traversal.until((GraphTraversal<Vertex,E>)builder.getQuery());
448 public QueryBuilder<E> groupCount() {
449 this.traversal.groupCount();
456 public QueryBuilder<E> both() {
457 this.traversal.both();
464 public QueryBuilder<E> by(String name) {
465 this.traversal.by(name);
475 public QueryBuilder<E> simplePath(){
476 this.traversal.simplePath();
482 public QueryBuilder<Edge> outE() {
483 this.traversal.outE();
485 return (QueryBuilder<Edge>)this;
489 public QueryBuilder<Edge> inE() {
490 this.traversal.inE();
492 return (QueryBuilder<Edge>)this;
496 public QueryBuilder<Vertex> outV() {
497 this.traversal.outV();
499 return (QueryBuilder<Vertex>)this;
503 public QueryBuilder<Vertex> inV() {
504 this.traversal.inV();
506 return (QueryBuilder<Vertex>)this;
510 public QueryBuilder<E> as(String name) {
511 this.traversal.as(name);
518 public QueryBuilder<E> not(QueryBuilder<E> builder) {
519 this.traversal.not(builder.getQuery());
526 public QueryBuilder<E> select(String name) {
527 this.traversal.select(name);
537 * @param outObj the out type
538 * @param inObj the in type
539 * @throws NoEdgeRuleFoundException
540 * @throws AAIException
542 private void edgeQueryToVertex(EdgeType type, Introspector outObj, Introspector inObj, List<String> labels) throws AAIException {
543 String outType = outObj.getDbName();
544 String inType = inObj.getDbName();
546 if (outObj.isContainer()) {
547 outType = outObj.getChildDBName();
549 if (inObj.isContainer()) {
550 inType = inObj.getChildDBName();
552 markParentBoundary();
553 Map<String, EdgeRule> rules;
554 if (labels == null) {
555 rules = edgeRules.getEdgeRules(type, outType, inType);
557 rules = edgeRules.getEdgeRulesWithLabels(type, outType, inType, labels);
560 final List<String> inLabels = new ArrayList<>();
561 final List<String> outLabels = new ArrayList<>();
563 rules.forEach((k, edgeRule) -> {
564 if (labels != null && !labels.contains(k)) {
567 if (edgeRule.getDirection().equals(Direction.IN)) {
568 inLabels.add(edgeRule.getLabel());
570 outLabels.add(edgeRule.getLabel());
575 if (inLabels.isEmpty() && !outLabels.isEmpty()) {
576 traversal.out(outLabels.toArray(new String[outLabels.size()]));
577 } else if (outLabels.isEmpty() && !inLabels.isEmpty()) {
578 traversal.in(inLabels.toArray(new String[inLabels.size()]));
580 traversal.union(__.out(outLabels.toArray(new String[outLabels.size()])), __.in(inLabels.toArray(new String[inLabels.size()])));
585 this.createContainerQuery(inObj);
592 * @param outObj the out type
593 * @param inObj the in type
594 * @throws NoEdgeRuleFoundException
595 * @throws AAIException
597 private void edgeQuery(EdgeType type, Introspector outObj, Introspector inObj, List<String> labels) throws AAIException {
598 String outType = outObj.getDbName();
599 String inType = inObj.getDbName();
601 if (outObj.isContainer()) {
602 outType = outObj.getChildDBName();
604 if (inObj.isContainer()) {
605 inType = inObj.getChildDBName();
608 markParentBoundary();
609 Map<String, EdgeRule> rules;
610 if (labels == null) {
611 rules = edgeRules.getEdgeRules(type, outType, inType);
613 rules = edgeRules.getEdgeRulesWithLabels(type, outType, inType, labels);
616 final List<String> inLabels = new ArrayList<>();
617 final List<String> outLabels = new ArrayList<>();
619 rules.forEach((k, edgeRule) -> {
620 if (labels != null && !labels.contains(k)) {
623 if (edgeRule.getDirection().equals(Direction.IN)) {
624 inLabels.add(edgeRule.getLabel());
626 outLabels.add(edgeRule.getLabel());
631 if (inLabels.isEmpty() && !outLabels.isEmpty()) {
632 traversal.outE(outLabels.toArray(new String[outLabels.size()]));
633 } else if (outLabels.isEmpty() && !inLabels.isEmpty()) {
634 traversal.inE(inLabels.toArray(new String[inLabels.size()]));
636 traversal.union(__.outE(outLabels.toArray(new String[outLabels.size()])), __.inE(inLabels.toArray(new String[inLabels.size()])));
641 public QueryBuilder<E> limit(long amount) {
642 traversal.limit(amount);
650 public <E2> E2 getQuery() {
651 return (E2)this.traversal;
658 public QueryBuilder<E> getParentQuery() {
660 return cloneQueryAtStep(parentStepIndex);
664 public QueryBuilder<E> getContainerQuery() {
666 if (this.parentStepIndex == 0) {
667 return removeQueryStepsBetween(0, containerStepIndex);
669 return cloneQueryAtStep(containerStepIndex);
677 public void markParentBoundary() {
678 parentStepIndex = stepIndex;
682 public void markContainer() {
683 containerStepIndex = stepIndex;
691 public Vertex getStart() {
695 protected int getParentStepIndex() {
696 return parentStepIndex;
699 protected int getContainerStepIndex() {
700 return containerStepIndex;
703 protected int getStepIndex() {
707 protected abstract QueryBuilder<E> cloneQueryAtStep(int index);
715 protected abstract QueryBuilder<E> removeQueryStepsBetween(int start, int end);
717 private void executeQuery() {
721 this.completeTraversal = traversal.asAdmin();
723 admin = source.V().asAdmin();
724 TraversalHelper.insertTraversal(admin.getEndStep(), traversal.asAdmin(), admin);
726 this.completeTraversal = (Admin<Vertex, E>) admin;
734 public boolean hasNext() {
735 if (this.completeTraversal == null) {
739 return this.completeTraversal.hasNext();
744 if (this.completeTraversal == null) {
748 return this.completeTraversal.next();
752 public List<E> toList() {
753 if (this.completeTraversal == null) {
757 return this.completeTraversal.toList();