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.Path;
30 import org.apache.tinkerpop.gremlin.process.traversal.Traversal;
31 import org.apache.tinkerpop.gremlin.process.traversal.Traversal.Admin;
32 import org.apache.tinkerpop.gremlin.process.traversal.dsl.graph.GraphTraversal;
33 import org.apache.tinkerpop.gremlin.process.traversal.dsl.graph.GraphTraversalSource;
34 import org.apache.tinkerpop.gremlin.process.traversal.dsl.graph.__;
35 import org.apache.tinkerpop.gremlin.process.traversal.util.TraversalHelper;
36 import org.apache.tinkerpop.gremlin.structure.Direction;
37 import org.apache.tinkerpop.gremlin.structure.Edge;
38 import org.apache.tinkerpop.gremlin.structure.Vertex;
39 import org.onap.aai.db.props.AAIProperties;
40 import org.onap.aai.exceptions.AAIException;
41 import org.onap.aai.introspection.Introspector;
42 import org.onap.aai.introspection.Loader;
43 import org.onap.aai.schema.enums.ObjectMetadata;
44 import org.onap.aai.schema.enums.PropertyMetadata;
45 import org.onap.aai.serialization.db.EdgeRule;
46 import org.onap.aai.serialization.db.EdgeRules;
47 import org.onap.aai.serialization.db.EdgeType;
48 import org.onap.aai.serialization.db.exceptions.NoEdgeRuleFoundException;
51 * The Class GraphTraversalBuilder.
53 public abstract class GraphTraversalBuilder<E> extends QueryBuilder<E> {
55 protected GraphTraversal<Vertex, E> traversal = null;
56 protected Admin<Vertex, E> completeTraversal = null;
57 private EdgeRules edgeRules = EdgeRules.getInstance();
59 protected int parentStepIndex = 0;
60 protected int containerStepIndex = 0;
61 protected int stepIndex = 0;
64 * Instantiates a new graph traversal builder.
66 * @param loader the loader
68 public GraphTraversalBuilder(Loader loader, GraphTraversalSource source) {
69 super(loader, source);
71 traversal = (GraphTraversal<Vertex, E>) __.<E>start();
76 * Instantiates a new graph traversal builder.
78 * @param loader the loader
80 public GraphTraversalBuilder(Loader loader, GraphTraversalSource source, EdgeRules edgeRules) {
81 super(loader, source);
82 this.edgeRules = edgeRules;
83 traversal = (GraphTraversal<Vertex, E>) __.<E>start();
88 * Instantiates a new graph traversal builder.
90 * @param loader the loader
91 * @param start the start
93 public GraphTraversalBuilder(Loader loader, GraphTraversalSource source, Vertex start) {
94 super(loader, source, start);
96 traversal = (GraphTraversal<Vertex, E>) __.__(start);
101 * Instantiates a new graph traversal builder.
103 * @param loader the loader
104 * @param start the start
106 public GraphTraversalBuilder(Loader loader, GraphTraversalSource source, Vertex start, EdgeRules edgeRules) {
107 super(loader, source, start);
108 this.edgeRules = edgeRules;
109 traversal = (GraphTraversal<Vertex, E>) __.__(start);
117 public QueryBuilder<Vertex> getVerticesByProperty(String key, Object value) {
119 // correct value call because the index is registered as an Integer
120 traversal.has(key, this.correctObjectType(value));
123 return (QueryBuilder<Vertex>) this;
130 public QueryBuilder<Vertex> getVerticesByProperty(final String key, final List<?> values) {
132 //this is because the index is registered as an Integer
133 List<Object> correctedValues = new ArrayList<>();
134 for (Object item : values) {
135 correctedValues.add(this.correctObjectType(item));
138 traversal.has(key, P.within(correctedValues));
141 return (QueryBuilder<Vertex>) this;
148 public QueryBuilder<Vertex> getVerticesExcludeByProperty(String key, Object value) {
150 // correct value call because the index is registered as an Integer
151 traversal.has(key, P.neq(this.correctObjectType(value)));
154 return (QueryBuilder<Vertex>) this;
161 public QueryBuilder<Vertex> getVerticesExcludeByProperty(final String key, final List<?> values) {
163 //this is because the index is registered as an Integer
164 List<Object> correctedValues = new ArrayList<>();
165 for (Object item : values) {
166 correctedValues.add(this.correctObjectType(item));
169 traversal.has(key, P.without(correctedValues));
172 return (QueryBuilder<Vertex>) this;
179 public QueryBuilder<Vertex> getChildVerticesFromParent(String parentKey, String parentValue, String childType) {
180 traversal.has(parentKey, parentValue).has(AAIProperties.NODE_TYPE, childType);
182 return (QueryBuilder<Vertex>) this;
189 public QueryBuilder<Vertex> getTypedVerticesByMap(String type, Map<String, String> map) {
191 for (Map.Entry<String, String> es : map.entrySet()) {
192 traversal.has(es.getKey(), es.getValue());
195 traversal.has(AAIProperties.NODE_TYPE, type);
197 return (QueryBuilder<Vertex>) this;
204 public QueryBuilder<Vertex> createKeyQuery(Introspector obj) {
205 Set<String> keys = obj.getKeys();
207 for (String key : keys) {
208 val = obj.getValue(key);
209 Optional<String> metadata = obj.getPropertyMetadata(key, PropertyMetadata.DB_ALIAS);
210 if (metadata.isPresent()) {
211 //use the db name for the field rather than the object model
212 key = metadata.get();
215 //this is because the index is registered as an Integer
216 if (val.getClass().equals(Long.class)) {
217 traversal.has(key,new Integer(val.toString()));
219 traversal.has(key, val);
224 return (QueryBuilder<Vertex>) this;
228 public QueryBuilder<Vertex> exactMatchQuery(Introspector obj) {
229 this.createKeyQuery(obj);
230 allPropertiesQuery(obj);
231 this.createContainerQuery(obj);
232 return (QueryBuilder<Vertex>) this;
235 private void allPropertiesQuery(Introspector obj) {
236 Set<String> props = obj.getProperties();
237 Set<String> keys = obj.getKeys();
239 for (String prop : props) {
240 if (obj.isSimpleType(prop) && !keys.contains(prop)) {
241 val = obj.getValue(prop);
243 Optional<String> metadata = obj.getPropertyMetadata(prop, PropertyMetadata.DB_ALIAS);
244 if (metadata.isPresent()) {
245 //use the db name for the field rather than the object model
246 prop = metadata.get();
248 //this is because the index is registered as an Integer
249 if (val.getClass().equals(Long.class)) {
250 traversal.has(prop,new Integer(val.toString()));
252 traversal.has(prop, val);
265 public QueryBuilder<Vertex> createContainerQuery(Introspector obj) {
266 String type = obj.getChildDBName();
267 String abstractType = obj.getMetadata(ObjectMetadata.ABSTRACT);
268 if (abstractType != null) {
269 String[] inheritors = obj.getMetadata(ObjectMetadata.INHERITORS).split(",");
270 traversal.has(AAIProperties.NODE_TYPE, P.within(inheritors));
272 traversal.has(AAIProperties.NODE_TYPE, type);
276 return (QueryBuilder<Vertex>) this;
280 * @throws NoEdgeRuleFoundException
281 * @throws AAIException
285 public QueryBuilder<Vertex> createEdgeTraversal(EdgeType type, Introspector parent, Introspector child) throws AAIException {
286 String isAbstractType = parent.getMetadata(ObjectMetadata.ABSTRACT);
287 if ("true".equals(isAbstractType)) {
288 markParentBoundary();
289 traversal.union(handleAbstractEdge(type, parent, child));
292 this.edgeQueryToVertex(type, parent, child, null);
294 return (QueryBuilder<Vertex>) this;
303 public QueryBuilder<Vertex> createEdgeTraversalWithLabels(EdgeType type, Introspector out, Introspector in, List<String> labels) throws AAIException {
304 this.edgeQueryToVertex(type, out, in, labels);
305 return (QueryBuilder<Vertex>) this;
309 private Traversal<Vertex, Vertex>[] handleAbstractEdge(EdgeType type, Introspector abstractParent, Introspector child) throws AAIException, NoEdgeRuleFoundException {
310 String childName = child.getDbName();
311 String inheritorMetadata = abstractParent.getMetadata(ObjectMetadata.INHERITORS);
312 String[] inheritors = inheritorMetadata.split(",");
313 List<Traversal<Vertex, Vertex>> unionTraversals = new ArrayList<>(inheritors.length);
315 for (int i = 0; i < inheritors.length; i++) {
316 String inheritor = inheritors[i];
317 if (edgeRules.hasEdgeRule(inheritor, childName) || edgeRules.hasEdgeRule(childName, inheritor)) {
318 Map<String, EdgeRule> rules = edgeRules.getEdgeRules(type, inheritor, childName);
319 GraphTraversal<Vertex, Vertex> innerTraversal = __.start();
321 final List<String> inLabels = new ArrayList<>();
322 final List<String> outLabels = new ArrayList<>();
324 rules.forEach((k,v) -> {
325 if (v.getDirection().equals(Direction.IN)) {
332 if (inLabels.isEmpty() && !outLabels.isEmpty()) {
333 innerTraversal.out(outLabels.toArray(new String[outLabels.size()]));
334 } else if (outLabels.isEmpty() && !inLabels.isEmpty()) {
335 innerTraversal.in(inLabels.toArray(new String[inLabels.size()]));
337 innerTraversal.union(__.out(outLabels.toArray(new String[outLabels.size()])), __.in(inLabels.toArray(new String[inLabels.size()])));
340 innerTraversal.has(AAIProperties.NODE_TYPE, childName);
341 unionTraversals.add(innerTraversal);
345 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();
486 public QueryBuilder<Path> path(){
487 this.traversal.path();
489 return (QueryBuilder<Path>)this;
493 public QueryBuilder<Edge> outE() {
494 this.traversal.outE();
496 return (QueryBuilder<Edge>)this;
500 public QueryBuilder<Edge> inE() {
501 this.traversal.inE();
503 return (QueryBuilder<Edge>)this;
507 public QueryBuilder<Vertex> outV() {
508 this.traversal.outV();
510 return (QueryBuilder<Vertex>)this;
514 public QueryBuilder<Vertex> inV() {
515 this.traversal.inV();
517 return (QueryBuilder<Vertex>)this;
521 public QueryBuilder<E> as(String name) {
522 this.traversal.as(name);
529 public QueryBuilder<E> not(QueryBuilder<E> builder) {
530 this.traversal.not(builder.getQuery());
537 public QueryBuilder<E> select(String name) {
538 this.traversal.select(name);
548 * @param outObj the out type
549 * @param inObj the in type
550 * @throws NoEdgeRuleFoundException
551 * @throws AAIException
553 private void edgeQueryToVertex(EdgeType type, Introspector outObj, Introspector inObj, List<String> labels) throws AAIException {
554 String outType = outObj.getDbName();
555 String inType = inObj.getDbName();
557 if (outObj.isContainer()) {
558 outType = outObj.getChildDBName();
560 if (inObj.isContainer()) {
561 inType = inObj.getChildDBName();
563 markParentBoundary();
564 Map<String, EdgeRule> rules;
565 if (labels == null) {
566 rules = edgeRules.getEdgeRules(type, outType, inType);
568 rules = edgeRules.getEdgeRulesWithLabels(type, outType, inType, labels);
571 final List<String> inLabels = new ArrayList<>();
572 final List<String> outLabels = new ArrayList<>();
574 rules.forEach((k, edgeRule) -> {
575 if (labels != null && !labels.contains(k)) {
578 if (edgeRule.getDirection().equals(Direction.IN)) {
579 inLabels.add(edgeRule.getLabel());
581 outLabels.add(edgeRule.getLabel());
586 if (inLabels.isEmpty() && !outLabels.isEmpty()) {
587 traversal.out(outLabels.toArray(new String[outLabels.size()]));
588 } else if (outLabels.isEmpty() && !inLabels.isEmpty()) {
589 traversal.in(inLabels.toArray(new String[inLabels.size()]));
591 traversal.union(__.out(outLabels.toArray(new String[outLabels.size()])), __.in(inLabels.toArray(new String[inLabels.size()])));
596 this.createContainerQuery(inObj);
603 * @param outObj the out type
604 * @param inObj the in type
605 * @throws NoEdgeRuleFoundException
606 * @throws AAIException
608 private void edgeQuery(EdgeType type, Introspector outObj, Introspector inObj, List<String> labels) throws AAIException {
609 String outType = outObj.getDbName();
610 String inType = inObj.getDbName();
612 if (outObj.isContainer()) {
613 outType = outObj.getChildDBName();
615 if (inObj.isContainer()) {
616 inType = inObj.getChildDBName();
619 markParentBoundary();
620 Map<String, EdgeRule> rules;
621 if (labels == null) {
622 rules = edgeRules.getEdgeRules(type, outType, inType);
624 rules = edgeRules.getEdgeRulesWithLabels(type, outType, inType, labels);
627 final List<String> inLabels = new ArrayList<>();
628 final List<String> outLabels = new ArrayList<>();
630 rules.forEach((k, edgeRule) -> {
631 if (labels != null && !labels.contains(k)) {
634 if (edgeRule.getDirection().equals(Direction.IN)) {
635 inLabels.add(edgeRule.getLabel());
637 outLabels.add(edgeRule.getLabel());
642 if (inLabels.isEmpty() && !outLabels.isEmpty()) {
643 traversal.outE(outLabels.toArray(new String[outLabels.size()]));
644 } else if (outLabels.isEmpty() && !inLabels.isEmpty()) {
645 traversal.inE(inLabels.toArray(new String[inLabels.size()]));
647 traversal.union(__.outE(outLabels.toArray(new String[outLabels.size()])), __.inE(inLabels.toArray(new String[inLabels.size()])));
652 public QueryBuilder<E> limit(long amount) {
653 traversal.limit(amount);
661 public <E2> E2 getQuery() {
662 return (E2)this.traversal;
669 public QueryBuilder<E> getParentQuery() {
671 return cloneQueryAtStep(parentStepIndex);
675 public QueryBuilder<E> getContainerQuery() {
677 if (this.parentStepIndex == 0) {
678 return removeQueryStepsBetween(0, containerStepIndex);
680 return cloneQueryAtStep(containerStepIndex);
688 public void markParentBoundary() {
689 parentStepIndex = stepIndex;
693 public void markContainer() {
694 containerStepIndex = stepIndex;
702 public Vertex getStart() {
706 protected int getParentStepIndex() {
707 return parentStepIndex;
710 protected int getContainerStepIndex() {
711 return containerStepIndex;
714 protected int getStepIndex() {
718 protected abstract QueryBuilder<E> cloneQueryAtStep(int index);
726 protected abstract QueryBuilder<E> removeQueryStepsBetween(int start, int end);
728 private void executeQuery() {
732 this.completeTraversal = traversal.asAdmin();
734 admin = source.V().asAdmin();
735 TraversalHelper.insertTraversal(admin.getEndStep(), traversal.asAdmin(), admin);
737 this.completeTraversal = (Admin<Vertex, E>) admin;
745 public boolean hasNext() {
746 if (this.completeTraversal == null) {
750 return this.completeTraversal.hasNext();
755 if (this.completeTraversal == null) {
759 return this.completeTraversal.next();
763 public List<E> toList() {
764 if (this.completeTraversal == null) {
768 return this.completeTraversal.toList();
771 protected QueryBuilder<Edge> has(String key, String value) {
772 traversal.has(key, value);
774 return (QueryBuilder<Edge>)this;