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.List;
27 import java.util.Optional;
30 import org.apache.tinkerpop.gremlin.process.traversal.P;
31 import org.apache.tinkerpop.gremlin.process.traversal.Traversal;
32 import org.apache.tinkerpop.gremlin.process.traversal.Traversal.Admin;
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.dsl.graph.__;
36 import org.apache.tinkerpop.gremlin.process.traversal.util.TraversalHelper;
37 import org.apache.tinkerpop.gremlin.structure.Direction;
38 import org.apache.tinkerpop.gremlin.structure.Edge;
39 import org.apache.tinkerpop.gremlin.structure.Vertex;
40 import org.onap.aai.db.props.AAIProperties;
41 import org.onap.aai.exceptions.AAIException;
42 import org.onap.aai.introspection.Introspector;
43 import org.onap.aai.introspection.Loader;
44 import org.onap.aai.schema.enums.ObjectMetadata;
45 import org.onap.aai.schema.enums.PropertyMetadata;
46 import org.onap.aai.serialization.db.EdgeRule;
47 import org.onap.aai.serialization.db.EdgeRules;
48 import org.onap.aai.serialization.db.EdgeType;
49 import org.onap.aai.serialization.db.exceptions.NoEdgeRuleFoundException;
52 * The Class GraphTraversalBuilder.
54 public abstract class GraphTraversalBuilder<E> extends QueryBuilder<E> {
56 protected GraphTraversal<Vertex, E> traversal = null;
57 protected Admin<Vertex, E> completeTraversal = null;
58 private EdgeRules edgeRules = EdgeRules.getInstance();
60 protected int parentStepIndex = 0;
61 protected int containerStepIndex = 0;
62 protected int stepIndex = 0;
65 * Instantiates a new graph traversal builder.
67 * @param loader the loader
69 public GraphTraversalBuilder(Loader loader, GraphTraversalSource source) {
70 super(loader, source);
72 traversal = (GraphTraversal<Vertex, E>) __.<E>start();
77 * Instantiates a new graph traversal builder.
79 * @param loader the loader
81 public GraphTraversalBuilder(Loader loader, GraphTraversalSource source, EdgeRules edgeRules) {
82 super(loader, source);
83 this.edgeRules = edgeRules;
84 traversal = (GraphTraversal<Vertex, E>) __.<E>start();
89 * Instantiates a new graph traversal builder.
91 * @param loader the loader
92 * @param start the start
94 public GraphTraversalBuilder(Loader loader, GraphTraversalSource source, Vertex start) {
95 super(loader, source, start);
97 traversal = (GraphTraversal<Vertex, E>) __.__(start);
102 * Instantiates a new graph traversal builder.
104 * @param loader the loader
105 * @param start the start
107 public GraphTraversalBuilder(Loader loader, GraphTraversalSource source, Vertex start, EdgeRules edgeRules) {
108 super(loader, source, start);
109 this.edgeRules = edgeRules;
110 traversal = (GraphTraversal<Vertex, E>) __.__(start);
118 public QueryBuilder<Vertex> getVerticesByProperty(String key, Object value) {
120 // correct value call because the index is registered as an Integer
121 traversal.has(key, this.correctObjectType(value));
124 return (QueryBuilder<Vertex>) this;
131 public QueryBuilder<Vertex> getVerticesByProperty(final String key, final List<?> values) {
133 //this is because the index is registered as an Integer
134 List<Object> correctedValues = new ArrayList<>();
135 for (Object item : values) {
136 correctedValues.add(this.correctObjectType(item));
139 traversal.has(key, P.within(correctedValues));
142 return (QueryBuilder<Vertex>) this;
149 public QueryBuilder<Vertex> getVerticesExcludeByProperty(String key, Object value) {
151 // correct value call because the index is registered as an Integer
152 traversal.has(key, P.neq(this.correctObjectType(value)));
155 return (QueryBuilder<Vertex>) this;
162 public QueryBuilder<Vertex> getVerticesExcludeByProperty(final String key, final List<?> values) {
164 //this is because the index is registered as an Integer
165 List<Object> correctedValues = new ArrayList<>();
166 for (Object item : values) {
167 correctedValues.add(this.correctObjectType(item));
170 traversal.has(key, P.without(correctedValues));
173 return (QueryBuilder<Vertex>) this;
180 public QueryBuilder<Vertex> getChildVerticesFromParent(String parentKey, String parentValue, String childType) {
181 traversal.has(parentKey, parentValue).has(AAIProperties.NODE_TYPE, childType);
183 return (QueryBuilder<Vertex>) this;
190 public QueryBuilder<Vertex> getTypedVerticesByMap(String type, Map<String, String> map) {
192 for (Map.Entry<String, String> es : map.entrySet()) {
193 traversal.has(es.getKey(), es.getValue());
196 traversal.has(AAIProperties.NODE_TYPE, type);
198 return (QueryBuilder<Vertex>) this;
205 public QueryBuilder<Vertex> createKeyQuery(Introspector obj) {
206 Set<String> keys = obj.getKeys();
208 for (String key : keys) {
209 val = obj.getValue(key);
210 Optional<String> metadata = obj.getPropertyMetadata(key, PropertyMetadata.DB_ALIAS);
211 if (metadata.isPresent()) {
212 //use the db name for the field rather than the object model
213 key = metadata.get();
216 //this is because the index is registered as an Integer
217 if (val.getClass().equals(Long.class)) {
218 traversal.has(key,new Integer(val.toString()));
220 traversal.has(key, val);
225 return (QueryBuilder<Vertex>) this;
229 public QueryBuilder<Vertex> exactMatchQuery(Introspector obj) {
230 this.createKeyQuery(obj);
231 allPropertiesQuery(obj);
232 this.createContainerQuery(obj);
233 return (QueryBuilder<Vertex>) this;
236 private void allPropertiesQuery(Introspector obj) {
237 Set<String> props = obj.getProperties();
238 Set<String> keys = obj.getKeys();
240 for (String prop : props) {
241 if (obj.isSimpleType(prop) && !keys.contains(prop)) {
242 val = obj.getValue(prop);
244 Optional<String> metadata = obj.getPropertyMetadata(prop, PropertyMetadata.DB_ALIAS);
245 if (metadata.isPresent()) {
246 //use the db name for the field rather than the object model
247 prop = metadata.get();
249 //this is because the index is registered as an Integer
250 if (val.getClass().equals(Long.class)) {
251 traversal.has(prop,new Integer(val.toString()));
253 traversal.has(prop, val);
266 public QueryBuilder<Vertex> createContainerQuery(Introspector obj) {
267 String type = obj.getChildDBName();
268 String abstractType = obj.getMetadata(ObjectMetadata.ABSTRACT);
269 if (abstractType != null) {
270 String[] inheritors = obj.getMetadata(ObjectMetadata.INHERITORS).split(",");
271 traversal.has(AAIProperties.NODE_TYPE, P.within(inheritors));
273 traversal.has(AAIProperties.NODE_TYPE, type);
277 return (QueryBuilder<Vertex>) this;
281 * @throws NoEdgeRuleFoundException
282 * @throws AAIException
286 public QueryBuilder<Vertex> createEdgeTraversal(EdgeType type, Introspector parent, Introspector child) throws AAIException {
287 String isAbstractType = parent.getMetadata(ObjectMetadata.ABSTRACT);
288 if ("true".equals(isAbstractType)) {
289 markParentBoundary();
290 traversal.union(handleAbstractEdge(type, parent, child));
293 this.edgeQueryToVertex(type, parent, child, null);
295 return (QueryBuilder<Vertex>) this;
304 public QueryBuilder<Vertex> createEdgeTraversalWithLabels(EdgeType type, Introspector out, Introspector in, List<String> labels) throws AAIException {
305 this.edgeQueryToVertex(type, out, in, labels);
306 return (QueryBuilder<Vertex>) this;
310 private Traversal<Vertex, Vertex>[] handleAbstractEdge(EdgeType type, Introspector abstractParent, Introspector child) throws AAIException, NoEdgeRuleFoundException {
311 String childName = child.getDbName();
312 String inheritorMetadata = abstractParent.getMetadata(ObjectMetadata.INHERITORS);
313 String[] inheritors = inheritorMetadata.split(",");
314 List<Traversal<Vertex, Vertex>> unionTraversals = new ArrayList<>(inheritors.length);
316 for (int i = 0; i < inheritors.length; i++) {
317 String inheritor = inheritors[i];
318 if (edgeRules.hasEdgeRule(inheritor, childName) || edgeRules.hasEdgeRule(childName, inheritor)) {
319 Map<String, EdgeRule> rules = edgeRules.getEdgeRules(type, inheritor, childName);
320 GraphTraversal<Vertex, Vertex> innerTraversal = __.start();
322 final List<String> inLabels = new ArrayList<>();
323 final List<String> outLabels = new ArrayList<>();
325 rules.forEach((k,v) -> {
326 if (v.getDirection().equals(Direction.IN)) {
333 if (inLabels.isEmpty() && !outLabels.isEmpty()) {
334 innerTraversal.out(outLabels.toArray(new String[outLabels.size()]));
335 } else if (outLabels.isEmpty() && !inLabels.isEmpty()) {
336 innerTraversal.in(inLabels.toArray(new String[inLabels.size()]));
338 innerTraversal.union(__.out(outLabels.toArray(new String[outLabels.size()])), __.in(inLabels.toArray(new String[inLabels.size()])));
341 innerTraversal.has(AAIProperties.NODE_TYPE, childName);
342 unionTraversals.add(innerTraversal);
346 return unionTraversals.toArray(new Traversal[unionTraversals.size()]);
349 public QueryBuilder<Edge> getEdgesBetweenWithLabels(EdgeType type, String outNodeType, String inNodeType, List<String> labels) throws AAIException {
350 Introspector outObj = loader.introspectorFromName(outNodeType);
351 Introspector inObj = loader.introspectorFromName(inNodeType);
352 this.edgeQuery(type, outObj, inObj, labels);
354 return (QueryBuilder<Edge>)this;
362 public QueryBuilder<E> union(QueryBuilder... builder) {
363 GraphTraversal<Vertex, Vertex>[] traversals = new GraphTraversal[builder.length];
364 for (int i = 0; i < builder.length; i++) {
365 traversals[i] = (GraphTraversal<Vertex, Vertex>)builder[i].getQuery();
367 this.traversal.union(traversals);
377 public QueryBuilder<E> where(QueryBuilder... builder) {
378 GraphTraversal<Vertex, Vertex>[] traversals = new GraphTraversal[builder.length];
379 for (int i = 0; i < builder.length; i++) {
380 this.traversal.where((GraphTraversal<Vertex, Vertex>)builder[i].getQuery());
388 public QueryBuilder<E> store(String name) {
390 this.traversal.store(name);
397 public QueryBuilder<E> cap(String name) {
398 this.traversal.cap(name);
405 public QueryBuilder<E> unfold() {
406 this.traversal.unfold();
413 public QueryBuilder<E> dedup() {
415 this.traversal.dedup();
422 public QueryBuilder<E> emit() {
424 this.traversal.emit();
432 public QueryBuilder<E> repeat(QueryBuilder<E> builder) {
434 this.traversal.repeat((GraphTraversal<Vertex, E>)builder.getQuery());
441 public QueryBuilder<E> until(QueryBuilder<E> builder) {
442 this.traversal.until((GraphTraversal<Vertex,E>)builder.getQuery());
449 public QueryBuilder<E> groupCount() {
450 this.traversal.groupCount();
457 public QueryBuilder<E> both() {
458 this.traversal.both();
465 public QueryBuilder<E> by(String name) {
466 this.traversal.by(name);
476 public QueryBuilder<E> simplePath(){
477 this.traversal.simplePath();
483 public QueryBuilder<Edge> outE() {
484 this.traversal.outE();
486 return (QueryBuilder<Edge>)this;
490 public QueryBuilder<Edge> inE() {
491 this.traversal.inE();
493 return (QueryBuilder<Edge>)this;
497 public QueryBuilder<Vertex> outV() {
498 this.traversal.outV();
500 return (QueryBuilder<Vertex>)this;
504 public QueryBuilder<Vertex> inV() {
505 this.traversal.inV();
507 return (QueryBuilder<Vertex>)this;
511 public QueryBuilder<E> as(String name) {
512 this.traversal.as(name);
519 public QueryBuilder<E> not(QueryBuilder<E> builder) {
520 this.traversal.not(builder.getQuery());
527 public QueryBuilder<E> select(String name) {
528 this.traversal.select(name);
538 * @param outObj the out type
539 * @param inObj the in type
540 * @throws NoEdgeRuleFoundException
541 * @throws AAIException
543 private void edgeQueryToVertex(EdgeType type, Introspector outObj, Introspector inObj, List<String> labels) throws AAIException {
544 String outType = outObj.getDbName();
545 String inType = inObj.getDbName();
547 if (outObj.isContainer()) {
548 outType = outObj.getChildDBName();
550 if (inObj.isContainer()) {
551 inType = inObj.getChildDBName();
553 markParentBoundary();
554 Map<String, EdgeRule> rules;
555 if (labels == null) {
556 rules = edgeRules.getEdgeRules(type, outType, inType);
558 rules = edgeRules.getEdgeRulesWithLabels(type, outType, inType, labels);
561 final List<String> inLabels = new ArrayList<>();
562 final List<String> outLabels = new ArrayList<>();
564 rules.forEach((k, edgeRule) -> {
565 if (labels != null && !labels.contains(k)) {
568 if (edgeRule.getDirection().equals(Direction.IN)) {
569 inLabels.add(edgeRule.getLabel());
571 outLabels.add(edgeRule.getLabel());
576 if (inLabels.isEmpty() && !outLabels.isEmpty()) {
577 traversal.out(outLabels.toArray(new String[outLabels.size()]));
578 } else if (outLabels.isEmpty() && !inLabels.isEmpty()) {
579 traversal.in(inLabels.toArray(new String[inLabels.size()]));
581 traversal.union(__.out(outLabels.toArray(new String[outLabels.size()])), __.in(inLabels.toArray(new String[inLabels.size()])));
586 this.createContainerQuery(inObj);
593 * @param outObj the out type
594 * @param inObj the in type
595 * @throws NoEdgeRuleFoundException
596 * @throws AAIException
598 private void edgeQuery(EdgeType type, Introspector outObj, Introspector inObj, List<String> labels) throws AAIException {
599 String outType = outObj.getDbName();
600 String inType = inObj.getDbName();
602 if (outObj.isContainer()) {
603 outType = outObj.getChildDBName();
605 if (inObj.isContainer()) {
606 inType = inObj.getChildDBName();
609 markParentBoundary();
610 Map<String, EdgeRule> rules;
611 if (labels == null) {
612 rules = edgeRules.getEdgeRules(type, outType, inType);
614 rules = edgeRules.getEdgeRulesWithLabels(type, outType, inType, labels);
617 final List<String> inLabels = new ArrayList<>();
618 final List<String> outLabels = new ArrayList<>();
620 rules.forEach((k, edgeRule) -> {
621 if (labels != null && !labels.contains(k)) {
624 if (edgeRule.getDirection().equals(Direction.IN)) {
625 inLabels.add(edgeRule.getLabel());
627 outLabels.add(edgeRule.getLabel());
632 if (inLabels.isEmpty() && !outLabels.isEmpty()) {
633 traversal.outE(outLabels.toArray(new String[outLabels.size()]));
634 } else if (outLabels.isEmpty() && !inLabels.isEmpty()) {
635 traversal.inE(inLabels.toArray(new String[inLabels.size()]));
637 traversal.union(__.outE(outLabels.toArray(new String[outLabels.size()])), __.inE(inLabels.toArray(new String[inLabels.size()])));
642 public QueryBuilder<E> limit(long amount) {
643 traversal.limit(amount);
651 public <E2> E2 getQuery() {
652 return (E2)this.traversal;
659 public QueryBuilder<E> getParentQuery() {
661 return cloneQueryAtStep(parentStepIndex);
665 public QueryBuilder<E> getContainerQuery() {
667 if (this.parentStepIndex == 0) {
668 return removeQueryStepsBetween(0, containerStepIndex);
670 return cloneQueryAtStep(containerStepIndex);
678 public void markParentBoundary() {
679 parentStepIndex = stepIndex;
683 public void markContainer() {
684 containerStepIndex = stepIndex;
692 public Vertex getStart() {
696 protected int getParentStepIndex() {
697 return parentStepIndex;
700 protected int getContainerStepIndex() {
701 return containerStepIndex;
704 protected int getStepIndex() {
708 protected abstract QueryBuilder<E> cloneQueryAtStep(int index);
716 protected abstract QueryBuilder<E> removeQueryStepsBetween(int start, int end);
718 private void executeQuery() {
722 this.completeTraversal = traversal.asAdmin();
724 admin = source.V().asAdmin();
725 TraversalHelper.insertTraversal(admin.getEndStep(), traversal.asAdmin(), admin);
727 this.completeTraversal = (Admin<Vertex, E>) admin;
735 public boolean hasNext() {
736 if (this.completeTraversal == null) {
740 return this.completeTraversal.hasNext();
745 if (this.completeTraversal == null) {
749 return this.completeTraversal.next();
753 public List<E> toList() {
754 if (this.completeTraversal == null) {
758 return this.completeTraversal.toList();