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()]);
350 public QueryBuilder<Edge> getEdgesBetweenWithLabels(EdgeType type, String outNodeType, String inNodeType, List<String> labels) throws AAIException {
351 Introspector outObj = loader.introspectorFromName(outNodeType);
352 Introspector inObj = loader.introspectorFromName(inNodeType);
353 this.edgeQuery(type, outObj, inObj, labels);
355 return (QueryBuilder<Edge>)this;
363 public QueryBuilder<E> union(QueryBuilder... builder) {
364 GraphTraversal<Vertex, Vertex>[] traversals = new GraphTraversal[builder.length];
365 for (int i = 0; i < builder.length; i++) {
366 traversals[i] = (GraphTraversal<Vertex, Vertex>)builder[i].getQuery();
368 this.traversal.union(traversals);
378 public QueryBuilder<E> where(QueryBuilder... builder) {
379 GraphTraversal<Vertex, Vertex>[] traversals = new GraphTraversal[builder.length];
380 for (int i = 0; i < builder.length; i++) {
381 this.traversal.where((GraphTraversal<Vertex, Vertex>)builder[i].getQuery());
389 public QueryBuilder<E> store(String name) {
391 this.traversal.store(name);
398 public QueryBuilder<E> cap(String name) {
399 this.traversal.cap(name);
406 public QueryBuilder<E> unfold() {
407 this.traversal.unfold();
414 public QueryBuilder<E> dedup() {
416 this.traversal.dedup();
423 public QueryBuilder<E> emit() {
425 this.traversal.emit();
433 public QueryBuilder<E> repeat(QueryBuilder<E> builder) {
435 this.traversal.repeat((GraphTraversal<Vertex, E>)builder.getQuery());
442 public QueryBuilder<E> until(QueryBuilder<E> builder) {
443 this.traversal.until((GraphTraversal<Vertex,E>)builder.getQuery());
450 public QueryBuilder<E> groupCount() {
451 this.traversal.groupCount();
458 public QueryBuilder<E> both() {
459 this.traversal.both();
466 public QueryBuilder<E> by(String name) {
467 this.traversal.by(name);
477 public QueryBuilder<E> simplePath(){
478 this.traversal.simplePath();
484 public QueryBuilder<Edge> outE() {
485 this.traversal.outE();
487 return (QueryBuilder<Edge>)this;
491 public QueryBuilder<Edge> inE() {
492 this.traversal.inE();
494 return (QueryBuilder<Edge>)this;
498 public QueryBuilder<Vertex> outV() {
499 this.traversal.outV();
501 return (QueryBuilder<Vertex>)this;
505 public QueryBuilder<Vertex> inV() {
506 this.traversal.inV();
508 return (QueryBuilder<Vertex>)this;
512 public QueryBuilder<E> as(String name) {
513 this.traversal.as(name);
520 public QueryBuilder<E> not(QueryBuilder<E> builder) {
521 this.traversal.not(builder.getQuery());
528 public QueryBuilder<E> select(String name) {
529 this.traversal.select(name);
539 * @param outObj the out type
540 * @param inObj the in type
541 * @throws NoEdgeRuleFoundException
542 * @throws AAIException
544 private void edgeQueryToVertex(EdgeType type, Introspector outObj, Introspector inObj, List<String> labels) throws AAIException {
545 String outType = outObj.getDbName();
546 String inType = inObj.getDbName();
548 if (outObj.isContainer()) {
549 outType = outObj.getChildDBName();
551 if (inObj.isContainer()) {
552 inType = inObj.getChildDBName();
554 markParentBoundary();
555 Map<String, EdgeRule> rules;
556 if (labels == null) {
557 rules = edgeRules.getEdgeRules(type, outType, inType);
559 rules = edgeRules.getEdgeRulesWithLabels(type, outType, inType, labels);
562 final List<String> inLabels = new ArrayList<>();
563 final List<String> outLabels = new ArrayList<>();
565 rules.forEach((k, edgeRule) -> {
566 if (labels != null && !labels.contains(k)) {
569 if (edgeRule.getDirection().equals(Direction.IN)) {
570 inLabels.add(edgeRule.getLabel());
572 outLabels.add(edgeRule.getLabel());
577 if (inLabels.isEmpty() && !outLabels.isEmpty()) {
578 traversal.out(outLabels.toArray(new String[outLabels.size()]));
579 } else if (outLabels.isEmpty() && !inLabels.isEmpty()) {
580 traversal.in(inLabels.toArray(new String[inLabels.size()]));
582 traversal.union(__.out(outLabels.toArray(new String[outLabels.size()])), __.in(inLabels.toArray(new String[inLabels.size()])));
587 this.createContainerQuery(inObj);
594 * @param outObj the out type
595 * @param inObj the in type
596 * @throws NoEdgeRuleFoundException
597 * @throws AAIException
599 private void edgeQuery(EdgeType type, Introspector outObj, Introspector inObj, List<String> labels) throws AAIException {
600 String outType = outObj.getDbName();
601 String inType = inObj.getDbName();
603 if (outObj.isContainer()) {
604 outType = outObj.getChildDBName();
606 if (inObj.isContainer()) {
607 inType = inObj.getChildDBName();
610 markParentBoundary();
611 Map<String, EdgeRule> rules;
612 if (labels == null) {
613 rules = edgeRules.getEdgeRules(type, outType, inType);
615 rules = edgeRules.getEdgeRulesWithLabels(type, outType, inType, labels);
618 final List<String> inLabels = new ArrayList<>();
619 final List<String> outLabels = new ArrayList<>();
621 rules.forEach((k, edgeRule) -> {
622 if (labels != null && !labels.contains(k)) {
625 if (edgeRule.getDirection().equals(Direction.IN)) {
626 inLabels.add(edgeRule.getLabel());
628 outLabels.add(edgeRule.getLabel());
633 if (inLabels.isEmpty() && !outLabels.isEmpty()) {
634 traversal.outE(outLabels.toArray(new String[outLabels.size()]));
635 } else if (outLabels.isEmpty() && !inLabels.isEmpty()) {
636 traversal.inE(inLabels.toArray(new String[inLabels.size()]));
638 traversal.union(__.outE(outLabels.toArray(new String[outLabels.size()])), __.inE(inLabels.toArray(new String[inLabels.size()])));
643 public QueryBuilder<E> limit(long amount) {
644 traversal.limit(amount);
652 public <E2> E2 getQuery() {
653 return (E2)this.traversal;
660 public QueryBuilder<E> getParentQuery() {
662 return cloneQueryAtStep(parentStepIndex);
666 public QueryBuilder<E> getContainerQuery() {
668 if (this.parentStepIndex == 0) {
669 return removeQueryStepsBetween(0, containerStepIndex);
671 return cloneQueryAtStep(containerStepIndex);
679 public void markParentBoundary() {
680 parentStepIndex = stepIndex;
684 public void markContainer() {
685 containerStepIndex = stepIndex;
693 public Vertex getStart() {
697 protected int getParentStepIndex() {
698 return parentStepIndex;
701 protected int getContainerStepIndex() {
702 return containerStepIndex;
705 protected int getStepIndex() {
709 protected abstract QueryBuilder<E> cloneQueryAtStep(int index);
717 protected abstract QueryBuilder<E> removeQueryStepsBetween(int start, int end);
719 private void executeQuery() {
723 this.completeTraversal = traversal.asAdmin();
725 admin = source.V().asAdmin();
726 TraversalHelper.insertTraversal(admin.getEndStep(), traversal.asAdmin(), admin);
728 this.completeTraversal = (Admin<Vertex, E>) admin;
736 public boolean hasNext() {
737 if (this.completeTraversal == null) {
741 return this.completeTraversal.hasNext();
746 if (this.completeTraversal == null) {
750 return this.completeTraversal.next();
754 public List<E> toList() {
755 if (this.completeTraversal == null) {
759 return this.completeTraversal.toList();