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> getChildVerticesFromParent(String parentKey, String parentValue, String childType) {
150 traversal.has(parentKey, parentValue).has(AAIProperties.NODE_TYPE, childType);
152 return (QueryBuilder<Vertex>) this;
159 public QueryBuilder<Vertex> getTypedVerticesByMap(String type, Map<String, String> map) {
161 for (Map.Entry<String, String> es : map.entrySet()) {
162 traversal.has(es.getKey(), es.getValue());
165 traversal.has(AAIProperties.NODE_TYPE, type);
167 return (QueryBuilder<Vertex>) this;
174 public QueryBuilder<Vertex> createKeyQuery(Introspector obj) {
175 Set<String> keys = obj.getKeys();
177 for (String key : keys) {
178 val = obj.getValue(key);
179 Optional<String> metadata = obj.getPropertyMetadata(key, PropertyMetadata.DB_ALIAS);
180 if (metadata.isPresent()) {
181 //use the db name for the field rather than the object model
182 key = metadata.get();
185 //this is because the index is registered as an Integer
186 if (val.getClass().equals(Long.class)) {
187 traversal.has(key,new Integer(val.toString()));
189 traversal.has(key, val);
194 return (QueryBuilder<Vertex>) this;
198 public QueryBuilder<Vertex> exactMatchQuery(Introspector obj) {
199 this.createKeyQuery(obj);
200 allPropertiesQuery(obj);
201 this.createContainerQuery(obj);
202 return (QueryBuilder<Vertex>) this;
205 private void allPropertiesQuery(Introspector obj) {
206 Set<String> props = obj.getProperties();
207 Set<String> keys = obj.getKeys();
209 for (String prop : props) {
210 if (obj.isSimpleType(prop) && !keys.contains(prop)) {
211 val = obj.getValue(prop);
213 Optional<String> metadata = obj.getPropertyMetadata(prop, PropertyMetadata.DB_ALIAS);
214 if (metadata.isPresent()) {
215 //use the db name for the field rather than the object model
216 prop = metadata.get();
218 //this is because the index is registered as an Integer
219 if (val.getClass().equals(Long.class)) {
220 traversal.has(prop,new Integer(val.toString()));
222 traversal.has(prop, val);
235 public QueryBuilder<Vertex> createContainerQuery(Introspector obj) {
236 String type = obj.getChildDBName();
237 String abstractType = obj.getMetadata(ObjectMetadata.ABSTRACT);
238 if (abstractType != null) {
239 String[] inheritors = obj.getMetadata(ObjectMetadata.INHERITORS).split(",");
240 traversal.has(AAIProperties.NODE_TYPE, P.within(inheritors));
242 traversal.has(AAIProperties.NODE_TYPE, type);
246 return (QueryBuilder<Vertex>) this;
250 * @throws NoEdgeRuleFoundException
251 * @throws AAIException
255 public QueryBuilder<Vertex> createEdgeTraversal(EdgeType type, Introspector parent, Introspector child) throws AAIException {
256 String isAbstractType = parent.getMetadata(ObjectMetadata.ABSTRACT);
257 if ("true".equals(isAbstractType)) {
258 markParentBoundary();
259 traversal.union(handleAbstractEdge(type, parent, child));
262 this.edgeQueryToVertex(type, parent, child, null);
264 return (QueryBuilder<Vertex>) this;
273 public QueryBuilder<Vertex> createEdgeTraversalWithLabels(EdgeType type, Introspector out, Introspector in, List<String> labels) throws AAIException {
274 this.edgeQueryToVertex(type, out, in, labels);
275 return (QueryBuilder<Vertex>) this;
279 private Traversal<Vertex, Vertex>[] handleAbstractEdge(EdgeType type, Introspector abstractParent, Introspector child) throws AAIException, NoEdgeRuleFoundException {
280 String childName = child.getDbName();
281 String inheritorMetadata = abstractParent.getMetadata(ObjectMetadata.INHERITORS);
282 String[] inheritors = inheritorMetadata.split(",");
283 List<Traversal<Vertex, Vertex>> unionTraversals = new ArrayList<>(inheritors.length);
285 for (int i = 0; i < inheritors.length; i++) {
286 String inheritor = inheritors[i];
287 if (edgeRules.hasEdgeRule(inheritor, childName) || edgeRules.hasEdgeRule(childName, inheritor)) {
288 Map<String, EdgeRule> rules = edgeRules.getEdgeRules(type, inheritor, childName);
289 GraphTraversal<Vertex, Vertex> innerTraversal = __.start();
291 final List<String> inLabels = new ArrayList<>();
292 final List<String> outLabels = new ArrayList<>();
294 rules.forEach((k,v) -> {
295 if (v.getDirection().equals(Direction.IN)) {
302 if (inLabels.isEmpty() && !outLabels.isEmpty()) {
303 innerTraversal.out(outLabels.toArray(new String[outLabels.size()]));
304 } else if (outLabels.isEmpty() && !inLabels.isEmpty()) {
305 innerTraversal.in(inLabels.toArray(new String[inLabels.size()]));
307 innerTraversal.union(__.out(outLabels.toArray(new String[outLabels.size()])), __.in(inLabels.toArray(new String[inLabels.size()])));
310 innerTraversal.has(AAIProperties.NODE_TYPE, childName);
311 unionTraversals.add(innerTraversal);
315 return unionTraversals.toArray(new Traversal[unionTraversals.size()]);
318 public QueryBuilder<Edge> getEdgesBetweenWithLabels(EdgeType type, String outNodeType, String inNodeType, List<String> labels) throws AAIException {
319 Introspector outObj = loader.introspectorFromName(outNodeType);
320 Introspector inObj = loader.introspectorFromName(inNodeType);
321 this.edgeQuery(type, outObj, inObj, labels);
323 return (QueryBuilder<Edge>)this;
331 public QueryBuilder<E> union(QueryBuilder... builder) {
332 GraphTraversal<Vertex, Vertex>[] traversals = new GraphTraversal[builder.length];
333 for (int i = 0; i < builder.length; i++) {
334 traversals[i] = (GraphTraversal<Vertex, Vertex>)builder[i].getQuery();
336 this.traversal.union(traversals);
346 public QueryBuilder<E> where(QueryBuilder... builder) {
347 GraphTraversal<Vertex, Vertex>[] traversals = new GraphTraversal[builder.length];
348 for (int i = 0; i < builder.length; i++) {
349 this.traversal.where((GraphTraversal<Vertex, Vertex>)builder[i].getQuery());
357 public QueryBuilder<E> store(String name) {
359 this.traversal.store(name);
366 public QueryBuilder<E> cap(String name) {
367 this.traversal.cap(name);
374 public QueryBuilder<E> unfold() {
375 this.traversal.unfold();
382 public QueryBuilder<E> dedup() {
384 this.traversal.dedup();
391 public QueryBuilder<E> emit() {
393 this.traversal.emit();
401 public QueryBuilder<E> repeat(QueryBuilder<E> builder) {
403 this.traversal.repeat((GraphTraversal<Vertex, E>)builder.getQuery());
410 public QueryBuilder<E> until(QueryBuilder<E> builder) {
411 this.traversal.until((GraphTraversal<Vertex,E>)builder.getQuery());
421 public QueryBuilder<E> simplePath(){
422 this.traversal.simplePath();
428 public QueryBuilder<Edge> outE() {
429 this.traversal.outE();
431 return (QueryBuilder<Edge>)this;
435 public QueryBuilder<Edge> inE() {
436 this.traversal.inE();
438 return (QueryBuilder<Edge>)this;
442 public QueryBuilder<Vertex> outV() {
443 this.traversal.outV();
445 return (QueryBuilder<Vertex>)this;
449 public QueryBuilder<Vertex> inV() {
450 this.traversal.inV();
452 return (QueryBuilder<Vertex>)this;
456 public QueryBuilder<E> as(String name) {
457 this.traversal.as(name);
464 public QueryBuilder<E> not(QueryBuilder<E> builder) {
465 this.traversal.not(builder.getQuery());
472 public QueryBuilder<E> select(String name) {
473 this.traversal.select(name);
483 * @param outObj the out type
484 * @param inObj the in type
485 * @throws NoEdgeRuleFoundException
486 * @throws AAIException
488 private void edgeQueryToVertex(EdgeType type, Introspector outObj, Introspector inObj, List<String> labels) throws AAIException {
489 String outType = outObj.getDbName();
490 String inType = inObj.getDbName();
492 if (outObj.isContainer()) {
493 outType = outObj.getChildDBName();
495 if (inObj.isContainer()) {
496 inType = inObj.getChildDBName();
498 markParentBoundary();
499 Map<String, EdgeRule> rules;
500 if (labels == null) {
501 rules = edgeRules.getEdgeRules(type, outType, inType);
503 rules = edgeRules.getEdgeRulesWithLabels(type, outType, inType, labels);
506 final List<String> inLabels = new ArrayList<>();
507 final List<String> outLabels = new ArrayList<>();
509 rules.forEach((k, edgeRule) -> {
510 if (labels != null && !labels.contains(k)) {
513 if (edgeRule.getDirection().equals(Direction.IN)) {
514 inLabels.add(edgeRule.getLabel());
516 outLabels.add(edgeRule.getLabel());
521 if (inLabels.isEmpty() && !outLabels.isEmpty()) {
522 traversal.out(outLabels.toArray(new String[outLabels.size()]));
523 } else if (outLabels.isEmpty() && !inLabels.isEmpty()) {
524 traversal.in(inLabels.toArray(new String[inLabels.size()]));
526 traversal.union(__.out(outLabels.toArray(new String[outLabels.size()])), __.in(inLabels.toArray(new String[inLabels.size()])));
531 this.createContainerQuery(inObj);
538 * @param outObj the out type
539 * @param inObj the in type
540 * @throws NoEdgeRuleFoundException
541 * @throws AAIException
543 private void edgeQuery(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();
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.outE(outLabels.toArray(new String[outLabels.size()]));
579 } else if (outLabels.isEmpty() && !inLabels.isEmpty()) {
580 traversal.inE(inLabels.toArray(new String[inLabels.size()]));
582 traversal.union(__.outE(outLabels.toArray(new String[outLabels.size()])), __.inE(inLabels.toArray(new String[inLabels.size()])));
587 public QueryBuilder<E> limit(long amount) {
588 traversal.limit(amount);
596 public <E2> E2 getQuery() {
597 return (E2)this.traversal;
604 public QueryBuilder<E> getParentQuery() {
606 return cloneQueryAtStep(parentStepIndex);
610 public QueryBuilder<E> getContainerQuery() {
612 if (this.parentStepIndex == 0) {
613 return removeQueryStepsBetween(0, containerStepIndex);
615 return cloneQueryAtStep(containerStepIndex);
623 public void markParentBoundary() {
624 parentStepIndex = stepIndex;
628 public void markContainer() {
629 containerStepIndex = stepIndex;
637 public Vertex getStart() {
641 protected int getParentStepIndex() {
642 return parentStepIndex;
645 protected int getContainerStepIndex() {
646 return containerStepIndex;
649 protected int getStepIndex() {
653 protected abstract QueryBuilder<E> cloneQueryAtStep(int index);
661 protected abstract QueryBuilder<E> removeQueryStepsBetween(int start, int end);
663 private void executeQuery() {
667 this.completeTraversal = traversal.asAdmin();
669 admin = source.V().asAdmin();
670 TraversalHelper.insertTraversal(admin.getEndStep(), traversal.asAdmin(), admin);
672 this.completeTraversal = (Admin<Vertex, E>) admin;
680 public boolean hasNext() {
681 if (this.completeTraversal == null) {
685 return this.completeTraversal.hasNext();
690 if (this.completeTraversal == null) {
694 return this.completeTraversal.next();
698 public List<E> toList() {
699 if (this.completeTraversal == null) {
703 return this.completeTraversal.toList();